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_FREEFORM;
20 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
21 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
22 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
23 import static android.content.pm.ActivityInfo.COLOR_MODE_DEFAULT;
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.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
28 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
29 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
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 import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
35 import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE;
36 import static android.view.WindowManager.TRANSIT_UNSET;
37 import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
38 
39 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
40 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
41 import static com.android.server.wm.AppWindowTokenProto.ALL_DRAWN;
42 import static com.android.server.wm.AppWindowTokenProto.APP_STOPPED;
43 import static com.android.server.wm.AppWindowTokenProto.CLIENT_HIDDEN;
44 import static com.android.server.wm.AppWindowTokenProto.DEFER_HIDING_CLIENT;
45 import static com.android.server.wm.AppWindowTokenProto.FILLS_PARENT;
46 import static com.android.server.wm.AppWindowTokenProto.FROZEN_BOUNDS;
47 import static com.android.server.wm.AppWindowTokenProto.HIDDEN_REQUESTED;
48 import static com.android.server.wm.AppWindowTokenProto.HIDDEN_SET_FROM_TRANSFERRED_STARTING_WINDOW;
49 import static com.android.server.wm.AppWindowTokenProto.IS_REALLY_ANIMATING;
50 import static com.android.server.wm.AppWindowTokenProto.IS_WAITING_FOR_TRANSITION_START;
51 import static com.android.server.wm.AppWindowTokenProto.LAST_ALL_DRAWN;
52 import static com.android.server.wm.AppWindowTokenProto.LAST_SURFACE_SHOWING;
53 import static com.android.server.wm.AppWindowTokenProto.NAME;
54 import static com.android.server.wm.AppWindowTokenProto.NUM_DRAWN_WINDOWS;
55 import static com.android.server.wm.AppWindowTokenProto.NUM_INTERESTING_WINDOWS;
56 import static com.android.server.wm.AppWindowTokenProto.REMOVED;
57 import static com.android.server.wm.AppWindowTokenProto.REPORTED_DRAWN;
58 import static com.android.server.wm.AppWindowTokenProto.REPORTED_VISIBLE;
59 import static com.android.server.wm.AppWindowTokenProto.STARTING_DISPLAYED;
60 import static com.android.server.wm.AppWindowTokenProto.STARTING_MOVED;
61 import static com.android.server.wm.AppWindowTokenProto.STARTING_WINDOW;
62 import static com.android.server.wm.AppWindowTokenProto.THUMBNAIL;
63 import static com.android.server.wm.AppWindowTokenProto.WINDOW_TOKEN;
64 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
65 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
66 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
67 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
68 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
69 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
70 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
71 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE;
72 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
73 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
74 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
75 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
76 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
77 import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN;
78 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
79 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
80 import static com.android.server.wm.WindowManagerService.logWithStack;
81 import static com.android.server.wm.WindowState.LEGACY_POLICY_VISIBILITY;
82 import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
83 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
84 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
85 
86 import android.annotation.CallSuper;
87 import android.annotation.Size;
88 import android.app.Activity;
89 import android.app.ActivityManager;
90 import android.content.ComponentName;
91 import android.content.res.CompatibilityInfo;
92 import android.content.res.Configuration;
93 import android.graphics.GraphicBuffer;
94 import android.graphics.Point;
95 import android.graphics.Rect;
96 import android.os.Binder;
97 import android.os.Build;
98 import android.os.Debug;
99 import android.os.IBinder;
100 import android.os.RemoteException;
101 import android.os.SystemClock;
102 import android.os.Trace;
103 import android.util.ArraySet;
104 import android.util.Slog;
105 import android.util.proto.ProtoOutputStream;
106 import android.view.DisplayInfo;
107 import android.view.IApplicationToken;
108 import android.view.InputApplicationHandle;
109 import android.view.RemoteAnimationAdapter;
110 import android.view.RemoteAnimationDefinition;
111 import android.view.SurfaceControl;
112 import android.view.SurfaceControl.Transaction;
113 import android.view.WindowManager;
114 import android.view.WindowManager.LayoutParams;
115 import android.view.animation.Animation;
116 
117 import com.android.internal.R;
118 import com.android.internal.annotations.VisibleForTesting;
119 import com.android.internal.util.ToBooleanFunction;
120 import com.android.server.AttributeCache;
121 import com.android.server.LocalServices;
122 import com.android.server.display.color.ColorDisplayService;
123 import com.android.server.policy.WindowManagerPolicy;
124 import com.android.server.policy.WindowManagerPolicy.StartingSurface;
125 import com.android.server.wm.RemoteAnimationController.RemoteAnimationRecord;
126 import com.android.server.wm.WindowManagerService.H;
127 
128 import java.io.PrintWriter;
129 import java.lang.ref.WeakReference;
130 import java.util.ArrayDeque;
131 import java.util.ArrayList;
132 import java.util.function.Consumer;
133 
134 class AppTokenList extends ArrayList<AppWindowToken> {
135 }
136 
137 /**
138  * Version of WindowToken that is specifically for a particular application (or
139  * really activity) that is displaying windows.
140  */
141 class AppWindowToken extends WindowToken implements WindowManagerService.AppFreezeListener,
142         ConfigurationContainerListener {
143     private static final String TAG = TAG_WITH_CLASS_NAME ? "AppWindowToken" : TAG_WM;
144 
145     /**
146      * Value to increment the z-layer when boosting a layer during animations. BOOST in l33tsp34k.
147      */
148     @VisibleForTesting static final int Z_BOOST_BASE = 800570000;
149 
150     // Non-null only for application tokens.
151     final IApplicationToken appToken;
152     final ComponentName mActivityComponent;
153     final boolean mVoiceInteraction;
154 
155     /** @see WindowContainer#fillsParent() */
156     private boolean mFillsParent;
157     boolean mShowForAllUsers;
158     int mTargetSdk;
159 
160     // Flag set while reparenting to prevent actions normally triggered by an individual parent
161     // change.
162     private boolean mReparenting;
163 
164     // True if we are current in the process of removing this app token from the display
165     private boolean mRemovingFromDisplay = false;
166 
167     // The input dispatching timeout for this application token in nanoseconds.
168     long mInputDispatchingTimeoutNanos;
169 
170     // These are used for determining when all windows associated with
171     // an activity have been drawn, so they can be made visible together
172     // at the same time.
173     // initialize so that it doesn't match mTransactionSequence which is an int.
174     private long mLastTransactionSequence = Long.MIN_VALUE;
175     private int mNumInterestingWindows;
176     private int mNumDrawnWindows;
177     boolean inPendingTransaction;
178     boolean allDrawn;
179     private boolean mLastAllDrawn;
180     private boolean mUseTransferredAnimation;
181 
182     // Set to true when this app creates a surface while in the middle of an animation. In that
183     // case do not clear allDrawn until the animation completes.
184     boolean deferClearAllDrawn;
185 
186     // Is this window's surface needed?  This is almost like hidden, except
187     // it will sometimes be true a little earlier: when the token has
188     // been shown, but is still waiting for its app transition to execute
189     // before making its windows shown.
190     boolean hiddenRequested;
191 
192     // Have we told the window clients to hide themselves?
193     private boolean mClientHidden;
194 
195     // If true we will defer setting mClientHidden to true and reporting to the client that it is
196     // hidden.
197     boolean mDeferHidingClient;
198 
199     // Last visibility state we reported to the app token.
200     boolean reportedVisible;
201 
202     // Last drawn state we reported to the app token.
203     private boolean reportedDrawn;
204 
205     // Set to true when the token has been removed from the window mgr.
206     boolean removed;
207 
208     // Information about an application starting window if displayed.
209     // Note: these are de-referenced before the starting window animates away.
210     StartingData mStartingData;
211     WindowState startingWindow;
212     StartingSurface startingSurface;
213     boolean startingDisplayed;
214     boolean startingMoved;
215 
216     // True if the hidden state of this token was forced to false due to a transferred starting
217     // window.
218     private boolean mHiddenSetFromTransferredStartingWindow;
219     boolean firstWindowDrawn;
220     private final WindowState.UpdateReportedVisibilityResults mReportedVisibilityResults =
221             new WindowState.UpdateReportedVisibilityResults();
222 
223     // Input application handle used by the input dispatcher.
224     final InputApplicationHandle mInputApplicationHandle;
225 
226     // TODO: Have a WindowContainer state for tracking exiting/deferred removal.
227     boolean mIsExiting;
228 
229     boolean mLaunchTaskBehind;
230     boolean mEnteringAnimation;
231 
232     private boolean mAlwaysFocusable;
233 
234     boolean mAppStopped;
235     int mRotationAnimationHint;
236     private int mPendingRelaunchCount;
237 
238     private boolean mLastContainsShowWhenLockedWindow;
239     private boolean mLastContainsDismissKeyguardWindow;
240 
241     ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
242     ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>();
243 
244     /**
245      * The scale to fit at least one side of the activity to its parent. If the activity uses
246      * 1920x1080, and the actually size on the screen is 960x540, then the scale is 0.5.
247      */
248     private float mSizeCompatScale = 1f;
249     /**
250      * The bounds in global coordinates for activity in size compatibility mode.
251      * @see ActivityRecord#inSizeCompatMode
252      */
253     private Rect mSizeCompatBounds;
254 
255     private boolean mDisablePreviewScreenshots;
256 
257     private Task mLastParent;
258 
259     // TODO: Remove after unification
260     ActivityRecord mActivityRecord;
261 
262     /**
263      * See {@link #canTurnScreenOn()}
264      */
265     private boolean mCanTurnScreenOn = true;
266 
267     /**
268      * If we are running an animation, this determines the transition type. Must be one of
269      * AppTransition.TRANSIT_* constants.
270      */
271     private int mTransit;
272 
273     /**
274      * If we are running an animation, this determines the flags during this animation. Must be a
275      * bitwise combination of AppTransition.TRANSIT_FLAG_* constants.
276      */
277     private int mTransitFlags;
278 
279     /** Whether our surface was set to be showing in the last call to {@link #prepareSurfaces} */
280     private boolean mLastSurfaceShowing = true;
281 
282     /**
283      * This gets used during some open/close transitions as well as during a change transition
284      * where it represents the starting-state snapshot.
285      */
286     private AppWindowThumbnail mThumbnail;
287     private final Rect mTransitStartRect = new Rect();
288 
289     /**
290      * This leash is used to "freeze" the app surface in place after the state change, but before
291      * the animation is ready to start.
292      */
293     private SurfaceControl mTransitChangeLeash = null;
294 
295     /** Have we been asked to have this token keep the screen frozen? */
296     private boolean mFreezingScreen;
297 
298     /** Whether this token should be boosted at the top of all app window tokens. */
299     @VisibleForTesting boolean mNeedsZBoost;
300     private Letterbox mLetterbox;
301 
302     private final Point mTmpPoint = new Point();
303     private final Rect mTmpRect = new Rect();
304     private final Rect mTmpPrevBounds = new Rect();
305     private RemoteAnimationDefinition mRemoteAnimationDefinition;
306     private AnimatingAppWindowTokenRegistry mAnimatingAppWindowTokenRegistry;
307 
308     /**
309      * A flag to determine if this AWT is in the process of closing or entering PIP. This is needed
310      * to help AWT know that the app is in the process of closing but hasn't yet started closing on
311      * the WM side.
312      */
313     private boolean mWillCloseOrEnterPip;
314 
315     /** Layer used to constrain the animation to a token's stack bounds. */
316     SurfaceControl mAnimationBoundsLayer;
317 
318     /** Whether this token needs to create mAnimationBoundsLayer for cropping animations. */
319     boolean mNeedsAnimationBoundsLayer;
320 
321     private static final int STARTING_WINDOW_TYPE_NONE = 0;
322     private static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1;
323     private static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2;
324 
325     private AppSaturationInfo mLastAppSaturationInfo;
326 
327     private final ColorDisplayService.ColorTransformController mColorTransformController =
328             (matrix, translation) -> mWmService.mH.post(() -> {
329                 synchronized (mWmService.mGlobalLock) {
330                     if (mLastAppSaturationInfo == null) {
331                         mLastAppSaturationInfo = new AppSaturationInfo();
332                     }
333 
334                     mLastAppSaturationInfo.setSaturation(matrix, translation);
335                     updateColorTransform();
336                 }
337             });
338 
AppWindowToken(WindowManagerService service, IApplicationToken token, ComponentName activityComponent, boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint, boolean launchTaskBehind, boolean alwaysFocusable, ActivityRecord activityRecord)339     AppWindowToken(WindowManagerService service, IApplicationToken token,
340             ComponentName activityComponent, boolean voiceInteraction, DisplayContent dc,
341             long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers,
342             int targetSdk, int orientation, int rotationAnimationHint,
343             boolean launchTaskBehind, boolean alwaysFocusable,
344             ActivityRecord activityRecord) {
345         this(service, token, activityComponent, voiceInteraction, dc, fullscreen);
346         // TODO: remove after unification
347         mActivityRecord = activityRecord;
348         mActivityRecord.registerConfigurationChangeListener(this);
349         mInputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
350         mShowForAllUsers = showForAllUsers;
351         mTargetSdk = targetSdk;
352         mOrientation = orientation;
353         mLaunchTaskBehind = launchTaskBehind;
354         mAlwaysFocusable = alwaysFocusable;
355         mRotationAnimationHint = rotationAnimationHint;
356 
357         // Application tokens start out hidden.
358         setHidden(true);
359         hiddenRequested = true;
360 
361         ColorDisplayService.ColorDisplayServiceInternal cds = LocalServices.getService(
362                 ColorDisplayService.ColorDisplayServiceInternal.class);
363         cds.attachColorTransformController(activityRecord.packageName, activityRecord.mUserId,
364                 new WeakReference<>(mColorTransformController));
365     }
366 
AppWindowToken(WindowManagerService service, IApplicationToken token, ComponentName activityComponent, boolean voiceInteraction, DisplayContent dc, boolean fillsParent)367     AppWindowToken(WindowManagerService service, IApplicationToken token,
368             ComponentName activityComponent, boolean voiceInteraction, DisplayContent dc,
369             boolean fillsParent) {
370         super(service, token != null ? token.asBinder() : null, TYPE_APPLICATION, true, dc,
371                 false /* ownerCanManageAppTokens */);
372         appToken = token;
373         mActivityComponent = activityComponent;
374         mVoiceInteraction = voiceInteraction;
375         mFillsParent = fillsParent;
376         mInputApplicationHandle = new InputApplicationHandle(appToken.asBinder());
377     }
378 
onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator)379     void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) {
380         firstWindowDrawn = true;
381 
382         // We now have a good window to show, remove dead placeholders
383         removeDeadWindows();
384 
385         if (startingWindow != null) {
386             if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Slog.v(TAG, "Finish starting "
387                     + win.mToken + ": first real window is shown, no animation");
388             // If this initial window is animating, stop it -- we will do an animation to reveal
389             // it from behind the starting window, so there is no need for it to also be doing its
390             // own stuff.
391             win.cancelAnimation();
392         }
393         removeStartingWindow();
394         updateReportedVisibilityLocked();
395     }
396 
updateReportedVisibilityLocked()397     void updateReportedVisibilityLocked() {
398         if (appToken == null) {
399             return;
400         }
401 
402         if (DEBUG_VISIBILITY) Slog.v(TAG, "Update reported visibility: " + this);
403         final int count = mChildren.size();
404 
405         mReportedVisibilityResults.reset();
406 
407         for (int i = 0; i < count; i++) {
408             final WindowState win = mChildren.get(i);
409             win.updateReportedVisibility(mReportedVisibilityResults);
410         }
411 
412         int numInteresting = mReportedVisibilityResults.numInteresting;
413         int numVisible = mReportedVisibilityResults.numVisible;
414         int numDrawn = mReportedVisibilityResults.numDrawn;
415         boolean nowGone = mReportedVisibilityResults.nowGone;
416 
417         boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting;
418         boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting && !isHidden();
419         if (!nowGone) {
420             // If the app is not yet gone, then it can only become visible/drawn.
421             if (!nowDrawn) {
422                 nowDrawn = reportedDrawn;
423             }
424             if (!nowVisible) {
425                 nowVisible = reportedVisible;
426             }
427         }
428         if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting="
429                 + numInteresting + " visible=" + numVisible);
430         if (nowDrawn != reportedDrawn) {
431             if (mActivityRecord != null) {
432                 mActivityRecord.onWindowsDrawn(nowDrawn, SystemClock.uptimeMillis());
433             }
434             reportedDrawn = nowDrawn;
435         }
436         if (nowVisible != reportedVisible) {
437             if (DEBUG_VISIBILITY) Slog.v(TAG,
438                     "Visibility changed in " + this + ": vis=" + nowVisible);
439             reportedVisible = nowVisible;
440             if (mActivityRecord != null) {
441                 if (nowVisible) {
442                     onWindowsVisible();
443                 } else {
444                     onWindowsGone();
445                 }
446             }
447         }
448     }
449 
onWindowsGone()450     private void onWindowsGone() {
451         if (mActivityRecord == null) {
452             return;
453         }
454         if (DEBUG_VISIBILITY) {
455             Slog.v(TAG_WM, "Reporting gone in " + mActivityRecord.appToken);
456         }
457         mActivityRecord.onWindowsGone();
458     }
459 
onWindowsVisible()460     private void onWindowsVisible() {
461         if (mActivityRecord == null) {
462             return;
463         }
464         if (DEBUG_VISIBILITY) {
465             Slog.v(TAG_WM, "Reporting visible in " + mActivityRecord.appToken);
466         }
467         mActivityRecord.onWindowsVisible();
468     }
469 
isClientHidden()470     boolean isClientHidden() {
471         return mClientHidden;
472     }
473 
setClientHidden(boolean hideClient)474     void setClientHidden(boolean hideClient) {
475         if (mClientHidden == hideClient || (hideClient && mDeferHidingClient)) {
476             return;
477         }
478         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "setClientHidden: " + this
479                 + " clientHidden=" + hideClient + " Callers=" + Debug.getCallers(5));
480         mClientHidden = hideClient;
481         sendAppVisibilityToClients();
482     }
483 
setVisibility(boolean visible, boolean deferHidingClient)484     void setVisibility(boolean visible, boolean deferHidingClient) {
485         final AppTransition appTransition = getDisplayContent().mAppTransition;
486 
487         // Don't set visibility to false if we were already not visible. This prevents WM from
488         // adding the app to the closing app list which doesn't make sense for something that is
489         // already not visible. However, set visibility to true even if we are already visible.
490         // This makes sure the app is added to the opening apps list so that the right
491         // transition can be selected.
492         // TODO: Probably a good idea to separate the concept of opening/closing apps from the
493         // concept of setting visibility...
494         if (!visible && hiddenRequested) {
495 
496             if (!deferHidingClient && mDeferHidingClient) {
497                 // We previously deferred telling the client to hide itself when visibility was
498                 // initially set to false. Now we would like it to hide, so go ahead and set it.
499                 mDeferHidingClient = deferHidingClient;
500                 setClientHidden(true);
501             }
502             return;
503         }
504 
505         if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) {
506             Slog.v(TAG_WM, "setAppVisibility("
507                     + appToken + ", visible=" + visible + "): " + appTransition
508                     + " hidden=" + isHidden() + " hiddenRequested="
509                     + hiddenRequested + " Callers=" + Debug.getCallers(6));
510         }
511 
512         final DisplayContent displayContent = getDisplayContent();
513         displayContent.mOpeningApps.remove(this);
514         displayContent.mClosingApps.remove(this);
515         if (isInChangeTransition()) {
516             clearChangeLeash(getPendingTransaction(), true /* cancel */);
517         }
518         displayContent.mChangingApps.remove(this);
519         waitingToShow = false;
520         hiddenRequested = !visible;
521         mDeferHidingClient = deferHidingClient;
522 
523         if (!visible) {
524             // If the app is dead while it was visible, we kept its dead window on screen.
525             // Now that the app is going invisible, we can remove it. It will be restarted
526             // if made visible again.
527             removeDeadWindows();
528         } else {
529             if (!appTransition.isTransitionSet()
530                     && appTransition.isReady()) {
531                 // Add the app mOpeningApps if transition is unset but ready. This means
532                 // we're doing a screen freeze, and the unfreeze will wait for all opening
533                 // apps to be ready.
534                 displayContent.mOpeningApps.add(this);
535             }
536             startingMoved = false;
537             // If the token is currently hidden (should be the common case), or has been
538             // stopped, then we need to set up to wait for its windows to be ready.
539             if (isHidden() || mAppStopped) {
540                 clearAllDrawn();
541 
542                 // If the app was already visible, don't reset the waitingToShow state.
543                 if (isHidden()) {
544                     waitingToShow = true;
545 
546                     // Let's reset the draw state in order to prevent the starting window to be
547                     // immediately dismissed when the app still has the surface.
548                     forAllWindows(w -> {
549                         if (w.mWinAnimator.mDrawState == HAS_DRAWN) {
550                             w.mWinAnimator.resetDrawState();
551 
552                             // Force add to mResizingWindows, so that we are guaranteed to get
553                             // another reportDrawn callback.
554                             w.resetLastContentInsets();
555                         }
556                     },  true /* traverseTopToBottom */);
557                 }
558             }
559 
560             // In the case where we are making an app visible but holding off for a transition,
561             // we still need to tell the client to make its windows visible so they get drawn.
562             // Otherwise, we will wait on performing the transition until all windows have been
563             // drawn, they never will be, and we are sad.
564             setClientHidden(false);
565 
566             requestUpdateWallpaperIfNeeded();
567 
568             if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + this);
569             mAppStopped = false;
570 
571             transferStartingWindowFromHiddenAboveTokenIfNeeded();
572         }
573 
574         // If we are preparing an app transition, then delay changing
575         // the visibility of this token until we execute that transition.
576         if (okToAnimate() && appTransition.isTransitionSet()) {
577             inPendingTransaction = true;
578             if (visible) {
579                 displayContent.mOpeningApps.add(this);
580                 mEnteringAnimation = true;
581             } else {
582                 displayContent.mClosingApps.add(this);
583                 mEnteringAnimation = false;
584             }
585             if (appTransition.getAppTransition()
586                     == WindowManager.TRANSIT_TASK_OPEN_BEHIND) {
587                 // We're launchingBehind, add the launching activity to mOpeningApps.
588                 final WindowState win = getDisplayContent().findFocusedWindow();
589                 if (win != null) {
590                     final AppWindowToken focusedToken = win.mAppToken;
591                     if (focusedToken != null) {
592                         if (DEBUG_APP_TRANSITIONS) {
593                             Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, "
594                                     + " adding " + focusedToken + " to mOpeningApps");
595                         }
596                         // Force animation to be loaded.
597                         focusedToken.setHidden(true);
598                         displayContent.mOpeningApps.add(focusedToken);
599                     }
600                 }
601             }
602             // Changes in opening apps and closing apps may cause orientation change.
603             reportDescendantOrientationChangeIfNeeded();
604             return;
605         }
606 
607         commitVisibility(null, visible, TRANSIT_UNSET, true, mVoiceInteraction);
608         updateReportedVisibilityLocked();
609     }
610 
commitVisibility(WindowManager.LayoutParams lp, boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction)611     boolean commitVisibility(WindowManager.LayoutParams lp,
612             boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction) {
613 
614         boolean delayed = false;
615         inPendingTransaction = false;
616         // Reset the state of mHiddenSetFromTransferredStartingWindow since visibility is actually
617         // been set by the app now.
618         mHiddenSetFromTransferredStartingWindow = false;
619 
620         // Allow for state changes and animation to be applied if:
621         // * token is transitioning visibility state
622         // * or the token was marked as hidden and is exiting before we had a chance to play the
623         // transition animation
624         // * or this is an opening app and windows are being replaced.
625         boolean visibilityChanged = false;
626         if (isHidden() == visible || (isHidden() && mIsExiting) || (visible && waitingForReplacement())) {
627             final AccessibilityController accessibilityController =
628                     mWmService.mAccessibilityController;
629             boolean changed = false;
630             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
631                     "Changing app " + this + " hidden=" + isHidden() + " performLayout=" + performLayout);
632 
633             boolean runningAppAnimation = false;
634 
635             if (transit != WindowManager.TRANSIT_UNSET) {
636                 if (mUseTransferredAnimation) {
637                     runningAppAnimation = isReallyAnimating();
638                 } else if (applyAnimationLocked(lp, transit, visible, isVoiceInteraction)) {
639                     runningAppAnimation = true;
640                 }
641                 delayed = runningAppAnimation;
642                 final WindowState window = findMainWindow();
643                 if (window != null && accessibilityController != null) {
644                     accessibilityController.onAppWindowTransitionLocked(window, transit);
645                 }
646                 changed = true;
647             }
648 
649             final int windowsCount = mChildren.size();
650             for (int i = 0; i < windowsCount; i++) {
651                 final WindowState win = mChildren.get(i);
652                 changed |= win.onAppVisibilityChanged(visible, runningAppAnimation);
653             }
654 
655             setHidden(!visible);
656             hiddenRequested = !visible;
657             visibilityChanged = true;
658             if (!visible) {
659                 stopFreezingScreen(true, true);
660             } else {
661                 // If we are being set visible, and the starting window is not yet displayed,
662                 // then make sure it doesn't get displayed.
663                 if (startingWindow != null && !startingWindow.isDrawnLw()) {
664                     startingWindow.clearPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY);
665                     startingWindow.mLegacyPolicyVisibilityAfterAnim = false;
666                 }
667 
668                 // We are becoming visible, so better freeze the screen with the windows that are
669                 // getting visible so we also wait for them.
670                 forAllWindows(mWmService::makeWindowFreezingScreenIfNeededLocked, true);
671             }
672 
673             if (DEBUG_APP_TRANSITIONS) {
674                 Slog.v(TAG_WM, "commitVisibility: " + this
675                         + ": hidden=" + isHidden() + " hiddenRequested=" + hiddenRequested);
676             }
677 
678             if (changed) {
679                 getDisplayContent().getInputMonitor().setUpdateInputWindowsNeededLw();
680                 if (performLayout) {
681                     mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
682                             false /*updateInputWindows*/);
683                     mWmService.mWindowPlacerLocked.performSurfacePlacement();
684                 }
685                 getDisplayContent().getInputMonitor().updateInputWindowsLw(false /*force*/);
686             }
687         }
688         mUseTransferredAnimation = false;
689 
690         if (isReallyAnimating()) {
691             delayed = true;
692         } else {
693 
694             // We aren't animating anything, but exiting windows rely on the animation finished
695             // callback being called in case the AppWindowToken was pretending to be animating,
696             // which we might have done because we were in closing/opening apps list.
697             onAnimationFinished();
698         }
699 
700         for (int i = mChildren.size() - 1; i >= 0 && !delayed; i--) {
701             if ((mChildren.get(i)).isSelfOrChildAnimating()) {
702                 delayed = true;
703             }
704         }
705 
706         if (visibilityChanged) {
707             if (visible && !delayed) {
708                 // The token was made immediately visible, there will be no entrance animation.
709                 // We need to inform the client the enter animation was finished.
710                 mEnteringAnimation = true;
711                 mWmService.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(
712                         token);
713             }
714 
715             // If we're becoming visible, immediately change client visibility as well. there seem
716             // to be some edge cases where we change our visibility but client visibility never gets
717             // updated.
718             // If we're becoming invisible, update the client visibility if we are not running an
719             // animation. Otherwise, we'll update client visibility in onAnimationFinished.
720             if (visible || !isReallyAnimating()) {
721                 setClientHidden(!visible);
722             }
723 
724             if (!getDisplayContent().mClosingApps.contains(this)
725                     && !getDisplayContent().mOpeningApps.contains(this)) {
726                 // The token is not closing nor opening, so even if there is an animation set, that
727                 // doesn't mean that it goes through the normal app transition cycle so we have
728                 // to inform the docked controller about visibility change.
729                 // TODO(multi-display): notify docked divider on all displays where visibility was
730                 // affected.
731                 getDisplayContent().getDockedDividerController().notifyAppVisibilityChanged();
732 
733                 // Take the screenshot before possibly hiding the WSA, otherwise the screenshot
734                 // will not be taken.
735                 mWmService.mTaskSnapshotController.notifyAppVisibilityChanged(this, visible);
736             }
737 
738             // If we are hidden but there is no delay needed we immediately
739             // apply the Surface transaction so that the ActivityManager
740             // can have some guarantee on the Surface state following
741             // setting the visibility. This captures cases like dismissing
742             // the docked or pinned stack where there is no app transition.
743             //
744             // In the case of a "Null" animation, there will be
745             // no animation but there will still be a transition set.
746             // We still need to delay hiding the surface such that it
747             // can be synchronized with showing the next surface in the transition.
748             if (isHidden() && !delayed && !getDisplayContent().mAppTransition.isTransitionSet()) {
749                 SurfaceControl.openTransaction();
750                 for (int i = mChildren.size() - 1; i >= 0; i--) {
751                     mChildren.get(i).mWinAnimator.hide("immediately hidden");
752                 }
753                 SurfaceControl.closeTransaction();
754             }
755 
756             // Visibility changes may cause orientation request change.
757             reportDescendantOrientationChangeIfNeeded();
758         }
759 
760         return delayed;
761     }
762 
reportDescendantOrientationChangeIfNeeded()763     private void reportDescendantOrientationChangeIfNeeded() {
764         // Orientation request is exposed only when we're visible. Therefore visibility change
765         // will change requested orientation. Notify upward the hierarchy ladder to adjust
766         // configuration. This is important to cases where activities with incompatible
767         // orientations launch, or user goes back from an activity of bi-orientation to an
768         // activity with specified orientation.
769         if (mActivityRecord.getRequestedConfigurationOrientation() == getConfiguration().orientation
770                 || getOrientationIgnoreVisibility() == SCREEN_ORIENTATION_UNSET) {
771             return;
772         }
773 
774         final IBinder freezeToken =
775                 mActivityRecord.mayFreezeScreenLocked(mActivityRecord.app)
776                         ? mActivityRecord.appToken : null;
777         onDescendantOrientationChanged(freezeToken, mActivityRecord);
778     }
779 
780     /**
781      * @return The to top most child window for which {@link LayoutParams#isFullscreen()} returns
782      *         true.
783      */
getTopFullscreenWindow()784     WindowState getTopFullscreenWindow() {
785         for (int i = mChildren.size() - 1; i >= 0; i--) {
786             final WindowState win = mChildren.get(i);
787             if (win != null && win.mAttrs.isFullscreen()) {
788                 return win;
789             }
790         }
791         return null;
792     }
793 
findMainWindow()794     WindowState findMainWindow() {
795         return findMainWindow(true);
796     }
797 
798     /**
799      * Finds the main window that either has type base application or application starting if
800      * requested.
801      *
802      * @param includeStartingApp Allow to search application-starting windows to also be returned.
803      * @return The main window of type base application or application starting if requested.
804      */
findMainWindow(boolean includeStartingApp)805     WindowState findMainWindow(boolean includeStartingApp) {
806         WindowState candidate = null;
807         for (int j = mChildren.size() - 1; j >= 0; --j) {
808             final WindowState win = mChildren.get(j);
809             final int type = win.mAttrs.type;
810             // No need to loop through child window as base application and starting types can't be
811             // child windows.
812             if (type == TYPE_BASE_APPLICATION
813                     || (includeStartingApp && type == TYPE_APPLICATION_STARTING)) {
814                 // In cases where there are multiple windows, we prefer the non-exiting window. This
815                 // happens for example when replacing windows during an activity relaunch. When
816                 // constructing the animation, we want the new window, not the exiting one.
817                 if (win.mAnimatingExit) {
818                     candidate = win;
819                 } else {
820                     return win;
821                 }
822             }
823         }
824         return candidate;
825     }
826 
windowsAreFocusable()827     boolean windowsAreFocusable() {
828         if (mTargetSdk < Build.VERSION_CODES.Q) {
829             final int pid = mActivityRecord != null
830                     ? (mActivityRecord.app != null ? mActivityRecord.app.getPid() : 0) : 0;
831             final AppWindowToken topFocusedAppOfMyProcess =
832                     mWmService.mRoot.mTopFocusedAppByProcess.get(pid);
833             if (topFocusedAppOfMyProcess != null && topFocusedAppOfMyProcess != this) {
834                 // For the apps below Q, there can be only one app which has the focused window per
835                 // process, because legacy apps may not be ready for a multi-focus system.
836                 return false;
837             }
838         }
839         return getWindowConfiguration().canReceiveKeys() || mAlwaysFocusable;
840     }
841 
842     @Override
isVisible()843     boolean isVisible() {
844         // If the app token isn't hidden then it is considered visible and there is no need to check
845         // its children windows to see if they are visible.
846         return !isHidden();
847     }
848 
849     @Override
removeImmediately()850     void removeImmediately() {
851         onRemovedFromDisplay();
852         if (mActivityRecord != null) {
853             mActivityRecord.unregisterConfigurationChangeListener(this);
854         }
855         super.removeImmediately();
856     }
857 
858     @Override
removeIfPossible()859     void removeIfPossible() {
860         mIsExiting = false;
861         removeAllWindowsIfPossible();
862         removeImmediately();
863     }
864 
865     @Override
checkCompleteDeferredRemoval()866     boolean checkCompleteDeferredRemoval() {
867         if (mIsExiting) {
868             removeIfPossible();
869         }
870         return super.checkCompleteDeferredRemoval();
871     }
872 
onRemovedFromDisplay()873     void onRemovedFromDisplay() {
874         if (mRemovingFromDisplay) {
875             return;
876         }
877         mRemovingFromDisplay = true;
878 
879         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app token: " + this);
880 
881         boolean delayed = commitVisibility(null, false, TRANSIT_UNSET, true, mVoiceInteraction);
882 
883         getDisplayContent().mOpeningApps.remove(this);
884         getDisplayContent().mChangingApps.remove(this);
885         getDisplayContent().mUnknownAppVisibilityController.appRemovedOrHidden(this);
886         mWmService.mTaskSnapshotController.onAppRemoved(this);
887         waitingToShow = false;
888         if (getDisplayContent().mClosingApps.contains(this)) {
889             delayed = true;
890         } else if (getDisplayContent().mAppTransition.isTransitionSet()) {
891             getDisplayContent().mClosingApps.add(this);
892             delayed = true;
893         }
894 
895         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app " + this + " delayed=" + delayed
896                 + " animation=" + getAnimation() + " animating=" + isSelfAnimating());
897 
898         if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM, "removeAppToken: "
899                 + this + " delayed=" + delayed + " Callers=" + Debug.getCallers(4));
900 
901         if (mStartingData != null) {
902             removeStartingWindow();
903         }
904 
905         // If this window was animating, then we need to ensure that the app transition notifies
906         // that animations have completed in DisplayContent.handleAnimatingStoppedAndTransition(),
907         // so add to that list now
908         if (isSelfAnimating()) {
909             getDisplayContent().mNoAnimationNotifyOnTransitionFinished.add(token);
910         }
911 
912         final TaskStack stack = getStack();
913         if (delayed && !isEmpty()) {
914             // set the token aside because it has an active animation to be finished
915             if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM,
916                     "removeAppToken make exiting: " + this);
917             if (stack != null) {
918                 stack.mExitingAppTokens.add(this);
919             }
920             mIsExiting = true;
921         } else {
922             // Make sure there is no animation running on this token, so any windows associated
923             // with it will be removed as soon as their animations are complete
924             cancelAnimation();
925             if (stack != null) {
926                 stack.mExitingAppTokens.remove(this);
927             }
928             removeIfPossible();
929         }
930 
931         removed = true;
932         stopFreezingScreen(true, true);
933 
934         final DisplayContent dc = getDisplayContent();
935         if (dc.mFocusedApp == this) {
936             if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Removing focused app token:" + this
937                    + " displayId=" + dc.getDisplayId());
938             dc.setFocusedApp(null);
939             mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
940         }
941         if (mLetterbox != null) {
942             mLetterbox.destroy();
943             mLetterbox = null;
944         }
945 
946         if (!delayed) {
947             updateReportedVisibilityLocked();
948         }
949 
950         mRemovingFromDisplay = false;
951     }
952 
clearAnimatingFlags()953     void clearAnimatingFlags() {
954         boolean wallpaperMightChange = false;
955         for (int i = mChildren.size() - 1; i >= 0; i--) {
956             final WindowState win = mChildren.get(i);
957             wallpaperMightChange |= win.clearAnimatingFlags();
958         }
959         if (wallpaperMightChange) {
960             requestUpdateWallpaperIfNeeded();
961         }
962     }
963 
destroySurfaces()964     void destroySurfaces() {
965         destroySurfaces(false /*cleanupOnResume*/);
966     }
967 
968     /**
969      * Destroy surfaces which have been marked as eligible by the animator, taking care to ensure
970      * the client has finished with them.
971      *
972      * @param cleanupOnResume whether this is done when app is resumed without fully stopped. If
973      * set to true, destroy only surfaces of removed windows, and clear relevant flags of the
974      * others so that they are ready to be reused. If set to false (common case), destroy all
975      * surfaces that's eligible, if the app is already stopped.
976      */
destroySurfaces(boolean cleanupOnResume)977     private void destroySurfaces(boolean cleanupOnResume) {
978         boolean destroyedSomething = false;
979 
980         // Copying to a different list as multiple children can be removed.
981         final ArrayList<WindowState> children = new ArrayList<>(mChildren);
982         for (int i = children.size() - 1; i >= 0; i--) {
983             final WindowState win = children.get(i);
984             destroyedSomething |= win.destroySurface(cleanupOnResume, mAppStopped);
985         }
986         if (destroyedSomething) {
987             final DisplayContent dc = getDisplayContent();
988             dc.assignWindowLayers(true /*setLayoutNeeded*/);
989             updateLetterboxSurface(null);
990         }
991     }
992 
993     /**
994      * Notify that the app is now resumed, and it was not stopped before, perform a clean
995      * up of the surfaces
996      */
notifyAppResumed(boolean wasStopped)997     void notifyAppResumed(boolean wasStopped) {
998         if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppResumed: wasStopped=" + wasStopped
999                 + " " + this);
1000         mAppStopped = false;
1001         // Allow the window to turn the screen on once the app is resumed again.
1002         setCanTurnScreenOn(true);
1003         if (!wasStopped) {
1004             destroySurfaces(true /*cleanupOnResume*/);
1005         }
1006     }
1007 
1008     /**
1009      * Notify that the app has stopped, and it is okay to destroy any surfaces which were
1010      * keeping alive in case they were still being used.
1011      */
notifyAppStopped()1012     void notifyAppStopped() {
1013         if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppStopped: " + this);
1014         mAppStopped = true;
1015         destroySurfaces();
1016         // Remove any starting window that was added for this app if they are still around.
1017         removeStartingWindow();
1018     }
1019 
clearAllDrawn()1020     void clearAllDrawn() {
1021         allDrawn = false;
1022         deferClearAllDrawn = false;
1023     }
1024 
getTask()1025     Task getTask() {
1026         return (Task) getParent();
1027     }
1028 
getStack()1029     TaskStack getStack() {
1030         final Task task = getTask();
1031         if (task != null) {
1032             return task.mStack;
1033         } else {
1034             return null;
1035         }
1036     }
1037 
1038     @Override
onParentChanged()1039     void onParentChanged() {
1040         super.onParentChanged();
1041 
1042         final Task task = getTask();
1043 
1044         // When the associated task is {@code null}, the {@link AppWindowToken} can no longer
1045         // access visual elements like the {@link DisplayContent}. We must remove any associations
1046         // such as animations.
1047         if (!mReparenting) {
1048             if (task == null) {
1049                 // It is possible we have been marked as a closing app earlier. We must remove ourselves
1050                 // from this list so we do not participate in any future animations.
1051                 getDisplayContent().mClosingApps.remove(this);
1052             } else if (mLastParent != null && mLastParent.mStack != null) {
1053                 task.mStack.mExitingAppTokens.remove(this);
1054             }
1055         }
1056         final TaskStack stack = getStack();
1057 
1058         // If we reparent, make sure to remove ourselves from the old animation registry.
1059         if (mAnimatingAppWindowTokenRegistry != null) {
1060             mAnimatingAppWindowTokenRegistry.notifyFinished(this);
1061         }
1062         mAnimatingAppWindowTokenRegistry = stack != null
1063                 ? stack.getAnimatingAppWindowTokenRegistry()
1064                 : null;
1065 
1066         mLastParent = task;
1067 
1068         updateColorTransform();
1069     }
1070 
postWindowRemoveStartingWindowCleanup(WindowState win)1071     void postWindowRemoveStartingWindowCleanup(WindowState win) {
1072         // TODO: Something smells about the code below...Is there a better way?
1073         if (startingWindow == win) {
1074             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Notify removed startingWindow " + win);
1075             removeStartingWindow();
1076         } else if (mChildren.size() == 0) {
1077             // If this is the last window and we had requested a starting transition window,
1078             // well there is no point now.
1079             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Nulling last startingData");
1080             mStartingData = null;
1081             if (mHiddenSetFromTransferredStartingWindow) {
1082                 // We set the hidden state to false for the token from a transferred starting window.
1083                 // We now reset it back to true since the starting window was the last window in the
1084                 // token.
1085                 setHidden(true);
1086             }
1087         } else if (mChildren.size() == 1 && startingSurface != null && !isRelaunching()) {
1088             // If this is the last window except for a starting transition window,
1089             // we need to get rid of the starting transition.
1090             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Last window, removing starting window "
1091                     + win);
1092             removeStartingWindow();
1093         }
1094     }
1095 
removeDeadWindows()1096     void removeDeadWindows() {
1097         for (int winNdx = mChildren.size() - 1; winNdx >= 0; --winNdx) {
1098             WindowState win = mChildren.get(winNdx);
1099             if (win.mAppDied) {
1100                 if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.w(TAG,
1101                         "removeDeadWindows: " + win);
1102                 // Set mDestroying, we don't want any animation or delayed removal here.
1103                 win.mDestroying = true;
1104                 // Also removes child windows.
1105                 win.removeIfPossible();
1106             }
1107         }
1108     }
1109 
hasWindowsAlive()1110     boolean hasWindowsAlive() {
1111         for (int i = mChildren.size() - 1; i >= 0; i--) {
1112             // No need to loop through child windows as the answer should be the same as that of the
1113             // parent window.
1114             if (!(mChildren.get(i)).mAppDied) {
1115                 return true;
1116             }
1117         }
1118         return false;
1119     }
1120 
setWillReplaceWindows(boolean animate)1121     void setWillReplaceWindows(boolean animate) {
1122         if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM,
1123                 "Marking app token " + this + " with replacing windows.");
1124 
1125         for (int i = mChildren.size() - 1; i >= 0; i--) {
1126             final WindowState w = mChildren.get(i);
1127             w.setWillReplaceWindow(animate);
1128         }
1129     }
1130 
setWillReplaceChildWindows()1131     void setWillReplaceChildWindows() {
1132         if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + this
1133                 + " with replacing child windows.");
1134         for (int i = mChildren.size() - 1; i >= 0; i--) {
1135             final WindowState w = mChildren.get(i);
1136             w.setWillReplaceChildWindows();
1137         }
1138     }
1139 
clearWillReplaceWindows()1140     void clearWillReplaceWindows() {
1141         if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM,
1142                 "Resetting app token " + this + " of replacing window marks.");
1143 
1144         for (int i = mChildren.size() - 1; i >= 0; i--) {
1145             final WindowState w = mChildren.get(i);
1146             w.clearWillReplaceWindow();
1147         }
1148     }
1149 
requestUpdateWallpaperIfNeeded()1150     void requestUpdateWallpaperIfNeeded() {
1151         for (int i = mChildren.size() - 1; i >= 0; i--) {
1152             final WindowState w = mChildren.get(i);
1153             w.requestUpdateWallpaperIfNeeded();
1154         }
1155     }
1156 
isRelaunching()1157     boolean isRelaunching() {
1158         return mPendingRelaunchCount > 0;
1159     }
1160 
shouldFreezeBounds()1161     boolean shouldFreezeBounds() {
1162         final Task task = getTask();
1163 
1164         // For freeform windows, we can't freeze the bounds at the moment because this would make
1165         // the resizing unresponsive.
1166         if (task == null || task.inFreeformWindowingMode()) {
1167             return false;
1168         }
1169 
1170         // We freeze the bounds while drag resizing to deal with the time between
1171         // the divider/drag handle being released, and the handling it's new
1172         // configuration. If we are relaunched outside of the drag resizing state,
1173         // we need to be careful not to do this.
1174         return getTask().isDragResizing();
1175     }
1176 
startRelaunching()1177     void startRelaunching() {
1178         if (shouldFreezeBounds()) {
1179             freezeBounds();
1180         }
1181 
1182         // In the process of tearing down before relaunching, the app will
1183         // try and clean up it's child surfaces. We need to prevent this from
1184         // happening, so we sever the children, transfering their ownership
1185         // from the client it-self to the parent surface (owned by us).
1186         detachChildren();
1187 
1188         mPendingRelaunchCount++;
1189     }
1190 
detachChildren()1191     void detachChildren() {
1192         SurfaceControl.openTransaction();
1193         for (int i = mChildren.size() - 1; i >= 0; i--) {
1194             final WindowState w = mChildren.get(i);
1195             w.mWinAnimator.detachChildren();
1196         }
1197         SurfaceControl.closeTransaction();
1198     }
1199 
finishRelaunching()1200     void finishRelaunching() {
1201         unfreezeBounds();
1202 
1203         if (mPendingRelaunchCount > 0) {
1204             mPendingRelaunchCount--;
1205         } else {
1206             // Update keyguard flags upon finishing relaunch.
1207             checkKeyguardFlagsChanged();
1208         }
1209     }
1210 
clearRelaunching()1211     void clearRelaunching() {
1212         if (mPendingRelaunchCount == 0) {
1213             return;
1214         }
1215         unfreezeBounds();
1216         mPendingRelaunchCount = 0;
1217     }
1218 
1219     /**
1220      * Returns true if the new child window we are adding to this token is considered greater than
1221      * the existing child window in this token in terms of z-order.
1222      */
1223     @Override
isFirstChildWindowGreaterThanSecond(WindowState newWindow, WindowState existingWindow)1224     protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow,
1225             WindowState existingWindow) {
1226         final int type1 = newWindow.mAttrs.type;
1227         final int type2 = existingWindow.mAttrs.type;
1228 
1229         // Base application windows should be z-ordered BELOW all other windows in the app token.
1230         if (type1 == TYPE_BASE_APPLICATION && type2 != TYPE_BASE_APPLICATION) {
1231             return false;
1232         } else if (type1 != TYPE_BASE_APPLICATION && type2 == TYPE_BASE_APPLICATION) {
1233             return true;
1234         }
1235 
1236         // Starting windows should be z-ordered ABOVE all other windows in the app token.
1237         if (type1 == TYPE_APPLICATION_STARTING && type2 != TYPE_APPLICATION_STARTING) {
1238             return true;
1239         } else if (type1 != TYPE_APPLICATION_STARTING && type2 == TYPE_APPLICATION_STARTING) {
1240             return false;
1241         }
1242 
1243         // Otherwise the new window is greater than the existing window.
1244         return true;
1245     }
1246 
1247     /**
1248      * @return {@code true} if starting window is in app's hierarchy.
1249      */
hasStartingWindow()1250     boolean hasStartingWindow() {
1251         if (startingDisplayed || mStartingData != null) {
1252             return true;
1253         }
1254         for (int i = mChildren.size() - 1; i >= 0; i--) {
1255             if (getChildAt(i).mAttrs.type == TYPE_APPLICATION_STARTING) {
1256                 return true;
1257             }
1258         }
1259         return false;
1260     }
1261 
1262     @Override
addWindow(WindowState w)1263     void addWindow(WindowState w) {
1264         super.addWindow(w);
1265 
1266         boolean gotReplacementWindow = false;
1267         for (int i = mChildren.size() - 1; i >= 0; i--) {
1268             final WindowState candidate = mChildren.get(i);
1269             gotReplacementWindow |= candidate.setReplacementWindowIfNeeded(w);
1270         }
1271 
1272         // if we got a replacement window, reset the timeout to give drawing more time
1273         if (gotReplacementWindow) {
1274             mWmService.scheduleWindowReplacementTimeouts(this);
1275         }
1276         checkKeyguardFlagsChanged();
1277     }
1278 
1279     @Override
removeChild(WindowState child)1280     void removeChild(WindowState child) {
1281         if (!mChildren.contains(child)) {
1282             // This can be true when testing.
1283             return;
1284         }
1285         super.removeChild(child);
1286         checkKeyguardFlagsChanged();
1287         updateLetterboxSurface(child);
1288     }
1289 
waitingForReplacement()1290     private boolean waitingForReplacement() {
1291         for (int i = mChildren.size() - 1; i >= 0; i--) {
1292             final WindowState candidate = mChildren.get(i);
1293             if (candidate.waitingForReplacement()) {
1294                 return true;
1295             }
1296         }
1297         return false;
1298     }
1299 
onWindowReplacementTimeout()1300     void onWindowReplacementTimeout() {
1301         for (int i = mChildren.size() - 1; i >= 0; --i) {
1302             (mChildren.get(i)).onWindowReplacementTimeout();
1303         }
1304     }
1305 
reparent(Task task, int position)1306     void reparent(Task task, int position) {
1307         if (DEBUG_ADD_REMOVE) {
1308             Slog.i(TAG_WM, "reparent: moving app token=" + this
1309                     + " to task=" + task.mTaskId + " at " + position);
1310         }
1311         if (task == null) {
1312             throw new IllegalArgumentException("reparent: could not find task");
1313         }
1314         final Task currentTask = getTask();
1315         if (task == currentTask) {
1316             throw new IllegalArgumentException(
1317                     "window token=" + this + " already child of task=" + currentTask);
1318         }
1319 
1320         if (currentTask.mStack != task.mStack) {
1321             throw new IllegalArgumentException(
1322                     "window token=" + this + " current task=" + currentTask
1323                         + " belongs to a different stack than " + task);
1324         }
1325 
1326         if (DEBUG_ADD_REMOVE) Slog.i(TAG, "reParentWindowToken: removing window token=" + this
1327                 + " from task=" + currentTask);
1328         final DisplayContent prevDisplayContent = getDisplayContent();
1329 
1330         mReparenting = true;
1331 
1332         getParent().removeChild(this);
1333         task.addChild(this, position);
1334 
1335         mReparenting = false;
1336 
1337         // Relayout display(s).
1338         final DisplayContent displayContent = task.getDisplayContent();
1339         displayContent.setLayoutNeeded();
1340         if (prevDisplayContent != displayContent) {
1341             onDisplayChanged(displayContent);
1342             prevDisplayContent.setLayoutNeeded();
1343         }
1344         getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
1345     }
1346 
1347     @Override
onDisplayChanged(DisplayContent dc)1348     void onDisplayChanged(DisplayContent dc) {
1349         DisplayContent prevDc = mDisplayContent;
1350         super.onDisplayChanged(dc);
1351         if (prevDc == null || prevDc == mDisplayContent) {
1352             return;
1353         }
1354 
1355         if (prevDc.mOpeningApps.remove(this)) {
1356             // Transfer opening transition to new display.
1357             mDisplayContent.mOpeningApps.add(this);
1358             mDisplayContent.prepareAppTransition(prevDc.mAppTransition.getAppTransition(), true);
1359             mDisplayContent.executeAppTransition();
1360         }
1361 
1362         if (prevDc.mChangingApps.remove(this)) {
1363             // This gets called *after* the AppWindowToken has been reparented to the new display.
1364             // That reparenting resulted in this window changing modes (eg. FREEFORM -> FULLSCREEN),
1365             // so this token is now "frozen" while waiting for the animation to start on prevDc
1366             // (which will be cancelled since the window is no-longer a child). However, since this
1367             // is no longer a child of prevDc, this won't be notified of the cancelled animation,
1368             // so we need to cancel the change transition here.
1369             clearChangeLeash(getPendingTransaction(), true /* cancel */);
1370         }
1371         prevDc.mClosingApps.remove(this);
1372 
1373         if (prevDc.mFocusedApp == this) {
1374             prevDc.setFocusedApp(null);
1375             final TaskStack stack = dc.getTopStack();
1376             if (stack != null) {
1377                 final Task task = stack.getTopChild();
1378                 if (task != null && task.getTopChild() == this) {
1379                     dc.setFocusedApp(this);
1380                 }
1381             }
1382         }
1383 
1384         if (mLetterbox != null) {
1385             mLetterbox.onMovedToDisplay(mDisplayContent.getDisplayId());
1386         }
1387     }
1388 
1389     /**
1390      * Freezes the task bounds. The size of this task reported the app will be fixed to the bounds
1391      * freezed by {@link Task#prepareFreezingBounds} until {@link #unfreezeBounds} gets called, even
1392      * if they change in the meantime. If the bounds are already frozen, the bounds will be frozen
1393      * with a queue.
1394      */
freezeBounds()1395     private void freezeBounds() {
1396         final Task task = getTask();
1397         mFrozenBounds.offer(new Rect(task.mPreparedFrozenBounds));
1398 
1399         if (task.mPreparedFrozenMergedConfig.equals(Configuration.EMPTY)) {
1400             // We didn't call prepareFreezingBounds on the task, so use the current value.
1401             mFrozenMergedConfig.offer(new Configuration(task.getConfiguration()));
1402         } else {
1403             mFrozenMergedConfig.offer(new Configuration(task.mPreparedFrozenMergedConfig));
1404         }
1405         // Calling unset() to make it equal to Configuration.EMPTY.
1406         task.mPreparedFrozenMergedConfig.unset();
1407     }
1408 
1409     /**
1410      * Unfreezes the previously frozen bounds. See {@link #freezeBounds}.
1411      */
unfreezeBounds()1412     private void unfreezeBounds() {
1413         if (mFrozenBounds.isEmpty()) {
1414             return;
1415         }
1416         mFrozenBounds.remove();
1417         if (!mFrozenMergedConfig.isEmpty()) {
1418             mFrozenMergedConfig.remove();
1419         }
1420         for (int i = mChildren.size() - 1; i >= 0; i--) {
1421             final WindowState win = mChildren.get(i);
1422             win.onUnfreezeBounds();
1423         }
1424         mWmService.mWindowPlacerLocked.performSurfacePlacement();
1425     }
1426 
setAppLayoutChanges(int changes, String reason)1427     void setAppLayoutChanges(int changes, String reason) {
1428         if (!mChildren.isEmpty()) {
1429             final DisplayContent dc = getDisplayContent();
1430             dc.pendingLayoutChanges |= changes;
1431             if (DEBUG_LAYOUT_REPEATS) {
1432                 mWmService.mWindowPlacerLocked.debugLayoutRepeats(reason, dc.pendingLayoutChanges);
1433             }
1434         }
1435     }
1436 
removeReplacedWindowIfNeeded(WindowState replacement)1437     void removeReplacedWindowIfNeeded(WindowState replacement) {
1438         for (int i = mChildren.size() - 1; i >= 0; i--) {
1439             final WindowState win = mChildren.get(i);
1440             if (win.removeReplacedWindowIfNeeded(replacement)) {
1441                 return;
1442             }
1443         }
1444     }
1445 
startFreezingScreen()1446     void startFreezingScreen() {
1447         if (DEBUG_ORIENTATION) logWithStack(TAG, "Set freezing of " + appToken + ": hidden="
1448                 + isHidden() + " freezing=" + mFreezingScreen + " hiddenRequested="
1449                 + hiddenRequested);
1450         if (!hiddenRequested) {
1451             if (!mFreezingScreen) {
1452                 mFreezingScreen = true;
1453                 mWmService.registerAppFreezeListener(this);
1454                 mWmService.mAppsFreezingScreen++;
1455                 if (mWmService.mAppsFreezingScreen == 1) {
1456                     mWmService.startFreezingDisplayLocked(0, 0, getDisplayContent());
1457                     mWmService.mH.removeMessages(H.APP_FREEZE_TIMEOUT);
1458                     mWmService.mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000);
1459                 }
1460             }
1461             final int count = mChildren.size();
1462             for (int i = 0; i < count; i++) {
1463                 final WindowState w = mChildren.get(i);
1464                 w.onStartFreezingScreen();
1465             }
1466         }
1467     }
1468 
stopFreezingScreen(boolean unfreezeSurfaceNow, boolean force)1469     void stopFreezingScreen(boolean unfreezeSurfaceNow, boolean force) {
1470         if (!mFreezingScreen) {
1471             return;
1472         }
1473         if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + this + " force=" + force);
1474         final int count = mChildren.size();
1475         boolean unfrozeWindows = false;
1476         for (int i = 0; i < count; i++) {
1477             final WindowState w = mChildren.get(i);
1478             unfrozeWindows |= w.onStopFreezingScreen();
1479         }
1480         if (force || unfrozeWindows) {
1481             if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "No longer freezing: " + this);
1482             mFreezingScreen = false;
1483             mWmService.unregisterAppFreezeListener(this);
1484             mWmService.mAppsFreezingScreen--;
1485             mWmService.mLastFinishedFreezeSource = this;
1486         }
1487         if (unfreezeSurfaceNow) {
1488             if (unfrozeWindows) {
1489                 mWmService.mWindowPlacerLocked.performSurfacePlacement();
1490             }
1491             mWmService.stopFreezingDisplayLocked();
1492         }
1493     }
1494 
1495     @Override
onAppFreezeTimeout()1496     public void onAppFreezeTimeout() {
1497         Slog.w(TAG_WM, "Force clearing freeze: " + this);
1498         stopFreezingScreen(true, true);
1499     }
1500 
1501     /**
1502      * Tries to transfer the starting window from a token that's above ourselves in the task but
1503      * not visible anymore. This is a common scenario apps use: Trampoline activity T start main
1504      * activity M in the same task. Now, when reopening the task, T starts on top of M but then
1505      * immediately finishes after, so we have to transfer T to M.
1506      */
transferStartingWindowFromHiddenAboveTokenIfNeeded()1507     void transferStartingWindowFromHiddenAboveTokenIfNeeded() {
1508         final Task task = getTask();
1509         for (int i = task.mChildren.size() - 1; i >= 0; i--) {
1510             final AppWindowToken fromToken = task.mChildren.get(i);
1511             if (fromToken == this) {
1512                 return;
1513             }
1514             if (fromToken.hiddenRequested && transferStartingWindow(fromToken.token)) {
1515                 return;
1516             }
1517         }
1518     }
1519 
transferStartingWindow(IBinder transferFrom)1520     boolean transferStartingWindow(IBinder transferFrom) {
1521         final AppWindowToken fromToken = getDisplayContent().getAppWindowToken(transferFrom);
1522         if (fromToken == null) {
1523             return false;
1524         }
1525 
1526         final WindowState tStartingWindow = fromToken.startingWindow;
1527         if (tStartingWindow != null && fromToken.startingSurface != null) {
1528             // In this case, the starting icon has already been displayed, so start
1529             // letting windows get shown immediately without any more transitions.
1530             getDisplayContent().mSkipAppTransitionAnimation = true;
1531 
1532             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Moving existing starting " + tStartingWindow
1533                     + " from " + fromToken + " to " + this);
1534 
1535             final long origId = Binder.clearCallingIdentity();
1536             try {
1537                 // Transfer the starting window over to the new token.
1538                 mStartingData = fromToken.mStartingData;
1539                 startingSurface = fromToken.startingSurface;
1540                 startingDisplayed = fromToken.startingDisplayed;
1541                 fromToken.startingDisplayed = false;
1542                 startingWindow = tStartingWindow;
1543                 reportedVisible = fromToken.reportedVisible;
1544                 fromToken.mStartingData = null;
1545                 fromToken.startingSurface = null;
1546                 fromToken.startingWindow = null;
1547                 fromToken.startingMoved = true;
1548                 tStartingWindow.mToken = this;
1549                 tStartingWindow.mAppToken = this;
1550 
1551                 if (DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
1552                         "Removing starting " + tStartingWindow + " from " + fromToken);
1553                 fromToken.removeChild(tStartingWindow);
1554                 fromToken.postWindowRemoveStartingWindowCleanup(tStartingWindow);
1555                 fromToken.mHiddenSetFromTransferredStartingWindow = false;
1556                 addWindow(tStartingWindow);
1557 
1558                 // Propagate other interesting state between the tokens. If the old token is displayed,
1559                 // we should immediately force the new one to be displayed. If it is animating, we need
1560                 // to move that animation to the new one.
1561                 if (fromToken.allDrawn) {
1562                     allDrawn = true;
1563                     deferClearAllDrawn = fromToken.deferClearAllDrawn;
1564                 }
1565                 if (fromToken.firstWindowDrawn) {
1566                     firstWindowDrawn = true;
1567                 }
1568                 if (!fromToken.isHidden()) {
1569                     setHidden(false);
1570                     hiddenRequested = false;
1571                     mHiddenSetFromTransferredStartingWindow = true;
1572                 }
1573                 setClientHidden(fromToken.mClientHidden);
1574 
1575                 transferAnimation(fromToken);
1576 
1577                 // When transferring an animation, we no longer need to apply an animation to the
1578                 // the token we transfer the animation over. Thus, set this flag to indicate we've
1579                 // transferred the animation.
1580                 mUseTransferredAnimation = true;
1581 
1582                 mWmService.updateFocusedWindowLocked(
1583                         UPDATE_FOCUS_WILL_PLACE_SURFACES, true /*updateInputWindows*/);
1584                 getDisplayContent().setLayoutNeeded();
1585                 mWmService.mWindowPlacerLocked.performSurfacePlacement();
1586             } finally {
1587                 Binder.restoreCallingIdentity(origId);
1588             }
1589             return true;
1590         } else if (fromToken.mStartingData != null) {
1591             // The previous app was getting ready to show a
1592             // starting window, but hasn't yet done so.  Steal it!
1593             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
1594                     "Moving pending starting from " + fromToken + " to " + this);
1595             mStartingData = fromToken.mStartingData;
1596             fromToken.mStartingData = null;
1597             fromToken.startingMoved = true;
1598             scheduleAddStartingWindow();
1599             return true;
1600         }
1601 
1602         // TODO: Transfer thumbnail
1603 
1604         return false;
1605     }
1606 
isLastWindow(WindowState win)1607     boolean isLastWindow(WindowState win) {
1608         return mChildren.size() == 1 && mChildren.get(0) == win;
1609     }
1610 
1611     @Override
onAppTransitionDone()1612     void onAppTransitionDone() {
1613         sendingToBottom = false;
1614     }
1615 
1616     /**
1617      * We override because this class doesn't want its children affecting its reported orientation
1618      * in anyway.
1619      */
1620     @Override
getOrientation(int candidate)1621     int getOrientation(int candidate) {
1622         if (candidate == SCREEN_ORIENTATION_BEHIND) {
1623             // Allow app to specify orientation regardless of its visibility state if the current
1624             // candidate want us to use orientation behind. I.e. the visible app on-top of this one
1625             // wants us to use the orientation of the app behind it.
1626             return mOrientation;
1627         }
1628 
1629         // The {@link AppWindowToken} should only specify an orientation when it is not closing or
1630         // going to the bottom. Allowing closing {@link AppWindowToken} to participate can lead to
1631         // an Activity in another task being started in the wrong orientation during the transition.
1632         if (!(sendingToBottom || getDisplayContent().mClosingApps.contains(this))
1633                 && (isVisible() || getDisplayContent().mOpeningApps.contains(this))) {
1634             return mOrientation;
1635         }
1636 
1637         return SCREEN_ORIENTATION_UNSET;
1638     }
1639 
1640     /** Returns the app's preferred orientation regardless of its currently visibility state. */
getOrientationIgnoreVisibility()1641     int getOrientationIgnoreVisibility() {
1642         return mOrientation;
1643     }
1644 
1645     /** @return {@code true} if the compatibility bounds is taking effect. */
inSizeCompatMode()1646     boolean inSizeCompatMode() {
1647         return mSizeCompatBounds != null;
1648     }
1649 
1650     @Override
getSizeCompatScale()1651     float getSizeCompatScale() {
1652         return inSizeCompatMode() ? mSizeCompatScale : super.getSizeCompatScale();
1653     }
1654 
1655     /**
1656      * @return Non-empty bounds if the activity has override bounds.
1657      * @see ActivityRecord#resolveOverrideConfiguration(Configuration)
1658      */
getResolvedOverrideBounds()1659     Rect getResolvedOverrideBounds() {
1660         // Get bounds from resolved override configuration because it is computed with orientation.
1661         return getResolvedOverrideConfiguration().windowConfiguration.getBounds();
1662     }
1663 
1664     @Override
onConfigurationChanged(Configuration newParentConfig)1665     public void onConfigurationChanged(Configuration newParentConfig) {
1666         final int prevWinMode = getWindowingMode();
1667         mTmpPrevBounds.set(getBounds());
1668         super.onConfigurationChanged(newParentConfig);
1669 
1670         final Task task = getTask();
1671         final Rect overrideBounds = getResolvedOverrideBounds();
1672         if (task != null && !overrideBounds.isEmpty()
1673                 // If the changes come from change-listener, the incoming parent configuration is
1674                 // still the old one. Make sure their orientations are the same to reduce computing
1675                 // the compatibility bounds for the intermediate state.
1676                 && (task.mTaskRecord == null || task.mTaskRecord
1677                         .getConfiguration().orientation == newParentConfig.orientation)) {
1678             final Rect taskBounds = task.getBounds();
1679             // Since we only center the activity horizontally, if only the fixed height is smaller
1680             // than its container, the override bounds don't need to take effect.
1681             if ((overrideBounds.width() != taskBounds.width()
1682                     || overrideBounds.height() > taskBounds.height())) {
1683                 calculateCompatBoundsTransformation(newParentConfig);
1684                 updateSurfacePosition();
1685             } else if (mSizeCompatBounds != null) {
1686                 mSizeCompatBounds = null;
1687                 mSizeCompatScale = 1f;
1688                 updateSurfacePosition();
1689             }
1690         }
1691 
1692         final int winMode = getWindowingMode();
1693 
1694         if (prevWinMode == winMode) {
1695             return;
1696         }
1697 
1698         if (prevWinMode != WINDOWING_MODE_UNDEFINED && winMode == WINDOWING_MODE_PINNED) {
1699             // Entering PiP from fullscreen, reset the snap fraction
1700             mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(this);
1701         } else if (prevWinMode == WINDOWING_MODE_PINNED && winMode != WINDOWING_MODE_UNDEFINED
1702                 && !isHidden()) {
1703             // Leaving PiP to fullscreen, save the snap fraction based on the pre-animation bounds
1704             // for the next re-entry into PiP (assuming the activity is not hidden or destroyed)
1705             final TaskStack pinnedStack = mDisplayContent.getPinnedStack();
1706             if (pinnedStack != null) {
1707                 final Rect stackBounds;
1708                 if (pinnedStack.lastAnimatingBoundsWasToFullscreen()) {
1709                     // We are animating the bounds, use the pre-animation bounds to save the snap
1710                     // fraction
1711                     stackBounds = pinnedStack.mPreAnimationBounds;
1712                 } else {
1713                     // We skip the animation if the fullscreen configuration is not compatible, so
1714                     // use the current bounds to calculate the saved snap fraction instead
1715                     // (see PinnedActivityStack.skipResizeAnimation())
1716                     stackBounds = mTmpRect;
1717                     pinnedStack.getBounds(stackBounds);
1718                 }
1719                 mDisplayContent.mPinnedStackControllerLocked.saveReentrySnapFraction(this,
1720                         stackBounds);
1721             }
1722         } else if (shouldStartChangeTransition(prevWinMode, winMode)) {
1723             initializeChangeTransition(mTmpPrevBounds);
1724         }
1725     }
1726 
shouldStartChangeTransition(int prevWinMode, int newWinMode)1727     private boolean shouldStartChangeTransition(int prevWinMode, int newWinMode) {
1728         if (mWmService.mDisableTransitionAnimation
1729                 || !isVisible()
1730                 || getDisplayContent().mAppTransition.isTransitionSet()
1731                 || getSurfaceControl() == null) {
1732             return false;
1733         }
1734         // Only do an animation into and out-of freeform mode for now. Other mode
1735         // transition animations are currently handled by system-ui.
1736         return (prevWinMode == WINDOWING_MODE_FREEFORM) != (newWinMode == WINDOWING_MODE_FREEFORM);
1737     }
1738 
1739     /**
1740      * Initializes a change transition. Because the app is visible already, there is a small period
1741      * of time where the user can see the app content/window update before the transition starts.
1742      * To prevent this, we immediately take a snapshot and place the app/snapshot into a leash which
1743      * "freezes" the location/crop until the transition starts.
1744      * <p>
1745      * Here's a walk-through of the process:
1746      * 1. Create a temporary leash ("interim-change-leash") and reparent the app to it.
1747      * 2. Set the temporary leash's position/crop to the current state.
1748      * 3. Create a snapshot and place that at the top of the leash to cover up content changes.
1749      * 4. Once the transition is ready, it will reparent the app to the animation leash.
1750      * 5. Detach the interim-change-leash.
1751      */
initializeChangeTransition(Rect startBounds)1752     private void initializeChangeTransition(Rect startBounds) {
1753         mDisplayContent.prepareAppTransition(TRANSIT_TASK_CHANGE_WINDOWING_MODE,
1754                 false /* alwaysKeepCurrent */, 0, false /* forceOverride */);
1755         mDisplayContent.mChangingApps.add(this);
1756         mTransitStartRect.set(startBounds);
1757 
1758         final SurfaceControl.Builder builder = makeAnimationLeash()
1759                 .setParent(getAnimationLeashParent())
1760                 .setName(getSurfaceControl() + " - interim-change-leash");
1761         mTransitChangeLeash = builder.build();
1762         Transaction t = getPendingTransaction();
1763         t.setWindowCrop(mTransitChangeLeash, startBounds.width(), startBounds.height());
1764         t.setPosition(mTransitChangeLeash, startBounds.left, startBounds.top);
1765         t.show(mTransitChangeLeash);
1766         t.reparent(getSurfaceControl(), mTransitChangeLeash);
1767         onAnimationLeashCreated(t, mTransitChangeLeash);
1768 
1769         // Skip creating snapshot if this transition is controlled by a remote animator which
1770         // doesn't need it.
1771         ArraySet<Integer> activityTypes = new ArraySet<>();
1772         activityTypes.add(getActivityType());
1773         RemoteAnimationAdapter adapter =
1774                 mDisplayContent.mAppTransitionController.getRemoteAnimationOverride(
1775                         this, TRANSIT_TASK_CHANGE_WINDOWING_MODE, activityTypes);
1776         if (adapter != null && !adapter.getChangeNeedsSnapshot()) {
1777             return;
1778         }
1779 
1780         Task task = getTask();
1781         if (mThumbnail == null && task != null && !hasCommittedReparentToAnimationLeash()) {
1782             SurfaceControl.ScreenshotGraphicBuffer snapshot =
1783                     mWmService.mTaskSnapshotController.createTaskSnapshot(
1784                             task, 1 /* scaleFraction */);
1785             if (snapshot != null) {
1786                 mThumbnail = new AppWindowThumbnail(t, this, snapshot.getGraphicBuffer(),
1787                         true /* relative */);
1788             }
1789         }
1790     }
1791 
isInChangeTransition()1792     boolean isInChangeTransition() {
1793         return mTransitChangeLeash != null || AppTransition.isChangeTransit(mTransit);
1794     }
1795 
1796     @VisibleForTesting
getThumbnail()1797     AppWindowThumbnail getThumbnail() {
1798         return mThumbnail;
1799     }
1800 
1801     /**
1802      * Calculates the scale and offset to horizontal center the size compatibility bounds into the
1803      * region which is available to application.
1804      */
calculateCompatBoundsTransformation(Configuration newParentConfig)1805     private void calculateCompatBoundsTransformation(Configuration newParentConfig) {
1806         final Rect parentAppBounds = newParentConfig.windowConfiguration.getAppBounds();
1807         final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
1808         final Rect viewportBounds = parentAppBounds != null ? parentAppBounds : parentBounds;
1809         final Rect appBounds = getWindowConfiguration().getAppBounds();
1810         final Rect contentBounds = appBounds != null ? appBounds : getResolvedOverrideBounds();
1811         final float contentW = contentBounds.width();
1812         final float contentH = contentBounds.height();
1813         final float viewportW = viewportBounds.width();
1814         final float viewportH = viewportBounds.height();
1815         // Only allow to scale down.
1816         mSizeCompatScale = (contentW <= viewportW && contentH <= viewportH)
1817                 ? 1 : Math.min(viewportW / contentW, viewportH / contentH);
1818         final int offsetX = (int) ((viewportW - contentW * mSizeCompatScale + 1) * 0.5f)
1819                 + viewportBounds.left;
1820 
1821         if (mSizeCompatBounds == null) {
1822             mSizeCompatBounds = new Rect();
1823         }
1824         mSizeCompatBounds.set(contentBounds);
1825         mSizeCompatBounds.offsetTo(0, 0);
1826         mSizeCompatBounds.scale(mSizeCompatScale);
1827         // Ensure to align the top with the parent.
1828         mSizeCompatBounds.top = parentBounds.top;
1829         // The decor inset is included in height.
1830         mSizeCompatBounds.bottom += viewportBounds.top;
1831         mSizeCompatBounds.left += offsetX;
1832         mSizeCompatBounds.right += offsetX;
1833     }
1834 
1835     @Override
getBounds()1836     public Rect getBounds() {
1837         if (mSizeCompatBounds != null) {
1838             return mSizeCompatBounds;
1839         }
1840         return super.getBounds();
1841     }
1842 
1843     @Override
matchParentBounds()1844     public boolean matchParentBounds() {
1845         if (super.matchParentBounds()) {
1846             return true;
1847         }
1848         // An activity in size compatibility mode may have override bounds which equals to its
1849         // parent bounds, so the exact bounds should also be checked.
1850         final WindowContainer parent = getParent();
1851         return parent == null || parent.getBounds().equals(getResolvedOverrideBounds());
1852     }
1853 
1854     @Override
checkAppWindowsReadyToShow()1855     void checkAppWindowsReadyToShow() {
1856         if (allDrawn == mLastAllDrawn) {
1857             return;
1858         }
1859 
1860         mLastAllDrawn = allDrawn;
1861         if (!allDrawn) {
1862             return;
1863         }
1864 
1865         // The token has now changed state to having all windows shown...  what to do, what to do?
1866         if (mFreezingScreen) {
1867             showAllWindowsLocked();
1868             stopFreezingScreen(false, true);
1869             if (DEBUG_ORIENTATION) Slog.i(TAG,
1870                     "Setting mOrientationChangeComplete=true because wtoken " + this
1871                     + " numInteresting=" + mNumInterestingWindows + " numDrawn=" + mNumDrawnWindows);
1872             // This will set mOrientationChangeComplete and cause a pass through layout.
1873             setAppLayoutChanges(FINISH_LAYOUT_REDO_WALLPAPER,
1874                     "checkAppWindowsReadyToShow: freezingScreen");
1875         } else {
1876             setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM, "checkAppWindowsReadyToShow");
1877 
1878             // We can now show all of the drawn windows!
1879             if (!getDisplayContent().mOpeningApps.contains(this) && canShowWindows()) {
1880                 showAllWindowsLocked();
1881             }
1882         }
1883     }
1884 
1885     /**
1886      * Returns whether the drawn window states of this {@link AppWindowToken} has considered every
1887      * child {@link WindowState}. A child is considered if it has been passed into
1888      * {@link #updateDrawnWindowStates(WindowState)} after being added. This is used to determine
1889      * whether states, such as {@code allDrawn}, can be set, which relies on state variables such as
1890      * {@code mNumInterestingWindows}, which depend on all {@link WindowState}s being considered.
1891      *
1892      * @return {@code true} If all children have been considered, {@code false}.
1893      */
allDrawnStatesConsidered()1894     private boolean allDrawnStatesConsidered() {
1895         for (int i = mChildren.size() - 1; i >= 0; --i) {
1896             final WindowState child = mChildren.get(i);
1897             if (child.mightAffectAllDrawn() && !child.getDrawnStateEvaluated()) {
1898                 return false;
1899             }
1900         }
1901         return true;
1902     }
1903 
1904     /**
1905      *  Determines if the token has finished drawing. This should only be called from
1906      *  {@link DisplayContent#applySurfaceChangesTransaction}
1907      */
updateAllDrawn()1908     void updateAllDrawn() {
1909         if (!allDrawn) {
1910             // Number of drawn windows can be less when a window is being relaunched, wait for
1911             // all windows to be launched and drawn for this token be considered all drawn.
1912             final int numInteresting = mNumInterestingWindows;
1913 
1914             // We must make sure that all present children have been considered (determined by
1915             // {@link #allDrawnStatesConsidered}) before evaluating whether everything has been
1916             // drawn.
1917             if (numInteresting > 0 && allDrawnStatesConsidered()
1918                     && mNumDrawnWindows >= numInteresting && !isRelaunching()) {
1919                 if (DEBUG_VISIBILITY) Slog.v(TAG, "allDrawn: " + this
1920                         + " interesting=" + numInteresting + " drawn=" + mNumDrawnWindows);
1921                 allDrawn = true;
1922                 // Force an additional layout pass where
1923                 // WindowStateAnimator#commitFinishDrawingLocked() will call performShowLocked().
1924                 if (mDisplayContent != null) {
1925                     mDisplayContent.setLayoutNeeded();
1926                 }
1927                 mWmService.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN, token).sendToTarget();
1928 
1929                 // Notify the pinned stack upon all windows drawn. If there was an animation in
1930                 // progress then this signal will resume that animation.
1931                 final TaskStack pinnedStack = mDisplayContent.getPinnedStack();
1932                 if (pinnedStack != null) {
1933                     pinnedStack.onAllWindowsDrawn();
1934                 }
1935             }
1936         }
1937     }
1938 
keyDispatchingTimedOut(String reason, int windowPid)1939     boolean keyDispatchingTimedOut(String reason, int windowPid) {
1940         return mActivityRecord != null && mActivityRecord.keyDispatchingTimedOut(reason, windowPid);
1941     }
1942 
1943     /**
1944      * Updated this app token tracking states for interesting and drawn windows based on the window.
1945      *
1946      * @return Returns true if the input window is considered interesting and drawn while all the
1947      *         windows in this app token where not considered drawn as of the last pass.
1948      */
updateDrawnWindowStates(WindowState w)1949     boolean updateDrawnWindowStates(WindowState w) {
1950         w.setDrawnStateEvaluated(true /*evaluated*/);
1951 
1952         if (DEBUG_STARTING_WINDOW_VERBOSE && w == startingWindow) {
1953             Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen=" + w.isOnScreen()
1954                     + " allDrawn=" + allDrawn + " freezingScreen=" + mFreezingScreen);
1955         }
1956 
1957         if (allDrawn && !mFreezingScreen) {
1958             return false;
1959         }
1960 
1961         if (mLastTransactionSequence != mWmService.mTransactionSequence) {
1962             mLastTransactionSequence = mWmService.mTransactionSequence;
1963             mNumDrawnWindows = 0;
1964             startingDisplayed = false;
1965 
1966             // There is the main base application window, even if it is exiting, wait for it
1967             mNumInterestingWindows = findMainWindow(false /* includeStartingApp */) != null ? 1 : 0;
1968         }
1969 
1970         final WindowStateAnimator winAnimator = w.mWinAnimator;
1971 
1972         boolean isInterestingAndDrawn = false;
1973 
1974         if (!allDrawn && w.mightAffectAllDrawn()) {
1975             if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
1976                 Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
1977                         + ", isAnimationSet=" + isSelfAnimating());
1978                 if (!w.isDrawnLw()) {
1979                     Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceController
1980                             + " pv=" + w.isVisibleByPolicy()
1981                             + " mDrawState=" + winAnimator.drawStateToString()
1982                             + " ph=" + w.isParentWindowHidden() + " th=" + hiddenRequested
1983                             + " a=" + isSelfAnimating());
1984                 }
1985             }
1986 
1987             if (w != startingWindow) {
1988                 if (w.isInteresting()) {
1989                     // Add non-main window as interesting since the main app has already been added
1990                     if (findMainWindow(false /* includeStartingApp */) != w) {
1991                         mNumInterestingWindows++;
1992                     }
1993                     if (w.isDrawnLw()) {
1994                         mNumDrawnWindows++;
1995 
1996                         if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG, "tokenMayBeDrawn: "
1997                                 + this + " w=" + w + " numInteresting=" + mNumInterestingWindows
1998                                 + " freezingScreen=" + mFreezingScreen
1999                                 + " mAppFreezing=" + w.mAppFreezing);
2000 
2001                         isInterestingAndDrawn = true;
2002                     }
2003                 }
2004             } else if (w.isDrawnLw()) {
2005                 if (mActivityRecord != null) {
2006                     mActivityRecord.onStartingWindowDrawn(SystemClock.uptimeMillis());
2007                 }
2008                 startingDisplayed = true;
2009             }
2010         }
2011 
2012         return isInterestingAndDrawn;
2013     }
2014 
layoutLetterbox(WindowState winHint)2015     void layoutLetterbox(WindowState winHint) {
2016         final WindowState w = findMainWindow();
2017         if (w == null || winHint != null && w != winHint) {
2018             return;
2019         }
2020         final boolean surfaceReady = w.isDrawnLw()  // Regular case
2021                 || w.mWinAnimator.mSurfaceDestroyDeferred  // The preserved surface is still ready.
2022                 || w.isDragResizeChanged();  // Waiting for relayoutWindow to call preserveSurface.
2023         final boolean needsLetterbox = surfaceReady && w.isLetterboxedAppWindow() && fillsParent();
2024         if (needsLetterbox) {
2025             if (mLetterbox == null) {
2026                 mLetterbox = new Letterbox(() -> makeChildSurface(null));
2027                 mLetterbox.attachInput(w);
2028             }
2029             getPosition(mTmpPoint);
2030             // Get the bounds of the "space-to-fill". In multi-window mode, the task-level
2031             // represents this. In fullscreen-mode, the stack does (since the orientation letterbox
2032             // is also applied to the task).
2033             Rect spaceToFill = (inMultiWindowMode() || getStack() == null)
2034                     ? getTask().getDisplayedBounds() : getStack().getDisplayedBounds();
2035             mLetterbox.layout(spaceToFill, w.getFrameLw(), mTmpPoint);
2036         } else if (mLetterbox != null) {
2037             mLetterbox.hide();
2038         }
2039     }
2040 
updateLetterboxSurface(WindowState winHint)2041     void updateLetterboxSurface(WindowState winHint) {
2042         final WindowState w = findMainWindow();
2043         if (w != winHint && winHint != null && w != null) {
2044             return;
2045         }
2046         layoutLetterbox(winHint);
2047         if (mLetterbox != null && mLetterbox.needsApplySurfaceChanges()) {
2048             mLetterbox.applySurfaceChanges(getPendingTransaction());
2049         }
2050     }
2051 
2052     @Override
forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom)2053     boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
2054         // For legacy reasons we process the TaskStack.mExitingAppTokens first in DisplayContent
2055         // before the non-exiting app tokens. So, we skip the exiting app tokens here.
2056         // TODO: Investigate if we need to continue to do this or if we can just process them
2057         // in-order.
2058         if (mIsExiting && !waitingForReplacement()) {
2059             return false;
2060         }
2061         return forAllWindowsUnchecked(callback, traverseTopToBottom);
2062     }
2063 
2064     @Override
forAllAppWindows(Consumer<AppWindowToken> callback)2065     void forAllAppWindows(Consumer<AppWindowToken> callback) {
2066         callback.accept(this);
2067     }
2068 
forAllWindowsUnchecked(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom)2069     boolean forAllWindowsUnchecked(ToBooleanFunction<WindowState> callback,
2070             boolean traverseTopToBottom) {
2071         return super.forAllWindows(callback, traverseTopToBottom);
2072     }
2073 
2074     @Override
asAppWindowToken()2075     AppWindowToken asAppWindowToken() {
2076         // I am an app window token!
2077         return this;
2078     }
2079 
addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents)2080     boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
2081             CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
2082             IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
2083             boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) {
2084         // If the display is frozen, we won't do anything until the actual window is
2085         // displayed so there is no reason to put in the starting window.
2086         if (!okToDisplay()) {
2087             return false;
2088         }
2089 
2090         if (mStartingData != null) {
2091             return false;
2092         }
2093 
2094         final WindowState mainWin = findMainWindow();
2095         if (mainWin != null && mainWin.mWinAnimator.getShown()) {
2096             // App already has a visible window...why would you want a starting window?
2097             return false;
2098         }
2099 
2100         final ActivityManager.TaskSnapshot snapshot =
2101                 mWmService.mTaskSnapshotController.getSnapshot(
2102                         getTask().mTaskId, getTask().mUserId,
2103                         false /* restoreFromDisk */, false /* reducedResolution */);
2104         final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
2105                 allowTaskSnapshot, activityCreated, fromRecents, snapshot);
2106 
2107         if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
2108             return createSnapshot(snapshot);
2109         }
2110 
2111         // If this is a translucent window, then don't show a starting window -- the current
2112         // effect (a full-screen opaque starting window that fades away to the real contents
2113         // when it is ready) does not work for this.
2114         if (DEBUG_STARTING_WINDOW) {
2115             Slog.v(TAG, "Checking theme of starting window: 0x" + Integer.toHexString(theme));
2116         }
2117         if (theme != 0) {
2118             AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
2119                     com.android.internal.R.styleable.Window,
2120                     mWmService.mCurrentUserId);
2121             if (ent == null) {
2122                 // Whoops!  App doesn't exist. Um. Okay. We'll just pretend like we didn't
2123                 // see that.
2124                 return false;
2125             }
2126             final boolean windowIsTranslucent = ent.array.getBoolean(
2127                     com.android.internal.R.styleable.Window_windowIsTranslucent, false);
2128             final boolean windowIsFloating = ent.array.getBoolean(
2129                     com.android.internal.R.styleable.Window_windowIsFloating, false);
2130             final boolean windowShowWallpaper = ent.array.getBoolean(
2131                     com.android.internal.R.styleable.Window_windowShowWallpaper, false);
2132             final boolean windowDisableStarting = ent.array.getBoolean(
2133                     com.android.internal.R.styleable.Window_windowDisablePreview, false);
2134             if (DEBUG_STARTING_WINDOW) {
2135                 Slog.v(TAG, "Translucent=" + windowIsTranslucent
2136                         + " Floating=" + windowIsFloating
2137                         + " ShowWallpaper=" + windowShowWallpaper);
2138             }
2139             if (windowIsTranslucent) {
2140                 return false;
2141             }
2142             if (windowIsFloating || windowDisableStarting) {
2143                 return false;
2144             }
2145             if (windowShowWallpaper) {
2146                 if (getDisplayContent().mWallpaperController
2147                         .getWallpaperTarget() == null) {
2148                     // If this theme is requesting a wallpaper, and the wallpaper
2149                     // is not currently visible, then this effectively serves as
2150                     // an opaque window and our starting window transition animation
2151                     // can still work.  We just need to make sure the starting window
2152                     // is also showing the wallpaper.
2153                     windowFlags |= FLAG_SHOW_WALLPAPER;
2154                 } else {
2155                     return false;
2156                 }
2157             }
2158         }
2159 
2160         if (transferStartingWindow(transferFrom)) {
2161             return true;
2162         }
2163 
2164         // There is no existing starting window, and we don't want to create a splash screen, so
2165         // that's it!
2166         if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
2167             return false;
2168         }
2169 
2170         if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SplashScreenStartingData");
2171         mStartingData = new SplashScreenStartingData(mWmService, pkg,
2172                 theme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
2173                 getMergedOverrideConfiguration());
2174         scheduleAddStartingWindow();
2175         return true;
2176     }
2177 
2178 
createSnapshot(ActivityManager.TaskSnapshot snapshot)2179     private boolean createSnapshot(ActivityManager.TaskSnapshot snapshot) {
2180         if (snapshot == null) {
2181             return false;
2182         }
2183 
2184         if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SnapshotStartingData");
2185         mStartingData = new SnapshotStartingData(mWmService, snapshot);
2186         scheduleAddStartingWindow();
2187         return true;
2188     }
2189 
scheduleAddStartingWindow()2190     void scheduleAddStartingWindow() {
2191         // Note: we really want to do sendMessageAtFrontOfQueue() because we
2192         // want to process the message ASAP, before any other queued
2193         // messages.
2194         if (!mWmService.mAnimationHandler.hasCallbacks(mAddStartingWindow)) {
2195             if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Enqueueing ADD_STARTING");
2196             mWmService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
2197         }
2198     }
2199 
2200     private final Runnable mAddStartingWindow = new Runnable() {
2201 
2202         @Override
2203         public void run() {
2204             // Can be accessed without holding the global lock
2205             final StartingData startingData;
2206             synchronized (mWmService.mGlobalLock) {
2207                 // There can only be one adding request, silly caller!
2208                 mWmService.mAnimationHandler.removeCallbacks(this);
2209 
2210                 if (mStartingData == null) {
2211                     // Animation has been canceled... do nothing.
2212                     if (DEBUG_STARTING_WINDOW) {
2213                         Slog.v(TAG, "startingData was nulled out before handling"
2214                                 + " mAddStartingWindow: " + AppWindowToken.this);
2215                     }
2216                     return;
2217                 }
2218                 startingData = mStartingData;
2219             }
2220 
2221             if (DEBUG_STARTING_WINDOW) {
2222                 Slog.v(TAG, "Add starting " + this + ": startingData=" + startingData);
2223             }
2224 
2225             WindowManagerPolicy.StartingSurface surface = null;
2226             try {
2227                 surface = startingData.createStartingSurface(AppWindowToken.this);
2228             } catch (Exception e) {
2229                 Slog.w(TAG, "Exception when adding starting window", e);
2230             }
2231             if (surface != null) {
2232                 boolean abort = false;
2233                 synchronized (mWmService.mGlobalLock) {
2234                     // If the window was successfully added, then
2235                     // we need to remove it.
2236                     if (removed || mStartingData == null) {
2237                         if (DEBUG_STARTING_WINDOW) {
2238                             Slog.v(TAG, "Aborted starting " + AppWindowToken.this
2239                                     + ": removed=" + removed + " startingData=" + mStartingData);
2240                         }
2241                         startingWindow = null;
2242                         mStartingData = null;
2243                         abort = true;
2244                     } else {
2245                         startingSurface = surface;
2246                     }
2247                     if (DEBUG_STARTING_WINDOW && !abort) {
2248                         Slog.v(TAG,
2249                                 "Added starting " + AppWindowToken.this + ": startingWindow="
2250                                         + startingWindow + " startingView=" + startingSurface);
2251                     }
2252                 }
2253                 if (abort) {
2254                     surface.remove();
2255                 }
2256             } else if (DEBUG_STARTING_WINDOW) {
2257                 Slog.v(TAG, "Surface returned was null: " + AppWindowToken.this);
2258             }
2259         }
2260     };
2261 
getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents, ActivityManager.TaskSnapshot snapshot)2262     private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
2263             boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents,
2264             ActivityManager.TaskSnapshot snapshot) {
2265         if (getDisplayContent().mAppTransition.getAppTransition()
2266                 == TRANSIT_DOCK_TASK_FROM_RECENTS) {
2267             // TODO(b/34099271): Remove this statement to add back the starting window and figure
2268             // out why it causes flickering, the starting window appears over the thumbnail while
2269             // the docked from recents transition occurs
2270             return STARTING_WINDOW_TYPE_NONE;
2271         } else if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
2272             return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
2273         } else if (taskSwitch && allowTaskSnapshot) {
2274             if (mWmService.mLowRamTaskSnapshotsAndRecents) {
2275                 // For low RAM devices, we use the splash screen starting window instead of the
2276                 // task snapshot starting window.
2277                 return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
2278             }
2279             return snapshot == null ? STARTING_WINDOW_TYPE_NONE
2280                     : snapshotOrientationSameAsTask(snapshot) || fromRecents
2281                             ? STARTING_WINDOW_TYPE_SNAPSHOT : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
2282         } else {
2283             return STARTING_WINDOW_TYPE_NONE;
2284         }
2285     }
2286 
2287 
snapshotOrientationSameAsTask(ActivityManager.TaskSnapshot snapshot)2288     private boolean snapshotOrientationSameAsTask(ActivityManager.TaskSnapshot snapshot) {
2289         if (snapshot == null) {
2290             return false;
2291         }
2292         return getTask().getConfiguration().orientation == snapshot.getOrientation();
2293     }
2294 
removeStartingWindow()2295     void removeStartingWindow() {
2296         if (startingWindow == null) {
2297             if (mStartingData != null) {
2298                 // Starting window has not been added yet, but it is scheduled to be added.
2299                 // Go ahead and cancel the request.
2300                 if (DEBUG_STARTING_WINDOW) {
2301                     Slog.v(TAG_WM, "Clearing startingData for token=" + this);
2302                 }
2303                 mStartingData = null;
2304             }
2305             return;
2306         }
2307 
2308         final WindowManagerPolicy.StartingSurface surface;
2309         if (mStartingData != null) {
2310             surface = startingSurface;
2311             mStartingData = null;
2312             startingSurface = null;
2313             startingWindow = null;
2314             startingDisplayed = false;
2315             if (surface == null) {
2316                 if (DEBUG_STARTING_WINDOW) {
2317                     Slog.v(TAG_WM, "startingWindow was set but startingSurface==null, couldn't "
2318                             + "remove");
2319                 }
2320                 return;
2321             }
2322         } else {
2323             if (DEBUG_STARTING_WINDOW) {
2324                 Slog.v(TAG_WM, "Tried to remove starting window but startingWindow was null:"
2325                         + this);
2326             }
2327             return;
2328         }
2329 
2330         if (DEBUG_STARTING_WINDOW) {
2331             Slog.v(TAG_WM, "Schedule remove starting " + this
2332                     + " startingWindow=" + startingWindow
2333                     + " startingView=" + startingSurface
2334                     + " Callers=" + Debug.getCallers(5));
2335         }
2336 
2337         // Use the same thread to remove the window as we used to add it, as otherwise we end up
2338         // with things in the view hierarchy being called from different threads.
2339         mWmService.mAnimationHandler.post(() -> {
2340             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Removing startingView=" + surface);
2341             try {
2342                 surface.remove();
2343             } catch (Exception e) {
2344                 Slog.w(TAG_WM, "Exception when removing starting window", e);
2345             }
2346         });
2347     }
2348 
2349     @Override
fillsParent()2350     boolean fillsParent() {
2351         return mFillsParent;
2352     }
2353 
setFillsParent(boolean fillsParent)2354     void setFillsParent(boolean fillsParent) {
2355         mFillsParent = fillsParent;
2356     }
2357 
containsDismissKeyguardWindow()2358     boolean containsDismissKeyguardWindow() {
2359         // Window state is transient during relaunch. We are not guaranteed to be frozen during the
2360         // entirety of the relaunch.
2361         if (isRelaunching()) {
2362             return mLastContainsDismissKeyguardWindow;
2363         }
2364 
2365         for (int i = mChildren.size() - 1; i >= 0; i--) {
2366             if ((mChildren.get(i).mAttrs.flags & FLAG_DISMISS_KEYGUARD) != 0) {
2367                 return true;
2368             }
2369         }
2370         return false;
2371     }
2372 
containsShowWhenLockedWindow()2373     boolean containsShowWhenLockedWindow() {
2374         // When we are relaunching, it is possible for us to be unfrozen before our previous
2375         // windows have been added back. Using the cached value ensures that our previous
2376         // showWhenLocked preference is honored until relaunching is complete.
2377         if (isRelaunching()) {
2378             return mLastContainsShowWhenLockedWindow;
2379         }
2380 
2381         for (int i = mChildren.size() - 1; i >= 0; i--) {
2382             if ((mChildren.get(i).mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
2383                 return true;
2384             }
2385         }
2386 
2387         return false;
2388     }
2389 
checkKeyguardFlagsChanged()2390     void checkKeyguardFlagsChanged() {
2391         final boolean containsDismissKeyguard = containsDismissKeyguardWindow();
2392         final boolean containsShowWhenLocked = containsShowWhenLockedWindow();
2393         if (containsDismissKeyguard != mLastContainsDismissKeyguardWindow
2394                 || containsShowWhenLocked != mLastContainsShowWhenLockedWindow) {
2395             mWmService.notifyKeyguardFlagsChanged(null /* callback */,
2396                     getDisplayContent().getDisplayId());
2397         }
2398         mLastContainsDismissKeyguardWindow = containsDismissKeyguard;
2399         mLastContainsShowWhenLockedWindow = containsShowWhenLocked;
2400     }
2401 
getImeTargetBelowWindow(WindowState w)2402     WindowState getImeTargetBelowWindow(WindowState w) {
2403         final int index = mChildren.indexOf(w);
2404         if (index > 0) {
2405             final WindowState target = mChildren.get(index - 1);
2406             if (target.canBeImeTarget()) {
2407                 return target;
2408             }
2409         }
2410         return null;
2411     }
2412 
getHighestAnimLayerWindow(WindowState currentTarget)2413     WindowState getHighestAnimLayerWindow(WindowState currentTarget) {
2414         WindowState candidate = null;
2415         for (int i = mChildren.indexOf(currentTarget); i >= 0; i--) {
2416             final WindowState w = mChildren.get(i);
2417             if (w.mRemoved) {
2418                 continue;
2419             }
2420             if (candidate == null) {
2421                 candidate = w;
2422             }
2423         }
2424         return candidate;
2425     }
2426 
2427     /**
2428      * See {@link Activity#setDisablePreviewScreenshots}.
2429      */
setDisablePreviewScreenshots(boolean disable)2430     void setDisablePreviewScreenshots(boolean disable) {
2431         mDisablePreviewScreenshots = disable;
2432     }
2433 
2434     /**
2435      * Sets whether the current launch can turn the screen on. See {@link #canTurnScreenOn()}
2436      */
setCanTurnScreenOn(boolean canTurnScreenOn)2437     void setCanTurnScreenOn(boolean canTurnScreenOn) {
2438         mCanTurnScreenOn = canTurnScreenOn;
2439     }
2440 
2441     /**
2442      * Indicates whether the current launch can turn the screen on. This is to prevent multiple
2443      * relayouts from turning the screen back on. The screen should only turn on at most
2444      * once per activity resume.
2445      *
2446      * @return true if the screen can be turned on.
2447      */
canTurnScreenOn()2448     boolean canTurnScreenOn() {
2449         return mCanTurnScreenOn;
2450     }
2451 
2452     /**
2453      * Retrieves whether we'd like to generate a snapshot that's based solely on the theme. This is
2454      * the case when preview screenshots are disabled {@link #setDisablePreviewScreenshots} or when
2455      * we can't take a snapshot for other reasons, for example, if we have a secure window.
2456      *
2457      * @return True if we need to generate an app theme snapshot, false if we'd like to take a real
2458      *         screenshot.
2459      */
shouldUseAppThemeSnapshot()2460     boolean shouldUseAppThemeSnapshot() {
2461         return mDisablePreviewScreenshots || forAllWindows(w -> (w.mAttrs.flags & FLAG_SECURE) != 0,
2462                 true /* topToBottom */);
2463     }
2464 
getAppAnimationLayer()2465     SurfaceControl getAppAnimationLayer() {
2466         return getAppAnimationLayer(isActivityTypeHome() ? ANIMATION_LAYER_HOME
2467                 : needsZBoost() ? ANIMATION_LAYER_BOOSTED
2468                 : ANIMATION_LAYER_STANDARD);
2469     }
2470 
2471     @Override
getAnimationLeashParent()2472     public SurfaceControl getAnimationLeashParent() {
2473         // All normal app transitions take place in an animation layer which is below the pinned
2474         // stack but may be above the parent stacks of the given animating apps.
2475         // For transitions in the pinned stack (menu activity) we just let them occur as a child
2476         // of the pinned stack.
2477         if (!inPinnedWindowingMode()) {
2478             return getAppAnimationLayer();
2479         } else {
2480             return getStack().getSurfaceControl();
2481         }
2482     }
2483 
2484 
2485     @VisibleForTesting
shouldAnimate(int transit)2486     boolean shouldAnimate(int transit) {
2487         final boolean isSplitScreenPrimary =
2488                 getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
2489         final boolean allowSplitScreenPrimaryAnimation = transit != TRANSIT_WALLPAPER_OPEN;
2490 
2491         // Don't animate while the task runs recents animation but only if we are in the mode
2492         // where we cancel with deferred screenshot, which means that the controller has
2493         // transformed the task.
2494         final RecentsAnimationController controller = mWmService.getRecentsAnimationController();
2495         if (controller != null && controller.isAnimatingTask(getTask())
2496                 && controller.shouldDeferCancelUntilNextTransition()) {
2497             return false;
2498         }
2499 
2500         // We animate always if it's not split screen primary, and only some special cases in split
2501         // screen primary because it causes issues with stack clipping when we run an un-minimize
2502         // animation at the same time.
2503         return !isSplitScreenPrimary || allowSplitScreenPrimaryAnimation;
2504     }
2505 
2506     /**
2507      * Creates a layer to apply crop to an animation.
2508      */
createAnimationBoundsLayer(Transaction t)2509     private SurfaceControl createAnimationBoundsLayer(Transaction t) {
2510         if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.i(TAG, "Creating animation bounds layer");
2511         final SurfaceControl.Builder builder = makeAnimationLeash()
2512                 .setParent(getAnimationLeashParent())
2513                 .setName(getSurfaceControl() + " - animation-bounds");
2514         final SurfaceControl boundsLayer = builder.build();
2515         t.show(boundsLayer);
2516         return boundsLayer;
2517     }
2518 
2519     @Override
getDisplayedBounds()2520     Rect getDisplayedBounds() {
2521         final Task task = getTask();
2522         if (task != null) {
2523             final Rect overrideDisplayedBounds = task.getOverrideDisplayedBounds();
2524             if (!overrideDisplayedBounds.isEmpty()) {
2525                 return overrideDisplayedBounds;
2526             }
2527         }
2528         return getBounds();
2529     }
2530 
2531     @VisibleForTesting
getAnimationBounds(int appStackClipMode)2532     Rect getAnimationBounds(int appStackClipMode) {
2533         if (appStackClipMode == STACK_CLIP_BEFORE_ANIM && getStack() != null) {
2534             // Using the stack bounds here effectively applies the clipping before animation.
2535             return getStack().getBounds();
2536         }
2537         // Use task-bounds if available so that activity-level letterbox (maxAspectRatio) is
2538         // included in the animation.
2539         return getTask() != null ? getTask().getBounds() : getBounds();
2540     }
2541 
applyAnimationLocked(WindowManager.LayoutParams lp, int transit, boolean enter, boolean isVoiceInteraction)2542     boolean applyAnimationLocked(WindowManager.LayoutParams lp, int transit, boolean enter,
2543             boolean isVoiceInteraction) {
2544 
2545         if (mWmService.mDisableTransitionAnimation || !shouldAnimate(transit)) {
2546             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
2547                 Slog.v(TAG_WM, "applyAnimation: transition animation is disabled or skipped."
2548                         + " atoken=" + this);
2549             }
2550             cancelAnimation();
2551             return false;
2552         }
2553 
2554         // Only apply an animation if the display isn't frozen. If it is frozen, there is no reason
2555         // to animate and it can cause strange artifacts when we unfreeze the display if some
2556         // different animation is running.
2557         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AWT#applyAnimationLocked");
2558         if (okToAnimate()) {
2559             final AnimationAdapter adapter;
2560             AnimationAdapter thumbnailAdapter = null;
2561 
2562             final int appStackClipMode =
2563                     getDisplayContent().mAppTransition.getAppStackClipMode();
2564 
2565             // Separate position and size for use in animators.
2566             mTmpRect.set(getAnimationBounds(appStackClipMode));
2567             mTmpPoint.set(mTmpRect.left, mTmpRect.top);
2568             mTmpRect.offsetTo(0, 0);
2569 
2570             final boolean isChanging = AppTransition.isChangeTransit(transit) && enter
2571                     && getDisplayContent().mChangingApps.contains(this);
2572 
2573             // Delaying animation start isn't compatible with remote animations at all.
2574             if (getDisplayContent().mAppTransition.getRemoteAnimationController() != null
2575                     && !mSurfaceAnimator.isAnimationStartDelayed()) {
2576                 RemoteAnimationRecord adapters =
2577                         getDisplayContent().mAppTransition.getRemoteAnimationController()
2578                                 .createRemoteAnimationRecord(this, mTmpPoint, mTmpRect,
2579                                         (isChanging ? mTransitStartRect : null));
2580                 adapter = adapters.mAdapter;
2581                 thumbnailAdapter = adapters.mThumbnailAdapter;
2582             } else if (isChanging) {
2583                 final float durationScale = mWmService.getTransitionAnimationScaleLocked();
2584                 mTmpRect.offsetTo(mTmpPoint.x, mTmpPoint.y);
2585                 adapter = new LocalAnimationAdapter(
2586                         new WindowChangeAnimationSpec(mTransitStartRect, mTmpRect,
2587                                 getDisplayContent().getDisplayInfo(), durationScale,
2588                                 true /* isAppAnimation */, false /* isThumbnail */),
2589                         mWmService.mSurfaceAnimationRunner);
2590                 if (mThumbnail != null) {
2591                     thumbnailAdapter = new LocalAnimationAdapter(
2592                             new WindowChangeAnimationSpec(mTransitStartRect, mTmpRect,
2593                                     getDisplayContent().getDisplayInfo(), durationScale,
2594                                     true /* isAppAnimation */, true /* isThumbnail */),
2595                             mWmService.mSurfaceAnimationRunner);
2596                 }
2597                 mTransit = transit;
2598                 mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags();
2599             } else {
2600                 mNeedsAnimationBoundsLayer = (appStackClipMode == STACK_CLIP_AFTER_ANIM);
2601 
2602                 final Animation a = loadAnimation(lp, transit, enter, isVoiceInteraction);
2603                 if (a != null) {
2604                     // Only apply corner radius to animation if we're not in multi window mode.
2605                     // We don't want rounded corners when in pip or split screen.
2606                     final float windowCornerRadius = !inMultiWindowMode()
2607                             ? getDisplayContent().getWindowCornerRadius()
2608                             : 0;
2609                     adapter = new LocalAnimationAdapter(
2610                             new WindowAnimationSpec(a, mTmpPoint, mTmpRect,
2611                                     getDisplayContent().mAppTransition.canSkipFirstFrame(),
2612                                     appStackClipMode,
2613                                     true /* isAppAnimation */,
2614                                     windowCornerRadius),
2615                             mWmService.mSurfaceAnimationRunner);
2616                     if (a.getZAdjustment() == Animation.ZORDER_TOP) {
2617                         mNeedsZBoost = true;
2618                     }
2619                     mTransit = transit;
2620                     mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags();
2621                 } else {
2622                     adapter = null;
2623                 }
2624             }
2625             if (adapter != null) {
2626                 startAnimation(getPendingTransaction(), adapter, !isVisible());
2627                 if (adapter.getShowWallpaper()) {
2628                     mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
2629                 }
2630                 if (thumbnailAdapter != null) {
2631                     mThumbnail.startAnimation(
2632                             getPendingTransaction(), thumbnailAdapter, !isVisible());
2633                 }
2634             }
2635         } else {
2636             cancelAnimation();
2637         }
2638         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
2639 
2640         return isReallyAnimating();
2641     }
2642 
loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, boolean isVoiceInteraction)2643     private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
2644             boolean isVoiceInteraction) {
2645         final DisplayContent displayContent = getTask().getDisplayContent();
2646         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
2647         final int width = displayInfo.appWidth;
2648         final int height = displayInfo.appHeight;
2649         if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG_WM,
2650                 "applyAnimation: atoken=" + this);
2651 
2652         // Determine the visible rect to calculate the thumbnail clip
2653         final WindowState win = findMainWindow();
2654         final Rect frame = new Rect(0, 0, width, height);
2655         final Rect displayFrame = new Rect(0, 0,
2656                 displayInfo.logicalWidth, displayInfo.logicalHeight);
2657         final Rect insets = new Rect();
2658         final Rect stableInsets = new Rect();
2659         Rect surfaceInsets = null;
2660         final boolean freeform = win != null && win.inFreeformWindowingMode();
2661         if (win != null) {
2662             // Containing frame will usually cover the whole screen, including dialog windows.
2663             // For freeform workspace windows it will not cover the whole screen and it also
2664             // won't exactly match the final freeform window frame (e.g. when overlapping with
2665             // the status bar). In that case we need to use the final frame.
2666             if (freeform) {
2667                 frame.set(win.getFrameLw());
2668             } else if (win.isLetterboxedAppWindow()) {
2669                 frame.set(getTask().getBounds());
2670             } else if (win.isDockedResizing()) {
2671                 // If we are animating while docked resizing, then use the stack bounds as the
2672                 // animation target (which will be different than the task bounds)
2673                 frame.set(getTask().getParent().getBounds());
2674             } else {
2675                 frame.set(win.getContainingFrame());
2676             }
2677             surfaceInsets = win.getAttrs().surfaceInsets;
2678             // XXX(b/72757033): These are insets relative to the window frame, but we're really
2679             // interested in the insets relative to the frame we chose in the if-blocks above.
2680             win.getContentInsets(insets);
2681             win.getStableInsets(stableInsets);
2682         }
2683 
2684         if (mLaunchTaskBehind) {
2685             // Differentiate the two animations. This one which is briefly on the screen
2686             // gets the !enter animation, and the other activity which remains on the
2687             // screen gets the enter animation. Both appear in the mOpeningApps set.
2688             enter = false;
2689         }
2690         if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "Loading animation for app transition."
2691                 + " transit=" + AppTransition.appTransitionToString(transit) + " enter=" + enter
2692                 + " frame=" + frame + " insets=" + insets + " surfaceInsets=" + surfaceInsets);
2693         final Configuration displayConfig = displayContent.getConfiguration();
2694         final Animation a = getDisplayContent().mAppTransition.loadAnimation(lp, transit, enter,
2695                 displayConfig.uiMode, displayConfig.orientation, frame, displayFrame, insets,
2696                 surfaceInsets, stableInsets, isVoiceInteraction, freeform, getTask().mTaskId);
2697         if (a != null) {
2698             if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + this);
2699             final int containingWidth = frame.width();
2700             final int containingHeight = frame.height();
2701             a.initialize(containingWidth, containingHeight, width, height);
2702             a.scaleCurrentDuration(mWmService.getTransitionAnimationScaleLocked());
2703         }
2704         return a;
2705     }
2706 
2707     @Override
shouldDeferAnimationFinish(Runnable endDeferFinishCallback)2708     public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
2709         return mAnimatingAppWindowTokenRegistry != null
2710                 && mAnimatingAppWindowTokenRegistry.notifyAboutToFinish(
2711                         this, endDeferFinishCallback);
2712     }
2713 
2714     @Override
onAnimationLeashLost(Transaction t)2715     public void onAnimationLeashLost(Transaction t) {
2716         super.onAnimationLeashLost(t);
2717         if (mAnimationBoundsLayer != null) {
2718             t.remove(mAnimationBoundsLayer);
2719             mAnimationBoundsLayer = null;
2720         }
2721 
2722         if (mAnimatingAppWindowTokenRegistry != null) {
2723             mAnimatingAppWindowTokenRegistry.notifyFinished(this);
2724         }
2725     }
2726 
2727     @Override
setLayer(Transaction t, int layer)2728     protected void setLayer(Transaction t, int layer) {
2729         if (!mSurfaceAnimator.hasLeash()) {
2730             t.setLayer(mSurfaceControl, layer);
2731         }
2732     }
2733 
2734     @Override
setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer)2735     protected void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
2736         if (!mSurfaceAnimator.hasLeash()) {
2737             t.setRelativeLayer(mSurfaceControl, relativeTo, layer);
2738         }
2739     }
2740 
2741     @Override
reparentSurfaceControl(Transaction t, SurfaceControl newParent)2742     protected void reparentSurfaceControl(Transaction t, SurfaceControl newParent) {
2743         if (!mSurfaceAnimator.hasLeash()) {
2744             t.reparent(mSurfaceControl, newParent);
2745         }
2746     }
2747 
2748     @Override
onAnimationLeashCreated(Transaction t, SurfaceControl leash)2749     public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
2750         // The leash is parented to the animation layer. We need to preserve the z-order by using
2751         // the prefix order index, but we boost if necessary.
2752         int layer = 0;
2753         if (!inPinnedWindowingMode()) {
2754             layer = getPrefixOrderIndex();
2755         } else {
2756             // Pinned stacks have animations take place within themselves rather than an animation
2757             // layer so we need to preserve the order relative to the stack (e.g. the order of our
2758             // task/parent).
2759             layer = getParent().getPrefixOrderIndex();
2760         }
2761 
2762         if (mNeedsZBoost) {
2763             layer += Z_BOOST_BASE;
2764         }
2765         if (!mNeedsAnimationBoundsLayer) {
2766             leash.setLayer(layer);
2767         }
2768 
2769         final DisplayContent dc = getDisplayContent();
2770         dc.assignStackOrdering();
2771 
2772         if (leash == mTransitChangeLeash) {
2773             // This is a temporary state so skip any animation notifications
2774             return;
2775         } else if (mTransitChangeLeash != null) {
2776             // unparent mTransitChangeLeash for clean-up
2777             clearChangeLeash(t, false /* cancel */);
2778         }
2779 
2780         if (mAnimatingAppWindowTokenRegistry != null) {
2781             mAnimatingAppWindowTokenRegistry.notifyStarting(this);
2782         }
2783 
2784         // If the animation needs to be cropped then an animation bounds layer is created as a child
2785         // of the pinned stack or animation layer. The leash is then reparented to this new layer.
2786         if (mNeedsAnimationBoundsLayer) {
2787             mTmpRect.setEmpty();
2788             final Task task = getTask();
2789             if (getDisplayContent().mAppTransitionController.isTransitWithinTask(
2790                     getTransit(), task)) {
2791                 task.getBounds(mTmpRect);
2792             } else {
2793                 final TaskStack stack = getStack();
2794                 if (stack == null) {
2795                     return;
2796                 }
2797                 // Set clip rect to stack bounds.
2798                 stack.getBounds(mTmpRect);
2799             }
2800             mAnimationBoundsLayer = createAnimationBoundsLayer(t);
2801 
2802             // Crop to stack bounds.
2803             t.setWindowCrop(mAnimationBoundsLayer, mTmpRect);
2804             t.setLayer(mAnimationBoundsLayer, layer);
2805 
2806             // Reparent leash to animation bounds layer.
2807             t.reparent(leash, mAnimationBoundsLayer);
2808         }
2809     }
2810 
2811     /**
2812      * This must be called while inside a transaction.
2813      */
showAllWindowsLocked()2814     void showAllWindowsLocked() {
2815         forAllWindows(windowState -> {
2816             if (DEBUG_VISIBILITY) Slog.v(TAG, "performing show on: " + windowState);
2817             windowState.performShowLocked();
2818         }, false /* traverseTopToBottom */);
2819     }
2820 
2821     @Override
onAnimationFinished()2822     protected void onAnimationFinished() {
2823         super.onAnimationFinished();
2824 
2825         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AWT#onAnimationFinished");
2826         mTransit = TRANSIT_UNSET;
2827         mTransitFlags = 0;
2828         mNeedsZBoost = false;
2829         mNeedsAnimationBoundsLayer = false;
2830 
2831         setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM | FINISH_LAYOUT_REDO_WALLPAPER,
2832                 "AppWindowToken");
2833 
2834         clearThumbnail();
2835         setClientHidden(isHidden() && hiddenRequested);
2836 
2837         getDisplayContent().computeImeTargetIfNeeded(this);
2838 
2839         if (DEBUG_ANIM) Slog.v(TAG, "Animation done in " + this
2840                 + ": reportedVisible=" + reportedVisible
2841                 + " okToDisplay=" + okToDisplay()
2842                 + " okToAnimate=" + okToAnimate()
2843                 + " startingDisplayed=" + startingDisplayed);
2844 
2845         // clean up thumbnail window
2846         if (mThumbnail != null) {
2847             mThumbnail.destroy();
2848             mThumbnail = null;
2849         }
2850 
2851         // WindowState.onExitAnimationDone might modify the children list, so make a copy and then
2852         // traverse the copy.
2853         final ArrayList<WindowState> children = new ArrayList<>(mChildren);
2854         children.forEach(WindowState::onExitAnimationDone);
2855 
2856         getDisplayContent().mAppTransition.notifyAppTransitionFinishedLocked(token);
2857         scheduleAnimation();
2858 
2859         mActivityRecord.onAnimationFinished();
2860         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
2861     }
2862 
2863     @Override
isAppAnimating()2864     boolean isAppAnimating() {
2865         return isSelfAnimating();
2866     }
2867 
2868     @Override
isSelfAnimating()2869     boolean isSelfAnimating() {
2870         // If we are about to start a transition, we also need to be considered animating.
2871         return isWaitingForTransitionStart() || isReallyAnimating();
2872     }
2873 
2874     /**
2875      * @return True if and only if we are actually running an animation. Note that
2876      *         {@link #isSelfAnimating} also returns true if we are waiting for an animation to
2877      *         start.
2878      */
isReallyAnimating()2879     private boolean isReallyAnimating() {
2880         return super.isSelfAnimating();
2881     }
2882 
2883     /**
2884      * @param cancel {@code true} if clearing the leash due to cancelling instead of transferring
2885      *                            to another leash.
2886      */
clearChangeLeash(Transaction t, boolean cancel)2887     private void clearChangeLeash(Transaction t, boolean cancel) {
2888         if (mTransitChangeLeash == null) {
2889             return;
2890         }
2891         if (cancel) {
2892             clearThumbnail();
2893             SurfaceControl sc = getSurfaceControl();
2894             SurfaceControl parentSc = getParentSurfaceControl();
2895             // Don't reparent if surface is getting destroyed
2896             if (parentSc != null && sc != null) {
2897                 t.reparent(sc, getParentSurfaceControl());
2898             }
2899         }
2900         t.hide(mTransitChangeLeash);
2901         t.remove(mTransitChangeLeash);
2902         mTransitChangeLeash = null;
2903         if (cancel) {
2904             onAnimationLeashLost(t);
2905         }
2906     }
2907 
2908     @Override
cancelAnimation()2909     void cancelAnimation() {
2910         cancelAnimationOnly();
2911         clearThumbnail();
2912         clearChangeLeash(getPendingTransaction(), true /* cancel */);
2913     }
2914 
2915     /**
2916      * This only cancels the animation. It doesn't do other teardown like cleaning-up thumbnail
2917      * or interim leashes.
2918      * <p>
2919      * Used when canceling in preparation for starting a new animation.
2920      */
cancelAnimationOnly()2921     void cancelAnimationOnly() {
2922         super.cancelAnimation();
2923     }
2924 
isWaitingForTransitionStart()2925     boolean isWaitingForTransitionStart() {
2926         return getDisplayContent().mAppTransition.isTransitionSet()
2927                 && (getDisplayContent().mOpeningApps.contains(this)
2928                     || getDisplayContent().mClosingApps.contains(this)
2929                     || getDisplayContent().mChangingApps.contains(this));
2930     }
2931 
getTransit()2932     public int getTransit() {
2933         return mTransit;
2934     }
2935 
getTransitFlags()2936     int getTransitFlags() {
2937         return mTransitFlags;
2938     }
2939 
attachThumbnailAnimation()2940     void attachThumbnailAnimation() {
2941         if (!isReallyAnimating()) {
2942             return;
2943         }
2944         final int taskId = getTask().mTaskId;
2945         final GraphicBuffer thumbnailHeader =
2946                 getDisplayContent().mAppTransition.getAppTransitionThumbnailHeader(taskId);
2947         if (thumbnailHeader == null) {
2948             if (DEBUG_APP_TRANSITIONS) Slog.d(TAG, "No thumbnail header bitmap for: " + taskId);
2949             return;
2950         }
2951         clearThumbnail();
2952         mThumbnail = new AppWindowThumbnail(getPendingTransaction(), this, thumbnailHeader);
2953         mThumbnail.startAnimation(getPendingTransaction(), loadThumbnailAnimation(thumbnailHeader));
2954     }
2955 
2956     /**
2957      * Attaches a surface with a thumbnail for the
2958      * {@link android.app.ActivityOptions#ANIM_OPEN_CROSS_PROFILE_APPS} animation.
2959      */
attachCrossProfileAppsThumbnailAnimation()2960     void attachCrossProfileAppsThumbnailAnimation() {
2961         if (!isReallyAnimating()) {
2962             return;
2963         }
2964         clearThumbnail();
2965 
2966         final WindowState win = findMainWindow();
2967         if (win == null) {
2968             return;
2969         }
2970         final Rect frame = win.getFrameLw();
2971         final int thumbnailDrawableRes = getTask().mUserId == mWmService.mCurrentUserId
2972                 ? R.drawable.ic_account_circle
2973                 : R.drawable.ic_corp_badge;
2974         final GraphicBuffer thumbnail =
2975                 getDisplayContent().mAppTransition
2976                         .createCrossProfileAppsThumbnail(thumbnailDrawableRes, frame);
2977         if (thumbnail == null) {
2978             return;
2979         }
2980         mThumbnail = new AppWindowThumbnail(getPendingTransaction(), this, thumbnail);
2981         final Animation animation =
2982                 getDisplayContent().mAppTransition.createCrossProfileAppsThumbnailAnimationLocked(
2983                         win.getFrameLw());
2984         mThumbnail.startAnimation(getPendingTransaction(), animation, new Point(frame.left,
2985                 frame.top));
2986     }
2987 
loadThumbnailAnimation(GraphicBuffer thumbnailHeader)2988     private Animation loadThumbnailAnimation(GraphicBuffer thumbnailHeader) {
2989         final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
2990 
2991         // If this is a multi-window scenario, we use the windows frame as
2992         // destination of the thumbnail header animation. If this is a full screen
2993         // window scenario, we use the whole display as the target.
2994         WindowState win = findMainWindow();
2995         Rect appRect = win != null ? win.getContentFrameLw() :
2996                 new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight);
2997         final Rect insets = win != null ? win.getContentInsets() : null;
2998         final Configuration displayConfig = mDisplayContent.getConfiguration();
2999         return getDisplayContent().mAppTransition.createThumbnailAspectScaleAnimationLocked(
3000                 appRect, insets, thumbnailHeader, getTask().mTaskId, displayConfig.uiMode,
3001                 displayConfig.orientation);
3002     }
3003 
clearThumbnail()3004     private void clearThumbnail() {
3005         if (mThumbnail == null) {
3006             return;
3007         }
3008         mThumbnail.destroy();
3009         mThumbnail = null;
3010     }
3011 
registerRemoteAnimations(RemoteAnimationDefinition definition)3012     void registerRemoteAnimations(RemoteAnimationDefinition definition) {
3013         mRemoteAnimationDefinition = definition;
3014     }
3015 
getRemoteAnimationDefinition()3016     RemoteAnimationDefinition getRemoteAnimationDefinition() {
3017         return mRemoteAnimationDefinition;
3018     }
3019 
3020     @Override
dump(PrintWriter pw, String prefix, boolean dumpAll)3021     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
3022         super.dump(pw, prefix, dumpAll);
3023         if (appToken != null) {
3024             pw.println(prefix + "app=true mVoiceInteraction=" + mVoiceInteraction);
3025         }
3026         pw.println(prefix + "component=" + mActivityComponent.flattenToShortString());
3027         pw.print(prefix); pw.print("task="); pw.println(getTask());
3028         pw.print(prefix); pw.print(" mFillsParent="); pw.print(mFillsParent);
3029                 pw.print(" mOrientation="); pw.println(mOrientation);
3030         pw.println(prefix + "hiddenRequested=" + hiddenRequested + " mClientHidden=" + mClientHidden
3031             + ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "")
3032             + " reportedDrawn=" + reportedDrawn + " reportedVisible=" + reportedVisible);
3033         if (paused) {
3034             pw.print(prefix); pw.print("paused="); pw.println(paused);
3035         }
3036         if (mAppStopped) {
3037             pw.print(prefix); pw.print("mAppStopped="); pw.println(mAppStopped);
3038         }
3039         if (mNumInterestingWindows != 0 || mNumDrawnWindows != 0
3040                 || allDrawn || mLastAllDrawn) {
3041             pw.print(prefix); pw.print("mNumInterestingWindows=");
3042                     pw.print(mNumInterestingWindows);
3043                     pw.print(" mNumDrawnWindows="); pw.print(mNumDrawnWindows);
3044                     pw.print(" inPendingTransaction="); pw.print(inPendingTransaction);
3045                     pw.print(" allDrawn="); pw.print(allDrawn);
3046                     pw.print(" lastAllDrawn="); pw.print(mLastAllDrawn);
3047                     pw.println(")");
3048         }
3049         if (inPendingTransaction) {
3050             pw.print(prefix); pw.print("inPendingTransaction=");
3051                     pw.println(inPendingTransaction);
3052         }
3053         if (mStartingData != null || removed || firstWindowDrawn || mIsExiting) {
3054             pw.print(prefix); pw.print("startingData="); pw.print(mStartingData);
3055                     pw.print(" removed="); pw.print(removed);
3056                     pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn);
3057                     pw.print(" mIsExiting="); pw.println(mIsExiting);
3058         }
3059         if (startingWindow != null || startingSurface != null
3060                 || startingDisplayed || startingMoved || mHiddenSetFromTransferredStartingWindow) {
3061             pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow);
3062                     pw.print(" startingSurface="); pw.print(startingSurface);
3063                     pw.print(" startingDisplayed="); pw.print(startingDisplayed);
3064                     pw.print(" startingMoved="); pw.print(startingMoved);
3065                     pw.println(" mHiddenSetFromTransferredStartingWindow="
3066                             + mHiddenSetFromTransferredStartingWindow);
3067         }
3068         if (!mFrozenBounds.isEmpty()) {
3069             pw.print(prefix); pw.print("mFrozenBounds="); pw.println(mFrozenBounds);
3070             pw.print(prefix); pw.print("mFrozenMergedConfig="); pw.println(mFrozenMergedConfig);
3071         }
3072         if (mPendingRelaunchCount != 0) {
3073             pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount);
3074         }
3075         if (mSizeCompatScale != 1f || mSizeCompatBounds != null) {
3076             pw.println(prefix + "mSizeCompatScale=" + mSizeCompatScale + " mSizeCompatBounds="
3077                     + mSizeCompatBounds);
3078         }
3079         if (mRemovingFromDisplay) {
3080             pw.println(prefix + "mRemovingFromDisplay=" + mRemovingFromDisplay);
3081         }
3082     }
3083 
3084     @Override
setHidden(boolean hidden)3085     void setHidden(boolean hidden) {
3086         super.setHidden(hidden);
3087 
3088         if (hidden) {
3089             // Once the app window is hidden, reset the last saved PiP snap fraction
3090             mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(this);
3091         }
3092         scheduleAnimation();
3093     }
3094 
3095     @Override
prepareSurfaces()3096     void prepareSurfaces() {
3097         // isSelfAnimating also returns true when we are about to start a transition, so we need
3098         // to check super here.
3099         final boolean reallyAnimating = super.isSelfAnimating();
3100         final boolean show = !isHidden() || reallyAnimating;
3101 
3102         if (mSurfaceControl != null) {
3103             if (show && !mLastSurfaceShowing) {
3104                 getPendingTransaction().show(mSurfaceControl);
3105             } else if (!show && mLastSurfaceShowing) {
3106                 getPendingTransaction().hide(mSurfaceControl);
3107             }
3108         }
3109         if (mThumbnail != null) {
3110             mThumbnail.setShowing(getPendingTransaction(), show);
3111         }
3112         mLastSurfaceShowing = show;
3113         super.prepareSurfaces();
3114     }
3115 
3116     /**
3117      * @return Whether our {@link #getSurfaceControl} is currently showing.
3118      */
isSurfaceShowing()3119     boolean isSurfaceShowing() {
3120         return mLastSurfaceShowing;
3121     }
3122 
isFreezingScreen()3123     boolean isFreezingScreen() {
3124         return mFreezingScreen;
3125     }
3126 
3127     @Override
needsZBoost()3128     boolean needsZBoost() {
3129         return mNeedsZBoost || super.needsZBoost();
3130     }
3131 
3132     @CallSuper
3133     @Override
writeToProto(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel)3134     public void writeToProto(ProtoOutputStream proto, long fieldId,
3135             @WindowTraceLogLevel int logLevel) {
3136         // Critical log level logs only visible elements to mitigate performance overheard
3137         if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
3138             return;
3139         }
3140 
3141         final long token = proto.start(fieldId);
3142         writeNameToProto(proto, NAME);
3143         super.writeToProto(proto, WINDOW_TOKEN, logLevel);
3144         proto.write(LAST_SURFACE_SHOWING, mLastSurfaceShowing);
3145         proto.write(IS_WAITING_FOR_TRANSITION_START, isWaitingForTransitionStart());
3146         proto.write(IS_REALLY_ANIMATING, isReallyAnimating());
3147         if (mThumbnail != null){
3148             mThumbnail.writeToProto(proto, THUMBNAIL);
3149         }
3150         proto.write(FILLS_PARENT, mFillsParent);
3151         proto.write(APP_STOPPED, mAppStopped);
3152         proto.write(HIDDEN_REQUESTED, hiddenRequested);
3153         proto.write(CLIENT_HIDDEN, mClientHidden);
3154         proto.write(DEFER_HIDING_CLIENT, mDeferHidingClient);
3155         proto.write(REPORTED_DRAWN, reportedDrawn);
3156         proto.write(REPORTED_VISIBLE, reportedVisible);
3157         proto.write(NUM_INTERESTING_WINDOWS, mNumInterestingWindows);
3158         proto.write(NUM_DRAWN_WINDOWS, mNumDrawnWindows);
3159         proto.write(ALL_DRAWN, allDrawn);
3160         proto.write(LAST_ALL_DRAWN, mLastAllDrawn);
3161         proto.write(REMOVED, removed);
3162         if (startingWindow != null) {
3163             startingWindow.writeIdentifierToProto(proto, STARTING_WINDOW);
3164         }
3165         proto.write(STARTING_DISPLAYED, startingDisplayed);
3166         proto.write(STARTING_MOVED, startingMoved);
3167         proto.write(HIDDEN_SET_FROM_TRANSFERRED_STARTING_WINDOW,
3168                 mHiddenSetFromTransferredStartingWindow);
3169         for (Rect bounds : mFrozenBounds) {
3170             bounds.writeToProto(proto, FROZEN_BOUNDS);
3171         }
3172         proto.end(token);
3173     }
3174 
writeNameToProto(ProtoOutputStream proto, long fieldId)3175     void writeNameToProto(ProtoOutputStream proto, long fieldId) {
3176         if (appToken == null) {
3177             return;
3178         }
3179         try {
3180             proto.write(fieldId, appToken.getName());
3181         } catch (RemoteException e) {
3182             // This shouldn't happen, but in this case fall back to outputting nothing
3183             Slog.e(TAG, e.toString());
3184         }
3185     }
3186 
3187     @Override
toString()3188     public String toString() {
3189         if (stringName == null) {
3190             StringBuilder sb = new StringBuilder();
3191             sb.append("AppWindowToken{");
3192             sb.append(Integer.toHexString(System.identityHashCode(this)));
3193             sb.append(" token="); sb.append(token); sb.append('}');
3194             stringName = sb.toString();
3195         }
3196         return stringName + ((mIsExiting) ? " mIsExiting=" : "");
3197     }
3198 
getLetterboxInsets()3199     Rect getLetterboxInsets() {
3200         if (mLetterbox != null) {
3201             return mLetterbox.getInsets();
3202         } else {
3203             return new Rect();
3204         }
3205     }
3206 
3207     /** Gets the inner bounds of letterbox. The bounds will be empty if there is no letterbox. */
getLetterboxInnerBounds(Rect outBounds)3208     void getLetterboxInnerBounds(Rect outBounds) {
3209         if (mLetterbox != null) {
3210             outBounds.set(mLetterbox.getInnerFrame());
3211         } else {
3212             outBounds.setEmpty();
3213         }
3214     }
3215 
3216     /**
3217      * @return {@code true} if there is a letterbox and any part of that letterbox overlaps with
3218      * the given {@code rect}.
3219      */
isLetterboxOverlappingWith(Rect rect)3220     boolean isLetterboxOverlappingWith(Rect rect) {
3221         return mLetterbox != null && mLetterbox.isOverlappingWith(rect);
3222     }
3223 
3224     /**
3225      * Sets if this AWT is in the process of closing or entering PIP.
3226      * {@link #mWillCloseOrEnterPip}}
3227      */
setWillCloseOrEnterPip(boolean willCloseOrEnterPip)3228     void setWillCloseOrEnterPip(boolean willCloseOrEnterPip) {
3229         mWillCloseOrEnterPip = willCloseOrEnterPip;
3230     }
3231 
3232     /**
3233      * Returns whether this AWT is considered closing. Conditions are either
3234      * 1. Is this app animating and was requested to be hidden
3235      * 2. App is delayed closing since it might enter PIP.
3236      */
isClosingOrEnteringPip()3237     boolean isClosingOrEnteringPip() {
3238         return (isAnimating() && hiddenRequested) || mWillCloseOrEnterPip;
3239     }
3240 
3241     /**
3242      * @return Whether we are allowed to show non-starting windows at the moment. We disallow
3243      *         showing windows during transitions in case we have windows that have wide-color-gamut
3244      *         color mode set to avoid jank in the middle of the transition.
3245      */
canShowWindows()3246     boolean canShowWindows() {
3247         return allDrawn && !(isReallyAnimating() && hasNonDefaultColorWindow());
3248     }
3249 
3250     /**
3251      * @return true if we have a window that has a non-default color mode set; false otherwise.
3252      */
hasNonDefaultColorWindow()3253     private boolean hasNonDefaultColorWindow() {
3254         return forAllWindows(ws -> ws.mAttrs.getColorMode() != COLOR_MODE_DEFAULT,
3255                 true /* topToBottom */);
3256     }
3257 
updateColorTransform()3258     private void updateColorTransform() {
3259         if (mSurfaceControl != null && mLastAppSaturationInfo != null) {
3260             getPendingTransaction().setColorTransform(mSurfaceControl,
3261                     mLastAppSaturationInfo.mMatrix, mLastAppSaturationInfo.mTranslation);
3262             mWmService.scheduleAnimationLocked();
3263         }
3264     }
3265 
3266     private static class AppSaturationInfo {
3267         float[] mMatrix = new float[9];
3268         float[] mTranslation = new float[3];
3269 
setSaturation(@ize9) float[] matrix, @Size(3) float[] translation)3270         void setSaturation(@Size(9) float[] matrix, @Size(3) float[] translation) {
3271             System.arraycopy(matrix, 0, mMatrix, 0, mMatrix.length);
3272             System.arraycopy(translation, 0, mTranslation, 0, mTranslation.length);
3273         }
3274     }
3275 }
3276