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