Let external activities run when the primary display is off
- Make activity sleep state independent of power manager wakefulness
state. The state is now entirely dependent on sleep tokens (and the
voice interactor).
- Make sleep tokens operate on a per-display basis (and convert the
keyguard to a sleep token).
- Make ActivityStackSupervisor acquire/release sleep tokens for
non-default displays when the displays are turned on/off.
- Make WindowManagerService.okToDisplay operate on a per-display basis.
Bug: 34280365
Test: android.server.cts.ActivityManagerDisplayTests
Test: #testExternalDisplayActivityTurnPrimaryOff
Test: #testLaunchExternalDisplayActivityWhilePrimaryOff
Test: #testExternalDisplayToggleState
Change-Id: I92086d7006a67b4b4f320c9bb3aa606954f85012
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ddc524f..ea52119 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1344,7 +1344,7 @@
* Set while we are running a voice interaction. This overrides
* sleeping while it is active.
*/
- private IVoiceInteractionSession mRunningVoice;
+ IVoiceInteractionSession mRunningVoice;
/**
* For some direct access we need to power manager.
@@ -1364,13 +1364,6 @@
private int mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
/**
- * A list of tokens that cause the top activity to be put to sleep.
- * They are used by components that may hide and block interaction with underlying
- * activities.
- */
- final ArrayList<SleepToken> mSleepTokens = new ArrayList<SleepToken>();
-
- /**
* Set if we are shutting down the system, similar to sleeping.
*/
boolean mShuttingDown = false;
@@ -12393,7 +12386,19 @@
void onWakefulnessChanged(int wakefulness) {
synchronized(this) {
mWakefulness = wakefulness;
- updateSleepIfNeededLocked();
+
+ // Also update state in a special way for running foreground services UI.
+ switch (mWakefulness) {
+ case PowerManagerInternal.WAKEFULNESS_ASLEEP:
+ case PowerManagerInternal.WAKEFULNESS_DREAMING:
+ case PowerManagerInternal.WAKEFULNESS_DOZING:
+ mServices.updateScreenStateLocked(false /* screenOn */);
+ break;
+ case PowerManagerInternal.WAKEFULNESS_AWAKE:
+ default:
+ mServices.updateScreenStateLocked(true /* screenOn */);
+ break;
+ }
}
}
@@ -12413,14 +12418,24 @@
}
void updateSleepIfNeededLocked() {
- final boolean shouldSleep = shouldSleepLocked();
- if (mSleeping && !shouldSleep) {
- mSleeping = false;
- startTimeTrackingFocusedActivityLocked();
- mTopProcessState = ActivityManager.PROCESS_STATE_TOP;
- mStackSupervisor.comeOutOfSleepIfNeededLocked();
- sendNotifyVrManagerOfSleepState(false);
- updateOomAdjLocked();
+ final boolean shouldSleep = !mStackSupervisor.hasAwakeDisplay();
+ final boolean wasSleeping = mSleeping;
+
+ if (!shouldSleep) {
+ // If wasSleeping is true, we need to wake up activity manager state from when
+ // we started sleeping. In either case, we need to apply the sleep tokens, which
+ // will wake up stacks or put them to sleep as appropriate.
+ if (wasSleeping) {
+ mSleeping = false;
+ startTimeTrackingFocusedActivityLocked();
+ mTopProcessState = ActivityManager.PROCESS_STATE_TOP;
+ mStackSupervisor.comeOutOfSleepIfNeededLocked();
+ }
+ mStackSupervisor.applySleepTokensLocked(true /* applyToStacks */);
+ if (wasSleeping) {
+ sendNotifyVrManagerOfSleepState(false);
+ updateOomAdjLocked();
+ }
} else if (!mSleeping && shouldSleep) {
mSleeping = true;
if (mCurAppTimeTracker != null) {
@@ -12431,40 +12446,6 @@
sendNotifyVrManagerOfSleepState(true);
updateOomAdjLocked();
}
-
- // Also update state in a special way for running foreground services UI.
- switch (mWakefulness) {
- case PowerManagerInternal.WAKEFULNESS_ASLEEP:
- case PowerManagerInternal.WAKEFULNESS_DREAMING:
- case PowerManagerInternal.WAKEFULNESS_DOZING:
- mServices.updateScreenStateLocked(false);
- break;
- case PowerManagerInternal.WAKEFULNESS_AWAKE:
- default:
- mServices.updateScreenStateLocked(true);
- break;
- }
- }
-
- private boolean shouldSleepLocked() {
- // Resume applications while running a voice interactor.
- if (mRunningVoice != null) {
- return false;
- }
-
- // TODO: Transform the lock screen state into a sleep token instead.
- switch (mWakefulness) {
- case PowerManagerInternal.WAKEFULNESS_AWAKE:
- case PowerManagerInternal.WAKEFULNESS_DREAMING:
- // Pause applications whenever the lock screen is shown or any sleep
- // tokens have been acquired.
- return mKeyguardController.isKeyguardShowing() || !mSleepTokens.isEmpty();
- case PowerManagerInternal.WAKEFULNESS_DOZING:
- case PowerManagerInternal.WAKEFULNESS_ASLEEP:
- default:
- // If we're asleep then pause applications unconditionally.
- return true;
- }
}
/** Pokes the task persister. */
@@ -12505,6 +12486,7 @@
synchronized(this) {
mShuttingDown = true;
+ mStackSupervisor.prepareForShutdownLocked();
updateEventDispatchingLocked();
timedout = mStackSupervisor.shutdownLocked(timeout);
}
@@ -14920,6 +14902,14 @@
this, in, out, err, args, callback, resultReceiver);
}
+ SleepToken acquireSleepToken(String tag, int displayId) {
+ synchronized (this) {
+ final SleepToken token = mStackSupervisor.createSleepTokenLocked(tag, displayId);
+ updateSleepIfNeededLocked();
+ return token;
+ }
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
@@ -15816,7 +15806,7 @@
if (dumpPackage == null) {
pw.println(" mWakefulness="
+ PowerManagerInternal.wakefulnessToString(mWakefulness));
- pw.println(" mSleepTokens=" + mSleepTokens);
+ pw.println(" mSleepTokens=" + mStackSupervisor.mSleepTokens);
pw.println(" mSleeping=" + mSleeping);
pw.println(" mShuttingDown=" + mShuttingDown + " mTestPssMode=" + mTestPssMode);
if (mRunningVoice != null) {
@@ -23777,15 +23767,9 @@
}
@Override
- public SleepToken acquireSleepToken(String tag) {
+ public SleepToken acquireSleepToken(String tag, int displayId) {
Preconditions.checkNotNull(tag);
-
- synchronized (ActivityManagerService.this) {
- SleepTokenImpl token = new SleepTokenImpl(tag);
- mSleepTokens.add(token);
- updateSleepIfNeededLocked();
- return token;
- }
+ return ActivityManagerService.this.acquireSleepToken(tag, displayId);
}
@Override
@@ -24222,30 +24206,6 @@
}
}
- private final class SleepTokenImpl extends SleepToken {
- private final String mTag;
- private final long mAcquireTime;
-
- public SleepTokenImpl(String tag) {
- mTag = tag;
- mAcquireTime = SystemClock.uptimeMillis();
- }
-
- @Override
- public void release() {
- synchronized (ActivityManagerService.this) {
- if (mSleepTokens.remove(this)) {
- updateSleepIfNeededLocked();
- }
- }
- }
-
- @Override
- public String toString() {
- return "{\"" + mTag + "\", acquire at " + TimeUtils.formatUptime(mAcquireTime) + "}";
- }
- }
-
/**
* An implementation of IAppTask, that allows an app to manage its own tasks via
* {@link android.app.ActivityManager.AppTask}. We keep track of the callingUid to ensure that
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 2aa5350..cf93f64 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1340,7 +1340,9 @@
intent, getUriPermissionsLocked(), userId);
final ReferrerIntent rintent = new ReferrerIntent(intent, referrer);
boolean unsent = true;
- final boolean isTopActivityWhileSleeping = service.isSleepingLocked() && isTopRunningActivity();
+ final ActivityStack stack = getStack();
+ final boolean isTopActivityWhileSleeping = isTopRunningActivity()
+ && (stack != null ? stack.shouldSleepActivities() : service.isSleepingLocked());
// 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
@@ -1730,7 +1732,7 @@
// 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();
+ stack.checkReadyForSleep();
}
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 9925ba0..b1095e4 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1163,10 +1163,25 @@
}
}
+ void checkReadyForSleep() {
+ if (shouldSleepActivities() && goToSleepIfPossible(false /* shuttingDown */)) {
+ mStackSupervisor.checkReadyForSleepLocked(true /* allowDelay */);
+ }
+ }
+
/**
+ * Tries to put the activities in the stack to sleep.
+ *
+ * If the stack is not in a state where its activities can be put to sleep, this function will
+ * start any necessary actions to move the stack into such a state. It is expected that this
+ * function get called again when those actions complete.
+ *
+ * @param shuttingDown true when the called because the device is shutting down.
* @return true if something must be done before going to sleep.
*/
- boolean checkReadyForSleepLocked() {
+ boolean goToSleepIfPossible(boolean shuttingDown) {
+ boolean shouldSleep = true;
+
if (mResumedActivity != null) {
// Still have something resumed; can't sleep until it is paused.
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep needs to pause " + mResumedActivity);
@@ -1176,26 +1191,47 @@
// If we are in the middle of resuming the top activity in
// {@link #resumeTopActivityUncheckedLocked}, mResumedActivity will be set but not
// resumed yet. We must not proceed pausing the activity here. This method will be
- // called again if necessary as part of
+ // called again if necessary as part of {@link #checkReadyForSleep} or
// {@link ActivityStackSupervisor#checkReadyForSleepLocked}.
if (mStackSupervisor.inResumeTopActivity) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "In the middle of resuming top activity "
+ mResumedActivity);
- return true;
+ } else {
+ startPausingLocked(false, true, null, false);
}
-
- startPausingLocked(false, true, null, false);
- return true;
- }
- if (mPausingActivity != null) {
+ shouldSleep = false ;
+ } else if (mPausingActivity != null) {
// Still waiting for something to pause; can't sleep yet.
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still waiting to pause " + mPausingActivity);
- return true;
+ shouldSleep = false;
}
- return false;
+
+ if (!shuttingDown) {
+ if (containsActivityFromStack(mStackSupervisor.mStoppingActivities)) {
+ // Still need to tell some activities to stop; can't sleep yet.
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to stop "
+ + mStackSupervisor.mStoppingActivities.size() + " activities");
+
+ mStackSupervisor.scheduleIdleLocked();
+ shouldSleep = false;
+ }
+
+ if (containsActivityFromStack(mStackSupervisor.mGoingToSleepActivities)) {
+ // Still need to tell some activities to sleep; can't sleep yet.
+ if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to sleep "
+ + mStackSupervisor.mGoingToSleepActivities.size() + " activities");
+ shouldSleep = false;
+ }
+ }
+
+ if (shouldSleep) {
+ goToSleep();
+ }
+
+ return !shouldSleep;
}
- void goToSleep() {
+ private void goToSleep() {
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
// Make sure any paused or stopped but visible activities are now sleeping.
@@ -1212,6 +1248,15 @@
}
}
+ private boolean containsActivityFromStack(List<ActivityRecord> rs) {
+ for (ActivityRecord r : rs) {
+ if (r.getStack() == this) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Schedule a pause timeout in case the app doesn't respond. We don't give it much time because
* this directly impacts the responsiveness seen by the user.
@@ -1244,7 +1289,7 @@
if (mPausingActivity != null) {
Slog.wtf(TAG, "Going to pause when pause is already pending for " + mPausingActivity
+ " state=" + mPausingActivity.state);
- if (!mService.isSleepingLocked()) {
+ if (!shouldSleepActivities()) {
// Avoid recursion among check for sleep and complete pause during sleeping.
// Because activity will be paused immediately after resume, just let pause
// be completed by the order of activity paused from clients.
@@ -1404,7 +1449,7 @@
// We can't clobber it, because the stop confirmation will not be handled.
// We don't need to schedule another stop, we only need to let it happen.
prev.state = STOPPING;
- } else if (!prev.visible || mService.isSleepingOrShuttingDownLocked()) {
+ } else if (!prev.visible || shouldSleepOrShutDownActivities()) {
// Clear out any deferred client hide we might currently have.
prev.setDeferHidingClient(false);
// If we were visible then resumeTopActivities will release resources before
@@ -1426,10 +1471,10 @@
if (resumeNext) {
final ActivityStack topStack = mStackSupervisor.getFocusedStack();
- if (!mService.isSleepingOrShuttingDownLocked()) {
+ if (!topStack.shouldSleepOrShutDownActivities()) {
mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
} else {
- mStackSupervisor.checkReadyForSleepLocked();
+ checkReadyForSleep();
ActivityRecord top = topStack.topRunningActivityLocked();
if (top == null || (prev != null && top != prev)) {
// If there are no more activities available to run, do resume anyway to start
@@ -1495,7 +1540,7 @@
mStackSupervisor.scheduleIdleTimeoutLocked(r);
}
} else {
- mStackSupervisor.checkReadyForSleepLocked();
+ checkReadyForSleep();
}
}
@@ -2204,7 +2249,7 @@
// is skipped.
final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
if (next == null || !next.canTurnScreenOn()) {
- mStackSupervisor.checkReadyForSleepLocked();
+ checkReadyForSleep();
}
return result;
@@ -2289,7 +2334,7 @@
// If we are sleeping, and there is no resumed activity, and the top
// activity is paused, well that is the state we want.
- if (mService.isSleepingOrShuttingDownLocked()
+ if (shouldSleepOrShutDownActivities()
&& mLastPausedActivity == next
&& mStackSupervisor.allPausedActivitiesComplete()) {
// Make sure we have executed any pending transitions, since there
@@ -2381,7 +2426,7 @@
// If the most recent activity was noHistory but was only stopped rather
// than stopped+finished because the device went to sleep, we need to make
// sure to finish it as we're making a new activity topmost.
- if (mService.isSleepingLocked() && mLastNoHistoryActivity != null &&
+ if (shouldSleepActivities() && mLastNoHistoryActivity != null &&
!mLastNoHistoryActivity.finishing) {
if (DEBUG_STATES) Slog.d(TAG_STATES,
"no-history finish of " + mLastNoHistoryActivity + " on new resume");
@@ -3384,7 +3429,7 @@
if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
if (!r.finishing) {
- if (!mService.isSleepingLocked()) {
+ if (!shouldSleepActivities()) {
if (DEBUG_STATES) Slog.d(TAG_STATES, "no-history finish of " + r);
if (requestFinishActivityLocked(r.appToken, Activity.RESULT_CANCELED, null,
"stop-no-history", false)) {
@@ -3416,7 +3461,7 @@
EventLogTags.writeAmStopActivity(
r.userId, System.identityHashCode(r), r.shortComponentName);
r.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags);
- if (mService.isSleepingOrShuttingDownLocked()) {
+ if (shouldSleepOrShutDownActivities()) {
r.setSleeping(true);
}
Message msg = mHandler.obtainMessage(STOP_TIMEOUT_MSG, r);
@@ -5262,4 +5307,13 @@
mNoAnimActivities.clear();
ActivityOptions.abort(options);
}
+
+ boolean shouldSleepActivities() {
+ final ActivityStackSupervisor.ActivityDisplay display = getDisplay();
+ return display != null ? display.isSleeping() : mService.isSleepingLocked();
+ }
+
+ boolean shouldSleepOrShutDownActivities() {
+ return shouldSleepActivities() || mService.isShuttingDownLocked();
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 5f42cdb..8712775 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -105,6 +105,7 @@
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackId;
import android.app.ActivityManager.StackInfo;
+import android.app.ActivityManagerInternal.SleepToken;
import android.app.ActivityOptions;
import android.app.AppOpsManager;
import android.app.ProfilerInfo;
@@ -156,6 +157,7 @@
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
+import android.util.TimeUtils;
import android.view.Display;
import com.android.internal.annotations.VisibleForTesting;
@@ -177,6 +179,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -375,9 +378,6 @@
* is being brought in front of us. */
boolean mUserLeaving = false;
- /** Set when we have taken too long waiting to go to sleep. */
- boolean mSleepTimeout = false;
-
/**
* We don't want to allow the device to go to sleep while in the process
* of launching an activity. This is primarily to allow alarm intent
@@ -393,6 +393,13 @@
*/
PowerManager.WakeLock mGoingToSleep;
+ /**
+ * A list of tokens that cause the top activity to be put to sleep.
+ * They are used by components that may hide and block interaction with underlying
+ * activities.
+ */
+ final ArrayList<SleepToken> mSleepTokens = new ArrayList<SleepToken>();
+
/** Stack id of the front stack when user switched, indexed by userId. */
SparseIntArray mUserStackInFront = new SparseIntArray(2);
@@ -3120,6 +3127,16 @@
return null;
}
+ boolean hasAwakeDisplay() {
+ for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+ final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+ if (!display.shouldSleep()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
void goingToSleepLocked() {
scheduleSleepTimeout();
if (!mGoingToSleep.isHeld()) {
@@ -3132,7 +3149,16 @@
mService.mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
}
}
- checkReadyForSleepLocked();
+
+ applySleepTokensLocked(false /* applyToStacks */);
+
+ checkReadyForSleepLocked(true /* allowDelay */);
+ }
+
+ void prepareForShutdownLocked() {
+ for (int i = 0; i < mActivityDisplays.size(); i++) {
+ createSleepTokenLocked("shutdown", mActivityDisplays.keyAt(i));
+ }
}
boolean shutdownLocked(int timeout) {
@@ -3145,7 +3171,8 @@
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
- cantShutdown |= stacks.get(stackNdx).checkReadyForSleepLocked();
+ cantShutdown |=
+ stacks.get(stackNdx).goToSleepIfPossible(true /* shuttingDown */);
}
}
if (cantShutdown) {
@@ -3166,8 +3193,7 @@
}
// Force checkReadyForSleep to complete.
- mSleepTimeout = true;
- checkReadyForSleepLocked();
+ checkReadyForSleepLocked(false /* allowDelay */);
return timedout;
}
@@ -3177,54 +3203,75 @@
if (mGoingToSleep.isHeld()) {
mGoingToSleep.release();
}
+ }
+
+ void applySleepTokensLocked(boolean applyToStacks) {
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+ // Set the sleeping state of the display.
+ final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+ final boolean displayShouldSleep = display.shouldSleep();
+ if (displayShouldSleep == display.isSleeping()) {
+ continue;
+ }
+ display.setIsSleeping(displayShouldSleep);
+
+ if (!applyToStacks) {
+ continue;
+ }
+
+ // Set the sleeping state of the stacks on the display.
+ final ArrayList<ActivityStack> stacks = display.mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
- stack.awakeFromSleepingLocked();
- if (isFocusedStack(stack)) {
- resumeFocusedStackTopActivityLocked();
+ if (displayShouldSleep) {
+ stack.goToSleepIfPossible(false /* shuttingDown */);
+ } else {
+ stack.awakeFromSleepingLocked();
+ if (isFocusedStack(stack)) {
+ resumeFocusedStackTopActivityLocked();
+ }
+ }
+ }
+
+ if (displayShouldSleep || mGoingToSleepActivities.isEmpty()) {
+ continue;
+ }
+ // The display is awake now, so clean up the going to sleep list.
+ for (Iterator<ActivityRecord> it = mGoingToSleepActivities.iterator(); it.hasNext(); ) {
+ final ActivityRecord r = it.next();
+ if (r.getDisplayId() == display.mDisplayId) {
+ it.remove();
}
}
}
- mGoingToSleepActivities.clear();
}
void activitySleptLocked(ActivityRecord r) {
mGoingToSleepActivities.remove(r);
- checkReadyForSleepLocked();
+ final ActivityStack s = r.getStack();
+ if (s != null) {
+ s.checkReadyForSleep();
+ } else {
+ checkReadyForSleepLocked(true);
+ }
}
- void checkReadyForSleepLocked() {
+ void checkReadyForSleepLocked(boolean allowDelay) {
if (!mService.isSleepingOrShuttingDownLocked()) {
// Do not care.
return;
}
- if (!mSleepTimeout) {
+ if (allowDelay) {
boolean dontSleep = false;
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+ final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);
+ final ArrayList<ActivityStack> stacks = display.mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
- dontSleep |= stacks.get(stackNdx).checkReadyForSleepLocked();
+ dontSleep |= stacks.get(stackNdx).goToSleepIfPossible(false /* shuttingDown */);
}
}
- if (mStoppingActivities.size() > 0) {
- // Still need to tell some activities to stop; can't sleep yet.
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to stop "
- + mStoppingActivities.size() + " activities");
- scheduleIdleLocked();
- dontSleep = true;
- }
-
- if (mGoingToSleepActivities.size() > 0) {
- // Still need to tell some activities to sleep; can't sleep yet.
- if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to sleep "
- + mGoingToSleepActivities.size() + " activities");
- dontSleep = true;
- }
-
if (dontSleep) {
return;
}
@@ -3233,13 +3280,6 @@
// Send launch end powerhint before going sleep
mService.mActivityStarter.sendPowerHintForLaunchEndIfNeeded();
- for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
- final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
- for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
- stacks.get(stackNdx).goToSleep();
- }
- }
-
removeSleepTimeouts();
if (mGoingToSleep.isHeld()) {
@@ -3510,21 +3550,27 @@
s.setVisibility(false);
}
}
- if ((!waitingVisible || mService.isSleepingOrShuttingDownLocked()) && remove) {
- if (!processPausingActivities && s.state == PAUSING) {
- // Defer processing pausing activities in this iteration and reschedule
- // a delayed idle to reprocess it again
- removeTimeoutsForActivityLocked(idleActivity);
- scheduleIdleTimeoutLocked(idleActivity);
- continue;
- }
+ if (remove) {
+ final ActivityStack stack = s.getStack();
+ final boolean shouldSleepOrShutDown = stack != null
+ ? stack.shouldSleepOrShutDownActivities()
+ : mService.isSleepingOrShuttingDownLocked();
+ if (!waitingVisible || shouldSleepOrShutDown) {
+ if (!processPausingActivities && s.state == PAUSING) {
+ // Defer processing pausing activities in this iteration and reschedule
+ // a delayed idle to reprocess it again
+ removeTimeoutsForActivityLocked(idleActivity);
+ scheduleIdleTimeoutLocked(idleActivity);
+ continue;
+ }
- if (DEBUG_STATES) Slog.v(TAG, "Ready to stop: " + s);
- if (stops == null) {
- stops = new ArrayList<>();
+ if (DEBUG_STATES) Slog.v(TAG, "Ready to stop: " + s);
+ if (stops == null) {
+ stops = new ArrayList<>();
+ }
+ stops.add(s);
+ mStoppingActivities.remove(activityNdx);
}
- stops.add(s);
- mStoppingActivities.remove(activityNdx);
}
}
@@ -3577,7 +3623,6 @@
public void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("mFocusedStack=" + mFocusedStack);
pw.print(" mLastFocusedStack="); pw.println(mLastFocusedStack);
- pw.print(prefix); pw.println("mSleepTimeout=" + mSleepTimeout);
pw.print(prefix);
pw.println("mCurTaskIdForUser=" + mCurTaskIdForUser);
pw.print(prefix); pw.println("mUserStackInFront=" + mUserStackInFront);
@@ -3674,6 +3719,8 @@
stackHeader.append("\n");
stackHeader.append(" mFullscreen=" + stack.mFullscreen);
stackHeader.append("\n");
+ stackHeader.append(" isSleeping=" + stack.shouldSleepActivities());
+ stackHeader.append("\n");
stackHeader.append(" mBounds=" + stack.mBounds);
final boolean printedStackHeader = stack.dumpActivitiesLocked(fd, pw, dumpAll,
@@ -3725,8 +3772,6 @@
" Activities waiting for another to become visible:", null);
printed |= dumpHistoryList(fd, pw, mGoingToSleepActivities, " ", "Sleep", false, !dumpAll,
false, dumpPackage, true, " Activities waiting to sleep:", null);
- printed |= dumpHistoryList(fd, pw, mGoingToSleepActivities, " ", "Sleep", false, !dumpAll,
- false, dumpPackage, true, " Activities waiting to sleep:", null);
return printed;
}
@@ -3837,7 +3882,6 @@
}
void removeSleepTimeouts() {
- mSleepTimeout = false;
mHandler.removeMessages(SLEEP_TIMEOUT_MSG);
}
@@ -3939,6 +3983,9 @@
moveTasksToFullscreenStackLocked(stack.getStackId(), true /* onTop */);
}
}
+
+ releaseSleepTokens(activityDisplay);
+
mActivityDisplays.remove(displayId);
mWindowManager.onDisplayRemoved(displayId);
}
@@ -3949,12 +3996,60 @@
synchronized (mService) {
ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
if (activityDisplay != null) {
+ // The window policy is responsible for stopping activities on the default display
+ if (displayId != Display.DEFAULT_DISPLAY) {
+ int displayState = activityDisplay.mDisplay.getState();
+ if (displayState == Display.STATE_OFF && activityDisplay.mOffToken == null) {
+ activityDisplay.mOffToken =
+ mService.acquireSleepToken("Display-off", displayId);
+ } else if (displayState == Display.STATE_ON
+ && activityDisplay.mOffToken != null) {
+ activityDisplay.mOffToken.release();
+ activityDisplay.mOffToken = null;
+ }
+ }
// TODO: Update the bounds.
}
mWindowManager.onDisplayChanged(displayId);
}
}
+ SleepToken createSleepTokenLocked(String tag, int displayId) {
+ ActivityDisplay display = mActivityDisplays.get(displayId);
+ if (display == null) {
+ throw new IllegalArgumentException("Invalid display: " + displayId);
+ }
+
+ final SleepTokenImpl token = new SleepTokenImpl(tag, displayId);
+ mSleepTokens.add(token);
+ display.mAllSleepTokens.add(token);
+ return token;
+ }
+
+ private void removeSleepTokenLocked(SleepTokenImpl token) {
+ mSleepTokens.remove(token);
+
+ ActivityDisplay display = mActivityDisplays.get(token.mDisplayId);
+ if (display != null) {
+ display.mAllSleepTokens.remove(token);
+ if (display.mAllSleepTokens.isEmpty()) {
+ mService.updateSleepIfNeededLocked();
+ }
+ }
+ }
+
+ private void releaseSleepTokens(ActivityDisplay display) {
+ if (display.mAllSleepTokens.isEmpty()) {
+ return;
+ }
+ for (SleepTokenImpl token : display.mAllSleepTokens) {
+ mSleepTokens.remove(token);
+ }
+ display.mAllSleepTokens.clear();
+
+ mService.updateSleepIfNeededLocked();
+ }
+
private StackInfo getStackInfoLocked(ActivityStack stack) {
final int displayId = stack.mDisplayId;
final ActivityDisplay display = mActivityDisplays.get(displayId);
@@ -4260,9 +4355,9 @@
void activityRelaunchedLocked(IBinder token) {
mWindowManager.notifyAppRelaunchingFinished(token);
- if (mService.isSleepingOrShuttingDownLocked()) {
- final ActivityRecord r = ActivityRecord.isInStackLocked(token);
- if (r != null) {
+ final ActivityRecord r = ActivityRecord.isInStackLocked(token);
+ if (r != null) {
+ if (r.getStack().shouldSleepOrShutDownActivities()) {
r.setSleeping(true, true);
}
}
@@ -4414,8 +4509,7 @@
synchronized (mService) {
if (mService.isSleepingOrShuttingDownLocked()) {
Slog.w(TAG, "Sleep timeout! Sleeping now.");
- mSleepTimeout = true;
- checkReadyForSleepLocked();
+ checkReadyForSleepLocked(false /* allowDelay */);
}
}
} break;
@@ -4540,6 +4634,13 @@
/** Array of all UIDs that are present on the display. */
private IntArray mDisplayAccessUIDs = new IntArray();
+ /** All tokens used to put activities on this stack to sleep (including mOffToken) */
+ final ArrayList<SleepTokenImpl> mAllSleepTokens = new ArrayList<>();
+ /** The token acquired by ActivityStackSupervisor to put stacks on the display to sleep */
+ SleepToken mOffToken;
+
+ private boolean mSleeping;
+
@VisibleForTesting
ActivityDisplay() {
mActivityDisplays.put(mDisplayId, this);
@@ -4564,12 +4665,14 @@
if (DEBUG_STACK) Slog.v(TAG_STACK, "attachStack: attaching " + stack
+ " to displayId=" + mDisplayId + " position=" + position);
mStacks.add(position, stack);
+ mService.updateSleepIfNeededLocked();
}
void detachStack(ActivityStack stack) {
if (DEBUG_STACK) Slog.v(TAG_STACK, "detachStack: detaching " + stack
+ " from displayId=" + mDisplayId);
mStacks.remove(stack);
+ mService.updateSleepIfNeededLocked();
}
@Override
@@ -4617,6 +4720,19 @@
boolean shouldDestroyContentOnRemove() {
return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT;
}
+
+ boolean shouldSleep() {
+ return (mStacks.isEmpty() || !mAllSleepTokens.isEmpty())
+ && (mService.mRunningVoice == null);
+ }
+
+ boolean isSleeping() {
+ return mSleeping;
+ }
+
+ void setIsSleeping(boolean asleep) {
+ mSleeping = asleep;
+ }
}
ActivityStack findStackBehind(ActivityStack stack) {
@@ -4798,4 +4914,30 @@
mResult.dump(pw, prefix);
}
}
+
+ private final class SleepTokenImpl extends SleepToken {
+ private final String mTag;
+ private final long mAcquireTime;
+ private final int mDisplayId;
+
+ public SleepTokenImpl(String tag, int displayId) {
+ mTag = tag;
+ mDisplayId = displayId;
+ mAcquireTime = SystemClock.uptimeMillis();
+ }
+
+ @Override
+ public void release() {
+ synchronized (mService) {
+ removeSleepTokenLocked(this);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "{\"" + mTag + "\", display " + mDisplayId
+ + ", acquire at " + TimeUtils.formatUptime(mAcquireTime) + "}";
+ }
+ }
+
}
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index 58e71df..cea80c8 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -18,6 +18,7 @@
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS;
import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
import static android.view.WindowManagerPolicy.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
@@ -32,6 +33,7 @@
import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_UNOCCLUDE;
import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
+import android.app.ActivityManagerInternal.SleepToken;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.Trace;
@@ -63,6 +65,7 @@
private ActivityRecord mDismissingKeyguardActivity;
private int mBeforeUnoccludeTransit;
private int mVisibilityTransactionDepth;
+ private SleepToken mSleepToken;
KeyguardController(ActivityManagerService service,
ActivityStackSupervisor stackSupervisor) {
@@ -102,7 +105,7 @@
mDismissalRequested = false;
}
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
- mService.updateSleepIfNeededLocked();
+ updateKeyguardSleepToken();
}
/**
@@ -122,7 +125,7 @@
mWindowManager.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
false /* alwaysKeepCurrent */, convertTransitFlags(flags),
false /* forceOverride */);
- mService.updateSleepIfNeededLocked();
+ updateKeyguardSleepToken();
// Some stack visibility might change (e.g. docked stack)
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
@@ -263,7 +266,7 @@
try {
mWindowManager.prepareAppTransition(resolveOccludeTransit(),
false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
- mService.updateSleepIfNeededLocked();
+ updateKeyguardSleepToken();
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
mWindowManager.executeAppTransition();
} finally {
@@ -333,6 +336,15 @@
}
}
+ private void updateKeyguardSleepToken() {
+ if (mSleepToken == null && isKeyguardShowing()) {
+ mSleepToken = mService.acquireSleepToken("Keyguard", DEFAULT_DISPLAY);
+ } else if (mSleepToken != null && !isKeyguardShowing()) {
+ mSleepToken.release();
+ mSleepToken = null;
+ }
+ }
+
void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "KeyguardController:");
pw.println(prefix + " mKeyguardShowing=" + mKeyguardShowing);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index e3cf459..c39bf00 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -7462,10 +7462,12 @@
}
}
+ // TODO (multidisplay): Support multiple displays in WindowManagerPolicy.
private void updateDreamingSleepToken(boolean acquire) {
if (acquire) {
if (mDreamingSleepToken == null) {
- mDreamingSleepToken = mActivityManagerInternal.acquireSleepToken("Dream");
+ mDreamingSleepToken = mActivityManagerInternal.acquireSleepToken(
+ "Dream", Display.DEFAULT_DISPLAY);
}
} else {
if (mDreamingSleepToken != null) {
@@ -7475,10 +7477,12 @@
}
}
+ // TODO (multidisplay): Support multiple displays in WindowManagerPolicy.
private void updateScreenOffSleepToken(boolean acquire) {
if (acquire) {
if (mScreenOffSleepToken == null) {
- mScreenOffSleepToken = mActivityManagerInternal.acquireSleepToken("ScreenOff");
+ mScreenOffSleepToken = mActivityManagerInternal.acquireSleepToken(
+ "ScreenOff", Display.DEFAULT_DISPLAY);
}
} else {
if (mScreenOffSleepToken != null) {
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index f3a09ed..956573a 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -16,8 +16,8 @@
package com.android.server.wm;
+import static android.view.Display.INVALID_DISPLAY;
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
-
import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
@@ -350,7 +350,7 @@
// This must be called while inside a transaction.
boolean stepAnimationLocked(long currentTime) {
- if (mService.okToAnimate()) {
+ if (mAppToken.okToAnimate()) {
// We will run animations as long as the display isn't frozen.
if (animation == sDummyAnimation) {
@@ -415,8 +415,8 @@
if (DEBUG_ANIM) Slog.v(TAG, "Animation done in " + mAppToken
+ ": reportedVisible=" + mAppToken.reportedVisible
- + " okToDisplay=" + mService.okToDisplay()
- + " okToAnimate=" + mService.okToAnimate()
+ + " okToDisplay=" + mAppToken.okToDisplay()
+ + " okToAnimate=" + mAppToken.okToAnimate()
+ " startingDisplayed=" + mAppToken.startingDisplayed);
transformation.clear();
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index 4a04af5..ba694b8c 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS;
@@ -401,7 +402,7 @@
// If we are preparing an app transition, then delay changing
// the visibility of this token until we execute that transition.
- if (mService.okToAnimate() && mService.mAppTransition.isTransitionSet()) {
+ if (wtoken.okToAnimate() && mService.mAppTransition.isTransitionSet()) {
// A dummy animation is a placeholder animation which informs others that an
// animation is going on (in this case an application transition). If the animation
// was transferred from another application/animator, no dummy animator should be
@@ -478,7 +479,7 @@
// If the display is frozen, we won't do anything until the actual window is
// displayed so there is no reason to put in the starting window.
- if (!mService.okToDisplay()) {
+ if (!mContainer.okToDisplay()) {
return false;
}
@@ -715,16 +716,17 @@
public void startFreezingScreen(int configChanges) {
synchronized(mWindowMap) {
- if (configChanges == 0 && mService.okToDisplay()) {
- if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
- return;
- }
-
if (mContainer == null) {
Slog.w(TAG_WM,
"Attempted to freeze screen with non-existing app token: " + mContainer);
return;
}
+
+ if (configChanges == 0 && mContainer.okToDisplay()) {
+ if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
+ return;
+ }
+
mContainer.startFreezingScreen();
}
}
diff --git a/services/core/java/com/android/server/wm/DimLayerController.java b/services/core/java/com/android/server/wm/DimLayerController.java
index 7414928..6f9e45a 100644
--- a/services/core/java/com/android/server/wm/DimLayerController.java
+++ b/services/core/java/com/android/server/wm/DimLayerController.java
@@ -290,7 +290,7 @@
state.dimLayer.setLayer(dimLayer);
}
if (state.dimLayer.isAnimating()) {
- if (!mDisplayContent.mService.okToAnimate()) {
+ if (!mDisplayContent.okToAnimate()) {
// Jump to the end of the animation.
state.dimLayer.show();
} else {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4d77d40..37af94a 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -3204,6 +3204,19 @@
mService.requestTraversal();
}
+ boolean okToDisplay() {
+ if (mDisplayId == DEFAULT_DISPLAY) {
+ return !mService.mDisplayFrozen
+ && mService.mDisplayEnabled && mService.mPolicy.isScreenOn();
+ }
+ return mDisplayInfo.state == Display.STATE_ON;
+ }
+
+ boolean okToAnimate() {
+ return okToDisplay() &&
+ (mDisplayId != DEFAULT_DISPLAY || mService.mPolicy.okToAnimate());
+ }
+
static final class TaskForResizePointSearchResult {
boolean searchDone;
Task taskForResize;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 5db691e..233c266 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2329,7 +2329,7 @@
// artifacts when we unfreeze the display if some different animation
// is running.
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WM#applyAnimationLocked");
- if (okToAnimate()) {
+ if (atoken.okToAnimate()) {
final DisplayContent displayContent = atoken.getTask().getDisplayContent();
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
final int width = displayInfo.appWidth;
@@ -2407,14 +2407,6 @@
return false;
}
- boolean okToDisplay() {
- return !mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOn();
- }
-
- boolean okToAnimate() {
- return okToDisplay() && mPolicy.okToAnimate();
- }
-
@Override
public void addWindowToken(IBinder binder, int type, int displayId) {
if (!checkCallingPermission(MANAGE_APP_TOKENS, "addWindowToken()")) {
@@ -2681,7 +2673,9 @@
synchronized(mWindowMap) {
boolean prepared = mAppTransition.prepareAppTransitionLocked(transit, alwaysKeepCurrent,
flags, forceOverride);
- if (prepared && okToAnimate()) {
+ // TODO (multidisplay): associate app transitions with displays
+ final DisplayContent dc = mRoot.getDisplayContent(DEFAULT_DISPLAY);
+ if (prepared && dc != null && dc.okToAnimate()) {
mSkipAppTransitionAnimation = false;
}
}
@@ -5795,7 +5789,10 @@
// If the screen is currently frozen or off, then keep
// it frozen/off until this window draws at its new
// orientation.
- if (!okToDisplay() && mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
+ // TODO (multidisplay): Support screen freezing on secondary displays.
+ final DisplayContent dc = mRoot.getDisplayContent(DEFAULT_DISPLAY);
+ if ((dc == null || !dc.okToDisplay())
+ && mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Changing surface while display frozen: " + w);
w.setOrientationChanging(true);
w.mLastFreezeDuration = 0;
@@ -6011,7 +6008,7 @@
return;
}
- if (!displayContent.isReady() || !mPolicy.isScreenOn() || !okToAnimate()) {
+ if (!displayContent.isReady() || !mPolicy.isScreenOn() || !displayContent.okToAnimate()) {
// No need to freeze the screen before the display is ready, if the screen is off,
// or we can't currently animate.
return;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 7decb11..9875f48 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1683,7 +1683,7 @@
final boolean adjustedForMinimizedDockOrIme = task != null
&& (task.mStack.isAdjustedForMinimizedDockedStack()
|| task.mStack.isAdjustedForIme());
- if (mService.okToAnimate()
+ if (mToken.okToAnimate()
&& (mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
&& !isDragResizing() && !adjustedForMinimizedDockOrIme
&& (task == null || getTask().mStack.hasMovementAnimations())
@@ -1852,7 +1852,7 @@
// First, see if we need to run an animation. If we do, we have to hold off on removing the
// window until the animation is done. If the display is frozen, just remove immediately,
// since the animation wouldn't be seen.
- if (mHasSurface && mService.okToAnimate()) {
+ if (mHasSurface && mToken.okToAnimate()) {
if (mWillReplaceWindow) {
// This window is going to be replaced. We need to keep it around until the new one
// gets added, then we will get rid of this one.
@@ -2282,7 +2282,7 @@
mLayoutNeeded = true;
}
- if (isDrawnLw() && mService.okToAnimate()) {
+ if (isDrawnLw() && mToken.okToAnimate()) {
mWinAnimator.applyEnterAnimationLocked();
}
}
@@ -2438,7 +2438,7 @@
if (doAnimation) {
if (DEBUG_VISIBILITY) Slog.v(TAG, "doAnimation: mPolicyVisibility="
+ mPolicyVisibility + " mAnimation=" + mWinAnimator.mAnimation);
- if (!mService.okToAnimate()) {
+ if (!mToken.okToAnimate()) {
doAnimation = false;
} else if (mPolicyVisibility && mWinAnimator.mAnimation == null) {
// Check for the case where we are currently visible and
@@ -2468,7 +2468,7 @@
boolean hideLw(boolean doAnimation, boolean requestAnim) {
if (doAnimation) {
- if (!mService.okToAnimate()) {
+ if (!mToken.okToAnimate()) {
doAnimation = false;
}
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 23b515e..cbd381a 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -368,7 +368,7 @@
// we just started or just stopped animating by comparing mWasAnimating with isAnimationSet().
mWasAnimating = mAnimating;
final DisplayContent displayContent = mWin.getDisplayContent();
- if (displayContent != null && mService.okToAnimate()) {
+ if (mWin.mToken.okToAnimate()) {
// We will run animations as long as the display isn't frozen.
if (mWin.isDrawnLw() && mAnimation != null) {
@@ -1788,7 +1788,7 @@
// artifacts when we unfreeze the display if some different animation
// is running.
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "WSA#applyAnimationLocked");
- if (mService.okToAnimate()) {
+ if (mWin.mToken.okToAnimate()) {
int anim = mPolicy.selectAnimationLw(mWin, transit);
int attr = -1;
Animation a = null;
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index e3033c9..48d1618 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -288,4 +288,12 @@
String getName() {
return toString();
}
+
+ boolean okToDisplay() {
+ return mDisplayContent != null && mDisplayContent.okToDisplay();
+ }
+
+ boolean okToAnimate() {
+ return mDisplayContent != null && mDisplayContent.okToAnimate();
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
index 48464e5..ba22159 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -78,7 +78,7 @@
service.mStackSupervisor.inResumeTopActivity = true;
testStack.mResumedActivity = activityRecord;
- final boolean waiting = testStack.checkReadyForSleepLocked();
+ final boolean waiting = testStack.goToSleepIfPossible(false);
// Ensure we report not being ready for sleep.
assertTrue(waiting);
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 04b5bde..4ad92c7 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -218,6 +218,12 @@
return createTestStack(stackId, createOnTop);
}
+
+ // Always keep things awake
+ @Override
+ boolean hasAwakeDisplay() {
+ return true;
+ }
}
private static WindowManagerService prepareMockWindowManager() {