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