1 2 package com.android.server.wm; 3 4 import static android.app.ActivityManager.StackId.INVALID_STACK_ID; 5 import static android.app.ActivityManagerInternal.APP_TRANSITION_SAVED_SURFACE; 6 import static android.app.ActivityManagerInternal.APP_TRANSITION_SNAPSHOT; 7 import static android.app.ActivityManagerInternal.APP_TRANSITION_SPLASH_SCREEN; 8 import static android.app.ActivityManagerInternal.APP_TRANSITION_WINDOWS_DRAWN; 9 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG; 10 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; 11 import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_CLOSE; 12 import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN; 13 import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION; 14 import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE; 15 import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER; 16 import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_GOING_AWAY; 17 import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER; 18 import static com.android.server.wm.AppTransition.TRANSIT_NONE; 19 import static com.android.server.wm.AppTransition.TRANSIT_TASK_CLOSE; 20 import static com.android.server.wm.AppTransition.TRANSIT_TASK_IN_PLACE; 21 import static com.android.server.wm.AppTransition.TRANSIT_TASK_OPEN; 22 import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_BACK; 23 import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_FRONT; 24 import static com.android.server.wm.AppTransition.TRANSIT_WALLPAPER_CLOSE; 25 import static com.android.server.wm.AppTransition.TRANSIT_WALLPAPER_INTRA_CLOSE; 26 import static com.android.server.wm.AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN; 27 import static com.android.server.wm.AppTransition.TRANSIT_WALLPAPER_OPEN; 28 import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit; 29 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG; 30 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; 31 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; 32 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; 33 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 34 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 35 import static com.android.server.wm.WindowManagerService.H.NOTIFY_APP_TRANSITION_STARTING; 36 import static com.android.server.wm.WindowManagerService.H.REPORT_WINDOWS_CHANGE; 37 import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD; 38 import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION; 39 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES; 40 41 import android.content.res.Configuration; 42 import android.graphics.GraphicBuffer; 43 import android.graphics.PixelFormat; 44 import android.graphics.Rect; 45 import android.os.Binder; 46 import android.os.Debug; 47 import android.os.Trace; 48 import android.util.ArraySet; 49 import android.util.Slog; 50 import android.util.SparseIntArray; 51 import android.view.Display; 52 import android.view.DisplayInfo; 53 import android.view.Surface; 54 import android.view.SurfaceControl; 55 import android.view.WindowManager.LayoutParams; 56 import android.view.animation.Animation; 57 58 import com.android.server.wm.WindowManagerService.H; 59 60 import java.io.PrintWriter; 61 import java.util.ArrayList; 62 63 /** 64 * Positions windows and their surfaces. 65 * 66 * It sets positions of windows by calculating their frames and then applies this by positioning 67 * surfaces according to these frames. Z layer is still assigned withing WindowManagerService. 68 */ 69 class WindowSurfacePlacer { 70 private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowSurfacePlacer" : TAG_WM; 71 private final WindowManagerService mService; 72 private final WallpaperController mWallpaperControllerLocked; 73 74 private boolean mInLayout = false; 75 76 /** Only do a maximum of 6 repeated layouts. After that quit */ 77 private int mLayoutRepeatCount; 78 79 static final int SET_UPDATE_ROTATION = 1 << 0; 80 static final int SET_WALLPAPER_MAY_CHANGE = 1 << 1; 81 static final int SET_FORCE_HIDING_CHANGED = 1 << 2; 82 static final int SET_ORIENTATION_CHANGE_COMPLETE = 1 << 3; 83 static final int SET_TURN_ON_SCREEN = 1 << 4; 84 static final int SET_WALLPAPER_ACTION_PENDING = 1 << 5; 85 86 private final Rect mTmpStartRect = new Rect(); 87 private final Rect mTmpContentRect = new Rect(); 88 89 private boolean mTraversalScheduled; 90 private int mDeferDepth = 0; 91 92 private static final class LayerAndToken { 93 public int layer; 94 public AppWindowToken token; 95 } 96 private final LayerAndToken mTmpLayerAndToken = new LayerAndToken(); 97 98 private final ArrayList<SurfaceControl> mPendingDestroyingSurfaces = new ArrayList<>(); 99 private final SparseIntArray mTempTransitionReasons = new SparseIntArray(); 100 101 private final Runnable mPerformSurfacePlacement; 102 WindowSurfacePlacer(WindowManagerService service)103 public WindowSurfacePlacer(WindowManagerService service) { 104 mService = service; 105 mWallpaperControllerLocked = mService.mRoot.mWallpaperController; 106 mPerformSurfacePlacement = () -> { 107 synchronized (mService.mWindowMap) { 108 performSurfacePlacement(); 109 } 110 }; 111 } 112 113 /** 114 * See {@link WindowManagerService#deferSurfaceLayout()} 115 */ deferLayout()116 void deferLayout() { 117 mDeferDepth++; 118 } 119 120 /** 121 * See {@link WindowManagerService#continueSurfaceLayout()} 122 */ continueLayout()123 void continueLayout() { 124 mDeferDepth--; 125 if (mDeferDepth <= 0) { 126 performSurfacePlacement(); 127 } 128 } 129 performSurfacePlacement()130 final void performSurfacePlacement() { 131 performSurfacePlacement(false /* force */); 132 } 133 performSurfacePlacement(boolean force)134 final void performSurfacePlacement(boolean force) { 135 if (mDeferDepth > 0 && !force) { 136 return; 137 } 138 int loopCount = 6; 139 do { 140 mTraversalScheduled = false; 141 performSurfacePlacementLoop(); 142 mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement); 143 loopCount--; 144 } while (mTraversalScheduled && loopCount > 0); 145 mService.mRoot.mWallpaperActionPending = false; 146 } 147 performSurfacePlacementLoop()148 private void performSurfacePlacementLoop() { 149 if (mInLayout) { 150 if (DEBUG) { 151 throw new RuntimeException("Recursive call!"); 152 } 153 Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout. Callers=" 154 + Debug.getCallers(3)); 155 return; 156 } 157 158 if (mService.mWaitingForConfig) { 159 // Our configuration has changed (most likely rotation), but we 160 // don't yet have the complete configuration to report to 161 // applications. Don't do any window layout until we have it. 162 return; 163 } 164 165 if (!mService.mDisplayReady) { 166 // Not yet initialized, nothing to do. 167 return; 168 } 169 170 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout"); 171 mInLayout = true; 172 173 boolean recoveringMemory = false; 174 if (!mService.mForceRemoves.isEmpty()) { 175 recoveringMemory = true; 176 // Wait a little bit for things to settle down, and off we go. 177 while (!mService.mForceRemoves.isEmpty()) { 178 final WindowState ws = mService.mForceRemoves.remove(0); 179 Slog.i(TAG, "Force removing: " + ws); 180 ws.removeImmediately(); 181 } 182 Slog.w(TAG, "Due to memory failure, waiting a bit for next layout"); 183 Object tmp = new Object(); 184 synchronized (tmp) { 185 try { 186 tmp.wait(250); 187 } catch (InterruptedException e) { 188 } 189 } 190 } 191 192 try { 193 mService.mRoot.performSurfacePlacement(recoveringMemory); 194 195 mInLayout = false; 196 197 if (mService.mRoot.isLayoutNeeded()) { 198 if (++mLayoutRepeatCount < 6) { 199 requestTraversal(); 200 } else { 201 Slog.e(TAG, "Performed 6 layouts in a row. Skipping"); 202 mLayoutRepeatCount = 0; 203 } 204 } else { 205 mLayoutRepeatCount = 0; 206 } 207 208 if (mService.mWindowsChanged && !mService.mWindowChangeListeners.isEmpty()) { 209 mService.mH.removeMessages(REPORT_WINDOWS_CHANGE); 210 mService.mH.sendEmptyMessage(REPORT_WINDOWS_CHANGE); 211 } 212 } catch (RuntimeException e) { 213 mInLayout = false; 214 Slog.wtf(TAG, "Unhandled exception while laying out windows", e); 215 } 216 217 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); 218 } 219 debugLayoutRepeats(final String msg, int pendingLayoutChanges)220 void debugLayoutRepeats(final String msg, int pendingLayoutChanges) { 221 if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) { 222 Slog.v(TAG, "Layouts looping: " + msg + 223 ", mPendingLayoutChanges = 0x" + Integer.toHexString(pendingLayoutChanges)); 224 } 225 } 226 isInLayout()227 boolean isInLayout() { 228 return mInLayout; 229 } 230 231 /** 232 * @return bitmap indicating if another pass through layout must be made. 233 */ handleAppTransitionReadyLocked()234 int handleAppTransitionReadyLocked() { 235 int appsCount = mService.mOpeningApps.size(); 236 if (!transitionGoodToGo(appsCount)) { 237 return 0; 238 } 239 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady"); 240 241 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO"); 242 int transit = mService.mAppTransition.getAppTransition(); 243 if (mService.mSkipAppTransitionAnimation && !isKeyguardGoingAwayTransit(transit)) { 244 transit = AppTransition.TRANSIT_UNSET; 245 } 246 mService.mSkipAppTransitionAnimation = false; 247 mService.mNoAnimationNotifyOnTransitionFinished.clear(); 248 249 mService.mH.removeMessages(H.APP_TRANSITION_TIMEOUT); 250 251 final DisplayContent displayContent = mService.getDefaultDisplayContentLocked(); 252 // TODO: Don't believe this is really needed... 253 //mService.mWindowsChanged = true; 254 255 mService.mRoot.mWallpaperMayChange = false; 256 257 // The top-most window will supply the layout params, and we will determine it below. 258 LayoutParams animLp = null; 259 int bestAnimLayer = -1; 260 boolean fullscreenAnim = false; 261 boolean voiceInteraction = false; 262 263 int i; 264 for (i = 0; i < appsCount; i++) { 265 final AppWindowToken wtoken = mService.mOpeningApps.valueAt(i); 266 // Clearing the mAnimatingExit flag before entering animation. It's set to true if app 267 // window is removed, or window relayout to invisible. This also affects window 268 // visibility. We need to clear it *before* maybeUpdateTransitToWallpaper() as the 269 // transition selection depends on wallpaper target visibility. 270 wtoken.clearAnimatingFlags(); 271 272 } 273 274 // Adjust wallpaper before we pull the lower/upper target, since pending changes 275 // (like the clearAnimatingFlags() above) might affect wallpaper target result. 276 // Or, the opening app window should be a wallpaper target. 277 mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(displayContent, 278 mService.mOpeningApps); 279 280 final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget(); 281 boolean openingAppHasWallpaper = false; 282 boolean closingAppHasWallpaper = false; 283 284 // Do a first pass through the tokens for two things: 285 // (1) Determine if both the closing and opening app token sets are wallpaper targets, in 286 // which case special animations are needed (since the wallpaper needs to stay static behind 287 // them). 288 // (2) Find the layout params of the top-most application window in the tokens, which is 289 // what will control the animation theme. 290 final int closingAppsCount = mService.mClosingApps.size(); 291 appsCount = closingAppsCount + mService.mOpeningApps.size(); 292 for (i = 0; i < appsCount; i++) { 293 final AppWindowToken wtoken; 294 if (i < closingAppsCount) { 295 wtoken = mService.mClosingApps.valueAt(i); 296 if (wallpaperTarget != null && wtoken.windowsCanBeWallpaperTarget()) { 297 closingAppHasWallpaper = true; 298 } 299 } else { 300 wtoken = mService.mOpeningApps.valueAt(i - closingAppsCount); 301 if (wallpaperTarget != null && wtoken.windowsCanBeWallpaperTarget()) { 302 openingAppHasWallpaper = true; 303 } 304 } 305 306 voiceInteraction |= wtoken.mVoiceInteraction; 307 308 if (wtoken.fillsParent()) { 309 final WindowState ws = wtoken.findMainWindow(); 310 if (ws != null) { 311 animLp = ws.mAttrs; 312 bestAnimLayer = ws.mLayer; 313 fullscreenAnim = true; 314 } 315 } else if (!fullscreenAnim) { 316 final WindowState ws = wtoken.findMainWindow(); 317 if (ws != null) { 318 if (ws.mLayer > bestAnimLayer) { 319 animLp = ws.mAttrs; 320 bestAnimLayer = ws.mLayer; 321 } 322 } 323 } 324 } 325 326 transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper, 327 closingAppHasWallpaper); 328 329 // If all closing windows are obscured, then there is no need to do an animation. This is 330 // the case, for example, when this transition is being done behind the lock screen. 331 if (!mService.mPolicy.allowAppAnimationsLw()) { 332 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 333 "Animations disallowed by keyguard or dream."); 334 animLp = null; 335 } 336 337 processApplicationsAnimatingInPlace(transit); 338 339 mTmpLayerAndToken.token = null; 340 handleClosingApps(transit, animLp, voiceInteraction, mTmpLayerAndToken); 341 final AppWindowToken topClosingApp = mTmpLayerAndToken.token; 342 final int topClosingLayer = mTmpLayerAndToken.layer; 343 344 final AppWindowToken topOpeningApp = handleOpeningApps(transit, 345 animLp, voiceInteraction, topClosingLayer); 346 347 mService.mAppTransition.setLastAppTransition(transit, topOpeningApp, topClosingApp); 348 349 final AppWindowAnimator openingAppAnimator = (topOpeningApp == null) ? null : 350 topOpeningApp.mAppAnimator; 351 final AppWindowAnimator closingAppAnimator = (topClosingApp == null) ? null : 352 topClosingApp.mAppAnimator; 353 354 final int flags = mService.mAppTransition.getTransitFlags(); 355 int layoutRedo = mService.mAppTransition.goodToGo(transit, openingAppAnimator, 356 closingAppAnimator, mService.mOpeningApps, mService.mClosingApps); 357 handleNonAppWindowsInTransition(transit, flags); 358 mService.mAppTransition.postAnimationCallback(); 359 mService.mAppTransition.clear(); 360 361 mService.mTaskSnapshotController.onTransitionStarting(); 362 363 mService.mOpeningApps.clear(); 364 mService.mClosingApps.clear(); 365 mService.mUnknownAppVisibilityController.clear(); 366 367 // This has changed the visibility of windows, so perform 368 // a new layout to get them all up-to-date. 369 displayContent.setLayoutNeeded(); 370 371 // TODO(multidisplay): IMEs are only supported on the default display. 372 final DisplayContent dc = mService.getDefaultDisplayContentLocked(); 373 dc.computeImeTarget(true /* updateImeTarget */); 374 mService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, 375 true /*updateInputWindows*/); 376 mService.mFocusMayChange = false; 377 378 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); 379 380 return layoutRedo | FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG; 381 } 382 handleOpeningApps(int transit, LayoutParams animLp, boolean voiceInteraction, int topClosingLayer)383 private AppWindowToken handleOpeningApps(int transit, LayoutParams animLp, 384 boolean voiceInteraction, int topClosingLayer) { 385 AppWindowToken topOpeningApp = null; 386 final int appsCount = mService.mOpeningApps.size(); 387 for (int i = 0; i < appsCount; i++) { 388 AppWindowToken wtoken = mService.mOpeningApps.valueAt(i); 389 final AppWindowAnimator appAnimator = wtoken.mAppAnimator; 390 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken); 391 392 if (!appAnimator.usingTransferredAnimation) { 393 appAnimator.clearThumbnail(); 394 appAnimator.setNullAnimation(); 395 } 396 397 if (!wtoken.setVisibility(animLp, true, transit, false, voiceInteraction)){ 398 // This token isn't going to be animating. Add it to the list of tokens to 399 // be notified of app transition complete since the notification will not be 400 // sent be the app window animator. 401 mService.mNoAnimationNotifyOnTransitionFinished.add(wtoken.token); 402 } 403 wtoken.updateReportedVisibilityLocked(); 404 wtoken.waitingToShow = false; 405 wtoken.setAllAppWinAnimators(); 406 407 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, 408 ">>> OPEN TRANSACTION handleAppTransitionReadyLocked()"); 409 mService.openSurfaceTransaction(); 410 try { 411 mService.mAnimator.orAnimating(appAnimator.showAllWindowsLocked()); 412 } finally { 413 mService.closeSurfaceTransaction(); 414 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, 415 "<<< CLOSE TRANSACTION handleAppTransitionReadyLocked()"); 416 } 417 mService.mAnimator.mAppWindowAnimating |= appAnimator.isAnimating(); 418 419 int topOpeningLayer = 0; 420 if (animLp != null) { 421 final int layer = wtoken.getHighestAnimLayer(); 422 if (topOpeningApp == null || layer > topOpeningLayer) { 423 topOpeningApp = wtoken; 424 topOpeningLayer = layer; 425 } 426 } 427 if (mService.mAppTransition.isNextAppTransitionThumbnailUp()) { 428 createThumbnailAppAnimator(transit, wtoken, topOpeningLayer, topClosingLayer); 429 } 430 } 431 return topOpeningApp; 432 } 433 handleClosingApps(int transit, LayoutParams animLp, boolean voiceInteraction, LayerAndToken layerAndToken)434 private void handleClosingApps(int transit, LayoutParams animLp, boolean voiceInteraction, 435 LayerAndToken layerAndToken) { 436 final int appsCount; 437 appsCount = mService.mClosingApps.size(); 438 for (int i = 0; i < appsCount; i++) { 439 AppWindowToken wtoken = mService.mClosingApps.valueAt(i); 440 441 // If we still have some windows animating with saved surfaces that's 442 // either invisible or already removed, mark them exiting so that they 443 // are disposed of after the exit animation. These are not supposed to 444 // be shown, or are delayed removal until app is actually drawn (in which 445 // case the window will be removed after the animation). 446 wtoken.markSavedSurfaceExiting(); 447 448 final AppWindowAnimator appAnimator = wtoken.mAppAnimator; 449 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken); 450 appAnimator.clearThumbnail(); 451 appAnimator.setNullAnimation(); 452 // TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not 453 // animating? 454 wtoken.setVisibility(animLp, false, transit, false, voiceInteraction); 455 wtoken.updateReportedVisibilityLocked(); 456 // Force the allDrawn flag, because we want to start 457 // this guy's animations regardless of whether it's 458 // gotten drawn. 459 wtoken.allDrawn = true; 460 wtoken.deferClearAllDrawn = false; 461 // Ensure that apps that are mid-starting are also scheduled to have their 462 // starting windows removed after the animation is complete 463 if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit 464 && wtoken.getController() != null) { 465 wtoken.getController().removeStartingWindow(); 466 } 467 mService.mAnimator.mAppWindowAnimating |= appAnimator.isAnimating(); 468 469 if (animLp != null) { 470 int layer = wtoken.getHighestAnimLayer(); 471 if (layerAndToken.token == null || layer > layerAndToken.layer) { 472 layerAndToken.token = wtoken; 473 layerAndToken.layer = layer; 474 } 475 } 476 if (mService.mAppTransition.isNextAppTransitionThumbnailDown()) { 477 createThumbnailAppAnimator(transit, wtoken, 0, layerAndToken.layer); 478 } 479 } 480 } 481 handleNonAppWindowsInTransition(int transit, int flags)482 private void handleNonAppWindowsInTransition(int transit, int flags) { 483 if (transit == TRANSIT_KEYGUARD_GOING_AWAY) { 484 if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0 485 && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0) { 486 Animation anim = mService.mPolicy.createKeyguardWallpaperExit( 487 (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0); 488 if (anim != null) { 489 mService.getDefaultDisplayContentLocked().mWallpaperController 490 .startWallpaperAnimation(anim); 491 } 492 } 493 } 494 if (transit == TRANSIT_KEYGUARD_GOING_AWAY 495 || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) { 496 mService.getDefaultDisplayContentLocked().startKeyguardExitOnNonAppWindows( 497 transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER, 498 (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0); 499 } 500 } 501 transitionGoodToGo(int appsCount)502 private boolean transitionGoodToGo(int appsCount) { 503 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 504 "Checking " + appsCount + " opening apps (frozen=" 505 + mService.mDisplayFrozen + " timeout=" 506 + mService.mAppTransition.isTimeout() + ")..."); 507 final ScreenRotationAnimation screenRotationAnimation = 508 mService.mAnimator.getScreenRotationAnimationLocked( 509 Display.DEFAULT_DISPLAY); 510 511 final SparseIntArray reasons = mTempTransitionReasons; 512 if (!mService.mAppTransition.isTimeout()) { 513 // Imagine the case where we are changing orientation due to an app transition, but a previous 514 // orientation change is still in progress. We won't process the orientation change 515 // for our transition because we need to wait for the rotation animation to finish. 516 // If we start the app transition at this point, we will interrupt it halfway with a new rotation 517 // animation after the old one finally finishes. It's better to defer the 518 // app transition. 519 if (screenRotationAnimation != null && screenRotationAnimation.isAnimating() && 520 mService.rotationNeedsUpdateLocked()) { 521 if (DEBUG_APP_TRANSITIONS) { 522 Slog.v(TAG, "Delaying app transition for screen rotation animation to finish"); 523 } 524 return false; 525 } 526 for (int i = 0; i < appsCount; i++) { 527 AppWindowToken wtoken = mService.mOpeningApps.valueAt(i); 528 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 529 "Check opening app=" + wtoken + ": allDrawn=" 530 + wtoken.allDrawn + " startingDisplayed=" 531 + wtoken.startingDisplayed + " startingMoved=" 532 + wtoken.startingMoved + " isRelaunching()=" 533 + wtoken.isRelaunching()); 534 535 final boolean drawnBeforeRestoring = wtoken.allDrawn; 536 wtoken.restoreSavedSurfaceForInterestingWindows(); 537 538 final boolean allDrawn = wtoken.allDrawn && !wtoken.isRelaunching(); 539 if (!allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) { 540 return false; 541 } 542 final TaskStack stack = wtoken.getStack(); 543 final int stackId = stack != null ? stack.mStackId : INVALID_STACK_ID; 544 if (allDrawn) { 545 reasons.put(stackId, drawnBeforeRestoring ? APP_TRANSITION_WINDOWS_DRAWN 546 : APP_TRANSITION_SAVED_SURFACE); 547 } else { 548 reasons.put(stackId, wtoken.startingData instanceof SplashScreenStartingData 549 ? APP_TRANSITION_SPLASH_SCREEN 550 : APP_TRANSITION_SNAPSHOT); 551 } 552 } 553 554 // We also need to wait for the specs to be fetched, if needed. 555 if (mService.mAppTransition.isFetchingAppTransitionsSpecs()) { 556 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "isFetchingAppTransitionSpecs=true"); 557 return false; 558 } 559 560 if (!mService.mUnknownAppVisibilityController.allResolved()) { 561 if (DEBUG_APP_TRANSITIONS) { 562 Slog.v(TAG, "unknownApps is not empty: " 563 + mService.mUnknownAppVisibilityController.getDebugMessage()); 564 } 565 return false; 566 } 567 568 // If the wallpaper is visible, we need to check it's ready too. 569 boolean wallpaperReady = !mWallpaperControllerLocked.isWallpaperVisible() || 570 mWallpaperControllerLocked.wallpaperTransitionReady(); 571 if (wallpaperReady) { 572 mService.mH.obtainMessage(NOTIFY_APP_TRANSITION_STARTING, reasons.clone()) 573 .sendToTarget(); 574 return true; 575 } 576 return false; 577 } 578 mService.mH.obtainMessage(NOTIFY_APP_TRANSITION_STARTING, reasons.clone()).sendToTarget(); 579 return true; 580 } 581 maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper, boolean closingAppHasWallpaper)582 private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper, 583 boolean closingAppHasWallpaper) { 584 // Given no app transition pass it through instead of a wallpaper transition 585 if (transit == TRANSIT_NONE) { 586 return TRANSIT_NONE; 587 } 588 589 // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper 590 final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget(); 591 final WindowState oldWallpaper = mWallpaperControllerLocked.isWallpaperTargetAnimating() 592 ? null : wallpaperTarget; 593 final ArraySet<AppWindowToken> openingApps = mService.mOpeningApps; 594 final ArraySet<AppWindowToken> closingApps = mService.mClosingApps; 595 boolean openingCanBeWallpaperTarget = canBeWallpaperTarget(openingApps); 596 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 597 "New wallpaper target=" + wallpaperTarget 598 + ", oldWallpaper=" + oldWallpaper 599 + ", openingApps=" + openingApps 600 + ", closingApps=" + closingApps); 601 mService.mAnimateWallpaperWithTarget = false; 602 if (openingCanBeWallpaperTarget && transit == TRANSIT_KEYGUARD_GOING_AWAY) { 603 transit = TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER; 604 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 605 "New transit: " + AppTransition.appTransitionToString(transit)); 606 } 607 // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic 608 // relies on the fact that we always execute a Keyguard transition after preparing one. 609 else if (!isKeyguardGoingAwayTransit(transit)) { 610 if (closingAppHasWallpaper && openingAppHasWallpaper) { 611 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!"); 612 switch (transit) { 613 case TRANSIT_ACTIVITY_OPEN: 614 case TRANSIT_TASK_OPEN: 615 case TRANSIT_TASK_TO_FRONT: 616 transit = TRANSIT_WALLPAPER_INTRA_OPEN; 617 break; 618 case TRANSIT_ACTIVITY_CLOSE: 619 case TRANSIT_TASK_CLOSE: 620 case TRANSIT_TASK_TO_BACK: 621 transit = TRANSIT_WALLPAPER_INTRA_CLOSE; 622 break; 623 } 624 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 625 "New transit: " + AppTransition.appTransitionToString(transit)); 626 } else if (oldWallpaper != null && !mService.mOpeningApps.isEmpty() 627 && !openingApps.contains(oldWallpaper.mAppToken) 628 && closingApps.contains(oldWallpaper.mAppToken)) { 629 // We are transitioning from an activity with a wallpaper to one without. 630 transit = TRANSIT_WALLPAPER_CLOSE; 631 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit away from wallpaper: " 632 + AppTransition.appTransitionToString(transit)); 633 } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw() && 634 openingApps.contains(wallpaperTarget.mAppToken)) { 635 // We are transitioning from an activity without 636 // a wallpaper to now showing the wallpaper 637 transit = TRANSIT_WALLPAPER_OPEN; 638 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit into wallpaper: " 639 + AppTransition.appTransitionToString(transit)); 640 } else { 641 mService.mAnimateWallpaperWithTarget = true; 642 } 643 } 644 return transit; 645 } 646 canBeWallpaperTarget(ArraySet<AppWindowToken> apps)647 private boolean canBeWallpaperTarget(ArraySet<AppWindowToken> apps) { 648 for (int i = apps.size() - 1; i >= 0; i--) { 649 if (apps.valueAt(i).windowsCanBeWallpaperTarget()) { 650 return true; 651 } 652 } 653 return false; 654 } 655 processApplicationsAnimatingInPlace(int transit)656 private void processApplicationsAnimatingInPlace(int transit) { 657 if (transit == TRANSIT_TASK_IN_PLACE) { 658 // Find the focused window 659 final WindowState win = mService.getDefaultDisplayContentLocked().findFocusedWindow(); 660 if (win != null) { 661 final AppWindowToken wtoken = win.mAppToken; 662 final AppWindowAnimator appAnimator = wtoken.mAppAnimator; 663 if (DEBUG_APP_TRANSITIONS) 664 Slog.v(TAG, "Now animating app in place " + wtoken); 665 appAnimator.clearThumbnail(); 666 appAnimator.setNullAnimation(); 667 mService.updateTokenInPlaceLocked(wtoken, transit); 668 wtoken.updateReportedVisibilityLocked(); 669 wtoken.setAllAppWinAnimators(); 670 mService.mAnimator.mAppWindowAnimating |= appAnimator.isAnimating(); 671 mService.mAnimator.orAnimating(appAnimator.showAllWindowsLocked()); 672 } 673 } 674 } 675 createThumbnailAppAnimator(int transit, AppWindowToken appToken, int openingLayer, int closingLayer)676 private void createThumbnailAppAnimator(int transit, AppWindowToken appToken, 677 int openingLayer, int closingLayer) { 678 AppWindowAnimator openingAppAnimator = (appToken == null) ? null : appToken.mAppAnimator; 679 if (openingAppAnimator == null || openingAppAnimator.animation == null) { 680 return; 681 } 682 final int taskId = appToken.getTask().mTaskId; 683 final GraphicBuffer thumbnailHeader = 684 mService.mAppTransition.getAppTransitionThumbnailHeader(taskId); 685 if (thumbnailHeader == null) { 686 if (DEBUG_APP_TRANSITIONS) Slog.d(TAG, "No thumbnail header bitmap for: " + taskId); 687 return; 688 } 689 // This thumbnail animation is very special, we need to have 690 // an extra surface with the thumbnail included with the animation. 691 Rect dirty = new Rect(0, 0, thumbnailHeader.getWidth(), thumbnailHeader.getHeight()); 692 try { 693 // TODO(multi-display): support other displays 694 final DisplayContent displayContent = mService.getDefaultDisplayContentLocked(); 695 final Display display = displayContent.getDisplay(); 696 final DisplayInfo displayInfo = displayContent.getDisplayInfo(); 697 698 // Create a new surface for the thumbnail 699 WindowState window = appToken.findMainWindow(); 700 SurfaceControl surfaceControl = new SurfaceControl(mService.mFxSession, 701 "thumbnail anim", dirty.width(), dirty.height(), 702 PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN, 703 appToken.windowType, 704 window != null ? window.mOwnerUid : Binder.getCallingUid()); 705 surfaceControl.setLayerStack(display.getLayerStack()); 706 if (SHOW_TRANSACTIONS) { 707 Slog.i(TAG, " THUMBNAIL " + surfaceControl + ": CREATE"); 708 } 709 710 // Transfer the thumbnail to the surface 711 Surface drawSurface = new Surface(); 712 drawSurface.copyFrom(surfaceControl); 713 drawSurface.attachAndQueueBuffer(thumbnailHeader); 714 drawSurface.release(); 715 716 // Get the thumbnail animation 717 Animation anim; 718 if (mService.mAppTransition.isNextThumbnailTransitionAspectScaled()) { 719 // If this is a multi-window scenario, we use the windows frame as 720 // destination of the thumbnail header animation. If this is a full screen 721 // window scenario, we use the whole display as the target. 722 WindowState win = appToken.findMainWindow(); 723 Rect appRect = win != null ? win.getContentFrameLw() : 724 new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight); 725 Rect insets = win != null ? win.mContentInsets : null; 726 final Configuration displayConfig = displayContent.getConfiguration(); 727 // For the new aspect-scaled transition, we want it to always show 728 // above the animating opening/closing window, and we want to 729 // synchronize its thumbnail surface with the surface for the 730 // open/close animation (only on the way down) 731 anim = mService.mAppTransition.createThumbnailAspectScaleAnimationLocked(appRect, 732 insets, thumbnailHeader, taskId, displayConfig.uiMode, 733 displayConfig.orientation); 734 openingAppAnimator.thumbnailForceAboveLayer = Math.max(openingLayer, closingLayer); 735 openingAppAnimator.deferThumbnailDestruction = 736 !mService.mAppTransition.isNextThumbnailTransitionScaleUp(); 737 } else { 738 anim = mService.mAppTransition.createThumbnailScaleAnimationLocked( 739 displayInfo.appWidth, displayInfo.appHeight, transit, thumbnailHeader); 740 } 741 anim.restrictDuration(MAX_ANIMATION_DURATION); 742 anim.scaleCurrentDuration(mService.getTransitionAnimationScaleLocked()); 743 744 openingAppAnimator.thumbnail = surfaceControl; 745 openingAppAnimator.thumbnailLayer = openingLayer; 746 openingAppAnimator.thumbnailAnimation = anim; 747 mService.mAppTransition.getNextAppTransitionStartRect(taskId, mTmpStartRect); 748 } catch (Surface.OutOfResourcesException e) { 749 Slog.e(TAG, "Can't allocate thumbnail/Canvas surface w=" 750 + dirty.width() + " h=" + dirty.height(), e); 751 openingAppAnimator.clearThumbnail(); 752 } 753 } 754 requestTraversal()755 void requestTraversal() { 756 if (!mTraversalScheduled) { 757 mTraversalScheduled = true; 758 mService.mAnimationHandler.post(mPerformSurfacePlacement); 759 } 760 } 761 762 /** 763 * Puts the {@param surface} into a pending list to be destroyed after the current transaction 764 * has been committed. 765 */ destroyAfterTransaction(SurfaceControl surface)766 void destroyAfterTransaction(SurfaceControl surface) { 767 mPendingDestroyingSurfaces.add(surface); 768 } 769 770 /** 771 * Destroys any surfaces that have been put into the pending list with 772 * {@link #destroyAfterTransaction}. 773 */ destroyPendingSurfaces()774 void destroyPendingSurfaces() { 775 for (int i = mPendingDestroyingSurfaces.size() - 1; i >= 0; i--) { 776 mPendingDestroyingSurfaces.get(i).destroy(); 777 } 778 mPendingDestroyingSurfaces.clear(); 779 } 780 dump(PrintWriter pw, String prefix)781 public void dump(PrintWriter pw, String prefix) { 782 pw.println(prefix + "mTraversalScheduled=" + mTraversalScheduled); 783 pw.println(prefix + "mHoldScreenWindow=" + mService.mRoot.mHoldScreenWindow); 784 pw.println(prefix + "mObscuringWindow=" + mService.mRoot.mObscuringWindow); 785 } 786 } 787