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