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