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