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.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; 21 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; 22 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; 23 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; 24 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; 25 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; 26 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW; 27 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; 28 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT; 29 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 30 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 31 import static com.android.server.wm.WindowManagerService.WINDOW_REPLACEMENT_TIMEOUT_DURATION; 32 import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN; 33 34 import com.android.server.input.InputApplicationHandle; 35 import com.android.server.wm.WindowManagerService.H; 36 37 import android.annotation.NonNull; 38 import android.content.pm.ActivityInfo; 39 import android.content.res.Configuration; 40 import android.graphics.Rect; 41 import android.os.Message; 42 import android.os.RemoteException; 43 import android.util.Slog; 44 import android.view.IApplicationToken; 45 import android.view.View; 46 import android.view.WindowManager; 47 48 import java.io.PrintWriter; 49 import java.util.ArrayDeque; 50 import java.util.ArrayList; 51 52 class AppTokenList extends ArrayList<AppWindowToken> { 53 } 54 55 /** 56 * Version of WindowToken that is specifically for a particular application (or 57 * really activity) that is displaying windows. 58 */ 59 class AppWindowToken extends WindowToken { 60 private static final String TAG = TAG_WITH_CLASS_NAME ? "AppWindowToken" : TAG_WM; 61 62 // Non-null only for application tokens. 63 final IApplicationToken appToken; 64 65 // All of the windows and child windows that are included in this 66 // application token. Note this list is NOT sorted! 67 final WindowList allAppWindows = new WindowList(); 68 @NonNull final AppWindowAnimator mAppAnimator; 69 70 final boolean voiceInteraction; 71 72 Task mTask; 73 boolean appFullscreen; 74 int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 75 boolean layoutConfigChanges; 76 boolean showForAllUsers; 77 int targetSdk; 78 79 // The input dispatching timeout for this application token in nanoseconds. 80 long inputDispatchingTimeoutNanos; 81 82 // These are used for determining when all windows associated with 83 // an activity have been drawn, so they can be made visible together 84 // at the same time. 85 // initialize so that it doesn't match mTransactionSequence which is an int. 86 long lastTransactionSequence = Long.MIN_VALUE; 87 int numInterestingWindows; 88 int numDrawnWindows; 89 boolean inPendingTransaction; 90 boolean allDrawn; 91 // Set to true when this app creates a surface while in the middle of an animation. In that 92 // case do not clear allDrawn until the animation completes. 93 boolean deferClearAllDrawn; 94 95 // These are to track the app's real drawing status if there were no saved surfaces. 96 boolean allDrawnExcludingSaved; 97 int numInterestingWindowsExcludingSaved; 98 int numDrawnWindowsExclusingSaved; 99 100 // Is this window's surface needed? This is almost like hidden, except 101 // it will sometimes be true a little earlier: when the token has 102 // been shown, but is still waiting for its app transition to execute 103 // before making its windows shown. 104 boolean hiddenRequested; 105 106 // Have we told the window clients to hide themselves? 107 boolean clientHidden; 108 109 // Last visibility state we reported to the app token. 110 boolean reportedVisible; 111 112 // Last drawn state we reported to the app token. 113 boolean reportedDrawn; 114 115 // Set to true when the token has been removed from the window mgr. 116 boolean removed; 117 118 // Information about an application starting window if displayed. 119 StartingData startingData; 120 WindowState startingWindow; 121 View startingView; 122 boolean startingDisplayed; 123 boolean startingMoved; 124 boolean firstWindowDrawn; 125 126 // Input application handle used by the input dispatcher. 127 final InputApplicationHandle mInputApplicationHandle; 128 129 boolean mIsExiting; 130 131 boolean mLaunchTaskBehind; 132 boolean mEnteringAnimation; 133 134 boolean mAlwaysFocusable; 135 136 boolean mAppStopped; 137 int mRotationAnimationHint; 138 int mPendingRelaunchCount; 139 140 private ArrayList<WindowSurfaceController.SurfaceControlWithBackground> mSurfaceViewBackgrounds = 141 new ArrayList<WindowSurfaceController.SurfaceControlWithBackground>(); 142 143 ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>(); 144 ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>(); 145 AppWindowToken(WindowManagerService _service, IApplicationToken _token, boolean _voiceInteraction)146 AppWindowToken(WindowManagerService _service, IApplicationToken _token, 147 boolean _voiceInteraction) { 148 super(_service, _token.asBinder(), 149 WindowManager.LayoutParams.TYPE_APPLICATION, true); 150 appWindowToken = this; 151 appToken = _token; 152 voiceInteraction = _voiceInteraction; 153 mInputApplicationHandle = new InputApplicationHandle(this); 154 mAppAnimator = new AppWindowAnimator(this); 155 } 156 sendAppVisibilityToClients()157 void sendAppVisibilityToClients() { 158 final int N = allAppWindows.size(); 159 for (int i=0; i<N; i++) { 160 WindowState win = allAppWindows.get(i); 161 if (win == startingWindow && clientHidden) { 162 // Don't hide the starting window. 163 continue; 164 } 165 try { 166 if (DEBUG_VISIBILITY) Slog.v(TAG, 167 "Setting visibility of " + win + ": " + (!clientHidden)); 168 win.mClient.dispatchAppVisibility(!clientHidden); 169 } catch (RemoteException e) { 170 } 171 } 172 } 173 setVisibleBeforeClientHidden()174 void setVisibleBeforeClientHidden() { 175 for (int i = allAppWindows.size() - 1; i >= 0; i--) { 176 final WindowState w = allAppWindows.get(i); 177 w.setVisibleBeforeClientHidden(); 178 } 179 } 180 onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator)181 void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) { 182 firstWindowDrawn = true; 183 184 // We now have a good window to show, remove dead placeholders 185 removeAllDeadWindows(); 186 187 if (startingData != null) { 188 if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Slog.v(TAG, "Finish starting " 189 + win.mToken + ": first real window is shown, no animation"); 190 // If this initial window is animating, stop it -- we will do an animation to reveal 191 // it from behind the starting window, so there is no need for it to also be doing its 192 // own stuff. 193 winAnimator.clearAnimation(); 194 winAnimator.mService.mFinishedStarting.add(this); 195 winAnimator.mService.mH.sendEmptyMessage(H.FINISHED_STARTING); 196 } 197 updateReportedVisibilityLocked(); 198 } 199 updateReportedVisibilityLocked()200 void updateReportedVisibilityLocked() { 201 if (appToken == null) { 202 return; 203 } 204 205 int numInteresting = 0; 206 int numVisible = 0; 207 int numDrawn = 0; 208 boolean nowGone = true; 209 210 if (DEBUG_VISIBILITY) Slog.v(TAG, 211 "Update reported visibility: " + this); 212 final int N = allAppWindows.size(); 213 for (int i=0; i<N; i++) { 214 WindowState win = allAppWindows.get(i); 215 if (win == startingWindow || win.mAppFreezing 216 || win.mViewVisibility != View.VISIBLE 217 || win.mAttrs.type == TYPE_APPLICATION_STARTING 218 || win.mDestroying) { 219 continue; 220 } 221 if (DEBUG_VISIBILITY) { 222 Slog.v(TAG, "Win " + win + ": isDrawn=" 223 + win.isDrawnLw() 224 + ", isAnimationSet=" + win.mWinAnimator.isAnimationSet()); 225 if (!win.isDrawnLw()) { 226 Slog.v(TAG, "Not displayed: s=" + 227 win.mWinAnimator.mSurfaceController 228 + " pv=" + win.mPolicyVisibility 229 + " mDrawState=" + win.mWinAnimator.mDrawState 230 + " ah=" + win.mAttachedHidden 231 + " th=" 232 + (win.mAppToken != null 233 ? win.mAppToken.hiddenRequested : false) 234 + " a=" + win.mWinAnimator.mAnimating); 235 } 236 } 237 numInteresting++; 238 if (win.isDrawnLw()) { 239 numDrawn++; 240 if (!win.mWinAnimator.isAnimationSet()) { 241 numVisible++; 242 } 243 nowGone = false; 244 } else if (win.mWinAnimator.isAnimationSet()) { 245 nowGone = false; 246 } 247 } 248 249 boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting; 250 boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting; 251 if (!nowGone) { 252 // If the app is not yet gone, then it can only become visible/drawn. 253 if (!nowDrawn) { 254 nowDrawn = reportedDrawn; 255 } 256 if (!nowVisible) { 257 nowVisible = reportedVisible; 258 } 259 } 260 if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting=" 261 + numInteresting + " visible=" + numVisible); 262 if (nowDrawn != reportedDrawn) { 263 if (nowDrawn) { 264 Message m = service.mH.obtainMessage( 265 H.REPORT_APPLICATION_TOKEN_DRAWN, this); 266 service.mH.sendMessage(m); 267 } 268 reportedDrawn = nowDrawn; 269 } 270 if (nowVisible != reportedVisible) { 271 if (DEBUG_VISIBILITY) Slog.v( 272 TAG, "Visibility changed in " + this 273 + ": vis=" + nowVisible); 274 reportedVisible = nowVisible; 275 Message m = service.mH.obtainMessage( 276 H.REPORT_APPLICATION_TOKEN_WINDOWS, 277 nowVisible ? 1 : 0, 278 nowGone ? 1 : 0, 279 this); 280 service.mH.sendMessage(m); 281 } 282 } 283 findMainWindow()284 WindowState findMainWindow() { 285 WindowState candidate = null; 286 int j = windows.size(); 287 while (j > 0) { 288 j--; 289 WindowState win = windows.get(j); 290 if (win.mAttrs.type == WindowManager.LayoutParams.TYPE_BASE_APPLICATION 291 || win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) { 292 // In cases where there are multiple windows, we prefer the non-exiting window. This 293 // happens for example when replacing windows during an activity relaunch. When 294 // constructing the animation, we want the new window, not the exiting one. 295 if (win.mAnimatingExit) { 296 candidate = win; 297 } else { 298 return win; 299 } 300 } 301 } 302 return candidate; 303 } 304 windowsAreFocusable()305 boolean windowsAreFocusable() { 306 return StackId.canReceiveKeys(mTask.mStack.mStackId) || mAlwaysFocusable; 307 } 308 isVisible()309 boolean isVisible() { 310 final int N = allAppWindows.size(); 311 for (int i=0; i<N; i++) { 312 WindowState win = allAppWindows.get(i); 313 // If we're animating with a saved surface, we're already visible. 314 // Return true so that the alpha doesn't get cleared. 315 if (!win.mAppFreezing 316 && (win.mViewVisibility == View.VISIBLE || win.isAnimatingWithSavedSurface() 317 || (win.mWinAnimator.isAnimationSet() 318 && !service.mAppTransition.isTransitionSet())) 319 && !win.mDestroying 320 && win.isDrawnLw()) { 321 return true; 322 } 323 } 324 return false; 325 } 326 removeAppFromTaskLocked()327 void removeAppFromTaskLocked() { 328 mIsExiting = false; 329 removeAllWindows(); 330 331 // Use local variable because removeAppToken will null out mTask. 332 final Task task = mTask; 333 if (task != null) { 334 if (!task.removeAppToken(this)) { 335 Slog.e(TAG, "removeAppFromTaskLocked: token=" + this 336 + " not found."); 337 } 338 task.mStack.mExitingAppTokens.remove(this); 339 } 340 } 341 clearAnimatingFlags()342 void clearAnimatingFlags() { 343 boolean wallpaperMightChange = false; 344 for (int i = allAppWindows.size() - 1; i >= 0; i--) { 345 final WindowState win = allAppWindows.get(i); 346 // We don't want to clear it out for windows that get replaced, because the 347 // animation depends on the flag to remove the replaced window. 348 // 349 // We also don't clear the mAnimatingExit flag for windows which have the 350 // mRemoveOnExit flag. This indicates an explicit remove request has been issued 351 // by the client. We should let animation proceed and not clear this flag or 352 // they won't eventually be removed by WindowStateAnimator#finishExit. 353 if (!win.mWillReplaceWindow && !win.mRemoveOnExit) { 354 // Clear mAnimating flag together with mAnimatingExit. When animation 355 // changes from exiting to entering, we need to clear this flag until the 356 // new animation gets applied, so that isAnimationStarting() becomes true 357 // until then. 358 // Otherwise applySurfaceChangesTransaction will faill to skip surface 359 // placement for this window during this period, one or more frame will 360 // show up with wrong position or scale. 361 if (win.mAnimatingExit) { 362 win.mAnimatingExit = false; 363 wallpaperMightChange = true; 364 } 365 if (win.mWinAnimator.mAnimating) { 366 win.mWinAnimator.mAnimating = false; 367 wallpaperMightChange = true; 368 } 369 if (win.mDestroying) { 370 win.mDestroying = false; 371 service.mDestroySurface.remove(win); 372 wallpaperMightChange = true; 373 } 374 } 375 } 376 if (wallpaperMightChange) { 377 requestUpdateWallpaperIfNeeded(); 378 } 379 } 380 destroySurfaces()381 void destroySurfaces() { 382 destroySurfaces(false /*cleanupOnResume*/); 383 } 384 385 /** 386 * Destroy surfaces which have been marked as eligible by the animator, taking care to ensure 387 * the client has finished with them. 388 * 389 * @param cleanupOnResume whether this is done when app is resumed without fully stopped. If 390 * set to true, destroy only surfaces of removed windows, and clear relevant flags of the 391 * others so that they are ready to be reused. If set to false (common case), destroy all 392 * surfaces that's eligible, if the app is already stopped. 393 */ 394 destroySurfaces(boolean cleanupOnResume)395 private void destroySurfaces(boolean cleanupOnResume) { 396 final ArrayList<WindowState> allWindows = (ArrayList<WindowState>) allAppWindows.clone(); 397 final DisplayContentList displayList = new DisplayContentList(); 398 for (int i = allWindows.size() - 1; i >= 0; i--) { 399 final WindowState win = allWindows.get(i); 400 401 if (!(mAppStopped || win.mWindowRemovalAllowed || cleanupOnResume)) { 402 continue; 403 } 404 405 win.mWinAnimator.destroyPreservedSurfaceLocked(); 406 407 if (!win.mDestroying) { 408 continue; 409 } 410 411 if (DEBUG_ADD_REMOVE) Slog.e(TAG_WM, "win=" + win 412 + " destroySurfaces: mAppStopped=" + mAppStopped 413 + " win.mWindowRemovalAllowed=" + win.mWindowRemovalAllowed 414 + " win.mRemoveOnExit=" + win.mRemoveOnExit); 415 416 if (!cleanupOnResume || win.mRemoveOnExit) { 417 win.destroyOrSaveSurface(); 418 } 419 if (win.mRemoveOnExit) { 420 service.removeWindowInnerLocked(win); 421 } 422 final DisplayContent displayContent = win.getDisplayContent(); 423 if (displayContent != null && !displayList.contains(displayContent)) { 424 displayList.add(displayContent); 425 } 426 if (cleanupOnResume) { 427 win.requestUpdateWallpaperIfNeeded(); 428 } 429 win.mDestroying = false; 430 } 431 for (int i = 0; i < displayList.size(); i++) { 432 final DisplayContent displayContent = displayList.get(i); 433 service.mLayersController.assignLayersLocked(displayContent.getWindowList()); 434 displayContent.layoutNeeded = true; 435 } 436 } 437 438 /** 439 * Notify that the app is now resumed, and it was not stopped before, perform a clean 440 * up of the surfaces 441 */ notifyAppResumed(boolean wasStopped, boolean allowSavedSurface)442 void notifyAppResumed(boolean wasStopped, boolean allowSavedSurface) { 443 if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppResumed: wasStopped=" + wasStopped 444 + " allowSavedSurface=" + allowSavedSurface + " " + this); 445 mAppStopped = false; 446 if (!wasStopped) { 447 destroySurfaces(true /*cleanupOnResume*/); 448 } 449 if (!allowSavedSurface) { 450 destroySavedSurfaces(); 451 } 452 } 453 454 /** 455 * Notify that the app has stopped, and it is okay to destroy any surfaces which were 456 * keeping alive in case they were still being used. 457 */ notifyAppStopped()458 void notifyAppStopped() { 459 if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppStopped: " + this); 460 mAppStopped = true; 461 destroySurfaces(); 462 // Remove any starting window that was added for this app if they are still around. 463 mTask.mService.scheduleRemoveStartingWindowLocked(this); 464 } 465 466 /** 467 * Checks whether we should save surfaces for this app. 468 * 469 * @return true if the surfaces should be saved, false otherwise. 470 */ shouldSaveSurface()471 boolean shouldSaveSurface() { 472 // We want to save surface if the app's windows are "allDrawn". 473 // (If we started entering animation early with saved surfaces, allDrawn 474 // should have been restored to true. So we'll save again in that case 475 // even if app didn't actually finish drawing.) 476 return allDrawn; 477 } 478 canRestoreSurfaces()479 boolean canRestoreSurfaces() { 480 for (int i = allAppWindows.size() -1; i >= 0; i--) { 481 final WindowState w = allAppWindows.get(i); 482 if (w.canRestoreSurface()) { 483 return true; 484 } 485 } 486 return false; 487 } 488 clearVisibleBeforeClientHidden()489 void clearVisibleBeforeClientHidden() { 490 for (int i = allAppWindows.size() - 1; i >= 0; i--) { 491 final WindowState w = allAppWindows.get(i); 492 w.clearVisibleBeforeClientHidden(); 493 } 494 } 495 496 /** 497 * Whether the app has some window that is invisible in layout, but 498 * animating with saved surface. 499 */ isAnimatingInvisibleWithSavedSurface()500 boolean isAnimatingInvisibleWithSavedSurface() { 501 for (int i = allAppWindows.size() - 1; i >= 0; i--) { 502 final WindowState w = allAppWindows.get(i); 503 if (w.isAnimatingInvisibleWithSavedSurface()) { 504 return true; 505 } 506 } 507 return false; 508 } 509 510 /** 511 * Hide all window surfaces that's still invisible in layout but animating 512 * with a saved surface, and mark them destroying. 513 */ stopUsingSavedSurfaceLocked()514 void stopUsingSavedSurfaceLocked() { 515 for (int i = allAppWindows.size() - 1; i >= 0; i--) { 516 final WindowState w = allAppWindows.get(i); 517 if (w.isAnimatingInvisibleWithSavedSurface()) { 518 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG, 519 "stopUsingSavedSurfaceLocked: " + w); 520 w.clearAnimatingWithSavedSurface(); 521 w.mDestroying = true; 522 w.mWinAnimator.hide("stopUsingSavedSurfaceLocked"); 523 w.mWinAnimator.mWallpaperControllerLocked.hideWallpapers(w); 524 } 525 } 526 destroySurfaces(); 527 } 528 markSavedSurfaceExiting()529 void markSavedSurfaceExiting() { 530 for (int i = allAppWindows.size() - 1; i >= 0; i--) { 531 final WindowState w = allAppWindows.get(i); 532 if (w.isAnimatingInvisibleWithSavedSurface()) { 533 w.mAnimatingExit = true; 534 w.mWinAnimator.mAnimating = true; 535 } 536 } 537 } 538 restoreSavedSurfaces()539 void restoreSavedSurfaces() { 540 if (!canRestoreSurfaces()) { 541 clearVisibleBeforeClientHidden(); 542 return; 543 } 544 // Check if we have enough drawn windows to mark allDrawn= true. 545 int numInteresting = 0; 546 int numDrawn = 0; 547 for (int i = allAppWindows.size() - 1; i >= 0; i--) { 548 WindowState w = allAppWindows.get(i); 549 if (w != startingWindow && !w.mAppDied && w.wasVisibleBeforeClientHidden() 550 && (!mAppAnimator.freezingScreen || !w.mAppFreezing)) { 551 numInteresting++; 552 if (w.hasSavedSurface()) { 553 w.restoreSavedSurface(); 554 } 555 if (w.isDrawnLw()) { 556 numDrawn++; 557 } 558 } 559 } 560 561 if (!allDrawn) { 562 allDrawn = (numInteresting > 0) && (numInteresting == numDrawn); 563 if (allDrawn) { 564 service.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN, token).sendToTarget(); 565 } 566 } 567 clearVisibleBeforeClientHidden(); 568 569 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG, 570 "restoreSavedSurfaces: " + appWindowToken + " allDrawn=" + allDrawn 571 + " numInteresting=" + numInteresting + " numDrawn=" + numDrawn); 572 } 573 destroySavedSurfaces()574 void destroySavedSurfaces() { 575 for (int i = allAppWindows.size() - 1; i >= 0; i--) { 576 WindowState win = allAppWindows.get(i); 577 win.destroySavedSurface(); 578 } 579 } 580 clearAllDrawn()581 void clearAllDrawn() { 582 allDrawn = false; 583 deferClearAllDrawn = false; 584 allDrawnExcludingSaved = false; 585 } 586 587 @Override removeAllWindows()588 void removeAllWindows() { 589 for (int winNdx = allAppWindows.size() - 1; winNdx >= 0; 590 // removeWindowLocked at bottom of loop may remove multiple entries from 591 // allAppWindows if the window to be removed has child windows. It also may 592 // not remove any windows from allAppWindows at all if win is exiting and 593 // currently animating away. This ensures that winNdx is monotonically decreasing 594 // and never beyond allAppWindows bounds. 595 winNdx = Math.min(winNdx - 1, allAppWindows.size() - 1)) { 596 WindowState win = allAppWindows.get(winNdx); 597 if (DEBUG_WINDOW_MOVEMENT) { 598 Slog.w(TAG, "removeAllWindows: removing win=" + win); 599 } 600 601 service.removeWindowLocked(win); 602 } 603 allAppWindows.clear(); 604 windows.clear(); 605 } 606 removeAllDeadWindows()607 void removeAllDeadWindows() { 608 for (int winNdx = allAppWindows.size() - 1; winNdx >= 0; 609 // removeWindowLocked at bottom of loop may remove multiple entries from 610 // allAppWindows if the window to be removed has child windows. It also may 611 // not remove any windows from allAppWindows at all if win is exiting and 612 // currently animating away. This ensures that winNdx is monotonically decreasing 613 // and never beyond allAppWindows bounds. 614 winNdx = Math.min(winNdx - 1, allAppWindows.size() - 1)) { 615 WindowState win = allAppWindows.get(winNdx); 616 if (win.mAppDied) { 617 if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) { 618 Slog.w(TAG, "removeAllDeadWindows: " + win); 619 } 620 // Set mDestroying, we don't want any animation or delayed removal here. 621 win.mDestroying = true; 622 service.removeWindowLocked(win); 623 } 624 } 625 } 626 hasWindowsAlive()627 boolean hasWindowsAlive() { 628 for (int i = allAppWindows.size() - 1; i >= 0; i--) { 629 if (!allAppWindows.get(i).mAppDied) { 630 return true; 631 } 632 } 633 return false; 634 } 635 setReplacingWindows(boolean animate)636 void setReplacingWindows(boolean animate) { 637 if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + appWindowToken 638 + " with replacing windows."); 639 640 for (int i = allAppWindows.size() - 1; i >= 0; i--) { 641 final WindowState w = allAppWindows.get(i); 642 w.setReplacing(animate); 643 } 644 if (animate) { 645 // Set-up dummy animation so we can start treating windows associated with this 646 // token like they are in transition before the new app window is ready for us to 647 // run the real transition animation. 648 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, 649 "setReplacingWindow() Setting dummy animation on: " + this); 650 mAppAnimator.setDummyAnimation(); 651 } 652 } 653 setReplacingChildren()654 void setReplacingChildren() { 655 if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Marking app token " + appWindowToken 656 + " with replacing child windows."); 657 for (int i = allAppWindows.size() - 1; i >= 0; i--) { 658 final WindowState w = allAppWindows.get(i); 659 if (w.shouldBeReplacedWithChildren()) { 660 w.setReplacing(false /* animate */); 661 } 662 } 663 } 664 resetReplacingWindows()665 void resetReplacingWindows() { 666 if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Resetting app token " + appWindowToken 667 + " of replacing window marks."); 668 669 for (int i = allAppWindows.size() - 1; i >= 0; i--) { 670 final WindowState w = allAppWindows.get(i); 671 w.resetReplacing(); 672 } 673 } 674 requestUpdateWallpaperIfNeeded()675 void requestUpdateWallpaperIfNeeded() { 676 for (int i = allAppWindows.size() - 1; i >= 0; i--) { 677 final WindowState w = allAppWindows.get(i); 678 w.requestUpdateWallpaperIfNeeded(); 679 } 680 } 681 isRelaunching()682 boolean isRelaunching() { 683 return mPendingRelaunchCount > 0; 684 } 685 startRelaunching()686 void startRelaunching() { 687 if (canFreezeBounds()) { 688 freezeBounds(); 689 } 690 mPendingRelaunchCount++; 691 } 692 finishRelaunching()693 void finishRelaunching() { 694 if (canFreezeBounds()) { 695 unfreezeBounds(); 696 } 697 if (mPendingRelaunchCount > 0) { 698 mPendingRelaunchCount--; 699 } 700 } 701 clearRelaunching()702 void clearRelaunching() { 703 if (mPendingRelaunchCount == 0) { 704 return; 705 } 706 if (canFreezeBounds()) { 707 unfreezeBounds(); 708 } 709 mPendingRelaunchCount = 0; 710 } 711 addWindow(WindowState w)712 void addWindow(WindowState w) { 713 for (int i = allAppWindows.size() - 1; i >= 0; i--) { 714 WindowState candidate = allAppWindows.get(i); 715 if (candidate.mWillReplaceWindow && candidate.mReplacingWindow == null && 716 candidate.getWindowTag().toString().equals(w.getWindowTag().toString())) { 717 candidate.mReplacingWindow = w; 718 w.mSkipEnterAnimationForSeamlessReplacement = !candidate.mAnimateReplacingWindow; 719 720 // if we got a replacement window, reset the timeout to give drawing more time 721 service.scheduleReplacingWindowTimeouts(this); 722 } 723 } 724 allAppWindows.add(w); 725 } 726 waitingForReplacement()727 boolean waitingForReplacement() { 728 for (int i = allAppWindows.size() -1; i >= 0; i--) { 729 WindowState candidate = allAppWindows.get(i); 730 if (candidate.mWillReplaceWindow) { 731 return true; 732 } 733 } 734 return false; 735 } 736 clearTimedoutReplacesLocked()737 void clearTimedoutReplacesLocked() { 738 for (int i = allAppWindows.size() - 1; i >= 0; 739 // removeWindowLocked at bottom of loop may remove multiple entries from 740 // allAppWindows if the window to be removed has child windows. It also may 741 // not remove any windows from allAppWindows at all if win is exiting and 742 // currently animating away. This ensures that winNdx is monotonically decreasing 743 // and never beyond allAppWindows bounds. 744 i = Math.min(i - 1, allAppWindows.size() - 1)) { 745 WindowState candidate = allAppWindows.get(i); 746 if (candidate.mWillReplaceWindow == false) { 747 continue; 748 } 749 candidate.mWillReplaceWindow = false; 750 if (candidate.mReplacingWindow != null) { 751 candidate.mReplacingWindow.mSkipEnterAnimationForSeamlessReplacement = false; 752 } 753 // Since the window already timed out, remove it immediately now. 754 // Use removeWindowInnerLocked() instead of removeWindowLocked(), as the latter 755 // delays removal on certain conditions, which will leave the stale window in the 756 // stack and marked mWillReplaceWindow=false, so the window will never be removed. 757 service.removeWindowInnerLocked(candidate); 758 } 759 } 760 canFreezeBounds()761 private boolean canFreezeBounds() { 762 // For freeform windows, we can't freeze the bounds at the moment because this would make 763 // the resizing unresponsive. 764 return mTask != null && !mTask.inFreeformWorkspace(); 765 } 766 767 /** 768 * Freezes the task bounds. The size of this task reported the app will be fixed to the bounds 769 * freezed by {@link Task#prepareFreezingBounds} until {@link #unfreezeBounds} gets called, even 770 * if they change in the meantime. If the bounds are already frozen, the bounds will be frozen 771 * with a queue. 772 */ freezeBounds()773 private void freezeBounds() { 774 mFrozenBounds.offer(new Rect(mTask.mPreparedFrozenBounds)); 775 776 if (mTask.mPreparedFrozenMergedConfig.equals(Configuration.EMPTY)) { 777 // We didn't call prepareFreezingBounds on the task, so use the current value. 778 final Configuration config = new Configuration(service.mCurConfiguration); 779 config.updateFrom(mTask.mOverrideConfig); 780 mFrozenMergedConfig.offer(config); 781 } else { 782 mFrozenMergedConfig.offer(new Configuration(mTask.mPreparedFrozenMergedConfig)); 783 } 784 mTask.mPreparedFrozenMergedConfig.setToDefaults(); 785 } 786 787 /** 788 * Unfreezes the previously frozen bounds. See {@link #freezeBounds}. 789 */ unfreezeBounds()790 private void unfreezeBounds() { 791 if (!mFrozenBounds.isEmpty()) { 792 mFrozenBounds.remove(); 793 } 794 if (!mFrozenMergedConfig.isEmpty()) { 795 mFrozenMergedConfig.remove(); 796 } 797 for (int i = windows.size() - 1; i >= 0; i--) { 798 final WindowState win = windows.get(i); 799 if (!win.mHasSurface) { 800 continue; 801 } 802 win.mLayoutNeeded = true; 803 win.setDisplayLayoutNeeded(); 804 if (!service.mResizingWindows.contains(win)) { 805 service.mResizingWindows.add(win); 806 } 807 } 808 service.mWindowPlacerLocked.performSurfacePlacement(); 809 } 810 addSurfaceViewBackground(WindowSurfaceController.SurfaceControlWithBackground background)811 void addSurfaceViewBackground(WindowSurfaceController.SurfaceControlWithBackground background) { 812 mSurfaceViewBackgrounds.add(background); 813 } 814 removeSurfaceViewBackground(WindowSurfaceController.SurfaceControlWithBackground background)815 void removeSurfaceViewBackground(WindowSurfaceController.SurfaceControlWithBackground background) { 816 mSurfaceViewBackgrounds.remove(background); 817 updateSurfaceViewBackgroundVisibilities(); 818 } 819 820 // We use DimLayers behind SurfaceViews to prevent holes while resizing and creating. 821 // However, we need to ensure one SurfaceView doesn't cover another when they are both placed 822 // below the main app window (as traditionally a SurfaceView which is never drawn 823 // to is totally translucent). So we look at all our SurfaceView backgrounds and only enable 824 // the background for the SurfaceView with lowest Z order updateSurfaceViewBackgroundVisibilities()825 void updateSurfaceViewBackgroundVisibilities() { 826 WindowSurfaceController.SurfaceControlWithBackground bottom = null; 827 int bottomLayer = Integer.MAX_VALUE; 828 for (int i = 0; i < mSurfaceViewBackgrounds.size(); i++) { 829 WindowSurfaceController.SurfaceControlWithBackground sc = mSurfaceViewBackgrounds.get(i); 830 if (sc.mVisible && sc.mLayer < bottomLayer) { 831 bottomLayer = sc.mLayer; 832 bottom = sc; 833 } 834 } 835 for (int i = 0; i < mSurfaceViewBackgrounds.size(); i++) { 836 WindowSurfaceController.SurfaceControlWithBackground sc = mSurfaceViewBackgrounds.get(i); 837 sc.updateBackgroundVisibility(sc != bottom); 838 } 839 } 840 841 @Override dump(PrintWriter pw, String prefix)842 void dump(PrintWriter pw, String prefix) { 843 super.dump(pw, prefix); 844 if (appToken != null) { 845 pw.print(prefix); pw.print("app=true voiceInteraction="); pw.println(voiceInteraction); 846 } 847 if (allAppWindows.size() > 0) { 848 pw.print(prefix); pw.print("allAppWindows="); pw.println(allAppWindows); 849 } 850 pw.print(prefix); pw.print("task="); pw.println(mTask); 851 pw.print(prefix); pw.print(" appFullscreen="); pw.print(appFullscreen); 852 pw.print(" requestedOrientation="); pw.println(requestedOrientation); 853 pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested); 854 pw.print(" clientHidden="); pw.print(clientHidden); 855 pw.print(" reportedDrawn="); pw.print(reportedDrawn); 856 pw.print(" reportedVisible="); pw.println(reportedVisible); 857 if (paused) { 858 pw.print(prefix); pw.print("paused="); pw.println(paused); 859 } 860 if (mAppStopped) { 861 pw.print(prefix); pw.print("mAppStopped="); pw.println(mAppStopped); 862 } 863 if (numInterestingWindows != 0 || numDrawnWindows != 0 864 || allDrawn || mAppAnimator.allDrawn) { 865 pw.print(prefix); pw.print("numInterestingWindows="); 866 pw.print(numInterestingWindows); 867 pw.print(" numDrawnWindows="); pw.print(numDrawnWindows); 868 pw.print(" inPendingTransaction="); pw.print(inPendingTransaction); 869 pw.print(" allDrawn="); pw.print(allDrawn); 870 pw.print(" (animator="); pw.print(mAppAnimator.allDrawn); 871 pw.println(")"); 872 } 873 if (inPendingTransaction) { 874 pw.print(prefix); pw.print("inPendingTransaction="); 875 pw.println(inPendingTransaction); 876 } 877 if (startingData != null || removed || firstWindowDrawn || mIsExiting) { 878 pw.print(prefix); pw.print("startingData="); pw.print(startingData); 879 pw.print(" removed="); pw.print(removed); 880 pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn); 881 pw.print(" mIsExiting="); pw.println(mIsExiting); 882 } 883 if (startingWindow != null || startingView != null 884 || startingDisplayed || startingMoved) { 885 pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow); 886 pw.print(" startingView="); pw.print(startingView); 887 pw.print(" startingDisplayed="); pw.print(startingDisplayed); 888 pw.print(" startingMoved="); pw.println(startingMoved); 889 } 890 if (!mFrozenBounds.isEmpty()) { 891 pw.print(prefix); pw.print("mFrozenBounds="); pw.println(mFrozenBounds); 892 pw.print(prefix); pw.print("mFrozenMergedConfig="); pw.println(mFrozenMergedConfig); 893 } 894 if (mPendingRelaunchCount != 0) { 895 pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount); 896 } 897 } 898 899 @Override toString()900 public String toString() { 901 if (stringName == null) { 902 StringBuilder sb = new StringBuilder(); 903 sb.append("AppWindowToken{"); 904 sb.append(Integer.toHexString(System.identityHashCode(this))); 905 sb.append(" token="); sb.append(token); sb.append('}'); 906 stringName = sb.toString(); 907 } 908 return stringName; 909 } 910 } 911