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