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.ActivityManager.StackId; 20 import static android.app.ActivityManager.StackId.PINNED_STACK_ID; 21 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION; 22 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE; 23 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; 24 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; 25 import static android.view.Display.DEFAULT_DISPLAY; 26 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; 27 import static android.view.WindowManager.LayoutParams.FLAG_SECURE; 28 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; 29 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; 30 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; 31 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; 32 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; 33 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; 34 import static com.android.server.wm.AppTransition.TRANSIT_UNSET; 35 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; 36 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; 37 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; 38 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT; 39 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS; 40 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; 41 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW; 42 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE; 43 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT; 44 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; 45 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT; 46 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 47 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 48 import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN; 49 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; 50 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES; 51 import static com.android.server.wm.WindowManagerService.logWithStack; 52 53 import android.annotation.NonNull; 54 import android.app.Activity; 55 import android.content.res.Configuration; 56 import android.graphics.Rect; 57 import android.os.Binder; 58 import android.os.Debug; 59 import android.os.IBinder; 60 import android.os.SystemClock; 61 import android.util.Slog; 62 import android.view.IApplicationToken; 63 import android.view.SurfaceControl; 64 import android.view.WindowManager; 65 import android.view.WindowManagerPolicy.StartingSurface; 66 67 import com.android.internal.util.ToBooleanFunction; 68 import com.android.server.input.InputApplicationHandle; 69 import com.android.server.wm.WindowManagerService.H; 70 71 import java.io.PrintWriter; 72 import java.util.ArrayDeque; 73 import java.util.ArrayList; 74 75 import static android.os.Build.VERSION_CODES.O; 76 77 class AppTokenList extends ArrayList<AppWindowToken> { 78 } 79 80 /** 81 * Version of WindowToken that is specifically for a particular application (or 82 * really activity) that is displaying windows. 83 */ 84 class AppWindowToken extends WindowToken implements WindowManagerService.AppFreezeListener { 85 private static final String TAG = TAG_WITH_CLASS_NAME ? "AppWindowToken" : TAG_WM; 86 87 // Non-null only for application tokens. 88 final IApplicationToken appToken; 89 90 @NonNull final AppWindowAnimator mAppAnimator; 91 92 final boolean mVoiceInteraction; 93 94 /** @see WindowContainer#fillsParent() */ 95 private boolean mFillsParent; 96 boolean layoutConfigChanges; 97 boolean mShowForAllUsers; 98 int mTargetSdk; 99 100 // Flag set while reparenting to prevent actions normally triggered by an individual parent 101 // change. 102 private boolean mReparenting; 103 104 // True if we are current in the process of removing this app token from the display 105 private boolean mRemovingFromDisplay = false; 106 107 // The input dispatching timeout for this application token in nanoseconds. 108 long mInputDispatchingTimeoutNanos; 109 110 // These are used for determining when all windows associated with 111 // an activity have been drawn, so they can be made visible together 112 // at the same time. 113 // initialize so that it doesn't match mTransactionSequence which is an int. 114 private long mLastTransactionSequence = Long.MIN_VALUE; 115 private int mNumInterestingWindows; 116 private int mNumDrawnWindows; 117 boolean inPendingTransaction; 118 boolean allDrawn; 119 // Set to true when this app creates a surface while in the middle of an animation. In that 120 // case do not clear allDrawn until the animation completes. 121 boolean deferClearAllDrawn; 122 123 /** 124 * These are to track the app's real drawing status if there were no saved surfaces. 125 * @see #updateDrawnWindowStates 126 */ 127 boolean allDrawnExcludingSaved; 128 private int mNumInterestingWindowsExcludingSaved; 129 private int mNumDrawnWindowsExcludingSaved; 130 131 // Is this window's surface needed? This is almost like hidden, except 132 // it will sometimes be true a little earlier: when the token has 133 // been shown, but is still waiting for its app transition to execute 134 // before making its windows shown. 135 boolean hiddenRequested; 136 137 // Have we told the window clients to hide themselves? 138 private boolean mClientHidden; 139 140 // If true we will defer setting mClientHidden to true and reporting to the client that it is 141 // hidden. 142 boolean mDeferHidingClient; 143 144 // Last visibility state we reported to the app token. 145 boolean reportedVisible; 146 147 // Last drawn state we reported to the app token. 148 private boolean reportedDrawn; 149 150 // Set to true when the token has been removed from the window mgr. 151 boolean removed; 152 153 // Information about an application starting window if displayed. 154 StartingData startingData; 155 WindowState startingWindow; 156 StartingSurface startingSurface; 157 boolean startingDisplayed; 158 boolean startingMoved; 159 // True if the hidden state of this token was forced to false due to a transferred starting 160 // window. 161 private boolean mHiddenSetFromTransferredStartingWindow; 162 boolean firstWindowDrawn; 163 private final WindowState.UpdateReportedVisibilityResults mReportedVisibilityResults = 164 new WindowState.UpdateReportedVisibilityResults(); 165 166 // Input application handle used by the input dispatcher. 167 final InputApplicationHandle mInputApplicationHandle; 168 169 // TODO: Have a WindowContainer state for tracking exiting/deferred removal. 170 boolean mIsExiting; 171 172 boolean mLaunchTaskBehind; 173 boolean mEnteringAnimation; 174 175 private boolean mAlwaysFocusable; 176 177 boolean mAppStopped; 178 int mRotationAnimationHint; 179 private int mPendingRelaunchCount; 180 181 private boolean mLastContainsShowWhenLockedWindow; 182 private boolean mLastContainsDismissKeyguardWindow; 183 184 // The bounds of this activity. Mainly used for aspect-ratio compatibility. 185 // TODO(b/36505427): Every level on WindowContainer now has bounds information, which directly 186 // affects the configuration. We should probably move this into that class. 187 private final Rect mBounds = new Rect(); 188 189 ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>(); 190 ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>(); 191 192 private boolean mDisablePreviewScreenshots; 193 194 Task mLastParent; 195 196 AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction, 197 DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen, 198 boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint, 199 int configChanges, boolean launchTaskBehind, boolean alwaysFocusable, 200 AppWindowContainerController controller, Configuration overrideConfig, Rect bounds) { 201 this(service, token, voiceInteraction, dc, fullscreen, overrideConfig, bounds); 202 setController(controller); 203 mInputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos; 204 mShowForAllUsers = showForAllUsers; 205 mTargetSdk = targetSdk; 206 mOrientation = orientation; 207 layoutConfigChanges = (configChanges & (CONFIG_SCREEN_SIZE | CONFIG_ORIENTATION)) != 0; 208 mLaunchTaskBehind = launchTaskBehind; 209 mAlwaysFocusable = alwaysFocusable; 210 mRotationAnimationHint = rotationAnimationHint; 211 212 // Application tokens start out hidden. 213 hidden = true; 214 hiddenRequested = true; 215 } 216 217 AppWindowToken(WindowManagerService service, IApplicationToken token, boolean voiceInteraction, 218 DisplayContent dc, boolean fillsParent, Configuration overrideConfig, Rect bounds) { 219 super(service, token != null ? token.asBinder() : null, TYPE_APPLICATION, true, dc, 220 false /* ownerCanManageAppTokens */); 221 appToken = token; 222 mVoiceInteraction = voiceInteraction; 223 mFillsParent = fillsParent; 224 mInputApplicationHandle = new InputApplicationHandle(this); 225 mAppAnimator = new AppWindowAnimator(this, service); 226 if (overrideConfig != null) { 227 onOverrideConfigurationChanged(overrideConfig); 228 } 229 if (bounds != null) { 230 mBounds.set(bounds); 231 } 232 } 233 234 void onOverrideConfigurationChanged(Configuration overrideConfiguration, Rect bounds) { 235 onOverrideConfigurationChanged(overrideConfiguration); 236 if (mBounds.equals(bounds)) { 237 return; 238 } 239 // TODO(b/36505427): If bounds is in WC, then we can automatically call onResize() when set. 240 mBounds.set(bounds); 241 onResize(); 242 } 243 244 void getBounds(Rect outBounds) { 245 outBounds.set(mBounds); 246 } 247 248 boolean hasBounds() { 249 return !mBounds.isEmpty(); 250 } 251 252 void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) { 253 firstWindowDrawn = true; 254 255 // We now have a good window to show, remove dead placeholders 256 removeDeadWindows(); 257 258 if (startingWindow != null) { 259 if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Slog.v(TAG, "Finish starting " 260 + win.mToken + ": first real window is shown, no animation"); 261 // If this initial window is animating, stop it -- we will do an animation to reveal 262 // it from behind the starting window, so there is no need for it to also be doing its 263 // own stuff. 264 winAnimator.clearAnimation(); 265 if (getController() != null) { 266 getController().removeStartingWindow(); 267 } 268 } 269 updateReportedVisibilityLocked(); 270 } 271 272 void updateReportedVisibilityLocked() { 273 if (appToken == null) { 274 return; 275 } 276 277 if (DEBUG_VISIBILITY) Slog.v(TAG, "Update reported visibility: " + this); 278 final int count = mChildren.size(); 279 280 mReportedVisibilityResults.reset(); 281 282 for (int i = 0; i < count; i++) { 283 final WindowState win = mChildren.get(i); 284 win.updateReportedVisibility(mReportedVisibilityResults); 285 } 286 287 int numInteresting = mReportedVisibilityResults.numInteresting; 288 int numVisible = mReportedVisibilityResults.numVisible; 289 int numDrawn = mReportedVisibilityResults.numDrawn; 290 boolean nowGone = mReportedVisibilityResults.nowGone; 291 292 boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting; 293 boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting; 294 if (!nowGone) { 295 // If the app is not yet gone, then it can only become visible/drawn. 296 if (!nowDrawn) { 297 nowDrawn = reportedDrawn; 298 } 299 if (!nowVisible) { 300 nowVisible = reportedVisible; 301 } 302 } 303 if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting=" 304 + numInteresting + " visible=" + numVisible); 305 final AppWindowContainerController controller = getController(); 306 if (nowDrawn != reportedDrawn) { 307 if (nowDrawn) { 308 if (controller != null) { 309 controller.reportWindowsDrawn(); 310 } 311 } 312 reportedDrawn = nowDrawn; 313 } 314 if (nowVisible != reportedVisible) { 315 if (DEBUG_VISIBILITY) Slog.v(TAG, 316 "Visibility changed in " + this + ": vis=" + nowVisible); 317 reportedVisible = nowVisible; 318 if (controller != null) { 319 if (nowVisible) { 320 controller.reportWindowsVisible(); 321 } else { 322 controller.reportWindowsGone(); 323 } 324 } 325 } 326 } 327 328 boolean isClientHidden() { 329 return mClientHidden; 330 } 331 332 void setClientHidden(boolean hideClient) { 333 if (mClientHidden == hideClient || (hideClient && mDeferHidingClient)) { 334 return; 335 } 336 mClientHidden = hideClient; 337 sendAppVisibilityToClients(); 338 } 339 340 boolean setVisibility(WindowManager.LayoutParams lp, 341 boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction) { 342 343 boolean delayed = false; 344 inPendingTransaction = false; 345 // Reset the state of mHiddenSetFromTransferredStartingWindow since visibility is actually 346 // been set by the app now. 347 mHiddenSetFromTransferredStartingWindow = false; 348 setClientHidden(!visible); 349 350 // Allow for state changes and animation to be applied if: 351 // * token is transitioning visibility state 352 // * or the token was marked as hidden and is exiting before we had a chance to play the 353 // transition animation 354 // * or this is an opening app and windows are being replaced. 355 boolean visibilityChanged = false; 356 if (hidden == visible || (hidden && mIsExiting) || (visible && waitingForReplacement())) { 357 final AccessibilityController accessibilityController = mService.mAccessibilityController; 358 boolean changed = false; 359 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, 360 "Changing app " + this + " hidden=" + hidden + " performLayout=" + performLayout); 361 362 boolean runningAppAnimation = false; 363 364 if (transit != AppTransition.TRANSIT_UNSET) { 365 if (mAppAnimator.animation == AppWindowAnimator.sDummyAnimation) { 366 mAppAnimator.setNullAnimation(); 367 } 368 if (mService.applyAnimationLocked(this, lp, transit, visible, isVoiceInteraction)) { 369 delayed = runningAppAnimation = true; 370 } 371 final WindowState window = findMainWindow(); 372 //TODO (multidisplay): Magnification is supported only for the default display. 373 if (window != null && accessibilityController != null 374 && getDisplayContent().getDisplayId() == DEFAULT_DISPLAY) { 375 accessibilityController.onAppWindowTransitionLocked(window, transit); 376 } 377 changed = true; 378 } 379 380 final int windowsCount = mChildren.size(); 381 for (int i = 0; i < windowsCount; i++) { 382 final WindowState win = mChildren.get(i); 383 changed |= win.onAppVisibilityChanged(visible, runningAppAnimation); 384 } 385 386 hidden = hiddenRequested = !visible; 387 visibilityChanged = true; 388 if (!visible) { 389 stopFreezingScreen(true, true); 390 } else { 391 // If we are being set visible, and the starting window is not yet displayed, 392 // then make sure it doesn't get displayed. 393 if (startingWindow != null && !startingWindow.isDrawnLw()) { 394 startingWindow.mPolicyVisibility = false; 395 startingWindow.mPolicyVisibilityAfterAnim = false; 396 } 397 398 // We are becoming visible, so better freeze the screen with the windows that are 399 // getting visible so we also wait for them. 400 forAllWindows(mService::makeWindowFreezingScreenIfNeededLocked, true); 401 } 402 403 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "setVisibility: " + this 404 + ": hidden=" + hidden + " hiddenRequested=" + hiddenRequested); 405 406 if (changed) { 407 mService.mInputMonitor.setUpdateInputWindowsNeededLw(); 408 if (performLayout) { 409 mService.updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, 410 false /*updateInputWindows*/); 411 mService.mWindowPlacerLocked.performSurfacePlacement(); 412 } 413 mService.mInputMonitor.updateInputWindowsLw(false /*force*/); 414 } 415 } 416 417 if (mAppAnimator.animation != null) { 418 delayed = true; 419 } 420 421 for (int i = mChildren.size() - 1; i >= 0 && !delayed; i--) { 422 if ((mChildren.get(i)).isWindowAnimationSet()) { 423 delayed = true; 424 } 425 } 426 427 if (visibilityChanged) { 428 if (visible && !delayed) { 429 // The token was made immediately visible, there will be no entrance animation. 430 // We need to inform the client the enter animation was finished. 431 mEnteringAnimation = true; 432 mService.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(token); 433 } 434 // If we are hidden but there is no delay needed we immediately 435 // apply the Surface transaction so that the ActivityManager 436 // can have some guarantee on the Surface state 437 // following setting the visibility. 438 if (hidden && !delayed) { 439 SurfaceControl.openTransaction(); 440 for (int i = mChildren.size() - 1; i >= 0; i--) { 441 mChildren.get(i).mWinAnimator.hide("immediately hidden"); 442 } 443 SurfaceControl.closeTransaction(); 444 } 445 446 if (!mService.mClosingApps.contains(this) && !mService.mOpeningApps.contains(this)) { 447 // The token is not closing nor opening, so even if there is an animation set, that 448 // doesn't mean that it goes through the normal app transition cycle so we have 449 // to inform the docked controller about visibility change. 450 // TODO(multi-display): notify docked divider on all displays where visibility was 451 // affected. 452 mService.getDefaultDisplayContentLocked().getDockedDividerController() 453 .notifyAppVisibilityChanged(); 454 mService.mTaskSnapshotController.notifyAppVisibilityChanged(this, visible); 455 } 456 } 457 458 return delayed; 459 } 460 461 WindowState findMainWindow() { 462 WindowState candidate = null; 463 int j = mChildren.size(); 464 while (j > 0) { 465 j--; 466 final WindowState win = mChildren.get(j); 467 final int type = win.mAttrs.type; 468 // No need to loop through child window as base application and starting types can't be 469 // child windows. 470 if (type == TYPE_BASE_APPLICATION || type == TYPE_APPLICATION_STARTING) { 471 // In cases where there are multiple windows, we prefer the non-exiting window. This 472 // happens for example when replacing windows during an activity relaunch. When 473 // constructing the animation, we want the new window, not the exiting one. 474 if (win.mAnimatingExit) { 475 candidate = win; 476 } else { 477 return win; 478 } 479 } 480 } 481 return candidate; 482 } 483 484 boolean windowsAreFocusable() { 485 return StackId.canReceiveKeys(getTask().mStack.mStackId) || mAlwaysFocusable; 486 } 487 488 AppWindowContainerController getController() { 489 final WindowContainerController controller = super.getController(); 490 return controller != null ? (AppWindowContainerController) controller : null; 491 } 492 493 @Override 494 boolean isVisible() { 495 // If the app token isn't hidden then it is considered visible and there is no need to check 496 // its children windows to see if they are visible. 497 return !hidden; 498 } 499 500 @Override 501 void removeImmediately() { 502 onRemovedFromDisplay(); 503 super.removeImmediately(); 504 } 505 506 @Override 507 void removeIfPossible() { 508 mIsExiting = false; 509 removeAllWindowsIfPossible(); 510 removeImmediately(); 511 } 512 513 @Override 514 boolean checkCompleteDeferredRemoval() { 515 if (mIsExiting) { 516 removeIfPossible(); 517 } 518 return super.checkCompleteDeferredRemoval(); 519 } 520 521 void onRemovedFromDisplay() { 522 if (mRemovingFromDisplay) { 523 return; 524 } 525 mRemovingFromDisplay = true; 526 527 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app token: " + this); 528 529 boolean delayed = setVisibility(null, false, TRANSIT_UNSET, true, mVoiceInteraction); 530 531 mService.mOpeningApps.remove(this); 532 mService.mUnknownAppVisibilityController.appRemovedOrHidden(this); 533 mService.mTaskSnapshotController.onAppRemoved(this); 534 waitingToShow = false; 535 if (mService.mClosingApps.contains(this)) { 536 delayed = true; 537 } else if (mService.mAppTransition.isTransitionSet()) { 538 mService.mClosingApps.add(this); 539 delayed = true; 540 } 541 542 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app " + this + " delayed=" + delayed 543 + " animation=" + mAppAnimator.animation + " animating=" + mAppAnimator.animating); 544 545 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM, "removeAppToken: " 546 + this + " delayed=" + delayed + " Callers=" + Debug.getCallers(4)); 547 548 if (startingData != null && getController() != null) { 549 getController().removeStartingWindow(); 550 } 551 552 // If this window was animating, then we need to ensure that the app transition notifies 553 // that animations have completed in WMS.handleAnimatingStoppedAndTransitionLocked(), so 554 // add to that list now 555 if (mAppAnimator.animating) { 556 mService.mNoAnimationNotifyOnTransitionFinished.add(token); 557 } 558 559 final TaskStack stack = getStack(); 560 if (delayed && !isEmpty()) { 561 // set the token aside because it has an active animation to be finished 562 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM, 563 "removeAppToken make exiting: " + this); 564 if (stack != null) { 565 stack.mExitingAppTokens.add(this); 566 } 567 mIsExiting = true; 568 } else { 569 // Make sure there is no animation running on this token, so any windows associated 570 // with it will be removed as soon as their animations are complete 571 mAppAnimator.clearAnimation(); 572 mAppAnimator.animating = false; 573 if (stack != null) { 574 stack.mExitingAppTokens.remove(this); 575 } 576 removeIfPossible(); 577 } 578 579 removed = true; 580 stopFreezingScreen(true, true); 581 582 if (mService.mFocusedApp == this) { 583 if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Removing focused app token:" + this); 584 mService.mFocusedApp = null; 585 mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/); 586 mService.mInputMonitor.setFocusedAppLw(null); 587 } 588 589 if (!delayed) { 590 updateReportedVisibilityLocked(); 591 } 592 593 mRemovingFromDisplay = false; 594 } 595 596 void clearAnimatingFlags() { 597 boolean wallpaperMightChange = false; 598 for (int i = mChildren.size() - 1; i >= 0; i--) { 599 final WindowState win = mChildren.get(i); 600 wallpaperMightChange |= win.clearAnimatingFlags(); 601 } 602 if (wallpaperMightChange) { 603 requestUpdateWallpaperIfNeeded(); 604 } 605 } 606 607 void destroySurfaces() { 608 destroySurfaces(false /*cleanupOnResume*/); 609 } 610 611 /** 612 * Destroy surfaces which have been marked as eligible by the animator, taking care to ensure 613 * the client has finished with them. 614 * 615 * @param cleanupOnResume whether this is done when app is resumed without fully stopped. If 616 * set to true, destroy only surfaces of removed windows, and clear relevant flags of the 617 * others so that they are ready to be reused. If set to false (common case), destroy all 618 * surfaces that's eligible, if the app is already stopped. 619 */ 620 private void destroySurfaces(boolean cleanupOnResume) { 621 boolean destroyedSomething = false; 622 for (int i = mChildren.size() - 1; i >= 0; i--) { 623 final WindowState win = mChildren.get(i); 624 destroyedSomething |= win.destroySurface(cleanupOnResume, mAppStopped); 625 } 626 if (destroyedSomething) { 627 final DisplayContent dc = getDisplayContent(); 628 dc.assignWindowLayers(true /*setLayoutNeeded*/); 629 } 630 } 631 632 /** 633 * Notify that the app is now resumed, and it was not stopped before, perform a clean 634 * up of the surfaces 635 */ 636 void notifyAppResumed(boolean wasStopped) { 637 if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppResumed: wasStopped=" + wasStopped 638 + " " + this); 639 mAppStopped = false; 640 if (!wasStopped) { 641 destroySurfaces(true /*cleanupOnResume*/); 642 } 643 } 644 645 /** 646 * Notify that the app has stopped, and it is okay to destroy any surfaces which were 647 * keeping alive in case they were still being used. 648 */ 649 void notifyAppStopped() { 650 if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppStopped: " + this); 651 mAppStopped = true; 652 destroySurfaces(); 653 // Remove any starting window that was added for this app if they are still around. 654 if (getController() != null) { 655 getController().removeStartingWindow(); 656 } 657 } 658 659 /** 660 * Checks whether we should save surfaces for this app. 661 * 662 * @return true if the surfaces should be saved, false otherwise. 663 */ 664 boolean shouldSaveSurface() { 665 // We want to save surface if the app's windows are "allDrawn". 666 // (If we started entering animation early with saved surfaces, allDrawn 667 // should have been restored to true. So we'll save again in that case 668 // even if app didn't actually finish drawing.) 669 return allDrawn; 670 } 671 672 private boolean canRestoreSurfaces() { 673 for (int i = mChildren.size() -1; i >= 0; i--) { 674 final WindowState w = mChildren.get(i); 675 if (w.canRestoreSurface()) { 676 return true; 677 } 678 } 679 return false; 680 } 681 682 private void clearWasVisibleBeforeClientHidden() { 683 for (int i = mChildren.size() - 1; i >= 0; i--) { 684 final WindowState w = mChildren.get(i); 685 w.clearWasVisibleBeforeClientHidden(); 686 } 687 } 688 689 /** 690 * Whether the app has some window that is invisible in layout, but 691 * animating with saved surface. 692 */ 693 boolean isAnimatingInvisibleWithSavedSurface() { 694 for (int i = mChildren.size() - 1; i >= 0; i--) { 695 final WindowState w = mChildren.get(i); 696 if (w.isAnimatingInvisibleWithSavedSurface()) { 697 return true; 698 } 699 } 700 return false; 701 } 702 703 /** 704 * Hide all window surfaces that's still invisible in layout but animating 705 * with a saved surface, and mark them destroying. 706 */ 707 void stopUsingSavedSurfaceLocked() { 708 for (int i = mChildren.size() - 1; i >= 0; i--) { 709 final WindowState w = mChildren.get(i); 710 w.stopUsingSavedSurface(); 711 } 712 destroySurfaces(); 713 } 714 715 void markSavedSurfaceExiting() { 716 for (int i = mChildren.size() - 1; i >= 0; i--) { 717 final WindowState w = mChildren.get(i); 718 w.markSavedSurfaceExiting(); 719 } 720 } 721 722 void restoreSavedSurfaceForInterestingWindows() { 723 if (!canRestoreSurfaces()) { 724 clearWasVisibleBeforeClientHidden(); 725 return; 726 } 727 728 // Check if all interesting windows are drawn and we can mark allDrawn=true. 729 int interestingNotDrawn = -1; 730 731 for (int i = mChildren.size() - 1; i >= 0; i--) { 732 final WindowState w = mChildren.get(i); 733 interestingNotDrawn = w.restoreSavedSurfaceForInterestingWindow(); 734 } 735 736 if (!allDrawn) { 737 allDrawn = (interestingNotDrawn == 0); 738 if (allDrawn) { 739 mService.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN, token).sendToTarget(); 740 } 741 } 742 clearWasVisibleBeforeClientHidden(); 743 744 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG, 745 "restoreSavedSurfaceForInterestingWindows: " + this + " allDrawn=" + allDrawn 746 + " interestingNotDrawn=" + interestingNotDrawn); 747 } 748 749 void destroySavedSurfaces() { 750 for (int i = mChildren.size() - 1; i >= 0; i--) { 751 final WindowState win = mChildren.get(i); 752 win.destroySavedSurface(); 753 } 754 } 755 756 void clearAllDrawn() { 757 allDrawn = false; 758 deferClearAllDrawn = false; 759 allDrawnExcludingSaved = false; 760 } 761 762 Task getTask() { 763 return (Task) getParent(); 764 } 765 766 TaskStack getStack() { 767 final Task task = getTask(); 768 if (task != null) { 769 return task.mStack; 770 } else { 771 return null; 772 } 773 } 774 775 @Override 776 void onParentSet() { 777 super.onParentSet(); 778 779 final Task task = getTask(); 780 781 // When the associated task is {@code null}, the {@link AppWindowToken} can no longer 782 // access visual elements like the {@link DisplayContent}. We must remove any associations 783 // such as animations. 784 if (!mReparenting) { 785 if (task == null) { 786 // It is possible we have been marked as a closing app earlier. We must remove ourselves 787 // from this list so we do not participate in any future animations. 788 mService.mClosingApps.remove(this); 789 } else if (mLastParent != null && mLastParent.mStack != null) { 790 task.mStack.mExitingAppTokens.remove(this); 791 } 792 } 793 mLastParent = task; 794 } 795 796 void postWindowRemoveStartingWindowCleanup(WindowState win) { 797 // TODO: Something smells about the code below...Is there a better way? 798 if (startingWindow == win) { 799 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Notify removed startingWindow " + win); 800 if (getController() != null) { 801 getController().removeStartingWindow(); 802 } 803 } else if (mChildren.size() == 0) { 804 // If this is the last window and we had requested a starting transition window, 805 // well there is no point now. 806 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Nulling last startingData"); 807 startingData = null; 808 if (mHiddenSetFromTransferredStartingWindow) { 809 // We set the hidden state to false for the token from a transferred starting window. 810 // We now reset it back to true since the starting window was the last window in the 811 // token. 812 hidden = true; 813 } 814 } else if (mChildren.size() == 1 && startingSurface != null && !isRelaunching()) { 815 // If this is the last window except for a starting transition window, 816 // we need to get rid of the starting transition. 817 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Last window, removing starting window " 818 + win); 819 if (getController() != null) { 820 getController().removeStartingWindow(); 821 } 822 } 823 } 824 825 void removeDeadWindows() { 826 for (int winNdx = mChildren.size() - 1; winNdx >= 0; --winNdx) { 827 WindowState win = mChildren.get(winNdx); 828 if (win.mAppDied) { 829 if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.w(TAG, 830 "removeDeadWindows: " + win); 831 // Set mDestroying, we don't want any animation or delayed removal here. 832 win.mDestroying = true; 833 // Also removes child windows. 834 win.removeIfPossible(); 835 } 836 } 837 } 838 839 boolean hasWindowsAlive() { 840 for (int i = mChildren.size() - 1; i >= 0; i--) { 841 // No need to loop through child windows as the answer should be the same as that of the 842 // parent window. 843 if (!(mChildren.get(i)).mAppDied) { 844 return true; 845 } 846 } 847 return false; 848 } 849 850 void setWillReplaceWindows(boolean animate) { 851 if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, 852 "Marking app token " + this + " with replacing windows."); 853 854 for (int i = mChildren.size() - 1; i >= 0; i--) { 855 final WindowState w = mChildren.get(i); 856 w.setWillReplaceWindow(animate); 857 } 858 if (animate) { 859 // Set-up dummy animation so we can start treating windows associated with this 860 // token like they are in transition before the new app window is ready for us to 861 // run the real transition animation. 862 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, 863 "setWillReplaceWindow() Setting dummy animation on: " + this); 864 mAppAnimator.setDummyAnimation(); 865 } 866 } 867 868 void setWillReplaceChildWindows() { 869 if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + this 870 + " with replacing child windows."); 871 for (int i = mChildren.size() - 1; i >= 0; i--) { 872 final WindowState w = mChildren.get(i); 873 w.setWillReplaceChildWindows(); 874 } 875 } 876 877 void clearWillReplaceWindows() { 878 if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, 879 "Resetting app token " + this + " of replacing window marks."); 880 881 for (int i = mChildren.size() - 1; i >= 0; i--) { 882 final WindowState w = mChildren.get(i); 883 w.clearWillReplaceWindow(); 884 } 885 } 886 887 void requestUpdateWallpaperIfNeeded() { 888 for (int i = mChildren.size() - 1; i >= 0; i--) { 889 final WindowState w = mChildren.get(i); 890 w.requestUpdateWallpaperIfNeeded(); 891 } 892 } 893 894 boolean isRelaunching() { 895 return mPendingRelaunchCount > 0; 896 } 897 898 boolean shouldFreezeBounds() { 899 final Task task = getTask(); 900 901 // For freeform windows, we can't freeze the bounds at the moment because this would make 902 // the resizing unresponsive. 903 if (task == null || task.inFreeformWorkspace()) { 904 return false; 905 } 906 907 // We freeze the bounds while drag resizing to deal with the time between 908 // the divider/drag handle being released, and the handling it's new 909 // configuration. If we are relaunched outside of the drag resizing state, 910 // we need to be careful not to do this. 911 return getTask().isDragResizing(); 912 } 913 914 void startRelaunching() { 915 if (shouldFreezeBounds()) { 916 freezeBounds(); 917 } 918 919 // In the process of tearing down before relaunching, the app will 920 // try and clean up it's child surfaces. We need to prevent this from 921 // happening, so we sever the children, transfering their ownership 922 // from the client it-self to the parent surface (owned by us). 923 for (int i = mChildren.size() - 1; i >= 0; i--) { 924 final WindowState w = mChildren.get(i); 925 w.mWinAnimator.detachChildren(); 926 } 927 928 mPendingRelaunchCount++; 929 } 930 931 void finishRelaunching() { 932 unfreezeBounds(); 933 934 if (mPendingRelaunchCount > 0) { 935 mPendingRelaunchCount--; 936 } else { 937 // Update keyguard flags upon finishing relaunch. 938 checkKeyguardFlagsChanged(); 939 } 940 941 updateAllDrawn(); 942 } 943 944 void clearRelaunching() { 945 if (mPendingRelaunchCount == 0) { 946 return; 947 } 948 unfreezeBounds(); 949 mPendingRelaunchCount = 0; 950 } 951 952 /** 953 * Returns true if the new child window we are adding to this token is considered greater than 954 * the existing child window in this token in terms of z-order. 955 */ 956 @Override 957 protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow, 958 WindowState existingWindow) { 959 final int type1 = newWindow.mAttrs.type; 960 final int type2 = existingWindow.mAttrs.type; 961 962 // Base application windows should be z-ordered BELOW all other windows in the app token. 963 if (type1 == TYPE_BASE_APPLICATION && type2 != TYPE_BASE_APPLICATION) { 964 return false; 965 } else if (type1 != TYPE_BASE_APPLICATION && type2 == TYPE_BASE_APPLICATION) { 966 return true; 967 } 968 969 // Starting windows should be z-ordered ABOVE all other windows in the app token. 970 if (type1 == TYPE_APPLICATION_STARTING && type2 != TYPE_APPLICATION_STARTING) { 971 return true; 972 } else if (type1 != TYPE_APPLICATION_STARTING && type2 == TYPE_APPLICATION_STARTING) { 973 return false; 974 } 975 976 // Otherwise the new window is greater than the existing window. 977 return true; 978 } 979 980 @Override 981 void addWindow(WindowState w) { 982 super.addWindow(w); 983 984 boolean gotReplacementWindow = false; 985 for (int i = mChildren.size() - 1; i >= 0; i--) { 986 final WindowState candidate = mChildren.get(i); 987 gotReplacementWindow |= candidate.setReplacementWindowIfNeeded(w); 988 } 989 990 // if we got a replacement window, reset the timeout to give drawing more time 991 if (gotReplacementWindow) { 992 mService.scheduleWindowReplacementTimeouts(this); 993 } 994 checkKeyguardFlagsChanged(); 995 } 996 997 @Override 998 void removeChild(WindowState child) { 999 super.removeChild(child); 1000 checkKeyguardFlagsChanged(); 1001 } 1002 1003 private boolean waitingForReplacement() { 1004 for (int i = mChildren.size() - 1; i >= 0; i--) { 1005 final WindowState candidate = mChildren.get(i); 1006 if (candidate.waitingForReplacement()) { 1007 return true; 1008 } 1009 } 1010 return false; 1011 } 1012 1013 void onWindowReplacementTimeout() { 1014 for (int i = mChildren.size() - 1; i >= 0; --i) { 1015 (mChildren.get(i)).onWindowReplacementTimeout(); 1016 } 1017 } 1018 1019 void reparent(Task task, int position) { 1020 final Task currentTask = getTask(); 1021 if (task == currentTask) { 1022 throw new IllegalArgumentException( 1023 "window token=" + this + " already child of task=" + currentTask); 1024 } 1025 1026 if (currentTask.mStack != task.mStack) { 1027 throw new IllegalArgumentException( 1028 "window token=" + this + " current task=" + currentTask 1029 + " belongs to a different stack than " + task); 1030 } 1031 1032 if (DEBUG_ADD_REMOVE) Slog.i(TAG, "reParentWindowToken: removing window token=" + this 1033 + " from task=" + currentTask); 1034 final DisplayContent prevDisplayContent = getDisplayContent(); 1035 1036 mReparenting = true; 1037 1038 getParent().removeChild(this); 1039 task.addChild(this, position); 1040 1041 mReparenting = false; 1042 1043 // Relayout display(s). 1044 final DisplayContent displayContent = task.getDisplayContent(); 1045 displayContent.setLayoutNeeded(); 1046 if (prevDisplayContent != displayContent) { 1047 onDisplayChanged(displayContent); 1048 prevDisplayContent.setLayoutNeeded(); 1049 } 1050 } 1051 1052 /** 1053 * Freezes the task bounds. The size of this task reported the app will be fixed to the bounds 1054 * freezed by {@link Task#prepareFreezingBounds} until {@link #unfreezeBounds} gets called, even 1055 * if they change in the meantime. If the bounds are already frozen, the bounds will be frozen 1056 * with a queue. 1057 */ 1058 private void freezeBounds() { 1059 final Task task = getTask(); 1060 mFrozenBounds.offer(new Rect(task.mPreparedFrozenBounds)); 1061 1062 if (task.mPreparedFrozenMergedConfig.equals(Configuration.EMPTY)) { 1063 // We didn't call prepareFreezingBounds on the task, so use the current value. 1064 mFrozenMergedConfig.offer(new Configuration(task.getConfiguration())); 1065 } else { 1066 mFrozenMergedConfig.offer(new Configuration(task.mPreparedFrozenMergedConfig)); 1067 } 1068 // Calling unset() to make it equal to Configuration.EMPTY. 1069 task.mPreparedFrozenMergedConfig.unset(); 1070 } 1071 1072 /** 1073 * Unfreezes the previously frozen bounds. See {@link #freezeBounds}. 1074 */ 1075 private void unfreezeBounds() { 1076 if (mFrozenBounds.isEmpty()) { 1077 return; 1078 } 1079 mFrozenBounds.remove(); 1080 if (!mFrozenMergedConfig.isEmpty()) { 1081 mFrozenMergedConfig.remove(); 1082 } 1083 for (int i = mChildren.size() - 1; i >= 0; i--) { 1084 final WindowState win = mChildren.get(i); 1085 win.onUnfreezeBounds(); 1086 } 1087 mService.mWindowPlacerLocked.performSurfacePlacement(); 1088 } 1089 1090 void setAppLayoutChanges(int changes, String reason) { 1091 if (!mChildren.isEmpty()) { 1092 final DisplayContent dc = getDisplayContent(); 1093 dc.pendingLayoutChanges |= changes; 1094 if (DEBUG_LAYOUT_REPEATS) { 1095 mService.mWindowPlacerLocked.debugLayoutRepeats(reason, dc.pendingLayoutChanges); 1096 } 1097 } 1098 } 1099 1100 void removeReplacedWindowIfNeeded(WindowState replacement) { 1101 for (int i = mChildren.size() - 1; i >= 0; i--) { 1102 final WindowState win = mChildren.get(i); 1103 if (win.removeReplacedWindowIfNeeded(replacement)) { 1104 return; 1105 } 1106 } 1107 } 1108 1109 void startFreezingScreen() { 1110 if (DEBUG_ORIENTATION) logWithStack(TAG, "Set freezing of " + appToken + ": hidden=" 1111 + hidden + " freezing=" + mAppAnimator.freezingScreen + " hiddenRequested=" 1112 + hiddenRequested); 1113 if (!hiddenRequested) { 1114 if (!mAppAnimator.freezingScreen) { 1115 mAppAnimator.freezingScreen = true; 1116 mService.registerAppFreezeListener(this); 1117 mAppAnimator.lastFreezeDuration = 0; 1118 mService.mAppsFreezingScreen++; 1119 if (mService.mAppsFreezingScreen == 1) { 1120 mService.startFreezingDisplayLocked(false, 0, 0, getDisplayContent()); 1121 mService.mH.removeMessages(H.APP_FREEZE_TIMEOUT); 1122 mService.mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000); 1123 } 1124 } 1125 final int count = mChildren.size(); 1126 for (int i = 0; i < count; i++) { 1127 final WindowState w = mChildren.get(i); 1128 w.onStartFreezingScreen(); 1129 } 1130 } 1131 } 1132 1133 void stopFreezingScreen(boolean unfreezeSurfaceNow, boolean force) { 1134 if (!mAppAnimator.freezingScreen) { 1135 return; 1136 } 1137 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + this + " force=" + force); 1138 final int count = mChildren.size(); 1139 boolean unfrozeWindows = false; 1140 for (int i = 0; i < count; i++) { 1141 final WindowState w = mChildren.get(i); 1142 unfrozeWindows |= w.onStopFreezingScreen(); 1143 } 1144 if (force || unfrozeWindows) { 1145 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "No longer freezing: " + this); 1146 mAppAnimator.freezingScreen = false; 1147 mService.unregisterAppFreezeListener(this); 1148 mAppAnimator.lastFreezeDuration = 1149 (int)(SystemClock.elapsedRealtime() - mService.mDisplayFreezeTime); 1150 mService.mAppsFreezingScreen--; 1151 mService.mLastFinishedFreezeSource = this; 1152 } 1153 if (unfreezeSurfaceNow) { 1154 if (unfrozeWindows) { 1155 mService.mWindowPlacerLocked.performSurfacePlacement(); 1156 } 1157 mService.stopFreezingDisplayLocked(); 1158 } 1159 } 1160 1161 @Override 1162 public void onAppFreezeTimeout() { 1163 Slog.w(TAG_WM, "Force clearing freeze: " + this); 1164 stopFreezingScreen(true, true); 1165 } 1166 1167 boolean transferStartingWindow(IBinder transferFrom) { 1168 final AppWindowToken fromToken = getDisplayContent().getAppWindowToken(transferFrom); 1169 if (fromToken == null) { 1170 return false; 1171 } 1172 1173 final WindowState tStartingWindow = fromToken.startingWindow; 1174 if (tStartingWindow != null && fromToken.startingSurface != null) { 1175 // In this case, the starting icon has already been displayed, so start 1176 // letting windows get shown immediately without any more transitions. 1177 mService.mSkipAppTransitionAnimation = true; 1178 1179 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Moving existing starting " + tStartingWindow 1180 + " from " + fromToken + " to " + this); 1181 1182 final long origId = Binder.clearCallingIdentity(); 1183 1184 // Transfer the starting window over to the new token. 1185 startingData = fromToken.startingData; 1186 startingSurface = fromToken.startingSurface; 1187 startingDisplayed = fromToken.startingDisplayed; 1188 fromToken.startingDisplayed = false; 1189 startingWindow = tStartingWindow; 1190 reportedVisible = fromToken.reportedVisible; 1191 fromToken.startingData = null; 1192 fromToken.startingSurface = null; 1193 fromToken.startingWindow = null; 1194 fromToken.startingMoved = true; 1195 tStartingWindow.mToken = this; 1196 tStartingWindow.mAppToken = this; 1197 1198 if (DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, 1199 "Removing starting " + tStartingWindow + " from " + fromToken); 1200 fromToken.removeChild(tStartingWindow); 1201 fromToken.postWindowRemoveStartingWindowCleanup(tStartingWindow); 1202 fromToken.mHiddenSetFromTransferredStartingWindow = false; 1203 addWindow(tStartingWindow); 1204 1205 // Propagate other interesting state between the tokens. If the old token is displayed, 1206 // we should immediately force the new one to be displayed. If it is animating, we need 1207 // to move that animation to the new one. 1208 if (fromToken.allDrawn) { 1209 allDrawn = true; 1210 deferClearAllDrawn = fromToken.deferClearAllDrawn; 1211 } 1212 if (fromToken.firstWindowDrawn) { 1213 firstWindowDrawn = true; 1214 } 1215 if (!fromToken.hidden) { 1216 hidden = false; 1217 hiddenRequested = false; 1218 mHiddenSetFromTransferredStartingWindow = true; 1219 } 1220 setClientHidden(fromToken.mClientHidden); 1221 fromToken.mAppAnimator.transferCurrentAnimation( 1222 mAppAnimator, tStartingWindow.mWinAnimator); 1223 1224 mService.updateFocusedWindowLocked( 1225 UPDATE_FOCUS_WILL_PLACE_SURFACES, true /*updateInputWindows*/); 1226 getDisplayContent().setLayoutNeeded(); 1227 mService.mWindowPlacerLocked.performSurfacePlacement(); 1228 Binder.restoreCallingIdentity(origId); 1229 return true; 1230 } else if (fromToken.startingData != null) { 1231 // The previous app was getting ready to show a 1232 // starting window, but hasn't yet done so. Steal it! 1233 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, 1234 "Moving pending starting from " + fromToken + " to " + this); 1235 startingData = fromToken.startingData; 1236 fromToken.startingData = null; 1237 fromToken.startingMoved = true; 1238 if (getController() != null) { 1239 getController().scheduleAddStartingWindow(); 1240 } 1241 return true; 1242 } 1243 1244 final AppWindowAnimator tAppAnimator = fromToken.mAppAnimator; 1245 final AppWindowAnimator wAppAnimator = mAppAnimator; 1246 if (tAppAnimator.thumbnail != null) { 1247 // The old token is animating with a thumbnail, transfer that to the new token. 1248 if (wAppAnimator.thumbnail != null) { 1249 wAppAnimator.thumbnail.destroy(); 1250 } 1251 wAppAnimator.thumbnail = tAppAnimator.thumbnail; 1252 wAppAnimator.thumbnailLayer = tAppAnimator.thumbnailLayer; 1253 wAppAnimator.thumbnailAnimation = tAppAnimator.thumbnailAnimation; 1254 tAppAnimator.thumbnail = null; 1255 } 1256 return false; 1257 } 1258 1259 boolean isLastWindow(WindowState win) { 1260 return mChildren.size() == 1 && mChildren.get(0) == win; 1261 } 1262 1263 void setAllAppWinAnimators() { 1264 final ArrayList<WindowStateAnimator> allAppWinAnimators = mAppAnimator.mAllAppWinAnimators; 1265 allAppWinAnimators.clear(); 1266 1267 final int windowsCount = mChildren.size(); 1268 for (int j = 0; j < windowsCount; j++) { 1269 (mChildren.get(j)).addWinAnimatorToList(allAppWinAnimators); 1270 } 1271 } 1272 1273 @Override 1274 void onAppTransitionDone() { 1275 sendingToBottom = false; 1276 } 1277 1278 /** 1279 * We override because this class doesn't want its children affecting its reported orientation 1280 * in anyway. 1281 */ 1282 @Override 1283 int getOrientation(int candidate) { 1284 // We do not allow non-fullscreen apps to influence orientation beyond O. While we do 1285 // throw an exception in {@link Activity#onCreate} and 1286 // {@link Activity#setRequestedOrientation}, we also ignore the orientation here so that 1287 // other calculations aren't affected. 1288 if (!fillsParent() && mTargetSdk > O) { 1289 // Can't specify orientation if app doesn't fill parent. 1290 return SCREEN_ORIENTATION_UNSET; 1291 } 1292 1293 if (candidate == SCREEN_ORIENTATION_BEHIND) { 1294 // Allow app to specify orientation regardless of its visibility state if the current 1295 // candidate want us to use orientation behind. I.e. the visible app on-top of this one 1296 // wants us to use the orientation of the app behind it. 1297 return mOrientation; 1298 } 1299 1300 // The {@link AppWindowToken} should only specify an orientation when it is not closing or 1301 // going to the bottom. Allowing closing {@link AppWindowToken} to participate can lead to 1302 // an Activity in another task being started in the wrong orientation during the transition. 1303 if (!(sendingToBottom || mService.mClosingApps.contains(this)) 1304 && (isVisible() || mService.mOpeningApps.contains(this))) { 1305 return mOrientation; 1306 } 1307 1308 return SCREEN_ORIENTATION_UNSET; 1309 } 1310 1311 /** Returns the app's preferred orientation regardless of its currently visibility state. */ 1312 int getOrientationIgnoreVisibility() { 1313 return mOrientation; 1314 } 1315 1316 @Override 1317 void checkAppWindowsReadyToShow() { 1318 if (allDrawn == mAppAnimator.allDrawn) { 1319 return; 1320 } 1321 1322 mAppAnimator.allDrawn = allDrawn; 1323 if (!allDrawn) { 1324 return; 1325 } 1326 1327 // The token has now changed state to having all windows shown... what to do, what to do? 1328 if (mAppAnimator.freezingScreen) { 1329 mAppAnimator.showAllWindowsLocked(); 1330 stopFreezingScreen(false, true); 1331 if (DEBUG_ORIENTATION) Slog.i(TAG, 1332 "Setting mOrientationChangeComplete=true because wtoken " + this 1333 + " numInteresting=" + mNumInterestingWindows + " numDrawn=" + mNumDrawnWindows); 1334 // This will set mOrientationChangeComplete and cause a pass through layout. 1335 setAppLayoutChanges(FINISH_LAYOUT_REDO_WALLPAPER, 1336 "checkAppWindowsReadyToShow: freezingScreen"); 1337 } else { 1338 setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM, "checkAppWindowsReadyToShow"); 1339 1340 // We can now show all of the drawn windows! 1341 if (!mService.mOpeningApps.contains(this)) { 1342 mService.mAnimator.orAnimating(mAppAnimator.showAllWindowsLocked()); 1343 } 1344 } 1345 } 1346 1347 void updateAllDrawn() { 1348 if (!allDrawn) { 1349 // Number of drawn windows can be less when a window is being relaunched, wait for 1350 // all windows to be launched and drawn for this token be considered all drawn 1351 final int numInteresting = mNumInterestingWindows; 1352 if (numInteresting > 0 && mNumDrawnWindows >= numInteresting && !isRelaunching()) { 1353 if (DEBUG_VISIBILITY) Slog.v(TAG, "allDrawn: " + this 1354 + " interesting=" + numInteresting + " drawn=" + mNumDrawnWindows); 1355 allDrawn = true; 1356 // Force an additional layout pass where 1357 // WindowStateAnimator#commitFinishDrawingLocked() will call performShowLocked(). 1358 if (mDisplayContent != null) { 1359 mDisplayContent.setLayoutNeeded(); 1360 } 1361 mService.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN, token).sendToTarget(); 1362 1363 // Notify the pinned stack upon all windows drawn. If there was an animation in 1364 // progress then this signal will resume that animation. 1365 final TaskStack pinnedStack = mDisplayContent.getStackById(PINNED_STACK_ID); 1366 if (pinnedStack != null) { 1367 pinnedStack.onAllWindowsDrawn(); 1368 } 1369 } 1370 } 1371 1372 if (!allDrawnExcludingSaved) { 1373 int numInteresting = mNumInterestingWindowsExcludingSaved; 1374 if (numInteresting > 0 && mNumDrawnWindowsExcludingSaved >= numInteresting) { 1375 if (DEBUG_VISIBILITY) Slog.v(TAG, "allDrawnExcludingSaved: " + this 1376 + " interesting=" + numInteresting 1377 + " drawn=" + mNumDrawnWindowsExcludingSaved); 1378 allDrawnExcludingSaved = true; 1379 if (mDisplayContent != null) { 1380 mDisplayContent.setLayoutNeeded(); 1381 } 1382 if (isAnimatingInvisibleWithSavedSurface() 1383 && !mService.mFinishedEarlyAnim.contains(this)) { 1384 mService.mFinishedEarlyAnim.add(this); 1385 } 1386 } 1387 } 1388 } 1389 1390 /** 1391 * Updated this app token tracking states for interesting and drawn windows based on the window. 1392 * 1393 * @return Returns true if the input window is considered interesting and drawn while all the 1394 * windows in this app token where not considered drawn as of the last pass. 1395 */ 1396 boolean updateDrawnWindowStates(WindowState w) { 1397 if (DEBUG_STARTING_WINDOW_VERBOSE && w == startingWindow) { 1398 Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen=" + w.isOnScreen() 1399 + " allDrawn=" + allDrawn + " freezingScreen=" + mAppAnimator.freezingScreen); 1400 } 1401 1402 if (allDrawn && allDrawnExcludingSaved && !mAppAnimator.freezingScreen) { 1403 return false; 1404 } 1405 1406 if (mLastTransactionSequence != mService.mTransactionSequence) { 1407 mLastTransactionSequence = mService.mTransactionSequence; 1408 mNumInterestingWindows = mNumDrawnWindows = 0; 1409 mNumInterestingWindowsExcludingSaved = 0; 1410 mNumDrawnWindowsExcludingSaved = 0; 1411 startingDisplayed = false; 1412 } 1413 1414 final WindowStateAnimator winAnimator = w.mWinAnimator; 1415 1416 boolean isInterestingAndDrawn = false; 1417 1418 if (!allDrawn && w.mightAffectAllDrawn(false /* visibleOnly */)) { 1419 if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) { 1420 Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw() 1421 + ", isAnimationSet=" + winAnimator.isAnimationSet()); 1422 if (!w.isDrawnLw()) { 1423 Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceController 1424 + " pv=" + w.mPolicyVisibility 1425 + " mDrawState=" + winAnimator.drawStateToString() 1426 + " ph=" + w.isParentWindowHidden() + " th=" + hiddenRequested 1427 + " a=" + winAnimator.mAnimating); 1428 } 1429 } 1430 1431 if (w != startingWindow) { 1432 if (w.isInteresting()) { 1433 mNumInterestingWindows++; 1434 if (w.isDrawnLw()) { 1435 mNumDrawnWindows++; 1436 1437 if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG, "tokenMayBeDrawn: " 1438 + this + " w=" + w + " numInteresting=" + mNumInterestingWindows 1439 + " freezingScreen=" + mAppAnimator.freezingScreen 1440 + " mAppFreezing=" + w.mAppFreezing); 1441 1442 isInterestingAndDrawn = true; 1443 } 1444 } 1445 } else if (w.isDrawnLw()) { 1446 if (getController() != null) { 1447 getController().reportStartingWindowDrawn(); 1448 } 1449 startingDisplayed = true; 1450 } 1451 } 1452 1453 if (!allDrawnExcludingSaved && w.mightAffectAllDrawn(true /* visibleOnly */)) { 1454 if (w != startingWindow && w.isInteresting()) { 1455 mNumInterestingWindowsExcludingSaved++; 1456 if (w.isDrawnLw() && !w.isAnimatingWithSavedSurface()) { 1457 mNumDrawnWindowsExcludingSaved++; 1458 1459 if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG, 1460 "tokenMayBeDrawnExcludingSaved: " + this + " w=" + w 1461 + " numInteresting=" + mNumInterestingWindowsExcludingSaved 1462 + " freezingScreen=" + mAppAnimator.freezingScreen 1463 + " mAppFreezing=" + w.mAppFreezing); 1464 1465 isInterestingAndDrawn = true; 1466 } 1467 } 1468 } 1469 1470 return isInterestingAndDrawn; 1471 } 1472 1473 @Override 1474 void stepAppWindowsAnimation(long currentTime) { 1475 mAppAnimator.wasAnimating = mAppAnimator.animating; 1476 if (mAppAnimator.stepAnimationLocked(currentTime)) { 1477 mAppAnimator.animating = true; 1478 mService.mAnimator.setAnimating(true); 1479 mService.mAnimator.mAppWindowAnimating = true; 1480 } else if (mAppAnimator.wasAnimating) { 1481 // stopped animating, do one more pass through the layout 1482 setAppLayoutChanges(FINISH_LAYOUT_REDO_WALLPAPER, 1483 DEBUG_LAYOUT_REPEATS ? "appToken " + this + " done" : null); 1484 if (DEBUG_ANIM) Slog.v(TAG, "updateWindowsApps...: done animating " + this); 1485 } 1486 } 1487 1488 @Override 1489 boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) { 1490 // For legacy reasons we process the TaskStack.mExitingAppTokens first in DisplayContent 1491 // before the non-exiting app tokens. So, we skip the exiting app tokens here. 1492 // TODO: Investigate if we need to continue to do this or if we can just process them 1493 // in-order. 1494 if (mIsExiting && !waitingForReplacement()) { 1495 return false; 1496 } 1497 return forAllWindowsUnchecked(callback, traverseTopToBottom); 1498 } 1499 1500 boolean forAllWindowsUnchecked(ToBooleanFunction<WindowState> callback, 1501 boolean traverseTopToBottom) { 1502 return super.forAllWindows(callback, traverseTopToBottom); 1503 } 1504 1505 @Override 1506 AppWindowToken asAppWindowToken() { 1507 // I am an app window token! 1508 return this; 1509 } 1510 1511 @Override 1512 boolean fillsParent() { 1513 return mFillsParent; 1514 } 1515 1516 void setFillsParent(boolean fillsParent) { 1517 mFillsParent = fillsParent; 1518 } 1519 1520 boolean containsDismissKeyguardWindow() { 1521 // Window state is transient during relaunch. We are not guaranteed to be frozen during the 1522 // entirety of the relaunch. 1523 if (isRelaunching()) { 1524 return mLastContainsDismissKeyguardWindow; 1525 } 1526 1527 for (int i = mChildren.size() - 1; i >= 0; i--) { 1528 if ((mChildren.get(i).mAttrs.flags & FLAG_DISMISS_KEYGUARD) != 0) { 1529 return true; 1530 } 1531 } 1532 return false; 1533 } 1534 1535 boolean containsShowWhenLockedWindow() { 1536 // When we are relaunching, it is possible for us to be unfrozen before our previous 1537 // windows have been added back. Using the cached value ensures that our previous 1538 // showWhenLocked preference is honored until relaunching is complete. 1539 if (isRelaunching()) { 1540 return mLastContainsShowWhenLockedWindow; 1541 } 1542 1543 for (int i = mChildren.size() - 1; i >= 0; i--) { 1544 if ((mChildren.get(i).mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) { 1545 return true; 1546 } 1547 } 1548 1549 return false; 1550 } 1551 1552 void checkKeyguardFlagsChanged() { 1553 final boolean containsDismissKeyguard = containsDismissKeyguardWindow(); 1554 final boolean containsShowWhenLocked = containsShowWhenLockedWindow(); 1555 if (containsDismissKeyguard != mLastContainsDismissKeyguardWindow 1556 || containsShowWhenLocked != mLastContainsShowWhenLockedWindow) { 1557 mService.notifyKeyguardFlagsChanged(null /* callback */); 1558 } 1559 mLastContainsDismissKeyguardWindow = containsDismissKeyguard; 1560 mLastContainsShowWhenLockedWindow = containsShowWhenLocked; 1561 } 1562 1563 WindowState getImeTargetBelowWindow(WindowState w) { 1564 final int index = mChildren.indexOf(w); 1565 if (index > 0) { 1566 final WindowState target = mChildren.get(index - 1); 1567 if (target.canBeImeTarget()) { 1568 return target; 1569 } 1570 } 1571 return null; 1572 } 1573 1574 WindowState getHighestAnimLayerWindow(WindowState currentTarget) { 1575 WindowState candidate = null; 1576 for (int i = mChildren.indexOf(currentTarget); i >= 0; i--) { 1577 final WindowState w = mChildren.get(i); 1578 if (w.mRemoved) { 1579 continue; 1580 } 1581 if (candidate == null || w.mWinAnimator.mAnimLayer > 1582 candidate.mWinAnimator.mAnimLayer) { 1583 candidate = w; 1584 } 1585 } 1586 return candidate; 1587 } 1588 1589 /** 1590 * See {@link Activity#setDisablePreviewScreenshots}. 1591 */ 1592 void setDisablePreviewScreenshots(boolean disable) { 1593 mDisablePreviewScreenshots = disable; 1594 } 1595 1596 /** 1597 * Retrieves whether we'd like to generate a snapshot that's based solely on the theme. This is 1598 * the case when preview screenshots are disabled {@link #setDisablePreviewScreenshots} or when 1599 * we can't take a snapshot for other reasons, for example, if we have a secure window. 1600 * 1601 * @return True if we need to generate an app theme snapshot, false if we'd like to take a real 1602 * screenshot. 1603 */ 1604 boolean shouldUseAppThemeSnapshot() { 1605 return mDisablePreviewScreenshots || forAllWindows(w -> (w.mAttrs.flags & FLAG_SECURE) != 0, 1606 true /* topToBottom */); 1607 } 1608 1609 @Override 1610 int getAnimLayerAdjustment() { 1611 return mAppAnimator.animLayerAdjustment; 1612 } 1613 1614 @Override 1615 void dump(PrintWriter pw, String prefix) { 1616 super.dump(pw, prefix); 1617 if (appToken != null) { 1618 pw.println(prefix + "app=true mVoiceInteraction=" + mVoiceInteraction); 1619 } 1620 pw.print(prefix); pw.print("task="); pw.println(getTask()); 1621 pw.print(prefix); pw.print(" mFillsParent="); pw.print(mFillsParent); 1622 pw.print(" mOrientation="); pw.println(mOrientation); 1623 pw.println(prefix + "hiddenRequested=" + hiddenRequested + " mClientHidden=" + mClientHidden 1624 + ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "") 1625 + " reportedDrawn=" + reportedDrawn + " reportedVisible=" + reportedVisible); 1626 if (paused) { 1627 pw.print(prefix); pw.print("paused="); pw.println(paused); 1628 } 1629 if (mAppStopped) { 1630 pw.print(prefix); pw.print("mAppStopped="); pw.println(mAppStopped); 1631 } 1632 if (mNumInterestingWindows != 0 || mNumDrawnWindows != 0 1633 || allDrawn || mAppAnimator.allDrawn) { 1634 pw.print(prefix); pw.print("mNumInterestingWindows="); 1635 pw.print(mNumInterestingWindows); 1636 pw.print(" mNumDrawnWindows="); pw.print(mNumDrawnWindows); 1637 pw.print(" inPendingTransaction="); pw.print(inPendingTransaction); 1638 pw.print(" allDrawn="); pw.print(allDrawn); 1639 pw.print(" (animator="); pw.print(mAppAnimator.allDrawn); 1640 pw.println(")"); 1641 } 1642 if (inPendingTransaction) { 1643 pw.print(prefix); pw.print("inPendingTransaction="); 1644 pw.println(inPendingTransaction); 1645 } 1646 if (startingData != null || removed || firstWindowDrawn || mIsExiting) { 1647 pw.print(prefix); pw.print("startingData="); pw.print(startingData); 1648 pw.print(" removed="); pw.print(removed); 1649 pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn); 1650 pw.print(" mIsExiting="); pw.println(mIsExiting); 1651 } 1652 if (startingWindow != null || startingSurface != null 1653 || startingDisplayed || startingMoved || mHiddenSetFromTransferredStartingWindow) { 1654 pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow); 1655 pw.print(" startingSurface="); pw.print(startingSurface); 1656 pw.print(" startingDisplayed="); pw.print(startingDisplayed); 1657 pw.print(" startingMoved="); pw.print(startingMoved); 1658 pw.println(" mHiddenSetFromTransferredStartingWindow=" 1659 + mHiddenSetFromTransferredStartingWindow); 1660 } 1661 if (!mFrozenBounds.isEmpty()) { 1662 pw.print(prefix); pw.print("mFrozenBounds="); pw.println(mFrozenBounds); 1663 pw.print(prefix); pw.print("mFrozenMergedConfig="); pw.println(mFrozenMergedConfig); 1664 } 1665 if (mPendingRelaunchCount != 0) { 1666 pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount); 1667 } 1668 if (getController() != null) { 1669 pw.print(prefix); pw.print("controller="); pw.println(getController()); 1670 } 1671 if (mRemovingFromDisplay) { 1672 pw.println(prefix + "mRemovingFromDisplay=" + mRemovingFromDisplay); 1673 } 1674 } 1675 1676 @Override 1677 public String toString() { 1678 if (stringName == null) { 1679 StringBuilder sb = new StringBuilder(); 1680 sb.append("AppWindowToken{"); 1681 sb.append(Integer.toHexString(System.identityHashCode(this))); 1682 sb.append(" token="); sb.append(token); sb.append('}'); 1683 stringName = sb.toString(); 1684 } 1685 return stringName + ((mIsExiting) ? " mIsExiting=" : ""); 1686 } 1687 } 1688