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_PINNED; 20 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; 21 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 22 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION; 23 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE; 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.Display.DEFAULT_DISPLAY; 28 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; 29 import static android.view.WindowManager.LayoutParams.FLAG_SECURE; 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 35 import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN; 36 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; 37 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; 38 import static android.view.WindowManager.TRANSIT_UNSET; 39 40 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; 41 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; 42 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; 43 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT; 44 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS; 45 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; 46 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW; 47 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE; 48 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT; 49 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; 50 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT; 51 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 52 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 53 import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN; 54 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; 55 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES; 56 import static com.android.server.wm.WindowManagerService.logWithStack; 57 import static com.android.server.wm.AppWindowTokenProto.ALL_DRAWN; 58 import static com.android.server.wm.AppWindowTokenProto.APP_STOPPED; 59 import static com.android.server.wm.AppWindowTokenProto.CLIENT_HIDDEN; 60 import static com.android.server.wm.AppWindowTokenProto.DEFER_HIDING_CLIENT; 61 import static com.android.server.wm.AppWindowTokenProto.FILLS_PARENT; 62 import static com.android.server.wm.AppWindowTokenProto.FROZEN_BOUNDS; 63 import static com.android.server.wm.AppWindowTokenProto.HIDDEN_REQUESTED; 64 import static com.android.server.wm.AppWindowTokenProto.HIDDEN_SET_FROM_TRANSFERRED_STARTING_WINDOW; 65 import static com.android.server.wm.AppWindowTokenProto.IS_REALLY_ANIMATING; 66 import static com.android.server.wm.AppWindowTokenProto.IS_WAITING_FOR_TRANSITION_START; 67 import static com.android.server.wm.AppWindowTokenProto.LAST_ALL_DRAWN; 68 import static com.android.server.wm.AppWindowTokenProto.LAST_SURFACE_SHOWING; 69 import static com.android.server.wm.AppWindowTokenProto.NAME; 70 import static com.android.server.wm.AppWindowTokenProto.NUM_DRAWN_WINDOWS; 71 import static com.android.server.wm.AppWindowTokenProto.NUM_INTERESTING_WINDOWS; 72 import static com.android.server.wm.AppWindowTokenProto.REMOVED; 73 import static com.android.server.wm.AppWindowTokenProto.REPORTED_DRAWN; 74 import static com.android.server.wm.AppWindowTokenProto.REPORTED_VISIBLE; 75 import static com.android.server.wm.AppWindowTokenProto.STARTING_DISPLAYED; 76 import static com.android.server.wm.AppWindowTokenProto.STARTING_MOVED; 77 import static com.android.server.wm.AppWindowTokenProto.STARTING_WINDOW; 78 import static com.android.server.wm.AppWindowTokenProto.THUMBNAIL; 79 import static com.android.server.wm.AppWindowTokenProto.WINDOW_TOKEN; 80 81 import android.annotation.CallSuper; 82 import android.app.Activity; 83 import android.content.res.Configuration; 84 import android.graphics.GraphicBuffer; 85 import android.graphics.Point; 86 import android.graphics.Rect; 87 import android.os.Binder; 88 import android.os.Debug; 89 import android.os.IBinder; 90 import android.os.RemoteException; 91 import android.os.Trace; 92 import android.util.Slog; 93 import android.util.proto.ProtoOutputStream; 94 import android.view.DisplayInfo; 95 import android.view.IApplicationToken; 96 import android.view.RemoteAnimationDefinition; 97 import android.view.SurfaceControl; 98 import android.view.SurfaceControl.Transaction; 99 import android.view.WindowManager; 100 import android.view.WindowManager.LayoutParams; 101 import android.view.animation.Animation; 102 103 import com.android.internal.R; 104 import com.android.internal.util.ToBooleanFunction; 105 import com.android.server.input.InputApplicationHandle; 106 import com.android.server.policy.WindowManagerPolicy.StartingSurface; 107 import com.android.server.wm.WindowManagerService.H; 108 109 import java.io.PrintWriter; 110 import java.util.ArrayDeque; 111 import java.util.ArrayList; 112 113 class AppTokenList extends ArrayList<AppWindowToken> { 114 } 115 116 /** 117 * Version of WindowToken that is specifically for a particular application (or 118 * really activity) that is displaying windows. 119 */ 120 class AppWindowToken extends WindowToken implements WindowManagerService.AppFreezeListener { 121 private static final String TAG = TAG_WITH_CLASS_NAME ? "AppWindowToken" : TAG_WM; 122 123 /** 124 * Value to increment the z-layer when boosting a layer during animations. BOOST in l33tsp34k. 125 */ 126 private static final int Z_BOOST_BASE = 800570000; 127 128 // Non-null only for application tokens. 129 final IApplicationToken appToken; 130 131 final boolean mVoiceInteraction; 132 133 /** @see WindowContainer#fillsParent() */ 134 private boolean mFillsParent; 135 boolean layoutConfigChanges; 136 boolean mShowForAllUsers; 137 int mTargetSdk; 138 139 // Flag set while reparenting to prevent actions normally triggered by an individual parent 140 // change. 141 private boolean mReparenting; 142 143 // True if we are current in the process of removing this app token from the display 144 private boolean mRemovingFromDisplay = false; 145 146 // The input dispatching timeout for this application token in nanoseconds. 147 long mInputDispatchingTimeoutNanos; 148 149 // These are used for determining when all windows associated with 150 // an activity have been drawn, so they can be made visible together 151 // at the same time. 152 // initialize so that it doesn't match mTransactionSequence which is an int. 153 private long mLastTransactionSequence = Long.MIN_VALUE; 154 private int mNumInterestingWindows; 155 private int mNumDrawnWindows; 156 boolean inPendingTransaction; 157 boolean allDrawn; 158 private boolean mLastAllDrawn; 159 160 // Set to true when this app creates a surface while in the middle of an animation. In that 161 // case do not clear allDrawn until the animation completes. 162 boolean deferClearAllDrawn; 163 164 // Is this window's surface needed? This is almost like hidden, except 165 // it will sometimes be true a little earlier: when the token has 166 // been shown, but is still waiting for its app transition to execute 167 // before making its windows shown. 168 boolean hiddenRequested; 169 170 // Have we told the window clients to hide themselves? 171 private boolean mClientHidden; 172 173 // If true we will defer setting mClientHidden to true and reporting to the client that it is 174 // hidden. 175 boolean mDeferHidingClient; 176 177 // Last visibility state we reported to the app token. 178 boolean reportedVisible; 179 180 // Last drawn state we reported to the app token. 181 private boolean reportedDrawn; 182 183 // Set to true when the token has been removed from the window mgr. 184 boolean removed; 185 186 // Information about an application starting window if displayed. 187 StartingData startingData; 188 WindowState startingWindow; 189 StartingSurface startingSurface; 190 boolean startingDisplayed; 191 boolean startingMoved; 192 193 // True if the hidden state of this token was forced to false due to a transferred starting 194 // window. 195 private boolean mHiddenSetFromTransferredStartingWindow; 196 boolean firstWindowDrawn; 197 private final WindowState.UpdateReportedVisibilityResults mReportedVisibilityResults = 198 new WindowState.UpdateReportedVisibilityResults(); 199 200 // Input application handle used by the input dispatcher. 201 final InputApplicationHandle mInputApplicationHandle; 202 203 // TODO: Have a WindowContainer state for tracking exiting/deferred removal. 204 boolean mIsExiting; 205 206 boolean mLaunchTaskBehind; 207 boolean mEnteringAnimation; 208 209 private boolean mAlwaysFocusable; 210 211 boolean mAppStopped; 212 int mRotationAnimationHint; 213 private int mPendingRelaunchCount; 214 215 private boolean mLastContainsShowWhenLockedWindow; 216 private boolean mLastContainsDismissKeyguardWindow; 217 218 ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>(); 219 ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>(); 220 221 private boolean mDisablePreviewScreenshots; 222 223 private Task mLastParent; 224 225 /** 226 * See {@link #canTurnScreenOn()} 227 */ 228 private boolean mCanTurnScreenOn = true; 229 230 /** 231 * If we are running an animation, this determines the transition type. Must be one of 232 * AppTransition.TRANSIT_* constants. 233 */ 234 private int mTransit; 235 236 /** 237 * If we are running an animation, this determines the flags during this animation. Must be a 238 * bitwise combination of AppTransition.TRANSIT_FLAG_* constants. 239 */ 240 private int mTransitFlags; 241 242 /** Whether our surface was set to be showing in the last call to {@link #prepareSurfaces} */ 243 private boolean mLastSurfaceShowing = true; 244 245 private AppWindowThumbnail mThumbnail; 246 247 /** Have we been asked to have this token keep the screen frozen? */ 248 private boolean mFreezingScreen; 249 250 /** Whether this token should be boosted at the top of all app window tokens. */ 251 private boolean mNeedsZBoost; 252 private Letterbox mLetterbox; 253 254 private final Point mTmpPoint = new Point(); 255 private final Rect mTmpRect = new Rect(); 256 private RemoteAnimationDefinition mRemoteAnimationDefinition; 257 private AnimatingAppWindowTokenRegistry mAnimatingAppWindowTokenRegistry; 258 259 /** 260 * A flag to determine if this AWT is in the process of closing or entering PIP. This is needed 261 * to help AWT know that the app is in the process of closing but hasn't yet started closing on 262 * the WM side. 263 */ 264 private boolean mWillCloseOrEnterPip; 265 AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint, int configChanges, boolean launchTaskBehind, boolean alwaysFocusable, AppWindowContainerController controller)266 AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction, 267 DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen, 268 boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint, 269 int configChanges, boolean launchTaskBehind, boolean alwaysFocusable, 270 AppWindowContainerController controller) { 271 this(service, token, voiceInteraction, dc, fullscreen); 272 setController(controller); 273 mInputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos; 274 mShowForAllUsers = showForAllUsers; 275 mTargetSdk = targetSdk; 276 mOrientation = orientation; 277 layoutConfigChanges = (configChanges & (CONFIG_SCREEN_SIZE | CONFIG_ORIENTATION)) != 0; 278 mLaunchTaskBehind = launchTaskBehind; 279 mAlwaysFocusable = alwaysFocusable; 280 mRotationAnimationHint = rotationAnimationHint; 281 282 // Application tokens start out hidden. 283 setHidden(true); 284 hiddenRequested = true; 285 } 286 AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction, DisplayContent dc, boolean fillsParent)287 AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction, 288 DisplayContent dc, boolean fillsParent) { 289 super(service, token != null ? token.asBinder() : null, TYPE_APPLICATION, true, dc, 290 false /* ownerCanManageAppTokens */); 291 appToken = token; 292 mVoiceInteraction = voiceInteraction; 293 mFillsParent = fillsParent; 294 mInputApplicationHandle = new InputApplicationHandle(this); 295 } 296 onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator)297 void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) { 298 firstWindowDrawn = true; 299 300 // We now have a good window to show, remove dead placeholders 301 removeDeadWindows(); 302 303 if (startingWindow != null) { 304 if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Slog.v(TAG, "Finish starting " 305 + win.mToken + ": first real window is shown, no animation"); 306 // If this initial window is animating, stop it -- we will do an animation to reveal 307 // it from behind the starting window, so there is no need for it to also be doing its 308 // own stuff. 309 win.cancelAnimation(); 310 if (getController() != null) { 311 getController().removeStartingWindow(); 312 } 313 } 314 updateReportedVisibilityLocked(); 315 } 316 updateReportedVisibilityLocked()317 void updateReportedVisibilityLocked() { 318 if (appToken == null) { 319 return; 320 } 321 322 if (DEBUG_VISIBILITY) Slog.v(TAG, "Update reported visibility: " + this); 323 final int count = mChildren.size(); 324 325 mReportedVisibilityResults.reset(); 326 327 for (int i = 0; i < count; i++) { 328 final WindowState win = mChildren.get(i); 329 win.updateReportedVisibility(mReportedVisibilityResults); 330 } 331 332 int numInteresting = mReportedVisibilityResults.numInteresting; 333 int numVisible = mReportedVisibilityResults.numVisible; 334 int numDrawn = mReportedVisibilityResults.numDrawn; 335 boolean nowGone = mReportedVisibilityResults.nowGone; 336 337 boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting; 338 boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting && !isHidden(); 339 if (!nowGone) { 340 // If the app is not yet gone, then it can only become visible/drawn. 341 if (!nowDrawn) { 342 nowDrawn = reportedDrawn; 343 } 344 if (!nowVisible) { 345 nowVisible = reportedVisible; 346 } 347 } 348 if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting=" 349 + numInteresting + " visible=" + numVisible); 350 final AppWindowContainerController controller = getController(); 351 if (nowDrawn != reportedDrawn) { 352 if (nowDrawn) { 353 if (controller != null) { 354 controller.reportWindowsDrawn(); 355 } 356 } 357 reportedDrawn = nowDrawn; 358 } 359 if (nowVisible != reportedVisible) { 360 if (DEBUG_VISIBILITY) Slog.v(TAG, 361 "Visibility changed in " + this + ": vis=" + nowVisible); 362 reportedVisible = nowVisible; 363 if (controller != null) { 364 if (nowVisible) { 365 controller.reportWindowsVisible(); 366 } else { 367 controller.reportWindowsGone(); 368 } 369 } 370 } 371 } 372 isClientHidden()373 boolean isClientHidden() { 374 return mClientHidden; 375 } 376 setClientHidden(boolean hideClient)377 void setClientHidden(boolean hideClient) { 378 if (mClientHidden == hideClient || (hideClient && mDeferHidingClient)) { 379 return; 380 } 381 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "setClientHidden: " + this 382 + " clientHidden=" + hideClient + " Callers=" + Debug.getCallers(5)); 383 mClientHidden = hideClient; 384 sendAppVisibilityToClients(); 385 } 386 setVisibility(WindowManager.LayoutParams lp, boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction)387 boolean setVisibility(WindowManager.LayoutParams lp, 388 boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction) { 389 390 boolean delayed = false; 391 inPendingTransaction = false; 392 // Reset the state of mHiddenSetFromTransferredStartingWindow since visibility is actually 393 // been set by the app now. 394 mHiddenSetFromTransferredStartingWindow = false; 395 396 // Allow for state changes and animation to be applied if: 397 // * token is transitioning visibility state 398 // * or the token was marked as hidden and is exiting before we had a chance to play the 399 // transition animation 400 // * or this is an opening app and windows are being replaced. 401 boolean visibilityChanged = false; 402 if (isHidden() == visible || (isHidden() && mIsExiting) || (visible && waitingForReplacement())) { 403 final AccessibilityController accessibilityController = mService.mAccessibilityController; 404 boolean changed = false; 405 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, 406 "Changing app " + this + " hidden=" + isHidden() + " performLayout=" + performLayout); 407 408 boolean runningAppAnimation = false; 409 410 if (transit != WindowManager.TRANSIT_UNSET) { 411 if (applyAnimationLocked(lp, transit, visible, isVoiceInteraction)) { 412 delayed = runningAppAnimation = true; 413 } 414 final WindowState window = findMainWindow(); 415 //TODO (multidisplay): Magnification is supported only for the default display. 416 if (window != null && accessibilityController != null 417 && getDisplayContent().getDisplayId() == DEFAULT_DISPLAY) { 418 accessibilityController.onAppWindowTransitionLocked(window, transit); 419 } 420 changed = true; 421 } 422 423 final int windowsCount = mChildren.size(); 424 for (int i = 0; i < windowsCount; i++) { 425 final WindowState win = mChildren.get(i); 426 changed |= win.onAppVisibilityChanged(visible, runningAppAnimation); 427 } 428 429 setHidden(!visible); 430 hiddenRequested = !visible; 431 visibilityChanged = true; 432 if (!visible) { 433 stopFreezingScreen(true, true); 434 } else { 435 // If we are being set visible, and the starting window is not yet displayed, 436 // then make sure it doesn't get displayed. 437 if (startingWindow != null && !startingWindow.isDrawnLw()) { 438 startingWindow.mPolicyVisibility = false; 439 startingWindow.mPolicyVisibilityAfterAnim = false; 440 } 441 442 // We are becoming visible, so better freeze the screen with the windows that are 443 // getting visible so we also wait for them. 444 forAllWindows(mService::makeWindowFreezingScreenIfNeededLocked, true); 445 } 446 447 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "setVisibility: " + this 448 + ": hidden=" + isHidden() + " hiddenRequested=" + hiddenRequested); 449 450 if (changed) { 451 mService.mInputMonitor.setUpdateInputWindowsNeededLw(); 452 if (performLayout) { 453 mService.updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, 454 false /*updateInputWindows*/); 455 mService.mWindowPlacerLocked.performSurfacePlacement(); 456 } 457 mService.mInputMonitor.updateInputWindowsLw(false /*force*/); 458 } 459 } 460 461 if (isReallyAnimating()) { 462 delayed = true; 463 } else { 464 465 // We aren't animating anything, but exiting windows rely on the animation finished 466 // callback being called in case the AppWindowToken was pretending to be animating, 467 // which we might have done because we were in closing/opening apps list. 468 onAnimationFinished(); 469 } 470 471 for (int i = mChildren.size() - 1; i >= 0 && !delayed; i--) { 472 if ((mChildren.get(i)).isSelfOrChildAnimating()) { 473 delayed = true; 474 } 475 } 476 477 if (visibilityChanged) { 478 if (visible && !delayed) { 479 // The token was made immediately visible, there will be no entrance animation. 480 // We need to inform the client the enter animation was finished. 481 mEnteringAnimation = true; 482 mService.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(token); 483 } 484 485 // If we're becoming visible, immediately change client visibility as well although it 486 // usually gets changed in AppWindowContainerController.setVisibility already. However, 487 // there seem to be some edge cases where we change our visibility but client visibility 488 // never gets updated. 489 // If we're becoming invisible, update the client visibility if we are not running an 490 // animation. Otherwise, we'll update client visibility in onAnimationFinished. 491 if (visible || !isReallyAnimating()) { 492 setClientHidden(!visible); 493 } 494 495 if (!mService.mClosingApps.contains(this) && !mService.mOpeningApps.contains(this)) { 496 // The token is not closing nor opening, so even if there is an animation set, that 497 // doesn't mean that it goes through the normal app transition cycle so we have 498 // to inform the docked controller about visibility change. 499 // TODO(multi-display): notify docked divider on all displays where visibility was 500 // affected. 501 mService.getDefaultDisplayContentLocked().getDockedDividerController() 502 .notifyAppVisibilityChanged(); 503 504 // Take the screenshot before possibly hiding the WSA, otherwise the screenshot 505 // will not be taken. 506 mService.mTaskSnapshotController.notifyAppVisibilityChanged(this, visible); 507 } 508 509 // If we are hidden but there is no delay needed we immediately 510 // apply the Surface transaction so that the ActivityManager 511 // can have some guarantee on the Surface state following 512 // setting the visibility. This captures cases like dismissing 513 // the docked or pinned stack where there is no app transition. 514 // 515 // In the case of a "Null" animation, there will be 516 // no animation but there will still be a transition set. 517 // We still need to delay hiding the surface such that it 518 // can be synchronized with showing the next surface in the transition. 519 if (isHidden() && !delayed && !mService.mAppTransition.isTransitionSet()) { 520 SurfaceControl.openTransaction(); 521 for (int i = mChildren.size() - 1; i >= 0; i--) { 522 mChildren.get(i).mWinAnimator.hide("immediately hidden"); 523 } 524 SurfaceControl.closeTransaction(); 525 } 526 } 527 528 return delayed; 529 } 530 531 /** 532 * @return The to top most child window for which {@link LayoutParams#isFullscreen()} returns 533 * true. 534 */ getTopFullscreenWindow()535 WindowState getTopFullscreenWindow() { 536 for (int i = mChildren.size() - 1; i >= 0; i--) { 537 final WindowState win = mChildren.get(i); 538 if (win != null && win.mAttrs.isFullscreen()) { 539 return win; 540 } 541 } 542 return null; 543 } 544 findMainWindow()545 WindowState findMainWindow() { 546 return findMainWindow(true); 547 } 548 549 /** 550 * Finds the main window that either has type base application or application starting if 551 * requested. 552 * 553 * @param includeStartingApp Allow to search application-starting windows to also be returned. 554 * @return The main window of type base application or application starting if requested. 555 */ findMainWindow(boolean includeStartingApp)556 WindowState findMainWindow(boolean includeStartingApp) { 557 WindowState candidate = null; 558 for (int j = mChildren.size() - 1; j >= 0; --j) { 559 final WindowState win = mChildren.get(j); 560 final int type = win.mAttrs.type; 561 // No need to loop through child window as base application and starting types can't be 562 // child windows. 563 if (type == TYPE_BASE_APPLICATION 564 || (includeStartingApp && type == TYPE_APPLICATION_STARTING)) { 565 // In cases where there are multiple windows, we prefer the non-exiting window. This 566 // happens for example when replacing windows during an activity relaunch. When 567 // constructing the animation, we want the new window, not the exiting one. 568 if (win.mAnimatingExit) { 569 candidate = win; 570 } else { 571 return win; 572 } 573 } 574 } 575 return candidate; 576 } 577 windowsAreFocusable()578 boolean windowsAreFocusable() { 579 return getWindowConfiguration().canReceiveKeys() || mAlwaysFocusable; 580 } 581 getController()582 AppWindowContainerController getController() { 583 final WindowContainerController controller = super.getController(); 584 return controller != null ? (AppWindowContainerController) controller : null; 585 } 586 587 @Override isVisible()588 boolean isVisible() { 589 // If the app token isn't hidden then it is considered visible and there is no need to check 590 // its children windows to see if they are visible. 591 return !isHidden(); 592 } 593 594 @Override removeImmediately()595 void removeImmediately() { 596 onRemovedFromDisplay(); 597 super.removeImmediately(); 598 } 599 600 @Override removeIfPossible()601 void removeIfPossible() { 602 mIsExiting = false; 603 removeAllWindowsIfPossible(); 604 removeImmediately(); 605 } 606 607 @Override checkCompleteDeferredRemoval()608 boolean checkCompleteDeferredRemoval() { 609 if (mIsExiting) { 610 removeIfPossible(); 611 } 612 return super.checkCompleteDeferredRemoval(); 613 } 614 onRemovedFromDisplay()615 void onRemovedFromDisplay() { 616 if (mRemovingFromDisplay) { 617 return; 618 } 619 mRemovingFromDisplay = true; 620 621 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app token: " + this); 622 623 boolean delayed = setVisibility(null, false, TRANSIT_UNSET, true, mVoiceInteraction); 624 625 mService.mOpeningApps.remove(this); 626 mService.mUnknownAppVisibilityController.appRemovedOrHidden(this); 627 mService.mTaskSnapshotController.onAppRemoved(this); 628 waitingToShow = false; 629 if (mService.mClosingApps.contains(this)) { 630 delayed = true; 631 } else if (mService.mAppTransition.isTransitionSet()) { 632 mService.mClosingApps.add(this); 633 delayed = true; 634 } 635 636 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app " + this + " delayed=" + delayed 637 + " animation=" + getAnimation() + " animating=" + isSelfAnimating()); 638 639 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM, "removeAppToken: " 640 + this + " delayed=" + delayed + " Callers=" + Debug.getCallers(4)); 641 642 if (startingData != null && getController() != null) { 643 getController().removeStartingWindow(); 644 } 645 646 // If this window was animating, then we need to ensure that the app transition notifies 647 // that animations have completed in WMS.handleAnimatingStoppedAndTransitionLocked(), so 648 // add to that list now 649 if (isSelfAnimating()) { 650 mService.mNoAnimationNotifyOnTransitionFinished.add(token); 651 } 652 653 final TaskStack stack = getStack(); 654 if (delayed && !isEmpty()) { 655 // set the token aside because it has an active animation to be finished 656 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM, 657 "removeAppToken make exiting: " + this); 658 if (stack != null) { 659 stack.mExitingAppTokens.add(this); 660 } 661 mIsExiting = true; 662 } else { 663 // Make sure there is no animation running on this token, so any windows associated 664 // with it will be removed as soon as their animations are complete 665 cancelAnimation(); 666 if (stack != null) { 667 stack.mExitingAppTokens.remove(this); 668 } 669 removeIfPossible(); 670 } 671 672 removed = true; 673 stopFreezingScreen(true, true); 674 675 if (mService.mFocusedApp == this) { 676 if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Removing focused app token:" + this); 677 mService.mFocusedApp = null; 678 mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/); 679 mService.mInputMonitor.setFocusedAppLw(null); 680 } 681 682 if (!delayed) { 683 updateReportedVisibilityLocked(); 684 } 685 686 mRemovingFromDisplay = false; 687 } 688 clearAnimatingFlags()689 void clearAnimatingFlags() { 690 boolean wallpaperMightChange = false; 691 for (int i = mChildren.size() - 1; i >= 0; i--) { 692 final WindowState win = mChildren.get(i); 693 wallpaperMightChange |= win.clearAnimatingFlags(); 694 } 695 if (wallpaperMightChange) { 696 requestUpdateWallpaperIfNeeded(); 697 } 698 } 699 destroySurfaces()700 void destroySurfaces() { 701 destroySurfaces(false /*cleanupOnResume*/); 702 } 703 704 /** 705 * Destroy surfaces which have been marked as eligible by the animator, taking care to ensure 706 * the client has finished with them. 707 * 708 * @param cleanupOnResume whether this is done when app is resumed without fully stopped. If 709 * set to true, destroy only surfaces of removed windows, and clear relevant flags of the 710 * others so that they are ready to be reused. If set to false (common case), destroy all 711 * surfaces that's eligible, if the app is already stopped. 712 */ destroySurfaces(boolean cleanupOnResume)713 private void destroySurfaces(boolean cleanupOnResume) { 714 boolean destroyedSomething = false; 715 716 // Copying to a different list as multiple children can be removed. 717 final ArrayList<WindowState> children = new ArrayList<>(mChildren); 718 for (int i = children.size() - 1; i >= 0; i--) { 719 final WindowState win = children.get(i); 720 destroyedSomething |= win.destroySurface(cleanupOnResume, mAppStopped); 721 } 722 if (destroyedSomething) { 723 final DisplayContent dc = getDisplayContent(); 724 dc.assignWindowLayers(true /*setLayoutNeeded*/); 725 updateLetterboxSurface(null); 726 } 727 } 728 729 /** 730 * Notify that the app is now resumed, and it was not stopped before, perform a clean 731 * up of the surfaces 732 */ notifyAppResumed(boolean wasStopped)733 void notifyAppResumed(boolean wasStopped) { 734 if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppResumed: wasStopped=" + wasStopped 735 + " " + this); 736 mAppStopped = false; 737 // Allow the window to turn the screen on once the app is resumed again. 738 setCanTurnScreenOn(true); 739 if (!wasStopped) { 740 destroySurfaces(true /*cleanupOnResume*/); 741 } 742 } 743 744 /** 745 * Notify that the app has stopped, and it is okay to destroy any surfaces which were 746 * keeping alive in case they were still being used. 747 */ notifyAppStopped()748 void notifyAppStopped() { 749 if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppStopped: " + this); 750 mAppStopped = true; 751 destroySurfaces(); 752 // Remove any starting window that was added for this app if they are still around. 753 if (getController() != null) { 754 getController().removeStartingWindow(); 755 } 756 } 757 clearAllDrawn()758 void clearAllDrawn() { 759 allDrawn = false; 760 deferClearAllDrawn = false; 761 } 762 getTask()763 Task getTask() { 764 return (Task) getParent(); 765 } 766 getStack()767 TaskStack getStack() { 768 final Task task = getTask(); 769 if (task != null) { 770 return task.mStack; 771 } else { 772 return null; 773 } 774 } 775 776 @Override onParentSet()777 void onParentSet() { 778 super.onParentSet(); 779 780 final Task task = getTask(); 781 782 // When the associated task is {@code null}, the {@link AppWindowToken} can no longer 783 // access visual elements like the {@link DisplayContent}. We must remove any associations 784 // such as animations. 785 if (!mReparenting) { 786 if (task == null) { 787 // It is possible we have been marked as a closing app earlier. We must remove ourselves 788 // from this list so we do not participate in any future animations. 789 mService.mClosingApps.remove(this); 790 } else if (mLastParent != null && mLastParent.mStack != null) { 791 task.mStack.mExitingAppTokens.remove(this); 792 } 793 } 794 final TaskStack stack = getStack(); 795 796 // If we reparent, make sure to remove ourselves from the old animation registry. 797 if (mAnimatingAppWindowTokenRegistry != null) { 798 mAnimatingAppWindowTokenRegistry.notifyFinished(this); 799 } 800 mAnimatingAppWindowTokenRegistry = stack != null 801 ? stack.getAnimatingAppWindowTokenRegistry() 802 : null; 803 804 mLastParent = task; 805 } 806 postWindowRemoveStartingWindowCleanup(WindowState win)807 void postWindowRemoveStartingWindowCleanup(WindowState win) { 808 // TODO: Something smells about the code below...Is there a better way? 809 if (startingWindow == win) { 810 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Notify removed startingWindow " + win); 811 if (getController() != null) { 812 getController().removeStartingWindow(); 813 } 814 } else if (mChildren.size() == 0) { 815 // If this is the last window and we had requested a starting transition window, 816 // well there is no point now. 817 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Nulling last startingData"); 818 startingData = null; 819 if (mHiddenSetFromTransferredStartingWindow) { 820 // We set the hidden state to false for the token from a transferred starting window. 821 // We now reset it back to true since the starting window was the last window in the 822 // token. 823 setHidden(true); 824 } 825 } else if (mChildren.size() == 1 && startingSurface != null && !isRelaunching()) { 826 // If this is the last window except for a starting transition window, 827 // we need to get rid of the starting transition. 828 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Last window, removing starting window " 829 + win); 830 if (getController() != null) { 831 getController().removeStartingWindow(); 832 } 833 } 834 } 835 removeDeadWindows()836 void removeDeadWindows() { 837 for (int winNdx = mChildren.size() - 1; winNdx >= 0; --winNdx) { 838 WindowState win = mChildren.get(winNdx); 839 if (win.mAppDied) { 840 if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.w(TAG, 841 "removeDeadWindows: " + win); 842 // Set mDestroying, we don't want any animation or delayed removal here. 843 win.mDestroying = true; 844 // Also removes child windows. 845 win.removeIfPossible(); 846 } 847 } 848 } 849 hasWindowsAlive()850 boolean hasWindowsAlive() { 851 for (int i = mChildren.size() - 1; i >= 0; i--) { 852 // No need to loop through child windows as the answer should be the same as that of the 853 // parent window. 854 if (!(mChildren.get(i)).mAppDied) { 855 return true; 856 } 857 } 858 return false; 859 } 860 setWillReplaceWindows(boolean animate)861 void setWillReplaceWindows(boolean animate) { 862 if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, 863 "Marking app token " + this + " with replacing windows."); 864 865 for (int i = mChildren.size() - 1; i >= 0; i--) { 866 final WindowState w = mChildren.get(i); 867 w.setWillReplaceWindow(animate); 868 } 869 } 870 setWillReplaceChildWindows()871 void setWillReplaceChildWindows() { 872 if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + this 873 + " with replacing child windows."); 874 for (int i = mChildren.size() - 1; i >= 0; i--) { 875 final WindowState w = mChildren.get(i); 876 w.setWillReplaceChildWindows(); 877 } 878 } 879 clearWillReplaceWindows()880 void clearWillReplaceWindows() { 881 if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, 882 "Resetting app token " + this + " of replacing window marks."); 883 884 for (int i = mChildren.size() - 1; i >= 0; i--) { 885 final WindowState w = mChildren.get(i); 886 w.clearWillReplaceWindow(); 887 } 888 } 889 requestUpdateWallpaperIfNeeded()890 void requestUpdateWallpaperIfNeeded() { 891 for (int i = mChildren.size() - 1; i >= 0; i--) { 892 final WindowState w = mChildren.get(i); 893 w.requestUpdateWallpaperIfNeeded(); 894 } 895 } 896 isRelaunching()897 boolean isRelaunching() { 898 return mPendingRelaunchCount > 0; 899 } 900 shouldFreezeBounds()901 boolean shouldFreezeBounds() { 902 final Task task = getTask(); 903 904 // For freeform windows, we can't freeze the bounds at the moment because this would make 905 // the resizing unresponsive. 906 if (task == null || task.inFreeformWindowingMode()) { 907 return false; 908 } 909 910 // We freeze the bounds while drag resizing to deal with the time between 911 // the divider/drag handle being released, and the handling it's new 912 // configuration. If we are relaunched outside of the drag resizing state, 913 // we need to be careful not to do this. 914 return getTask().isDragResizing(); 915 } 916 startRelaunching()917 void startRelaunching() { 918 if (shouldFreezeBounds()) { 919 freezeBounds(); 920 } 921 922 // In the process of tearing down before relaunching, the app will 923 // try and clean up it's child surfaces. We need to prevent this from 924 // happening, so we sever the children, transfering their ownership 925 // from the client it-self to the parent surface (owned by us). 926 detachChildren(); 927 928 mPendingRelaunchCount++; 929 } 930 detachChildren()931 void detachChildren() { 932 SurfaceControl.openTransaction(); 933 for (int i = mChildren.size() - 1; i >= 0; i--) { 934 final WindowState w = mChildren.get(i); 935 w.mWinAnimator.detachChildren(); 936 } 937 SurfaceControl.closeTransaction(); 938 } 939 finishRelaunching()940 void finishRelaunching() { 941 unfreezeBounds(); 942 943 if (mPendingRelaunchCount > 0) { 944 mPendingRelaunchCount--; 945 } else { 946 // Update keyguard flags upon finishing relaunch. 947 checkKeyguardFlagsChanged(); 948 } 949 } 950 clearRelaunching()951 void clearRelaunching() { 952 if (mPendingRelaunchCount == 0) { 953 return; 954 } 955 unfreezeBounds(); 956 mPendingRelaunchCount = 0; 957 } 958 959 /** 960 * Returns true if the new child window we are adding to this token is considered greater than 961 * the existing child window in this token in terms of z-order. 962 */ 963 @Override isFirstChildWindowGreaterThanSecond(WindowState newWindow, WindowState existingWindow)964 protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow, 965 WindowState existingWindow) { 966 final int type1 = newWindow.mAttrs.type; 967 final int type2 = existingWindow.mAttrs.type; 968 969 // Base application windows should be z-ordered BELOW all other windows in the app token. 970 if (type1 == TYPE_BASE_APPLICATION && type2 != TYPE_BASE_APPLICATION) { 971 return false; 972 } else if (type1 != TYPE_BASE_APPLICATION && type2 == TYPE_BASE_APPLICATION) { 973 return true; 974 } 975 976 // Starting windows should be z-ordered ABOVE all other windows in the app token. 977 if (type1 == TYPE_APPLICATION_STARTING && type2 != TYPE_APPLICATION_STARTING) { 978 return true; 979 } else if (type1 != TYPE_APPLICATION_STARTING && type2 == TYPE_APPLICATION_STARTING) { 980 return false; 981 } 982 983 // Otherwise the new window is greater than the existing window. 984 return true; 985 } 986 987 @Override addWindow(WindowState w)988 void addWindow(WindowState w) { 989 super.addWindow(w); 990 991 boolean gotReplacementWindow = false; 992 for (int i = mChildren.size() - 1; i >= 0; i--) { 993 final WindowState candidate = mChildren.get(i); 994 gotReplacementWindow |= candidate.setReplacementWindowIfNeeded(w); 995 } 996 997 // if we got a replacement window, reset the timeout to give drawing more time 998 if (gotReplacementWindow) { 999 mService.scheduleWindowReplacementTimeouts(this); 1000 } 1001 checkKeyguardFlagsChanged(); 1002 } 1003 1004 @Override removeChild(WindowState child)1005 void removeChild(WindowState child) { 1006 super.removeChild(child); 1007 checkKeyguardFlagsChanged(); 1008 updateLetterboxSurface(child); 1009 } 1010 waitingForReplacement()1011 private boolean waitingForReplacement() { 1012 for (int i = mChildren.size() - 1; i >= 0; i--) { 1013 final WindowState candidate = mChildren.get(i); 1014 if (candidate.waitingForReplacement()) { 1015 return true; 1016 } 1017 } 1018 return false; 1019 } 1020 onWindowReplacementTimeout()1021 void onWindowReplacementTimeout() { 1022 for (int i = mChildren.size() - 1; i >= 0; --i) { 1023 (mChildren.get(i)).onWindowReplacementTimeout(); 1024 } 1025 } 1026 reparent(Task task, int position)1027 void reparent(Task task, int position) { 1028 final Task currentTask = getTask(); 1029 if (task == currentTask) { 1030 throw new IllegalArgumentException( 1031 "window token=" + this + " already child of task=" + currentTask); 1032 } 1033 1034 if (currentTask.mStack != task.mStack) { 1035 throw new IllegalArgumentException( 1036 "window token=" + this + " current task=" + currentTask 1037 + " belongs to a different stack than " + task); 1038 } 1039 1040 if (DEBUG_ADD_REMOVE) Slog.i(TAG, "reParentWindowToken: removing window token=" + this 1041 + " from task=" + currentTask); 1042 final DisplayContent prevDisplayContent = getDisplayContent(); 1043 1044 mReparenting = true; 1045 1046 getParent().removeChild(this); 1047 task.addChild(this, position); 1048 1049 mReparenting = false; 1050 1051 // Relayout display(s). 1052 final DisplayContent displayContent = task.getDisplayContent(); 1053 displayContent.setLayoutNeeded(); 1054 if (prevDisplayContent != displayContent) { 1055 onDisplayChanged(displayContent); 1056 prevDisplayContent.setLayoutNeeded(); 1057 } 1058 } 1059 1060 /** 1061 * Freezes the task bounds. The size of this task reported the app will be fixed to the bounds 1062 * freezed by {@link Task#prepareFreezingBounds} until {@link #unfreezeBounds} gets called, even 1063 * if they change in the meantime. If the bounds are already frozen, the bounds will be frozen 1064 * with a queue. 1065 */ freezeBounds()1066 private void freezeBounds() { 1067 final Task task = getTask(); 1068 mFrozenBounds.offer(new Rect(task.mPreparedFrozenBounds)); 1069 1070 if (task.mPreparedFrozenMergedConfig.equals(Configuration.EMPTY)) { 1071 // We didn't call prepareFreezingBounds on the task, so use the current value. 1072 mFrozenMergedConfig.offer(new Configuration(task.getConfiguration())); 1073 } else { 1074 mFrozenMergedConfig.offer(new Configuration(task.mPreparedFrozenMergedConfig)); 1075 } 1076 // Calling unset() to make it equal to Configuration.EMPTY. 1077 task.mPreparedFrozenMergedConfig.unset(); 1078 } 1079 1080 /** 1081 * Unfreezes the previously frozen bounds. See {@link #freezeBounds}. 1082 */ unfreezeBounds()1083 private void unfreezeBounds() { 1084 if (mFrozenBounds.isEmpty()) { 1085 return; 1086 } 1087 mFrozenBounds.remove(); 1088 if (!mFrozenMergedConfig.isEmpty()) { 1089 mFrozenMergedConfig.remove(); 1090 } 1091 for (int i = mChildren.size() - 1; i >= 0; i--) { 1092 final WindowState win = mChildren.get(i); 1093 win.onUnfreezeBounds(); 1094 } 1095 mService.mWindowPlacerLocked.performSurfacePlacement(); 1096 } 1097 setAppLayoutChanges(int changes, String reason)1098 void setAppLayoutChanges(int changes, String reason) { 1099 if (!mChildren.isEmpty()) { 1100 final DisplayContent dc = getDisplayContent(); 1101 dc.pendingLayoutChanges |= changes; 1102 if (DEBUG_LAYOUT_REPEATS) { 1103 mService.mWindowPlacerLocked.debugLayoutRepeats(reason, dc.pendingLayoutChanges); 1104 } 1105 } 1106 } 1107 removeReplacedWindowIfNeeded(WindowState replacement)1108 void removeReplacedWindowIfNeeded(WindowState replacement) { 1109 for (int i = mChildren.size() - 1; i >= 0; i--) { 1110 final WindowState win = mChildren.get(i); 1111 if (win.removeReplacedWindowIfNeeded(replacement)) { 1112 return; 1113 } 1114 } 1115 } 1116 startFreezingScreen()1117 void startFreezingScreen() { 1118 if (DEBUG_ORIENTATION) logWithStack(TAG, "Set freezing of " + appToken + ": hidden=" 1119 + isHidden() + " freezing=" + mFreezingScreen + " hiddenRequested=" 1120 + hiddenRequested); 1121 if (!hiddenRequested) { 1122 if (!mFreezingScreen) { 1123 mFreezingScreen = true; 1124 mService.registerAppFreezeListener(this); 1125 mService.mAppsFreezingScreen++; 1126 if (mService.mAppsFreezingScreen == 1) { 1127 mService.startFreezingDisplayLocked(0, 0, getDisplayContent()); 1128 mService.mH.removeMessages(H.APP_FREEZE_TIMEOUT); 1129 mService.mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000); 1130 } 1131 } 1132 final int count = mChildren.size(); 1133 for (int i = 0; i < count; i++) { 1134 final WindowState w = mChildren.get(i); 1135 w.onStartFreezingScreen(); 1136 } 1137 } 1138 } 1139 stopFreezingScreen(boolean unfreezeSurfaceNow, boolean force)1140 void stopFreezingScreen(boolean unfreezeSurfaceNow, boolean force) { 1141 if (!mFreezingScreen) { 1142 return; 1143 } 1144 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + this + " force=" + force); 1145 final int count = mChildren.size(); 1146 boolean unfrozeWindows = false; 1147 for (int i = 0; i < count; i++) { 1148 final WindowState w = mChildren.get(i); 1149 unfrozeWindows |= w.onStopFreezingScreen(); 1150 } 1151 if (force || unfrozeWindows) { 1152 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "No longer freezing: " + this); 1153 mFreezingScreen = false; 1154 mService.unregisterAppFreezeListener(this); 1155 mService.mAppsFreezingScreen--; 1156 mService.mLastFinishedFreezeSource = this; 1157 } 1158 if (unfreezeSurfaceNow) { 1159 if (unfrozeWindows) { 1160 mService.mWindowPlacerLocked.performSurfacePlacement(); 1161 } 1162 mService.stopFreezingDisplayLocked(); 1163 } 1164 } 1165 1166 @Override onAppFreezeTimeout()1167 public void onAppFreezeTimeout() { 1168 Slog.w(TAG_WM, "Force clearing freeze: " + this); 1169 stopFreezingScreen(true, true); 1170 } 1171 1172 /** 1173 * Tries to transfer the starting window from a token that's above ourselves in the task but 1174 * not visible anymore. This is a common scenario apps use: Trampoline activity T start main 1175 * activity M in the same task. Now, when reopening the task, T starts on top of M but then 1176 * immediately finishes after, so we have to transfer T to M. 1177 */ transferStartingWindowFromHiddenAboveTokenIfNeeded()1178 void transferStartingWindowFromHiddenAboveTokenIfNeeded() { 1179 final Task task = getTask(); 1180 for (int i = task.mChildren.size() - 1; i >= 0; i--) { 1181 final AppWindowToken fromToken = task.mChildren.get(i); 1182 if (fromToken == this) { 1183 return; 1184 } 1185 if (fromToken.hiddenRequested && transferStartingWindow(fromToken.token)) { 1186 return; 1187 } 1188 } 1189 } 1190 transferStartingWindow(IBinder transferFrom)1191 boolean transferStartingWindow(IBinder transferFrom) { 1192 final AppWindowToken fromToken = getDisplayContent().getAppWindowToken(transferFrom); 1193 if (fromToken == null) { 1194 return false; 1195 } 1196 1197 final WindowState tStartingWindow = fromToken.startingWindow; 1198 if (tStartingWindow != null && fromToken.startingSurface != null) { 1199 // In this case, the starting icon has already been displayed, so start 1200 // letting windows get shown immediately without any more transitions. 1201 mService.mSkipAppTransitionAnimation = true; 1202 1203 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Moving existing starting " + tStartingWindow 1204 + " from " + fromToken + " to " + this); 1205 1206 final long origId = Binder.clearCallingIdentity(); 1207 try { 1208 // Transfer the starting window over to the new token. 1209 startingData = fromToken.startingData; 1210 startingSurface = fromToken.startingSurface; 1211 startingDisplayed = fromToken.startingDisplayed; 1212 fromToken.startingDisplayed = false; 1213 startingWindow = tStartingWindow; 1214 reportedVisible = fromToken.reportedVisible; 1215 fromToken.startingData = null; 1216 fromToken.startingSurface = null; 1217 fromToken.startingWindow = null; 1218 fromToken.startingMoved = true; 1219 tStartingWindow.mToken = this; 1220 tStartingWindow.mAppToken = this; 1221 1222 if (DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, 1223 "Removing starting " + tStartingWindow + " from " + fromToken); 1224 fromToken.removeChild(tStartingWindow); 1225 fromToken.postWindowRemoveStartingWindowCleanup(tStartingWindow); 1226 fromToken.mHiddenSetFromTransferredStartingWindow = false; 1227 addWindow(tStartingWindow); 1228 1229 // Propagate other interesting state between the tokens. If the old token is displayed, 1230 // we should immediately force the new one to be displayed. If it is animating, we need 1231 // to move that animation to the new one. 1232 if (fromToken.allDrawn) { 1233 allDrawn = true; 1234 deferClearAllDrawn = fromToken.deferClearAllDrawn; 1235 } 1236 if (fromToken.firstWindowDrawn) { 1237 firstWindowDrawn = true; 1238 } 1239 if (!fromToken.isHidden()) { 1240 setHidden(false); 1241 hiddenRequested = false; 1242 mHiddenSetFromTransferredStartingWindow = true; 1243 } 1244 setClientHidden(fromToken.mClientHidden); 1245 1246 transferAnimation(fromToken); 1247 1248 // When transferring an animation, we no longer need to apply an animation to the 1249 // the token we transfer the animation over. Thus, remove the animation from 1250 // pending opening apps. 1251 mService.mOpeningApps.remove(this); 1252 1253 mService.updateFocusedWindowLocked( 1254 UPDATE_FOCUS_WILL_PLACE_SURFACES, true /*updateInputWindows*/); 1255 getDisplayContent().setLayoutNeeded(); 1256 mService.mWindowPlacerLocked.performSurfacePlacement(); 1257 } finally { 1258 Binder.restoreCallingIdentity(origId); 1259 } 1260 return true; 1261 } else if (fromToken.startingData != null) { 1262 // The previous app was getting ready to show a 1263 // starting window, but hasn't yet done so. Steal it! 1264 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, 1265 "Moving pending starting from " + fromToken + " to " + this); 1266 startingData = fromToken.startingData; 1267 fromToken.startingData = null; 1268 fromToken.startingMoved = true; 1269 if (getController() != null) { 1270 getController().scheduleAddStartingWindow(); 1271 } 1272 return true; 1273 } 1274 1275 // TODO: Transfer thumbnail 1276 1277 return false; 1278 } 1279 isLastWindow(WindowState win)1280 boolean isLastWindow(WindowState win) { 1281 return mChildren.size() == 1 && mChildren.get(0) == win; 1282 } 1283 1284 @Override onAppTransitionDone()1285 void onAppTransitionDone() { 1286 sendingToBottom = false; 1287 } 1288 1289 /** 1290 * We override because this class doesn't want its children affecting its reported orientation 1291 * in anyway. 1292 */ 1293 @Override getOrientation(int candidate)1294 int getOrientation(int candidate) { 1295 if (candidate == SCREEN_ORIENTATION_BEHIND) { 1296 // Allow app to specify orientation regardless of its visibility state if the current 1297 // candidate want us to use orientation behind. I.e. the visible app on-top of this one 1298 // wants us to use the orientation of the app behind it. 1299 return mOrientation; 1300 } 1301 1302 // The {@link AppWindowToken} should only specify an orientation when it is not closing or 1303 // going to the bottom. Allowing closing {@link AppWindowToken} to participate can lead to 1304 // an Activity in another task being started in the wrong orientation during the transition. 1305 if (!(sendingToBottom || mService.mClosingApps.contains(this)) 1306 && (isVisible() || mService.mOpeningApps.contains(this))) { 1307 return mOrientation; 1308 } 1309 1310 return SCREEN_ORIENTATION_UNSET; 1311 } 1312 1313 /** Returns the app's preferred orientation regardless of its currently visibility state. */ getOrientationIgnoreVisibility()1314 int getOrientationIgnoreVisibility() { 1315 return mOrientation; 1316 } 1317 1318 @Override onConfigurationChanged(Configuration newParentConfig)1319 public void onConfigurationChanged(Configuration newParentConfig) { 1320 final int prevWinMode = getWindowingMode(); 1321 super.onConfigurationChanged(newParentConfig); 1322 final int winMode = getWindowingMode(); 1323 1324 if (prevWinMode == winMode) { 1325 return; 1326 } 1327 1328 if (prevWinMode != WINDOWING_MODE_UNDEFINED && winMode == WINDOWING_MODE_PINNED) { 1329 // Entering PiP from fullscreen, reset the snap fraction 1330 mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(this); 1331 } else if (prevWinMode == WINDOWING_MODE_PINNED && winMode != WINDOWING_MODE_UNDEFINED 1332 && !isHidden()) { 1333 // Leaving PiP to fullscreen, save the snap fraction based on the pre-animation bounds 1334 // for the next re-entry into PiP (assuming the activity is not hidden or destroyed) 1335 final TaskStack pinnedStack = mDisplayContent.getPinnedStack(); 1336 if (pinnedStack != null) { 1337 final Rect stackBounds; 1338 if (pinnedStack.lastAnimatingBoundsWasToFullscreen()) { 1339 // We are animating the bounds, use the pre-animation bounds to save the snap 1340 // fraction 1341 stackBounds = pinnedStack.mPreAnimationBounds; 1342 } else { 1343 // We skip the animation if the fullscreen configuration is not compatible, so 1344 // use the current bounds to calculate the saved snap fraction instead 1345 // (see PinnedActivityStack.skipResizeAnimation()) 1346 stackBounds = mTmpRect; 1347 pinnedStack.getBounds(stackBounds); 1348 } 1349 mDisplayContent.mPinnedStackControllerLocked.saveReentrySnapFraction(this, 1350 stackBounds); 1351 } 1352 } 1353 } 1354 1355 @Override checkAppWindowsReadyToShow()1356 void checkAppWindowsReadyToShow() { 1357 if (allDrawn == mLastAllDrawn) { 1358 return; 1359 } 1360 1361 mLastAllDrawn = allDrawn; 1362 if (!allDrawn) { 1363 return; 1364 } 1365 1366 // The token has now changed state to having all windows shown... what to do, what to do? 1367 if (mFreezingScreen) { 1368 showAllWindowsLocked(); 1369 stopFreezingScreen(false, true); 1370 if (DEBUG_ORIENTATION) Slog.i(TAG, 1371 "Setting mOrientationChangeComplete=true because wtoken " + this 1372 + " numInteresting=" + mNumInterestingWindows + " numDrawn=" + mNumDrawnWindows); 1373 // This will set mOrientationChangeComplete and cause a pass through layout. 1374 setAppLayoutChanges(FINISH_LAYOUT_REDO_WALLPAPER, 1375 "checkAppWindowsReadyToShow: freezingScreen"); 1376 } else { 1377 setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM, "checkAppWindowsReadyToShow"); 1378 1379 // We can now show all of the drawn windows! 1380 if (!mService.mOpeningApps.contains(this)) { 1381 showAllWindowsLocked(); 1382 } 1383 } 1384 } 1385 1386 /** 1387 * Returns whether the drawn window states of this {@link AppWindowToken} has considered every 1388 * child {@link WindowState}. A child is considered if it has been passed into 1389 * {@link #updateDrawnWindowStates(WindowState)} after being added. This is used to determine 1390 * whether states, such as {@code allDrawn}, can be set, which relies on state variables such as 1391 * {@code mNumInterestingWindows}, which depend on all {@link WindowState}s being considered. 1392 * 1393 * @return {@code true} If all children have been considered, {@code false}. 1394 */ allDrawnStatesConsidered()1395 private boolean allDrawnStatesConsidered() { 1396 for (int i = mChildren.size() - 1; i >= 0; --i) { 1397 final WindowState child = mChildren.get(i); 1398 if (child.mightAffectAllDrawn() && !child.getDrawnStateEvaluated()) { 1399 return false; 1400 } 1401 } 1402 return true; 1403 } 1404 1405 /** 1406 * Determines if the token has finished drawing. This should only be called from 1407 * {@link DisplayContent#applySurfaceChangesTransaction} 1408 */ updateAllDrawn()1409 void updateAllDrawn() { 1410 if (!allDrawn) { 1411 // Number of drawn windows can be less when a window is being relaunched, wait for 1412 // all windows to be launched and drawn for this token be considered all drawn. 1413 final int numInteresting = mNumInterestingWindows; 1414 1415 // We must make sure that all present children have been considered (determined by 1416 // {@link #allDrawnStatesConsidered}) before evaluating whether everything has been 1417 // drawn. 1418 if (numInteresting > 0 && allDrawnStatesConsidered() 1419 && mNumDrawnWindows >= numInteresting && !isRelaunching()) { 1420 if (DEBUG_VISIBILITY) Slog.v(TAG, "allDrawn: " + this 1421 + " interesting=" + numInteresting + " drawn=" + mNumDrawnWindows); 1422 allDrawn = true; 1423 // Force an additional layout pass where 1424 // WindowStateAnimator#commitFinishDrawingLocked() will call performShowLocked(). 1425 if (mDisplayContent != null) { 1426 mDisplayContent.setLayoutNeeded(); 1427 } 1428 mService.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN, token).sendToTarget(); 1429 1430 // Notify the pinned stack upon all windows drawn. If there was an animation in 1431 // progress then this signal will resume that animation. 1432 final TaskStack pinnedStack = mDisplayContent.getPinnedStack(); 1433 if (pinnedStack != null) { 1434 pinnedStack.onAllWindowsDrawn(); 1435 } 1436 } 1437 } 1438 } 1439 1440 /** 1441 * Updated this app token tracking states for interesting and drawn windows based on the window. 1442 * 1443 * @return Returns true if the input window is considered interesting and drawn while all the 1444 * windows in this app token where not considered drawn as of the last pass. 1445 */ updateDrawnWindowStates(WindowState w)1446 boolean updateDrawnWindowStates(WindowState w) { 1447 w.setDrawnStateEvaluated(true /*evaluated*/); 1448 1449 if (DEBUG_STARTING_WINDOW_VERBOSE && w == startingWindow) { 1450 Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen=" + w.isOnScreen() 1451 + " allDrawn=" + allDrawn + " freezingScreen=" + mFreezingScreen); 1452 } 1453 1454 if (allDrawn && !mFreezingScreen) { 1455 return false; 1456 } 1457 1458 if (mLastTransactionSequence != mService.mTransactionSequence) { 1459 mLastTransactionSequence = mService.mTransactionSequence; 1460 mNumDrawnWindows = 0; 1461 startingDisplayed = false; 1462 1463 // There is the main base application window, even if it is exiting, wait for it 1464 mNumInterestingWindows = findMainWindow(false /* includeStartingApp */) != null ? 1 : 0; 1465 } 1466 1467 final WindowStateAnimator winAnimator = w.mWinAnimator; 1468 1469 boolean isInterestingAndDrawn = false; 1470 1471 if (!allDrawn && w.mightAffectAllDrawn()) { 1472 if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) { 1473 Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw() 1474 + ", isAnimationSet=" + isSelfAnimating()); 1475 if (!w.isDrawnLw()) { 1476 Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceController 1477 + " pv=" + w.mPolicyVisibility 1478 + " mDrawState=" + winAnimator.drawStateToString() 1479 + " ph=" + w.isParentWindowHidden() + " th=" + hiddenRequested 1480 + " a=" + isSelfAnimating()); 1481 } 1482 } 1483 1484 if (w != startingWindow) { 1485 if (w.isInteresting()) { 1486 // Add non-main window as interesting since the main app has already been added 1487 if (findMainWindow(false /* includeStartingApp */) != w) { 1488 mNumInterestingWindows++; 1489 } 1490 if (w.isDrawnLw()) { 1491 mNumDrawnWindows++; 1492 1493 if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG, "tokenMayBeDrawn: " 1494 + this + " w=" + w + " numInteresting=" + mNumInterestingWindows 1495 + " freezingScreen=" + mFreezingScreen 1496 + " mAppFreezing=" + w.mAppFreezing); 1497 1498 isInterestingAndDrawn = true; 1499 } 1500 } 1501 } else if (w.isDrawnLw()) { 1502 if (getController() != null) { 1503 getController().reportStartingWindowDrawn(); 1504 } 1505 startingDisplayed = true; 1506 } 1507 } 1508 1509 return isInterestingAndDrawn; 1510 } 1511 layoutLetterbox(WindowState winHint)1512 void layoutLetterbox(WindowState winHint) { 1513 final WindowState w = findMainWindow(); 1514 if (w == null || winHint != null && w != winHint) { 1515 return; 1516 } 1517 final boolean surfaceReady = w.isDrawnLw() // Regular case 1518 || w.mWinAnimator.mSurfaceDestroyDeferred // The preserved surface is still ready. 1519 || w.isDragResizeChanged(); // Waiting for relayoutWindow to call preserveSurface. 1520 final boolean needsLetterbox = w.isLetterboxedAppWindow() && fillsParent() && surfaceReady; 1521 if (needsLetterbox) { 1522 if (mLetterbox == null) { 1523 mLetterbox = new Letterbox(() -> makeChildSurface(null)); 1524 } 1525 mLetterbox.layout(getParent().getBounds(), w.mFrame); 1526 } else if (mLetterbox != null) { 1527 mLetterbox.hide(); 1528 } 1529 } 1530 updateLetterboxSurface(WindowState winHint)1531 void updateLetterboxSurface(WindowState winHint) { 1532 final WindowState w = findMainWindow(); 1533 if (w != winHint && winHint != null && w != null) { 1534 return; 1535 } 1536 layoutLetterbox(winHint); 1537 if (mLetterbox != null && mLetterbox.needsApplySurfaceChanges()) { 1538 mLetterbox.applySurfaceChanges(mPendingTransaction); 1539 } 1540 } 1541 1542 @Override forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom)1543 boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) { 1544 // For legacy reasons we process the TaskStack.mExitingAppTokens first in DisplayContent 1545 // before the non-exiting app tokens. So, we skip the exiting app tokens here. 1546 // TODO: Investigate if we need to continue to do this or if we can just process them 1547 // in-order. 1548 if (mIsExiting && !waitingForReplacement()) { 1549 return false; 1550 } 1551 return forAllWindowsUnchecked(callback, traverseTopToBottom); 1552 } 1553 forAllWindowsUnchecked(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom)1554 boolean forAllWindowsUnchecked(ToBooleanFunction<WindowState> callback, 1555 boolean traverseTopToBottom) { 1556 return super.forAllWindows(callback, traverseTopToBottom); 1557 } 1558 1559 @Override asAppWindowToken()1560 AppWindowToken asAppWindowToken() { 1561 // I am an app window token! 1562 return this; 1563 } 1564 1565 @Override fillsParent()1566 boolean fillsParent() { 1567 return mFillsParent; 1568 } 1569 setFillsParent(boolean fillsParent)1570 void setFillsParent(boolean fillsParent) { 1571 mFillsParent = fillsParent; 1572 } 1573 containsDismissKeyguardWindow()1574 boolean containsDismissKeyguardWindow() { 1575 // Window state is transient during relaunch. We are not guaranteed to be frozen during the 1576 // entirety of the relaunch. 1577 if (isRelaunching()) { 1578 return mLastContainsDismissKeyguardWindow; 1579 } 1580 1581 for (int i = mChildren.size() - 1; i >= 0; i--) { 1582 if ((mChildren.get(i).mAttrs.flags & FLAG_DISMISS_KEYGUARD) != 0) { 1583 return true; 1584 } 1585 } 1586 return false; 1587 } 1588 containsShowWhenLockedWindow()1589 boolean containsShowWhenLockedWindow() { 1590 // When we are relaunching, it is possible for us to be unfrozen before our previous 1591 // windows have been added back. Using the cached value ensures that our previous 1592 // showWhenLocked preference is honored until relaunching is complete. 1593 if (isRelaunching()) { 1594 return mLastContainsShowWhenLockedWindow; 1595 } 1596 1597 for (int i = mChildren.size() - 1; i >= 0; i--) { 1598 if ((mChildren.get(i).mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) { 1599 return true; 1600 } 1601 } 1602 1603 return false; 1604 } 1605 checkKeyguardFlagsChanged()1606 void checkKeyguardFlagsChanged() { 1607 final boolean containsDismissKeyguard = containsDismissKeyguardWindow(); 1608 final boolean containsShowWhenLocked = containsShowWhenLockedWindow(); 1609 if (containsDismissKeyguard != mLastContainsDismissKeyguardWindow 1610 || containsShowWhenLocked != mLastContainsShowWhenLockedWindow) { 1611 mService.notifyKeyguardFlagsChanged(null /* callback */); 1612 } 1613 mLastContainsDismissKeyguardWindow = containsDismissKeyguard; 1614 mLastContainsShowWhenLockedWindow = containsShowWhenLocked; 1615 } 1616 getImeTargetBelowWindow(WindowState w)1617 WindowState getImeTargetBelowWindow(WindowState w) { 1618 final int index = mChildren.indexOf(w); 1619 if (index > 0) { 1620 final WindowState target = mChildren.get(index - 1); 1621 if (target.canBeImeTarget()) { 1622 return target; 1623 } 1624 } 1625 return null; 1626 } 1627 getLowestAnimLayer()1628 int getLowestAnimLayer() { 1629 for (int i = 0; i < mChildren.size(); i++) { 1630 final WindowState w = mChildren.get(i); 1631 if (w.mRemoved) { 1632 continue; 1633 } 1634 return w.mWinAnimator.mAnimLayer; 1635 } 1636 return Integer.MAX_VALUE; 1637 } 1638 getHighestAnimLayerWindow(WindowState currentTarget)1639 WindowState getHighestAnimLayerWindow(WindowState currentTarget) { 1640 WindowState candidate = null; 1641 for (int i = mChildren.indexOf(currentTarget); i >= 0; i--) { 1642 final WindowState w = mChildren.get(i); 1643 if (w.mRemoved) { 1644 continue; 1645 } 1646 if (candidate == null || w.mWinAnimator.mAnimLayer > 1647 candidate.mWinAnimator.mAnimLayer) { 1648 candidate = w; 1649 } 1650 } 1651 return candidate; 1652 } 1653 1654 /** 1655 * See {@link Activity#setDisablePreviewScreenshots}. 1656 */ setDisablePreviewScreenshots(boolean disable)1657 void setDisablePreviewScreenshots(boolean disable) { 1658 mDisablePreviewScreenshots = disable; 1659 } 1660 1661 /** 1662 * Sets whether the current launch can turn the screen on. See {@link #canTurnScreenOn()} 1663 */ setCanTurnScreenOn(boolean canTurnScreenOn)1664 void setCanTurnScreenOn(boolean canTurnScreenOn) { 1665 mCanTurnScreenOn = canTurnScreenOn; 1666 } 1667 1668 /** 1669 * Indicates whether the current launch can turn the screen on. This is to prevent multiple 1670 * relayouts from turning the screen back on. The screen should only turn on at most 1671 * once per activity resume. 1672 * 1673 * @return true if the screen can be turned on. 1674 */ canTurnScreenOn()1675 boolean canTurnScreenOn() { 1676 return mCanTurnScreenOn; 1677 } 1678 1679 /** 1680 * Retrieves whether we'd like to generate a snapshot that's based solely on the theme. This is 1681 * the case when preview screenshots are disabled {@link #setDisablePreviewScreenshots} or when 1682 * we can't take a snapshot for other reasons, for example, if we have a secure window. 1683 * 1684 * @return True if we need to generate an app theme snapshot, false if we'd like to take a real 1685 * screenshot. 1686 */ shouldUseAppThemeSnapshot()1687 boolean shouldUseAppThemeSnapshot() { 1688 return mDisablePreviewScreenshots || forAllWindows(w -> (w.mAttrs.flags & FLAG_SECURE) != 0, 1689 true /* topToBottom */); 1690 } 1691 getAppAnimationLayer()1692 SurfaceControl getAppAnimationLayer() { 1693 return getAppAnimationLayer(isActivityTypeHome() ? ANIMATION_LAYER_HOME 1694 : needsZBoost() ? ANIMATION_LAYER_BOOSTED 1695 : ANIMATION_LAYER_STANDARD); 1696 } 1697 1698 @Override getAnimationLeashParent()1699 public SurfaceControl getAnimationLeashParent() { 1700 // All normal app transitions take place in an animation layer which is below the pinned 1701 // stack but may be above the parent stacks of the given animating apps. 1702 // For transitions in the pinned stack (menu activity) we just let them occur as a child 1703 // of the pinned stack. 1704 if (!inPinnedWindowingMode()) { 1705 return getAppAnimationLayer(); 1706 } else { 1707 return getStack().getSurfaceControl(); 1708 } 1709 } 1710 shouldAnimate(int transit)1711 private boolean shouldAnimate(int transit) { 1712 final boolean isSplitScreenPrimary = 1713 getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; 1714 final boolean allowSplitScreenPrimaryAnimation = transit != TRANSIT_WALLPAPER_OPEN; 1715 1716 // We animate always if it's not split screen primary, and only some special cases in split 1717 // screen primary because it causes issues with stack clipping when we run an un-minimize 1718 // animation at the same time. 1719 return !isSplitScreenPrimary || allowSplitScreenPrimaryAnimation; 1720 } 1721 applyAnimationLocked(WindowManager.LayoutParams lp, int transit, boolean enter, boolean isVoiceInteraction)1722 boolean applyAnimationLocked(WindowManager.LayoutParams lp, int transit, boolean enter, 1723 boolean isVoiceInteraction) { 1724 1725 if (mService.mDisableTransitionAnimation || !shouldAnimate(transit)) { 1726 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { 1727 Slog.v(TAG_WM, "applyAnimation: transition animation is disabled or skipped." 1728 + " atoken=" + this); 1729 } 1730 cancelAnimation(); 1731 return false; 1732 } 1733 1734 // Only apply an animation if the display isn't frozen. If it is frozen, there is no reason 1735 // to animate and it can cause strange artifacts when we unfreeze the display if some 1736 // different animation is running. 1737 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AWT#applyAnimationLocked"); 1738 if (okToAnimate()) { 1739 final AnimationAdapter adapter; 1740 final TaskStack stack = getStack(); 1741 mTmpPoint.set(0, 0); 1742 mTmpRect.setEmpty(); 1743 if (stack != null) { 1744 stack.getRelativePosition(mTmpPoint); 1745 stack.getBounds(mTmpRect); 1746 mTmpRect.offsetTo(0, 0); 1747 } 1748 1749 // Delaying animation start isn't compatible with remote animations at all. 1750 if (mService.mAppTransition.getRemoteAnimationController() != null 1751 && !mSurfaceAnimator.isAnimationStartDelayed()) { 1752 adapter = mService.mAppTransition.getRemoteAnimationController() 1753 .createAnimationAdapter(this, mTmpPoint, mTmpRect); 1754 } else { 1755 final Animation a = loadAnimation(lp, transit, enter, isVoiceInteraction); 1756 if (a != null) { 1757 adapter = new LocalAnimationAdapter( 1758 new WindowAnimationSpec(a, mTmpPoint, mTmpRect, 1759 mService.mAppTransition.canSkipFirstFrame(), 1760 mService.mAppTransition.getAppStackClipMode(), 1761 true /* isAppAnimation */), 1762 mService.mSurfaceAnimationRunner); 1763 if (a.getZAdjustment() == Animation.ZORDER_TOP) { 1764 mNeedsZBoost = true; 1765 } 1766 mTransit = transit; 1767 mTransitFlags = mService.mAppTransition.getTransitFlags(); 1768 } else { 1769 adapter = null; 1770 } 1771 } 1772 if (adapter != null) { 1773 startAnimation(getPendingTransaction(), adapter, !isVisible()); 1774 if (adapter.getShowWallpaper()) { 1775 mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; 1776 } 1777 } 1778 } else { 1779 cancelAnimation(); 1780 } 1781 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 1782 1783 return isReallyAnimating(); 1784 } 1785 loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, boolean isVoiceInteraction)1786 private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter, 1787 boolean isVoiceInteraction) { 1788 final DisplayContent displayContent = getTask().getDisplayContent(); 1789 final DisplayInfo displayInfo = displayContent.getDisplayInfo(); 1790 final int width = displayInfo.appWidth; 1791 final int height = displayInfo.appHeight; 1792 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG_WM, 1793 "applyAnimation: atoken=" + this); 1794 1795 // Determine the visible rect to calculate the thumbnail clip 1796 final WindowState win = findMainWindow(); 1797 final Rect frame = new Rect(0, 0, width, height); 1798 final Rect displayFrame = new Rect(0, 0, 1799 displayInfo.logicalWidth, displayInfo.logicalHeight); 1800 final Rect insets = new Rect(); 1801 final Rect stableInsets = new Rect(); 1802 Rect surfaceInsets = null; 1803 final boolean freeform = win != null && win.inFreeformWindowingMode(); 1804 if (win != null) { 1805 // Containing frame will usually cover the whole screen, including dialog windows. 1806 // For freeform workspace windows it will not cover the whole screen and it also 1807 // won't exactly match the final freeform window frame (e.g. when overlapping with 1808 // the status bar). In that case we need to use the final frame. 1809 if (freeform) { 1810 frame.set(win.mFrame); 1811 } else if (win.isLetterboxedAppWindow()) { 1812 frame.set(getTask().getBounds()); 1813 } else if (win.isDockedResizing()) { 1814 // If we are animating while docked resizing, then use the stack bounds as the 1815 // animation target (which will be different than the task bounds) 1816 frame.set(getTask().getParent().getBounds()); 1817 } else { 1818 frame.set(win.mContainingFrame); 1819 } 1820 surfaceInsets = win.getAttrs().surfaceInsets; 1821 // XXX(b/72757033): These are insets relative to the window frame, but we're really 1822 // interested in the insets relative to the frame we chose in the if-blocks above. 1823 insets.set(win.mContentInsets); 1824 stableInsets.set(win.mStableInsets); 1825 } 1826 1827 if (mLaunchTaskBehind) { 1828 // Differentiate the two animations. This one which is briefly on the screen 1829 // gets the !enter animation, and the other activity which remains on the 1830 // screen gets the enter animation. Both appear in the mOpeningApps set. 1831 enter = false; 1832 } 1833 if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "Loading animation for app transition." 1834 + " transit=" + AppTransition.appTransitionToString(transit) + " enter=" + enter 1835 + " frame=" + frame + " insets=" + insets + " surfaceInsets=" + surfaceInsets); 1836 final Configuration displayConfig = displayContent.getConfiguration(); 1837 final Animation a = mService.mAppTransition.loadAnimation(lp, transit, enter, 1838 displayConfig.uiMode, displayConfig.orientation, frame, displayFrame, insets, 1839 surfaceInsets, stableInsets, isVoiceInteraction, freeform, getTask().mTaskId); 1840 if (a != null) { 1841 if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + this); 1842 final int containingWidth = frame.width(); 1843 final int containingHeight = frame.height(); 1844 a.initialize(containingWidth, containingHeight, width, height); 1845 a.scaleCurrentDuration(mService.getTransitionAnimationScaleLocked()); 1846 } 1847 return a; 1848 } 1849 1850 @Override shouldDeferAnimationFinish(Runnable endDeferFinishCallback)1851 public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) { 1852 return mAnimatingAppWindowTokenRegistry != null 1853 && mAnimatingAppWindowTokenRegistry.notifyAboutToFinish( 1854 this, endDeferFinishCallback); 1855 } 1856 1857 @Override onAnimationLeashDestroyed(Transaction t)1858 public void onAnimationLeashDestroyed(Transaction t) { 1859 super.onAnimationLeashDestroyed(t); 1860 if (mAnimatingAppWindowTokenRegistry != null) { 1861 mAnimatingAppWindowTokenRegistry.notifyFinished(this); 1862 } 1863 } 1864 1865 @Override setLayer(Transaction t, int layer)1866 protected void setLayer(Transaction t, int layer) { 1867 if (!mSurfaceAnimator.hasLeash()) { 1868 t.setLayer(mSurfaceControl, layer); 1869 } 1870 } 1871 1872 @Override setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer)1873 protected void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) { 1874 if (!mSurfaceAnimator.hasLeash()) { 1875 t.setRelativeLayer(mSurfaceControl, relativeTo, layer); 1876 } 1877 } 1878 1879 @Override reparentSurfaceControl(Transaction t, SurfaceControl newParent)1880 protected void reparentSurfaceControl(Transaction t, SurfaceControl newParent) { 1881 if (!mSurfaceAnimator.hasLeash()) { 1882 t.reparent(mSurfaceControl, newParent.getHandle()); 1883 } 1884 } 1885 1886 @Override onAnimationLeashCreated(Transaction t, SurfaceControl leash)1887 public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) { 1888 // The leash is parented to the animation layer. We need to preserve the z-order by using 1889 // the prefix order index, but we boost if necessary. 1890 int layer = 0; 1891 if (!inPinnedWindowingMode()) { 1892 layer = getPrefixOrderIndex(); 1893 } else { 1894 // Pinned stacks have animations take place within themselves rather than an animation 1895 // layer so we need to preserve the order relative to the stack (e.g. the order of our 1896 // task/parent). 1897 layer = getParent().getPrefixOrderIndex(); 1898 } 1899 1900 if (mNeedsZBoost) { 1901 layer += Z_BOOST_BASE; 1902 } 1903 leash.setLayer(layer); 1904 1905 final DisplayContent dc = getDisplayContent(); 1906 dc.assignStackOrdering(); 1907 if (mAnimatingAppWindowTokenRegistry != null) { 1908 mAnimatingAppWindowTokenRegistry.notifyStarting(this); 1909 } 1910 } 1911 1912 /** 1913 * This must be called while inside a transaction. 1914 */ showAllWindowsLocked()1915 void showAllWindowsLocked() { 1916 forAllWindows(windowState -> { 1917 if (DEBUG_VISIBILITY) Slog.v(TAG, "performing show on: " + windowState); 1918 windowState.performShowLocked(); 1919 }, false /* traverseTopToBottom */); 1920 } 1921 1922 @Override onAnimationFinished()1923 protected void onAnimationFinished() { 1924 super.onAnimationFinished(); 1925 1926 mTransit = TRANSIT_UNSET; 1927 mTransitFlags = 0; 1928 mNeedsZBoost = false; 1929 1930 setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM | FINISH_LAYOUT_REDO_WALLPAPER, 1931 "AppWindowToken"); 1932 1933 clearThumbnail(); 1934 setClientHidden(isHidden() && hiddenRequested); 1935 1936 if (mService.mInputMethodTarget != null && mService.mInputMethodTarget.mAppToken == this) { 1937 getDisplayContent().computeImeTarget(true /* updateImeTarget */); 1938 } 1939 1940 if (DEBUG_ANIM) Slog.v(TAG, "Animation done in " + this 1941 + ": reportedVisible=" + reportedVisible 1942 + " okToDisplay=" + okToDisplay() 1943 + " okToAnimate=" + okToAnimate() 1944 + " startingDisplayed=" + startingDisplayed); 1945 1946 // WindowState.onExitAnimationDone might modify the children list, so make a copy and then 1947 // traverse the copy. 1948 final ArrayList<WindowState> children = new ArrayList<>(mChildren); 1949 children.forEach(WindowState::onExitAnimationDone); 1950 1951 mService.mAppTransition.notifyAppTransitionFinishedLocked(token); 1952 scheduleAnimation(); 1953 } 1954 1955 @Override isAppAnimating()1956 boolean isAppAnimating() { 1957 return isSelfAnimating(); 1958 } 1959 1960 @Override isSelfAnimating()1961 boolean isSelfAnimating() { 1962 // If we are about to start a transition, we also need to be considered animating. 1963 return isWaitingForTransitionStart() || isReallyAnimating(); 1964 } 1965 1966 /** 1967 * @return True if and only if we are actually running an animation. Note that 1968 * {@link #isSelfAnimating} also returns true if we are waiting for an animation to 1969 * start. 1970 */ isReallyAnimating()1971 private boolean isReallyAnimating() { 1972 return super.isSelfAnimating(); 1973 } 1974 1975 @Override cancelAnimation()1976 void cancelAnimation() { 1977 super.cancelAnimation(); 1978 clearThumbnail(); 1979 } 1980 isWaitingForTransitionStart()1981 boolean isWaitingForTransitionStart() { 1982 return mService.mAppTransition.isTransitionSet() 1983 && (mService.mOpeningApps.contains(this) || mService.mClosingApps.contains(this)); 1984 } 1985 getTransit()1986 public int getTransit() { 1987 return mTransit; 1988 } 1989 getTransitFlags()1990 int getTransitFlags() { 1991 return mTransitFlags; 1992 } 1993 attachThumbnailAnimation()1994 void attachThumbnailAnimation() { 1995 if (!isReallyAnimating()) { 1996 return; 1997 } 1998 final int taskId = getTask().mTaskId; 1999 final GraphicBuffer thumbnailHeader = 2000 mService.mAppTransition.getAppTransitionThumbnailHeader(taskId); 2001 if (thumbnailHeader == null) { 2002 if (DEBUG_APP_TRANSITIONS) Slog.d(TAG, "No thumbnail header bitmap for: " + taskId); 2003 return; 2004 } 2005 clearThumbnail(); 2006 mThumbnail = new AppWindowThumbnail(getPendingTransaction(), this, thumbnailHeader); 2007 mThumbnail.startAnimation(getPendingTransaction(), loadThumbnailAnimation(thumbnailHeader)); 2008 } 2009 2010 /** 2011 * Attaches a surface with a thumbnail for the 2012 * {@link android.app.ActivityOptions#ANIM_OPEN_CROSS_PROFILE_APPS} animation. 2013 */ attachCrossProfileAppsThumbnailAnimation()2014 void attachCrossProfileAppsThumbnailAnimation() { 2015 if (!isReallyAnimating()) { 2016 return; 2017 } 2018 clearThumbnail(); 2019 2020 final WindowState win = findMainWindow(); 2021 if (win == null) { 2022 return; 2023 } 2024 final Rect frame = win.mFrame; 2025 final int thumbnailDrawableRes = getTask().mUserId == mService.mCurrentUserId 2026 ? R.drawable.ic_account_circle 2027 : R.drawable.ic_corp_badge; 2028 final GraphicBuffer thumbnail = 2029 mService.mAppTransition 2030 .createCrossProfileAppsThumbnail(thumbnailDrawableRes, frame); 2031 if (thumbnail == null) { 2032 return; 2033 } 2034 mThumbnail = new AppWindowThumbnail(getPendingTransaction(), this, thumbnail); 2035 final Animation animation = 2036 mService.mAppTransition.createCrossProfileAppsThumbnailAnimationLocked(win.mFrame); 2037 mThumbnail.startAnimation(getPendingTransaction(), animation, new Point(frame.left, 2038 frame.top)); 2039 } 2040 loadThumbnailAnimation(GraphicBuffer thumbnailHeader)2041 private Animation loadThumbnailAnimation(GraphicBuffer thumbnailHeader) { 2042 final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo(); 2043 2044 // If this is a multi-window scenario, we use the windows frame as 2045 // destination of the thumbnail header animation. If this is a full screen 2046 // window scenario, we use the whole display as the target. 2047 WindowState win = findMainWindow(); 2048 Rect appRect = win != null ? win.getContentFrameLw() : 2049 new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight); 2050 Rect insets = win != null ? win.mContentInsets : null; 2051 final Configuration displayConfig = mDisplayContent.getConfiguration(); 2052 return mService.mAppTransition.createThumbnailAspectScaleAnimationLocked( 2053 appRect, insets, thumbnailHeader, getTask().mTaskId, displayConfig.uiMode, 2054 displayConfig.orientation); 2055 } 2056 clearThumbnail()2057 private void clearThumbnail() { 2058 if (mThumbnail == null) { 2059 return; 2060 } 2061 mThumbnail.destroy(); 2062 mThumbnail = null; 2063 } 2064 registerRemoteAnimations(RemoteAnimationDefinition definition)2065 void registerRemoteAnimations(RemoteAnimationDefinition definition) { 2066 mRemoteAnimationDefinition = definition; 2067 } 2068 getRemoteAnimationDefinition()2069 RemoteAnimationDefinition getRemoteAnimationDefinition() { 2070 return mRemoteAnimationDefinition; 2071 } 2072 2073 @Override dump(PrintWriter pw, String prefix, boolean dumpAll)2074 void dump(PrintWriter pw, String prefix, boolean dumpAll) { 2075 super.dump(pw, prefix, dumpAll); 2076 if (appToken != null) { 2077 pw.println(prefix + "app=true mVoiceInteraction=" + mVoiceInteraction); 2078 } 2079 pw.print(prefix); pw.print("task="); pw.println(getTask()); 2080 pw.print(prefix); pw.print(" mFillsParent="); pw.print(mFillsParent); 2081 pw.print(" mOrientation="); pw.println(mOrientation); 2082 pw.println(prefix + "hiddenRequested=" + hiddenRequested + " mClientHidden=" + mClientHidden 2083 + ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "") 2084 + " reportedDrawn=" + reportedDrawn + " reportedVisible=" + reportedVisible); 2085 if (paused) { 2086 pw.print(prefix); pw.print("paused="); pw.println(paused); 2087 } 2088 if (mAppStopped) { 2089 pw.print(prefix); pw.print("mAppStopped="); pw.println(mAppStopped); 2090 } 2091 if (mNumInterestingWindows != 0 || mNumDrawnWindows != 0 2092 || allDrawn || mLastAllDrawn) { 2093 pw.print(prefix); pw.print("mNumInterestingWindows="); 2094 pw.print(mNumInterestingWindows); 2095 pw.print(" mNumDrawnWindows="); pw.print(mNumDrawnWindows); 2096 pw.print(" inPendingTransaction="); pw.print(inPendingTransaction); 2097 pw.print(" allDrawn="); pw.print(allDrawn); 2098 pw.print(" lastAllDrawn="); pw.print(mLastAllDrawn); 2099 pw.println(")"); 2100 } 2101 if (inPendingTransaction) { 2102 pw.print(prefix); pw.print("inPendingTransaction="); 2103 pw.println(inPendingTransaction); 2104 } 2105 if (startingData != null || removed || firstWindowDrawn || mIsExiting) { 2106 pw.print(prefix); pw.print("startingData="); pw.print(startingData); 2107 pw.print(" removed="); pw.print(removed); 2108 pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn); 2109 pw.print(" mIsExiting="); pw.println(mIsExiting); 2110 } 2111 if (startingWindow != null || startingSurface != null 2112 || startingDisplayed || startingMoved || mHiddenSetFromTransferredStartingWindow) { 2113 pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow); 2114 pw.print(" startingSurface="); pw.print(startingSurface); 2115 pw.print(" startingDisplayed="); pw.print(startingDisplayed); 2116 pw.print(" startingMoved="); pw.print(startingMoved); 2117 pw.println(" mHiddenSetFromTransferredStartingWindow=" 2118 + mHiddenSetFromTransferredStartingWindow); 2119 } 2120 if (!mFrozenBounds.isEmpty()) { 2121 pw.print(prefix); pw.print("mFrozenBounds="); pw.println(mFrozenBounds); 2122 pw.print(prefix); pw.print("mFrozenMergedConfig="); pw.println(mFrozenMergedConfig); 2123 } 2124 if (mPendingRelaunchCount != 0) { 2125 pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount); 2126 } 2127 if (getController() != null) { 2128 pw.print(prefix); pw.print("controller="); pw.println(getController()); 2129 } 2130 if (mRemovingFromDisplay) { 2131 pw.println(prefix + "mRemovingFromDisplay=" + mRemovingFromDisplay); 2132 } 2133 } 2134 2135 @Override setHidden(boolean hidden)2136 void setHidden(boolean hidden) { 2137 super.setHidden(hidden); 2138 2139 if (hidden) { 2140 // Once the app window is hidden, reset the last saved PiP snap fraction 2141 mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(this); 2142 } 2143 scheduleAnimation(); 2144 } 2145 2146 @Override prepareSurfaces()2147 void prepareSurfaces() { 2148 // isSelfAnimating also returns true when we are about to start a transition, so we need 2149 // to check super here. 2150 final boolean reallyAnimating = super.isSelfAnimating(); 2151 final boolean show = !isHidden() || reallyAnimating; 2152 if (show && !mLastSurfaceShowing) { 2153 mPendingTransaction.show(mSurfaceControl); 2154 } else if (!show && mLastSurfaceShowing) { 2155 mPendingTransaction.hide(mSurfaceControl); 2156 } 2157 if (mThumbnail != null) { 2158 mThumbnail.setShowing(mPendingTransaction, show); 2159 } 2160 mLastSurfaceShowing = show; 2161 super.prepareSurfaces(); 2162 } 2163 2164 /** 2165 * @return Whether our {@link #getSurfaceControl} is currently showing. 2166 */ isSurfaceShowing()2167 boolean isSurfaceShowing() { 2168 return mLastSurfaceShowing; 2169 } 2170 isFreezingScreen()2171 boolean isFreezingScreen() { 2172 return mFreezingScreen; 2173 } 2174 2175 @Override needsZBoost()2176 boolean needsZBoost() { 2177 return mNeedsZBoost || super.needsZBoost(); 2178 } 2179 2180 @CallSuper 2181 @Override writeToProto(ProtoOutputStream proto, long fieldId, boolean trim)2182 public void writeToProto(ProtoOutputStream proto, long fieldId, boolean trim) { 2183 final long token = proto.start(fieldId); 2184 writeNameToProto(proto, NAME); 2185 super.writeToProto(proto, WINDOW_TOKEN, trim); 2186 proto.write(LAST_SURFACE_SHOWING, mLastSurfaceShowing); 2187 proto.write(IS_WAITING_FOR_TRANSITION_START, isWaitingForTransitionStart()); 2188 proto.write(IS_REALLY_ANIMATING, isReallyAnimating()); 2189 if (mThumbnail != null){ 2190 mThumbnail.writeToProto(proto, THUMBNAIL); 2191 } 2192 proto.write(FILLS_PARENT, mFillsParent); 2193 proto.write(APP_STOPPED, mAppStopped); 2194 proto.write(HIDDEN_REQUESTED, hiddenRequested); 2195 proto.write(CLIENT_HIDDEN, mClientHidden); 2196 proto.write(DEFER_HIDING_CLIENT, mDeferHidingClient); 2197 proto.write(REPORTED_DRAWN, reportedDrawn); 2198 proto.write(REPORTED_VISIBLE, reportedVisible); 2199 proto.write(NUM_INTERESTING_WINDOWS, mNumInterestingWindows); 2200 proto.write(NUM_DRAWN_WINDOWS, mNumDrawnWindows); 2201 proto.write(ALL_DRAWN, allDrawn); 2202 proto.write(LAST_ALL_DRAWN, mLastAllDrawn); 2203 proto.write(REMOVED, removed); 2204 if (startingWindow != null){ 2205 startingWindow.writeIdentifierToProto(proto, STARTING_WINDOW); 2206 } 2207 proto.write(STARTING_DISPLAYED, startingDisplayed); 2208 proto.write(STARTING_MOVED, startingMoved); 2209 proto.write(HIDDEN_SET_FROM_TRANSFERRED_STARTING_WINDOW, 2210 mHiddenSetFromTransferredStartingWindow); 2211 for (Rect bounds : mFrozenBounds) { 2212 bounds.writeToProto(proto, FROZEN_BOUNDS); 2213 } 2214 proto.end(token); 2215 } 2216 writeNameToProto(ProtoOutputStream proto, long fieldId)2217 void writeNameToProto(ProtoOutputStream proto, long fieldId) { 2218 if (appToken == null) { 2219 return; 2220 } 2221 try { 2222 proto.write(fieldId, appToken.getName()); 2223 } catch (RemoteException e) { 2224 // This shouldn't happen, but in this case fall back to outputting nothing 2225 Slog.e(TAG, e.toString()); 2226 } 2227 } 2228 2229 @Override toString()2230 public String toString() { 2231 if (stringName == null) { 2232 StringBuilder sb = new StringBuilder(); 2233 sb.append("AppWindowToken{"); 2234 sb.append(Integer.toHexString(System.identityHashCode(this))); 2235 sb.append(" token="); sb.append(token); sb.append('}'); 2236 stringName = sb.toString(); 2237 } 2238 return stringName + ((mIsExiting) ? " mIsExiting=" : ""); 2239 } 2240 getLetterboxInsets()2241 Rect getLetterboxInsets() { 2242 if (mLetterbox != null) { 2243 return mLetterbox.getInsets(); 2244 } else { 2245 return new Rect(); 2246 } 2247 } 2248 2249 /** 2250 * @eturn true if there is a letterbox and any part of that letterbox overlaps with 2251 * the given {@code rect}. 2252 */ isLetterboxOverlappingWith(Rect rect)2253 boolean isLetterboxOverlappingWith(Rect rect) { 2254 return mLetterbox != null && mLetterbox.isOverlappingWith(rect); 2255 } 2256 2257 /** 2258 * Sets if this AWT is in the process of closing or entering PIP. 2259 * {@link #mWillCloseOrEnterPip}} 2260 */ setWillCloseOrEnterPip(boolean willCloseOrEnterPip)2261 void setWillCloseOrEnterPip(boolean willCloseOrEnterPip) { 2262 mWillCloseOrEnterPip = willCloseOrEnterPip; 2263 } 2264 2265 /** 2266 * Returns whether this AWT is considered closing. Conditions are either 2267 * 1. Is this app animating and was requested to be hidden 2268 * 2. App is delayed closing since it might enter PIP. 2269 */ isClosingOrEnteringPip()2270 boolean isClosingOrEnteringPip() { 2271 return (isAnimating() && hiddenRequested) || mWillCloseOrEnterPip; 2272 } 2273 } 2274