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