Defer stop for all activities becoming invisible

If we are deferring a stop until a window is becoming visible,
it's a good idea to also defer stopping all other activities that
are go into stopping state to avoid flickers.

Furthermore we need to fix an issue where activities weren't
cleared from mActivitiesWaitingForVisibleActivity which messed
up the newly introduced logic.

This fixes an issue with quickstep when swiping right and the
previous activity hasn't finished pausing yet when we start the
new activity. In the normal case, prev=Launcher and all is fine,
as we wait with stopping launcher until the animation is done. In
the bad case, prev=the previous activity that was on screen before
swiping, so Launcher doesn't get added to the waiting list, which
means that it will be stopped too early, aborting the animation
because Launcher is also driving it.

Test: ActivityManagerDisplayLockedKeyguardTests
Test: go/wm-smoke
Test: Swipe right from Chrome to any other app, observe no jump
Fixes: 80313326
Bug: 110032866
Change-Id: I39454fe218ac10ef73cc4ca23efc7c9fb3bc87ad
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index aea29ac..f58f717 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1654,6 +1654,16 @@
     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
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index e034b82..a6cd9f7 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -3930,6 +3930,10 @@
                         stops = new ArrayList<>();
                     }
                     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);
                 }
             }