diff options
19 files changed, 664 insertions, 187 deletions
diff --git a/api/current.txt b/api/current.txt index 31ed25adc0f4..7ffc57515bfe 100644 --- a/api/current.txt +++ b/api/current.txt @@ -1180,6 +1180,7 @@ package android { field public static final int showSilent = 16843259; // 0x10101fb field public static final int showText = 16843949; // 0x10104ad field public static final deprecated int showWeekNumber = 16843582; // 0x101033e + field public static final int showWhenLocked = 16844137; // 0x1010569 field public static final deprecated int shownWeekCount = 16843585; // 0x1010341 field public static final int shrinkColumns = 16843082; // 0x101014a field public static final deprecated int singleLine = 16843101; // 0x101015d @@ -1438,6 +1439,7 @@ package android { field public static final int trimPathOffset = 16843786; // 0x101040a field public static final int trimPathStart = 16843784; // 0x1010408 field public static final int tunerCount = 16844061; // 0x101051d + field public static final int turnScreenOn = 16844138; // 0x101056a field public static final int type = 16843169; // 0x10101a1 field public static final int typeface = 16842902; // 0x1010096 field public static final int uiOptions = 16843672; // 0x1010398 @@ -3764,10 +3766,12 @@ package android.app { method public final void setResult(int); method public final void setResult(int, android.content.Intent); method public final deprecated void setSecondaryProgress(int); + method public void setShowWhenLocked(boolean); method public void setTaskDescription(android.app.ActivityManager.TaskDescription); method public void setTitle(java.lang.CharSequence); method public void setTitle(int); method public deprecated void setTitleColor(int); + method public void setTurnScreenOn(boolean); method public void setVisible(boolean); method public final void setVolumeControlStream(int); method public void setVrModeEnabled(boolean, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException; @@ -46969,12 +46973,12 @@ package android.view { field public static final int FLAG_SCALED = 16384; // 0x4000 field public static final int FLAG_SECURE = 8192; // 0x2000 field public static final int FLAG_SHOW_WALLPAPER = 1048576; // 0x100000 - field public static final int FLAG_SHOW_WHEN_LOCKED = 524288; // 0x80000 + field public static final deprecated int FLAG_SHOW_WHEN_LOCKED = 524288; // 0x80000 field public static final int FLAG_SPLIT_TOUCH = 8388608; // 0x800000 field public static final deprecated int FLAG_TOUCHABLE_WHEN_WAKING = 64; // 0x40 field public static final int FLAG_TRANSLUCENT_NAVIGATION = 134217728; // 0x8000000 field public static final int FLAG_TRANSLUCENT_STATUS = 67108864; // 0x4000000 - field public static final int FLAG_TURN_SCREEN_ON = 2097152; // 0x200000 + field public static final deprecated int FLAG_TURN_SCREEN_ON = 2097152; // 0x200000 field public static final int FLAG_WATCH_OUTSIDE_TOUCH = 262144; // 0x40000 field public static final int FORMAT_CHANGED = 8; // 0x8 field public static final int LAST_APPLICATION_WINDOW = 99; // 0x63 diff --git a/api/system-current.txt b/api/system-current.txt index 08523f3aebc8..07a7b462ff5a 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -1307,6 +1307,7 @@ package android { field public static final int showSilent = 16843259; // 0x10101fb field public static final int showText = 16843949; // 0x10104ad field public static final deprecated int showWeekNumber = 16843582; // 0x101033e + field public static final int showWhenLocked = 16844137; // 0x1010569 field public static final deprecated int shownWeekCount = 16843585; // 0x1010341 field public static final int shrinkColumns = 16843082; // 0x101014a field public static final deprecated int singleLine = 16843101; // 0x101015d @@ -1565,6 +1566,7 @@ package android { field public static final int trimPathOffset = 16843786; // 0x101040a field public static final int trimPathStart = 16843784; // 0x1010408 field public static final int tunerCount = 16844061; // 0x101051d + field public static final int turnScreenOn = 16844138; // 0x101056a field public static final int type = 16843169; // 0x10101a1 field public static final int typeface = 16842902; // 0x1010096 field public static final int uiOptions = 16843672; // 0x1010398 @@ -3900,10 +3902,12 @@ package android.app { method public final void setResult(int); method public final void setResult(int, android.content.Intent); method public final deprecated void setSecondaryProgress(int); + method public void setShowWhenLocked(boolean); method public void setTaskDescription(android.app.ActivityManager.TaskDescription); method public void setTitle(java.lang.CharSequence); method public void setTitle(int); method public deprecated void setTitleColor(int); + method public void setTurnScreenOn(boolean); method public void setVisible(boolean); method public final void setVolumeControlStream(int); method public void setVrModeEnabled(boolean, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException; @@ -50522,12 +50526,12 @@ package android.view { field public static final int FLAG_SCALED = 16384; // 0x4000 field public static final int FLAG_SECURE = 8192; // 0x2000 field public static final int FLAG_SHOW_WALLPAPER = 1048576; // 0x100000 - field public static final int FLAG_SHOW_WHEN_LOCKED = 524288; // 0x80000 + field public static final deprecated int FLAG_SHOW_WHEN_LOCKED = 524288; // 0x80000 field public static final int FLAG_SPLIT_TOUCH = 8388608; // 0x800000 field public static final deprecated int FLAG_TOUCHABLE_WHEN_WAKING = 64; // 0x40 field public static final int FLAG_TRANSLUCENT_NAVIGATION = 134217728; // 0x8000000 field public static final int FLAG_TRANSLUCENT_STATUS = 67108864; // 0x4000000 - field public static final int FLAG_TURN_SCREEN_ON = 2097152; // 0x200000 + field public static final deprecated int FLAG_TURN_SCREEN_ON = 2097152; // 0x200000 field public static final int FLAG_WATCH_OUTSIDE_TOUCH = 262144; // 0x40000 field public static final int FORMAT_CHANGED = 8; // 0x8 field public static final int LAST_APPLICATION_WINDOW = 99; // 0x63 diff --git a/api/test-current.txt b/api/test-current.txt index 29e82ab42078..46491eb9ecac 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -1180,6 +1180,7 @@ package android { field public static final int showSilent = 16843259; // 0x10101fb field public static final int showText = 16843949; // 0x10104ad field public static final deprecated int showWeekNumber = 16843582; // 0x101033e + field public static final int showWhenLocked = 16844137; // 0x1010569 field public static final deprecated int shownWeekCount = 16843585; // 0x1010341 field public static final int shrinkColumns = 16843082; // 0x101014a field public static final deprecated int singleLine = 16843101; // 0x101015d @@ -1438,6 +1439,7 @@ package android { field public static final int trimPathOffset = 16843786; // 0x101040a field public static final int trimPathStart = 16843784; // 0x1010408 field public static final int tunerCount = 16844061; // 0x101051d + field public static final int turnScreenOn = 16844138; // 0x101056a field public static final int type = 16843169; // 0x10101a1 field public static final int typeface = 16842902; // 0x1010096 field public static final int uiOptions = 16843672; // 0x1010398 @@ -3766,10 +3768,12 @@ package android.app { method public final void setResult(int); method public final void setResult(int, android.content.Intent); method public final deprecated void setSecondaryProgress(int); + method public void setShowWhenLocked(boolean); method public void setTaskDescription(android.app.ActivityManager.TaskDescription); method public void setTitle(java.lang.CharSequence); method public void setTitle(int); method public deprecated void setTitleColor(int); + method public void setTurnScreenOn(boolean); method public void setVisible(boolean); method public final void setVolumeControlStream(int); method public void setVrModeEnabled(boolean, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException; @@ -47385,12 +47389,12 @@ package android.view { field public static final int FLAG_SCALED = 16384; // 0x4000 field public static final int FLAG_SECURE = 8192; // 0x2000 field public static final int FLAG_SHOW_WALLPAPER = 1048576; // 0x100000 - field public static final int FLAG_SHOW_WHEN_LOCKED = 524288; // 0x80000 + field public static final deprecated int FLAG_SHOW_WHEN_LOCKED = 524288; // 0x80000 field public static final int FLAG_SPLIT_TOUCH = 8388608; // 0x800000 field public static final deprecated int FLAG_TOUCHABLE_WHEN_WAKING = 64; // 0x40 field public static final int FLAG_TRANSLUCENT_NAVIGATION = 134217728; // 0x8000000 field public static final int FLAG_TRANSLUCENT_STATUS = 67108864; // 0x4000000 - field public static final int FLAG_TURN_SCREEN_ON = 2097152; // 0x200000 + field public static final deprecated int FLAG_TURN_SCREEN_ON = 2097152; // 0x200000 field public static final int FLAG_WATCH_OUTSIDE_TOUCH = 262144; // 0x40000 field public static final int FORMAT_CHANGED = 8; // 0x8 field public static final int LAST_APPLICATION_WINDOW = 99; // 0x63 diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index d7fe1a5d1bc8..adb3152d4ae7 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -7548,6 +7548,53 @@ public class Activity extends ContextThemeWrapper } } + /** + * Specifies whether an {@link Activity} should be shown on top of the the lock screen whenever + * the lockscreen is up and the activity is resumed. Normally an activity will be transitioned + * to the stopped state if it is started while the lockscreen is up, but with this flag set the + * activity will remain in the resumed state visible on-top of the lock screen. This value can + * be set as a manifest attribute using {@link android.R.attr#showWhenLocked}. + * + * @param showWhenLocked {@code true} to show the {@link Activity} on top of the lock screen; + * {@code false} otherwise. + * @see #setTurnScreenOn(boolean) + * @see android.R.attr#turnScreenOn + * @see android.R.attr#showWhenLocked + */ + public void setShowWhenLocked(boolean showWhenLocked) { + try { + ActivityManager.getService().setShowWhenLocked(mToken, showWhenLocked); + } catch (RemoteException e) { + Log.e(TAG, "Failed to call setShowWhenLocked", 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 + * screen if off, but with this flag set the activity will cause the screen to turn on if the + * activity will be visible and resumed due to the screen coming on. The screen will not be + * turned on if the activity won't be visible after the screen is turned on. This flag is + * normally used in conjunction with the {@link android.R.attr#showWhenLocked} flag to make sure + * the activity is visible after the screen is turned on when the lockscreen is up. In addition, + * if this flag is set and the activity calls {@link + * KeyguardManager#requestDismissKeyguard(Activity, KeyguardManager.KeyguardDismissCallback)} + * the screen will turn on. + * + * @param turnScreenOn {@code true} to turn on the screen; {@code false} otherwise. + * + * @see #setShowWhenLocked(boolean) + * @see android.R.attr#turnScreenOn + * @see android.R.attr#showWhenLocked + */ + public void setTurnScreenOn(boolean turnScreenOn) { + try { + ActivityManager.getService().setTurnScreenOn(mToken, turnScreenOn); + } catch (RemoteException e) { + Log.e(TAG, "Failed to call setTurnScreenOn", e); + } + } + class HostCallbacks extends FragmentHostCallback<Activity> { public HostCallbacks() { super(Activity.this /*activity*/); diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 54cd26a090bb..b27e224251d3 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -633,4 +633,7 @@ interface IActivityManager { // side. If so, make sure they are using the correct transaction ids and arguments. // If a transaction which will also be used on the native side is being inserted, add it // alongside with other transactions of this kind at the top of this file. + + void setShowWhenLocked(in IBinder token, boolean showWhenLocked); + void setTurnScreenOn(in IBinder token, boolean turnScreenOn); } diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java index 16b21f15353e..c0381d69d681 100644 --- a/core/java/android/app/KeyguardManager.java +++ b/core/java/android/app/KeyguardManager.java @@ -461,6 +461,9 @@ public class KeyguardManager { * <p> * If the Keyguard is secure and the device is not in a trusted state, this will bring up the * UI so the user can enter their credentials. + * <p> + * If the value set for the {@link Activity} attr {@link android.R.attr#turnScreenOn} is true, + * the screen will turn on when the keyguard is dismissed. * * @param activity The activity requesting the dismissal. The activity must be either visible * by using {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} or must be in a state in diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java index 9a014766c206..b75c39c0d350 100644 --- a/core/java/android/content/pm/ActivityInfo.java +++ b/core/java/android/content/pm/ActivityInfo.java @@ -441,6 +441,22 @@ public class ActivityInfo extends ComponentInfo * @hide */ public static final int FLAG_SUPPORTS_PICTURE_IN_PICTURE = 0x400000; + + /** + * Bit in {@link #flags} indicating if the activity should be shown when locked. + * See {@link android.R.attr#showWhenLocked} + * @hide + */ + public static final int FLAG_SHOW_WHEN_LOCKED = 0x800000; + + /** + * Bit in {@link #flags} indicating if the screen should turn on when starting the activity. + * See {@link android.R.attr#turnScreenOn} + * @hide + */ + public static final int FLAG_TURN_SCREEN_ON = 0x1000000; + + /** * @hide Bit in {@link #flags}: If set, this component will only be seen * by the system user. Only works with broadcast receivers. Set from the @@ -462,6 +478,7 @@ public class ActivityInfo extends ComponentInfo * thrown. Set from the {@link android.R.attr#allowEmbedded} attribute. */ public static final int FLAG_ALLOW_EMBEDDED = 0x80000000; + /** * Options that have been set in the activity declaration in the * manifest. diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 1b88ce7c3a04..e4f2fc1c5035 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -4292,6 +4292,15 @@ public class PackageParser { a.info.colorMode = sa.getInt(R.styleable.AndroidManifestActivity_colorMode, ActivityInfo.COLOR_MODE_DEFAULT); + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_showWhenLocked, false)) { + a.info.flags |= ActivityInfo.FLAG_SHOW_WHEN_LOCKED; + } + + if (sa.getBoolean(R.styleable.AndroidManifestActivity_turnScreenOn, false)) { + a.info.flags |= ActivityInfo.FLAG_TURN_SCREEN_ON; + } + } else { a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE; a.info.configChanges = 0; diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 4c0a1902d6a4..a9c4b11cfbee 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -941,7 +941,11 @@ public interface WindowManager extends ViewManager { * {@link #FLAG_DISMISS_KEYGUARD} to automatically fully dismisss * non-secure keyguards. This flag only applies to the top-most * full-screen window. + * @deprecated Use {@link android.R.attr#showWhenLocked} or + * {@link android.app.Activity#setShowWhenLocked(boolean)} instead to prevent an + * unintentional double life-cycle event. */ + @Deprecated public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000; /** Window flag: ask that the system wallpaper be shown behind @@ -966,7 +970,12 @@ public interface WindowManager extends ViewManager { /** Window flag: when set as a window is being added or made * visible, once the window has been shown then the system will * poke the power manager's user activity (as if the user had woken - * up the device) to turn the screen on. */ + * up the device) to turn the screen on. + * @deprecated Use {@link android.R.attr#turnScreenOn} or + * {@link android.app.Activity#setTurnScreenOn(boolean)} instead to prevent an + * unintentional double life-cycle event. + */ + @Deprecated public static final int FLAG_TURN_SCREEN_ON = 0x00200000; /** Window flag: when set the window will cause the keyguard to diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index ced22cc37f5a..01b8e1558fb3 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -561,6 +561,35 @@ to be set for all windows of this activity --> <attr name="showForAllUsers" format="boolean" /> + <!-- Specifies whether an {@link Activity} should be shown on top of the the lock screen + whenever the lockscreen is up and the activity is resumed. Normally an activity will be + transitioned to the stopped state if it is started while the lockscreen is up, but with + this flag set the activity will remain in the resumed state visible on-top of the lock + screen. + + <p>This should be used instead of {@link android.view.LayoutParams#FLAG_SHOW_WHEN_LOCKED} + flag set for Windows. When using the Window flag during activity startup, there may not be + time to add it before the system stops your activity for being behind the lock-screen. + This leads to a double life-cycle as it is then restarted.</p> --> + <attr name="showWhenLocked" format="boolean" /> + + <!-- 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 + screen if off, but with this flag set the activity will cause the screen to turn on if the + activity will be visible and resumed due to the screen coming on. The screen will not be + turned on if the activity won't be visible after the screen is turned on. This flag is + normally used in conjunction with the {@link android.R.attr#showWhenLocked} flag to make + sure the activity is visible after the screen is turned on when the lockscreen is up. In + addition, if this flag is set and the activity calls + {@link KeyguardManager#requestDismissKeyguard(Activity, KeyguardManager.KeyguardDismissCallback)} + the screen will turn on. + + <p>This should be used instead of {@link android.view.LayoutParams.FLAG_TURN_SCREEN_ON} + flag set for Windows. When using the Window flag during activity startup, there may not be + time to add it before the system stops your activity because the screen has not yet turned + on. This leads to a double life-cycle as it is then restarted.</p> --> + <attr name="turnScreenOn" format="boolean" /> + <!-- Specify the authorities under which this content provider can be found. Multiple authorities may be supplied by separating them with a semicolon. Authority names should use a Java-style naming @@ -2093,6 +2122,10 @@ <attr name="maxAspectRatio" /> <attr name="lockTaskMode" /> <attr name="showForAllUsers" /> + + <attr name="showWhenLocked" /> + <attr name="turnScreenOn" /> + <attr name="directBootAware" /> <!-- @hide This activity is always focusable regardless of if it is in a task/stack whose activities are normally not focusable. diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 48e667a06aa0..2a4881d6b167 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2843,6 +2843,8 @@ <eat-comment /> <public-group type="attr" first-id="0x01010569"> + <public name="showWhenLocked"/> + <public name="turnScreenOn"/> </public-group> <public-group type="style" first-id="0x010302e0"> diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 10700a73f1b5..1566720102b5 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -24447,4 +24447,37 @@ public class ActivityManagerService extends IActivityManager.Stub return mNmi != null; } } + + @Override + public void setShowWhenLocked(IBinder token, boolean showWhenLocked) + throws RemoteException { + synchronized (this) { + final ActivityRecord r = ActivityRecord.isInStackLocked(token); + if (r == null) { + return; + } + final long origId = Binder.clearCallingIdentity(); + try { + r.setShowWhenLocked(showWhenLocked); + } finally { + Binder.restoreCallingIdentity(origId); + } + } + } + + @Override + public void setTurnScreenOn(IBinder token, boolean turnScreenOn) throws RemoteException { + synchronized (this) { + final ActivityRecord r = ActivityRecord.isInStackLocked(token); + if (r == null) { + return; + } + final long origId = Binder.clearCallingIdentity(); + try { + r.setTurnScreenOn(turnScreenOn); + } finally { + Binder.restoreCallingIdentity(origId); + } + } + } } diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index e5a4f89a3835..4b2b6a77deb6 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -47,11 +47,13 @@ import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE; import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; import static android.content.pm.ActivityInfo.CONFIG_UI_MODE; import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; +import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED; 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_MULTIPROCESS; import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; import static android.content.pm.ActivityInfo.FLAG_STATE_NOT_NEEDED; +import static android.content.pm.ActivityInfo.FLAG_TURN_SCREEN_ON; import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; @@ -344,6 +346,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo // handle calculating override configuration from the bounds. private final Rect mBounds = new Rect(); + private boolean mShowWhenLocked; + private boolean mTurnScreenOn; + /** * Temp configs used in {@link #ensureActivityConfigurationLocked(int, boolean)} */ @@ -904,6 +909,9 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo requestedVrComponent = (aInfo.requestedVrComponent == null) ? null : ComponentName.unflattenFromString(aInfo.requestedVrComponent); + + mShowWhenLocked = (aInfo.flags & FLAG_SHOW_WHEN_LOCKED) != 0; + mTurnScreenOn = (aInfo.flags & FLAG_TURN_SCREEN_ON) != 0; } AppWindowContainerController getWindowContainerController() { @@ -1258,13 +1266,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo return (info.flags & FLAG_ALWAYS_FOCUSABLE) != 0; } - /** - * @return true if the activity contains windows that have - * {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} set - */ - boolean hasShowWhenLockedWindows() { - return service.mWindowManager.containsShowWhenLockedWindow(appToken); - } /** * @return true if the activity contains windows that have @@ -1341,11 +1342,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo intent, getUriPermissionsLocked(), userId); final ReferrerIntent rintent = new ReferrerIntent(intent, referrer); boolean unsent = true; - final ActivityStack stack = getStack(); - final boolean isTopActivityInStack = - stack != null && stack.topRunningActivityLocked() == this; - final boolean isTopActivityWhileSleeping = - service.isSleepingLocked() && isTopActivityInStack; + final boolean isTopActivityWhileSleeping = service.isSleepingLocked() && isTopRunningActivity(); // We want to immediately deliver the intent to the activity if: // - It is currently resumed or paused. i.e. it is currently visible to the user and we want @@ -1733,7 +1730,15 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo } returningOptions = null; - mStackSupervisor.checkReadyForSleepLocked(); + + if (canTurnScreenOn()) { + mStackSupervisor.wakeUp("turnScreenOnFlag"); + } else { + // If the screen is going to turn on because the caller explicitly requested it and + // the keyguard is not showing don't attempt to sleep. Otherwise the Activity will + // pause and then resume again later, which will result in a double life-cycle event. + mStackSupervisor.checkReadyForSleepLocked(); + } } final void activityStoppedLocked(Bundle newIcicle, PersistableBundle newPersistentState, @@ -2797,6 +2802,44 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo return info.applicationInfo.uid; } + void setShowWhenLocked(boolean showWhenLocked) { + mShowWhenLocked = showWhenLocked; + } + + /** + * @return true if the activity contains windows that have + * {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} set or if the activity has set + * {@link #mShowWhenLocked}. + */ + boolean canShowWhenLocked() { + return mShowWhenLocked || service.mWindowManager.containsShowWhenLockedWindow(appToken); + } + + void setTurnScreenOn(boolean turnScreenOn) { + mTurnScreenOn = turnScreenOn; + } + + /** + * Determines whether this ActivityRecord can turn the screen on. It checks whether the flag + * {@link #mTurnScreenOn} is set and checks whether the ActivityRecord should be visible + * depending on Keyguard state + * + * @return true if the screen can be turned on, false otherwise. + */ + boolean canTurnScreenOn() { + final ActivityStack stack = getStack(); + return mTurnScreenOn && stack != null && + stack.checkKeyguardVisibility(this, true /* shouldBeVisible */, true /* isTop */); + } + + boolean getTurnScreenOnFlag() { + return mTurnScreenOn; + } + + boolean isTopRunningActivity() { + return mStackSupervisor.topRunningActivityLocked() == this; + } + @Override public String toString() { if (stringName != null) { diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index d32bc080c266..77e438a7c610 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1907,7 +1907,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai final boolean isInPinnedStack = r.getStack().getStackId() == PINNED_STACK_ID; final boolean keyguardShowing = mStackSupervisor.mKeyguardController.isKeyguardShowing(); final boolean keyguardLocked = mStackSupervisor.mKeyguardController.isKeyguardLocked(); - final boolean showWhenLocked = r.hasShowWhenLockedWindows() && !isInPinnedStack; + final boolean showWhenLocked = r.canShowWhenLocked() && !isInPinnedStack; final boolean dismissKeyguard = r.hasDismissKeyguardWindows(); if (shouldBeVisible) { if (dismissKeyguard && mTopDismissingKeyguardActivity == null) { @@ -2176,12 +2176,18 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai } finally { mStackSupervisor.inResumeTopActivity = false; } + // When resuming the top activity, it may be necessary to pause the top activity (for // example, returning to the lock screen. We suppress the normal pause logic in // {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the end. // We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here to ensure - // any necessary pause logic occurs. - mStackSupervisor.checkReadyForSleepLocked(); + // any necessary pause logic occurs. In the case where the Activity will be shown regardless + // of the lock screen, the call to {@link ActivityStackSupervisor#checkReadyForSleepLocked} + // is skipped. + final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */); + if (next == null || !next.canTurnScreenOn()) { + mStackSupervisor.checkReadyForSleepLocked(); + } return result; } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 29e11d108d6c..fa279c227d79 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -40,6 +40,7 @@ import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Process.SYSTEM_UID; +import static android.os.PowerManager.PARTIAL_WAKE_LOCK; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.FLAG_PRIVATE; @@ -556,6 +557,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final KeyguardController mKeyguardController; + private PowerManager mPowerManager; + private int mDeferResumeCount; + /** * Description of a request to start a new activity, which has been held * due to app switches being disabled. @@ -604,9 +608,10 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D * initialized. So we initialize our wakelocks afterwards. */ void initPowerManagement() { - PowerManager pm = (PowerManager)mService.mContext.getSystemService(Context.POWER_SERVICE); - mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep"); - mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*launch*"); + mPowerManager = (PowerManager)mService.mContext.getSystemService(Context.POWER_SERVICE); + mGoingToSleep = mPowerManager + .newWakeLock(PARTIAL_WAKE_LOCK, "ActivityManager-Sleep"); + mLaunchingActivity = mPowerManager.newWakeLock(PARTIAL_WAKE_LOCK, "*launch*"); mLaunchingActivity.setReferenceCounted(false); } @@ -1334,184 +1339,196 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return false; } - r.startFreezingScreenLocked(app, 0); - if (r.getStack().checkKeyguardVisibility(r, true /* shouldBeVisible */, true /* isTop */)) { - // We only set the visibility to true if the activity is allowed to be visible based on - // keyguard state. This avoids setting this into motion in window manager that is later - // cancelled due to later calls to ensure visible activities that set visibility back to - // false. - r.setVisibility(true); - } + final TaskRecord task = r.getTask(); + final ActivityStack stack = task.getStack(); - // schedule launch ticks to collect information about slow apps. - r.startLaunchTickingLocked(); + beginDeferResume(); - // Have the window manager re-evaluate the orientation of the screen based on the new - // activity order. Note that as a result of this, it can call back into the activity - // manager with a new orientation. We don't care about that, because the activity is not - // currently running so we are just restarting it anyway. - if (checkConfig) { - final int displayId = r.getDisplayId(); - final Configuration config = mWindowManager.updateOrientationFromAppTokens( - getDisplayOverrideConfiguration(displayId), - r.mayFreezeScreenLocked(app) ? r.appToken : null, displayId); - // Deferring resume here because we're going to launch new activity shortly. - // We don't want to perform a redundant launch of the same record while ensuring - // configurations and trying to resume top activity of focused stack. - mService.updateDisplayOverrideConfigurationLocked(config, r, true /* deferResume */, - displayId); - } + try { + r.startFreezingScreenLocked(app, 0); - if (mKeyguardController.isKeyguardLocked()) { - r.notifyUnknownVisibilityLaunched(); - } - final int applicationInfoUid = - (r.info.applicationInfo != null) ? r.info.applicationInfo.uid : -1; - if ((r.userId != app.userId) || (r.appInfo.uid != applicationInfoUid)) { - Slog.wtf(TAG, - "User ID for activity changing for " + r - + " appInfo.uid=" + r.appInfo.uid - + " info.ai.uid=" + applicationInfoUid - + " old=" + r.app + " new=" + app); - } + // schedule launch ticks to collect information about slow apps. + r.startLaunchTickingLocked(); - r.app = app; - app.waitingToKill = null; - r.launchCount++; - r.lastLaunchTime = SystemClock.uptimeMillis(); + r.app = app; - if (DEBUG_ALL) Slog.v(TAG, "Launching: " + r); + // Have the window manager re-evaluate the orientation of the screen based on the new + // activity order. Note that as a result of this, it can call back into the activity + // manager with a new orientation. We don't care about that, because the activity is + // not currently running so we are just restarting it anyway. + if (checkConfig) { + final int displayId = r.getDisplayId(); + final Configuration config = mWindowManager.updateOrientationFromAppTokens( + getDisplayOverrideConfiguration(displayId), + r.mayFreezeScreenLocked(app) ? r.appToken : null, displayId); + // Deferring resume here because we're going to launch new activity shortly. + // We don't want to perform a redundant launch of the same record while ensuring + // configurations and trying to resume top activity of focused stack. + mService.updateDisplayOverrideConfigurationLocked(config, r, true /* deferResume */, + displayId); + } - int idx = app.activities.indexOf(r); - if (idx < 0) { - app.activities.add(r); - } - mService.updateLruProcessLocked(app, true, null); - mService.updateOomAdjLocked(); + if (r.getStack().checkKeyguardVisibility(r, true /* shouldBeVisible */, + true /* isTop */)) { + // We only set the visibility to true if the activity is allowed to be visible + // based on + // keyguard state. This avoids setting this into motion in window manager that is + // later cancelled due to later calls to ensure visible activities that set + // visibility back to false. + r.setVisibility(true); + } - final TaskRecord task = r.getTask(); - if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE || - task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE_PRIV) { - setLockTaskModeLocked(task, LOCK_TASK_MODE_LOCKED, "mLockTaskAuth==LAUNCHABLE", false); - } + if (mKeyguardController.isKeyguardLocked()) { + r.notifyUnknownVisibilityLaunched(); + } + final int applicationInfoUid = + (r.info.applicationInfo != null) ? r.info.applicationInfo.uid : -1; + if ((r.userId != app.userId) || (r.appInfo.uid != applicationInfoUid)) { + Slog.wtf(TAG, + "User ID for activity changing for " + r + + " appInfo.uid=" + r.appInfo.uid + + " info.ai.uid=" + applicationInfoUid + + " old=" + r.app + " new=" + app); + } - final ActivityStack stack = task.getStack(); - try { - if (app.thread == null) { - throw new RemoteException(); - } - List<ResultInfo> results = null; - List<ReferrerIntent> newIntents = null; - if (andResume) { - // We don't need to deliver new intents and/or set results if activity is going - // to pause immediately after launch. - results = r.results; - newIntents = r.newIntents; - } - if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, - "Launching: " + r + " icicle=" + r.icicle + " with results=" + results - + " newIntents=" + newIntents + " andResume=" + andResume); - EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY, r.userId, - System.identityHashCode(r), task.taskId, r.shortComponentName); - if (r.isHomeActivity()) { - // Home process is the root process of the task. - mService.mHomeProcess = task.mActivities.get(0).app; - } - mService.notifyPackageUse(r.intent.getComponent().getPackageName(), - PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY); - r.sleeping = false; - r.forceNewConfig = false; - mService.showUnsupportedZoomDialogIfNeededLocked(r); - mService.showAskCompatModeDialogLocked(r); - r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo); - ProfilerInfo profilerInfo = null; - if (mService.mProfileApp != null && mService.mProfileApp.equals(app.processName)) { - if (mService.mProfileProc == null || mService.mProfileProc == app) { - mService.mProfileProc = app; - final String profileFile = mService.mProfileFile; - if (profileFile != null) { - ParcelFileDescriptor profileFd = mService.mProfileFd; - if (profileFd != null) { - try { - profileFd = profileFd.dup(); - } catch (IOException e) { - if (profileFd != null) { - try { - profileFd.close(); - } catch (IOException o) { + app.waitingToKill = null; + r.launchCount++; + r.lastLaunchTime = SystemClock.uptimeMillis(); + + if (DEBUG_ALL) Slog.v(TAG, "Launching: " + r); + + int idx = app.activities.indexOf(r); + if (idx < 0) { + app.activities.add(r); + } + mService.updateLruProcessLocked(app, true, null); + mService.updateOomAdjLocked(); + + if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE || + task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE_PRIV) { + setLockTaskModeLocked(task, LOCK_TASK_MODE_LOCKED, "mLockTaskAuth==LAUNCHABLE", + false); + } + + try { + if (app.thread == null) { + throw new RemoteException(); + } + List<ResultInfo> results = null; + List<ReferrerIntent> newIntents = null; + if (andResume) { + // We don't need to deliver new intents and/or set results if activity is going + // to pause immediately after launch. + results = r.results; + newIntents = r.newIntents; + } + if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, + "Launching: " + r + " icicle=" + r.icicle + " with results=" + results + + " newIntents=" + newIntents + " andResume=" + andResume); + EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY, r.userId, + System.identityHashCode(r), task.taskId, r.shortComponentName); + if (r.isHomeActivity()) { + // Home process is the root process of the task. + mService.mHomeProcess = task.mActivities.get(0).app; + } + mService.notifyPackageUse(r.intent.getComponent().getPackageName(), + PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY); + r.sleeping = false; + r.forceNewConfig = false; + mService.showUnsupportedZoomDialogIfNeededLocked(r); + mService.showAskCompatModeDialogLocked(r); + r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo); + ProfilerInfo profilerInfo = null; + if (mService.mProfileApp != null && mService.mProfileApp.equals(app.processName)) { + if (mService.mProfileProc == null || mService.mProfileProc == app) { + mService.mProfileProc = app; + final String profileFile = mService.mProfileFile; + if (profileFile != null) { + ParcelFileDescriptor profileFd = mService.mProfileFd; + if (profileFd != null) { + try { + profileFd = profileFd.dup(); + } catch (IOException e) { + if (profileFd != null) { + try { + profileFd.close(); + } catch (IOException o) { + } + profileFd = null; } - profileFd = null; } } - } - profilerInfo = new ProfilerInfo(profileFile, profileFd, - mService.mSamplingInterval, mService.mAutoStopProfiler, - mService.mStreamingOutput); + profilerInfo = new ProfilerInfo(profileFile, profileFd, + mService.mSamplingInterval, mService.mAutoStopProfiler, + mService.mStreamingOutput); + } } } - } - app.hasShownUi = true; - app.pendingUiClean = true; - app.forceProcessStateUpTo(mService.mTopProcessState); - // Because we could be starting an Activity in the system process this may not go across - // a Binder interface which would create a new Configuration. Consequently we have to - // always create a new Configuration here. - - final MergedConfiguration mergedConfiguration = new MergedConfiguration( - mService.getGlobalConfiguration(), r.getMergedOverrideConfiguration()); - r.setLastReportedConfiguration(mergedConfiguration); - - logIfTransactionTooLarge(r.intent, r.icicle); - app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken, - System.identityHashCode(r), r.info, - // TODO: Have this take the merged configuration instead of separate global and - // override configs. - mergedConfiguration.getGlobalConfiguration(), - mergedConfiguration.getOverrideConfiguration(), r.compat, - r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle, - r.persistentState, results, newIntents, !andResume, - mService.isNextTransitionForward(), profilerInfo); - - if ((app.info.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) { - // This may be a heavy-weight process! Note that the package - // manager will ensure that only activity can run in the main - // process of the .apk, which is the only thing that will be - // considered heavy-weight. - if (app.processName.equals(app.info.packageName)) { - if (mService.mHeavyWeightProcess != null - && mService.mHeavyWeightProcess != app) { - Slog.w(TAG, "Starting new heavy weight process " + app - + " when already running " - + mService.mHeavyWeightProcess); + app.hasShownUi = true; + app.pendingUiClean = true; + app.forceProcessStateUpTo(mService.mTopProcessState); + // Because we could be starting an Activity in the system process this may not go + // across a Binder interface which would create a new Configuration. Consequently + // we have to always create a new Configuration here. + + final MergedConfiguration mergedConfiguration = new MergedConfiguration( + mService.getGlobalConfiguration(), r.getMergedOverrideConfiguration()); + r.setLastReportedConfiguration(mergedConfiguration); + + logIfTransactionTooLarge(r.intent, r.icicle); + app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken, + System.identityHashCode(r), r.info, + // TODO: Have this take the merged configuration instead of separate global + // and override configs. + mergedConfiguration.getGlobalConfiguration(), + mergedConfiguration.getOverrideConfiguration(), r.compat, + r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle, + r.persistentState, results, newIntents, !andResume, + mService.isNextTransitionForward(), profilerInfo); + + if ((app.info.privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) { + // This may be a heavy-weight process! Note that the package + // manager will ensure that only activity can run in the main + // process of the .apk, which is the only thing that will be + // considered heavy-weight. + if (app.processName.equals(app.info.packageName)) { + if (mService.mHeavyWeightProcess != null + && mService.mHeavyWeightProcess != app) { + Slog.w(TAG, "Starting new heavy weight process " + app + + " when already running " + + mService.mHeavyWeightProcess); + } + mService.mHeavyWeightProcess = app; + Message msg = mService.mHandler.obtainMessage( + ActivityManagerService.POST_HEAVY_NOTIFICATION_MSG); + msg.obj = r; + mService.mHandler.sendMessage(msg); } - mService.mHeavyWeightProcess = app; - Message msg = mService.mHandler.obtainMessage( - ActivityManagerService.POST_HEAVY_NOTIFICATION_MSG); - msg.obj = r; - mService.mHandler.sendMessage(msg); } - } - } catch (RemoteException e) { - if (r.launchFailed) { - // This is the second time we failed -- finish activity - // and give up. - Slog.e(TAG, "Second failure launching " - + r.intent.getComponent().flattenToShortString() - + ", giving up", e); - mService.appDiedLocked(app); - stack.requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null, - "2nd-crash", false); - return false; - } + } catch (RemoteException e) { + if (r.launchFailed) { + // This is the second time we failed -- finish activity + // and give up. + Slog.e(TAG, "Second failure launching " + + r.intent.getComponent().flattenToShortString() + + ", giving up", e); + mService.appDiedLocked(app); + stack.requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null, + "2nd-crash", false); + return false; + } - // This is the first time we failed -- restart process and - // retry. - r.launchFailed = true; - app.activities.remove(r); - throw e; + // This is the first time we failed -- restart process and + // retry. + r.launchFailed = true; + app.activities.remove(r); + throw e; + } + } finally { + endDeferResume(); } r.launchFailed = false; @@ -1519,7 +1536,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D Slog.w(TAG, "Activity " + r + " being launched, but already in LRU list"); } - if (andResume) { + if (andResume && readyToResume()) { // As part of the process of launching, ActivityThread also performs // a resume. stack.minimalResumeActivityLocked(r); @@ -2073,9 +2090,15 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D boolean resumeFocusedStackTopActivityLocked( ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) { + + if (!readyToResume()) { + return false; + } + if (targetStack != null && isFocusedStack(targetStack)) { return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions); } + final ActivityRecord r = mFocusedStack.topRunningActivityLocked(); if (r == null || r.state != RESUMED) { mFocusedStack.resumeTopActivityUncheckedLocked(null, null); @@ -2083,6 +2106,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // Kick off any lingering app transitions form the MoveTaskToFront operation. mFocusedStack.executeAppTransition(targetOptions); } + return false; } @@ -4361,6 +4385,31 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mIsDockMinimized = minimized; } + void wakeUp(String reason) { + mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.server.am:TURN_ON:" + reason); + } + + /** + * Begin deferring resume to avoid duplicate resumes in one pass. + */ + private void beginDeferResume() { + mDeferResumeCount++; + } + + /** + * End deferring resume and determine if resume can be called. + */ + private void endDeferResume() { + mDeferResumeCount--; + } + + /** + * @return True if resume can be called. + */ + private boolean readyToResume() { + return mDeferResumeCount == 0; + } + private final class ActivityStackSupervisorHandler extends Handler { public ActivityStackSupervisorHandler(Looper looper) { diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java index a46c85170ba2..372d80df928f 100644 --- a/services/core/java/com/android/server/am/KeyguardController.java +++ b/services/core/java/com/android/server/am/KeyguardController.java @@ -30,7 +30,6 @@ import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AW import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_GOING_AWAY; import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_OCCLUDE; import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_UNOCCLUDE; -import static com.android.server.wm.AppTransition.TRANSIT_NONE; import static com.android.server.wm.AppTransition.TRANSIT_UNSET; import android.os.IBinder; @@ -144,6 +143,13 @@ class KeyguardController { failCallback(callback); return; } + + // If the client has requested to dismiss the keyguard and the Activity has the flag to + // turn the screen on, wakeup the screen if it's the top Activity. + if (activityRecord.getTurnScreenOnFlag() && activityRecord.isTopRunningActivity()) { + mStackSupervisor.wakeUp("dismissKeyguard"); + } + mWindowManager.dismissKeyguard(callback); } diff --git a/tests/ShowWhenLockedApp/Android.mk b/tests/ShowWhenLockedApp/Android.mk new file mode 100644 index 000000000000..006416791dd9 --- /dev/null +++ b/tests/ShowWhenLockedApp/Android.mk @@ -0,0 +1,10 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := ShowWhenLocked + +LOCAL_MODULE_TAGS := tests + +include $(BUILD_PACKAGE)
\ No newline at end of file diff --git a/tests/ShowWhenLockedApp/AndroidManifest.xml b/tests/ShowWhenLockedApp/AndroidManifest.xml new file mode 100644 index 000000000000..a872e061526f --- /dev/null +++ b/tests/ShowWhenLockedApp/AndroidManifest.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.showwhenlocked"> + <application android:label="ShowWhenLocked"> + <activity android:name=".ShowWhenLockedActivity" + android:showWhenLocked="true" + android:turnScreenOn="true" + android:launchMode="singleTask"> + <intent-filter> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/tests/ShowWhenLockedApp/src/com/android/showwhenlocked/ShowWhenLockedActivity.java b/tests/ShowWhenLockedApp/src/com/android/showwhenlocked/ShowWhenLockedActivity.java new file mode 100644 index 000000000000..f71483182676 --- /dev/null +++ b/tests/ShowWhenLockedApp/src/com/android/showwhenlocked/ShowWhenLockedActivity.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.showwhenlocked; + +import android.app.Activity; +import android.app.KeyguardManager; +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; + +/** + * Sample app to test the manifest attrs {@link android.R.attr#showWhenLocked} + * and {@link android.R.attr#turnScreenOn}. + * + * <p>Run with adb shell am start -n com.android.showwhenlocked/.ShowWhenLockedActivity to test + * when the phone has a keyguard enabled and/or the screen is off. + * + * Use the extra {@link #EXTRA_SHOW_WHEN_LOCKED} and {@link #EXTRA_TURN_SCREEN_ON} to test + * multiple scenarios. + * + * Ex: adb shell am start -n com.android.showwhenlocked/.ShowWhenLockedActivity --ez \ + * showWhenLocked false \ + * setTurnScreenOnAtStop false + * + * Note: Behavior may change if values are set to true after the Activity is already created + * and only brought to the front. For example, turnScreenOn only takes effect on the next launch + * if set using the extra value. + */ +public class ShowWhenLockedActivity extends Activity { + private static final String TAG = ShowWhenLockedActivity.class.getSimpleName(); + + /** + * The value set for this extra sets {@link #setShowWhenLocked(boolean)} as soon as the app + * is launched. This may cause delays in when the value set takes affect. + */ + private static final String EXTRA_SHOW_WHEN_LOCKED = "showWhenLocked"; + + /** + * The value set for this extra sets {@link #setTurnScreenOn(boolean)} as soon as the app + * is launched. This may cause delays in when the value set takes affect. + */ + private static final String EXTRA_TURN_SCREEN_ON = "turnScreenOn"; + + /** + * The value set for this extra will call {@link #setShowWhenLocked(boolean)} at onStop so + * it take effect on the next launch. + */ + private static final String EXTRA_SHOW_WHEN_LOCKED_STOP = "setShowWhenLockedAtStop"; + + /** + * The value set for this extra will call {@link #setTurnScreenOn(boolean)} at onStop so + * it take effect on the next launch. + */ + private static final String EXTRA_TURN_SCREEN_ON_STOP = "setTurnScreenOnAtStop"; + + /** + * The value set for this extra will call + * {@link KeyguardManager#requestDismissKeyguard(Activity, KeyguardManager.KeyguardDismissCallback)} + * as soon as the app is launched. + */ + private static final String EXTRA_DISMISS_KEYGUARD = "dismissKeyguard"; + + private boolean showWhenLockedAtStop = true; + private boolean turnScreenOnAtStop = true; + + private KeyguardManager mKeyguardManager; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Log.v(TAG, "onCreate"); + mKeyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE); + handleExtras(getIntent().getExtras()); + } + + @Override + protected void onStart() { + super.onStart(); + Log.v(TAG, "onStart"); + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + handleExtras(intent.getExtras()); + } + + @Override + protected void onResume() { + super.onResume(); + Log.v(TAG, "onResume"); + } + + @Override + protected void onPause() { + super.onPause(); + Log.v(TAG, "onPause"); + } + + @Override + protected void onStop() { + super.onStop(); + Log.v(TAG, "onStop"); + + setShowWhenLocked(showWhenLockedAtStop); + setTurnScreenOn(turnScreenOnAtStop); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + Log.v(TAG, "onDestroy"); + } + + private void handleExtras(Bundle extras) { + if (extras == null) { + return; + } + + if (extras.containsKey(EXTRA_SHOW_WHEN_LOCKED)) { + boolean showWhenLocked = extras.getBoolean(EXTRA_SHOW_WHEN_LOCKED, true); + Log.v(TAG, "Setting showWhenLocked to " + showWhenLocked); + setShowWhenLocked(showWhenLocked); + } + + if (extras.containsKey(EXTRA_TURN_SCREEN_ON)) { + boolean turnScreenOn = extras.getBoolean(EXTRA_TURN_SCREEN_ON, true); + Log.v(TAG, "Setting turnScreenOn to " + turnScreenOn); + setTurnScreenOn(turnScreenOn); + } + + if (extras.containsKey(EXTRA_SHOW_WHEN_LOCKED_STOP)) { + showWhenLockedAtStop = extras.getBoolean(EXTRA_SHOW_WHEN_LOCKED_STOP, true); + Log.v(TAG, "Setting showWhenLockedAtStop to " + showWhenLockedAtStop); + } + + if (extras.containsKey(EXTRA_TURN_SCREEN_ON_STOP)) { + turnScreenOnAtStop = extras.getBoolean(EXTRA_TURN_SCREEN_ON_STOP, true); + Log.v(TAG, "Setting turnScreenOnAtStop to " + turnScreenOnAtStop); + } + + if (extras.containsKey(EXTRA_DISMISS_KEYGUARD)) { + if (extras.getBoolean(EXTRA_DISMISS_KEYGUARD, false)) { + Log.v(TAG, "Requesting dismiss keyguard"); + mKeyguardManager.requestDismissKeyguard(this, null); + } + } + } +} + |