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