From 74e1eb2220a7514c68f4619e93b78ba21cd69e60 Mon Sep 17 00:00:00 2001 From: Issei Suzuki Date: Thu, 20 Dec 2018 17:42:52 +0100 Subject: Add inheritShowWhenLocked System API to activity. Let an activity show on top of the lock screen if the activity behind this can be shown on top of the screen. This is pre-requisite for showing permission dialog on top of the lock screen only when it makes sence. Bug: 109754623 Test: atest server.am.KeyguardTests Change-Id: Ideaa2b77519649a70c682bc95277e451e149adad --- api/system-current.txt | 2 + api/test-current.txt | 1 + core/java/android/app/Activity.java | 27 ++++++++++++ core/java/android/app/IActivityTaskManager.aidl | 1 + core/java/android/content/pm/ActivityInfo.java | 22 +++++++++- core/java/android/content/pm/PackageParser.java | 4 ++ core/res/res/values/attrs_manifest.xml | 15 ++++++- core/res/res/values/public.xml | 2 + .../java/com/android/server/wm/ActivityRecord.java | 51 ++++++++++++++++------ .../java/com/android/server/wm/ActivityStack.java | 7 ++- .../server/wm/ActivityTaskManagerService.java | 16 +++++++ .../android/server/wm/WindowManagerService.java | 22 ---------- 12 files changed, 131 insertions(+), 39 deletions(-) diff --git a/api/system-current.txt b/api/system-current.txt index e79ede8dc9b7..76c14186f996 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -197,6 +197,7 @@ package android { } public static final class R.attr { + field public static final int inheritShowWhenLocked = 16844194; // 0x10105a2 field public static final int isVrOnly = 16844152; // 0x1010578 field public static final int requiredSystemPropertyName = 16844133; // 0x1010565 field public static final int requiredSystemPropertyValue = 16844134; // 0x1010566 @@ -256,6 +257,7 @@ package android.app { method public boolean convertToTranslucent(android.app.Activity.TranslucentConversionListener, android.app.ActivityOptions); method public deprecated boolean isBackgroundVisibleBehind(); method public deprecated void onBackgroundVisibleBehindChanged(boolean); + method public void setInheritShowWhenLocked(boolean); } public static abstract interface Activity.TranslucentConversionListener { diff --git a/api/test-current.txt b/api/test-current.txt index 1401cbb4211e..9ae09ea10c02 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -28,6 +28,7 @@ package android.app { public class Activity extends android.view.ContextThemeWrapper implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback android.view.LayoutInflater.Factory2 android.view.View.OnCreateContextMenuListener android.view.Window.Callback { method public void onMovedToDisplay(int, android.content.res.Configuration); + method public void setInheritShowWhenLocked(boolean); } public class ActivityManager { diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 5b8261e38f1e..85656ebe6f8c 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -8281,6 +8281,33 @@ public class Activity extends ContextThemeWrapper } } + /** + * Specifies whether this {@link Activity} should be shown on top of the lock screen whenever + * the lockscreen is up and this activity has another activity behind it with the showWhenLock + * attribute set. That is, this activity is only visible on the lock screen if there is another + * activity with the showWhenLock attribute visible at the same time on the lock screen. A use + * case for this is permission dialogs, that should only be visible on the lock screen if their + * requesting activity is also visible. This value can be set as a manifest attribute using + * android.R.attr#inheritShowWhenLocked. + * + * @param inheritShowWhenLocked {@code true} to show the {@link Activity} on top of the lock + * screen when this activity has another activity behind it with + * the showWhenLock attribute set; {@code false} otherwise. + * @see #setShowWhenLocked(boolean) + * See android.R.attr#inheritShowWhenLocked + * @hide + */ + @SystemApi + @TestApi + public void setInheritShowWhenLocked(boolean inheritShowWhenLocked) { + try { + ActivityTaskManager.getService().setInheritShowWhenLocked( + mToken, inheritShowWhenLocked); + } catch (RemoteException e) { + Log.e(TAG, "Failed to call setInheritShowWhenLocked", e); + } + } + /** * Specifies whether the screen should be turned on when the {@link Activity} is resumed. * Normally an activity will be transitioned to the stopped state if it is started while the diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index dd87dc330b65..cc6c999ed255 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -419,6 +419,7 @@ interface IActivityTaskManager { void updateLockTaskFeatures(int userId, int flags); void setShowWhenLocked(in IBinder token, boolean showWhenLocked); + void setInheritShowWhenLocked(in IBinder token, boolean setInheritShownWhenLocked); void setTurnScreenOn(in IBinder token, boolean turnScreenOn); /** diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 0edb36c5daff..3cfbe0c6f08a 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -505,6 +505,22 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { */ public int flags; + /** + * Bit in {@link #privateFlags} indicating if the activity should be shown when locked in case + * an activity behind this can also be shown when locked. + * See android.R.attr#inheritShowWhenLocked + * @hide + */ + public static final int FLAG_INHERIT_SHOW_WHEN_LOCKED = 0x1; + + /** + * Options that have been set in the activity declaration in the manifest. + * These include: + * {@link #FLAG_INHERIT_SHOW_WHEN_LOCKED}. + * @hide + */ + public int privateFlags; + /** @hide */ @IntDef(prefix = { "SCREEN_ORIENTATION_" }, value = { SCREEN_ORIENTATION_UNSET, @@ -975,6 +991,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { taskAffinity = orig.taskAffinity; targetActivity = orig.targetActivity; flags = orig.flags; + privateFlags = orig.privateFlags; screenOrientation = orig.screenOrientation; configChanges = orig.configChanges; softInputMode = orig.softInputMode; @@ -1122,9 +1139,10 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { + " targetActivity=" + targetActivity + " persistableMode=" + persistableModeToString()); } - if (launchMode != 0 || flags != 0 || theme != 0) { + if (launchMode != 0 || flags != 0 || privateFlags != 0 || theme != 0) { pw.println(prefix + "launchMode=" + launchMode + " flags=0x" + Integer.toHexString(flags) + + " privateFlags=0x" + Integer.toHexString(privateFlags) + " theme=0x" + Integer.toHexString(theme)); } if (screenOrientation != SCREEN_ORIENTATION_UNSPECIFIED @@ -1178,6 +1196,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { dest.writeString(targetActivity); dest.writeString(launchToken); dest.writeInt(flags); + dest.writeInt(privateFlags); dest.writeInt(screenOrientation); dest.writeInt(configChanges); dest.writeInt(softInputMode); @@ -1307,6 +1326,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable { targetActivity = source.readString(); launchToken = source.readString(); flags = source.readInt(); + privateFlags = source.readInt(); screenOrientation = source.readInt(); configChanges = source.readInt(); softInputMode = source.readInt(); diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 2b266b730485..29163b7f3c57 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -4546,6 +4546,9 @@ public class PackageParser { a.info.flags |= ActivityInfo.FLAG_TURN_SCREEN_ON; } + if (sa.getBoolean(R.styleable.AndroidManifestActivity_inheritShowWhenLocked, false)) { + a.info.privateFlags |= ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED; + } } else { a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE; a.info.configChanges = 0; @@ -4925,6 +4928,7 @@ public class PackageParser { info.targetActivity = targetActivity; info.configChanges = target.info.configChanges; info.flags = target.info.flags; + info.privateFlags = target.info.privateFlags; info.icon = target.info.icon; info.logo = target.info.logo; info.banner = target.info.banner; diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 54f6c632907f..18a42bc5ed0b 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -593,7 +593,7 @@ to be set for all windows of this activity --> - + + + + diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 799d9d858b59..b3b30e992302 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2934,6 +2934,8 @@ + + diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 8884615d2fe1..822d3f7975cb 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -54,6 +54,7 @@ import static android.content.pm.ActivityInfo.CONFIG_WINDOW_CONFIGURATION; import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; import static android.content.pm.ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE; +import static android.content.pm.ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED; import static android.content.pm.ActivityInfo.FLAG_MULTIPROCESS; import static android.content.pm.ActivityInfo.FLAG_NO_HISTORY; import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; @@ -142,6 +143,7 @@ import static org.xmlpull.v1.XmlPullParser.END_TAG; import static org.xmlpull.v1.XmlPullParser.START_TAG; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.ActivityManager.TaskDescription; import android.app.ActivityOptions; import android.app.PendingIntent; @@ -387,6 +389,7 @@ final class ActivityRecord extends ConfigurationContainer { int mRotationAnimationHint = -1; private boolean mShowWhenLocked; + private boolean mInheritShownWhenLocked; private boolean mTurnScreenOn; /** @@ -996,6 +999,7 @@ final class ActivityRecord extends ConfigurationContainer { null : ComponentName.unflattenFromString(aInfo.requestedVrComponent); mShowWhenLocked = (aInfo.flags & FLAG_SHOW_WHEN_LOCKED) != 0; + mInheritShownWhenLocked = (aInfo.privateFlags & FLAG_INHERIT_SHOW_WHEN_LOCKED) != 0; mTurnScreenOn = (aInfo.flags & FLAG_TURN_SCREEN_ON) != 0; mRotationAnimationHint = aInfo.rotationAnimation; @@ -1481,14 +1485,6 @@ final class ActivityRecord extends ConfigurationContainer { return true; } - /** - * @return true if the activity contains windows that have - * {@link LayoutParams#FLAG_DISMISS_KEYGUARD} set - */ - boolean hasDismissKeyguardWindows() { - return mAtmService.mWindowManager.containsDismissKeyguardWindow(appToken); - } - void makeFinishingLocked() { if (finishing) { return; @@ -3177,16 +3173,45 @@ final class ActivityRecord extends ConfigurationContainer { false /* preserveWindows */); } + void setInheritShowWhenLocked(boolean inheritShowWhenLocked) { + mInheritShownWhenLocked = inheritShowWhenLocked; + mRootActivityContainer.ensureActivitiesVisible(null, 0, false); + } + /** * @return true if the activity windowing mode is not - * {@link android.app.WindowConfiguration#WINDOWING_MODE_PINNED} and activity contains - * windows that have {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} set or if the activity - * has set {@link #mShowWhenLocked}. + * {@link android.app.WindowConfiguration#WINDOWING_MODE_PINNED} and a) activity + * contains windows that have {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} set or if the + * activity has set {@link #mShowWhenLocked}, or b) if the activity has set + * {@link #mInheritShownWhenLocked} and the activity behind this satisfies the + * conditions a) above. * Multi-windowing mode will be exited if true is returned. */ boolean canShowWhenLocked() { - return !inPinnedWindowingMode() && (mShowWhenLocked - || mAtmService.mWindowManager.containsShowWhenLockedWindow(appToken)); + if (!inPinnedWindowingMode() && (mShowWhenLocked + || (mAppWindowToken != null && mAppWindowToken.containsShowWhenLockedWindow()))) { + return true; + } else if (mInheritShownWhenLocked) { + ActivityRecord r = getActivityBelow(); + return r != null && !r.inPinnedWindowingMode() && (r.mShowWhenLocked + || (r.mAppWindowToken != null + && r.mAppWindowToken.containsShowWhenLockedWindow())); + } else { + return false; + } + } + + /** + * @return an {@link ActivityRecord} of the activity below this activity, or {@code null} if no + * such activity exists. + */ + @Nullable + private ActivityRecord getActivityBelow() { + final int pos = task.mActivities.indexOf(this); + if (pos == -1) { + throw new IllegalStateException("Activity not found in its task"); + } + return pos == 0 ? null : task.getChildAt(pos - 1); } void setTurnScreenOn(boolean turnScreenOn) { diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 4581a0f9f350..4d7de9058105 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -2204,7 +2204,8 @@ class ActivityStack extends ConfigurationContai .isKeyguardOrAodShowing(displayId); final boolean keyguardLocked = mStackSupervisor.getKeyguardController().isKeyguardLocked(); final boolean showWhenLocked = r.canShowWhenLocked(); - final boolean dismissKeyguard = r.hasDismissKeyguardWindows(); + final boolean dismissKeyguard = r.mAppWindowToken != null + && r.mAppWindowToken.containsDismissKeyguardWindow(); if (shouldBeVisible) { if (dismissKeyguard && mTopDismissingKeyguardActivity == null) { mTopDismissingKeyguardActivity = r; @@ -2561,7 +2562,9 @@ class ActivityStack extends ConfigurationContai final boolean canShowWhenLocked = !mTopActivityOccludesKeyguard && next.canShowWhenLocked(); final boolean mayDismissKeyguard = mTopDismissingKeyguardActivity != next - && next.hasDismissKeyguardWindows(); + && next.mAppWindowToken != null + && next.mAppWindowToken.containsDismissKeyguardWindow(); + if (canShowWhenLocked || mayDismissKeyguard) { ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */, !PRESERVE_WINDOWS); diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 42121ca08696..99f9973cbbb8 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -4333,6 +4333,22 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } } + @Override + public void setInheritShowWhenLocked(IBinder token, boolean inheritShowWhenLocked) { + synchronized (mGlobalLock) { + final ActivityRecord r = ActivityRecord.isInStackLocked(token); + if (r == null) { + return; + } + final long origId = Binder.clearCallingIdentity(); + try { + r.setInheritShowWhenLocked(inheritShowWhenLocked); + } finally { + Binder.restoreCallingIdentity(origId); + } + } + } + @Override public void setTurnScreenOn(IBinder token, boolean turnScreenOn) { synchronized (mGlobalLock) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index f5f55e2ebf73..7cfc42f4d651 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2650,28 +2650,6 @@ public class WindowManagerService extends IWindowManager.Stub mWindowPlacerLocked.continueLayout(); } - /** - * @return true if the activity contains windows that have - * {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} set - */ - public boolean containsShowWhenLockedWindow(IBinder token) { - synchronized (mGlobalLock) { - final AppWindowToken wtoken = mRoot.getAppWindowToken(token); - return wtoken != null && wtoken.containsShowWhenLockedWindow(); - } - } - - /** - * @return true if the activity contains windows that have - * {@link LayoutParams#FLAG_DISMISS_KEYGUARD} set - */ - public boolean containsDismissKeyguardWindow(IBinder token) { - synchronized (mGlobalLock) { - final AppWindowToken wtoken = mRoot.getAppWindowToken(token); - return wtoken != null && wtoken.containsDismissKeyguardWindow(); - } - } - /** * Notifies activity manager that some Keyguard flags have changed and that it needs to * reevaluate the visibilities of the activities. -- cgit v1.2.3-59-g8ed1b