Home | History | Annotate | Download | only in wm
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.wm;
     18 
     19 import static android.app.ActivityManager.StackId;
     20 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
     21 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
     22 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
     23 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
     24 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
     25 import static android.view.Display.DEFAULT_DISPLAY;
     26 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
     27 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
     28 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
     29 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
     30 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
     31 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
     32 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
     33 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
     34 import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
     35 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
     36 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
     37 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
     38 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
     39 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
     40 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
     41 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
     42 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
     43 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
     44 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
     45 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
     46 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
     47 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
     48 import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN;
     49 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
     50 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
     51 import static com.android.server.wm.WindowManagerService.logWithStack;
     52 
     53 import android.annotation.NonNull;
     54 import android.app.Activity;
     55 import android.content.res.Configuration;
     56 import android.graphics.Rect;
     57 import android.os.Binder;
     58 import android.os.Debug;
     59 import android.os.IBinder;
     60 import android.os.SystemClock;
     61 import android.util.Slog;
     62 import android.view.IApplicationToken;
     63 import android.view.SurfaceControl;
     64 import android.view.WindowManager;
     65 import android.view.WindowManagerPolicy.StartingSurface;
     66 
     67 import com.android.internal.util.ToBooleanFunction;
     68 import com.android.server.input.InputApplicationHandle;
     69 import com.android.server.wm.WindowManagerService.H;
     70 
     71 import java.io.PrintWriter;
     72 import java.util.ArrayDeque;
     73 import java.util.ArrayList;
     74 
     75 import static android.os.Build.VERSION_CODES.O;
     76 
     77 class AppTokenList extends ArrayList<AppWindowToken> {
     78 }
     79 
     80 /**
     81  * Version of WindowToken that is specifically for a particular application (or
     82  * really activity) that is displaying windows.
     83  */
     84 class AppWindowToken extends WindowToken implements WindowManagerService.AppFreezeListener {
     85     private static final String TAG = TAG_WITH_CLASS_NAME ? "AppWindowToken" : TAG_WM;
     86 
     87     // Non-null only for application tokens.
     88     final IApplicationToken appToken;
     89 
     90     @NonNull final AppWindowAnimator mAppAnimator;
     91 
     92     final boolean mVoiceInteraction;
     93 
     94     /** @see WindowContainer#fillsParent() */
     95     private boolean mFillsParent;
     96     boolean layoutConfigChanges;
     97     boolean mShowForAllUsers;
     98     int mTargetSdk;
     99 
    100     // Flag set while reparenting to prevent actions normally triggered by an individual parent
    101     // change.
    102     private boolean mReparenting;
    103 
    104     // True if we are current in the process of removing this app token from the display
    105     private boolean mRemovingFromDisplay = false;
    106 
    107     // The input dispatching timeout for this application token in nanoseconds.
    108     long mInputDispatchingTimeoutNanos;
    109 
    110     // These are used for determining when all windows associated with
    111     // an activity have been drawn, so they can be made visible together
    112     // at the same time.
    113     // initialize so that it doesn't match mTransactionSequence which is an int.
    114     private long mLastTransactionSequence = Long.MIN_VALUE;
    115     private int mNumInterestingWindows;
    116     private int mNumDrawnWindows;
    117     boolean inPendingTransaction;
    118     boolean allDrawn;
    119     // Set to true when this app creates a surface while in the middle of an animation. In that
    120     // case do not clear allDrawn until the animation completes.
    121     boolean deferClearAllDrawn;
    122 
    123     /**
    124      * These are to track the app's real drawing status if there were no saved surfaces.
    125      * @see #updateDrawnWindowStates
    126      */
    127     boolean allDrawnExcludingSaved;
    128     private int mNumInterestingWindowsExcludingSaved;
    129     private int mNumDrawnWindowsExcludingSaved;
    130 
    131     // Is this window's surface needed?  This is almost like hidden, except
    132     // it will sometimes be true a little earlier: when the token has
    133     // been shown, but is still waiting for its app transition to execute
    134     // before making its windows shown.
    135     boolean hiddenRequested;
    136 
    137     // Have we told the window clients to hide themselves?
    138     private boolean mClientHidden;
    139 
    140     // If true we will defer setting mClientHidden to true and reporting to the client that it is
    141     // hidden.
    142     boolean mDeferHidingClient;
    143 
    144     // Last visibility state we reported to the app token.
    145     boolean reportedVisible;
    146 
    147     // Last drawn state we reported to the app token.
    148     private boolean reportedDrawn;
    149 
    150     // Set to true when the token has been removed from the window mgr.
    151     boolean removed;
    152 
    153     // Information about an application starting window if displayed.
    154     StartingData startingData;
    155     WindowState startingWindow;
    156     StartingSurface startingSurface;
    157     boolean startingDisplayed;
    158     boolean startingMoved;
    159     // True if the hidden state of this token was forced to false due to a transferred starting
    160     // window.
    161     private boolean mHiddenSetFromTransferredStartingWindow;
    162     boolean firstWindowDrawn;
    163     private final WindowState.UpdateReportedVisibilityResults mReportedVisibilityResults =
    164             new WindowState.UpdateReportedVisibilityResults();
    165 
    166     // Input application handle used by the input dispatcher.
    167     final InputApplicationHandle mInputApplicationHandle;
    168 
    169     // TODO: Have a WindowContainer state for tracking exiting/deferred removal.
    170     boolean mIsExiting;
    171 
    172     boolean mLaunchTaskBehind;
    173     boolean mEnteringAnimation;
    174 
    175     private boolean mAlwaysFocusable;
    176 
    177     boolean mAppStopped;
    178     int mRotationAnimationHint;
    179     private int mPendingRelaunchCount;
    180 
    181     private boolean mLastContainsShowWhenLockedWindow;
    182     private boolean mLastContainsDismissKeyguardWindow;
    183 
    184     // The bounds of this activity. Mainly used for aspect-ratio compatibility.
    185     // TODO(b/36505427): Every level on WindowContainer now has bounds information, which directly
    186     // affects the configuration. We should probably move this into that class.
    187     private final Rect mBounds = new Rect();
    188 
    189     ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
    190     ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>();
    191 
    192     private boolean mDisablePreviewScreenshots;
    193 
    194     Task mLastParent;
    195 
    196     AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction,
    197             DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen,
    198             boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint,
    199             int configChanges, boolean launchTaskBehind, boolean alwaysFocusable,
    200             AppWindowContainerController controller, Configuration overrideConfig, Rect bounds) {
    201         this(service, token, voiceInteraction, dc, fullscreen, overrideConfig, bounds);
    202         setController(controller);
    203         mInputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
    204         mShowForAllUsers = showForAllUsers;
    205         mTargetSdk = targetSdk;
    206         mOrientation = orientation;
    207         layoutConfigChanges = (configChanges & (CONFIG_SCREEN_SIZE | CONFIG_ORIENTATION)) != 0;
    208         mLaunchTaskBehind = launchTaskBehind;
    209         mAlwaysFocusable = alwaysFocusable;
    210         mRotationAnimationHint = rotationAnimationHint;
    211 
    212         // Application tokens start out hidden.
    213         hidden = true;
    214         hiddenRequested = true;
    215     }
    216 
    217     AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction,
    218             DisplayContent dc, boolean fillsParent, Configuration overrideConfig, Rect bounds) {
    219         super(service, token != null ? token.asBinder() : null, TYPE_APPLICATION, true, dc,
    220                 false /* ownerCanManageAppTokens */);
    221         appToken = token;
    222         mVoiceInteraction = voiceInteraction;
    223         mFillsParent = fillsParent;
    224         mInputApplicationHandle = new InputApplicationHandle(this);
    225         mAppAnimator = new AppWindowAnimator(this, service);
    226         if (overrideConfig != null) {
    227             onOverrideConfigurationChanged(overrideConfig);
    228         }
    229         if (bounds != null) {
    230             mBounds.set(bounds);
    231         }
    232     }
    233 
    234     void onOverrideConfigurationChanged(Configuration overrideConfiguration, Rect bounds) {
    235         onOverrideConfigurationChanged(overrideConfiguration);
    236         if (mBounds.equals(bounds)) {
    237             return;
    238         }
    239         // TODO(b/36505427): If bounds is in WC, then we can automatically call onResize() when set.
    240         mBounds.set(bounds);
    241         onResize();
    242     }
    243 
    244     void getBounds(Rect outBounds) {
    245         outBounds.set(mBounds);
    246     }
    247 
    248     boolean hasBounds() {
    249         return !mBounds.isEmpty();
    250     }
    251 
    252     void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) {
    253         firstWindowDrawn = true;
    254 
    255         // We now have a good window to show, remove dead placeholders
    256         removeDeadWindows();
    257 
    258         if (startingWindow != null) {
    259             if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Slog.v(TAG, "Finish starting "
    260                     + win.mToken + ": first real window is shown, no animation");
    261             // If this initial window is animating, stop it -- we will do an animation to reveal
    262             // it from behind the starting window, so there is no need for it to also be doing its
    263             // own stuff.
    264             winAnimator.clearAnimation();
    265             if (getController() != null) {
    266                 getController().removeStartingWindow();
    267             }
    268         }
    269         updateReportedVisibilityLocked();
    270     }
    271 
    272     void updateReportedVisibilityLocked() {
    273         if (appToken == null) {
    274             return;
    275         }
    276 
    277         if (DEBUG_VISIBILITY) Slog.v(TAG, "Update reported visibility: " + this);
    278         final int count = mChildren.size();
    279 
    280         mReportedVisibilityResults.reset();
    281 
    282         for (int i = 0; i < count; i++) {
    283             final WindowState win = mChildren.get(i);
    284             win.updateReportedVisibility(mReportedVisibilityResults);
    285         }
    286 
    287         int numInteresting = mReportedVisibilityResults.numInteresting;
    288         int numVisible = mReportedVisibilityResults.numVisible;
    289         int numDrawn = mReportedVisibilityResults.numDrawn;
    290         boolean nowGone = mReportedVisibilityResults.nowGone;
    291 
    292         boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting;
    293         boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting;
    294         if (!nowGone) {
    295             // If the app is not yet gone, then it can only become visible/drawn.
    296             if (!nowDrawn) {
    297                 nowDrawn = reportedDrawn;
    298             }
    299             if (!nowVisible) {
    300                 nowVisible = reportedVisible;
    301             }
    302         }
    303         if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting="
    304                 + numInteresting + " visible=" + numVisible);
    305         final AppWindowContainerController controller = getController();
    306         if (nowDrawn != reportedDrawn) {
    307             if (nowDrawn) {
    308                 if (controller != null) {
    309                     controller.reportWindowsDrawn();
    310                 }
    311             }
    312             reportedDrawn = nowDrawn;
    313         }
    314         if (nowVisible != reportedVisible) {
    315             if (DEBUG_VISIBILITY) Slog.v(TAG,
    316                     "Visibility changed in " + this + ": vis=" + nowVisible);
    317             reportedVisible = nowVisible;
    318             if (controller != null) {
    319                 if (nowVisible) {
    320                     controller.reportWindowsVisible();
    321                 } else {
    322                     controller.reportWindowsGone();
    323                 }
    324             }
    325         }
    326     }
    327 
    328     boolean isClientHidden() {
    329         return mClientHidden;
    330     }
    331 
    332     void setClientHidden(boolean hideClient) {
    333         if (mClientHidden == hideClient || (hideClient && mDeferHidingClient)) {
    334             return;
    335         }
    336         mClientHidden = hideClient;
    337         sendAppVisibilityToClients();
    338     }
    339 
    340     boolean setVisibility(WindowManager.LayoutParams lp,
    341             boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction) {
    342 
    343         boolean delayed = false;
    344         inPendingTransaction = false;
    345         // Reset the state of mHiddenSetFromTransferredStartingWindow since visibility is actually
    346         // been set by the app now.
    347         mHiddenSetFromTransferredStartingWindow = false;
    348         setClientHidden(!visible);
    349 
    350         // Allow for state changes and animation to be applied if:
    351         // * token is transitioning visibility state
    352         // * or the token was marked as hidden and is exiting before we had a chance to play the
    353         // transition animation
    354         // * or this is an opening app and windows are being replaced.
    355         boolean visibilityChanged = false;
    356         if (hidden == visible || (hidden && mIsExiting) || (visible && waitingForReplacement())) {
    357             final AccessibilityController accessibilityController = mService.mAccessibilityController;
    358             boolean changed = false;
    359             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
    360                     "Changing app " + this + " hidden=" + hidden + " performLayout=" + performLayout);
    361 
    362             boolean runningAppAnimation = false;
    363 
    364             if (transit != AppTransition.TRANSIT_UNSET) {
    365                 if (mAppAnimator.animation == AppWindowAnimator.sDummyAnimation) {
    366                     mAppAnimator.setNullAnimation();
    367                 }
    368                 if (mService.applyAnimationLocked(this, lp, transit, visible, isVoiceInteraction)) {
    369                     delayed = runningAppAnimation = true;
    370                 }
    371                 final WindowState window = findMainWindow();
    372                 //TODO (multidisplay): Magnification is supported only for the default display.
    373                 if (window != null && accessibilityController != null
    374                         && getDisplayContent().getDisplayId() == DEFAULT_DISPLAY) {
    375                     accessibilityController.onAppWindowTransitionLocked(window, transit);
    376                 }
    377                 changed = true;
    378             }
    379 
    380             final int windowsCount = mChildren.size();
    381             for (int i = 0; i < windowsCount; i++) {
    382                 final WindowState win = mChildren.get(i);
    383                 changed |= win.onAppVisibilityChanged(visible, runningAppAnimation);
    384             }
    385 
    386             hidden = hiddenRequested = !visible;
    387             visibilityChanged = true;
    388             if (!visible) {
    389                 stopFreezingScreen(true, true);
    390             } else {
    391                 // If we are being set visible, and the starting window is not yet displayed,
    392                 // then make sure it doesn't get displayed.
    393                 if (startingWindow != null && !startingWindow.isDrawnLw()) {
    394                     startingWindow.mPolicyVisibility = false;
    395                     startingWindow.mPolicyVisibilityAfterAnim = false;
    396                 }
    397 
    398                 // We are becoming visible, so better freeze the screen with the windows that are
    399                 // getting visible so we also wait for them.
    400                 forAllWindows(mService::makeWindowFreezingScreenIfNeededLocked, true);
    401             }
    402 
    403             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "setVisibility: " + this
    404                     + ": hidden=" + hidden + " hiddenRequested=" + hiddenRequested);
    405 
    406             if (changed) {
    407                 mService.mInputMonitor.setUpdateInputWindowsNeededLw();
    408                 if (performLayout) {
    409                     mService.updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
    410                             false /*updateInputWindows*/);
    411                     mService.mWindowPlacerLocked.performSurfacePlacement();
    412                 }
    413                 mService.mInputMonitor.updateInputWindowsLw(false /*force*/);
    414             }
    415         }
    416 
    417         if (mAppAnimator.animation != null) {
    418             delayed = true;
    419         }
    420 
    421         for (int i = mChildren.size() - 1; i >= 0 && !delayed; i--) {
    422             if ((mChildren.get(i)).isWindowAnimationSet()) {
    423                 delayed = true;
    424             }
    425         }
    426 
    427         if (visibilityChanged) {
    428             if (visible && !delayed) {
    429                 // The token was made immediately visible, there will be no entrance animation.
    430                 // We need to inform the client the enter animation was finished.
    431                 mEnteringAnimation = true;
    432                 mService.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(token);
    433             }
    434             // If we are hidden but there is no delay needed we immediately
    435             // apply the Surface transaction so that the ActivityManager
    436             // can have some guarantee on the Surface state
    437             // following setting the visibility.
    438             if (hidden && !delayed) {
    439                 SurfaceControl.openTransaction();
    440                 for (int i = mChildren.size() - 1; i >= 0; i--) {
    441                     mChildren.get(i).mWinAnimator.hide("immediately hidden");
    442                 }
    443                 SurfaceControl.closeTransaction();
    444             }
    445 
    446             if (!mService.mClosingApps.contains(this) && !mService.mOpeningApps.contains(this)) {
    447                 // The token is not closing nor opening, so even if there is an animation set, that
    448                 // doesn't mean that it goes through the normal app transition cycle so we have
    449                 // to inform the docked controller about visibility change.
    450                 // TODO(multi-display): notify docked divider on all displays where visibility was
    451                 // affected.
    452                 mService.getDefaultDisplayContentLocked().getDockedDividerController()
    453                         .notifyAppVisibilityChanged();
    454                 mService.mTaskSnapshotController.notifyAppVisibilityChanged(this, visible);
    455             }
    456         }
    457 
    458         return delayed;
    459     }
    460 
    461     WindowState findMainWindow() {
    462         WindowState candidate = null;
    463         int j = mChildren.size();
    464         while (j > 0) {
    465             j--;
    466             final WindowState win = mChildren.get(j);
    467             final int type = win.mAttrs.type;
    468             // No need to loop through child window as base application and starting types can't be
    469             // child windows.
    470             if (type == TYPE_BASE_APPLICATION || type == TYPE_APPLICATION_STARTING) {
    471                 // In cases where there are multiple windows, we prefer the non-exiting window. This
    472                 // happens for example when replacing windows during an activity relaunch. When
    473                 // constructing the animation, we want the new window, not the exiting one.
    474                 if (win.mAnimatingExit) {
    475                     candidate = win;
    476                 } else {
    477                     return win;
    478                 }
    479             }
    480         }
    481         return candidate;
    482     }
    483 
    484     boolean windowsAreFocusable() {
    485         return StackId.canReceiveKeys(getTask().mStack.mStackId) || mAlwaysFocusable;
    486     }
    487 
    488     AppWindowContainerController getController() {
    489         final WindowContainerController controller = super.getController();
    490         return controller != null ? (AppWindowContainerController) controller : null;
    491     }
    492 
    493     @Override
    494     boolean isVisible() {
    495         // If the app token isn't hidden then it is considered visible and there is no need to check
    496         // its children windows to see if they are visible.
    497         return !hidden;
    498     }
    499 
    500     @Override
    501     void removeImmediately() {
    502         onRemovedFromDisplay();
    503         super.removeImmediately();
    504     }
    505 
    506     @Override
    507     void removeIfPossible() {
    508         mIsExiting = false;
    509         removeAllWindowsIfPossible();
    510         removeImmediately();
    511     }
    512 
    513     @Override
    514     boolean checkCompleteDeferredRemoval() {
    515         if (mIsExiting) {
    516             removeIfPossible();
    517         }
    518         return super.checkCompleteDeferredRemoval();
    519     }
    520 
    521     void onRemovedFromDisplay() {
    522         if (mRemovingFromDisplay) {
    523             return;
    524         }
    525         mRemovingFromDisplay = true;
    526 
    527         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app token: " + this);
    528 
    529         boolean delayed = setVisibility(null, false, TRANSIT_UNSET, true, mVoiceInteraction);
    530 
    531         mService.mOpeningApps.remove(this);
    532         mService.mUnknownAppVisibilityController.appRemovedOrHidden(this);
    533         mService.mTaskSnapshotController.onAppRemoved(this);
    534         waitingToShow = false;
    535         if (mService.mClosingApps.contains(this)) {
    536             delayed = true;
    537         } else if (mService.mAppTransition.isTransitionSet()) {
    538             mService.mClosingApps.add(this);
    539             delayed = true;
    540         }
    541 
    542         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app " + this + " delayed=" + delayed
    543                 + " animation=" + mAppAnimator.animation + " animating=" + mAppAnimator.animating);
    544 
    545         if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM, "removeAppToken: "
    546                 + this + " delayed=" + delayed + " Callers=" + Debug.getCallers(4));
    547 
    548         if (startingData != null && getController() != null) {
    549             getController().removeStartingWindow();
    550         }
    551 
    552         // If this window was animating, then we need to ensure that the app transition notifies
    553         // that animations have completed in WMS.handleAnimatingStoppedAndTransitionLocked(), so
    554         // add to that list now
    555         if (mAppAnimator.animating) {
    556             mService.mNoAnimationNotifyOnTransitionFinished.add(token);
    557         }
    558 
    559         final TaskStack stack = getStack();
    560         if (delayed && !isEmpty()) {
    561             // set the token aside because it has an active animation to be finished
    562             if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM,
    563                     "removeAppToken make exiting: " + this);
    564             if (stack != null) {
    565                 stack.mExitingAppTokens.add(this);
    566             }
    567             mIsExiting = true;
    568         } else {
    569             // Make sure there is no animation running on this token, so any windows associated
    570             // with it will be removed as soon as their animations are complete
    571             mAppAnimator.clearAnimation();
    572             mAppAnimator.animating = false;
    573             if (stack != null) {
    574                 stack.mExitingAppTokens.remove(this);
    575             }
    576             removeIfPossible();
    577         }
    578 
    579         removed = true;
    580         stopFreezingScreen(true, true);
    581 
    582         if (mService.mFocusedApp == this) {
    583             if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Removing focused app token:" + this);
    584             mService.mFocusedApp = null;
    585             mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
    586             mService.mInputMonitor.setFocusedAppLw(null);
    587         }
    588 
    589         if (!delayed) {
    590             updateReportedVisibilityLocked();
    591         }
    592 
    593         mRemovingFromDisplay = false;
    594     }
    595 
    596     void clearAnimatingFlags() {
    597         boolean wallpaperMightChange = false;
    598         for (int i = mChildren.size() - 1; i >= 0; i--) {
    599             final WindowState win = mChildren.get(i);
    600             wallpaperMightChange |= win.clearAnimatingFlags();
    601         }
    602         if (wallpaperMightChange) {
    603             requestUpdateWallpaperIfNeeded();
    604         }
    605     }
    606 
    607     void destroySurfaces() {
    608         destroySurfaces(false /*cleanupOnResume*/);
    609     }
    610 
    611     /**
    612      * Destroy surfaces which have been marked as eligible by the animator, taking care to ensure
    613      * the client has finished with them.
    614      *
    615      * @param cleanupOnResume whether this is done when app is resumed without fully stopped. If
    616      * set to true, destroy only surfaces of removed windows, and clear relevant flags of the
    617      * others so that they are ready to be reused. If set to false (common case), destroy all
    618      * surfaces that's eligible, if the app is already stopped.
    619      */
    620     private void destroySurfaces(boolean cleanupOnResume) {
    621         boolean destroyedSomething = false;
    622         for (int i = mChildren.size() - 1; i >= 0; i--) {
    623             final WindowState win = mChildren.get(i);
    624             destroyedSomething |= win.destroySurface(cleanupOnResume, mAppStopped);
    625         }
    626         if (destroyedSomething) {
    627             final DisplayContent dc = getDisplayContent();
    628             dc.assignWindowLayers(true /*setLayoutNeeded*/);
    629         }
    630     }
    631 
    632     /**
    633      * Notify that the app is now resumed, and it was not stopped before, perform a clean
    634      * up of the surfaces
    635      */
    636     void notifyAppResumed(boolean wasStopped) {
    637         if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppResumed: wasStopped=" + wasStopped
    638                 + " " + this);
    639         mAppStopped = false;
    640         if (!wasStopped) {
    641             destroySurfaces(true /*cleanupOnResume*/);
    642         }
    643     }
    644 
    645     /**
    646      * Notify that the app has stopped, and it is okay to destroy any surfaces which were
    647      * keeping alive in case they were still being used.
    648      */
    649     void notifyAppStopped() {
    650         if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppStopped: " + this);
    651         mAppStopped = true;
    652         destroySurfaces();
    653         // Remove any starting window that was added for this app if they are still around.
    654         if (getController() != null) {
    655             getController().removeStartingWindow();
    656         }
    657     }
    658 
    659     /**
    660      * Checks whether we should save surfaces for this app.
    661      *
    662      * @return true if the surfaces should be saved, false otherwise.
    663      */
    664     boolean shouldSaveSurface() {
    665         // We want to save surface if the app's windows are "allDrawn".
    666         // (If we started entering animation early with saved surfaces, allDrawn
    667         // should have been restored to true. So we'll save again in that case
    668         // even if app didn't actually finish drawing.)
    669         return allDrawn;
    670     }
    671 
    672     private boolean canRestoreSurfaces() {
    673         for (int i = mChildren.size() -1; i >= 0; i--) {
    674             final WindowState w = mChildren.get(i);
    675             if (w.canRestoreSurface()) {
    676                 return true;
    677             }
    678         }
    679         return false;
    680     }
    681 
    682     private void clearWasVisibleBeforeClientHidden() {
    683         for (int i = mChildren.size() - 1; i >= 0; i--) {
    684             final WindowState w = mChildren.get(i);
    685             w.clearWasVisibleBeforeClientHidden();
    686         }
    687     }
    688 
    689     /**
    690      * Whether the app has some window that is invisible in layout, but
    691      * animating with saved surface.
    692      */
    693     boolean isAnimatingInvisibleWithSavedSurface() {
    694         for (int i = mChildren.size() - 1; i >= 0; i--) {
    695             final WindowState w = mChildren.get(i);
    696             if (w.isAnimatingInvisibleWithSavedSurface()) {
    697                 return true;
    698             }
    699         }
    700         return false;
    701     }
    702 
    703     /**
    704      * Hide all window surfaces that's still invisible in layout but animating
    705      * with a saved surface, and mark them destroying.
    706      */
    707     void stopUsingSavedSurfaceLocked() {
    708         for (int i = mChildren.size() - 1; i >= 0; i--) {
    709             final WindowState w = mChildren.get(i);
    710             w.stopUsingSavedSurface();
    711         }
    712         destroySurfaces();
    713     }
    714 
    715     void markSavedSurfaceExiting() {
    716         for (int i = mChildren.size() - 1; i >= 0; i--) {
    717             final WindowState w = mChildren.get(i);
    718             w.markSavedSurfaceExiting();
    719         }
    720     }
    721 
    722     void restoreSavedSurfaceForInterestingWindows() {
    723         if (!canRestoreSurfaces()) {
    724             clearWasVisibleBeforeClientHidden();
    725             return;
    726         }
    727 
    728         // Check if all interesting windows are drawn and we can mark allDrawn=true.
    729         int interestingNotDrawn = -1;
    730 
    731         for (int i = mChildren.size() - 1; i >= 0; i--) {
    732             final WindowState w = mChildren.get(i);
    733             interestingNotDrawn = w.restoreSavedSurfaceForInterestingWindow();
    734         }
    735 
    736         if (!allDrawn) {
    737             allDrawn = (interestingNotDrawn == 0);
    738             if (allDrawn) {
    739                 mService.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN, token).sendToTarget();
    740             }
    741         }
    742         clearWasVisibleBeforeClientHidden();
    743 
    744         if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG,
    745                 "restoreSavedSurfaceForInterestingWindows: " + this + " allDrawn=" + allDrawn
    746                 + " interestingNotDrawn=" + interestingNotDrawn);
    747     }
    748 
    749     void destroySavedSurfaces() {
    750         for (int i = mChildren.size() - 1; i >= 0; i--) {
    751             final WindowState win = mChildren.get(i);
    752             win.destroySavedSurface();
    753         }
    754     }
    755 
    756     void clearAllDrawn() {
    757         allDrawn = false;
    758         deferClearAllDrawn = false;
    759         allDrawnExcludingSaved = false;
    760     }
    761 
    762     Task getTask() {
    763         return (Task) getParent();
    764     }
    765 
    766     TaskStack getStack() {
    767         final Task task = getTask();
    768         if (task != null) {
    769             return task.mStack;
    770         } else {
    771             return null;
    772         }
    773     }
    774 
    775     @Override
    776     void onParentSet() {
    777         super.onParentSet();
    778 
    779         final Task task = getTask();
    780 
    781         // When the associated task is {@code null}, the {@link AppWindowToken} can no longer
    782         // access visual elements like the {@link DisplayContent}. We must remove any associations
    783         // such as animations.
    784         if (!mReparenting) {
    785             if (task == null) {
    786                 // It is possible we have been marked as a closing app earlier. We must remove ourselves
    787                 // from this list so we do not participate in any future animations.
    788                 mService.mClosingApps.remove(this);
    789             } else if (mLastParent != null && mLastParent.mStack != null) {
    790                 task.mStack.mExitingAppTokens.remove(this);
    791             }
    792         }
    793         mLastParent = task;
    794     }
    795 
    796     void postWindowRemoveStartingWindowCleanup(WindowState win) {
    797         // TODO: Something smells about the code below...Is there a better way?
    798         if (startingWindow == win) {
    799             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Notify removed startingWindow " + win);
    800             if (getController() != null) {
    801                 getController().removeStartingWindow();
    802             }
    803         } else if (mChildren.size() == 0) {
    804             // If this is the last window and we had requested a starting transition window,
    805             // well there is no point now.
    806             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Nulling last startingData");
    807             startingData = null;
    808             if (mHiddenSetFromTransferredStartingWindow) {
    809                 // We set the hidden state to false for the token from a transferred starting window.
    810                 // We now reset it back to true since the starting window was the last window in the
    811                 // token.
    812                 hidden = true;
    813             }
    814         } else if (mChildren.size() == 1 && startingSurface != null && !isRelaunching()) {
    815             // If this is the last window except for a starting transition window,
    816             // we need to get rid of the starting transition.
    817             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Last window, removing starting window "
    818                     + win);
    819             if (getController() != null) {
    820                 getController().removeStartingWindow();
    821             }
    822         }
    823     }
    824 
    825     void removeDeadWindows() {
    826         for (int winNdx = mChildren.size() - 1; winNdx >= 0; --winNdx) {
    827             WindowState win = mChildren.get(winNdx);
    828             if (win.mAppDied) {
    829                 if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.w(TAG,
    830                         "removeDeadWindows: " + win);
    831                 // Set mDestroying, we don't want any animation or delayed removal here.
    832                 win.mDestroying = true;
    833                 // Also removes child windows.
    834                 win.removeIfPossible();
    835             }
    836         }
    837     }
    838 
    839     boolean hasWindowsAlive() {
    840         for (int i = mChildren.size() - 1; i >= 0; i--) {
    841             // No need to loop through child windows as the answer should be the same as that of the
    842             // parent window.
    843             if (!(mChildren.get(i)).mAppDied) {
    844                 return true;
    845             }
    846         }
    847         return false;
    848     }
    849 
    850     void setWillReplaceWindows(boolean animate) {
    851         if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM,
    852                 "Marking app token " + this + " with replacing windows.");
    853 
    854         for (int i = mChildren.size() - 1; i >= 0; i--) {
    855             final WindowState w = mChildren.get(i);
    856             w.setWillReplaceWindow(animate);
    857         }
    858         if (animate) {
    859             // Set-up dummy animation so we can start treating windows associated with this
    860             // token like they are in transition before the new app window is ready for us to
    861             // run the real transition animation.
    862             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
    863                     "setWillReplaceWindow() Setting dummy animation on: " + this);
    864             mAppAnimator.setDummyAnimation();
    865         }
    866     }
    867 
    868     void setWillReplaceChildWindows() {
    869         if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + this
    870                 + " with replacing child windows.");
    871         for (int i = mChildren.size() - 1; i >= 0; i--) {
    872             final WindowState w = mChildren.get(i);
    873             w.setWillReplaceChildWindows();
    874         }
    875     }
    876 
    877     void clearWillReplaceWindows() {
    878         if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM,
    879                 "Resetting app token " + this + " of replacing window marks.");
    880 
    881         for (int i = mChildren.size() - 1; i >= 0; i--) {
    882             final WindowState w = mChildren.get(i);
    883             w.clearWillReplaceWindow();
    884         }
    885     }
    886 
    887     void requestUpdateWallpaperIfNeeded() {
    888         for (int i = mChildren.size() - 1; i >= 0; i--) {
    889             final WindowState w = mChildren.get(i);
    890             w.requestUpdateWallpaperIfNeeded();
    891         }
    892     }
    893 
    894     boolean isRelaunching() {
    895         return mPendingRelaunchCount > 0;
    896     }
    897 
    898     boolean shouldFreezeBounds() {
    899         final Task task = getTask();
    900 
    901         // For freeform windows, we can't freeze the bounds at the moment because this would make
    902         // the resizing unresponsive.
    903         if (task == null || task.inFreeformWorkspace()) {
    904             return false;
    905         }
    906 
    907         // We freeze the bounds while drag resizing to deal with the time between
    908         // the divider/drag handle being released, and the handling it's new
    909         // configuration. If we are relaunched outside of the drag resizing state,
    910         // we need to be careful not to do this.
    911         return getTask().isDragResizing();
    912     }
    913 
    914     void startRelaunching() {
    915         if (shouldFreezeBounds()) {
    916             freezeBounds();
    917         }
    918 
    919         // In the process of tearing down before relaunching, the app will
    920         // try and clean up it's child surfaces. We need to prevent this from
    921         // happening, so we sever the children, transfering their ownership
    922         // from the client it-self to the parent surface (owned by us).
    923         for (int i = mChildren.size() - 1; i >= 0; i--) {
    924             final WindowState w = mChildren.get(i);
    925             w.mWinAnimator.detachChildren();
    926         }
    927 
    928         mPendingRelaunchCount++;
    929     }
    930 
    931     void finishRelaunching() {
    932         unfreezeBounds();
    933 
    934         if (mPendingRelaunchCount > 0) {
    935             mPendingRelaunchCount--;
    936         } else {
    937             // Update keyguard flags upon finishing relaunch.
    938             checkKeyguardFlagsChanged();
    939         }
    940 
    941         updateAllDrawn();
    942     }
    943 
    944     void clearRelaunching() {
    945         if (mPendingRelaunchCount == 0) {
    946             return;
    947         }
    948         unfreezeBounds();
    949         mPendingRelaunchCount = 0;
    950     }
    951 
    952     /**
    953      * Returns true if the new child window we are adding to this token is considered greater than
    954      * the existing child window in this token in terms of z-order.
    955      */
    956     @Override
    957     protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow,
    958             WindowState existingWindow) {
    959         final int type1 = newWindow.mAttrs.type;
    960         final int type2 = existingWindow.mAttrs.type;
    961 
    962         // Base application windows should be z-ordered BELOW all other windows in the app token.
    963         if (type1 == TYPE_BASE_APPLICATION && type2 != TYPE_BASE_APPLICATION) {
    964             return false;
    965         } else if (type1 != TYPE_BASE_APPLICATION && type2 == TYPE_BASE_APPLICATION) {
    966             return true;
    967         }
    968 
    969         // Starting windows should be z-ordered ABOVE all other windows in the app token.
    970         if (type1 == TYPE_APPLICATION_STARTING && type2 != TYPE_APPLICATION_STARTING) {
    971             return true;
    972         } else if (type1 != TYPE_APPLICATION_STARTING && type2 == TYPE_APPLICATION_STARTING) {
    973             return false;
    974         }
    975 
    976         // Otherwise the new window is greater than the existing window.
    977         return true;
    978     }
    979 
    980     @Override
    981     void addWindow(WindowState w) {
    982         super.addWindow(w);
    983 
    984         boolean gotReplacementWindow = false;
    985         for (int i = mChildren.size() - 1; i >= 0; i--) {
    986             final WindowState candidate = mChildren.get(i);
    987             gotReplacementWindow |= candidate.setReplacementWindowIfNeeded(w);
    988         }
    989 
    990         // if we got a replacement window, reset the timeout to give drawing more time
    991         if (gotReplacementWindow) {
    992             mService.scheduleWindowReplacementTimeouts(this);
    993         }
    994         checkKeyguardFlagsChanged();
    995     }
    996 
    997     @Override
    998     void removeChild(WindowState child) {
    999         super.removeChild(child);
   1000         checkKeyguardFlagsChanged();
   1001     }
   1002 
   1003     private boolean waitingForReplacement() {
   1004         for (int i = mChildren.size() - 1; i >= 0; i--) {
   1005             final WindowState candidate = mChildren.get(i);
   1006             if (candidate.waitingForReplacement()) {
   1007                 return true;
   1008             }
   1009         }
   1010         return false;
   1011     }
   1012 
   1013     void onWindowReplacementTimeout() {
   1014         for (int i = mChildren.size() - 1; i >= 0; --i) {
   1015             (mChildren.get(i)).onWindowReplacementTimeout();
   1016         }
   1017     }
   1018 
   1019     void reparent(Task task, int position) {
   1020         final Task currentTask = getTask();
   1021         if (task == currentTask) {
   1022             throw new IllegalArgumentException(
   1023                     "window token=" + this + " already child of task=" + currentTask);
   1024         }
   1025 
   1026         if (currentTask.mStack != task.mStack) {
   1027             throw new IllegalArgumentException(
   1028                     "window token=" + this + " current task=" + currentTask
   1029                         + " belongs to a different stack than " + task);
   1030         }
   1031 
   1032         if (DEBUG_ADD_REMOVE) Slog.i(TAG, "reParentWindowToken: removing window token=" + this
   1033                 + " from task=" + currentTask);
   1034         final DisplayContent prevDisplayContent = getDisplayContent();
   1035 
   1036         mReparenting = true;
   1037 
   1038         getParent().removeChild(this);
   1039         task.addChild(this, position);
   1040 
   1041         mReparenting = false;
   1042 
   1043         // Relayout display(s).
   1044         final DisplayContent displayContent = task.getDisplayContent();
   1045         displayContent.setLayoutNeeded();
   1046         if (prevDisplayContent != displayContent) {
   1047             onDisplayChanged(displayContent);
   1048             prevDisplayContent.setLayoutNeeded();
   1049         }
   1050     }
   1051 
   1052     /**
   1053      * Freezes the task bounds. The size of this task reported the app will be fixed to the bounds
   1054      * freezed by {@link Task#prepareFreezingBounds} until {@link #unfreezeBounds} gets called, even
   1055      * if they change in the meantime. If the bounds are already frozen, the bounds will be frozen
   1056      * with a queue.
   1057      */
   1058     private void freezeBounds() {
   1059         final Task task = getTask();
   1060         mFrozenBounds.offer(new Rect(task.mPreparedFrozenBounds));
   1061 
   1062         if (task.mPreparedFrozenMergedConfig.equals(Configuration.EMPTY)) {
   1063             // We didn't call prepareFreezingBounds on the task, so use the current value.
   1064             mFrozenMergedConfig.offer(new Configuration(task.getConfiguration()));
   1065         } else {
   1066             mFrozenMergedConfig.offer(new Configuration(task.mPreparedFrozenMergedConfig));
   1067         }
   1068         // Calling unset() to make it equal to Configuration.EMPTY.
   1069         task.mPreparedFrozenMergedConfig.unset();
   1070     }
   1071 
   1072     /**
   1073      * Unfreezes the previously frozen bounds. See {@link #freezeBounds}.
   1074      */
   1075     private void unfreezeBounds() {
   1076         if (mFrozenBounds.isEmpty()) {
   1077             return;
   1078         }
   1079         mFrozenBounds.remove();
   1080         if (!mFrozenMergedConfig.isEmpty()) {
   1081             mFrozenMergedConfig.remove();
   1082         }
   1083         for (int i = mChildren.size() - 1; i >= 0; i--) {
   1084             final WindowState win = mChildren.get(i);
   1085             win.onUnfreezeBounds();
   1086         }
   1087         mService.mWindowPlacerLocked.performSurfacePlacement();
   1088     }
   1089 
   1090     void setAppLayoutChanges(int changes, String reason) {
   1091         if (!mChildren.isEmpty()) {
   1092             final DisplayContent dc = getDisplayContent();
   1093             dc.pendingLayoutChanges |= changes;
   1094             if (DEBUG_LAYOUT_REPEATS) {
   1095                 mService.mWindowPlacerLocked.debugLayoutRepeats(reason, dc.pendingLayoutChanges);
   1096             }
   1097         }
   1098     }
   1099 
   1100     void removeReplacedWindowIfNeeded(WindowState replacement) {
   1101         for (int i = mChildren.size() - 1; i >= 0; i--) {
   1102             final WindowState win = mChildren.get(i);
   1103             if (win.removeReplacedWindowIfNeeded(replacement)) {
   1104                 return;
   1105             }
   1106         }
   1107     }
   1108 
   1109     void startFreezingScreen() {
   1110         if (DEBUG_ORIENTATION) logWithStack(TAG, "Set freezing of " + appToken + ": hidden="
   1111                 + hidden + " freezing=" + mAppAnimator.freezingScreen + " hiddenRequested="
   1112                 + hiddenRequested);
   1113         if (!hiddenRequested) {
   1114             if (!mAppAnimator.freezingScreen) {
   1115                 mAppAnimator.freezingScreen = true;
   1116                 mService.registerAppFreezeListener(this);
   1117                 mAppAnimator.lastFreezeDuration = 0;
   1118                 mService.mAppsFreezingScreen++;
   1119                 if (mService.mAppsFreezingScreen == 1) {
   1120                     mService.startFreezingDisplayLocked(false, 0, 0, getDisplayContent());
   1121                     mService.mH.removeMessages(H.APP_FREEZE_TIMEOUT);
   1122                     mService.mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000);
   1123                 }
   1124             }
   1125             final int count = mChildren.size();
   1126             for (int i = 0; i < count; i++) {
   1127                 final WindowState w = mChildren.get(i);
   1128                 w.onStartFreezingScreen();
   1129             }
   1130         }
   1131     }
   1132 
   1133     void stopFreezingScreen(boolean unfreezeSurfaceNow, boolean force) {
   1134         if (!mAppAnimator.freezingScreen) {
   1135             return;
   1136         }
   1137         if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + this + " force=" + force);
   1138         final int count = mChildren.size();
   1139         boolean unfrozeWindows = false;
   1140         for (int i = 0; i < count; i++) {
   1141             final WindowState w = mChildren.get(i);
   1142             unfrozeWindows |= w.onStopFreezingScreen();
   1143         }
   1144         if (force || unfrozeWindows) {
   1145             if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "No longer freezing: " + this);
   1146             mAppAnimator.freezingScreen = false;
   1147             mService.unregisterAppFreezeListener(this);
   1148             mAppAnimator.lastFreezeDuration =
   1149                     (int)(SystemClock.elapsedRealtime() - mService.mDisplayFreezeTime);
   1150             mService.mAppsFreezingScreen--;
   1151             mService.mLastFinishedFreezeSource = this;
   1152         }
   1153         if (unfreezeSurfaceNow) {
   1154             if (unfrozeWindows) {
   1155                 mService.mWindowPlacerLocked.performSurfacePlacement();
   1156             }
   1157             mService.stopFreezingDisplayLocked();
   1158         }
   1159     }
   1160 
   1161     @Override
   1162     public void onAppFreezeTimeout() {
   1163         Slog.w(TAG_WM, "Force clearing freeze: " + this);
   1164         stopFreezingScreen(true, true);
   1165     }
   1166 
   1167     boolean transferStartingWindow(IBinder transferFrom) {
   1168         final AppWindowToken fromToken = getDisplayContent().getAppWindowToken(transferFrom);
   1169         if (fromToken == null) {
   1170             return false;
   1171         }
   1172 
   1173         final WindowState tStartingWindow = fromToken.startingWindow;
   1174         if (tStartingWindow != null && fromToken.startingSurface != null) {
   1175             // In this case, the starting icon has already been displayed, so start
   1176             // letting windows get shown immediately without any more transitions.
   1177             mService.mSkipAppTransitionAnimation = true;
   1178 
   1179             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Moving existing starting " + tStartingWindow
   1180                     + " from " + fromToken + " to " + this);
   1181 
   1182             final long origId = Binder.clearCallingIdentity();
   1183 
   1184             // Transfer the starting window over to the new token.
   1185             startingData = fromToken.startingData;
   1186             startingSurface = fromToken.startingSurface;
   1187             startingDisplayed = fromToken.startingDisplayed;
   1188             fromToken.startingDisplayed = false;
   1189             startingWindow = tStartingWindow;
   1190             reportedVisible = fromToken.reportedVisible;
   1191             fromToken.startingData = null;
   1192             fromToken.startingSurface = null;
   1193             fromToken.startingWindow = null;
   1194             fromToken.startingMoved = true;
   1195             tStartingWindow.mToken = this;
   1196             tStartingWindow.mAppToken = this;
   1197 
   1198             if (DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
   1199                     "Removing starting " + tStartingWindow + " from " + fromToken);
   1200             fromToken.removeChild(tStartingWindow);
   1201             fromToken.postWindowRemoveStartingWindowCleanup(tStartingWindow);
   1202             fromToken.mHiddenSetFromTransferredStartingWindow = false;
   1203             addWindow(tStartingWindow);
   1204 
   1205             // Propagate other interesting state between the tokens. If the old token is displayed,
   1206             // we should immediately force the new one to be displayed. If it is animating, we need
   1207             // to move that animation to the new one.
   1208             if (fromToken.allDrawn) {
   1209                 allDrawn = true;
   1210                 deferClearAllDrawn = fromToken.deferClearAllDrawn;
   1211             }
   1212             if (fromToken.firstWindowDrawn) {
   1213                 firstWindowDrawn = true;
   1214             }
   1215             if (!fromToken.hidden) {
   1216                 hidden = false;
   1217                 hiddenRequested = false;
   1218                 mHiddenSetFromTransferredStartingWindow = true;
   1219             }
   1220             setClientHidden(fromToken.mClientHidden);
   1221             fromToken.mAppAnimator.transferCurrentAnimation(
   1222                     mAppAnimator, tStartingWindow.mWinAnimator);
   1223 
   1224             mService.updateFocusedWindowLocked(
   1225                     UPDATE_FOCUS_WILL_PLACE_SURFACES, true /*updateInputWindows*/);
   1226             getDisplayContent().setLayoutNeeded();
   1227             mService.mWindowPlacerLocked.performSurfacePlacement();
   1228             Binder.restoreCallingIdentity(origId);
   1229             return true;
   1230         } else if (fromToken.startingData != null) {
   1231             // The previous app was getting ready to show a
   1232             // starting window, but hasn't yet done so.  Steal it!
   1233             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
   1234                     "Moving pending starting from " + fromToken + " to " + this);
   1235             startingData = fromToken.startingData;
   1236             fromToken.startingData = null;
   1237             fromToken.startingMoved = true;
   1238             if (getController() != null) {
   1239                 getController().scheduleAddStartingWindow();
   1240             }
   1241             return true;
   1242         }
   1243 
   1244         final AppWindowAnimator tAppAnimator = fromToken.mAppAnimator;
   1245         final AppWindowAnimator wAppAnimator = mAppAnimator;
   1246         if (tAppAnimator.thumbnail != null) {
   1247             // The old token is animating with a thumbnail, transfer that to the new token.
   1248             if (wAppAnimator.thumbnail != null) {
   1249                 wAppAnimator.thumbnail.destroy();
   1250             }
   1251             wAppAnimator.thumbnail = tAppAnimator.thumbnail;
   1252             wAppAnimator.thumbnailLayer = tAppAnimator.thumbnailLayer;
   1253             wAppAnimator.thumbnailAnimation = tAppAnimator.thumbnailAnimation;
   1254             tAppAnimator.thumbnail = null;
   1255         }
   1256         return false;
   1257     }
   1258 
   1259     boolean isLastWindow(WindowState win) {
   1260         return mChildren.size() == 1 && mChildren.get(0) == win;
   1261     }
   1262 
   1263     void setAllAppWinAnimators() {
   1264         final ArrayList<WindowStateAnimator> allAppWinAnimators = mAppAnimator.mAllAppWinAnimators;
   1265         allAppWinAnimators.clear();
   1266 
   1267         final int windowsCount = mChildren.size();
   1268         for (int j = 0; j < windowsCount; j++) {
   1269             (mChildren.get(j)).addWinAnimatorToList(allAppWinAnimators);
   1270         }
   1271     }
   1272 
   1273     @Override
   1274     void onAppTransitionDone() {
   1275         sendingToBottom = false;
   1276     }
   1277 
   1278     /**
   1279      * We override because this class doesn't want its children affecting its reported orientation
   1280      * in anyway.
   1281      */
   1282     @Override
   1283     int getOrientation(int candidate) {
   1284         // We do not allow non-fullscreen apps to influence orientation beyond O. While we do
   1285         // throw an exception in {@link Activity#onCreate} and
   1286         // {@link Activity#setRequestedOrientation}, we also ignore the orientation here so that
   1287         // other calculations aren't affected.
   1288         if (!fillsParent() && mTargetSdk > O) {
   1289             // Can't specify orientation if app doesn't fill parent.
   1290             return SCREEN_ORIENTATION_UNSET;
   1291         }
   1292 
   1293         if (candidate == SCREEN_ORIENTATION_BEHIND) {
   1294             // Allow app to specify orientation regardless of its visibility state if the current
   1295             // candidate want us to use orientation behind. I.e. the visible app on-top of this one
   1296             // wants us to use the orientation of the app behind it.
   1297             return mOrientation;
   1298         }
   1299 
   1300         // The {@link AppWindowToken} should only specify an orientation when it is not closing or
   1301         // going to the bottom. Allowing closing {@link AppWindowToken} to participate can lead to
   1302         // an Activity in another task being started in the wrong orientation during the transition.
   1303         if (!(sendingToBottom || mService.mClosingApps.contains(this))
   1304                 && (isVisible() || mService.mOpeningApps.contains(this))) {
   1305             return mOrientation;
   1306         }
   1307 
   1308         return SCREEN_ORIENTATION_UNSET;
   1309     }
   1310 
   1311     /** Returns the app's preferred orientation regardless of its currently visibility state. */
   1312     int getOrientationIgnoreVisibility() {
   1313         return mOrientation;
   1314     }
   1315 
   1316     @Override
   1317     void checkAppWindowsReadyToShow() {
   1318         if (allDrawn == mAppAnimator.allDrawn) {
   1319             return;
   1320         }
   1321 
   1322         mAppAnimator.allDrawn = allDrawn;
   1323         if (!allDrawn) {
   1324             return;
   1325         }
   1326 
   1327         // The token has now changed state to having all windows shown...  what to do, what to do?
   1328         if (mAppAnimator.freezingScreen) {
   1329             mAppAnimator.showAllWindowsLocked();
   1330             stopFreezingScreen(false, true);
   1331             if (DEBUG_ORIENTATION) Slog.i(TAG,
   1332                     "Setting mOrientationChangeComplete=true because wtoken " + this
   1333                     + " numInteresting=" + mNumInterestingWindows + " numDrawn=" + mNumDrawnWindows);
   1334             // This will set mOrientationChangeComplete and cause a pass through layout.
   1335             setAppLayoutChanges(FINISH_LAYOUT_REDO_WALLPAPER,
   1336                     "checkAppWindowsReadyToShow: freezingScreen");
   1337         } else {
   1338             setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM, "checkAppWindowsReadyToShow");
   1339 
   1340             // We can now show all of the drawn windows!
   1341             if (!mService.mOpeningApps.contains(this)) {
   1342                 mService.mAnimator.orAnimating(mAppAnimator.showAllWindowsLocked());
   1343             }
   1344         }
   1345     }
   1346 
   1347     void updateAllDrawn() {
   1348         if (!allDrawn) {
   1349             // Number of drawn windows can be less when a window is being relaunched, wait for
   1350             // all windows to be launched and drawn for this token be considered all drawn
   1351             final int numInteresting = mNumInterestingWindows;
   1352             if (numInteresting > 0 && mNumDrawnWindows >= numInteresting && !isRelaunching()) {
   1353                 if (DEBUG_VISIBILITY) Slog.v(TAG, "allDrawn: " + this
   1354                         + " interesting=" + numInteresting + " drawn=" + mNumDrawnWindows);
   1355                 allDrawn = true;
   1356                 // Force an additional layout pass where
   1357                 // WindowStateAnimator#commitFinishDrawingLocked() will call performShowLocked().
   1358                 if (mDisplayContent != null) {
   1359                     mDisplayContent.setLayoutNeeded();
   1360                 }
   1361                 mService.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN, token).sendToTarget();
   1362 
   1363                 // Notify the pinned stack upon all windows drawn. If there was an animation in
   1364                 // progress then this signal will resume that animation.
   1365                 final TaskStack pinnedStack = mDisplayContent.getStackById(PINNED_STACK_ID);
   1366                 if (pinnedStack != null) {
   1367                     pinnedStack.onAllWindowsDrawn();
   1368                 }
   1369             }
   1370         }
   1371 
   1372         if (!allDrawnExcludingSaved) {
   1373             int numInteresting = mNumInterestingWindowsExcludingSaved;
   1374             if (numInteresting > 0 && mNumDrawnWindowsExcludingSaved >= numInteresting) {
   1375                 if (DEBUG_VISIBILITY) Slog.v(TAG, "allDrawnExcludingSaved: " + this
   1376                         + " interesting=" + numInteresting
   1377                         + " drawn=" + mNumDrawnWindowsExcludingSaved);
   1378                 allDrawnExcludingSaved = true;
   1379                 if (mDisplayContent != null) {
   1380                     mDisplayContent.setLayoutNeeded();
   1381                 }
   1382                 if (isAnimatingInvisibleWithSavedSurface()
   1383                         && !mService.mFinishedEarlyAnim.contains(this)) {
   1384                     mService.mFinishedEarlyAnim.add(this);
   1385                 }
   1386             }
   1387         }
   1388     }
   1389 
   1390     /**
   1391      * Updated this app token tracking states for interesting and drawn windows based on the window.
   1392      *
   1393      * @return Returns true if the input window is considered interesting and drawn while all the
   1394      *         windows in this app token where not considered drawn as of the last pass.
   1395      */
   1396     boolean updateDrawnWindowStates(WindowState w) {
   1397         if (DEBUG_STARTING_WINDOW_VERBOSE && w == startingWindow) {
   1398             Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen=" + w.isOnScreen()
   1399                     + " allDrawn=" + allDrawn + " freezingScreen=" + mAppAnimator.freezingScreen);
   1400         }
   1401 
   1402         if (allDrawn && allDrawnExcludingSaved && !mAppAnimator.freezingScreen) {
   1403             return false;
   1404         }
   1405 
   1406         if (mLastTransactionSequence != mService.mTransactionSequence) {
   1407             mLastTransactionSequence = mService.mTransactionSequence;
   1408             mNumInterestingWindows = mNumDrawnWindows = 0;
   1409             mNumInterestingWindowsExcludingSaved = 0;
   1410             mNumDrawnWindowsExcludingSaved = 0;
   1411             startingDisplayed = false;
   1412         }
   1413 
   1414         final WindowStateAnimator winAnimator = w.mWinAnimator;
   1415 
   1416         boolean isInterestingAndDrawn = false;
   1417 
   1418         if (!allDrawn && w.mightAffectAllDrawn(false /* visibleOnly */)) {
   1419             if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
   1420                 Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
   1421                         + ", isAnimationSet=" + winAnimator.isAnimationSet());
   1422                 if (!w.isDrawnLw()) {
   1423                     Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceController
   1424                             + " pv=" + w.mPolicyVisibility
   1425                             + " mDrawState=" + winAnimator.drawStateToString()
   1426                             + " ph=" + w.isParentWindowHidden() + " th=" + hiddenRequested
   1427                             + " a=" + winAnimator.mAnimating);
   1428                 }
   1429             }
   1430 
   1431             if (w != startingWindow) {
   1432                 if (w.isInteresting()) {
   1433                     mNumInterestingWindows++;
   1434                     if (w.isDrawnLw()) {
   1435                         mNumDrawnWindows++;
   1436 
   1437                         if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG, "tokenMayBeDrawn: "
   1438                                 + this + " w=" + w + " numInteresting=" + mNumInterestingWindows
   1439                                 + " freezingScreen=" + mAppAnimator.freezingScreen
   1440                                 + " mAppFreezing=" + w.mAppFreezing);
   1441 
   1442                         isInterestingAndDrawn = true;
   1443                     }
   1444                 }
   1445             } else if (w.isDrawnLw()) {
   1446                 if (getController() != null) {
   1447                     getController().reportStartingWindowDrawn();
   1448                 }
   1449                 startingDisplayed = true;
   1450             }
   1451         }
   1452 
   1453         if (!allDrawnExcludingSaved && w.mightAffectAllDrawn(true /* visibleOnly */)) {
   1454             if (w != startingWindow && w.isInteresting()) {
   1455                 mNumInterestingWindowsExcludingSaved++;
   1456                 if (w.isDrawnLw() && !w.isAnimatingWithSavedSurface()) {
   1457                     mNumDrawnWindowsExcludingSaved++;
   1458 
   1459                     if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,
   1460                             "tokenMayBeDrawnExcludingSaved: " + this + " w=" + w
   1461                             + " numInteresting=" + mNumInterestingWindowsExcludingSaved
   1462                             + " freezingScreen=" + mAppAnimator.freezingScreen
   1463                             + " mAppFreezing=" + w.mAppFreezing);
   1464 
   1465                     isInterestingAndDrawn = true;
   1466                 }
   1467             }
   1468         }
   1469 
   1470         return isInterestingAndDrawn;
   1471     }
   1472 
   1473     @Override
   1474     void stepAppWindowsAnimation(long currentTime) {
   1475         mAppAnimator.wasAnimating = mAppAnimator.animating;
   1476         if (mAppAnimator.stepAnimationLocked(currentTime)) {
   1477             mAppAnimator.animating = true;
   1478             mService.mAnimator.setAnimating(true);
   1479             mService.mAnimator.mAppWindowAnimating = true;
   1480         } else if (mAppAnimator.wasAnimating) {
   1481             // stopped animating, do one more pass through the layout
   1482             setAppLayoutChanges(FINISH_LAYOUT_REDO_WALLPAPER,
   1483                     DEBUG_LAYOUT_REPEATS ? "appToken " + this + " done" : null);
   1484             if (DEBUG_ANIM) Slog.v(TAG, "updateWindowsApps...: done animating " + this);
   1485         }
   1486     }
   1487 
   1488     @Override
   1489     boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
   1490         // For legacy reasons we process the TaskStack.mExitingAppTokens first in DisplayContent
   1491         // before the non-exiting app tokens. So, we skip the exiting app tokens here.
   1492         // TODO: Investigate if we need to continue to do this or if we can just process them
   1493         // in-order.
   1494         if (mIsExiting && !waitingForReplacement()) {
   1495             return false;
   1496         }
   1497         return forAllWindowsUnchecked(callback, traverseTopToBottom);
   1498     }
   1499 
   1500     boolean forAllWindowsUnchecked(ToBooleanFunction<WindowState> callback,
   1501             boolean traverseTopToBottom) {
   1502         return super.forAllWindows(callback, traverseTopToBottom);
   1503     }
   1504 
   1505     @Override
   1506     AppWindowToken asAppWindowToken() {
   1507         // I am an app window token!
   1508         return this;
   1509     }
   1510 
   1511     @Override
   1512     boolean fillsParent() {
   1513         return mFillsParent;
   1514     }
   1515 
   1516     void setFillsParent(boolean fillsParent) {
   1517         mFillsParent = fillsParent;
   1518     }
   1519 
   1520     boolean containsDismissKeyguardWindow() {
   1521         // Window state is transient during relaunch. We are not guaranteed to be frozen during the
   1522         // entirety of the relaunch.
   1523         if (isRelaunching()) {
   1524             return mLastContainsDismissKeyguardWindow;
   1525         }
   1526 
   1527         for (int i = mChildren.size() - 1; i >= 0; i--) {
   1528             if ((mChildren.get(i).mAttrs.flags & FLAG_DISMISS_KEYGUARD) != 0) {
   1529                 return true;
   1530             }
   1531         }
   1532         return false;
   1533     }
   1534 
   1535     boolean containsShowWhenLockedWindow() {
   1536         // When we are relaunching, it is possible for us to be unfrozen before our previous
   1537         // windows have been added back. Using the cached value ensures that our previous
   1538         // showWhenLocked preference is honored until relaunching is complete.
   1539         if (isRelaunching()) {
   1540             return mLastContainsShowWhenLockedWindow;
   1541         }
   1542 
   1543         for (int i = mChildren.size() - 1; i >= 0; i--) {
   1544             if ((mChildren.get(i).mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
   1545                 return true;
   1546             }
   1547         }
   1548 
   1549         return false;
   1550     }
   1551 
   1552     void checkKeyguardFlagsChanged() {
   1553         final boolean containsDismissKeyguard = containsDismissKeyguardWindow();
   1554         final boolean containsShowWhenLocked = containsShowWhenLockedWindow();
   1555         if (containsDismissKeyguard != mLastContainsDismissKeyguardWindow
   1556                 || containsShowWhenLocked != mLastContainsShowWhenLockedWindow) {
   1557             mService.notifyKeyguardFlagsChanged(null /* callback */);
   1558         }
   1559         mLastContainsDismissKeyguardWindow = containsDismissKeyguard;
   1560         mLastContainsShowWhenLockedWindow = containsShowWhenLocked;
   1561     }
   1562 
   1563     WindowState getImeTargetBelowWindow(WindowState w) {
   1564         final int index = mChildren.indexOf(w);
   1565         if (index > 0) {
   1566             final WindowState target = mChildren.get(index - 1);
   1567             if (target.canBeImeTarget()) {
   1568                 return target;
   1569             }
   1570         }
   1571         return null;
   1572     }
   1573 
   1574     WindowState getHighestAnimLayerWindow(WindowState currentTarget) {
   1575         WindowState candidate = null;
   1576         for (int i = mChildren.indexOf(currentTarget); i >= 0; i--) {
   1577             final WindowState w = mChildren.get(i);
   1578             if (w.mRemoved) {
   1579                 continue;
   1580             }
   1581             if (candidate == null || w.mWinAnimator.mAnimLayer >
   1582                     candidate.mWinAnimator.mAnimLayer) {
   1583                 candidate = w;
   1584             }
   1585         }
   1586         return candidate;
   1587     }
   1588 
   1589     /**
   1590      * See {@link Activity#setDisablePreviewScreenshots}.
   1591      */
   1592     void setDisablePreviewScreenshots(boolean disable) {
   1593         mDisablePreviewScreenshots = disable;
   1594     }
   1595 
   1596     /**
   1597      * Retrieves whether we'd like to generate a snapshot that's based solely on the theme. This is
   1598      * the case when preview screenshots are disabled {@link #setDisablePreviewScreenshots} or when
   1599      * we can't take a snapshot for other reasons, for example, if we have a secure window.
   1600      *
   1601      * @return True if we need to generate an app theme snapshot, false if we'd like to take a real
   1602      *         screenshot.
   1603      */
   1604     boolean shouldUseAppThemeSnapshot() {
   1605         return mDisablePreviewScreenshots || forAllWindows(w -> (w.mAttrs.flags & FLAG_SECURE) != 0,
   1606                 true /* topToBottom */);
   1607     }
   1608 
   1609     @Override
   1610     int getAnimLayerAdjustment() {
   1611         return mAppAnimator.animLayerAdjustment;
   1612     }
   1613 
   1614     @Override
   1615     void dump(PrintWriter pw, String prefix) {
   1616         super.dump(pw, prefix);
   1617         if (appToken != null) {
   1618             pw.println(prefix + "app=true mVoiceInteraction=" + mVoiceInteraction);
   1619         }
   1620         pw.print(prefix); pw.print("task="); pw.println(getTask());
   1621         pw.print(prefix); pw.print(" mFillsParent="); pw.print(mFillsParent);
   1622                 pw.print(" mOrientation="); pw.println(mOrientation);
   1623         pw.println(prefix + "hiddenRequested=" + hiddenRequested + " mClientHidden=" + mClientHidden
   1624             + ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "")
   1625             + " reportedDrawn=" + reportedDrawn + " reportedVisible=" + reportedVisible);
   1626         if (paused) {
   1627             pw.print(prefix); pw.print("paused="); pw.println(paused);
   1628         }
   1629         if (mAppStopped) {
   1630             pw.print(prefix); pw.print("mAppStopped="); pw.println(mAppStopped);
   1631         }
   1632         if (mNumInterestingWindows != 0 || mNumDrawnWindows != 0
   1633                 || allDrawn || mAppAnimator.allDrawn) {
   1634             pw.print(prefix); pw.print("mNumInterestingWindows=");
   1635                     pw.print(mNumInterestingWindows);
   1636                     pw.print(" mNumDrawnWindows="); pw.print(mNumDrawnWindows);
   1637                     pw.print(" inPendingTransaction="); pw.print(inPendingTransaction);
   1638                     pw.print(" allDrawn="); pw.print(allDrawn);
   1639                     pw.print(" (animator="); pw.print(mAppAnimator.allDrawn);
   1640                     pw.println(")");
   1641         }
   1642         if (inPendingTransaction) {
   1643             pw.print(prefix); pw.print("inPendingTransaction=");
   1644                     pw.println(inPendingTransaction);
   1645         }
   1646         if (startingData != null || removed || firstWindowDrawn || mIsExiting) {
   1647             pw.print(prefix); pw.print("startingData="); pw.print(startingData);
   1648                     pw.print(" removed="); pw.print(removed);
   1649                     pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn);
   1650                     pw.print(" mIsExiting="); pw.println(mIsExiting);
   1651         }
   1652         if (startingWindow != null || startingSurface != null
   1653                 || startingDisplayed || startingMoved || mHiddenSetFromTransferredStartingWindow) {
   1654             pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow);
   1655                     pw.print(" startingSurface="); pw.print(startingSurface);
   1656                     pw.print(" startingDisplayed="); pw.print(startingDisplayed);
   1657                     pw.print(" startingMoved="); pw.print(startingMoved);
   1658                     pw.println(" mHiddenSetFromTransferredStartingWindow="
   1659                             + mHiddenSetFromTransferredStartingWindow);
   1660         }
   1661         if (!mFrozenBounds.isEmpty()) {
   1662             pw.print(prefix); pw.print("mFrozenBounds="); pw.println(mFrozenBounds);
   1663             pw.print(prefix); pw.print("mFrozenMergedConfig="); pw.println(mFrozenMergedConfig);
   1664         }
   1665         if (mPendingRelaunchCount != 0) {
   1666             pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount);
   1667         }
   1668         if (getController() != null) {
   1669             pw.print(prefix); pw.print("controller="); pw.println(getController());
   1670         }
   1671         if (mRemovingFromDisplay) {
   1672             pw.println(prefix + "mRemovingFromDisplay=" + mRemovingFromDisplay);
   1673         }
   1674     }
   1675 
   1676     @Override
   1677     public String toString() {
   1678         if (stringName == null) {
   1679             StringBuilder sb = new StringBuilder();
   1680             sb.append("AppWindowToken{");
   1681             sb.append(Integer.toHexString(System.identityHashCode(this)));
   1682             sb.append(" token="); sb.append(token); sb.append('}');
   1683             stringName = sb.toString();
   1684         }
   1685         return stringName + ((mIsExiting) ? " mIsExiting=" : "");
   1686     }
   1687 }
   1688