Made AppWindowToken.allAppWindows private

Pre-clean-up before switching class to using WindowContainer.

Bug: 30060889
Change-Id: Ic3d47d47b922668eeb70988ce883267b46ca9d72
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 01be4c8..bbd6fd7 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -17,18 +17,27 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.StackId;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+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;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN;
+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;
 import com.android.server.wm.WindowManagerService.H;
@@ -37,8 +46,11 @@
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
+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;
 import android.view.View;
@@ -63,7 +75,7 @@
 
     // All of the windows and child windows that are included in this
     // application token.  Note this list is NOT sorted!
-    final WindowList allAppWindows = new WindowList();
+    private final WindowList allAppWindows = new WindowList();
     @NonNull final AppWindowAnimator mAppAnimator;
 
     final boolean voiceInteraction;
@@ -280,6 +292,149 @@
         }
     }
 
+    boolean setVisibility(WindowManager.LayoutParams lp,
+            boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction) {
+
+        boolean delayed = false;
+        inPendingTransaction = false;
+
+        if (clientHidden == visible) {
+            clientHidden = !visible;
+            sendAppVisibilityToClients();
+        }
+
+        // Allow for state changes and animation to be applied if:
+        // * token is transitioning visibility state
+        // * or the token was marked as hidden and is exiting before we had a chance to play the
+        // transition animation
+        // * or this is an opening app and windows are being replaced.
+        boolean visibilityChanged = false;
+        if (hidden == visible || (hidden && mIsExiting) || (visible && waitingForReplacement())) {
+            final AccessibilityController accessibilityController = service.mAccessibilityController;
+            boolean changed = false;
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
+                    "Changing app " + this + " hidden=" + hidden + " performLayout=" + performLayout);
+
+            boolean runningAppAnimation = false;
+
+            if (transit != AppTransition.TRANSIT_UNSET) {
+                if (mAppAnimator.animation == AppWindowAnimator.sDummyAnimation) {
+                    mAppAnimator.setNullAnimation();
+                }
+                if (service.applyAnimationLocked(this, lp, transit, visible, isVoiceInteraction)) {
+                    delayed = runningAppAnimation = true;
+                }
+                final WindowState window = findMainWindow();
+                //TODO (multidisplay): Magnification is supported only for the default display.
+                if (window != null && accessibilityController != null
+                        && window.getDisplayId() == DEFAULT_DISPLAY) {
+                    accessibilityController.onAppWindowTransitionLocked(window, transit);
+                }
+                changed = true;
+            }
+
+            final int windowsCount = allAppWindows.size();
+            for (int i = 0; i < windowsCount; i++) {
+                final WindowState win = allAppWindows.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();
+                }
+            }
+
+            hidden = hiddenRequested = !visible;
+            visibilityChanged = true;
+            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 (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "setVisibility: " + this
+                    + ": hidden=" + hidden + " hiddenRequested=" + hiddenRequested);
+
+            if (changed) {
+                service.mInputMonitor.setUpdateInputWindowsNeededLw();
+                if (performLayout) {
+                    service.updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
+                            false /*updateInputWindows*/);
+                    service.mWindowPlacerLocked.performSurfacePlacement();
+                }
+                service.mInputMonitor.updateInputWindowsLw(false /*force*/);
+            }
+        }
+
+        if (mAppAnimator.animation != null) {
+            delayed = true;
+        }
+
+        for (int i = allAppWindows.size() - 1; i >= 0 && !delayed; i--) {
+            if (allAppWindows.get(i).mWinAnimator.isWindowAnimationSet()) {
+                delayed = true;
+            }
+        }
+
+        if (visibilityChanged) {
+            if (visible && !delayed) {
+                // The token was made immediately visible, there will be no entrance animation.
+                // We need to inform the client the enter animation was finished.
+                mEnteringAnimation = true;
+                service.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(token);
+            }
+
+            if (!service.mClosingApps.contains(this) && !service.mOpeningApps.contains(this)) {
+                // The token is not closing nor opening, so even if there is an animation set, that
+                // doesn't mean that it goes through the normal app transition cycle so we have
+                // to inform the docked controller about visibility change.
+                service.getDefaultDisplayContentLocked().getDockedDividerController()
+                        .notifyAppVisibilityChanged();
+            }
+        }
+
+        return delayed;
+    }
+
     WindowState findMainWindow() {
         WindowState candidate = null;
         int j = allAppWindows.size();
@@ -323,6 +478,16 @@
         return false;
     }
 
