2 * Copyright (C) 2011 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.wm;
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;
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;
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;
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;
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;
134 class AppTokenList extends ArrayList<AppWindowToken> {
138 * Version of WindowToken that is specifically for a particular application (or
139 * really activity) that is displaying windows.
141 class AppWindowToken extends WindowToken implements WindowManagerService.AppFreezeListener,
142 ConfigurationContainerListener {
143 private static final String TAG = TAG_WITH_CLASS_NAME ? "AppWindowToken" : TAG_WM;
146 * Value to increment the z-layer when boosting a layer during animations. BOOST in l33tsp34k.
148 @VisibleForTesting static final int Z_BOOST_BASE = 800570000;
150 // Non-null only for application tokens.
151 final IApplicationToken appToken;
152 final ComponentName mActivityComponent;
153 final boolean mVoiceInteraction;
155 /** @see WindowContainer#fillsParent() */
156 private boolean mFillsParent;
157 boolean mShowForAllUsers;
160 // Flag set while reparenting to prevent actions normally triggered by an individual parent
162 private boolean mReparenting;
164 // True if we are current in the process of removing this app token from the display
165 private boolean mRemovingFromDisplay = false;
167 // The input dispatching timeout for this application token in nanoseconds.
168 long mInputDispatchingTimeoutNanos;
170 // These are used for determining when all windows associated with
171 // an activity have been drawn, so they can be made visible together
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;
179 private boolean mLastAllDrawn;
180 private boolean mUseTransferredAnimation;
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;
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;
192 // Have we told the window clients to hide themselves?
193 private boolean mClientHidden;
195 // If true we will defer setting mClientHidden to true and reporting to the client that it is
197 boolean mDeferHidingClient;
199 // Last visibility state we reported to the app token.
200 boolean reportedVisible;
202 // Last drawn state we reported to the app token.
203 private boolean reportedDrawn;
205 // Set to true when the token has been removed from the window mgr.
208 // Information about an application starting window if displayed.
209 StartingData mStartingData;
210 WindowState startingWindow;
211 StartingSurface startingSurface;
212 boolean startingDisplayed;
213 boolean startingMoved;
215 // True if the hidden state of this token was forced to false due to a transferred starting
217 private boolean mHiddenSetFromTransferredStartingWindow;
218 boolean firstWindowDrawn;
219 private final WindowState.UpdateReportedVisibilityResults mReportedVisibilityResults =
220 new WindowState.UpdateReportedVisibilityResults();
222 // Input application handle used by the input dispatcher.
223 final InputApplicationHandle mInputApplicationHandle;
225 // TODO: Have a WindowContainer state for tracking exiting/deferred removal.
228 boolean mLaunchTaskBehind;
229 boolean mEnteringAnimation;
231 private boolean mAlwaysFocusable;
234 int mRotationAnimationHint;
235 private int mPendingRelaunchCount;
237 private boolean mLastContainsShowWhenLockedWindow;
238 private boolean mLastContainsDismissKeyguardWindow;
240 ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
241 ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>();
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.
247 private float mSizeCompatScale = 1f;
249 * The bounds in global coordinates for activity in size compatibility mode.
250 * @see ActivityRecord#inSizeCompatMode
252 private Rect mSizeCompatBounds;
254 private boolean mDisablePreviewScreenshots;
256 private Task mLastParent;
258 // TODO: Remove after unification
259 ActivityRecord mActivityRecord;
262 * See {@link #canTurnScreenOn()}
264 private boolean mCanTurnScreenOn = true;
267 * If we are running an animation, this determines the transition type. Must be one of
268 * AppTransition.TRANSIT_* constants.
270 private int mTransit;
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.
276 private int mTransitFlags;
278 /** Whether our surface was set to be showing in the last call to {@link #prepareSurfaces} */
279 private boolean mLastSurfaceShowing = true;
282 * This gets used during some open/close transitions as well as during a change transition
283 * where it represents the starting-state snapshot.
285 private AppWindowThumbnail mThumbnail;
286 private final Rect mTransitStartRect = new Rect();
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.
292 private SurfaceControl mTransitChangeLeash = null;
294 /** Have we been asked to have this token keep the screen frozen? */
295 private boolean mFreezingScreen;
297 /** Whether this token should be boosted at the top of all app window tokens. */
298 @VisibleForTesting boolean mNeedsZBoost;
299 private Letterbox mLetterbox;
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;
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
312 private boolean mWillCloseOrEnterPip;
314 /** Layer used to constrain the animation to a token's stack bounds. */
315 SurfaceControl mAnimationBoundsLayer;
317 /** Whether this token needs to create mAnimationBoundsLayer for cropping animations. */
318 boolean mNeedsAnimationBoundsLayer;
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;
324 private AppSaturationInfo mLastAppSaturationInfo;
326 private final ColorDisplayService.ColorTransformController mColorTransformController =
327 (matrix, translation) -> mWmService.mH.post(() -> {
328 synchronized (mWmService.mGlobalLock) {
329 if (mLastAppSaturationInfo == null) {
330 mLastAppSaturationInfo = new AppSaturationInfo();
333 mLastAppSaturationInfo.setSaturation(matrix, translation);
334 updateColorTransform();
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;
356 // Application tokens start out hidden.
358 hiddenRequested = true;
360 ColorDisplayService.ColorDisplayServiceInternal cds = LocalServices.getService(
361 ColorDisplayService.ColorDisplayServiceInternal.class);
362 cds.attachColorTransformController(activityRecord.packageName, activityRecord.mUserId,
363 new WeakReference<>(mColorTransformController));
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 */);
372 mActivityComponent = activityComponent;
373 mVoiceInteraction = voiceInteraction;
374 mFillsParent = fillsParent;
375 mInputApplicationHandle = new InputApplicationHandle(appToken.asBinder());
378 void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) {
379 firstWindowDrawn = true;
381 // We now have a good window to show, remove dead placeholders
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
390 win.cancelAnimation();
392 removeStartingWindow();
393 updateReportedVisibilityLocked();
396 void updateReportedVisibilityLocked() {
397 if (appToken == null) {
401 if (DEBUG_VISIBILITY) Slog.v(TAG, "Update reported visibility: " + this);
402 final int count = mChildren.size();
404 mReportedVisibilityResults.reset();
406 for (int i = 0; i < count; i++) {
407 final WindowState win = mChildren.get(i);
408 win.updateReportedVisibility(mReportedVisibilityResults);
411 int numInteresting = mReportedVisibilityResults.numInteresting;
412 int numVisible = mReportedVisibilityResults.numVisible;
413 int numDrawn = mReportedVisibilityResults.numDrawn;
414 boolean nowGone = mReportedVisibilityResults.nowGone;
416 boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting;
417 boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting && !isHidden();
419 // If the app is not yet gone, then it can only become visible/drawn.
421 nowDrawn = reportedDrawn;
424 nowVisible = reportedVisible;
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());
433 reportedDrawn = nowDrawn;
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) {
449 private void onWindowsGone() {
450 if (mActivityRecord == null) {
453 if (DEBUG_VISIBILITY) {
454 Slog.v(TAG_WM, "Reporting gone in " + mActivityRecord.appToken);
456 mActivityRecord.onWindowsGone();
459 private void onWindowsVisible() {
460 if (mActivityRecord == null) {
463 if (DEBUG_VISIBILITY) {
464 Slog.v(TAG_WM, "Reporting visible in " + mActivityRecord.appToken);
466 mActivityRecord.onWindowsVisible();
469 boolean isClientHidden() {
470 return mClientHidden;
473 void setClientHidden(boolean hideClient) {
474 if (mClientHidden == hideClient || (hideClient && mDeferHidingClient)) {
477 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "setClientHidden: " + this
478 + " clientHidden=" + hideClient + " Callers=" + Debug.getCallers(5));
479 mClientHidden = hideClient;
480 sendAppVisibilityToClients();
483 void setVisibility(boolean visible, boolean deferHidingClient) {
484 final AppTransition appTransition = getDisplayContent().mAppTransition;
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) {
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);
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));
511 final DisplayContent displayContent = getDisplayContent();
512 displayContent.mOpeningApps.remove(this);
513 displayContent.mClosingApps.remove(this);
514 if (isInChangeTransition()) {
515 clearChangeLeash(getPendingTransaction(), true /* cancel */);
517 displayContent.mChangingApps.remove(this);
518 waitingToShow = false;
519 hiddenRequested = !visible;
520 mDeferHidingClient = deferHidingClient;
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.
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
533 displayContent.mOpeningApps.add(this);
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) {
541 // If the app was already visible, don't reset the waitingToShow state.
543 waitingToShow = true;
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.
548 if (w.mWinAnimator.mDrawState == HAS_DRAWN) {
549 w.mWinAnimator.resetDrawState();
551 // Force add to mResizingWindows, so that we are guaranteed to get
552 // another reportDrawn callback.
553 w.resetLastContentInsets();
555 }, true /* traverseTopToBottom */);
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);
565 requestUpdateWallpaperIfNeeded();
567 if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + this);
570 transferStartingWindowFromHiddenAboveTokenIfNeeded();
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;
578 displayContent.mOpeningApps.add(this);
579 mEnteringAnimation = true;
581 displayContent.mClosingApps.add(this);
582 mEnteringAnimation = false;
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();
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");
595 // Force animation to be loaded.
596 focusedToken.setHidden(true);
597 displayContent.mOpeningApps.add(focusedToken);
601 // Changes in opening apps and closing apps may cause orientation change.
602 reportDescendantOrientationChangeIfNeeded();
606 commitVisibility(null, visible, TRANSIT_UNSET, true, mVoiceInteraction);
607 updateReportedVisibilityLocked();
610 boolean commitVisibility(WindowManager.LayoutParams lp,
611 boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction) {
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;
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);
632 boolean runningAppAnimation = false;
634 if (transit != WindowManager.TRANSIT_UNSET) {
635 if (mUseTransferredAnimation) {
636 runningAppAnimation = isReallyAnimating();
637 } else if (applyAnimationLocked(lp, transit, visible, isVoiceInteraction)) {
638 runningAppAnimation = true;
640 delayed = runningAppAnimation;
641 final WindowState window = findMainWindow();
642 if (window != null && accessibilityController != null) {
643 accessibilityController.onAppWindowTransitionLocked(window, transit);
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);
655 hiddenRequested = !visible;
656 visibilityChanged = true;
658 stopFreezingScreen(true, true);
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;
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);
672 if (DEBUG_APP_TRANSITIONS) {
673 Slog.v(TAG_WM, "commitVisibility: " + this
674 + ": hidden=" + isHidden() + " hiddenRequested=" + hiddenRequested);
678 getDisplayContent().getInputMonitor().setUpdateInputWindowsNeededLw();
680 mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
681 false /*updateInputWindows*/);
682 mWmService.mWindowPlacerLocked.performSurfacePlacement();
684 getDisplayContent().getInputMonitor().updateInputWindowsLw(false /*force*/);
687 mUseTransferredAnimation = false;
689 if (isReallyAnimating()) {
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();
699 for (int i = mChildren.size() - 1; i >= 0 && !delayed; i--) {
700 if ((mChildren.get(i)).isSelfOrChildAnimating()) {
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(
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
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);
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
730 getDisplayContent().getDockedDividerController().notifyAppVisibilityChanged();
732 // Take the screenshot before possibly hiding the WSA, otherwise the screenshot
733 // will not be taken.
734 mWmService.mTaskSnapshotController.notifyAppVisibilityChanged(this, visible);
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.
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");
752 SurfaceControl.closeTransaction();
755 // Visibility changes may cause orientation request change.
756 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) {
773 final IBinder freezeToken =
774 mActivityRecord.mayFreezeScreenLocked(mActivityRecord.app)
775 ? mActivityRecord.appToken : null;
776 onDescendantOrientationChanged(freezeToken, mActivityRecord);
780 * @return The to top most child window for which {@link LayoutParams#isFullscreen()} returns
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()) {
793 WindowState findMainWindow() {
794 return findMainWindow(true);
798 * Finds the main window that either has type base application or application starting if
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.
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
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) {
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.
838 return getWindowConfiguration().canReceiveKeys() || mAlwaysFocusable;
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.
849 void removeImmediately() {
850 onRemovedFromDisplay();
851 if (mActivityRecord != null) {
852 mActivityRecord.unregisterConfigurationChangeListener(this);
854 super.removeImmediately();
858 void removeIfPossible() {
860 removeAllWindowsIfPossible();
865 boolean checkCompleteDeferredRemoval() {
869 return super.checkCompleteDeferredRemoval();
872 void onRemovedFromDisplay() {
873 if (mRemovingFromDisplay) {
876 mRemovingFromDisplay = true;
878 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app token: " + this);
880 boolean delayed = commitVisibility(null, false, TRANSIT_UNSET, true, mVoiceInteraction);
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)) {
889 } else if (getDisplayContent().mAppTransition.isTransitionSet()) {
890 getDisplayContent().mClosingApps.add(this);
894 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app " + this + " delayed=" + delayed
895 + " animation=" + getAnimation() + " animating=" + isSelfAnimating());
897 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM, "removeAppToken: "
898 + this + " delayed=" + delayed + " Callers=" + Debug.getCallers(4));
900 if (mStartingData != null) {
901 removeStartingWindow();
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);
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);
917 stack.mExitingAppTokens.add(this);
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
925 stack.mExitingAppTokens.remove(this);
931 stopFreezingScreen(true, true);
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*/);
940 if (mLetterbox != null) {
941 mLetterbox.destroy();
946 updateReportedVisibilityLocked();
949 mRemovingFromDisplay = false;
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();
958 if (wallpaperMightChange) {
959 requestUpdateWallpaperIfNeeded();
963 void destroySurfaces() {
964 destroySurfaces(false /*cleanupOnResume*/);
968 * Destroy surfaces which have been marked as eligible by the animator, taking care to ensure
969 * the client has finished with them.
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.
976 private void destroySurfaces(boolean cleanupOnResume) {
977 boolean destroyedSomething = false;
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);
985 if (destroyedSomething) {
986 final DisplayContent dc = getDisplayContent();
987 dc.assignWindowLayers(true /*setLayoutNeeded*/);
988 updateLetterboxSurface(null);
993 * Notify that the app is now resumed, and it was not stopped before, perform a clean
996 void notifyAppResumed(boolean wasStopped) {
997 if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppResumed: wasStopped=" + wasStopped
1000 // Allow the window to turn the screen on once the app is resumed again.
1001 setCanTurnScreenOn(true);
1003 destroySurfaces(true /*cleanupOnResume*/);
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.
1011 void notifyAppStopped() {
1012 if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppStopped: " + this);
1015 // Remove any starting window that was added for this app if they are still around.
1016 removeStartingWindow();
1019 void clearAllDrawn() {
1021 deferClearAllDrawn = false;
1025 return (Task) getParent();
1028 TaskStack getStack() {
1029 final Task task = getTask();
1038 void onParentChanged() {
1039 super.onParentChanged();
1041 final Task task = getTask();
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) {
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);
1055 final TaskStack stack = getStack();
1057 // If we reparent, make sure to remove ourselves from the old animation registry.
1058 if (mAnimatingAppWindowTokenRegistry != null) {
1059 mAnimatingAppWindowTokenRegistry.notifyFinished(this);
1061 mAnimatingAppWindowTokenRegistry = stack != null
1062 ? stack.getAnimatingAppWindowTokenRegistry()
1067 updateColorTransform();
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
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 "
1091 removeStartingWindow();
1095 void removeDeadWindows() {
1096 for (int winNdx = mChildren.size() - 1; winNdx >= 0; --winNdx) {
1097 WindowState win = mChildren.get(winNdx);
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();
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
1113 if (!(mChildren.get(i)).mAppDied) {
1120 void setWillReplaceWindows(boolean animate) {
1121 if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM,
1122 "Marking app token " + this + " with replacing windows.");
1124 for (int i = mChildren.size() - 1; i >= 0; i--) {
1125 final WindowState w = mChildren.get(i);
1126 w.setWillReplaceWindow(animate);
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();
1139 void clearWillReplaceWindows() {
1140 if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM,
1141 "Resetting app token " + this + " of replacing window marks.");
1143 for (int i = mChildren.size() - 1; i >= 0; i--) {
1144 final WindowState w = mChildren.get(i);
1145 w.clearWillReplaceWindow();
1149 void requestUpdateWallpaperIfNeeded() {
1150 for (int i = mChildren.size() - 1; i >= 0; i--) {
1151 final WindowState w = mChildren.get(i);
1152 w.requestUpdateWallpaperIfNeeded();
1156 boolean isRelaunching() {
1157 return mPendingRelaunchCount > 0;
1160 boolean shouldFreezeBounds() {
1161 final Task task = getTask();
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()) {
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();
1176 void startRelaunching() {
1177 if (shouldFreezeBounds()) {
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).
1187 mPendingRelaunchCount++;
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();
1196 SurfaceControl.closeTransaction();
1199 void finishRelaunching() {
1202 if (mPendingRelaunchCount > 0) {
1203 mPendingRelaunchCount--;
1205 // Update keyguard flags upon finishing relaunch.
1206 checkKeyguardFlagsChanged();
1210 void clearRelaunching() {
1211 if (mPendingRelaunchCount == 0) {
1215 mPendingRelaunchCount = 0;
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.
1223 protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow,
1224 WindowState existingWindow) {
1225 final int type1 = newWindow.mAttrs.type;
1226 final int type2 = existingWindow.mAttrs.type;
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) {
1231 } else if (type1 != TYPE_BASE_APPLICATION && type2 == TYPE_BASE_APPLICATION) {
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) {
1238 } else if (type1 != TYPE_APPLICATION_STARTING && type2 == TYPE_APPLICATION_STARTING) {
1242 // Otherwise the new window is greater than the existing window.
1247 void addWindow(WindowState w) {
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);
1256 // if we got a replacement window, reset the timeout to give drawing more time
1257 if (gotReplacementWindow) {
1258 mWmService.scheduleWindowReplacementTimeouts(this);
1260 checkKeyguardFlagsChanged();
1264 void removeChild(WindowState child) {
1265 if (!mChildren.contains(child)) {
1266 // This can be true when testing.
1269 super.removeChild(child);
1270 checkKeyguardFlagsChanged();
1271 updateLetterboxSurface(child);
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()) {
1284 void onWindowReplacementTimeout() {
1285 for (int i = mChildren.size() - 1; i >= 0; --i) {
1286 (mChildren.get(i)).onWindowReplacementTimeout();
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);
1296 throw new IllegalArgumentException("reparent: could not find task");
1298 final Task currentTask = getTask();
1299 if (task == currentTask) {
1300 throw new IllegalArgumentException(
1301 "window token=" + this + " already child of task=" + currentTask);
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);
1310 if (DEBUG_ADD_REMOVE) Slog.i(TAG, "reParentWindowToken: removing window token=" + this
1311 + " from task=" + currentTask);
1312 final DisplayContent prevDisplayContent = getDisplayContent();
1314 mReparenting = true;
1316 getParent().removeChild(this);
1317 task.addChild(this, position);
1319 mReparenting = false;
1321 // Relayout display(s).
1322 final DisplayContent displayContent = task.getDisplayContent();
1323 displayContent.setLayoutNeeded();
1324 if (prevDisplayContent != displayContent) {
1325 onDisplayChanged(displayContent);
1326 prevDisplayContent.setLayoutNeeded();
1328 getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
1332 void onDisplayChanged(DisplayContent dc) {
1333 DisplayContent prevDc = mDisplayContent;
1334 super.onDisplayChanged(dc);
1335 if (prevDc == null || prevDc == mDisplayContent) {
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();
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 */);
1355 prevDc.mClosingApps.remove(this);
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);
1368 if (mLetterbox != null) {
1369 mLetterbox.onMovedToDisplay(mDisplayContent.getDisplayId());
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
1379 private void freezeBounds() {
1380 final Task task = getTask();
1381 mFrozenBounds.offer(new Rect(task.mPreparedFrozenBounds));
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()));
1387 mFrozenMergedConfig.offer(new Configuration(task.mPreparedFrozenMergedConfig));
1389 // Calling unset() to make it equal to Configuration.EMPTY.
1390 task.mPreparedFrozenMergedConfig.unset();
1394 * Unfreezes the previously frozen bounds. See {@link #freezeBounds}.
1396 private void unfreezeBounds() {
1397 if (mFrozenBounds.isEmpty()) {
1400 mFrozenBounds.remove();
1401 if (!mFrozenMergedConfig.isEmpty()) {
1402 mFrozenMergedConfig.remove();
1404 for (int i = mChildren.size() - 1; i >= 0; i--) {
1405 final WindowState win = mChildren.get(i);
1406 win.onUnfreezeBounds();
1408 mWmService.mWindowPlacerLocked.performSurfacePlacement();
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);
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)) {
1430 void startFreezingScreen() {
1431 if (DEBUG_ORIENTATION) logWithStack(TAG, "Set freezing of " + appToken + ": hidden="
1432 + isHidden() + " freezing=" + mFreezingScreen + " 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);
1445 final int count = mChildren.size();
1446 for (int i = 0; i < count; i++) {
1447 final WindowState w = mChildren.get(i);
1448 w.onStartFreezingScreen();
1453 void stopFreezingScreen(boolean unfreezeSurfaceNow, boolean force) {
1454 if (!mFreezingScreen) {
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();
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;
1471 if (unfreezeSurfaceNow) {
1472 if (unfrozeWindows) {
1473 mWmService.mWindowPlacerLocked.performSurfacePlacement();
1475 mWmService.stopFreezingDisplayLocked();
1480 public void onAppFreezeTimeout() {
1481 Slog.w(TAG_WM, "Force clearing freeze: " + this);
1482 stopFreezingScreen(true, true);
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.
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) {
1498 if (fromToken.hiddenRequested && transferStartingWindow(fromToken.token)) {
1504 boolean transferStartingWindow(IBinder transferFrom) {
1505 final AppWindowToken fromToken = getDisplayContent().getAppWindowToken(transferFrom);
1506 if (fromToken == null) {
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;
1516 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Moving existing starting " + tStartingWindow
1517 + " from " + fromToken + " to " + this);
1519 final long origId = Binder.clearCallingIdentity();
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;
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);
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) {
1547 deferClearAllDrawn = fromToken.deferClearAllDrawn;
1549 if (fromToken.firstWindowDrawn) {
1550 firstWindowDrawn = true;
1552 if (!fromToken.isHidden()) {
1554 hiddenRequested = false;
1555 mHiddenSetFromTransferredStartingWindow = true;
1557 setClientHidden(fromToken.mClientHidden);
1559 transferAnimation(fromToken);
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;
1566 mWmService.updateFocusedWindowLocked(
1567 UPDATE_FOCUS_WILL_PLACE_SURFACES, true /*updateInputWindows*/);
1568 getDisplayContent().setLayoutNeeded();
1569 mWmService.mWindowPlacerLocked.performSurfacePlacement();
1571 Binder.restoreCallingIdentity(origId);
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();
1586 // TODO: Transfer thumbnail
1591 boolean isLastWindow(WindowState win) {
1592 return mChildren.size() == 1 && mChildren.get(0) == win;
1596 void onAppTransitionDone() {
1597 sendingToBottom = false;
1601 * We override because this class doesn't want its children affecting its reported orientation
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;
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;
1621 return SCREEN_ORIENTATION_UNSET;
1624 /** Returns the app's preferred orientation regardless of its currently visibility state. */
1625 int getOrientationIgnoreVisibility() {
1626 return mOrientation;
1629 /** @return {@code true} if the compatibility bounds is taking effect. */
1630 boolean inSizeCompatMode() {
1631 return mSizeCompatBounds != null;
1635 float getSizeCompatScale() {
1636 return inSizeCompatMode() ? mSizeCompatScale : super.getSizeCompatScale();
1640 * @return Non-empty bounds if the activity has override bounds.
1641 * @see ActivityRecord#resolveOverrideConfiguration(Configuration)
1643 Rect getResolvedOverrideBounds() {
1644 // Get bounds from resolved override configuration because it is computed with orientation.
1645 return getResolvedOverrideConfiguration().windowConfiguration.getBounds();
1649 public void onConfigurationChanged(Configuration newParentConfig) {
1650 final int prevWinMode = getWindowingMode();
1651 mTmpPrevBounds.set(getBounds());
1652 super.onConfigurationChanged(newParentConfig);
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();
1676 final int winMode = getWindowingMode();
1678 if (prevWinMode == winMode) {
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
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
1695 stackBounds = pinnedStack.mPreAnimationBounds;
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);
1703 mDisplayContent.mPinnedStackControllerLocked.saveReentrySnapFraction(this,
1706 } else if (shouldStartChangeTransition(prevWinMode, winMode)) {
1707 initializeChangeTransition(mTmpPrevBounds);
1711 private boolean shouldStartChangeTransition(int prevWinMode, int newWinMode) {
1712 if (mWmService.mDisableTransitionAnimation
1714 || getDisplayContent().mAppTransition.isTransitionSet()
1715 || getSurfaceControl() == null) {
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);
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.
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.
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);
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);
1753 // Skip creating snapshot if this transition is controlled by a remote animator which
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()) {
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 */);
1776 boolean isInChangeTransition() {
1777 return mTransitChangeLeash != null || AppTransition.isChangeTransit(mTransit);
1781 AppWindowThumbnail getThumbnail() {
1786 * Calculates the scale and offset to horizontal center the size compatibility bounds into the
1787 * region which is available to application.
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;
1805 if (mSizeCompatBounds == null) {
1806 mSizeCompatBounds = new Rect();
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;
1820 public Rect getBounds() {
1821 if (mSizeCompatBounds != null) {
1822 return mSizeCompatBounds;
1824 return super.getBounds();
1828 public boolean matchParentBounds() {
1829 if (super.matchParentBounds()) {
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());
1839 void checkAppWindowsReadyToShow() {
1840 if (allDrawn == mLastAllDrawn) {
1844 mLastAllDrawn = allDrawn;
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");
1860 setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM, "checkAppWindowsReadyToShow");
1862 // We can now show all of the drawn windows!
1863 if (!getDisplayContent().mOpeningApps.contains(this) && canShowWindows()) {
1864 showAllWindowsLocked();
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.
1876 * @return {@code true} If all children have been considered, {@code false}.
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()) {
1889 * Determines if the token has finished drawing. This should only be called from
1890 * {@link DisplayContent#applySurfaceChangesTransaction}
1892 void updateAllDrawn() {
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;
1898 // We must make sure that all present children have been considered (determined by
1899 // {@link #allDrawnStatesConsidered}) before evaluating whether everything has been
1901 if (numInteresting > 0 && allDrawnStatesConsidered()
1902 && mNumDrawnWindows >= numInteresting && !isRelaunching()) {
1903 if (DEBUG_VISIBILITY) Slog.v(TAG, "allDrawn: " + this
1904 + " interesting=" + numInteresting + " drawn=" + mNumDrawnWindows);
1906 // Force an additional layout pass where
1907 // WindowStateAnimator#commitFinishDrawingLocked() will call performShowLocked().
1908 if (mDisplayContent != null) {
1909 mDisplayContent.setLayoutNeeded();
1911 mWmService.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN, token).sendToTarget();
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();
1923 boolean keyDispatchingTimedOut(String reason, int windowPid) {
1924 return mActivityRecord != null && mActivityRecord.keyDispatchingTimedOut(reason, windowPid);
1928 * Updated this app token tracking states for interesting and drawn windows based on the window.
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.
1933 boolean updateDrawnWindowStates(WindowState w) {
1934 w.setDrawnStateEvaluated(true /*evaluated*/);
1936 if (DEBUG_STARTING_WINDOW_VERBOSE && w == startingWindow) {
1937 Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen=" + w.isOnScreen()
1938 + " allDrawn=" + allDrawn + " freezingScreen=" + mFreezingScreen);
1941 if (allDrawn && !mFreezingScreen) {
1945 if (mLastTransactionSequence != mWmService.mTransactionSequence) {
1946 mLastTransactionSequence = mWmService.mTransactionSequence;
1947 mNumDrawnWindows = 0;
1948 startingDisplayed = false;
1950 // There is the main base application window, even if it is exiting, wait for it
1951 mNumInterestingWindows = findMainWindow(false /* includeStartingApp */) != null ? 1 : 0;
1954 final WindowStateAnimator winAnimator = w.mWinAnimator;
1956 boolean isInterestingAndDrawn = false;
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());
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++;
1977 if (w.isDrawnLw()) {
1980 if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG, "tokenMayBeDrawn: "
1981 + this + " w=" + w + " numInteresting=" + mNumInterestingWindows
1982 + " freezingScreen=" + mFreezingScreen
1983 + " mAppFreezing=" + w.mAppFreezing);
1985 isInterestingAndDrawn = true;
1988 } else if (w.isDrawnLw()) {
1989 if (mActivityRecord != null) {
1990 mActivityRecord.onStartingWindowDrawn(SystemClock.uptimeMillis());
1992 startingDisplayed = true;
1996 return isInterestingAndDrawn;
1999 void layoutLetterbox(WindowState winHint) {
2000 final WindowState w = findMainWindow();
2001 if (w == null || winHint != null && w != winHint) {
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);
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) {
2025 void updateLetterboxSurface(WindowState winHint) {
2026 final WindowState w = findMainWindow();
2027 if (w != winHint && winHint != null && w != null) {
2030 layoutLetterbox(winHint);
2031 if (mLetterbox != null && mLetterbox.needsApplySurfaceChanges()) {
2032 mLetterbox.applySurfaceChanges(getPendingTransaction());
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
2042 if (mIsExiting && !waitingForReplacement()) {
2045 return forAllWindowsUnchecked(callback, traverseTopToBottom);
2049 void forAllAppWindows(Consumer<AppWindowToken> callback) {
2050 callback.accept(this);
2053 boolean forAllWindowsUnchecked(ToBooleanFunction<WindowState> callback,
2054 boolean traverseTopToBottom) {
2055 return super.forAllWindows(callback, traverseTopToBottom);
2059 AppWindowToken asAppWindowToken() {
2060 // I am an app window token!
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()) {
2074 if (mStartingData != null) {
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?
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);
2091 if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
2092 return createSnapshot(snapshot);
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));
2102 AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
2103 com.android.internal.R.styleable.Window,
2104 mWmService.mCurrentUserId);
2106 // Whoops! App doesn't exist. Um. Okay. We'll just pretend like we didn't
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);
2123 if (windowIsTranslucent) {
2126 if (windowIsFloating || windowDisableStarting) {
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;
2144 if (transferStartingWindow(transferFrom)) {
2148 // There is no existing starting window, and we don't want to create a splash screen, so
2150 if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
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();
2163 private boolean createSnapshot(ActivityManager.TaskSnapshot snapshot) {
2164 if (snapshot == null) {
2168 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SnapshotStartingData");
2169 mStartingData = new SnapshotStartingData(mWmService, snapshot);
2170 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
2178 if (!mWmService.mAnimationHandler.hasCallbacks(mAddStartingWindow)) {
2179 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Enqueueing ADD_STARTING");
2180 mWmService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
2184 private final Runnable mAddStartingWindow = new Runnable() {
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);
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);
2202 startingData = mStartingData;
2205 if (DEBUG_STARTING_WINDOW) {
2206 Slog.v(TAG, "Add starting " + this + ": startingData=" + startingData);
2209 WindowManagerPolicy.StartingSurface surface = null;
2211 surface = startingData.createStartingSurface(AppWindowToken.this);
2212 } catch (Exception e) {
2213 Slog.w(TAG, "Exception when adding starting window", e);
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);
2225 startingWindow = null;
2226 mStartingData = null;
2229 startingSurface = surface;
2231 if (DEBUG_STARTING_WINDOW && !abort) {
2233 "Added starting " + AppWindowToken.this + ": startingWindow="
2234 + startingWindow + " startingView=" + startingSurface);
2240 } else if (DEBUG_STARTING_WINDOW) {
2241 Slog.v(TAG, "Surface returned was null: " + AppWindowToken.this);
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;
2263 return snapshot == null ? STARTING_WINDOW_TYPE_NONE
2264 : snapshotOrientationSameAsTask(snapshot) || fromRecents
2265 ? STARTING_WINDOW_TYPE_SNAPSHOT : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
2267 return STARTING_WINDOW_TYPE_NONE;
2272 private boolean snapshotOrientationSameAsTask(ActivityManager.TaskSnapshot snapshot) {
2273 if (snapshot == null) {
2276 return getTask().getConfiguration().orientation == snapshot.getOrientation();
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);
2287 mStartingData = null;
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 "
2307 if (DEBUG_STARTING_WINDOW) {
2308 Slog.v(TAG_WM, "Tried to remove starting window but startingWindow was null:"
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));
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);
2327 } catch (Exception e) {
2328 Slog.w(TAG_WM, "Exception when removing starting window", e);
2334 boolean fillsParent() {
2335 return mFillsParent;
2338 void setFillsParent(boolean fillsParent) {
2339 mFillsParent = fillsParent;
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;
2349 for (int i = mChildren.size() - 1; i >= 0; i--) {
2350 if ((mChildren.get(i).mAttrs.flags & FLAG_DISMISS_KEYGUARD) != 0) {
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;
2365 for (int i = mChildren.size() - 1; i >= 0; i--) {
2366 if ((mChildren.get(i).mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
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());
2382 mLastContainsDismissKeyguardWindow = containsDismissKeyguard;
2383 mLastContainsShowWhenLockedWindow = containsShowWhenLocked;
2386 WindowState getImeTargetBelowWindow(WindowState w) {
2387 final int index = mChildren.indexOf(w);
2389 final WindowState target = mChildren.get(index - 1);
2390 if (target.canBeImeTarget()) {
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);
2404 if (candidate == null) {
2412 * See {@link Activity#setDisablePreviewScreenshots}.
2414 void setDisablePreviewScreenshots(boolean disable) {
2415 mDisablePreviewScreenshots = disable;
2419 * Sets whether the current launch can turn the screen on. See {@link #canTurnScreenOn()}
2421 void setCanTurnScreenOn(boolean canTurnScreenOn) {
2422 mCanTurnScreenOn = canTurnScreenOn;
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.
2430 * @return true if the screen can be turned on.
2432 boolean canTurnScreenOn() {
2433 return mCanTurnScreenOn;
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.
2441 * @return True if we need to generate an app theme snapshot, false if we'd like to take a real
2444 boolean shouldUseAppThemeSnapshot() {
2445 return mDisablePreviewScreenshots || forAllWindows(w -> (w.mAttrs.flags & FLAG_SECURE) != 0,
2446 true /* topToBottom */);
2449 SurfaceControl getAppAnimationLayer() {
2450 return getAppAnimationLayer(isActivityTypeHome() ? ANIMATION_LAYER_HOME
2451 : needsZBoost() ? ANIMATION_LAYER_BOOSTED
2452 : ANIMATION_LAYER_STANDARD);
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();
2464 return getStack().getSurfaceControl();
2470 boolean shouldAnimate(int transit) {
2471 final boolean isSplitScreenPrimary =
2472 getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
2473 final boolean allowSplitScreenPrimaryAnimation = transit != TRANSIT_WALLPAPER_OPEN;
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()) {
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;
2491 * Creates a layer to apply crop to an animation.
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);
2504 Rect getDisplayedBounds() {
2505 final Task task = getTask();
2507 final Rect overrideDisplayedBounds = task.getOverrideDisplayedBounds();
2508 if (!overrideDisplayedBounds.isEmpty()) {
2509 return overrideDisplayedBounds;
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();
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();
2526 boolean applyAnimationLocked(WindowManager.LayoutParams lp, int transit, boolean enter,
2527 boolean isVoiceInteraction) {
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);
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;
2546 final int appStackClipMode =
2547 getDisplayContent().mAppTransition.getAppStackClipMode();
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);
2554 final boolean isChanging = AppTransition.isChangeTransit(transit) && enter
2555 && getDisplayContent().mChangingApps.contains(this);
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);
2582 mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags();
2584 mNeedsAnimationBoundsLayer = (appStackClipMode == STACK_CLIP_AFTER_ANIM);
2586 final Animation a = loadAnimation(lp, transit, enter, isVoiceInteraction);
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()
2593 adapter = new LocalAnimationAdapter(
2594 new WindowAnimationSpec(a, mTmpPoint, mTmpRect,
2595 getDisplayContent().mAppTransition.canSkipFirstFrame(),
2597 true /* isAppAnimation */,
2598 windowCornerRadius),
2599 mWmService.mSurfaceAnimationRunner);
2600 if (a.getZAdjustment() == Animation.ZORDER_TOP) {
2601 mNeedsZBoost = true;
2604 mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags();
2609 if (adapter != null) {
2610 startAnimation(getPendingTransaction(), adapter, !isVisible());
2611 if (adapter.getShowWallpaper()) {
2612 mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
2614 if (thumbnailAdapter != null) {
2615 mThumbnail.startAnimation(
2616 getPendingTransaction(), thumbnailAdapter, !isVisible());
2622 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
2624 return isReallyAnimating();
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);
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();
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.
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());
2659 frame.set(win.getContainingFrame());
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);
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.
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);
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());
2692 public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
2693 return mAnimatingAppWindowTokenRegistry != null
2694 && mAnimatingAppWindowTokenRegistry.notifyAboutToFinish(
2695 this, endDeferFinishCallback);
2699 public void onAnimationLeashLost(Transaction t) {
2700 super.onAnimationLeashLost(t);
2701 if (mAnimationBoundsLayer != null) {
2702 t.remove(mAnimationBoundsLayer);
2703 mAnimationBoundsLayer = null;
2706 if (mAnimatingAppWindowTokenRegistry != null) {
2707 mAnimatingAppWindowTokenRegistry.notifyFinished(this);
2712 protected void setLayer(Transaction t, int layer) {
2713 if (!mSurfaceAnimator.hasLeash()) {
2714 t.setLayer(mSurfaceControl, layer);
2719 protected void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) {
2720 if (!mSurfaceAnimator.hasLeash()) {
2721 t.setRelativeLayer(mSurfaceControl, relativeTo, layer);
2726 protected void reparentSurfaceControl(Transaction t, SurfaceControl newParent) {
2727 if (!mSurfaceAnimator.hasLeash()) {
2728 t.reparent(mSurfaceControl, newParent);
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.
2737 if (!inPinnedWindowingMode()) {
2738 layer = getPrefixOrderIndex();
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
2743 layer = getParent().getPrefixOrderIndex();
2747 layer += Z_BOOST_BASE;
2749 if (!mNeedsAnimationBoundsLayer) {
2750 leash.setLayer(layer);
2753 final DisplayContent dc = getDisplayContent();
2754 dc.assignStackOrdering();
2756 if (leash == mTransitChangeLeash) {
2757 // This is a temporary state so skip any animation notifications
2759 } else if (mTransitChangeLeash != null) {
2760 // unparent mTransitChangeLeash for clean-up
2761 clearChangeLeash(t, false /* cancel */);
2764 if (mAnimatingAppWindowTokenRegistry != null) {
2765 mAnimatingAppWindowTokenRegistry.notifyStarting(this);
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);
2777 final TaskStack stack = getStack();
2778 if (stack == null) {
2781 // Set clip rect to stack bounds.
2782 stack.getBounds(mTmpRect);
2784 mAnimationBoundsLayer = createAnimationBoundsLayer(t);
2786 // Crop to stack bounds.
2787 t.setWindowCrop(mAnimationBoundsLayer, mTmpRect);
2788 t.setLayer(mAnimationBoundsLayer, layer);
2790 // Reparent leash to animation bounds layer.
2791 t.reparent(leash, mAnimationBoundsLayer);
2796 * This must be called while inside a transaction.
2798 void showAllWindowsLocked() {
2799 forAllWindows(windowState -> {
2800 if (DEBUG_VISIBILITY) Slog.v(TAG, "performing show on: " + windowState);
2801 windowState.performShowLocked();
2802 }, false /* traverseTopToBottom */);
2806 protected void onAnimationFinished() {
2807 super.onAnimationFinished();
2809 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AWT#onAnimationFinished");
2810 mTransit = TRANSIT_UNSET;
2812 mNeedsZBoost = false;
2813 mNeedsAnimationBoundsLayer = false;
2815 setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM | FINISH_LAYOUT_REDO_WALLPAPER,
2819 setClientHidden(isHidden() && hiddenRequested);
2821 getDisplayContent().computeImeTargetIfNeeded(this);
2823 if (DEBUG_ANIM) Slog.v(TAG, "Animation done in " + this
2824 + ": reportedVisible=" + reportedVisible
2825 + " okToDisplay=" + okToDisplay()
2826 + " okToAnimate=" + okToAnimate()
2827 + " startingDisplayed=" + startingDisplayed);
2829 // clean up thumbnail window
2830 if (mThumbnail != null) {
2831 mThumbnail.destroy();
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);
2840 getDisplayContent().mAppTransition.notifyAppTransitionFinishedLocked(token);
2841 scheduleAnimation();
2843 mActivityRecord.onAnimationFinished();
2844 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
2848 boolean isAppAnimating() {
2849 return isSelfAnimating();
2853 boolean isSelfAnimating() {
2854 // If we are about to start a transition, we also need to be considered animating.
2855 return isWaitingForTransitionStart() || isReallyAnimating();
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
2863 private boolean isReallyAnimating() {
2864 return super.isSelfAnimating();
2868 * @param cancel {@code true} if clearing the leash due to cancelling instead of transferring
2871 private void clearChangeLeash(Transaction t, boolean cancel) {
2872 if (mTransitChangeLeash == null) {
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());
2884 t.hide(mTransitChangeLeash);
2885 t.remove(mTransitChangeLeash);
2886 mTransitChangeLeash = null;
2888 onAnimationLeashLost(t);
2893 void cancelAnimation() {
2894 cancelAnimationOnly();
2896 clearChangeLeash(getPendingTransaction(), true /* cancel */);
2900 * This only cancels the animation. It doesn't do other teardown like cleaning-up thumbnail
2901 * or interim leashes.
2903 * Used when canceling in preparation for starting a new animation.
2905 void cancelAnimationOnly() {
2906 super.cancelAnimation();
2909 boolean isWaitingForTransitionStart() {
2910 return getDisplayContent().mAppTransition.isTransitionSet()
2911 && (getDisplayContent().mOpeningApps.contains(this)
2912 || getDisplayContent().mClosingApps.contains(this)
2913 || getDisplayContent().mChangingApps.contains(this));
2916 public int getTransit() {
2920 int getTransitFlags() {
2921 return mTransitFlags;
2924 void attachThumbnailAnimation() {
2925 if (!isReallyAnimating()) {
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);
2936 mThumbnail = new AppWindowThumbnail(getPendingTransaction(), this, thumbnailHeader);
2937 mThumbnail.startAnimation(getPendingTransaction(), loadThumbnailAnimation(thumbnailHeader));
2941 * Attaches a surface with a thumbnail for the
2942 * {@link android.app.ActivityOptions#ANIM_OPEN_CROSS_PROFILE_APPS} animation.
2944 void attachCrossProfileAppsThumbnailAnimation() {
2945 if (!isReallyAnimating()) {
2950 final WindowState win = findMainWindow();
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) {
2964 mThumbnail = new AppWindowThumbnail(getPendingTransaction(), this, thumbnail);
2965 final Animation animation =
2966 getDisplayContent().mAppTransition.createCrossProfileAppsThumbnailAnimationLocked(
2968 mThumbnail.startAnimation(getPendingTransaction(), animation, new Point(frame.left,
2972 private Animation loadThumbnailAnimation(GraphicBuffer thumbnailHeader) {
2973 final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
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);
2988 private void clearThumbnail() {
2989 if (mThumbnail == null) {
2992 mThumbnail.destroy();
2996 void registerRemoteAnimations(RemoteAnimationDefinition definition) {
2997 mRemoteAnimationDefinition = definition;
3000 RemoteAnimationDefinition getRemoteAnimationDefinition() {
3001 return mRemoteAnimationDefinition;
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);
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);
3018 pw.print(prefix); pw.print("paused="); pw.println(paused);
3021 pw.print(prefix); pw.print("mAppStopped="); pw.println(mAppStopped);
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);
3033 if (inPendingTransaction) {
3034 pw.print(prefix); pw.print("inPendingTransaction=");
3035 pw.println(inPendingTransaction);
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);
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);
3052 if (!mFrozenBounds.isEmpty()) {
3053 pw.print(prefix); pw.print("mFrozenBounds="); pw.println(mFrozenBounds);
3054 pw.print(prefix); pw.print("mFrozenMergedConfig="); pw.println(mFrozenMergedConfig);
3056 if (mPendingRelaunchCount != 0) {
3057 pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount);
3059 if (mSizeCompatScale != 1f || mSizeCompatBounds != null) {
3060 pw.println(prefix + "mSizeCompatScale=" + mSizeCompatScale + " mSizeCompatBounds="
3061 + mSizeCompatBounds);
3063 if (mRemovingFromDisplay) {
3064 pw.println(prefix + "mRemovingFromDisplay=" + mRemovingFromDisplay);
3069 void setHidden(boolean hidden) {
3070 super.setHidden(hidden);
3073 // Once the app window is hidden, reset the last saved PiP snap fraction
3074 mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(this);
3076 scheduleAnimation();
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;
3086 if (mSurfaceControl != null) {
3087 if (show && !mLastSurfaceShowing) {
3088 getPendingTransaction().show(mSurfaceControl);
3089 } else if (!show && mLastSurfaceShowing) {
3090 getPendingTransaction().hide(mSurfaceControl);
3093 if (mThumbnail != null) {
3094 mThumbnail.setShowing(getPendingTransaction(), show);
3096 mLastSurfaceShowing = show;
3097 super.prepareSurfaces();
3101 * @return Whether our {@link #getSurfaceControl} is currently showing.
3103 boolean isSurfaceShowing() {
3104 return mLastSurfaceShowing;
3107 boolean isFreezingScreen() {
3108 return mFreezingScreen;
3112 boolean needsZBoost() {
3113 return mNeedsZBoost || super.needsZBoost();
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()) {
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);
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);
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);
3159 void writeNameToProto(ProtoOutputStream proto, long fieldId) {
3160 if (appToken == null) {
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());
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();
3180 return stringName + ((mIsExiting) ? " mIsExiting=" : "");
3183 Rect getLetterboxInsets() {
3184 if (mLetterbox != null) {
3185 return mLetterbox.getInsets();
3191 /** Gets the inner bounds of letterbox. The bounds will be empty if there is no letterbox. */
3192 void getLetterboxInnerBounds(Rect outBounds) {
3193 if (mLetterbox != null) {
3194 outBounds.set(mLetterbox.getInnerFrame());
3196 outBounds.setEmpty();
3201 * @return {@code true} if there is a letterbox and any part of that letterbox overlaps with
3202 * the given {@code rect}.
3204 boolean isLetterboxOverlappingWith(Rect rect) {
3205 return mLetterbox != null && mLetterbox.isOverlappingWith(rect);
3209 * Sets if this AWT is in the process of closing or entering PIP.
3210 * {@link #mWillCloseOrEnterPip}}
3212 void setWillCloseOrEnterPip(boolean willCloseOrEnterPip) {
3213 mWillCloseOrEnterPip = willCloseOrEnterPip;
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.
3221 boolean isClosingOrEnteringPip() {
3222 return (isAnimating() && hiddenRequested) || mWillCloseOrEnterPip;
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.
3230 boolean canShowWindows() {
3231 return allDrawn && !(isReallyAnimating() && hasNonDefaultColorWindow());
3235 * @return true if we have a window that has a non-default color mode set; false otherwise.
3237 private boolean hasNonDefaultColorWindow() {
3238 return forAllWindows(ws -> ws.mAttrs.getColorMode() != COLOR_MODE_DEFAULT,
3239 true /* topToBottom */);
3242 private void updateColorTransform() {
3243 if (mSurfaceControl != null && mLastAppSaturationInfo != null) {
3244 getPendingTransaction().setColorTransform(mSurfaceControl,
3245 mLastAppSaturationInfo.mMatrix, mLastAppSaturationInfo.mTranslation);
3246 mWmService.scheduleAnimationLocked();
3250 private static class AppSaturationInfo {
3251 float[] mMatrix = new float[9];
3252 float[] mTranslation = new float[3];
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);