Nuke mActivitiesWaitingForVisibleActivity
Instead of relying on this brittle architecture we just check
whether the animation has finished. Much cleaner now :-)
Test: Swipe up to recents from Chrome, relaunch in the right
moment. Observe no jumpcut.
Test: Existing lifecycle tests should cover this
Test: android.server.am.lifecycle: All passed!
Bug: 111227410
Change-Id: I83b3dc0e026e842bf260a376ce9a57afd1b01d9f
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index f70adef..1783591 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -564,11 +564,8 @@
pw.print("requestedVrComponent=");
pw.println(requestedVrComponent);
}
- final boolean waitingVisible =
- mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(this);
- if (lastVisibleTime != 0 || waitingVisible || nowVisible) {
- pw.print(prefix); pw.print("waitingVisible="); pw.print(waitingVisible);
- pw.print(" nowVisible="); pw.print(nowVisible);
+ if (lastVisibleTime != 0 || nowVisible) {
+ pw.print(prefix); pw.print(" nowVisible="); pw.print(nowVisible);
pw.print(" lastVisibleTime=");
if (lastVisibleTime == 0) pw.print("0");
else TimeUtils.formatDuration(lastVisibleTime, now, pw);
@@ -2358,27 +2355,6 @@
if (!nowVisible) {
nowVisible = true;
lastVisibleTime = SystemClock.uptimeMillis();
- if (idle || mStackSupervisor.isStoppingNoHistoryActivity()) {
- // If this activity was already idle or there is an activity that must be
- // stopped immediately after visible, then we now need to make sure we perform
- // the full stop of any activities that are waiting to do so. This is because
- // we won't do that while they are still waiting for this one to become visible.
- final int size = mStackSupervisor.mActivitiesWaitingForVisibleActivity.size();
- if (size > 0) {
- for (int i = 0; i < size; i++) {
- final ActivityRecord r =
- mStackSupervisor.mActivitiesWaitingForVisibleActivity.get(i);
- if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "Was waiting for visible: " + r);
- }
- mStackSupervisor.mActivitiesWaitingForVisibleActivity.clear();
- mStackSupervisor.scheduleIdleLocked();
- }
- } else {
- // Instead of doing the full stop routine here, let's just hide any activities
- // we now can, and let them stop when the normal idle happens.
- mStackSupervisor.processStoppingActivitiesLocked(null /* idleActivity */,
- false /* remove */, true /* processPausingActivities */);
- }
mAtmService.scheduleAppGcsLocked();
}
}
@@ -2392,6 +2368,24 @@
}
}
+ void onAnimationFinished() {
+ if (mRootActivityContainer.allResumedActivitiesIdle()
+ || mStackSupervisor.isStoppingNoHistoryActivity()) {
+ // If all activities are already idle or there is an activity that must be
+ // stopped immediately after visible, then we now need to make sure we perform
+ // the full stop of this activity. This is because we won't do that while they are still
+ // waiting for the animation to finish.
+ if (mStackSupervisor.mStoppingActivities.contains(this)) {
+ mStackSupervisor.scheduleIdleLocked();
+ }
+ } else {
+ // Instead of doing the full stop routine here, let's just hide any activities
+ // we now can, and let them stop when the normal idle happens.
+ mStackSupervisor.processStoppingActivitiesLocked(null /* idleActivity */,
+ false /* remove */, true /* processPausingActivities */);
+ }
+ }
+
/**
* Called when the key dispatching to a window associated with the app window container
* timed-out.
@@ -2424,10 +2418,9 @@
}
private ActivityRecord getWaitingHistoryRecordLocked() {
- // First find the real culprit... if this activity is waiting for
- // another activity to start or has stopped, then the key dispatching
+ // First find the real culprit... if this activity has stopped, then the key dispatching
// timeout should not be caused by this.
- if (mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(this) || stopped) {
+ if (stopped) {
final ActivityStack stack = mRootActivityContainer.getTopDisplayFocusedStack();
// Try to use the one which is closest to top.
ActivityRecord r = stack.getResumedActivity();
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index ea2aff2..1483652 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -1799,10 +1799,6 @@
} else if (prev.hasProcess()) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev
+ " wasStopping=" + wasStopping + " visible=" + prev.visible);
- if (mStackSupervisor.mActivitiesWaitingForVisibleActivity.remove(prev)) {
- if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(TAG_PAUSE,
- "Complete pause, no longer waiting: " + prev);
- }
if (prev.deferRelaunchUntilPaused) {
// Complete the deferred relaunch that was waiting for pause to complete.
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Re-launching after pause: " + prev);
@@ -1882,16 +1878,6 @@
private void addToStopping(ActivityRecord r, boolean scheduleIdle, boolean idleDelayed) {
if (!mStackSupervisor.mStoppingActivities.contains(r)) {
mStackSupervisor.mStoppingActivities.add(r);
-
- // Some activity is waiting for another activity to become visible before it's being
- // stopped, which means that we also want to wait with stopping this one to avoid
- // flickers.
- if (!mStackSupervisor.mActivitiesWaitingForVisibleActivity.isEmpty()
- && !mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(r)) {
- if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "adding to waiting visible activity=" + r
- + " existing=" + mStackSupervisor.mActivitiesWaitingForVisibleActivity);
- mStackSupervisor.mActivitiesWaitingForVisibleActivity.add(r);
- }
}
// If we already have a few activities waiting to stop, then give up
@@ -2707,7 +2693,6 @@
mStackSupervisor.mStoppingActivities.remove(next);
mStackSupervisor.mGoingToSleepActivities.remove(next);
next.sleeping = false;
- mStackSupervisor.mActivitiesWaitingForVisibleActivity.remove(next);
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);
@@ -2716,11 +2701,6 @@
if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
"resumeTopActivityLocked: Skip resume: some activity pausing.");
- // Adding previous activity to the waiting visible list, or it would be stopped
- // before top activity being visible.
- if (prev != null && !next.nowVisible) {
- mStackSupervisor.mActivitiesWaitingForVisibleActivity.add(prev);
- }
return false;
}
@@ -2796,35 +2776,27 @@
mLastNoHistoryActivity = null;
}
- if (prev != null && prev != next) {
- if (!mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(prev)
- && !next.nowVisible) {
- mStackSupervisor.mActivitiesWaitingForVisibleActivity.add(prev);
+ if (prev != null && prev != next && next.nowVisible) {
+
+ // The next activity is already visible, so hide the previous
+ // activity's windows right now so we can show the new one ASAP.
+ // We only do this if the previous is finishing, which should mean
+ // it is on top of the one being resumed so hiding it quickly
+ // is good. Otherwise, we want to do the normal route of allowing
+ // the resumed activity to be shown so we can decide if the
+ // previous should actually be hidden depending on whether the
+ // new one is found to be full-screen or not.
+ if (prev.finishing) {
+ prev.setVisibility(false);
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
- "Resuming top, waiting visible to hide: " + prev);
+ "Not waiting for visible to hide: " + prev
+ + ", nowVisible=" + next.nowVisible);
} else {
- // The next activity is already visible, so hide the previous
- // activity's windows right now so we can show the new one ASAP.
- // We only do this if the previous is finishing, which should mean
- // it is on top of the one being resumed so hiding it quickly
- // is good. Otherwise, we want to do the normal route of allowing
- // the resumed activity to be shown so we can decide if the
- // previous should actually be hidden depending on whether the
- // new one is found to be full-screen or not.
- if (prev.finishing) {
- prev.setVisibility(false);
- if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
- "Not waiting for visible to hide: " + prev + ", waitingVisible="
- + mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(prev)
- + ", nowVisible=" + next.nowVisible);
- } else {
- if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
- "Previous already visible but still waiting to hide: " + prev
- + ", waitingVisible="
- + mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(prev)
- + ", nowVisible=" + next.nowVisible);
- }
+ if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
+ "Previous already visible but still waiting to hide: " + prev
+ + ", nowVisible=" + next.nowVisible);
}
+
}
// Launching this app's activity, make sure the app is no longer
@@ -4081,9 +4053,6 @@
dc.prepareAppTransition(transit, false);
r.setVisibility(false);
dc.executeAppTransition();
- if (!mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(r)) {
- mStackSupervisor.mActivitiesWaitingForVisibleActivity.add(r);
- }
}
static final int FINISH_IMMEDIATELY = 0;
@@ -4119,7 +4088,6 @@
// make sure the record is cleaned out of other places.
mStackSupervisor.mStoppingActivities.remove(r);
mStackSupervisor.mGoingToSleepActivities.remove(r);
- mStackSupervisor.mActivitiesWaitingForVisibleActivity.remove(r);
final ActivityState prevState = r.getState();
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to FINISHING: " + r);
@@ -4725,8 +4693,6 @@
"mStoppingActivities");
removeHistoryRecordsForAppLocked(mStackSupervisor.mGoingToSleepActivities, app,
"mGoingToSleepActivities");
- removeHistoryRecordsForAppLocked(mStackSupervisor.mActivitiesWaitingForVisibleActivity, app,
- "mActivitiesWaitingForVisibleActivity");
removeHistoryRecordsForAppLocked(mStackSupervisor.mFinishingActivities, app,
"mFinishingActivities");
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 758a765..d1108cc 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -267,12 +267,6 @@
*/
private final SparseIntArray mCurTaskIdForUser = new SparseIntArray(20);
- /** List of activities that are waiting for a new activity to become visible before completing
- * whatever operation they are supposed to do. */
- // TODO: Remove mActivitiesWaitingForVisibleActivity list and just remove activity from
- // mStoppingActivities when something else comes up.
- final ArrayList<ActivityRecord> mActivitiesWaitingForVisibleActivity = new ArrayList<>();
-
/** List of processes waiting to find out when a specific activity becomes visible. */
private final ArrayList<WaitInfo> mWaitingForActivityVisible = new ArrayList<>();
@@ -550,7 +544,6 @@
// This could happen, for example, if we are trimming activities
// down to the max limit while they are still waiting to finish.
mFinishingActivities.remove(r);
- mActivitiesWaitingForVisibleActivity.remove(r);
for (int i = mWaitingForActivityVisible.size() - 1; i >= 0; --i) {
if (mWaitingForActivityVisible.get(i).matches(r.mActivityComponent)) {
@@ -2142,28 +2135,27 @@
final boolean nowVisible = mRootActivityContainer.allResumedActivitiesVisible();
for (int activityNdx = mStoppingActivities.size() - 1; activityNdx >= 0; --activityNdx) {
ActivityRecord s = mStoppingActivities.get(activityNdx);
- boolean waitingVisible = mActivitiesWaitingForVisibleActivity.contains(s);
+
+ final boolean animating = s.mAppWindowToken.isSelfAnimating();
+
if (DEBUG_STATES) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + nowVisible
- + " waitingVisible=" + waitingVisible + " finishing=" + s.finishing);
- if (waitingVisible && nowVisible) {
- mActivitiesWaitingForVisibleActivity.remove(s);
- waitingVisible = false;
- if (s.finishing) {
- // If this activity is finishing, it is sitting on top of
- // everyone else but we now know it is no longer needed...
- // so get rid of it. Otherwise, we need to go through the
- // normal flow and hide it once we determine that it is
- // hidden by the activities in front of it.
- if (DEBUG_STATES) Slog.v(TAG, "Before stopping, can hide: " + s);
- s.setVisibility(false);
- }
+ + " animating=" + animating + " finishing=" + s.finishing);
+ if (nowVisible && s.finishing) {
+
+ // If this activity is finishing, it is sitting on top of
+ // everyone else but we now know it is no longer needed...
+ // so get rid of it. Otherwise, we need to go through the
+ // normal flow and hide it once we determine that it is
+ // hidden by the activities in front of it.
+ if (DEBUG_STATES) Slog.v(TAG, "Before stopping, can hide: " + s);
+ s.setVisibility(false);
}
if (remove) {
final ActivityStack stack = s.getActivityStack();
final boolean shouldSleepOrShutDown = stack != null
? stack.shouldSleepOrShutDownActivities()
: mService.isSleepingOrShuttingDownLocked();
- if (!waitingVisible || shouldSleepOrShutDown) {
+ if (!animating || shouldSleepOrShutDown) {
if (!processPausingActivities && s.isState(PAUSING)) {
// Defer processing pausing activities in this iteration and reschedule
// a delayed idle to reprocess it again
@@ -2178,9 +2170,6 @@
}
stops.add(s);
- // Make sure to remove it in all cases in case we entered this block with
- // shouldSleepOrShutDown
- mActivitiesWaitingForVisibleActivity.remove(s);
mStoppingActivities.remove(activityNdx);
}
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 78199d44..220370c 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -2784,6 +2784,8 @@
getDisplayContent().mAppTransition.notifyAppTransitionFinishedLocked(token);
scheduleAnimation();
+
+ mActivityRecord.onAnimationFinished();
}
@Override
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index e3beb19..e59b6d7 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -2016,8 +2016,7 @@
final ActivityStack stack = display.getChildAt(stackNdx);
final ActivityRecord r = stack.getResumedActivity();
if (r != null) {
- if (!r.nowVisible
- || mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(r)) {
+ if (!r.nowVisible) {
return false;
}
foundResumed = true;
@@ -2345,10 +2344,6 @@
printed |= dumpHistoryList(fd, pw, mStackSupervisor.mStoppingActivities, " ",
"Stop", false, !dumpAll,
false, dumpPackage, true, " Activities waiting to stop:", null);
- printed |= dumpHistoryList(fd, pw,
- mStackSupervisor.mActivitiesWaitingForVisibleActivity, " ", "Wait",
- false, !dumpAll, false, dumpPackage, true,
- " Activities waiting for another to become visible:", null);
printed |= dumpHistoryList(fd, pw, mStackSupervisor.mGoingToSleepActivities,
" ", "Sleep", false, !dumpAll,
false, dumpPackage, true, " Activities waiting to sleep:", null);