+    boolean isVisibleForUser() {
+        for (int j = allAppWindows.size() - 1; j >= 0; j--) {
+            final WindowState w = allAppWindows.get(j);
+            if (!w.isHiddenFromUserLocked()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     void removeAppFromTaskLocked() {
         mIsExiting = false;
         removeAllWindows();
@@ -585,6 +750,27 @@
         windows.clear();
     }
 
+    @Override
+    void removeWindow(WindowState win) {
+        super.removeWindow(win);
+
+        allAppWindows.remove(win);
+
+        if (startingWindow == win) {
+            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Notify removed startingWindow " + win);
+            service.scheduleRemoveStartingWindowLocked(this);
+        } else if (allAppWindows.size() == 0 && startingData != null) {
+            // If this is the last window and we had requested a starting transition window,
+            // well there is no point now.
+            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Nulling last startingWindow");
+            startingData = null;
+        } else if (allAppWindows.size() == 1 && startingView != null) {
+            // If this is the last window except for a starting transition window,
+            // we need to get rid of the starting transition.
+            service.scheduleRemoveStartingWindowLocked(this);
+        }
+    }
+
     void removeAllDeadWindows() {
         for (int winNdx = allAppWindows.size() - 1; winNdx >= 0;
             // removeWindowLocked at bottom of loop may remove multiple entries from
@@ -691,6 +877,10 @@
     }
 
     void addWindow(WindowState w) {
+        if (allAppWindows.contains(w)) {
+            return;
+        }
+
         for (int i = allAppWindows.size() - 1; i >= 0; i--) {
             WindowState candidate = allAppWindows.get(i);
             if (candidate.mWillReplaceWindow && candidate.mReplacingWindow == null &&
@@ -819,6 +1009,350 @@
         }
     }
 
+    void resetJustMovedInStack() {
+        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
+            allAppWindows.get(i).resetJustMovedInStack();
+        }
+    }
+
+    @Override
+    int adjustAnimLayer(int adj) {
+        int highestAnimLayer = super.adjustAnimLayer(adj);
+
+        final int windowCount = allAppWindows.size();
+
+        for (int i = 0; i < windowCount; i++) {
+            final WindowState w = allAppWindows.get(i);
+            w.adjustAnimLayer(adj);
+
+            final int animLayer = w.mWinAnimator.mAnimLayer;
+            if (DEBUG_LAYERS) Slog.v(TAG, "Updating layer " + w + ": " + animLayer);
+            if (animLayer > highestAnimLayer) {
+                highestAnimLayer = animLayer;
+            }
+            if (w == service.mInputMethodTarget && !service.mInputMethodTargetWaitingAnim) {
+                service.mLayersController.setInputMethodAnimLayerAdjustment(adj);
+            }
+        }
+
+        return highestAnimLayer;
+    }
+
+    @Override
+    int getHighestAnimLayer() {
+        int layer = super.getHighestAnimLayer();
+        for (int j = 0; j < allAppWindows.size(); j++) {
+            final WindowState win = allAppWindows.get(j);
+            if (win.mWinAnimator.mAnimLayer > layer) {
+                layer = win.mWinAnimator.mAnimLayer;
+            }
+        }
+        return layer;
+    }
+
+    void setWaitingForDrawnIfResizingChanged() {
+        for (int i = allAppWindows.size() - 1; i >= 0; --i) {
+            final WindowState win = allAppWindows.get(i);
+            if (win.isDragResizeChanged()) {
+                service.mWaitingForDrawn.add(win);
+            }
+        }
+    }
+
+    void resizeWindows() {
+        final ArrayList<WindowState> resizingWindows = service.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 = allAppWindows.size() - 1; winNdx >= 0; --winNdx) {
+            final WindowState win = allAppWindows.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 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;
+            }
+        }
+    }
+
+    void moveWindows() {
+        for (int winNdx = allAppWindows.size() - 1; winNdx >= 0; --winNdx) {
+            final WindowState win = allAppWindows.get(winNdx);
+            if (DEBUG_RESIZE) Slog.d(TAG, "moveWindows: Moving " + win);
+            win.mMovedByResize = true;
+        }
+    }
+
+    void notifyMovedInStack() {
+        for (int winNdx = allAppWindows.size() - 1; winNdx >= 0; --winNdx) {
+            final WindowState win = allAppWindows.get(winNdx);
+            win.notifyMovedInStack();
+        }
+    }
+
+    void resetDragResizingChangeReported() {
+        for (int winNdx = allAppWindows.size() - 1; winNdx >= 0; --winNdx) {
+            final WindowState win = allAppWindows.get(winNdx);
+            win.resetDragResizingChangeReported();
+        }
+    }
+
+    void detachDisplay() {
+        boolean doAnotherLayoutPass = false;
+        for (int winNdx = allAppWindows.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.
+            service.removeWindowLocked(allAppWindows.get(winNdx));
+            doAnotherLayoutPass = true;
+        }
+        if (doAnotherLayoutPass) {
+            service.mWindowPlacerLocked.requestTraversal();
+        }
+    }
+
+    void forceWindowsScaleableInTransaction(boolean force) {
+        for (int winNdx = allAppWindows.size() - 1; winNdx >= 0; --winNdx) {
+            final WindowStateAnimator winAnimator = allAppWindows.get(winNdx).mWinAnimator;
+            if (winAnimator == null || !winAnimator.hasSurface()) {
+                continue;
+            }
+            winAnimator.mSurfaceController.forceScaleableInTransaction(force);
+        }
+    }
+
+    boolean isAnimating() {
+        for (int winNdx = allAppWindows.size() - 1; winNdx >= 0; --winNdx) {
+            final WindowStateAnimator winAnimator = allAppWindows.get(winNdx).mWinAnimator;
+            if (winAnimator.isAnimationSet() || winAnimator.mWin.mAnimatingExit) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    void setAppLayoutChanges(int changes, String reason, int displayId) {
+        final WindowAnimator windowAnimator = mAppAnimator.mAnimator;
+        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
+            if (displayId == allAppWindows.get(i).getDisplayId()) {
+                windowAnimator.setPendingLayoutChanges(displayId, changes);
+                if (DEBUG_LAYOUT_REPEATS) {
+                    service.mWindowPlacerLocked.debugLayoutRepeats(
+                            reason, windowAnimator.getPendingLayoutChanges(displayId));
+                }
+                break;
+            }
+        }
+    }
+
+    void removeReplacedWindowIfNeeded(WindowState replacement) {
+        for (int i = allAppWindows.size() - 1; i >= 0; i--) {
+            final WindowState win = allAppWindows.get(i);
+            if (win.mWillReplaceWindow && win.mReplacingWindow == replacement
+                    && replacement.hasDrawnLw()) {
+                replacement.mSkipEnterAnimationForSeamlessReplacement = false;
+                win.removeReplacedWindow();
+            }
+        }
+    }
+
+    void startFreezingScreen() {
+        if (DEBUG_ORIENTATION) logWithStack(TAG, "Set freezing of " + appToken + ": hidden="
+                + hidden + " freezing=" + mAppAnimator.freezingScreen);
+        if (!hiddenRequested) {
+            if (!mAppAnimator.freezingScreen) {
+                mAppAnimator.freezingScreen = true;
+                mAppAnimator.lastFreezeDuration = 0;
+                service.mAppsFreezingScreen++;
+                if (service.mAppsFreezingScreen == 1) {
+                    service.startFreezingDisplayLocked(false, 0, 0);
+                    service.mH.removeMessages(H.APP_FREEZE_TIMEOUT);
+                    service.mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000);
+                }
+            }
+            final int count = allAppWindows.size();
+            for (int i = 0; i < count; i++) {
+                final WindowState w = allAppWindows.get(i);
+                w.mAppFreezing = true;
+            }
+        }
+    }
+
+    void stopFreezingScreen(boolean unfreezeSurfaceNow, boolean force) {
+        if (!mAppAnimator.freezingScreen) {
+            return;
+        }
+        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + this + " force=" + force);
+        final int count = allAppWindows.size();
+        boolean unfrozeWindows = false;
+        for (int i = 0; i < count; i++) {
+            final WindowState w = allAppWindows.get(i);
+            if (w.mAppFreezing) {
+                w.mAppFreezing = false;
+                if (w.mHasSurface && !w.mOrientationChanging
+                        && service.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
+                    if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "set mOrientationChanging of " + w);
+                    w.mOrientationChanging = true;
+                    service.mWindowPlacerLocked.mOrientationChangeComplete = false;
+                }
+                w.mLastFreezeDuration = 0;
+                unfrozeWindows = true;
+                w.setDisplayLayoutNeeded();
+            }
+        }
+        if (force || unfrozeWindows) {
+            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "No longer freezing: " + this);
+            mAppAnimator.freezingScreen = false;
+            mAppAnimator.lastFreezeDuration =
+                    (int)(SystemClock.elapsedRealtime() - service.mDisplayFreezeTime);
+            service.mAppsFreezingScreen--;
+            service.mLastFinishedFreezeSource = this;
+        }
+        if (unfreezeSurfaceNow) {
+            if (unfrozeWindows) {
+                service.mWindowPlacerLocked.performSurfacePlacement();
+            }
+            service.stopFreezingDisplayLocked();
+        }
+    }
+
+    boolean transferStartingWindow(IBinder transferFrom) {
+        final AppWindowToken fromToken = service.findAppWindowToken(transferFrom);
+        if (fromToken == null) {
+            return false;
+        }
+
+        final WindowState tStartingWindow = fromToken.startingWindow;
+        if (tStartingWindow != null && fromToken.startingView != null) {
+            // In this case, the starting icon has already been displayed, so start
+            // letting windows get shown immediately without any more transitions.
+            service.mSkipAppTransitionAnimation = true;
+
+            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Moving existing starting " + tStartingWindow
+                    + " from " + fromToken + " to " + this);
+
+            final long origId = Binder.clearCallingIdentity();
+
+            // Transfer the starting window over to the new token.
+            startingData = fromToken.startingData;
+            startingView = fromToken.startingView;
+            startingDisplayed = fromToken.startingDisplayed;
+            fromToken.startingDisplayed = false;
+            startingWindow = tStartingWindow;
+            reportedVisible = fromToken.reportedVisible;
+            fromToken.startingData = null;
+            fromToken.startingView = null;
+            fromToken.startingWindow = null;
+            fromToken.startingMoved = true;
+            tStartingWindow.mToken = this;
+            tStartingWindow.mRootToken = this;
+            tStartingWindow.mAppToken = this;
+
+            if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
+                    "Removing starting window: " + tStartingWindow);
+            tStartingWindow.getWindowList().remove(tStartingWindow);
+            service.mWindowsChanged = true;
+            if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+                    "Removing starting " + tStartingWindow + " from " + fromToken);
+            fromToken.removeWindow(tStartingWindow);
+            fromToken.allAppWindows.remove(tStartingWindow);
+            addWindowToList(tStartingWindow);
+
+            // Propagate other interesting state between the tokens. If the old token is displayed,
+            // we should immediately force the new one to be displayed. If it is animating, we need
+            // to move that animation to the new one.
+            if (fromToken.allDrawn) {
+                allDrawn = true;
+                deferClearAllDrawn = fromToken.deferClearAllDrawn;
+            }
+            if (fromToken.firstWindowDrawn) {
+                firstWindowDrawn = true;
+            }
+            if (!fromToken.hidden) {
+                hidden = false;
+                hiddenRequested = false;
+            }
+            if (clientHidden != fromToken.clientHidden) {
+                clientHidden = fromToken.clientHidden;
+                sendAppVisibilityToClients();
+            }
+            fromToken.mAppAnimator.transferCurrentAnimation(
+                    mAppAnimator, tStartingWindow.mWinAnimator);
+
+            service.updateFocusedWindowLocked(
+                    UPDATE_FOCUS_WILL_PLACE_SURFACES, true /*updateInputWindows*/);
+            service.getDefaultDisplayContentLocked().layoutNeeded = true;
+            service.mWindowPlacerLocked.performSurfacePlacement();
+            Binder.restoreCallingIdentity(origId);
+            return true;
+        } else if (fromToken.startingData != null) {
+            // The previous app was getting ready to show a
+            // starting window, but hasn't yet done so.  Steal it!
+            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
+                    "Moving pending starting from " + fromToken + " to " + this);
+            startingData = fromToken.startingData;
+            fromToken.startingData = null;
+            fromToken.startingMoved = true;
+            final Message m = service.mH.obtainMessage(H.ADD_STARTING, this);
+            // Note: we really want to do sendMessageAtFrontOfQueue() because we want to process the
+            // message ASAP, before any other queued messages.
+            service.mH.sendMessageAtFrontOfQueue(m);
+            return true;
+        }
+
+        final AppWindowAnimator tAppAnimator = fromToken.mAppAnimator;
+        final AppWindowAnimator wAppAnimator = mAppAnimator;
+        if (tAppAnimator.thumbnail != null) {
+            // The old token is animating with a thumbnail, transfer that to the new token.
+            if (wAppAnimator.thumbnail != null) {
+                wAppAnimator.thumbnail.destroy();
+            }
+            wAppAnimator.thumbnail = tAppAnimator.thumbnail;
+            wAppAnimator.thumbnailLayer = tAppAnimator.thumbnailLayer;
+            wAppAnimator.thumbnailAnimation = tAppAnimator.thumbnailAnimation;
+            tAppAnimator.thumbnail = null;
+        }
+        return false;
+    }
+
+    int getWindowsCount() {
+        return allAppWindows.size();
+    }
+
+    void setAllAppWinAnimators() {
+        final ArrayList<WindowStateAnimator> allAppWinAnimators = mAppAnimator.mAllAppWinAnimators;
+        allAppWinAnimators.clear();
+
+        final int windowsCount = allAppWindows.size();
+        for (int j = 0; j < windowsCount; j++) {
+            allAppWinAnimators.add(allAppWindows.get(j).mWinAnimator);
+        }
+    }
+
+    /** Returns true if the app token windows list is empty. */
+    @Override
+    boolean isEmpty() {
+        return allAppWindows.isEmpty();
+    }
+
     @Override
     void dump(PrintWriter pw, String prefix) {
         super.dump(pw, prefix);