diff options
author | chaviw <chaviw@google.com> | 2017-06-13 12:05:44 -0700 |
---|---|---|
committer | chaviw <chaviw@google.com> | 2017-06-29 13:33:43 -0700 |
commit | 59b9885bc8b781b6312adedd67c2c7c270f9213c (patch) | |
tree | ef828c70dfe767b2be66ca43cee920e8fd38f2eb | |
parent | e3bb95dddb3849d3a54538f507bfe83f6b74cb62 (diff) |
Added Activity flags to show on lock screen.
Added two new flags to the Activity to turn the screen on and
show on the lock screen. These can be used instead of the Window flags
LayouParams.FLAG_TURN_SCREEN_ON and LayoutParams.FLAG_SHOW_WHEN_LOCKED
to prevent the double onStart/onResume lifecycle events.
The flags can be set as an attr for the Activity in the AndroidManifest
using android:showWhenLocked="true" and android:turnScreenOn="true".
They can also be set through methods in the Activity class using
setShowWhenLocked(true) and setTurnScreen(true).
Fixes: 36850100
Test: Created sample application, tests/ShowWhenLockedApp, that set the
flags in the manifest and code. Tested multiple scenarios to
launch the Activity with the flags set and unset.
Test: cts-tradefed run commandAndExit cts-dev --module CtsServicesHostTestCases -t android.server.cts.KeyguardTransitionTests
Test: cts-tradefed run commandAndExit cts-dev --module CtsServicesHostTestCases -t android.server.cts.ActivityManagerActivityVisibilityTests
Test: cts-tradefed run commandAndExit cts-dev --module CtsServicesHostTestCases -t android.server.cts.KeyguardTests
Change-Id: I44f0e313df4531d49c7ac56108b6bf80e41fefc1
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); + } + } + } +} + |