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.WindowConfiguration.WINDOWING_MODE_PINNED;
     20 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
     21 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
     22 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
     23 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
     24 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
     25 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
     26 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
     27 import static android.view.Display.DEFAULT_DISPLAY;
     28 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
     29 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
     30 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
     31 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
     32 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
     33 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
     34 
     35 import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
     36 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
     37 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
     38 import static android.view.WindowManager.TRANSIT_UNSET;
     39 
     40 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
     41 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
     42 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
     43 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
     44 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
     45 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
     46 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
     47 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
     48 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
     49 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
     50 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
     51 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
     52 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
     53 import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN;
     54 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
     55 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
     56 import static com.android.server.wm.WindowManagerService.logWithStack;
     57 import static com.android.server.wm.AppWindowTokenProto.ALL_DRAWN;
     58 import static com.android.server.wm.AppWindowTokenProto.APP_STOPPED;
     59 import static com.android.server.wm.AppWindowTokenProto.CLIENT_HIDDEN;
     60 import static com.android.server.wm.AppWindowTokenProto.DEFER_HIDING_CLIENT;
     61 import static com.android.server.wm.AppWindowTokenProto.FILLS_PARENT;
     62 import static com.android.server.wm.AppWindowTokenProto.FROZEN_BOUNDS;
     63 import static com.android.server.wm.AppWindowTokenProto.HIDDEN_REQUESTED;
     64 import static com.android.server.wm.AppWindowTokenProto.HIDDEN_SET_FROM_TRANSFERRED_STARTING_WINDOW;
     65 import static com.android.server.wm.AppWindowTokenProto.IS_REALLY_ANIMATING;
     66 import static com.android.server.wm.AppWindowTokenProto.IS_WAITING_FOR_TRANSITION_START;
     67 import static com.android.server.wm.AppWindowTokenProto.LAST_ALL_DRAWN;
     68 import static com.android.server.wm.AppWindowTokenProto.LAST_SURFACE_SHOWING;
     69 import static com.android.server.wm.AppWindowTokenProto.NAME;
     70 import static com.android.server.wm.AppWindowTokenProto.NUM_DRAWN_WINDOWS;
     71 import static com.android.server.wm.AppWindowTokenProto.NUM_INTERESTING_WINDOWS;
     72 import static com.android.server.wm.AppWindowTokenProto.REMOVED;
     73 import static com.android.server.wm.AppWindowTokenProto.REPORTED_DRAWN;
     74 import static com.android.server.wm.AppWindowTokenProto.REPORTED_VISIBLE;
     75 import static com.android.server.wm.AppWindowTokenProto.STARTING_DISPLAYED;
     76 import static com.android.server.wm.AppWindowTokenProto.STARTING_MOVED;
     77 import static com.android.server.wm.AppWindowTokenProto.STARTING_WINDOW;
     78 import static com.android.server.wm.AppWindowTokenProto.THUMBNAIL;
     79 import static com.android.server.wm.AppWindowTokenProto.WINDOW_TOKEN;
     80 
     81 import android.annotation.CallSuper;
     82 import android.app.Activity;
     83 import android.content.res.Configuration;
     84 import android.graphics.GraphicBuffer;
     85 import android.graphics.Point;
     86 import android.graphics.Rect;
     87 import android.os.Binder;
     88 import android.os.Debug;
     89 import android.os.IBinder;
     90 import android.os.RemoteException;
     91 import android.os.Trace;
     92 import android.util.Slog;
     93 import android.util.proto.ProtoOutputStream;
     94 import android.view.DisplayInfo;
     95 import android.view.IApplicationToken;
     96 import android.view.RemoteAnimationDefinition;
     97 import android.view.SurfaceControl;
     98 import android.view.SurfaceControl.Transaction;
     99 import android.view.WindowManager;
    100 import android.view.WindowManager.LayoutParams;
    101 import android.view.animation.Animation;
    102 
    103 import com.android.internal.R;
    104 import com.android.internal.util.ToBooleanFunction;
    105 import com.android.server.input.InputApplicationHandle;
    106 import com.android.server.policy.WindowManagerPolicy.StartingSurface;
    107 import com.android.server.wm.WindowManagerService.H;
    108 
    109 import java.io.PrintWriter;
    110 import java.util.ArrayDeque;
    111 import java.util.ArrayList;
    112 
    113 class AppTokenList extends ArrayList<AppWindowToken> {
    114 }
    115 
    116 /**
    117  * Version of WindowToken that is specifically for a particular application (or
    118  * really activity) that is displaying windows.
    119  */
    120 class AppWindowToken extends WindowToken implements WindowManagerService.AppFreezeListener {
    121     private static final String TAG = TAG_WITH_CLASS_NAME ? "AppWindowToken" : TAG_WM;
    122 
    123     /**
    124      * Value to increment the z-layer when boosting a layer during animations. BOOST in l33tsp34k.
    125      */
    126     private static final int Z_BOOST_BASE = 800570000;
    127 
    128     // Non-null only for application tokens.
    129     final IApplicationToken appToken;
    130 
    131     final boolean mVoiceInteraction;
    132 
    133     /** @see WindowContainer#fillsParent() */
    134     private boolean mFillsParent;
    135     boolean layoutConfigChanges;
    136     boolean mShowForAllUsers;
    137     int mTargetSdk;
    138 
    139     // Flag set while reparenting to prevent actions normally triggered by an individual parent
    140     // change.
    141     private boolean mReparenting;
    142 
    143     // True if we are current in the process of removing this app token from the display
    144     private boolean mRemovingFromDisplay = false;
    145 
    146     // The input dispatching timeout for this application token in nanoseconds.
    147     long mInputDispatchingTimeoutNanos;
    148 
    149     // These are used for determining when all windows associated with
    150     // an activity have been drawn, so they can be made visible together
    151     // at the same time.
    152     // initialize so that it doesn't match mTransactionSequence which is an int.
    153     private long mLastTransactionSequence = Long.MIN_VALUE;
    154     private int mNumInterestingWindows;
    155     private int mNumDrawnWindows;
    156     boolean inPendingTransaction;
    157     boolean allDrawn;
    158     private boolean mLastAllDrawn;
    159 
    160     // Set to true when this app creates a surface while in the middle of an animation. In that
    161     // case do not clear allDrawn until the animation completes.
    162     boolean deferClearAllDrawn;
    163 
    164     // Is this window's surface needed?  This is almost like hidden, except
    165     // it will sometimes be true a little earlier: when the token has
    166     // been shown, but is still waiting for its app transition to execute
    167     // before making its windows shown.
    168     boolean hiddenRequested;
    169 
    170     // Have we told the window clients to hide themselves?
    171     private boolean mClientHidden;
    172 
    173     // If true we will defer setting mClientHidden to true and reporting to the client that it is
    174     // hidden.
    175     boolean mDeferHidingClient;
    176 
    177     // Last visibility state we reported to the app token.
    178     boolean reportedVisible;
    179 
    180     // Last drawn state we reported to the app token.
    181     private boolean reportedDrawn;
    182 
    183     // Set to true when the token has been removed from the window mgr.
    184     boolean removed;
    185 
    186     // Information about an application starting window if displayed.
    187     StartingData startingData;
    188     WindowState startingWindow;
    189     StartingSurface startingSurface;
    190     boolean startingDisplayed;
    191     boolean startingMoved;
    192 
    193     // True if the hidden state of this token was forced to false due to a transferred starting
    194     // window.
    195     private boolean mHiddenSetFromTransferredStartingWindow;
    196     boolean firstWindowDrawn;
    197     private final WindowState.UpdateReportedVisibilityResults mReportedVisibilityResults =
    198             new WindowState.UpdateReportedVisibilityResults();
    199 
    200     // Input application handle used by the input dispatcher.
    201     final InputApplicationHandle mInputApplicationHandle;
    202 
    203     // TODO: Have a WindowContainer state for tracking exiting/deferred removal.
    204     boolean mIsExiting;
    205 
    206     boolean mLaunchTaskBehind;
    207     boolean mEnteringAnimation;
    208 
    209     private boolean mAlwaysFocusable;
    210 
    211     boolean mAppStopped;
    212     int mRotationAnimationHint;
    213     private int mPendingRelaunchCount;
    214 
    215     private boolean mLastContainsShowWhenLockedWindow;
    216     private boolean mLastContainsDismissKeyguardWindow;
    217 
    218     ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
    219     ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>();
    220 
    221     private boolean mDisablePreviewScreenshots;
    222 
    223     private Task mLastParent;
    224 
    225     /**
    226      * See {@link #canTurnScreenOn()}
    227      */
    228     private boolean mCanTurnScreenOn = true;
    229 
    230     /**
    231      * If we are running an animation, this determines the transition type. Must be one of
    232      * AppTransition.TRANSIT_* constants.
    233      */
    234     private int mTransit;
    235 
    236     /**
    237      * If we are running an animation, this determines the flags during this animation. Must be a
    238      * bitwise combination of AppTransition.TRANSIT_FLAG_* constants.
    239      */
    240     private int mTransitFlags;
    241 
    242     /** Whether our surface was set to be showing in the last call to {@link #prepareSurfaces} */
    243     private boolean mLastSurfaceShowing = true;
    244 
    245     private AppWindowThumbnail mThumbnail;
    246 
    247     /** Have we been asked to have this token keep the screen frozen? */
    248     private boolean mFreezingScreen;
    249 
    250     /** Whether this token should be boosted at the top of all app window tokens. */
    251     private boolean mNeedsZBoost;
    252     private Letterbox mLetterbox;
    253 
    254     private final Point mTmpPoint = new Point();
    255     private final Rect mTmpRect = new Rect();
    256     private RemoteAnimationDefinition mRemoteAnimationDefinition;
    257     private AnimatingAppWindowTokenRegistry mAnimatingAppWindowTokenRegistry;
    258 
    259     /**
    260      * A flag to determine if this AWT is in the process of closing or entering PIP. This is needed
    261      * to help AWT know that the app is in the process of closing but hasn't yet started closing on
    262      * the WM side.
    263      */
    264     private boolean mWillCloseOrEnterPip;
    265 
    266     AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction,
    267             DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen,
    268             boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint,
    269             int configChanges, boolean launchTaskBehind, boolean alwaysFocusable,
    270             AppWindowContainerController controller) {
    271         this(service, token, voiceInteraction, dc, fullscreen);
    272         setController(controller);
    273         mInputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
    274         mShowForAllUsers = showForAllUsers;
    275         mTargetSdk = targetSdk;
    276         mOrientation = orientation;
    277         layoutConfigChanges = (configChanges & (CONFIG_SCREEN_SIZE | CONFIG_ORIENTATION)) != 0;
    278         mLaunchTaskBehind = launchTaskBehind;
    279         mAlwaysFocusable = alwaysFocusable;
    280         mRotationAnimationHint = rotationAnimationHint;
    281 
    282         // Application tokens start out hidden.
    283         setHidden(true);
    284         hiddenRequested = true;
    285     }
    286 
    287     AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction,
    288             DisplayContent dc, boolean fillsParent) {
    289         super(service, token != null ? token.asBinder() : null, TYPE_APPLICATION, true, dc,
    290                 false /* ownerCanManageAppTokens */);
    291         appToken = token;
    292         mVoiceInteraction = voiceInteraction;
    293         mFillsParent = fillsParent;
    294         mInputApplicationHandle = new InputApplicationHandle(this);
    295     }
    296 
    297     void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) {
    298         firstWindowDrawn = true;
    299 
    300         // We now have a good window to show, remove dead placeholders
    301         removeDeadWindows();
    302 
    303         if (startingWindow != null) {
    304             if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Slog.v(TAG, "Finish starting "
    305                     + win.mToken + ": first real window is shown, no animation");
    306             // If this initial window is animating, stop it -- we will do an animation to reveal
    307             // it from behind the starting window, so there is no need for it to also be doing its
    308             // own stuff.
    309             win.cancelAnimation();
    310             if (getController() != null) {
    311                 getController().removeStartingWindow();
    312             }
    313         }
    314         updateReportedVisibilityLocked();
    315     }
    316 
    317     void updateReportedVisibilityLocked() {
    318         if (appToken == null) {
    319             return;
    320         }
    321 
    322         if (DEBUG_VISIBILITY) Slog.v(TAG, "Update reported visibility: " + this);
    323         final int count = mChildren.size();
    324 
    325         mReportedVisibilityResults.reset();
    326 
    327         for (int i = 0; i < count; i++) {
    328             final WindowState win = mChildren.get(i);
    329             win.updateReportedVisibility(mReportedVisibilityResults);
    330         }
    331 
    332         int numInteresting = mReportedVisibilityResults.numInteresting;
    333         int numVisible = mReportedVisibilityResults.numVisible;
    334         int numDrawn = mReportedVisibilityResults.numDrawn;
    335         boolean nowGone = mReportedVisibilityResults.nowGone;
    336 
    337         boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting;
    338         boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting && !isHidden();
    339         if (!nowGone) {
    340             // If the app is not yet gone, then it can only become visible/drawn.
    341             if (!nowDrawn) {
    342                 nowDrawn = reportedDrawn;
    343             }
    344             if (!nowVisible) {
    345                 nowVisible = reportedVisible;
    346             }
    347         }
    348         if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting="
    349                 + numInteresting + " visible=" + numVisible);
    350         final AppWindowContainerController controller = getController();
    351         if (nowDrawn != reportedDrawn) {
    352             if (nowDrawn) {
    353                 if (controller != null) {
    354                     controller.reportWindowsDrawn();
    355                 }
    356             }
    357             reportedDrawn = nowDrawn;
    358         }
    359         if (nowVisible != reportedVisible) {
    360             if (DEBUG_VISIBILITY) Slog.v(TAG,
    361                     "Visibility changed in " + this + ": vis=" + nowVisible);
    362             reportedVisible = nowVisible;
    363             if (controller != null) {
    364                 if (nowVisible) {
    365                     controller.reportWindowsVisible();
    366                 } else {
    367                     controller.reportWindowsGone();
    368                 }
    369             }
    370         }
    371     }
    372 
    373     boolean isClientHidden() {
    374         return mClientHidden;
    375     }
    376 
    377     void setClientHidden(boolean hideClient) {
    378         if (mClientHidden == hideClient || (hideClient && mDeferHidingClient)) {
    379             return;
    380         }
    381         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "setClientHidden: " + this
    382                 + " clientHidden=" + hideClient + " Callers=" + Debug.getCallers(5));
    383         mClientHidden = hideClient;
    384         sendAppVisibilityToClients();
    385     }
    386 
    387     boolean setVisibility(WindowManager.LayoutParams lp,
    388             boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction) {
    389 
    390         boolean delayed = false;
    391         inPendingTransaction = false;
    392         // Reset the state of mHiddenSetFromTransferredStartingWindow since visibility is actually
    393         // been set by the app now.
    394         mHiddenSetFromTransferredStartingWindow = false;
    395 
    396         // Allow for state changes and animation to be applied if:
    397         // * token is transitioning visibility state
    398         // * or the token was marked as hidden and is exiting before we had a chance to play the
    399         // transition animation
    400         // * or this is an opening app and windows are being replaced.
    401         boolean visibilityChanged = false;
    402         if (isHidden() == visible || (isHidden() && mIsExiting) || (visible && waitingForReplacement())) {
    403             final AccessibilityController accessibilityController = mService.mAccessibilityController;
    404             boolean changed = false;
    405             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
    406                     "Changing app " + this + " hidden=" + isHidden() + " performLayout=" + performLayout);
    407 
    408             boolean runningAppAnimation = false;
    409 
    410             if (transit != WindowManager.TRANSIT_UNSET) {
    411                 if (applyAnimationLocked(lp, transit, visible, isVoiceInteraction)) {
    412                     delayed = runningAppAnimation = true;
    413                 }
    414                 final WindowState window = findMainWindow();
    415                 //TODO (multidisplay): Magnification is supported only for the default display.
    416                 if (window != null && accessibilityController != null
    417                         && getDisplayContent().getDisplayId() == DEFAULT_DISPLAY) {
    418                     accessibilityController.onAppWindowTransitionLocked(window, transit);
    419                 }
    420                 changed = true;
    421             }
    422 
    423             final int windowsCount = mChildren.size();
    424             for (int i = 0; i < windowsCount; i++) {
    425                 final WindowState win = mChildren.get(i);
    426                 changed |= win.onAppVisibilityChanged(visible, runningAppAnimation);
    427             }
    428 
    429             setHidden(!visible);
    430             hiddenRequested = !visible;
    431             visibilityChanged = true;
    432             if (!visible) {
    433                 stopFreezingScreen(true, true);
    434             } else {
    435                 // If we are being set visible, and the starting window is not yet displayed,
    436                 // then make sure it doesn't get displayed.
    437                 if (startingWindow != null && !startingWindow.isDrawnLw()) {
    438                     startingWindow.mPolicyVisibility = false;
    439                     startingWindow.mPolicyVisibilityAfterAnim = false;
    440                 }
    441 
    442                 // We are becoming visible, so better freeze the screen with the windows that are
    443                 // getting visible so we also wait for them.
    444                 forAllWindows(mService::makeWindowFreezingScreenIfNeededLocked, true);
    445             }
    446 
    447             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "setVisibility: " + this
    448                     + ": hidden=" + isHidden() + " hiddenRequested=" + hiddenRequested);
    449 
    450             if (changed) {
    451                 mService.mInputMonitor.setUpdateInputWindowsNeededLw();
    452                 if (performLayout) {
    453                     mService.updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
    454                             false /*updateInputWindows*/);
    455                     mService.mWindowPlacerLocked.performSurfacePlacement();
    456                 }
    457                 mService.mInputMonitor.updateInputWindowsLw(false /*force*/);
    458             }
    459         }
    460 
    461         if (isReallyAnimating()) {
    462             delayed = true;
    463         } else {
    464 
    465             // We aren't animating anything, but exiting windows rely on the animation finished
    466             // callback being called in case the AppWindowToken was pretending to be animating,
    467             // which we might have done because we were in closing/opening apps list.
    468             onAnimationFinished();
    469         }
    470 
    471         for (int i = mChildren.size() - 1; i >= 0 && !delayed; i--) {
    472             if ((mChildren.get(i)).isSelfOrChildAnimating()) {
    473                 delayed = true;
    474             }
    475         }
    476 
    477         if (visibilityChanged) {
    478             if (visible && !delayed) {
    479                 // The token was made immediately visible, there will be no entrance animation.
    480                 // We need to inform the client the enter animation was finished.
    481                 mEnteringAnimation = true;
    482                 mService.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(token);
    483             }
    484 
    485             // If we're becoming visible, immediately change client visibility as well although it
    486             // usually gets changed in AppWindowContainerController.setVisibility already. However,
    487             // there seem to be some edge cases where we change our visibility but client visibility
    488             // never gets updated.
    489             // If we're becoming invisible, update the client visibility if we are not running an
    490             // animation. Otherwise, we'll update client visibility in onAnimationFinished.
    491             if (visible || !isReallyAnimating()) {
    492                 setClientHidden(!visible);
    493             }
    494 
    495             if (!mService.mClosingApps.contains(this) && !mService.mOpeningApps.contains(this)) {
    496                 // The token is not closing nor opening, so even if there is an animation set, that
    497                 // doesn't mean that it goes through the normal app transition cycle so we have
    498                 // to inform the docked controller about visibility change.
    499                 // TODO(multi-display): notify docked divider on all displays where visibility was
    500                 // affected.
    501                 mService.getDefaultDisplayContentLocked().getDockedDividerController()
    502                         .notifyAppVisibilityChanged();
    503 
    504                 // Take the screenshot before possibly hiding the WSA, otherwise the screenshot
    505                 // will not be taken.
    506                 mService.mTaskSnapshotController.notifyAppVisibilityChanged(this, visible);
    507             }
    508 
    509             // If we are hidden but there is no delay needed we immediately
    510             // apply the Surface transaction so that the ActivityManager
    511             // can have some guarantee on the Surface state following
    512             // setting the visibility. This captures cases like dismissing
    513             // the docked or pinned stack where there is no app transition.
    514             //
    515             // In the case of a "Null" animation, there will be
    516             // no animation but there will still be a transition set.
    517             // We still need to delay hiding the surface such that it
    518             // can be synchronized with showing the next surface in the transition.
    519             if (isHidden() && !delayed && !mService.mAppTransition.isTransitionSet()) {
    520                 SurfaceControl.openTransaction();
    521                 for (int i = mChildren.size() - 1; i >= 0; i--) {
    522                     mChildren.get(i).mWinAnimator.hide("immediately hidden");
    523                 }
    524                 SurfaceControl.closeTransaction();
    525             }
    526         }
    527 
    528         return delayed;
    529     }
    530 
    531     /**
    532      * @return The to top most child window for which {@link LayoutParams#isFullscreen()} returns
    533      *         true.
    534      */
    535     WindowState getTopFullscreenWindow() {
    536         for (int i = mChildren.size() - 1; i >= 0; i--) {
    537             final WindowState win = mChildren.get(i);
    538             if (win != null && win.mAttrs.isFullscreen()) {
    539                 return win;
    540             }
    541         }
    542         return null;
    543     }
    544 
    545     WindowState findMainWindow() {
    546         return findMainWindow(true);
    547     }
    548 
    549     /**
    550      * Finds the main window that either has type base application or application starting if
    551      * requested.
    552      *
    553      * @param includeStartingApp Allow to search application-starting windows to also be returned.
    554      * @return The main window of type base application or application starting if requested.
    555      */
    556     WindowState findMainWindow(boolean includeStartingApp) {
    557         WindowState candidate = null;
    558         for (int j = mChildren.size() - 1; j >= 0; --j) {
    559             final WindowState win = mChildren.get(j);
    560             final int type = win.mAttrs.type;
    561             // No need to loop through child window as base application and starting types can't be
    562             // child windows.
    563             if (type == TYPE_BASE_APPLICATION
    564                     || (includeStartingApp && type == TYPE_APPLICATION_STARTING)) {
    565                 // In cases where there are multiple windows, we prefer the non-exiting window. This
    566                 // happens for example when replacing windows during an activity relaunch. When
    567                 // constructing the animation, we want the new window, not the exiting one.
    568                 if (win.mAnimatingExit) {
    569                     candidate = win;
    570                 } else {
    571                     return win;
    572                 }
    573             }
    574         }
    575         return candidate;
    576     }
    577 
    578     boolean windowsAreFocusable() {
    579         return getWindowConfiguration().canReceiveKeys() || mAlwaysFocusable;
    580     }
    581 
    582     AppWindowContainerController getController() {
    583         final WindowContainerController controller = super.getController();
    584         return controller != null ? (AppWindowContainerController) controller : null;
    585     }
    586 
    587     @Override
    588     boolean isVisible() {
    589         // If the app token isn't hidden then it is considered visible and there is no need to check
    590         // its children windows to see if they are visible.
    591         return !isHidden();
    592     }
    593 
    594     @Override
    595     void removeImmediately() {
    596         onRemovedFromDisplay();
    597         super.removeImmediately();
    598     }
    599 
    600     @Override
    601     void removeIfPossible() {
    602         mIsExiting = false;
    603         removeAllWindowsIfPossible();
    604         removeImmediately();
    605     }
    606 
    607     @Override
    608     boolean checkCompleteDeferredRemoval() {
    609         if (mIsExiting) {
    610             removeIfPossible();
    611         }
    612         return super.checkCompleteDeferredRemoval();
    613     }
    614 
    615     void onRemovedFromDisplay() {
    616         if (mRemovingFromDisplay) {
    617             return;
    618         }
    619         mRemovingFromDisplay = true;
    620 
    621         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app token: " + this);
    622 
    623         boolean delayed = setVisibility(null, false, TRANSIT_UNSET, true, mVoiceInteraction);
    624 
    625         mService.mOpeningApps.remove(this);
    626         mService.mUnknownAppVisibilityController.appRemovedOrHidden(this);
    627         mService.mTaskSnapshotController.onAppRemoved(this);
    628         waitingToShow = false;
    629         if (mService.mClosingApps.contains(this)) {
    630             delayed = true;
    631         } else if (mService.mAppTransition.isTransitionSet()) {
    632             mService.mClosingApps.add(this);
    633             delayed = true;
    634         }
    635 
    636         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app " + this + " delayed=" + delayed
    637                 + " animation=" + getAnimation() + " animating=" + isSelfAnimating());
    638 
    639         if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM, "removeAppToken: "
    640                 + this + " delayed=" + delayed + " Callers=" + Debug.getCallers(4));
    641 
    642         if (startingData != null && getController() != null) {
    643             getController().removeStartingWindow();
    644         }
    645 
    646         // If this window was animating, then we need to ensure that the app transition notifies
    647         // that animations have completed in WMS.handleAnimatingStoppedAndTransitionLocked(), so
    648         // add to that list now
    649         if (isSelfAnimating()) {
    650             mService.mNoAnimationNotifyOnTransitionFinished.add(token);
    651         }
    652 
    653         final TaskStack stack = getStack();
    654         if (delayed && !isEmpty()) {
    655             // set the token aside because it has an active animation to be finished
    656             if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM,
    657                     "removeAppToken make exiting: " + this);
    658             if (stack != null) {
    659                 stack.mExitingAppTokens.add(this);
    660             }
    661             mIsExiting = true;
    662         } else {
    663             // Make sure there is no animation running on this token, so any windows associated
    664             // with it will be removed as soon as their animations are complete
    665             cancelAnimation();
    666             if (stack != null) {
    667                 stack.mExitingAppTokens.remove(this);
    668             }
    669             removeIfPossible();
    670         }
    671 
    672         removed = true;
    673         stopFreezingScreen(true, true);
    674 
    675         if (mService.mFocusedApp == this) {
    676             if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Removing focused app token:" + this);
    677             mService.mFocusedApp = null;
    678             mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
    679             mService.mInputMonitor.setFocusedAppLw(null);
    680         }
    681 
    682         if (!delayed) {
    683             updateReportedVisibilityLocked();
    684         }
    685 
    686         mRemovingFromDisplay = false;
    687     }
    688 
    689     void clearAnimatingFlags() {
    690         boolean wallpaperMightChange = false;
    691         for (int i = mChildren.size() - 1; i >= 0; i--) {
    692             final WindowState win = mChildren.get(i);
    693             wallpaperMightChange |= win.clearAnimatingFlags();
    694         }
    695         if (wallpaperMightChange) {
    696             requestUpdateWallpaperIfNeeded();
    697         }
    698     }
    699 
    700     void destroySurfaces() {
    701         destroySurfaces(false /*cleanupOnResume*/);
    702     }
    703 
    704     /**
    705      * Destroy surfaces which have been marked as eligible by the animator, taking care to ensure
    706      * the client has finished with them.
    707      *
    708      * @param cleanupOnResume whether this is done when app is resumed without fully stopped. If
    709      * set to true, destroy only surfaces of removed windows, and clear relevant flags of the
    710      * others so that they are ready to be reused. If set to false (common case), destroy all
    711      * surfaces that's eligible, if the app is already stopped.
    712      */
    713     private void destroySurfaces(boolean cleanupOnResume) {
    714         boolean destroyedSomething = false;
    715 
    716         // Copying to a different list as multiple children can be removed.
    717         final ArrayList<WindowState> children = new ArrayList<>(mChildren);
    718         for (int i = children.size() - 1; i >= 0; i--) {
    719             final WindowState win = children.get(i);
    720             destroyedSomething |= win.destroySurface(cleanupOnResume, mAppStopped);
    721         }
    722         if (destroyedSomething) {
    723             final DisplayContent dc = getDisplayContent();
    724             dc.assignWindowLayers(true /*setLayoutNeeded*/);
    725             updateLetterboxSurface(null);
    726         }
    727     }
    728 
    729     /**
    730      * Notify that the app is now resumed, and it was not stopped before, perform a clean
    731      * up of the surfaces
    732      */
    733     void notifyAppResumed(boolean wasStopped) {
    734         if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppResumed: wasStopped=" + wasStopped
    735                 + " " + this);
    736         mAppStopped = false;
    737         // Allow the window to turn the screen on once the app is resumed again.
    738         setCanTurnScreenOn(true);
    739         if (!wasStopped) {
    740             destroySurfaces(true /*cleanupOnResume*/);
    741         }
    742     }
    743 
    744     /**
    745      * Notify that the app has stopped, and it is okay to destroy any surfaces which were
    746      * keeping alive in case they were still being used.
    747      */
    748     void notifyAppStopped() {
    749         if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppStopped: " + this);
    750         mAppStopped = true;
    751         destroySurfaces();
    752         // Remove any starting window that was added for this app if they are still around.
    753         if (getController() != null) {
    754             getController().removeStartingWindow();
    755         }
    756     }
    757 
    758     void clearAllDrawn() {
    759         allDrawn = false;
    760         deferClearAllDrawn = false;
    761     }
    762 
    763     Task getTask() {
    764         return (Task) getParent();
    765     }
    766 
    767     TaskStack getStack() {
    768         final Task task = getTask();
    769         if (task != null) {
    770             return task.mStack;
    771         } else {
    772             return null;
    773         }
    774     }
    775 
    776     @Override
    777     void onParentSet() {
    778         super.onParentSet();
    779 
    780         final Task task = getTask();
    781 
    782         // When the associated task is {@code null}, the {@link AppWindowToken} can no longer
    783         // access visual elements like the {@link DisplayContent}. We must remove any associations
    784         // such as animations.
    785         if (!mReparenting) {
    786             if (task == null) {
    787                 // It is possible we have been marked as a closing app earlier. We must remove ourselves
    788                 // from this list so we do not participate in any future animations.
    789                 mService.mClosingApps.remove(this);
    790             } else if (mLastParent != null && mLastParent.mStack != null) {
    791                 task.mStack.mExitingAppTokens.remove(this);
    792             }
    793         }
    794         final TaskStack stack = getStack();
    795 
    796         // If we reparent, make sure to remove ourselves from the old animation registry.
    797         if (mAnimatingAppWindowTokenRegistry != null) {
    798             mAnimatingAppWindowTokenRegistry.notifyFinished(this);
    799         }
    800         mAnimatingAppWindowTokenRegistry = stack != null
    801                 ? stack.getAnimatingAppWindowTokenRegistry()
    802                 : null;
    803 
    804         mLastParent = task;
    805     }
    806 
    807     void postWindowRemoveStartingWindowCleanup(WindowState win) {
    808         // TODO: Something smells about the code below...Is there a better way?
    809         if (startingWindow == win) {
    810             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Notify removed startingWindow " + win);
    811             if (getController() != null) {
    812                 getController().removeStartingWindow();
    813             }
    814         } else if (mChildren.size() == 0) {
    815             // If this is the last window and we had requested a starting transition window,
    816             // well there is no point now.
    817             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Nulling last startingData");
    818             startingData = null;
    819             if (mHiddenSetFromTransferredStartingWindow) {
    820                 // We set the hidden state to false for the token from a transferred starting window.
    821                 // We now reset it back to true since the starting window was the last window in the
    822                 // token.
    823                 setHidden(true);
    824             }
    825         } else if (mChildren.size() == 1 && startingSurface != null && !isRelaunching()) {
    826             // If this is the last window except for a starting transition window,
    827             // we need to get rid of the starting transition.
    828             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Last window, removing starting window "
    829                     + win);
    830             if (getController() != null) {
    831                 getController().removeStartingWindow();
    832             }
    833         }
    834     }
    835 
    836     void removeDeadWindows() {
    837         for (int winNdx = mChildren.size() - 1; winNdx >= 0; --winNdx) {
    838             WindowState win = mChildren.get(winNdx);
    839             if (win.mAppDied) {
    840                 if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.w(TAG,
    841                         "removeDeadWindows: " + win);
    842                 // Set mDestroying, we don't want any animation or delayed removal here.
    843                 win.mDestroying = true;
    844                 // Also removes child windows.
    845                 win.removeIfPossible();
    846             }
    847         }
    848     }
    849 
    850     boolean hasWindowsAlive() {
    851         for (int i = mChildren.size() - 1; i >= 0; i--) {
    852             // No need to loop through child windows as the answer should be the same as that of the
    853             // parent window.
    854             if (!(mChildren.get(i)).mAppDied) {
    855                 return true;
    856             }
    857         }
    858         return false;
    859     }
    860 
    861     void setWillReplaceWindows(boolean animate) {
    862         if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM,
    863                 "Marking app token " + this + " with replacing windows.");
    864 
    865         for (int i = mChildren.size() - 1; i >= 0; i--) {
    866             final WindowState w = mChildren.get(i);
    867             w.setWillReplaceWindow(animate);
    868         }
    869     }
    870 
    871     void setWillReplaceChildWindows() {
    872         if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + this
    873                 + " with replacing child windows.");
    874         for (int i = mChildren.size() - 1; i >= 0; i--) {
    875             final WindowState w = mChildren.get(i);
    876             w.setWillReplaceChildWindows();
    877         }
    878     }
    879 
    880     void clearWillReplaceWindows() {
    881         if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM,
    882                 "Resetting app token " + this + " of replacing window marks.");
    883 
    884         for (int i = mChildren.size() - 1; i >= 0; i--) {
    885             final WindowState w = mChildren.get(i);
    886             w.clearWillReplaceWindow();
    887         }
    888     }
    889 
    890     void requestUpdateWallpaperIfNeeded() {
    891         for (int i = mChildren.size() - 1; i >= 0; i--) {
    892             final WindowState w = mChildren.get(i);
    893             w.requestUpdateWallpaperIfNeeded();
    894         }
    895     }
    896 
    897     boolean isRelaunching() {
    898         return mPendingRelaunchCount > 0;
    899     }
    900 
    901     boolean shouldFreezeBounds() {
    902         final Task task = getTask();
    903 
    904         // For freeform windows, we can't freeze the bounds at the moment because this would make
    905         // the resizing unresponsive.
    906         if (task == null || task.inFreeformWindowingMode()) {
    907             return false;
    908         }
    909 
    910         // We freeze the bounds while drag resizing to deal with the time between
    911         // the divider/drag handle being released, and the handling it's new
    912         // configuration. If we are relaunched outside of the drag resizing state,
    913         // we need to be careful not to do this.
    914         return getTask().isDragResizing();
    915     }
    916 
    917     void startRelaunching() {
    918         if (shouldFreezeBounds()) {
    919             freezeBounds();
    920         }
    921 
    922         // In the process of tearing down before relaunching, the app will
    923         // try and clean up it's child surfaces. We need to prevent this from
    924         // happening, so we sever the children, transfering their ownership
    925         // from the client it-self to the parent surface (owned by us).
    926         detachChildren();
    927 
    928         mPendingRelaunchCount++;
    929     }
    930 
    931     void detachChildren() {
    932         SurfaceControl.openTransaction();
    933         for (int i = mChildren.size() - 1; i >= 0; i--) {
    934             final WindowState w = mChildren.get(i);
    935             w.mWinAnimator.detachChildren();
    936         }
    937         SurfaceControl.closeTransaction();
    938     }
    939 
    940     void finishRelaunching() {
    941         unfreezeBounds();
    942 
    943         if (mPendingRelaunchCount > 0) {
    944             mPendingRelaunchCount--;
    945         } else {
    946             // Update keyguard flags upon finishing relaunch.
    947             checkKeyguardFlagsChanged();
    948         }
    949     }
    950 
    951     void clearRelaunching() {
    952         if (mPendingRelaunchCount == 0) {
    953             return;
    954         }
    955         unfreezeBounds();
    956         mPendingRelaunchCount = 0;
    957     }
    958 
    959     /**
    960      * Returns true if the new child window we are adding to this token is considered greater than
    961      * the existing child window in this token in terms of z-order.
    962      */
    963     @Override
    964     protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow,
    965             WindowState existingWindow) {
    966         final int type1 = newWindow.mAttrs.type;
    967         final int type2 = existingWindow.mAttrs.type;
    968 
    969         // Base application windows should be z-ordered BELOW all other windows in the app token.
    970         if (type1 == TYPE_BASE_APPLICATION && type2 != TYPE_BASE_APPLICATION) {
    971             return false;
    972         } else if (type1 != TYPE_BASE_APPLICATION && type2 == TYPE_BASE_APPLICATION) {
    973             return true;
    974         }
    975 
    976         // Starting windows should be z-ordered ABOVE all other windows in the app token.
    977         if (type1 == TYPE_APPLICATION_STARTING && type2 != TYPE_APPLICATION_STARTING) {
    978             return true;
    979         } else if (type1 != TYPE_APPLICATION_STARTING && type2 == TYPE_APPLICATION_STARTING) {
    980             return false;
    981         }
    982 
    983         // Otherwise the new window is greater than the existing window.
    984         return true;
    985     }
    986 
    987     @Override
    988     void addWindow(WindowState w) {
    989         super.addWindow(w);
    990 
    991         boolean gotReplacementWindow = false;
    992         for (int i = mChildren.size() - 1; i >= 0; i--) {
    993             final WindowState candidate = mChildren.get(i);
    994             gotReplacementWindow |= candidate.setReplacementWindowIfNeeded(w);
    995         }
    996 
    997         // if we got a replacement window, reset the timeout to give drawing more time
    998         if (gotReplacementWindow) {
    999             mService.scheduleWindowReplacementTimeouts(this);
   1000         }
   1001         checkKeyguardFlagsChanged();
   1002     }
   1003 
   1004     @Override
   1005     void removeChild(WindowState child) {
   1006         super.removeChild(child);
   1007         checkKeyguardFlagsChanged();
   1008         updateLetterboxSurface(child);
   1009     }
   1010 
   1011     private boolean waitingForReplacement() {
   1012         for (int i = mChildren.size() - 1; i >= 0; i--) {
   1013             final WindowState candidate = mChildren.get(i);
   1014             if (candidate.waitingForReplacement()) {
   1015                 return true;
   1016             }
   1017         }
   1018         return false;
   1019     }
   1020 
   1021     void onWindowReplacementTimeout() {
   1022         for (int i = mChildren.size() - 1; i >= 0; --i) {
   1023             (mChildren.get(i)).onWindowReplacementTimeout();
   1024         }
   1025     }
   1026 
   1027     void reparent(Task task, int position) {
   1028         final Task currentTask = getTask();
   1029         if (task == currentTask) {
   1030             throw new IllegalArgumentException(
   1031                     "window token=" + this + " already child of task=" + currentTask);
   1032         }
   1033 
   1034         if (currentTask.mStack != task.mStack) {
   1035             throw new IllegalArgumentException(
   1036                     "window token=" + this + " current task=" + currentTask
   1037                         + " belongs to a different stack than " + task);
   1038         }
   1039 
   1040         if (DEBUG_ADD_REMOVE) Slog.i(TAG, "reParentWindowToken: removing window token=" + this
   1041                 + " from task=" + currentTask);
   1042         final DisplayContent prevDisplayContent = getDisplayContent();
   1043 
   1044         mReparenting = true;
   1045 
   1046         getParent().removeChild(this);
   1047         task.addChild(this, position);
   1048 
   1049         mReparenting = false;
   1050 
   1051         // Relayout display(s).
   1052         final DisplayContent displayContent = task.getDisplayContent();
   1053         displayContent.setLayoutNeeded();
   1054         if (prevDisplayContent != displayContent) {
   1055             onDisplayChanged(displayContent);
   1056             prevDisplayContent.setLayoutNeeded();
   1057         }
   1058     }
   1059 
   1060     /**
   1061      * Freezes the task bounds. The size of this task reported the app will be fixed to the bounds
   1062      * freezed by {@link Task#prepareFreezingBounds} until {@link #unfreezeBounds} gets called, even
   1063      * if they change in the meantime. If the bounds are already frozen, the bounds will be frozen
   1064      * with a queue.
   1065      */
   1066     private void freezeBounds() {
   1067         final Task task = getTask();
   1068         mFrozenBounds.offer(new Rect(task.mPreparedFrozenBounds));
   1069 
   1070         if (task.mPreparedFrozenMergedConfig.equals(Configuration.EMPTY)) {
   1071             // We didn't call prepareFreezingBounds on the task, so use the current value.
   1072             mFrozenMergedConfig.offer(new Configuration(task.getConfiguration()));
   1073         } else {
   1074             mFrozenMergedConfig.offer(new Configuration(task.mPreparedFrozenMergedConfig));
   1075         }
   1076         // Calling unset() to make it equal to Configuration.EMPTY.
   1077         task.mPreparedFrozenMergedConfig.unset();
   1078     }
   1079 
   1080     /**
   1081      * Unfreezes the previously frozen bounds. See {@link #freezeBounds}.
   1082      */
   1083     private void unfreezeBounds() {
   1084         if (mFrozenBounds.isEmpty()) {
   1085             return;
   1086         }
   1087         mFrozenBounds.remove();
   1088         if (!mFrozenMergedConfig.isEmpty()) {
   1089             mFrozenMergedConfig.remove();
   1090         }
   1091         for (int i = mChildren.size() - 1; i >= 0; i--) {
   1092             final WindowState win = mChildren.get(i);
   1093             win.onUnfreezeBounds();
   1094         }
   1095         mService.mWindowPlacerLocked.performSurfacePlacement();
   1096     }
   1097 
   1098     void setAppLayoutChanges(int changes, String reason) {
   1099         if (!mChildren.isEmpty()) {
   1100             final DisplayContent dc = getDisplayContent();
   1101             dc.pendingLayoutChanges |= changes;
   1102             if (DEBUG_LAYOUT_REPEATS) {
   1103                 mService.mWindowPlacerLocked.debugLayoutRepeats(reason, dc.pendingLayoutChanges);
   1104             }
   1105         }
   1106     }
   1107 
   1108     void removeReplacedWindowIfNeeded(WindowState replacement) {
   1109         for (int i = mChildren.size() - 1; i >= 0; i--) {
   1110             final WindowState win = mChildren.get(i);
   1111             if (win.removeReplacedWindowIfNeeded(replacement)) {
   1112                 return;
   1113             }
   1114         }
   1115     }
   1116 
   1117     void startFreezingScreen() {
   1118         if (DEBUG_ORIENTATION) logWithStack(TAG, "Set freezing of " + appToken + ": hidden="
   1119                 + isHidden() + " freezing=" + mFreezingScreen + " hiddenRequested="
   1120                 + hiddenRequested);
   1121         if (!hiddenRequested) {
   1122             if (!mFreezingScreen) {
   1123                 mFreezingScreen = true;
   1124                 mService.registerAppFreezeListener(this);
   1125                 mService.mAppsFreezingScreen++;
   1126                 if (mService.mAppsFreezingScreen == 1) {
   1127                     mService.startFreezingDisplayLocked(0, 0, getDisplayContent());
   1128                     mService.mH.removeMessages(H.APP_FREEZE_TIMEOUT);
   1129                     mService.mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000);
   1130                 }
   1131             }
   1132             final int count = mChildren.size();
   1133             for (int i = 0; i < count; i++) {
   1134                 final WindowState w = mChildren.get(i);
   1135                 w.onStartFreezingScreen();
   1136             }
   1137         }
   1138     }
   1139 
   1140     void stopFreezingScreen(boolean unfreezeSurfaceNow, boolean force) {
   1141         if (!mFreezingScreen) {
   1142             return;
   1143         }
   1144         if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + this + " force=" + force);
   1145         final int count = mChildren.size();
   1146         boolean unfrozeWindows = false;
   1147         for (int i = 0; i < count; i++) {
   1148             final WindowState w = mChildren.get(i);
   1149             unfrozeWindows |= w.onStopFreezingScreen();
   1150         }
   1151         if (force || unfrozeWindows) {
   1152             if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "No longer freezing: " + this);
   1153             mFreezingScreen = false;
   1154             mService.unregisterAppFreezeListener(this);
   1155             mService.mAppsFreezingScreen--;
   1156             mService.mLastFinishedFreezeSource = this;
   1157         }
   1158         if (unfreezeSurfaceNow) {
   1159             if (unfrozeWindows) {
   1160                 mService.mWindowPlacerLocked.performSurfacePlacement();
   1161             }
   1162             mService.stopFreezingDisplayLocked();
   1163         }
   1164     }
   1165 
   1166     @Override
   1167     public void onAppFreezeTimeout() {
   1168         Slog.w(TAG_WM, "Force clearing freeze: " + this);
   1169         stopFreezingScreen(true, true);
   1170     }
   1171 
   1172     /**
   1173      * Tries to transfer the starting window from a token that's above ourselves in the task but
   1174      * not visible anymore. This is a common scenario apps use: Trampoline activity T start main
   1175      * activity M in the same task. Now, when reopening the task, T starts on top of M but then
   1176      * immediately finishes after, so we have to transfer T to M.
   1177      */
   1178     void transferStartingWindowFromHiddenAboveTokenIfNeeded() {
   1179         final Task task = getTask();
   1180         for (int i = task.mChildren.size() - 1; i >= 0; i--) {
   1181             final AppWindowToken fromToken = task.mChildren.get(i);
   1182             if (fromToken == this) {
   1183                 return;
   1184             }
   1185             if (fromToken.hiddenRequested && transferStartingWindow(fromToken.token)) {
   1186                 return;
   1187             }
   1188         }
   1189     }
   1190 
   1191     boolean transferStartingWindow(IBinder transferFrom) {
   1192         final AppWindowToken fromToken = getDisplayContent().getAppWindowToken(transferFrom);
   1193         if (fromToken == null) {
   1194             return false;
   1195         }
   1196 
   1197         final WindowState tStartingWindow = fromToken.startingWindow;
   1198         if (tStartingWindow != null && fromToken.startingSurface != null) {
   1199             // In this case, the starting icon has already been displayed, so start
   1200             // letting windows get shown immediately without any more transitions.
   1201             mService.mSkipAppTransitionAnimation = true;
   1202 
   1203             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Moving existing starting " + tStartingWindow
   1204                     + " from " + fromToken + " to " + this);
   1205 
   1206             final long origId = Binder.clearCallingIdentity();
   1207             try {
   1208                 // Transfer the starting window over to the new token.
   1209                 startingData = fromToken.startingData;
   1210                 startingSurface = fromToken.startingSurface;
   1211                 startingDisplayed = fromToken.startingDisplayed;
   1212                 fromToken.startingDisplayed = false;
   1213                 startingWindow = tStartingWindow;
   1214                 reportedVisible = fromToken.reportedVisible;
   1215                 fromToken.startingData = null;
   1216                 fromToken.startingSurface = null;
   1217                 fromToken.startingWindow = null;
   1218                 fromToken.startingMoved = true;
   1219                 tStartingWindow.mToken = this;
   1220                 tStartingWindow.mAppToken = this;
   1221 
   1222                 if (DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
   1223                         "Removing starting " + tStartingWindow + " from " + fromToken);
   1224                 fromToken.removeChild(tStartingWindow);
   1225                 fromToken.postWindowRemoveStartingWindowCleanup(tStartingWindow);
   1226                 fromToken.mHiddenSetFromTransferredStartingWindow = false;
   1227                 addWindow(tStartingWindow);
   1228 
   1229                 // Propagate other interesting state between the tokens. If the old token is displayed,
   1230                 // we should immediately force the new one to be displayed. If it is animating, we need
   1231                 // to move that animation to the new one.
   1232                 if (fromToken.allDrawn) {
   1233                     allDrawn = true;
   1234                     deferClearAllDrawn = fromToken.deferClearAllDrawn;
   1235                 }
   1236                 if (fromToken.firstWindowDrawn) {
   1237                     firstWindowDrawn = true;
   1238                 }
   1239                 if (!fromToken.isHidden()) {
   1240                     setHidden(false);
   1241                     hiddenRequested = false;
   1242                     mHiddenSetFromTransferredStartingWindow = true;
   1243                 }
   1244                 setClientHidden(fromToken.mClientHidden);
   1245 
   1246                 transferAnimation(fromToken);
   1247 
   1248                 // When transferring an animation, we no longer need to apply an animation to the
   1249                 // the token we transfer the animation over. Thus, remove the animation from
   1250                 // pending opening apps.
   1251                 mService.mOpeningApps.remove(this);
   1252 
   1253                 mService.updateFocusedWindowLocked(
   1254                         UPDATE_FOCUS_WILL_PLACE_SURFACES, true /*updateInputWindows*/);
   1255                 getDisplayContent().setLayoutNeeded();
   1256                 mService.mWindowPlacerLocked.performSurfacePlacement();
   1257             } finally {
   1258                 Binder.restoreCallingIdentity(origId);
   1259             }
   1260             return true;
   1261         } else if (fromToken.startingData != null) {
   1262             // The previous app was getting ready to show a
   1263             // starting window, but hasn't yet done so.  Steal it!
   1264             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
   1265                     "Moving pending starting from " + fromToken + " to " + this);
   1266             startingData = fromToken.startingData;
   1267             fromToken.startingData = null;
   1268             fromToken.startingMoved = true;
   1269             if (getController() != null) {
   1270                 getController().scheduleAddStartingWindow();
   1271             }
   1272             return true;
   1273         }
   1274 
   1275         // TODO: Transfer thumbnail
   1276 
   1277         return false;
   1278     }
   1279 
   1280     boolean isLastWindow(WindowState win) {
   1281         return mChildren.size() == 1 && mChildren.get(0) == win;
   1282     }
   1283 
   1284     @Override
   1285     void onAppTransitionDone() {
   1286         sendingToBottom = false;
   1287     }
   1288 
   1289     /**
   1290      * We override because this class doesn't want its children affecting its reported orientation
   1291      * in anyway.
   1292      */
   1293     @Override
   1294     int getOrientation(int candidate) {
   1295         if (candidate == SCREEN_ORIENTATION_BEHIND) {
   1296             // Allow app to specify orientation regardless of its visibility state if the current
   1297             // candidate want us to use orientation behind. I.e. the visible app on-top of this one
   1298             // wants us to use the orientation of the app behind it.
   1299             return mOrientation;
   1300         }
   1301 
   1302         // The {@link AppWindowToken} should only specify an orientation when it is not closing or
   1303         // going to the bottom. Allowing closing {@link AppWindowToken} to participate can lead to
   1304         // an Activity in another task being started in the wrong orientation during the transition.
   1305         if (!(sendingToBottom || mService.mClosingApps.contains(this))
   1306                 && (isVisible() || mService.mOpeningApps.contains(this))) {
   1307             return mOrientation;
   1308         }
   1309 
   1310         return SCREEN_ORIENTATION_UNSET;
   1311     }
   1312 
   1313     /** Returns the app's preferred orientation regardless of its currently visibility state. */
   1314     int getOrientationIgnoreVisibility() {
   1315         return mOrientation;
   1316     }
   1317 
   1318     @Override
   1319     public void onConfigurationChanged(Configuration newParentConfig) {
   1320         final int prevWinMode = getWindowingMode();
   1321         super.onConfigurationChanged(newParentConfig);
   1322         final int winMode = getWindowingMode();
   1323 
   1324         if (prevWinMode == winMode) {
   1325             return;
   1326         }
   1327 
   1328         if (prevWinMode != WINDOWING_MODE_UNDEFINED && winMode == WINDOWING_MODE_PINNED) {
   1329             // Entering PiP from fullscreen, reset the snap fraction
   1330             mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(this);
   1331         } else if (prevWinMode == WINDOWING_MODE_PINNED && winMode != WINDOWING_MODE_UNDEFINED
   1332                 && !isHidden()) {
   1333             // Leaving PiP to fullscreen, save the snap fraction based on the pre-animation bounds
   1334             // for the next re-entry into PiP (assuming the activity is not hidden or destroyed)
   1335             final TaskStack pinnedStack = mDisplayContent.getPinnedStack();
   1336             if (pinnedStack != null) {
   1337                 final Rect stackBounds;
   1338                 if (pinnedStack.lastAnimatingBoundsWasToFullscreen()) {
   1339                     // We are animating the bounds, use the pre-animation bounds to save the snap
   1340                     // fraction
   1341                     stackBounds = pinnedStack.mPreAnimationBounds;
   1342                 } else {
   1343                     // We skip the animation if the fullscreen configuration is not compatible, so
   1344                     // use the current bounds to calculate the saved snap fraction instead
   1345                     // (see PinnedActivityStack.skipResizeAnimation())
   1346                     stackBounds = mTmpRect;
   1347                     pinnedStack.getBounds(stackBounds);
   1348                 }
   1349                 mDisplayContent.mPinnedStackControllerLocked.saveReentrySnapFraction(this,
   1350                         stackBounds);
   1351             }
   1352         }
   1353     }
   1354 
   1355     @Override
   1356     void checkAppWindowsReadyToShow() {
   1357         if (allDrawn == mLastAllDrawn) {
   1358             return;
   1359         }
   1360 
   1361         mLastAllDrawn = allDrawn;
   1362         if (!allDrawn) {
   1363             return;
   1364         }
   1365 
   1366         // The token has now changed state to having all windows shown...  what to do, what to do?
   1367         if (mFreezingScreen) {
   1368             showAllWindowsLocked();
   1369             stopFreezingScreen(false, true);
   1370             if (DEBUG_ORIENTATION) Slog.i(TAG,
   1371                     "Setting mOrientationChangeComplete=true because wtoken " + this
   1372                     + " numInteresting=" + mNumInterestingWindows + " numDrawn=" + mNumDrawnWindows);
   1373             // This will set mOrientationChangeComplete and cause a pass through layout.
   1374             setAppLayoutChanges(FINISH_LAYOUT_REDO_WALLPAPER,
   1375                     "checkAppWindowsReadyToShow: freezingScreen");
   1376         } else {
   1377             setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM, "checkAppWindowsReadyToShow");
   1378 
   1379             // We can now show all of the drawn windows!
   1380             if (!mService.mOpeningApps.contains(this)) {
   1381                 showAllWindowsLocked();
   1382             }
   1383         }
   1384     }
   1385 
   1386     /**
   1387      * Returns whether the drawn window states of this {@link AppWindowToken} has considered every
   1388      * child {@link WindowState}. A child is considered if it has been passed into
   1389      * {@link #updateDrawnWindowStates(WindowState)} after being added. This is used to determine
   1390      * whether states, such as {@code allDrawn}, can be set, which relies on state variables such as
   1391      * {@code mNumInterestingWindows}, which depend on all {@link WindowState}s being considered.
   1392      *
   1393      * @return {@code true} If all children have been considered, {@code false}.
   1394      */
   1395     private boolean allDrawnStatesConsidered() {
   1396         for (int i = mChildren.size() - 1; i >= 0; --i) {
   1397             final WindowState child = mChildren.get(i);
   1398             if (child.mightAffectAllDrawn() && !child.getDrawnStateEvaluated()) {
   1399                 return false;
   1400             }
   1401         }
   1402         return true;
   1403     }
   1404 
   1405     /**
   1406      *  Determines if the token has finished drawing. This should only be called from
   1407      *  {@link DisplayContent#applySurfaceChangesTransaction}
   1408      */
   1409     void updateAllDrawn() {
   1410         if (!allDrawn) {
   1411             // Number of drawn windows can be less when a window is being relaunched, wait for
   1412             // all windows to be launched and drawn for this token be considered all drawn.
   1413             final int numInteresting = mNumInterestingWindows;
   1414 
   1415             // We must make sure that all present children have been considered (determined by
   1416             // {@link #allDrawnStatesConsidered}) before evaluating whether everything has been
   1417             // drawn.
   1418             if (numInteresting > 0 && allDrawnStatesConsidered()
   1419                     && mNumDrawnWindows >= numInteresting && !isRelaunching()) {
   1420                 if (DEBUG_VISIBILITY) Slog.v(TAG, "allDrawn: " + this
   1421                         + " interesting=" + numInteresting + " drawn=" + mNumDrawnWindows);
   1422                 allDrawn = true;
   1423                 // Force an additional layout pass where
   1424                 // WindowStateAnimator#commitFinishDrawingLocked() will call performShowLocked().
   1425                 if (mDisplayContent != null) {
   1426                     mDisplayContent.setLayoutNeeded();
   1427                 }
   1428                 mService.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN, token).sendToTarget();
   1429 
   1430                 // Notify the pinned stack upon all windows drawn. If there was an animation in
   1431                 // progress then this signal will resume that animation.
   1432                 final TaskStack pinnedStack = mDisplayContent.getPinnedStack();
   1433                 if (pinnedStack != null) {
   1434                     pinnedStack.onAllWindowsDrawn();
   1435                 }
   1436             }
   1437         }
   1438     }
   1439 
   1440     /**
   1441      * Updated this app token tracking states for interesting and drawn windows based on the window.
   1442      *
   1443      * @return Returns true if the input window is considered interesting and drawn while all the
   1444      *         windows in this app token where not considered drawn as of the last pass.
   1445      */
   1446     boolean updateDrawnWindowStates(WindowState w) {
   1447         w.setDrawnStateEvaluated(true /*evaluated*/);
   1448 
   1449         if (DEBUG_STARTING_WINDOW_VERBOSE && w == startingWindow) {
   1450             Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen=" + w.isOnScreen()
   1451                     + " allDrawn=" + allDrawn + " freezingScreen=" + mFreezingScreen);
   1452         }
   1453 
   1454         if (allDrawn && !mFreezingScreen) {
   1455             return false;
   1456         }
   1457 
   1458         if (mLastTransactionSequence != mService.mTransactionSequence) {
   1459             mLastTransactionSequence = mService.mTransactionSequence;
   1460             mNumDrawnWindows = 0;
   1461             startingDisplayed = false;
   1462 
   1463             // There is the main base application window, even if it is exiting, wait for it
   1464             mNumInterestingWindows = findMainWindow(false /* includeStartingApp */) != null ? 1 : 0;
   1465         }
   1466 
   1467         final WindowStateAnimator winAnimator = w.mWinAnimator;
   1468 
   1469         boolean isInterestingAndDrawn = false;
   1470 
   1471         if (!allDrawn && w.mightAffectAllDrawn()) {
   1472             if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
   1473                 Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
   1474                         + ", isAnimationSet=" + isSelfAnimating());
   1475                 if (!w.isDrawnLw()) {
   1476                     Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceController
   1477                             + " pv=" + w.mPolicyVisibility
   1478                             + " mDrawState=" + winAnimator.drawStateToString()
   1479                             + " ph=" + w.isParentWindowHidden() + " th=" + hiddenRequested
   1480                             + " a=" + isSelfAnimating());
   1481                 }
   1482             }
   1483 
   1484             if (w != startingWindow) {
   1485                 if (w.isInteresting()) {
   1486                     // Add non-main window as interesting since the main app has already been added
   1487                     if (findMainWindow(false /* includeStartingApp */) != w) {
   1488                         mNumInterestingWindows++;
   1489                     }
   1490                     if (w.isDrawnLw()) {
   1491                         mNumDrawnWindows++;
   1492 
   1493                         if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG, "tokenMayBeDrawn: "
   1494                                 + this + " w=" + w + " numInteresting=" + mNumInterestingWindows
   1495                                 + " freezingScreen=" + mFreezingScreen
   1496                                 + " mAppFreezing=" + w.mAppFreezing);
   1497 
   1498                         isInterestingAndDrawn = true;
   1499                     }
   1500                 }
   1501             } else if (w.isDrawnLw()) {
   1502                 if (getController() != null) {
   1503                     getController().reportStartingWindowDrawn();
   1504                 }
   1505                 startingDisplayed = true;
   1506             }
   1507         }
   1508 
   1509         return isInterestingAndDrawn;
   1510     }
   1511 
   1512     void layoutLetterbox(WindowState winHint) {
   1513         final WindowState w = findMainWindow();
   1514         if (w == null || winHint != null && w != winHint) {
   1515             return;
   1516         }
   1517         final boolean surfaceReady = w.isDrawnLw()  // Regular case
   1518                 || w.mWinAnimator.mSurfaceDestroyDeferred  // The preserved surface is still ready.
   1519                 || w.isDragResizeChanged();  // Waiting for relayoutWindow to call preserveSurface.
   1520         final boolean needsLetterbox = w.isLetterboxedAppWindow() && fillsParent() && surfaceReady;
   1521         if (needsLetterbox) {
   1522             if (mLetterbox == null) {
   1523                 mLetterbox = new Letterbox(() -> makeChildSurface(null));
   1524             }
   1525             mLetterbox.layout(getParent().getBounds(), w.mFrame);
   1526         } else if (mLetterbox != null) {
   1527             mLetterbox.hide();
   1528         }
   1529     }
   1530 
   1531     void updateLetterboxSurface(WindowState winHint) {
   1532         final WindowState w = findMainWindow();
   1533         if (w != winHint && winHint != null && w != null) {
   1534             return;
   1535         }
   1536         layoutLetterbox(winHint);
   1537         if (mLetterbox != null && mLetterbox.needsApplySurfaceChanges()) {
   1538             mLetterbox.applySurfaceChanges(mPendingTransaction);
   1539         }
   1540     }
   1541 
   1542     @Override
   1543     boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
   1544         // For legacy reasons we process the TaskStack.mExitingAppTokens first in DisplayContent
   1545         // before the non-exiting app tokens. So, we skip the exiting app tokens here.
   1546         // TODO: Investigate if we need to continue to do this or if we can just process them
   1547         // in-order.
   1548         if (mIsExiting && !waitingForReplacement()) {
   1549             return false;
   1550         }
   1551         return forAllWindowsUnchecked(callback, traverseTopToBottom);
   1552     }
   1553 
   1554     boolean forAllWindowsUnchecked(ToBooleanFunction<WindowState> callback,
   1555             boolean traverseTopToBottom) {
   1556         return super.forAllWindows(callback, traverseTopToBottom);
   1557     }
   1558 
   1559     @Override
   1560     AppWindowToken asAppWindowToken() {
   1561         // I am an app window token!
   1562         return this;
   1563     }
   1564 
   1565     @Override
   1566     boolean fillsParent() {
   1567         return mFillsParent;
   1568     }
   1569 
   1570     void setFillsParent(boolean fillsParent) {
   1571         mFillsParent = fillsParent;
   1572     }
   1573 
   1574     boolean containsDismissKeyguardWindow() {
   1575         // Window state is transient during relaunch. We are not guaranteed to be frozen during the
   1576         // entirety of the relaunch.
   1577         if (isRelaunching()) {
   1578             return mLastContainsDismissKeyguardWindow;
   1579         }
   1580 
   1581         for (int i = mChildren.size() - 1; i >= 0; i--) {
   1582             if ((mChildren.get(i).mAttrs.flags & FLAG_DISMISS_KEYGUARD) != 0) {
   1583                 return true;
   1584             }
   1585         }
   1586         return false;
   1587     }
   1588 
   1589     boolean containsShowWhenLockedWindow() {
   1590         // When we are relaunching, it is possible for us to be unfrozen before our previous
   1591         // windows have been added back. Using the cached value ensures that our previous
   1592         // showWhenLocked preference is honored until relaunching is complete.
   1593         if (isRelaunching()) {
   1594             return mLastContainsShowWhenLockedWindow;
   1595         }
   1596 
   1597         for (int i = mChildren.size() - 1; i >= 0; i--) {
   1598             if ((mChildren.get(i).mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
   1599                 return true;
   1600             }
   1601         }
   1602 
   1603         return false;
   1604     }
   1605 
   1606     void checkKeyguardFlagsChanged() {
   1607         final boolean containsDismissKeyguard = containsDismissKeyguardWindow();
   1608         final boolean containsShowWhenLocked = containsShowWhenLockedWindow();
   1609         if (containsDismissKeyguard != mLastContainsDismissKeyguardWindow
   1610                 || containsShowWhenLocked != mLastContainsShowWhenLockedWindow) {
   1611             mService.notifyKeyguardFlagsChanged(null /* callback */);
   1612         }
   1613         mLastContainsDismissKeyguardWindow = containsDismissKeyguard;
   1614         mLastContainsShowWhenLockedWindow = containsShowWhenLocked;
   1615     }
   1616 
   1617     WindowState getImeTargetBelowWindow(WindowState w) {
   1618         final int index = mChildren.indexOf(w);
   1619         if (index > 0) {
   1620             final WindowState target = mChildren.get(index - 1);
   1621             if (target.canBeImeTarget()) {
   1622                 return target;
   1623             }
   1624         }
   1625         return null;
   1626     }
   1627 
   1628     int getLowestAnimLayer() {
   1629         for (int i = 0; i < mChildren.size(); i++) {
   1630             final WindowState w = mChildren.get(i);
   1631             if (w.mRemoved) {
   1632                 continue;
   1633             }
   1634             return w.mWinAnimator.mAnimLayer;
   1635         }
   1636         return Integer.MAX_VALUE;
   1637     }
   1638 
   1639     WindowState getHighestAnimLayerWindow(WindowState currentTarget) {
   1640         WindowState candidate = null;
   1641         for (int i = mChildren.indexOf(currentTarget); i >= 0; i--) {
   1642             final WindowState w = mChildren.get(i);
   1643             if (w.mRemoved) {
   1644                 continue;
   1645             }
   1646             if (candidate == null || w.mWinAnimator.mAnimLayer >
   1647                     candidate.mWinAnimator.mAnimLayer) {
   1648                 candidate = w;
   1649             }
   1650         }
   1651         return candidate;
   1652     }
   1653 
   1654     /**
   1655      * See {@link Activity#setDisablePreviewScreenshots}.
   1656      */
   1657     void setDisablePreviewScreenshots(boolean disable) {
   1658         mDisablePreviewScreenshots = disable;
   1659     }
   1660 
   1661     /**
   1662      * Sets whether the current launch can turn the screen on. See {@link #canTurnScreenOn()}
   1663      */
   1664     void setCanTurnScreenOn(boolean canTurnScreenOn) {
   1665         mCanTurnScreenOn = canTurnScreenOn;
   1666     }
   1667 
   1668     /**
   1669      * Indicates whether the current launch can turn the screen on. This is to prevent multiple
   1670      * relayouts from turning the screen back on. The screen should only turn on at most
   1671      * once per activity resume.
   1672      *
   1673      * @return true if the screen can be turned on.
   1674      */
   1675     boolean canTurnScreenOn() {
   1676         return mCanTurnScreenOn;
   1677     }
   1678 
   1679     /**
   1680      * Retrieves whether we'd like to generate a snapshot that's based solely on the theme. This is
   1681      * the case when preview screenshots are disabled {@link #setDisablePreviewScreenshots} or when
   1682      * we can't take a snapshot for other reasons, for example, if we have a secure window.
   1683      *
   1684      * @return True if we need to generate an app theme snapshot, false if we'd like to take a real
   1685      *         screenshot.
   1686      */
   1687     boolean shouldUseAppThemeSnapshot() {
   1688         return mDisablePreviewScreenshots || forAllWindows(w -> (w.mAttrs.flags & FLAG_SECURE) != 0,
   1689                 true /* topToBottom */);
   1690     }
   1691 
   1692     SurfaceControl getAppAnimationLayer() {
   1693         return getAppAnimationLayer(isActivityTypeHome() ? ANIMATION_LAYER_HOME
   1694                 : needsZBoost() ? ANIMATION_LAYER_BOOSTED
   1695                 : ANIMATION_LAYER_STANDARD);
   1696     }
   1697 
   1698     @Override
   1699     public SurfaceControl getAnimationLeashParent() {
   1700         // All normal app transitions take place in an animation layer which is below the pinned
   1701         // stack but may be above the parent stacks of the given animating apps.
   1702         // For transitions in the pinned stack (menu activity) we just let them occur as a child
   1703         // of the pinned stack.
   1704         if (!inPinnedWindowingMode()) {
   1705             return getAppAnimationLayer();
   1706         } else {
   1707             return getStack().getSurfaceControl();
   1708         }
   1709     }
   1710 
   1711     private boolean shouldAnimate(int transit) {
   1712         final boolean isSplitScreenPrimary =
   1713                 getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
   1714         final boolean allowSplitScreenPrimaryAnimation = transit != TRANSIT_WALLPAPER_OPEN;
   1715 
   1716         // We animate always if it's not split screen primary, and only some special cases in split
   1717         // screen primary because it causes issues with stack clipping when we run an un-minimize
   1718         // animation at the same time.
   1719         return !isSplitScreenPrimary || allowSplitScreenPrimaryAnimation;
   1720     }
   1721 
   1722     boolean applyAnimationLocked(WindowManager.LayoutParams lp, int transit, boolean enter,
   1723             boolean isVoiceInteraction) {
   1724 
   1725         if (mService.mDisableTransitionAnimation || !shouldAnimate(transit)) {
   1726             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
   1727                 Slog.v(TAG_WM, "applyAnimation: transition animation is disabled or skipped."
   1728                         + " atoken=" + this);
   1729             }
   1730             cancelAnimation();
   1731             return false;
   1732         }
   1733 
   1734         // Only apply an animation if the display isn't frozen. If it is frozen, there is no reason
   1735         // to animate and it can cause strange artifacts when we unfreeze the display if some
   1736         // different animation is running.
   1737         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AWT#applyAnimationLocked");
   1738         if (okToAnimate()) {
   1739             final AnimationAdapter adapter;
   1740             final TaskStack stack = getStack();
   1741             mTmpPoint.set(0, 0);
   1742             mTmpRect.setEmpty();
   1743             if (stack != null) {
   1744                 stack.getRelativePosition(mTmpPoint);
   1745                 stack.getBounds(mTmpRect);
   1746                 mTmpRect.offsetTo(0, 0);
   1747             }
   1748 
   1749             // Delaying animation start isn't compatible with remote animations at all.
   1750             if (mService.mAppTransition.getRemoteAnimationController() != null
   1751                     && !mSurfaceAnimator.isAnimationStartDelayed()) {
   1752                 adapter = mService.mAppTransition.getRemoteAnimationController()
   1753                         .createAnimationAdapter(this, mTmpPoint, mTmpRect);
   1754             } else {
   1755                 final Animation a = loadAnimation(lp, transit, enter, isVoiceInteraction);
   1756                 if (a != null) {
   1757                     adapter = new LocalAnimationAdapter(
   1758                             new WindowAnimationSpec(a, mTmpPoint, mTmpRect,
   1759                                     mService.mAppTransition.canSkipFirstFrame(),
   1760                                     mService.mAppTransition.getAppStackClipMode(),
   1761                                     true /* isAppAnimation */),
   1762                             mService.mSurfaceAnimationRunner);
   1763                     if (a.getZAdjustment() == Animation.ZORDER_TOP) {
   1764                         mNeedsZBoost = true;
   1765                     }
   1766                     mTransit = transit;
   1767                     mTransitFlags = mService.mAppTransition.getTransitFlags();
   1768                 } else {
   1769                     adapter = null;
   1770                 }
   1771             }
   1772             if (adapter != null) {
   1773                 startAnimation(getPendingTransaction(), adapter, !isVisible());
   1774                 if (adapter.getShowWallpaper()) {
   1775                     mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
   1776                 }
   1777             }
   1778         } else {
   1779             cancelAnimation();
   1780         }
   1781         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
   1782 
   1783         return isReallyAnimating();
   1784     }
   1785 
   1786     private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
   1787             boolean isVoiceInteraction) {
   1788         final DisplayContent displayContent = getTask().getDisplayContent();
   1789         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
   1790         final int width = displayInfo.appWidth;
   1791         final int height = displayInfo.appHeight;
   1792         if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG_WM,
   1793                 "applyAnimation: atoken=" + this);
   1794 
   1795         // Determine the visible rect to calculate the thumbnail clip
   1796         final WindowState win = findMainWindow();
   1797         final Rect frame = new Rect(0, 0, width, height);
   1798         final Rect displayFrame = new Rect(0, 0,
   1799                 displayInfo.logicalWidth, displayInfo.logicalHeight);
   1800         final Rect insets = new Rect();
   1801         final Rect stableInsets = new Rect();
   1802         Rect surfaceInsets = null;
   1803         final boolean freeform = win != null && win.inFreeformWindowingMode();
   1804         if (win != null) {
   1805             // Containing frame will usually cover the whole screen, including dialog windows.
   1806             // For freeform workspace windows it will not cover the whole screen and it also
   1807             // won't exactly match the final freeform window frame (e.g. when overlapping with
   1808             // the status bar). In that case we need to use the final frame.
   1809             if (freeform) {
   1810                 frame.set(win.mFrame);
   1811             } else if (win.isLetterboxedAppWindow()) {
   1812                 frame.set(getTask().getBounds());
   1813             } else if (win.isDockedResizing()) {
   1814                 // If we are animating while docked resizing, then use the stack bounds as the
   1815                 // animation target (which will be different than the task bounds)
   1816                 frame.set(getTask().getParent().getBounds());
   1817             } else {
   1818                 frame.set(win.mContainingFrame);
   1819             }
   1820             surfaceInsets = win.getAttrs().surfaceInsets;
   1821             // XXX(b/72757033): These are insets relative to the window frame, but we're really
   1822             // interested in the insets relative to the frame we chose in the if-blocks above.
   1823             insets.set(win.mContentInsets);
   1824             stableInsets.set(win.mStableInsets);
   1825         }
   1826 
   1827         if (mLaunchTaskBehind) {
   1828             // Differentiate the two animations. This one which is briefly on the screen
   1829             // gets the !enter animation, and the other activity which remains on the
   1830             // screen gets the enter animation. Both appear in the mOpeningApps set.
   1831             enter = false;
   1832         }
   1833         if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "Loading animation for app transition."
   1834                 + " transit=" + AppTransition.appTransitionToString(transit) + " enter=" + enter
   1835                 + " frame=" + frame + " insets=" + insets + " surfaceInsets=" + surfaceInsets);
   1836         final Configuration displayConfig = displayContent.getConfiguration();
   1837         final Animation a = mService.mAppTransition.loadAnimation(lp, transit, enter,
   1838                 displayConfig.uiMode, displayConfig.orientation, frame, displayFrame, insets,
   1839                 surfaceInsets, stableInsets, isVoiceInteraction, freeform, getTask().mTaskId);
   1840         if (a != null) {
   1841             if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + this);
   1842             final int containingWidth = frame.width();
   1843             final int containingHeight = frame.height();
   1844             a.initialize(containingWidth, containingHeight, width, height);
   1845             a.scaleCurrentDuration(mService.getTransitionAnimationScaleLocked());
   1846         }
   1847         return a;
   1848     }
   1849 
   1850     @Override
   1851     public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
   1852         return mAnimatingAppWindowTokenRegistry != null
   1853                 && mAnimatingAppWindowTokenRegistry.notifyAboutToFinish(
   1854                         this, endDeferFinishCallback);
   1855     }
   1856 
   1857     @Override
   1858     public void onAnimationLeashDestroyed(Transaction t) {
   1859         super.onAnimationLeashDestroyed(t);
   1860         if (mAnimatingAppWindowTokenRegistry != null) {
   1861             mAnimatingAppWindowTokenRegistry.notifyFinished(this);
   1862         }
   1863     }
   1864 
   1865     @Override
   1866     protected void setLayer(Transaction t, int layer) {
   1867         if (!mSurfaceAnimator.hasLeash()) {
   1868             t.setLayer(mSurfaceControl, layer);
   1869         }
   1870     }
   1871 
   1872     @Override
   1873     protected void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
   1874         if (!mSurfaceAnimator.hasLeash()) {
   1875             t.setRelativeLayer(mSurfaceControl, relativeTo, layer);
   1876         }
   1877     }
   1878 
   1879     @Override
   1880     protected void reparentSurfaceControl(Transaction t, SurfaceControl newParent) {
   1881         if (!mSurfaceAnimator.hasLeash()) {
   1882             t.reparent(mSurfaceControl, newParent.getHandle());
   1883         }
   1884     }
   1885 
   1886     @Override
   1887     public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
   1888         // The leash is parented to the animation layer. We need to preserve the z-order by using
   1889         // the prefix order index, but we boost if necessary.
   1890         int layer = 0;
   1891         if (!inPinnedWindowingMode()) {
   1892             layer = getPrefixOrderIndex();
   1893         } else {
   1894             // Pinned stacks have animations take place within themselves rather than an animation
   1895             // layer so we need to preserve the order relative to the stack (e.g. the order of our
   1896             // task/parent).
   1897             layer = getParent().getPrefixOrderIndex();
   1898         }
   1899 
   1900         if (mNeedsZBoost) {
   1901             layer += Z_BOOST_BASE;
   1902         }
   1903         leash.setLayer(layer);
   1904 
   1905         final DisplayContent dc = getDisplayContent();
   1906         dc.assignStackOrdering();
   1907         if (mAnimatingAppWindowTokenRegistry != null) {
   1908             mAnimatingAppWindowTokenRegistry.notifyStarting(this);
   1909         }
   1910     }
   1911 
   1912     /**
   1913      * This must be called while inside a transaction.
   1914      */
   1915     void showAllWindowsLocked() {
   1916         forAllWindows(windowState -> {
   1917             if (DEBUG_VISIBILITY) Slog.v(TAG, "performing show on: " + windowState);
   1918             windowState.performShowLocked();
   1919         }, false /* traverseTopToBottom */);
   1920     }
   1921 
   1922     @Override
   1923     protected void onAnimationFinished() {
   1924         super.onAnimationFinished();
   1925 
   1926         mTransit = TRANSIT_UNSET;
   1927         mTransitFlags = 0;
   1928         mNeedsZBoost = false;
   1929 
   1930         setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM | FINISH_LAYOUT_REDO_WALLPAPER,
   1931                 "AppWindowToken");
   1932 
   1933         clearThumbnail();
   1934         setClientHidden(isHidden() && hiddenRequested);
   1935 
   1936         if (mService.mInputMethodTarget != null && mService.mInputMethodTarget.mAppToken == this) {
   1937             getDisplayContent().computeImeTarget(true /* updateImeTarget */);
   1938         }
   1939 
   1940         if (DEBUG_ANIM) Slog.v(TAG, "Animation done in " + this
   1941                 + ": reportedVisible=" + reportedVisible
   1942                 + " okToDisplay=" + okToDisplay()
   1943                 + " okToAnimate=" + okToAnimate()
   1944                 + " startingDisplayed=" + startingDisplayed);
   1945 
   1946         // WindowState.onExitAnimationDone might modify the children list, so make a copy and then
   1947         // traverse the copy.
   1948         final ArrayList<WindowState> children = new ArrayList<>(mChildren);
   1949         children.forEach(WindowState::onExitAnimationDone);
   1950 
   1951         mService.mAppTransition.notifyAppTransitionFinishedLocked(token);
   1952         scheduleAnimation();
   1953     }
   1954 
   1955     @Override
   1956     boolean isAppAnimating() {
   1957         return isSelfAnimating();
   1958     }
   1959 
   1960     @Override
   1961     boolean isSelfAnimating() {
   1962         // If we are about to start a transition, we also need to be considered animating.
   1963         return isWaitingForTransitionStart() || isReallyAnimating();
   1964     }
   1965 
   1966     /**
   1967      * @return True if and only if we are actually running an animation. Note that
   1968      *         {@link #isSelfAnimating} also returns true if we are waiting for an animation to
   1969      *         start.
   1970      */
   1971     private boolean isReallyAnimating() {
   1972         return super.isSelfAnimating();
   1973     }
   1974 
   1975     @Override
   1976     void cancelAnimation() {
   1977         super.cancelAnimation();
   1978         clearThumbnail();
   1979     }
   1980 
   1981     boolean isWaitingForTransitionStart() {
   1982         return mService.mAppTransition.isTransitionSet()
   1983                 && (mService.mOpeningApps.contains(this) || mService.mClosingApps.contains(this));
   1984     }
   1985 
   1986     public int getTransit() {
   1987         return mTransit;
   1988     }
   1989 
   1990     int getTransitFlags() {
   1991         return mTransitFlags;
   1992     }
   1993 
   1994     void attachThumbnailAnimation() {
   1995         if (!isReallyAnimating()) {
   1996             return;
   1997         }
   1998         final int taskId = getTask().mTaskId;
   1999         final GraphicBuffer thumbnailHeader =
   2000                 mService.mAppTransition.getAppTransitionThumbnailHeader(taskId);
   2001         if (thumbnailHeader == null) {
   2002             if (DEBUG_APP_TRANSITIONS) Slog.d(TAG, "No thumbnail header bitmap for: " + taskId);
   2003             return;
   2004         }
   2005         clearThumbnail();
   2006         mThumbnail = new AppWindowThumbnail(getPendingTransaction(), this, thumbnailHeader);
   2007         mThumbnail.startAnimation(getPendingTransaction(), loadThumbnailAnimation(thumbnailHeader));
   2008     }
   2009 
   2010     /**
   2011      * Attaches a surface with a thumbnail for the
   2012      * {@link android.app.ActivityOptions#ANIM_OPEN_CROSS_PROFILE_APPS} animation.
   2013      */
   2014     void attachCrossProfileAppsThumbnailAnimation() {
   2015         if (!isReallyAnimating()) {
   2016             return;
   2017         }
   2018         clearThumbnail();
   2019 
   2020         final WindowState win = findMainWindow();
   2021         if (win == null) {
   2022             return;
   2023         }
   2024         final Rect frame = win.mFrame;
   2025         final int thumbnailDrawableRes = getTask().mUserId == mService.mCurrentUserId
   2026                 ? R.drawable.ic_account_circle
   2027                 : R.drawable.ic_corp_badge;
   2028         final GraphicBuffer thumbnail =
   2029                 mService.mAppTransition
   2030                         .createCrossProfileAppsThumbnail(thumbnailDrawableRes, frame);
   2031         if (thumbnail == null) {
   2032             return;
   2033         }
   2034         mThumbnail = new AppWindowThumbnail(getPendingTransaction(), this, thumbnail);
   2035         final Animation animation =
   2036                 mService.mAppTransition.createCrossProfileAppsThumbnailAnimationLocked(win.mFrame);
   2037         mThumbnail.startAnimation(getPendingTransaction(), animation, new Point(frame.left,
   2038                 frame.top));
   2039     }
   2040 
   2041     private Animation loadThumbnailAnimation(GraphicBuffer thumbnailHeader) {
   2042         final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
   2043 
   2044         // If this is a multi-window scenario, we use the windows frame as
   2045         // destination of the thumbnail header animation. If this is a full screen
   2046         // window scenario, we use the whole display as the target.
   2047         WindowState win = findMainWindow();
   2048         Rect appRect = win != null ? win.getContentFrameLw() :
   2049                 new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight);
   2050         Rect insets = win != null ? win.mContentInsets : null;
   2051         final Configuration displayConfig = mDisplayContent.getConfiguration();
   2052         return mService.mAppTransition.createThumbnailAspectScaleAnimationLocked(
   2053                 appRect, insets, thumbnailHeader, getTask().mTaskId, displayConfig.uiMode,
   2054                 displayConfig.orientation);
   2055     }
   2056 
   2057     private void clearThumbnail() {
   2058         if (mThumbnail == null) {
   2059             return;
   2060         }
   2061         mThumbnail.destroy();
   2062         mThumbnail = null;
   2063     }
   2064 
   2065     void registerRemoteAnimations(RemoteAnimationDefinition definition) {
   2066         mRemoteAnimationDefinition = definition;
   2067     }
   2068 
   2069     RemoteAnimationDefinition getRemoteAnimationDefinition() {
   2070         return mRemoteAnimationDefinition;
   2071     }
   2072 
   2073     @Override
   2074     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
   2075         super.dump(pw, prefix, dumpAll);
   2076         if (appToken != null) {
   2077             pw.println(prefix + "app=true mVoiceInteraction=" + mVoiceInteraction);
   2078         }
   2079         pw.print(prefix); pw.print("task="); pw.println(getTask());
   2080         pw.print(prefix); pw.print(" mFillsParent="); pw.print(mFillsParent);
   2081                 pw.print(" mOrientation="); pw.println(mOrientation);
   2082         pw.println(prefix + "hiddenRequested=" + hiddenRequested + " mClientHidden=" + mClientHidden
   2083             + ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "")
   2084             + " reportedDrawn=" + reportedDrawn + " reportedVisible=" + reportedVisible);
   2085         if (paused) {
   2086             pw.print(prefix); pw.print("paused="); pw.println(paused);
   2087         }
   2088         if (mAppStopped) {
   2089             pw.print(prefix); pw.print("mAppStopped="); pw.println(mAppStopped);
   2090         }
   2091         if (mNumInterestingWindows != 0 || mNumDrawnWindows != 0
   2092                 || allDrawn || mLastAllDrawn) {
   2093             pw.print(prefix); pw.print("mNumInterestingWindows=");
   2094                     pw.print(mNumInterestingWindows);
   2095                     pw.print(" mNumDrawnWindows="); pw.print(mNumDrawnWindows);
   2096                     pw.print(" inPendingTransaction="); pw.print(inPendingTransaction);
   2097                     pw.print(" allDrawn="); pw.print(allDrawn);
   2098                     pw.print(" lastAllDrawn="); pw.print(mLastAllDrawn);
   2099                     pw.println(")");
   2100         }
   2101         if (inPendingTransaction) {
   2102             pw.print(prefix); pw.print("inPendingTransaction=");
   2103                     pw.println(inPendingTransaction);
   2104         }
   2105         if (startingData != null || removed || firstWindowDrawn || mIsExiting) {
   2106             pw.print(prefix); pw.print("startingData="); pw.print(startingData);
   2107                     pw.print(" removed="); pw.print(removed);
   2108                     pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn);
   2109                     pw.print(" mIsExiting="); pw.println(mIsExiting);
   2110         }
   2111         if (startingWindow != null || startingSurface != null
   2112                 || startingDisplayed || startingMoved || mHiddenSetFromTransferredStartingWindow) {
   2113             pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow);
   2114                     pw.print(" startingSurface="); pw.print(startingSurface);
   2115                     pw.print(" startingDisplayed="); pw.print(startingDisplayed);
   2116                     pw.print(" startingMoved="); pw.print(startingMoved);
   2117                     pw.println(" mHiddenSetFromTransferredStartingWindow="
   2118                             + mHiddenSetFromTransferredStartingWindow);
   2119         }
   2120         if (!mFrozenBounds.isEmpty()) {
   2121             pw.print(prefix); pw.print("mFrozenBounds="); pw.println(mFrozenBounds);
   2122             pw.print(prefix); pw.print("mFrozenMergedConfig="); pw.println(mFrozenMergedConfig);
   2123         }
   2124         if (mPendingRelaunchCount != 0) {
   2125             pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount);
   2126         }
   2127         if (getController() != null) {
   2128             pw.print(prefix); pw.print("controller="); pw.println(getController());
   2129         }
   2130         if (mRemovingFromDisplay) {
   2131             pw.println(prefix + "mRemovingFromDisplay=" + mRemovingFromDisplay);
   2132         }
   2133     }
   2134 
   2135     @Override
   2136     void setHidden(boolean hidden) {
   2137         super.setHidden(hidden);
   2138 
   2139         if (hidden) {
   2140             // Once the app window is hidden, reset the last saved PiP snap fraction
   2141             mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(this);
   2142         }
   2143         scheduleAnimation();
   2144     }
   2145 
   2146     @Override
   2147     void prepareSurfaces() {
   2148         // isSelfAnimating also returns true when we are about to start a transition, so we need
   2149         // to check super here.
   2150         final boolean reallyAnimating = super.isSelfAnimating();
   2151         final boolean show = !isHidden() || reallyAnimating;
   2152         if (show && !mLastSurfaceShowing) {
   2153             mPendingTransaction.show(mSurfaceControl);
   2154         } else if (!show && mLastSurfaceShowing) {
   2155             mPendingTransaction.hide(mSurfaceControl);
   2156         }
   2157         if (mThumbnail != null) {
   2158             mThumbnail.setShowing(mPendingTransaction, show);
   2159         }
   2160         mLastSurfaceShowing = show;
   2161         super.prepareSurfaces();
   2162     }
   2163 
   2164     /**
   2165      * @return Whether our {@link #getSurfaceControl} is currently showing.
   2166      */
   2167     boolean isSurfaceShowing() {
   2168         return mLastSurfaceShowing;
   2169     }
   2170 
   2171     boolean isFreezingScreen() {
   2172         return mFreezingScreen;
   2173     }
   2174 
   2175     @Override
   2176     boolean needsZBoost() {
   2177         return mNeedsZBoost || super.needsZBoost();
   2178     }
   2179 
   2180     @CallSuper
   2181     @Override
   2182     public void writeToProto(ProtoOutputStream proto, long fieldId, boolean trim) {
   2183         final long token = proto.start(fieldId);
   2184         writeNameToProto(proto, NAME);
   2185         super.writeToProto(proto, WINDOW_TOKEN, trim);
   2186         proto.write(LAST_SURFACE_SHOWING, mLastSurfaceShowing);
   2187         proto.write(IS_WAITING_FOR_TRANSITION_START, isWaitingForTransitionStart());
   2188         proto.write(IS_REALLY_ANIMATING, isReallyAnimating());
   2189         if (mThumbnail != null){
   2190             mThumbnail.writeToProto(proto, THUMBNAIL);
   2191         }
   2192         proto.write(FILLS_PARENT, mFillsParent);
   2193         proto.write(APP_STOPPED, mAppStopped);
   2194         proto.write(HIDDEN_REQUESTED, hiddenRequested);
   2195         proto.write(CLIENT_HIDDEN, mClientHidden);
   2196         proto.write(DEFER_HIDING_CLIENT, mDeferHidingClient);
   2197         proto.write(REPORTED_DRAWN, reportedDrawn);
   2198         proto.write(REPORTED_VISIBLE, reportedVisible);
   2199         proto.write(NUM_INTERESTING_WINDOWS, mNumInterestingWindows);
   2200         proto.write(NUM_DRAWN_WINDOWS, mNumDrawnWindows);
   2201         proto.write(ALL_DRAWN, allDrawn);
   2202         proto.write(LAST_ALL_DRAWN, mLastAllDrawn);
   2203         proto.write(REMOVED, removed);
   2204         if (startingWindow != null){
   2205             startingWindow.writeIdentifierToProto(proto, STARTING_WINDOW);
   2206         }
   2207         proto.write(STARTING_DISPLAYED, startingDisplayed);
   2208         proto.write(STARTING_MOVED, startingMoved);
   2209         proto.write(HIDDEN_SET_FROM_TRANSFERRED_STARTING_WINDOW,
   2210                 mHiddenSetFromTransferredStartingWindow);
   2211         for (Rect bounds : mFrozenBounds) {
   2212             bounds.writeToProto(proto, FROZEN_BOUNDS);
   2213         }
   2214         proto.end(token);
   2215     }
   2216 
   2217     void writeNameToProto(ProtoOutputStream proto, long fieldId) {
   2218         if (appToken == null) {
   2219             return;
   2220         }
   2221         try {
   2222             proto.write(fieldId, appToken.getName());
   2223         } catch (RemoteException e) {
   2224             // This shouldn't happen, but in this case fall back to outputting nothing
   2225             Slog.e(TAG, e.toString());
   2226         }
   2227     }
   2228 
   2229     @Override
   2230     public String toString() {
   2231         if (stringName == null) {
   2232             StringBuilder sb = new StringBuilder();
   2233             sb.append("AppWindowToken{");
   2234             sb.append(Integer.toHexString(System.identityHashCode(this)));
   2235             sb.append(" token="); sb.append(token); sb.append('}');
   2236             stringName = sb.toString();
   2237         }
   2238         return stringName + ((mIsExiting) ? " mIsExiting=" : "");
   2239     }
   2240 
   2241     Rect getLetterboxInsets() {
   2242         if (mLetterbox != null) {
   2243             return mLetterbox.getInsets();
   2244         } else {
   2245             return new Rect();
   2246         }
   2247     }
   2248 
   2249     /**
   2250      * @eturn true if there is a letterbox and any part of that letterbox overlaps with
   2251      * the given {@code rect}.
   2252      */
   2253     boolean isLetterboxOverlappingWith(Rect rect) {
   2254         return mLetterbox != null && mLetterbox.isOverlappingWith(rect);
   2255     }
   2256 
   2257     /**
   2258      * Sets if this AWT is in the process of closing or entering PIP.
   2259      * {@link #mWillCloseOrEnterPip}}
   2260      */
   2261     void setWillCloseOrEnterPip(boolean willCloseOrEnterPip) {
   2262         mWillCloseOrEnterPip = willCloseOrEnterPip;
   2263     }
   2264 
   2265     /**
   2266      * Returns whether this AWT is considered closing. Conditions are either
   2267      * 1. Is this app animating and was requested to be hidden
   2268      * 2. App is delayed closing since it might enter PIP.
   2269      */
   2270     boolean isClosingOrEnteringPip() {
   2271         return (isAnimating() && hiddenRequested) || mWillCloseOrEnterPip;
   2272     }
   2273 }
   2274