Removed child windows from WindowToken window list

With the window container hierarchy model, containers should only
link to their direct children and delegate any operation on
decendants of their children to their children.

Bug: 30060889
Change-Id: I99ca0d181d54cfe75bbe24c1b0daaa06cf7cfd9a
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index df212bc..66fa976 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -20,15 +20,11 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManagerPolicy.TRANSIT_ENTER;
-import static android.view.WindowManagerPolicy.TRANSIT_EXIT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
@@ -37,7 +33,6 @@
 import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
-import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT;
 import static com.android.server.wm.WindowManagerService.logWithStack;
 
 import com.android.server.input.InputApplicationHandle;
@@ -50,7 +45,6 @@
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.Message;
-import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.Slog;
 import android.view.IApplicationToken;
@@ -132,6 +126,8 @@
     boolean startingDisplayed;
     boolean startingMoved;
     boolean firstWindowDrawn;
+    private final WindowState.UpdateReportedVisibilityResults mReportedVisibilityResults =
+            new WindowState.UpdateReportedVisibilityResults();
 
     // Input application handle used by the input dispatcher.
     final InputApplicationHandle mInputApplicationHandle;
@@ -162,19 +158,10 @@
     }
 
     void sendAppVisibilityToClients() {
-        final int N = windows.size();
-        for (int i=0; i<N; i++) {
-            WindowState win = windows.get(i);
-            if (win == startingWindow && clientHidden) {
-                // Don't hide the starting window.
-                continue;
-            }
-            try {
-                if (DEBUG_VISIBILITY) Slog.v(TAG,
-                        "Setting visibility of " + win + ": " + (!clientHidden));
-                win.mClient.dispatchAppVisibility(!clientHidden);
-            } catch (RemoteException e) {
-            }
+        final int count = windows.size();
+        for (int i = 0; i < count; i++) {
+            final WindowState win = windows.get(i);
+            win.sendAppVisibilityToClients(clientHidden);
         }
     }
 
@@ -189,7 +176,7 @@
         firstWindowDrawn = true;
 
         // We now have a good window to show, remove dead placeholders
-        removeAllDeadWindows();
+        removeDeadWindows();
 
         if (startingData != null) {
             if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Slog.v(TAG, "Finish starting "
@@ -209,50 +196,21 @@
             return;
         }
 
-        int numInteresting = 0;
-        int numVisible = 0;
-        int numDrawn = 0;
-        boolean nowGone = true;
+        if (DEBUG_VISIBILITY) Slog.v(TAG, "Update reported visibility: " + this);
+        final int count = windows.size();
 
-        if (DEBUG_VISIBILITY) Slog.v(TAG,
-                "Update reported visibility: " + this);
-        final int N = windows.size();
-        for (int i=0; i<N; i++) {
-            WindowState win = windows.get(i);
-            if (win == startingWindow || win.mAppFreezing
-                    || win.mViewVisibility != View.VISIBLE
-                    || win.mAttrs.type == TYPE_APPLICATION_STARTING
-                    || win.mDestroying) {
-                continue;
-            }
-            if (DEBUG_VISIBILITY) {
-                Slog.v(TAG, "Win " + win + ": isDrawn="
-                        + win.isDrawnLw()
-                        + ", isAnimationSet=" + win.mWinAnimator.isAnimationSet());
-                if (!win.isDrawnLw()) {
-                    Slog.v(TAG, "Not displayed: s=" +
-                            win.mWinAnimator.mSurfaceController
-                            + " pv=" + win.mPolicyVisibility
-                            + " mDrawState=" + win.mWinAnimator.mDrawState
-                            + " ph=" + win.isParentWindowHidden()
-                            + " th="
-                            + (win.mAppToken != null
-                                    ? win.mAppToken.hiddenRequested : false)
-                            + " a=" + win.mWinAnimator.mAnimating);
-                }
-            }
-            numInteresting++;
-            if (win.isDrawnLw()) {
-                numDrawn++;
-                if (!win.mWinAnimator.isAnimationSet()) {
-                    numVisible++;
-                }
-                nowGone = false;
-            } else if (win.mWinAnimator.isAnimationSet()) {
-                nowGone = false;
-            }
+        mReportedVisibilityResults.reset();
+
+        for (int i = 0; i < count; i++) {
+            final WindowState win = windows.get(i);
+            win.updateReportedVisibility(mReportedVisibilityResults);
         }
 
+        int numInteresting = mReportedVisibilityResults.numInteresting;
+        int numVisible = mReportedVisibilityResults.numVisible;
+        int numDrawn = mReportedVisibilityResults.numDrawn;
+        boolean nowGone = mReportedVisibilityResults.nowGone;
+
         boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting;
         boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting;
         if (!nowGone) {
@@ -268,23 +226,16 @@
                 + numInteresting + " visible=" + numVisible);
         if (nowDrawn != reportedDrawn) {
             if (nowDrawn) {
-                Message m = mService.mH.obtainMessage(
-                        H.REPORT_APPLICATION_TOKEN_DRAWN, this);
-                mService.mH.sendMessage(m);
+                mService.mH.obtainMessage(H.REPORT_APPLICATION_TOKEN_DRAWN, this).sendToTarget();
             }
             reportedDrawn = nowDrawn;
         }
         if (nowVisible != reportedVisible) {
-            if (DEBUG_VISIBILITY) Slog.v(
-                    TAG, "Visibility changed in " + this
-                    + ": vis=" + nowVisible);
+            if (DEBUG_VISIBILITY) Slog.v(TAG,
+                    "Visibility changed in " + this + ": vis=" + nowVisible);
             reportedVisible = nowVisible;
-            Message m = mService.mH.obtainMessage(
-                    H.REPORT_APPLICATION_TOKEN_WINDOWS,
-                    nowVisible ? 1 : 0,
-                    nowGone ? 1 : 0,
-                    this);
-            mService.mH.sendMessage(m);
+            mService.mH.obtainMessage(H.REPORT_APPLICATION_TOKEN_WINDOWS,
+                    nowVisible ? 1 : 0, nowGone ? 1 : 0, this).sendToTarget();
         }
     }
 
@@ -332,45 +283,7 @@
             final int windowsCount = windows.size();
             for (int i = 0; i < windowsCount; i++) {
                 final WindowState win = windows.get(i);
-                if (win == startingWindow) {
-                    // Starting window that's exiting will be removed when the animation finishes.
-                    // Mark all relevant flags for that onExitAnimationDone will proceed all the way
-                    // to actually remove it.
-                    if (!visible && win.isVisibleNow() && mAppAnimator.isAnimating()) {
-                        win.mAnimatingExit = true;
-                        win.mRemoveOnExit = true;
-                        win.mWindowRemovalAllowed = true;
-                    }
-                    continue;
-                }
-
-                //Slog.i(TAG_WM, "Window " + win + ": vis=" + win.isVisible());
-                //win.dump("  ");
-                if (visible) {
-                    if (!win.isVisibleNow()) {
-                        if (!runningAppAnimation) {
-                            win.mWinAnimator.applyAnimationLocked(TRANSIT_ENTER, true);
-                            //TODO (multidisplay): Magnification is supported only for the default
-                            if (accessibilityController != null
-                                    && win.getDisplayId() == DEFAULT_DISPLAY) {
-                                accessibilityController.onWindowTransitionLocked(win, TRANSIT_ENTER);
-                            }
-                        }
-                        changed = true;
-                        win.setDisplayLayoutNeeded();
-                    }
-                } else if (win.isVisibleNow()) {
-                    if (!runningAppAnimation) {
-                        win.mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false);
-                        //TODO (multidisplay): Magnification is supported only for the default
-                        if (accessibilityController != null
-                                && win.getDisplayId() == DEFAULT_DISPLAY) {
-                            accessibilityController.onWindowTransitionLocked(win,TRANSIT_EXIT);
-                        }
-                    }
-                    changed = true;
-                    win.setDisplayLayoutNeeded();
-                }
+                changed |= win.onAppVisibilityChanged(visible, runningAppAnimation);
             }
 
             hidden = hiddenRequested = !visible;
@@ -378,12 +291,11 @@
             if (!visible) {
                 stopFreezingScreen(true, true);
             } else {
-                // If we are being set visible, and the starting window is
-                // not yet displayed, then make sure it doesn't get displayed.
-                WindowState swin = startingWindow;
-                if (swin != null && !swin.isDrawnLw()) {
-                    swin.mPolicyVisibility = false;
-                    swin.mPolicyVisibilityAfterAnim = false;
+                // If we are being set visible, and the starting window is not yet displayed,
+                // then make sure it doesn't get displayed.
+                if (startingWindow != null && !startingWindow.isDrawnLw()) {
+                    startingWindow.mPolicyVisibility = false;
+                    startingWindow.mPolicyVisibilityAfterAnim = false;
                 }
             }
 
@@ -406,7 +318,7 @@
         }
 
         for (int i = windows.size() - 1; i >= 0 && !delayed; i--) {
-            if (windows.get(i).mWinAnimator.isWindowAnimationSet()) {
+            if (windows.get(i).isWindowAnimationSet()) {
                 delayed = true;
             }
         }
@@ -436,9 +348,11 @@
         int j = windows.size();
         while (j > 0) {
             j--;
-            WindowState win = windows.get(j);
-            if (win.mAttrs.type == WindowManager.LayoutParams.TYPE_BASE_APPLICATION
-                    || win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
+            final WindowState win = windows.get(j);
+            final int type = win.mAttrs.type;
+            // No need to loop through child window as base application and starting types can't be
+            // child windows.
+            if (type == TYPE_BASE_APPLICATION || type == TYPE_APPLICATION_STARTING) {
                 // In cases where there are multiple windows, we prefer the non-exiting window. This
                 // happens for example when replacing windows during an activity relaunch. When
                 // constructing the animation, we want the new window, not the exiting one.
@@ -457,24 +371,17 @@
     }
 
     boolean isVisible() {
-        final int N = windows.size();
-        for (int i=0; i<N; i++) {
-            WindowState win = windows.get(i);
-            // If we're animating with a saved surface, we're already visible.
-            // Return true so that the alpha doesn't get cleared.
-            if (!win.mAppFreezing
-                    && (win.mViewVisibility == View.VISIBLE || win.isAnimatingWithSavedSurface()
-                            || (win.mWinAnimator.isAnimationSet()
-                                    && !mService.mAppTransition.isTransitionSet()))
-                    && !win.mDestroying
-                    && win.isDrawnLw()) {
+        final int count = windows.size();
+        for (int i = 0; i < count; i++) {
+            final WindowState win = windows.get(i);
+            if (win.isVisible()) {
                 return true;
             }
         }
         return false;
     }
 
-    boolean isVisibleForUser() {
+    boolean canBeVisibleForCurrentUser() {
         for (int j = windows.size() - 1; j >= 0; j--) {
             final WindowState w = windows.get(j);
             if (!w.isHiddenFromUserLocked()) {
@@ -503,35 +410,7 @@
         boolean wallpaperMightChange = false;
         for (int i = windows.size() - 1; i >= 0; i--) {
             final WindowState win = windows.get(i);
-            // We don't want to clear it out for windows that get replaced, because the
-            // animation depends on the flag to remove the replaced window.
-            //
-            // We also don't clear the mAnimatingExit flag for windows which have the
-            // mRemoveOnExit flag. This indicates an explicit remove request has been issued
-            // by the client. We should let animation proceed and not clear this flag or
-            // they won't eventually be removed by WindowStateAnimator#finishExit.
-            if (!win.mWillReplaceWindow && !win.mRemoveOnExit) {
-                // Clear mAnimating flag together with mAnimatingExit. When animation
-                // changes from exiting to entering, we need to clear this flag until the
-                // new animation gets applied, so that isAnimationStarting() becomes true
-                // until then.
-                // Otherwise applySurfaceChangesTransaction will faill to skip surface
-                // placement for this window during this period, one or more frame will
-                // show up with wrong position or scale.
-                if (win.mAnimatingExit) {
-                    win.mAnimatingExit = false;
-                    wallpaperMightChange = true;
-                }
-                if (win.mWinAnimator.mAnimating) {
-                    win.mWinAnimator.mAnimating = false;
-                    wallpaperMightChange = true;
-                }
-                if (win.mDestroying) {
-                    win.mDestroying = false;
-                    mService.mDestroySurface.remove(win);
-                    wallpaperMightChange = true;
-                }
-            }
+            wallpaperMightChange |= win.clearAnimatingFlags();
         }
         if (wallpaperMightChange) {
             requestUpdateWallpaperIfNeeded();
@@ -551,42 +430,18 @@
      * others so that they are ready to be reused. If set to false (common case), destroy all
      * surfaces that's eligible, if the app is already stopped.
      */
-
     private void destroySurfaces(boolean cleanupOnResume) {
-        final ArrayList<WindowState> allWindows = (ArrayList<WindowState>) windows.clone();
         final DisplayContentList displayList = new DisplayContentList();
-        for (int i = allWindows.size() - 1; i >= 0; i--) {
-            final WindowState win = allWindows.get(i);
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            final WindowState win = windows.get(i);
+            final boolean destroyed = win.destroySurface(cleanupOnResume, mAppStopped);
 
-            if (!(mAppStopped || win.mWindowRemovalAllowed || cleanupOnResume)) {
-                continue;
+            if (destroyed) {
+                final DisplayContent displayContent = win.getDisplayContent();
+                if (displayContent != null && !displayList.contains(displayContent)) {
+                    displayList.add(displayContent);
+                }
             }
-
-            win.mWinAnimator.destroyPreservedSurfaceLocked();
-
-            if (!win.mDestroying) {
-                continue;
-            }
-
-            if (DEBUG_ADD_REMOVE) Slog.e(TAG_WM, "win=" + win
-                    + " destroySurfaces: mAppStopped=" + mAppStopped
-                    + " win.mWindowRemovalAllowed=" + win.mWindowRemovalAllowed
-                    + " win.mRemoveOnExit=" + win.mRemoveOnExit);
-
-            if (!cleanupOnResume || win.mRemoveOnExit) {
-                win.destroyOrSaveSurface();
-            }
-            if (win.mRemoveOnExit) {
-                win.remove();
-            }
-            final DisplayContent displayContent = win.getDisplayContent();
-            if (displayContent != null && !displayList.contains(displayContent)) {
-                displayList.add(displayContent);
-            }
-            if (cleanupOnResume) {
-                win.requestUpdateWallpaperIfNeeded();
-            }
-            win.mDestroying = false;
         }
         for (int i = 0; i < displayList.size(); i++) {
             final DisplayContent displayContent = displayList.get(i);
@@ -646,10 +501,10 @@
         return false;
     }
 
-    void clearVisibleBeforeClientHidden() {
+    void clearWasVisibleBeforeClientHidden() {
         for (int i = windows.size() - 1; i >= 0; i--) {
             final WindowState w = windows.get(i);
-            w.clearVisibleBeforeClientHidden();
+            w.clearWasVisibleBeforeClientHidden();
         }
     }
 
@@ -674,14 +529,7 @@
     void stopUsingSavedSurfaceLocked() {
         for (int i = windows.size() - 1; i >= 0; i--) {
             final WindowState w = windows.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");
-                mService.mWallpaperControllerLocked.hideWallpapers(w);
-            }
+            w.stopUsingSavedSurface();
         }
         destroySurfaces();
     }
@@ -689,51 +537,40 @@
     void markSavedSurfaceExiting() {
         for (int i = windows.size() - 1; i >= 0; i--) {
             final WindowState w = windows.get(i);
-            if (w.isAnimatingInvisibleWithSavedSurface()) {
-                w.mAnimatingExit = true;
-                w.mWinAnimator.mAnimating = true;
-            }
+            w.markSavedSurfaceExiting();
         }
     }
 
-    void restoreSavedSurfaces() {
+    void restoreSavedSurfaceForInterestingWindows() {
         if (!canRestoreSurfaces()) {
-            clearVisibleBeforeClientHidden();
+            clearWasVisibleBeforeClientHidden();
             return;
         }
-        // Check if we have enough drawn windows to mark allDrawn= true.
-        int numInteresting = 0;
-        int numDrawn = 0;
+
+        // Check if all interesting windows are drawn and we can mark allDrawn=true.
+        int interestingNotDrawn = -1;
+
         for (int i = windows.size() - 1; i >= 0; i--) {
-            WindowState w = windows.get(i);
-            if (w != startingWindow && !w.mAppDied && w.wasVisibleBeforeClientHidden()
-                    && (!mAppAnimator.freezingScreen || !w.mAppFreezing)) {
-                numInteresting++;
-                if (w.hasSavedSurface()) {
-                    w.restoreSavedSurface();
-                }
-                if (w.isDrawnLw()) {
-                    numDrawn++;
-                }
-            }
+            final WindowState w = windows.get(i);
+            interestingNotDrawn = w.restoreSavedSurfaceForInterestingWindow();
         }
 
         if (!allDrawn) {
-            allDrawn = (numInteresting > 0) && (numInteresting == numDrawn);
+            allDrawn = (interestingNotDrawn == 0);
             if (allDrawn) {
                 mService.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN, token).sendToTarget();
             }
         }
-        clearVisibleBeforeClientHidden();
+        clearWasVisibleBeforeClientHidden();
 
         if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG,
-                "restoreSavedSurfaces: " + this + " allDrawn=" + allDrawn
-                + " numInteresting=" + numInteresting + " numDrawn=" + numDrawn);
+                "restoreSavedSurfaceForInterestingWindows: " + this + " allDrawn=" + allDrawn
+                + " interestingNotDrawn=" + interestingNotDrawn);
     }
 
     void destroySavedSurfaces() {
         for (int i = windows.size() - 1; i >= 0; i--) {
-            WindowState win = windows.get(i);
+            final WindowState win = windows.get(i);
             win.destroySavedSurface();
         }
     }
@@ -764,7 +601,7 @@
         }
     }
 
-    void removeAllDeadWindows() {
+    void removeDeadWindows() {
         for (int winNdx = windows.size() - 1; winNdx >= 0;
             // WindowState#removeIfPossible() at bottom of loop may remove multiple entries from
             // windows if the window to be removed has child windows. It also may
@@ -775,9 +612,10 @@
             WindowState win = windows.get(winNdx);
             if (win.mAppDied) {
                 if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.w(TAG,
-                        "removeAllDeadWindows: " + win);
+                        "removeDeadWindows: " + win);
                 // Set mDestroying, we don't want any animation or delayed removal here.
                 win.mDestroying = true;
+                // Also removes child windows.
                 win.removeIfPossible();
             }
         }
@@ -785,6 +623,8 @@
 
     boolean hasWindowsAlive() {
         for (int i = windows.size() - 1; i >= 0; i--) {
+            // No need to loop through child windows as the answer should be the same as that of the
+            // parent window.
             if (!windows.get(i).mAppDied) {
                 return true;
             }
@@ -792,42 +632,40 @@
         return false;
     }
 
-    void setReplacingWindows(boolean animate) {
+    void setWillReplaceWindows(boolean animate) {
         if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM,
                 "Marking app token " + this + " with replacing windows.");
 
         for (int i = windows.size() - 1; i >= 0; i--) {
             final WindowState w = windows.get(i);
-            w.setReplacing(animate);
+            w.setWillReplaceWindow(animate);
         }
         if (animate) {
             // Set-up dummy animation so we can start treating windows associated with this
             // token like they are in transition before the new app window is ready for us to
             // run the real transition animation.
             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
-                    "setReplacingWindow() Setting dummy animation on: " + this);
+                    "setWillReplaceWindow() Setting dummy animation on: " + this);
             mAppAnimator.setDummyAnimation();
         }
     }
 
-    void setReplacingChildren() {
+    void setWillReplaceChildWindows() {
         if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + this
                 + " with replacing child windows.");
         for (int i = windows.size() - 1; i >= 0; i--) {
             final WindowState w = windows.get(i);
-            if (w.shouldBeReplacedWithChildren()) {
-                w.setReplacing(false /* animate */);
-            }
+            w.setWillReplaceChildWindows();
         }
     }
 
-    void resetReplacingWindows() {
+    void clearWillReplaceWindows() {
         if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM,
                 "Resetting app token " + this + " of replacing window marks.");
 
         for (int i = windows.size() - 1; i >= 0; i--) {
             final WindowState w = windows.get(i);
-            w.resetReplacing();
+            w.clearWillReplaceWindow();
         }
     }
 
@@ -872,49 +710,31 @@
     void addWindow(WindowState w) {
         super.addWindow(w);
 
+        boolean gotReplacementWindow = false;
         for (int i = windows.size() - 1; i >= 0; i--) {
             final WindowState candidate = windows.get(i);
-            if (candidate.mWillReplaceWindow && candidate.mReplacingWindow == null
-                    && candidate.getWindowTag().toString().equals(w.getWindowTag().toString())) {
+            gotReplacementWindow |= candidate.setReplacementWindowIfNeeded(w);
+        }
 
-                candidate.mReplacingWindow = w;
-                w.mSkipEnterAnimationForSeamlessReplacement = !candidate.mAnimateReplacingWindow;
-                // if we got a replacement window, reset the timeout to give drawing more time
-                mService.scheduleReplacingWindowTimeouts(this);
-            }
+        // if we got a replacement window, reset the timeout to give drawing more time
+        if (gotReplacementWindow) {
+            mService.scheduleWindowReplacementTimeouts(this);
         }
     }
 
     boolean waitingForReplacement() {
         for (int i = windows.size() - 1; i >= 0; i--) {
-            WindowState candidate = windows.get(i);
-            if (candidate.mWillReplaceWindow) {
+            final WindowState candidate = windows.get(i);
+            if (candidate.waitingForReplacement()) {
                 return true;
             }
         }
         return false;
     }
 
-    void clearTimedoutReplacesLocked() {
-        for (int i = windows.size() - 1; i >= 0;
-             // WindowState#remove() at bottom of loop may remove multiple entries from windows if
-             // the window to be removed has child windows. It also may not remove any windows from
-             // windows at all if win is exiting and currently animating away. This ensures that
-             // winNdx is monotonically decreasing and never beyond windows bounds.
-             i = Math.min(i - 1, windows.size() - 1)) {
-            final WindowState candidate = windows.get(i);
-            if (!candidate.mWillReplaceWindow) {
-                continue;
-            }
-            candidate.mWillReplaceWindow = false;
-            if (candidate.mReplacingWindow != null) {
-                candidate.mReplacingWindow.mSkipEnterAnimationForSeamlessReplacement = false;
-            }
-            // Since the window already timed out, remove it immediately now.
-            // Use WindowState#remove() instead of WindowState#removeIfPossible(), as the latter
-            // delays removal on certain conditions, which will leave the stale window in the
-            // stack and marked mWillReplaceWindow=false, so the window will never be removed.
-            candidate.remove();
+    void onWindowReplacementTimeout() {
+        for (int i = windows.size() - 1; i >= 0; --i) {
+            windows.get(i).onWindowReplacementTimeout();
         }
     }
 
@@ -956,14 +776,7 @@
         }
         for (int i = windows.size() - 1; i >= 0; i--) {
             final WindowState win = windows.get(i);
-            if (!win.mHasSurface) {
-                continue;
-            }
-            win.mLayoutNeeded = true;
-            win.setDisplayLayoutNeeded();
-            if (!mService.mResizingWindows.contains(win)) {
-                mService.mResizingWindows.add(win);
-            }
+            win.onUnfreezeBounds();
         }
         mService.mWindowPlacerLocked.performSurfacePlacement();
     }
@@ -1019,52 +832,21 @@
     void setWaitingForDrawnIfResizingChanged() {
         for (int i = windows.size() - 1; i >= 0; --i) {
             final WindowState win = windows.get(i);
-            if (win.isDragResizeChanged()) {
-                mService.mWaitingForDrawn.add(win);
-            }
+            win.setWaitingForDrawnIfResizingChanged();
         }
     }
 
     void resizeWindows() {
-        final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
-        // Some windows won't go through the resizing process, if they don't have a surface, so
-        // destroy all saved surfaces here.
-        destroySavedSurfaces();
-
         for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
             final WindowState win = windows.get(winNdx);
-            if (win.mHasSurface && !resizingWindows.contains(win)) {
-                if (DEBUG_RESIZE) Slog.d(TAG, "resizeWindows: Resizing " + win);
-                resizingWindows.add(win);
-
-                // If we are not drag resizing, force recreating of a new surface so updating
-                // the content and positioning that surface will be in sync.
-                //
-                // As we use this flag as a hint to freeze surface boundary updates,
-                // we'd like to only apply this to TYPE_BASE_APPLICATION,
-                // windows of TYPE_APPLICATION (or TYPE_DRAWN_APPLICATION) like dialogs,
-                // could appear to not be drag resizing while they resize, but we'd
-                // still like to manipulate their frame to update crop, etc...
-                //
-                // Anyway we don't need to synchronize position and content updates for these
-                // windows since they aren't at the base layer and could be moved around anyway.
-                if (!win.computeDragResizing() && win.mAttrs.type == TYPE_BASE_APPLICATION &&
-                        !mTask.mStack.getBoundsAnimating() && !win.isGoneForLayoutLw() &&
-                        !mTask.inPinnedWorkspace()) {
-                    win.setResizedWhileNotDragResizing(true);
-                }
-            }
-            if (win.isGoneForLayoutLw()) {
-                win.mResizedWhileGone = true;
-            }
+            win.addToResizingList();
         }
     }
 
-    void moveWindows() {
+    void setMovedByResize() {
         for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
             final WindowState win = windows.get(winNdx);
-            if (DEBUG_RESIZE) Slog.d(TAG, "moveWindows: Moving " + win);
-            win.mMovedByResize = true;
+            win.setMovedByResize();
         }
     }
 
@@ -1087,6 +869,7 @@
         for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
             // We are in the middle of changing the state of displays/stacks/tasks. We need
             // to finish that, before we let layout interfere with it.
+            // Also removes child windows.
             windows.get(winNdx).removeIfPossible();
             doAnotherLayoutPass = true;
         }
@@ -1097,18 +880,13 @@
 
     void forceWindowsScaleableInTransaction(boolean force) {
         for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
-            final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
-            if (winAnimator == null || !winAnimator.hasSurface()) {
-                continue;
-            }
-            winAnimator.mSurfaceController.forceScaleableInTransaction(force);
+            windows.get(winNdx).forceWindowsScaleableInTransaction(force);
         }
     }
 
     boolean isAnimating() {
         for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
-            final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
-            if (winAnimator.isAnimationSet() || winAnimator.mWin.mAnimatingExit) {
+            if (windows.get(winNdx).isAnimating()) {
                 return true;
             }
         }
@@ -1118,6 +896,7 @@
     void setAppLayoutChanges(int changes, String reason, int displayId) {
         final WindowAnimator windowAnimator = mAppAnimator.mAnimator;
         for (int i = windows.size() - 1; i >= 0; i--) {
+            // Child windows will be on the same display as their parents.
             if (displayId == windows.get(i).getDisplayId()) {
                 windowAnimator.setPendingLayoutChanges(displayId, changes);
                 if (DEBUG_LAYOUT_REPEATS) {
@@ -1132,17 +911,16 @@
     void removeReplacedWindowIfNeeded(WindowState replacement) {
         for (int i = windows.size() - 1; i >= 0; i--) {
             final WindowState win = windows.get(i);
-            if (win.mWillReplaceWindow && win.mReplacingWindow == replacement
-                    && replacement.hasDrawnLw()) {
-                replacement.mSkipEnterAnimationForSeamlessReplacement = false;
-                win.removeReplacedWindow();
+            if (win.removeReplacedWindowIfNeeded(replacement)) {
+                return;
             }
         }
     }
 
     void startFreezingScreen() {
         if (DEBUG_ORIENTATION) logWithStack(TAG, "Set freezing of " + appToken + ": hidden="
-                + hidden + " freezing=" + mAppAnimator.freezingScreen);
+                + hidden + " freezing=" + mAppAnimator.freezingScreen + " hiddenRequested="
+                + hiddenRequested);
         if (!hiddenRequested) {
             if (!mAppAnimator.freezingScreen) {
                 mAppAnimator.freezingScreen = true;
@@ -1157,7 +935,7 @@
             final int count = windows.size();
             for (int i = 0; i < count; i++) {
                 final WindowState w = windows.get(i);
-                w.mAppFreezing = true;
+                w.onStartFreezingScreen();
             }
         }
     }
@@ -1171,18 +949,7 @@
         boolean unfrozeWindows = false;
         for (int i = 0; i < count; i++) {
             final WindowState w = windows.get(i);
-            if (w.mAppFreezing) {
-                w.mAppFreezing = false;
-                if (w.mHasSurface && !w.mOrientationChanging
-                        && mService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
-                    if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "set mOrientationChanging of " + w);
-                    w.mOrientationChanging = true;
-                    mService.mWindowPlacerLocked.mOrientationChangeComplete = false;
-                }
-                w.mLastFreezeDuration = 0;
-                unfrozeWindows = true;
-                w.setDisplayLayoutNeeded();
-            }
+            unfrozeWindows |= w.onStopFreezingScreen();
         }
         if (force || unfrozeWindows) {
             if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "No longer freezing: " + this);
@@ -1297,8 +1064,8 @@
         return false;
     }
 
-    int getWindowsCount() {
-        return windows.size();
+    boolean isLastWindow(WindowState win) {
+        return windows.size() == 1 && windows.get(0) == win;
     }
 
     void setAllAppWinAnimators() {
@@ -1307,7 +1074,7 @@
 
         final int windowsCount = windows.size();
         for (int j = 0; j < windowsCount; j++) {
-            allAppWinAnimators.add(windows.get(j).mWinAnimator);
+            windows.get(j).addWinAnimatorToList(allAppWinAnimators);
         }
     }