summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt8
-rw-r--r--api/system-current.txt8
-rw-r--r--api/test-current.txt8
-rw-r--r--core/java/android/app/Activity.java47
-rw-r--r--core/java/android/app/IActivityManager.aidl3
-rw-r--r--core/java/android/app/KeyguardManager.java3
-rw-r--r--core/java/android/content/pm/ActivityInfo.java17
-rw-r--r--core/java/android/content/pm/PackageParser.java9
-rw-r--r--core/java/android/view/WindowManager.java11
-rw-r--r--core/res/res/values/attrs_manifest.xml33
-rw-r--r--core/res/res/values/public.xml2
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java33
-rw-r--r--services/core/java/com/android/server/am/ActivityRecord.java69
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java12
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java375
-rw-r--r--services/core/java/com/android/server/am/KeyguardController.java8
-rw-r--r--tests/ShowWhenLockedApp/Android.mk10
-rw-r--r--tests/ShowWhenLockedApp/AndroidManifest.xml31
-rw-r--r--tests/ShowWhenLockedApp/src/com/android/showwhenlocked/ShowWhenLockedActivity.java164
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);
+ }
+ }
+ }
+}
+