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