Fix a flicker when window is removed during entering animation

When animation is started with saved surfaces, app may decide to
remove one of the child windows during early animation and replace
it with a new window. This causes the app below (usually Recents)
to show through for one or more frames.

If we started animation early with a window, delay removal of
that window until the app is allDrawn in the "traditional sense"
(i.e. allDrawn without using any saved surfaces).

bug: 28742353
Change-Id: I4ef663a947b737aae96c3ccfe13a9f4c1d0567f0
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index e490a40..abbb5f4 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -88,6 +88,11 @@
     // case do not clear allDrawn until the animation completes.
     boolean deferClearAllDrawn;
 
+    // These are to track the app's real drawing status if there were no saved surfaces.
+    boolean allDrawnExcludingSaved;
+    int numInterestingWindowsExcludingSaved;
+    int numDrawnWindowsExclusingSaved;
+
     // Is this window's surface needed?  This is almost like hidden, except
     // it will sometimes be true a little earlier: when the token has
     // been shown, but is still waiting for its app transition to execute
@@ -411,6 +416,39 @@
         }
     }
 
+    /**
+     * Whether the app has some window that is invisible in layout, but
+     * animating with saved surface.
+     */
+    boolean isAnimatingInvisibleWithSavedSurface() {
+        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
+            final WindowState w = allAppWindows.get(i);
+            if (w.isAnimatingInvisibleWithSavedSurface()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Hide all window surfaces that's still invisible in layout but animating
+     * with a saved surface, and mark them destroying.
+     */
+    void stopUsingSavedSurfaceLocked() {
+        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
+            final WindowState w = allAppWindows.get(i);
+            if (w.isAnimatingInvisibleWithSavedSurface()) {
+                if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG,
+                        "stopUsingSavedSurfaceLocked: " + w);
+                w.clearAnimatingWithSavedSurface();
+                w.mDestroying = true;
+                w.mWinAnimator.hide("stopUsingSavedSurfaceLocked");
+                w.mWinAnimator.mWallpaperControllerLocked.hideWallpapers(w);
+            }
+        }
+        destroySurfaces();
+    }
+
     void restoreSavedSurfaces() {
         if (!canRestoreSurfaces()) {
             clearVisibleBeforeClientHidden();
@@ -456,6 +494,7 @@
     void clearAllDrawn() {
         allDrawn = false;
         deferClearAllDrawn = false;
+        allDrawnExcludingSaved = false;
     }
 
     @Override