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 
AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint, int configChanges, boolean launchTaskBehind, boolean alwaysFocusable, AppWindowContainerController controller)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 
AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction, DisplayContent dc, boolean fillsParent)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 
onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator)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 
updateReportedVisibilityLocked()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 
isClientHidden()373     boolean isClientHidden() {
374         return mClientHidden;
375     }
376 
setClientHidden(boolean hideClient)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 
setVisibility(WindowManager.LayoutParams lp, boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction)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      */
getTopFullscreenWindow()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 
findMainWindow()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      */
findMainWindow(boolean includeStartingApp)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 
windowsAreFocusable()578     boolean windowsAreFocusable() {
579         return getWindowConfiguration().canReceiveKeys() || mAlwaysFocusable;
580     }
581 
getController()582     AppWindowContainerController getController() {
583         final WindowContainerController controller = super.getController();
584         return controller != null ? (AppWindowContainerController) controller : null;
585     }
586 
587     @Override
isVisible()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
removeImmediately()595     void removeImmediately() {
596         onRemovedFromDisplay();
597         super.removeImmediately();
598     }
599 
600     @Override
removeIfPossible()601     void removeIfPossible() {
602         mIsExiting = false;
603         removeAllWindowsIfPossible();
604         removeImmediately();
605     }
606 
607     @Override
checkCompleteDeferredRemoval()608     boolean checkCompleteDeferredRemoval() {
609         if (mIsExiting) {
610             removeIfPossible();
611         }
612         return super.checkCompleteDeferredRemoval();
613     }
614 
onRemovedFromDisplay()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 
clearAnimatingFlags()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 
destroySurfaces()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      */
destroySurfaces(boolean cleanupOnResume)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      */
notifyAppResumed(boolean wasStopped)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      */
notifyAppStopped()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 
clearAllDrawn()758     void clearAllDrawn() {
759         allDrawn = false;
760         deferClearAllDrawn = false;
761     }
762 
getTask()763     Task getTask() {
764         return (Task) getParent();
765     }
766 
getStack()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
onParentSet()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 
postWindowRemoveStartingWindowCleanup(WindowState win)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 
removeDeadWindows()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 
hasWindowsAlive()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 
setWillReplaceWindows(boolean animate)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 
setWillReplaceChildWindows()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 
clearWillReplaceWindows()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 
requestUpdateWallpaperIfNeeded()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 
isRelaunching()897     boolean isRelaunching() {
898         return mPendingRelaunchCount > 0;
899     }
900 
shouldFreezeBounds()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 
startRelaunching()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 
detachChildren()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 
finishRelaunching()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 
clearRelaunching()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
isFirstChildWindowGreaterThanSecond(WindowState newWindow, WindowState existingWindow)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
addWindow(WindowState w)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
removeChild(WindowState child)1005     void removeChild(WindowState child) {
1006         super.removeChild(child);
1007         checkKeyguardFlagsChanged();
1008         updateLetterboxSurface(child);
1009     }
1010 
waitingForReplacement()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 
onWindowReplacementTimeout()1021     void onWindowReplacementTimeout() {
1022         for (int i = mChildren.size() - 1; i >= 0; --i) {
1023             (mChildren.get(i)).onWindowReplacementTimeout();
1024         }
1025     }
1026 
reparent(Task task, int position)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      */
freezeBounds()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      */
unfreezeBounds()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 
setAppLayoutChanges(int changes, String reason)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 
removeReplacedWindowIfNeeded(WindowState replacement)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 
startFreezingScreen()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 
stopFreezingScreen(boolean unfreezeSurfaceNow, boolean force)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
onAppFreezeTimeout()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      */
transferStartingWindowFromHiddenAboveTokenIfNeeded()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 
transferStartingWindow(IBinder transferFrom)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 
isLastWindow(WindowState win)1280     boolean isLastWindow(WindowState win) {
1281         return mChildren.size() == 1 && mChildren.get(0) == win;
1282     }
1283 
1284     @Override
onAppTransitionDone()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
getOrientation(int candidate)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. */
getOrientationIgnoreVisibility()1314     int getOrientationIgnoreVisibility() {
1315         return mOrientation;
1316     }
1317 
1318     @Override
onConfigurationChanged(Configuration newParentConfig)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
checkAppWindowsReadyToShow()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      */
allDrawnStatesConsidered()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      */
updateAllDrawn()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      */
updateDrawnWindowStates(WindowState w)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 
layoutLetterbox(WindowState winHint)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 
updateLetterboxSurface(WindowState winHint)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
forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom)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 
forAllWindowsUnchecked(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom)1554     boolean forAllWindowsUnchecked(ToBooleanFunction<WindowState> callback,
1555             boolean traverseTopToBottom) {
1556         return super.forAllWindows(callback, traverseTopToBottom);
1557     }
1558 
1559     @Override
asAppWindowToken()1560     AppWindowToken asAppWindowToken() {
1561         // I am an app window token!
1562         return this;
1563     }
1564 
1565     @Override
fillsParent()1566     boolean fillsParent() {
1567         return mFillsParent;
1568     }
1569 
setFillsParent(boolean fillsParent)1570     void setFillsParent(boolean fillsParent) {
1571         mFillsParent = fillsParent;
1572     }
1573 
containsDismissKeyguardWindow()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 
containsShowWhenLockedWindow()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 
checkKeyguardFlagsChanged()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 
getImeTargetBelowWindow(WindowState w)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 
getLowestAnimLayer()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 
getHighestAnimLayerWindow(WindowState currentTarget)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      */
setDisablePreviewScreenshots(boolean disable)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      */
setCanTurnScreenOn(boolean canTurnScreenOn)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      */
canTurnScreenOn()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      */
shouldUseAppThemeSnapshot()1687     boolean shouldUseAppThemeSnapshot() {
1688         return mDisablePreviewScreenshots || forAllWindows(w -> (w.mAttrs.flags & FLAG_SECURE) != 0,
1689                 true /* topToBottom */);
1690     }
1691 
getAppAnimationLayer()1692     SurfaceControl getAppAnimationLayer() {
1693         return getAppAnimationLayer(isActivityTypeHome() ? ANIMATION_LAYER_HOME
1694                 : needsZBoost() ? ANIMATION_LAYER_BOOSTED
1695                 : ANIMATION_LAYER_STANDARD);
1696     }
1697 
1698     @Override
getAnimationLeashParent()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 
shouldAnimate(int transit)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 
applyAnimationLocked(WindowManager.LayoutParams lp, int transit, boolean enter, boolean isVoiceInteraction)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 
loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, boolean isVoiceInteraction)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
shouldDeferAnimationFinish(Runnable endDeferFinishCallback)1851     public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
1852         return mAnimatingAppWindowTokenRegistry != null
1853                 && mAnimatingAppWindowTokenRegistry.notifyAboutToFinish(
1854                         this, endDeferFinishCallback);
1855     }
1856 
1857     @Override
onAnimationLeashDestroyed(Transaction t)1858     public void onAnimationLeashDestroyed(Transaction t) {
1859         super.onAnimationLeashDestroyed(t);
1860         if (mAnimatingAppWindowTokenRegistry != null) {
1861             mAnimatingAppWindowTokenRegistry.notifyFinished(this);
1862         }
1863     }
1864 
1865     @Override
setLayer(Transaction t, int layer)1866     protected void setLayer(Transaction t, int layer) {
1867         if (!mSurfaceAnimator.hasLeash()) {
1868             t.setLayer(mSurfaceControl, layer);
1869         }
1870     }
1871 
1872     @Override
setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer)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
reparentSurfaceControl(Transaction t, SurfaceControl newParent)1880     protected void reparentSurfaceControl(Transaction t, SurfaceControl newParent) {
1881         if (!mSurfaceAnimator.hasLeash()) {
1882             t.reparent(mSurfaceControl, newParent.getHandle());
1883         }
1884     }
1885 
1886     @Override
onAnimationLeashCreated(Transaction t, SurfaceControl leash)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      */
showAllWindowsLocked()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
onAnimationFinished()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
isAppAnimating()1956     boolean isAppAnimating() {
1957         return isSelfAnimating();
1958     }
1959 
1960     @Override
isSelfAnimating()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      */
isReallyAnimating()1971     private boolean isReallyAnimating() {
1972         return super.isSelfAnimating();
1973     }
1974 
1975     @Override
cancelAnimation()1976     void cancelAnimation() {
1977         super.cancelAnimation();
1978         clearThumbnail();
1979     }
1980 
isWaitingForTransitionStart()1981     boolean isWaitingForTransitionStart() {
1982         return mService.mAppTransition.isTransitionSet()
1983                 && (mService.mOpeningApps.contains(this) || mService.mClosingApps.contains(this));
1984     }
1985 
getTransit()1986     public int getTransit() {
1987         return mTransit;
1988     }
1989 
getTransitFlags()1990     int getTransitFlags() {
1991         return mTransitFlags;
1992     }
1993 
attachThumbnailAnimation()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      */
attachCrossProfileAppsThumbnailAnimation()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 
loadThumbnailAnimation(GraphicBuffer thumbnailHeader)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 
clearThumbnail()2057     private void clearThumbnail() {
2058         if (mThumbnail == null) {
2059             return;
2060         }
2061         mThumbnail.destroy();
2062         mThumbnail = null;
2063     }
2064 
registerRemoteAnimations(RemoteAnimationDefinition definition)2065     void registerRemoteAnimations(RemoteAnimationDefinition definition) {
2066         mRemoteAnimationDefinition = definition;
2067     }
2068 
getRemoteAnimationDefinition()2069     RemoteAnimationDefinition getRemoteAnimationDefinition() {
2070         return mRemoteAnimationDefinition;
2071     }
2072 
2073     @Override
dump(PrintWriter pw, String prefix, boolean dumpAll)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
setHidden(boolean hidden)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
prepareSurfaces()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      */
isSurfaceShowing()2167     boolean isSurfaceShowing() {
2168         return mLastSurfaceShowing;
2169     }
2170 
isFreezingScreen()2171     boolean isFreezingScreen() {
2172         return mFreezingScreen;
2173     }
2174 
2175     @Override
needsZBoost()2176     boolean needsZBoost() {
2177         return mNeedsZBoost || super.needsZBoost();
2178     }
2179 
2180     @CallSuper
2181     @Override
writeToProto(ProtoOutputStream proto, long fieldId, boolean trim)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 
writeNameToProto(ProtoOutputStream proto, long fieldId)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
toString()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 
getLetterboxInsets()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      */
isLetterboxOverlappingWith(Rect rect)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      */
setWillCloseOrEnterPip(boolean willCloseOrEnterPip)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      */
isClosingOrEnteringPip()2270     boolean isClosingOrEnteringPip() {
2271         return (isAnimating() && hiddenRequested) || mWillCloseOrEnterPip;
2272     }
2273 }
2274