1 /* 2 * Copyright (C) 2015 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 com.android.internal.util.ToBooleanFunction; 20 21 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; 22 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; 23 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; 24 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; 25 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; 26 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; 27 28 import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER; 29 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS; 30 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER; 31 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT; 32 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 33 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 34 import static com.android.server.wm.WindowManagerService.H.WALLPAPER_DRAW_PENDING_TIMEOUT; 35 36 import android.os.Bundle; 37 import android.os.Debug; 38 import android.os.IBinder; 39 import android.os.RemoteException; 40 import android.os.SystemClock; 41 import android.util.ArraySet; 42 import android.util.Slog; 43 import android.view.DisplayInfo; 44 import android.view.WindowManager; 45 import android.view.animation.Animation; 46 47 import java.io.PrintWriter; 48 import java.util.ArrayList; 49 50 /** 51 * Controls wallpaper windows visibility, ordering, and so on. 52 * NOTE: All methods in this class must be called with the window manager service lock held. 53 */ 54 class WallpaperController { 55 private static final String TAG = TAG_WITH_CLASS_NAME ? "WallpaperController" : TAG_WM; 56 private WindowManagerService mService; 57 58 private final ArrayList<WallpaperWindowToken> mWallpaperTokens = new ArrayList<>(); 59 60 // If non-null, this is the currently visible window that is associated 61 // with the wallpaper. 62 private WindowState mWallpaperTarget = null; 63 // If non-null, we are in the middle of animating from one wallpaper target 64 // to another, and this is the previous wallpaper target. 65 private WindowState mPrevWallpaperTarget = null; 66 67 private int mWallpaperAnimLayerAdjustment; 68 69 private float mLastWallpaperX = -1; 70 private float mLastWallpaperY = -1; 71 private float mLastWallpaperXStep = -1; 72 private float mLastWallpaperYStep = -1; 73 private int mLastWallpaperDisplayOffsetX = Integer.MIN_VALUE; 74 private int mLastWallpaperDisplayOffsetY = Integer.MIN_VALUE; 75 76 // This is set when we are waiting for a wallpaper to tell us it is done 77 // changing its scroll position. 78 private WindowState mWaitingOnWallpaper; 79 80 // The last time we had a timeout when waiting for a wallpaper. 81 private long mLastWallpaperTimeoutTime; 82 // We give a wallpaper up to 150ms to finish scrolling. 83 private static final long WALLPAPER_TIMEOUT = 150; 84 // Time we wait after a timeout before trying to wait again. 85 private static final long WALLPAPER_TIMEOUT_RECOVERY = 10000; 86 87 // Set to the wallpaper window we would like to hide once the transition animations are done. 88 // This is useful in cases where we don't want the wallpaper to be hidden when the close app 89 // is a wallpaper target and is done animating out, but the opening app isn't a wallpaper 90 // target and isn't done animating in. 91 WindowState mDeferredHideWallpaper = null; 92 93 // We give a wallpaper up to 500ms to finish drawing before playing app transitions. 94 private static final long WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION = 500; 95 private static final int WALLPAPER_DRAW_NORMAL = 0; 96 private static final int WALLPAPER_DRAW_PENDING = 1; 97 private static final int WALLPAPER_DRAW_TIMEOUT = 2; 98 private int mWallpaperDrawState = WALLPAPER_DRAW_NORMAL; 99 100 private final FindWallpaperTargetResult mFindResults = new FindWallpaperTargetResult(); 101 102 private final ToBooleanFunction<WindowState> mFindWallpaperTargetFunction = w -> { 103 final WindowAnimator winAnimator = mService.mAnimator; 104 if ((w.mAttrs.type == TYPE_WALLPAPER)) { 105 if (mFindResults.topWallpaper == null || mFindResults.resetTopWallpaper) { 106 mFindResults.setTopWallpaper(w); 107 mFindResults.resetTopWallpaper = false; 108 } 109 return false; 110 } 111 112 mFindResults.resetTopWallpaper = true; 113 if (w != winAnimator.mWindowDetachedWallpaper && w.mAppToken != null) { 114 // If this window's app token is hidden and not animating, it is of no interest to us. 115 if (w.mAppToken.hidden && w.mAppToken.mAppAnimator.animation == null) { 116 if (DEBUG_WALLPAPER) Slog.v(TAG, 117 "Skipping hidden and not animating token: " + w); 118 return false; 119 } 120 } 121 if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w + ": isOnScreen=" + w.isOnScreen() 122 + " mDrawState=" + w.mWinAnimator.mDrawState); 123 124 if (w.mWillReplaceWindow && mWallpaperTarget == null 125 && !mFindResults.useTopWallpaperAsTarget) { 126 // When we are replacing a window and there was wallpaper before replacement, we want to 127 // keep the window until the new windows fully appear and can determine the visibility, 128 // to avoid flickering. 129 mFindResults.setUseTopWallpaperAsTarget(true); 130 } 131 132 final boolean keyguardGoingAwayWithWallpaper = (w.mAppToken != null 133 && AppTransition.isKeyguardGoingAwayTransit( 134 w.mAppToken.mAppAnimator.getTransit()) 135 && (w.mAppToken.mAppAnimator.getTransitFlags() 136 & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0); 137 138 boolean needsShowWhenLockedWallpaper = false; 139 if ((w.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0 140 && mService.mPolicy.isKeyguardLocked() 141 && mService.mPolicy.isKeyguardOccluded()) { 142 // The lowest show when locked window decides whether we need to put the wallpaper 143 // behind. 144 needsShowWhenLockedWallpaper = !isFullscreen(w.mAttrs) 145 || (w.mAppToken != null && !w.mAppToken.fillsParent()); 146 } 147 148 if (keyguardGoingAwayWithWallpaper || needsShowWhenLockedWallpaper) { 149 // Keep the wallpaper during Keyguard exit but also when it's needed for a 150 // non-fullscreen show when locked activity. 151 mFindResults.setUseTopWallpaperAsTarget(true); 152 } 153 154 final boolean hasWallpaper = (w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0; 155 if (hasWallpaper && w.isOnScreen() && (mWallpaperTarget == w || w.isDrawFinishedLw())) { 156 if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: " + w); 157 mFindResults.setWallpaperTarget(w); 158 if (w == mWallpaperTarget && w.mWinAnimator.isAnimationSet()) { 159 // The current wallpaper target is animating, so we'll look behind it for 160 // another possible target and figure out what is going on later. 161 if (DEBUG_WALLPAPER) Slog.v(TAG, 162 "Win " + w + ": token animating, looking behind."); 163 } 164 // Found a target! End search. 165 return true; 166 } else if (w == winAnimator.mWindowDetachedWallpaper) { 167 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, 168 "Found animating detached wallpaper target win: " + w); 169 mFindResults.setUseTopWallpaperAsTarget(true); 170 } 171 return false; 172 }; 173 WallpaperController(WindowManagerService service)174 public WallpaperController(WindowManagerService service) { 175 mService = service; 176 } 177 getWallpaperTarget()178 WindowState getWallpaperTarget() { 179 return mWallpaperTarget; 180 } 181 isWallpaperTarget(WindowState win)182 boolean isWallpaperTarget(WindowState win) { 183 return win == mWallpaperTarget; 184 } 185 isBelowWallpaperTarget(WindowState win)186 boolean isBelowWallpaperTarget(WindowState win) { 187 return mWallpaperTarget != null && mWallpaperTarget.mLayer >= win.mBaseLayer; 188 } 189 isWallpaperVisible()190 boolean isWallpaperVisible() { 191 return isWallpaperVisible(mWallpaperTarget); 192 } 193 194 /** 195 * Starts {@param a} on all wallpaper windows. 196 */ startWallpaperAnimation(Animation a)197 void startWallpaperAnimation(Animation a) { 198 for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) { 199 final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx); 200 token.startAnimation(a); 201 } 202 } 203 isWallpaperVisible(WindowState wallpaperTarget)204 private boolean isWallpaperVisible(WindowState wallpaperTarget) { 205 if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper vis: target " + wallpaperTarget + ", obscured=" 206 + (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??") 207 + " anim=" + ((wallpaperTarget != null && wallpaperTarget.mAppToken != null) 208 ? wallpaperTarget.mAppToken.mAppAnimator.animation : null) 209 + " prev=" + mPrevWallpaperTarget); 210 return (wallpaperTarget != null 211 && (!wallpaperTarget.mObscured || (wallpaperTarget.mAppToken != null 212 && wallpaperTarget.mAppToken.mAppAnimator.animation != null))) 213 || mPrevWallpaperTarget != null; 214 } 215 isWallpaperTargetAnimating()216 boolean isWallpaperTargetAnimating() { 217 return mWallpaperTarget != null && mWallpaperTarget.mWinAnimator.isAnimationSet() 218 && !mWallpaperTarget.mWinAnimator.isDummyAnimation(); 219 } 220 updateWallpaperVisibility()221 void updateWallpaperVisibility() { 222 final boolean visible = isWallpaperVisible(mWallpaperTarget); 223 224 for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) { 225 final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx); 226 token.updateWallpaperVisibility(visible); 227 } 228 } 229 hideDeferredWallpapersIfNeeded()230 void hideDeferredWallpapersIfNeeded() { 231 if (mDeferredHideWallpaper != null) { 232 hideWallpapers(mDeferredHideWallpaper); 233 mDeferredHideWallpaper = null; 234 } 235 } 236 hideWallpapers(final WindowState winGoingAway)237 void hideWallpapers(final WindowState winGoingAway) { 238 if (mWallpaperTarget != null 239 && (mWallpaperTarget != winGoingAway || mPrevWallpaperTarget != null)) { 240 return; 241 } 242 if (mService.mAppTransition.isRunning()) { 243 // Defer hiding the wallpaper when app transition is running until the animations 244 // are done. 245 mDeferredHideWallpaper = winGoingAway; 246 return; 247 } 248 249 final boolean wasDeferred = (mDeferredHideWallpaper == winGoingAway); 250 for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) { 251 final WallpaperWindowToken token = mWallpaperTokens.get(i); 252 token.hideWallpaperToken(wasDeferred, "hideWallpapers"); 253 if (DEBUG_WALLPAPER_LIGHT && !token.hidden) Slog.d(TAG, "Hiding wallpaper " + token 254 + " from " + winGoingAway + " target=" + mWallpaperTarget + " prev=" 255 + mPrevWallpaperTarget + "\n" + Debug.getCallers(5, " ")); 256 } 257 } 258 updateWallpaperOffset(WindowState wallpaperWin, int dw, int dh, boolean sync)259 boolean updateWallpaperOffset(WindowState wallpaperWin, int dw, int dh, boolean sync) { 260 boolean rawChanged = false; 261 // Set the default wallpaper x-offset to either edge of the screen (depending on RTL), to 262 // match the behavior of most Launchers 263 float defaultWallpaperX = wallpaperWin.isRtl() ? 1f : 0f; 264 float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : defaultWallpaperX; 265 float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f; 266 int availw = wallpaperWin.mFrame.right - wallpaperWin.mFrame.left - dw; 267 int offset = availw > 0 ? -(int)(availw * wpx + .5f) : 0; 268 if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) { 269 offset += mLastWallpaperDisplayOffsetX; 270 } 271 boolean changed = wallpaperWin.mXOffset != offset; 272 if (changed) { 273 if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " x: " + offset); 274 wallpaperWin.mXOffset = offset; 275 } 276 if (wallpaperWin.mWallpaperX != wpx || wallpaperWin.mWallpaperXStep != wpxs) { 277 wallpaperWin.mWallpaperX = wpx; 278 wallpaperWin.mWallpaperXStep = wpxs; 279 rawChanged = true; 280 } 281 282 float wpy = mLastWallpaperY >= 0 ? mLastWallpaperY : 0.5f; 283 float wpys = mLastWallpaperYStep >= 0 ? mLastWallpaperYStep : -1.0f; 284 int availh = wallpaperWin.mFrame.bottom - wallpaperWin.mFrame.top - dh; 285 offset = availh > 0 ? -(int)(availh * wpy + .5f) : 0; 286 if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) { 287 offset += mLastWallpaperDisplayOffsetY; 288 } 289 if (wallpaperWin.mYOffset != offset) { 290 if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " y: " + offset); 291 changed = true; 292 wallpaperWin.mYOffset = offset; 293 } 294 if (wallpaperWin.mWallpaperY != wpy || wallpaperWin.mWallpaperYStep != wpys) { 295 wallpaperWin.mWallpaperY = wpy; 296 wallpaperWin.mWallpaperYStep = wpys; 297 rawChanged = true; 298 } 299 300 if (rawChanged && (wallpaperWin.mAttrs.privateFlags & 301 WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) != 0) { 302 try { 303 if (DEBUG_WALLPAPER) Slog.v(TAG, "Report new wp offset " 304 + wallpaperWin + " x=" + wallpaperWin.mWallpaperX 305 + " y=" + wallpaperWin.mWallpaperY); 306 if (sync) { 307 mWaitingOnWallpaper = wallpaperWin; 308 } 309 wallpaperWin.mClient.dispatchWallpaperOffsets( 310 wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY, 311 wallpaperWin.mWallpaperXStep, wallpaperWin.mWallpaperYStep, sync); 312 if (sync) { 313 if (mWaitingOnWallpaper != null) { 314 long start = SystemClock.uptimeMillis(); 315 if ((mLastWallpaperTimeoutTime + WALLPAPER_TIMEOUT_RECOVERY) 316 < start) { 317 try { 318 if (DEBUG_WALLPAPER) Slog.v(TAG, 319 "Waiting for offset complete..."); 320 mService.mWindowMap.wait(WALLPAPER_TIMEOUT); 321 } catch (InterruptedException e) { 322 } 323 if (DEBUG_WALLPAPER) Slog.v(TAG, "Offset complete!"); 324 if ((start + WALLPAPER_TIMEOUT) < SystemClock.uptimeMillis()) { 325 Slog.i(TAG, "Timeout waiting for wallpaper to offset: " 326 + wallpaperWin); 327 mLastWallpaperTimeoutTime = start; 328 } 329 } 330 mWaitingOnWallpaper = null; 331 } 332 } 333 } catch (RemoteException e) { 334 } 335 } 336 337 return changed; 338 } 339 setWindowWallpaperPosition( WindowState window, float x, float y, float xStep, float yStep)340 void setWindowWallpaperPosition( 341 WindowState window, float x, float y, float xStep, float yStep) { 342 if (window.mWallpaperX != x || window.mWallpaperY != y) { 343 window.mWallpaperX = x; 344 window.mWallpaperY = y; 345 window.mWallpaperXStep = xStep; 346 window.mWallpaperYStep = yStep; 347 updateWallpaperOffsetLocked(window, true); 348 } 349 } 350 setWindowWallpaperDisplayOffset(WindowState window, int x, int y)351 void setWindowWallpaperDisplayOffset(WindowState window, int x, int y) { 352 if (window.mWallpaperDisplayOffsetX != x || window.mWallpaperDisplayOffsetY != y) { 353 window.mWallpaperDisplayOffsetX = x; 354 window.mWallpaperDisplayOffsetY = y; 355 updateWallpaperOffsetLocked(window, true); 356 } 357 } 358 sendWindowWallpaperCommand( WindowState window, String action, int x, int y, int z, Bundle extras, boolean sync)359 Bundle sendWindowWallpaperCommand( 360 WindowState window, String action, int x, int y, int z, Bundle extras, boolean sync) { 361 if (window == mWallpaperTarget || window == mPrevWallpaperTarget) { 362 boolean doWait = sync; 363 for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) { 364 final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx); 365 token.sendWindowWallpaperCommand(action, x, y, z, extras, sync); 366 } 367 368 if (doWait) { 369 // TODO: Need to wait for result. 370 } 371 } 372 373 return null; 374 } 375 updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync)376 private void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) { 377 final DisplayContent displayContent = changingTarget.getDisplayContent(); 378 if (displayContent == null) { 379 return; 380 } 381 final DisplayInfo displayInfo = displayContent.getDisplayInfo(); 382 final int dw = displayInfo.logicalWidth; 383 final int dh = displayInfo.logicalHeight; 384 385 WindowState target = mWallpaperTarget; 386 if (target != null) { 387 if (target.mWallpaperX >= 0) { 388 mLastWallpaperX = target.mWallpaperX; 389 } else if (changingTarget.mWallpaperX >= 0) { 390 mLastWallpaperX = changingTarget.mWallpaperX; 391 } 392 if (target.mWallpaperY >= 0) { 393 mLastWallpaperY = target.mWallpaperY; 394 } else if (changingTarget.mWallpaperY >= 0) { 395 mLastWallpaperY = changingTarget.mWallpaperY; 396 } 397 if (target.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) { 398 mLastWallpaperDisplayOffsetX = target.mWallpaperDisplayOffsetX; 399 } else if (changingTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) { 400 mLastWallpaperDisplayOffsetX = changingTarget.mWallpaperDisplayOffsetX; 401 } 402 if (target.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) { 403 mLastWallpaperDisplayOffsetY = target.mWallpaperDisplayOffsetY; 404 } else if (changingTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) { 405 mLastWallpaperDisplayOffsetY = changingTarget.mWallpaperDisplayOffsetY; 406 } 407 if (target.mWallpaperXStep >= 0) { 408 mLastWallpaperXStep = target.mWallpaperXStep; 409 } else if (changingTarget.mWallpaperXStep >= 0) { 410 mLastWallpaperXStep = changingTarget.mWallpaperXStep; 411 } 412 if (target.mWallpaperYStep >= 0) { 413 mLastWallpaperYStep = target.mWallpaperYStep; 414 } else if (changingTarget.mWallpaperYStep >= 0) { 415 mLastWallpaperYStep = changingTarget.mWallpaperYStep; 416 } 417 } 418 419 for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) { 420 mWallpaperTokens.get(curTokenNdx).updateWallpaperOffset(dw, dh, sync); 421 } 422 } 423 clearLastWallpaperTimeoutTime()424 void clearLastWallpaperTimeoutTime() { 425 mLastWallpaperTimeoutTime = 0; 426 } 427 wallpaperCommandComplete(IBinder window)428 void wallpaperCommandComplete(IBinder window) { 429 if (mWaitingOnWallpaper != null && 430 mWaitingOnWallpaper.mClient.asBinder() == window) { 431 mWaitingOnWallpaper = null; 432 mService.mWindowMap.notifyAll(); 433 } 434 } 435 wallpaperOffsetsComplete(IBinder window)436 void wallpaperOffsetsComplete(IBinder window) { 437 if (mWaitingOnWallpaper != null && 438 mWaitingOnWallpaper.mClient.asBinder() == window) { 439 mWaitingOnWallpaper = null; 440 mService.mWindowMap.notifyAll(); 441 } 442 } 443 getAnimLayerAdjustment()444 int getAnimLayerAdjustment() { 445 return mWallpaperAnimLayerAdjustment; 446 } 447 findWallpaperTarget(DisplayContent dc)448 private void findWallpaperTarget(DisplayContent dc) { 449 mFindResults.reset(); 450 if (dc.isStackVisible(FREEFORM_WORKSPACE_STACK_ID)) { 451 // In freeform mode we set the wallpaper as its own target, so we don't need an 452 // additional window to make it visible. 453 mFindResults.setUseTopWallpaperAsTarget(true); 454 } 455 456 dc.forAllWindows(mFindWallpaperTargetFunction, true /* traverseTopToBottom */); 457 458 if (mFindResults.wallpaperTarget == null && mFindResults.useTopWallpaperAsTarget) { 459 mFindResults.setWallpaperTarget(mFindResults.topWallpaper); 460 } 461 } 462 isFullscreen(WindowManager.LayoutParams attrs)463 private boolean isFullscreen(WindowManager.LayoutParams attrs) { 464 return attrs.x == 0 && attrs.y == 0 465 && attrs.width == MATCH_PARENT && attrs.height == MATCH_PARENT; 466 } 467 468 /** Updates the target wallpaper if needed and returns true if an update happened. */ updateWallpaperWindowsTarget(DisplayContent dc, FindWallpaperTargetResult result)469 private void updateWallpaperWindowsTarget(DisplayContent dc, 470 FindWallpaperTargetResult result) { 471 472 WindowState wallpaperTarget = result.wallpaperTarget; 473 474 if (mWallpaperTarget == wallpaperTarget 475 || (mPrevWallpaperTarget != null && mPrevWallpaperTarget == wallpaperTarget)) { 476 477 if (mPrevWallpaperTarget == null) { 478 return; 479 } 480 481 // Is it time to stop animating? 482 if (!mPrevWallpaperTarget.isAnimatingLw()) { 483 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "No longer animating wallpaper targets!"); 484 mPrevWallpaperTarget = null; 485 mWallpaperTarget = wallpaperTarget; 486 } 487 return; 488 } 489 490 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, 491 "New wallpaper target: " + wallpaperTarget + " prevTarget: " + mWallpaperTarget); 492 493 mPrevWallpaperTarget = null; 494 495 final WindowState prevWallpaperTarget = mWallpaperTarget; 496 mWallpaperTarget = wallpaperTarget; 497 498 if (wallpaperTarget == null || prevWallpaperTarget == null) { 499 return; 500 } 501 502 // Now what is happening... if the current and new targets are animating, 503 // then we are in our super special mode! 504 boolean oldAnim = prevWallpaperTarget.isAnimatingLw(); 505 boolean foundAnim = wallpaperTarget.isAnimatingLw(); 506 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, 507 "New animation: " + foundAnim + " old animation: " + oldAnim); 508 509 if (!foundAnim || !oldAnim) { 510 return; 511 } 512 513 if (dc.getWindow(w -> w == prevWallpaperTarget) == null) { 514 return; 515 } 516 517 final boolean newTargetHidden = wallpaperTarget.mAppToken != null 518 && wallpaperTarget.mAppToken.hiddenRequested; 519 final boolean oldTargetHidden = prevWallpaperTarget.mAppToken != null 520 && prevWallpaperTarget.mAppToken.hiddenRequested; 521 522 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Animating wallpapers:" + " old: " 523 + prevWallpaperTarget + " hidden=" + oldTargetHidden + " new: " + wallpaperTarget 524 + " hidden=" + newTargetHidden); 525 526 mPrevWallpaperTarget = prevWallpaperTarget; 527 528 if (newTargetHidden && !oldTargetHidden) { 529 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Old wallpaper still the target."); 530 // Use the old target if new target is hidden but old target 531 // is not. If they're both hidden, still use the new target. 532 mWallpaperTarget = prevWallpaperTarget; 533 } else if (newTargetHidden == oldTargetHidden 534 && !mService.mOpeningApps.contains(wallpaperTarget.mAppToken) 535 && (mService.mOpeningApps.contains(prevWallpaperTarget.mAppToken) 536 || mService.mClosingApps.contains(prevWallpaperTarget.mAppToken))) { 537 // If they're both hidden (or both not hidden), prefer the one that's currently in 538 // opening or closing app list, this allows transition selection logic to better 539 // determine the wallpaper status of opening/closing apps. 540 mWallpaperTarget = prevWallpaperTarget; 541 } 542 543 result.setWallpaperTarget(wallpaperTarget); 544 } 545 updateWallpaperTokens(boolean visible)546 private void updateWallpaperTokens(boolean visible) { 547 for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) { 548 final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx); 549 token.updateWallpaperWindows(visible, mWallpaperAnimLayerAdjustment); 550 token.getDisplayContent().assignWindowLayers(false); 551 } 552 } 553 adjustWallpaperWindows(DisplayContent dc)554 void adjustWallpaperWindows(DisplayContent dc) { 555 mService.mRoot.mWallpaperMayChange = false; 556 557 // First find top-most window that has asked to be on top of the wallpaper; 558 // all wallpapers go behind it. 559 findWallpaperTarget(dc); 560 updateWallpaperWindowsTarget(dc, mFindResults); 561 562 // The window is visible to the compositor...but is it visible to the user? 563 // That is what the wallpaper cares about. 564 final boolean visible = mWallpaperTarget != null && isWallpaperVisible(mWallpaperTarget); 565 if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper visibility: " + visible); 566 567 if (visible) { 568 // If the wallpaper target is animating, we may need to copy its layer adjustment. 569 // Only do this if we are not transferring between two wallpaper targets. 570 mWallpaperAnimLayerAdjustment = 571 (mPrevWallpaperTarget == null && mWallpaperTarget.mAppToken != null) 572 ? mWallpaperTarget.mAppToken.getAnimLayerAdjustment() : 0; 573 574 if (mWallpaperTarget.mWallpaperX >= 0) { 575 mLastWallpaperX = mWallpaperTarget.mWallpaperX; 576 mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep; 577 } 578 if (mWallpaperTarget.mWallpaperY >= 0) { 579 mLastWallpaperY = mWallpaperTarget.mWallpaperY; 580 mLastWallpaperYStep = mWallpaperTarget.mWallpaperYStep; 581 } 582 if (mWallpaperTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) { 583 mLastWallpaperDisplayOffsetX = mWallpaperTarget.mWallpaperDisplayOffsetX; 584 } 585 if (mWallpaperTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) { 586 mLastWallpaperDisplayOffsetY = mWallpaperTarget.mWallpaperDisplayOffsetY; 587 } 588 } 589 590 updateWallpaperTokens(visible); 591 592 if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, "New wallpaper: target=" + mWallpaperTarget 593 + " prev=" + mPrevWallpaperTarget); 594 } 595 processWallpaperDrawPendingTimeout()596 boolean processWallpaperDrawPendingTimeout() { 597 if (mWallpaperDrawState == WALLPAPER_DRAW_PENDING) { 598 mWallpaperDrawState = WALLPAPER_DRAW_TIMEOUT; 599 if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG, 600 "*** WALLPAPER DRAW TIMEOUT"); 601 return true; 602 } 603 return false; 604 } 605 wallpaperTransitionReady()606 boolean wallpaperTransitionReady() { 607 boolean transitionReady = true; 608 boolean wallpaperReady = true; 609 for (int curTokenIndex = mWallpaperTokens.size() - 1; 610 curTokenIndex >= 0 && wallpaperReady; curTokenIndex--) { 611 final WallpaperWindowToken token = mWallpaperTokens.get(curTokenIndex); 612 if (token.hasVisibleNotDrawnWallpaper()) { 613 // We've told this wallpaper to be visible, but it is not drawn yet 614 wallpaperReady = false; 615 if (mWallpaperDrawState != WALLPAPER_DRAW_TIMEOUT) { 616 // wait for this wallpaper until it is drawn or timeout 617 transitionReady = false; 618 } 619 if (mWallpaperDrawState == WALLPAPER_DRAW_NORMAL) { 620 mWallpaperDrawState = WALLPAPER_DRAW_PENDING; 621 mService.mH.removeMessages(WALLPAPER_DRAW_PENDING_TIMEOUT); 622 mService.mH.sendEmptyMessageDelayed(WALLPAPER_DRAW_PENDING_TIMEOUT, 623 WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION); 624 } 625 if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG, 626 "Wallpaper should be visible but has not been drawn yet. " + 627 "mWallpaperDrawState=" + mWallpaperDrawState); 628 break; 629 } 630 } 631 if (wallpaperReady) { 632 mWallpaperDrawState = WALLPAPER_DRAW_NORMAL; 633 mService.mH.removeMessages(WALLPAPER_DRAW_PENDING_TIMEOUT); 634 } 635 636 return transitionReady; 637 } 638 639 /** 640 * Adjusts the wallpaper windows if the input display has a pending wallpaper layout or one of 641 * the opening apps should be a wallpaper target. 642 */ adjustWallpaperWindowsForAppTransitionIfNeeded(DisplayContent dc, ArraySet<AppWindowToken> openingApps)643 void adjustWallpaperWindowsForAppTransitionIfNeeded(DisplayContent dc, 644 ArraySet<AppWindowToken> openingApps) { 645 boolean adjust = false; 646 if ((dc.pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) { 647 adjust = true; 648 } else { 649 for (int i = openingApps.size() - 1; i >= 0; --i) { 650 final AppWindowToken token = openingApps.valueAt(i); 651 if (token.windowsCanBeWallpaperTarget()) { 652 adjust = true; 653 break; 654 } 655 } 656 } 657 658 if (adjust) { 659 adjustWallpaperWindows(dc); 660 } 661 } 662 addWallpaperToken(WallpaperWindowToken token)663 void addWallpaperToken(WallpaperWindowToken token) { 664 mWallpaperTokens.add(token); 665 } 666 removeWallpaperToken(WallpaperWindowToken token)667 void removeWallpaperToken(WallpaperWindowToken token) { 668 mWallpaperTokens.remove(token); 669 } 670 dump(PrintWriter pw, String prefix)671 void dump(PrintWriter pw, String prefix) { 672 pw.print(prefix); pw.print("mWallpaperTarget="); pw.println(mWallpaperTarget); 673 if (mPrevWallpaperTarget != null) { 674 pw.print(prefix); pw.print("mPrevWallpaperTarget="); pw.println(mPrevWallpaperTarget); 675 } 676 pw.print(prefix); pw.print("mLastWallpaperX="); pw.print(mLastWallpaperX); 677 pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY); 678 if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE 679 || mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) { 680 pw.print(prefix); 681 pw.print("mLastWallpaperDisplayOffsetX="); pw.print(mLastWallpaperDisplayOffsetX); 682 pw.print(" mLastWallpaperDisplayOffsetY="); pw.println(mLastWallpaperDisplayOffsetY); 683 } 684 685 if (mWallpaperAnimLayerAdjustment != 0) { 686 pw.println(prefix + "mWallpaperAnimLayerAdjustment=" + mWallpaperAnimLayerAdjustment); 687 } 688 } 689 690 /** Helper class for storing the results of a wallpaper target find operation. */ 691 final private static class FindWallpaperTargetResult { 692 WindowState topWallpaper = null; 693 boolean useTopWallpaperAsTarget = false; 694 WindowState wallpaperTarget = null; 695 boolean resetTopWallpaper = false; 696 setTopWallpaper(WindowState win)697 void setTopWallpaper(WindowState win) { 698 topWallpaper = win; 699 } 700 setWallpaperTarget(WindowState win)701 void setWallpaperTarget(WindowState win) { 702 wallpaperTarget = win; 703 } 704 setUseTopWallpaperAsTarget(boolean topWallpaperAsTarget)705 void setUseTopWallpaperAsTarget(boolean topWallpaperAsTarget) { 706 useTopWallpaperAsTarget = topWallpaperAsTarget; 707 } 708 reset()709 void reset() { 710 topWallpaper = null; 711 wallpaperTarget = null; 712 useTopWallpaperAsTarget = false; 713 resetTopWallpaper = false; 714 } 715 } 716 } 717