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