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 float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : 0.5f; 250 float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f; 251 int availw = wallpaperWin.mFrame.right - wallpaperWin.mFrame.left - dw; 252 int offset = availw > 0 ? -(int)(availw * wpx + .5f) : 0; 253 if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) { 254 offset += mLastWallpaperDisplayOffsetX; 255 } 256 boolean changed = wallpaperWin.mXOffset != offset; 257 if (changed) { 258 if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " x: " + offset); 259 wallpaperWin.mXOffset = offset; 260 } 261 if (wallpaperWin.mWallpaperX != wpx || wallpaperWin.mWallpaperXStep != wpxs) { 262 wallpaperWin.mWallpaperX = wpx; 263 wallpaperWin.mWallpaperXStep = wpxs; 264 rawChanged = true; 265 } 266 267 float wpy = mLastWallpaperY >= 0 ? mLastWallpaperY : 0.5f; 268 float wpys = mLastWallpaperYStep >= 0 ? mLastWallpaperYStep : -1.0f; 269 int availh = wallpaperWin.mFrame.bottom - wallpaperWin.mFrame.top - dh; 270 offset = availh > 0 ? -(int)(availh * wpy + .5f) : 0; 271 if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) { 272 offset += mLastWallpaperDisplayOffsetY; 273 } 274 if (wallpaperWin.mYOffset != offset) { 275 if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " y: " + offset); 276 changed = true; 277 wallpaperWin.mYOffset = offset; 278 } 279 if (wallpaperWin.mWallpaperY != wpy || wallpaperWin.mWallpaperYStep != wpys) { 280 wallpaperWin.mWallpaperY = wpy; 281 wallpaperWin.mWallpaperYStep = wpys; 282 rawChanged = true; 283 } 284 285 if (rawChanged && (wallpaperWin.mAttrs.privateFlags & 286 WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) != 0) { 287 try { 288 if (DEBUG_WALLPAPER) Slog.v(TAG, "Report new wp offset " 289 + wallpaperWin + " x=" + wallpaperWin.mWallpaperX 290 + " y=" + wallpaperWin.mWallpaperY); 291 if (sync) { 292 mWaitingOnWallpaper = wallpaperWin; 293 } 294 wallpaperWin.mClient.dispatchWallpaperOffsets( 295 wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY, 296 wallpaperWin.mWallpaperXStep, wallpaperWin.mWallpaperYStep, sync); 297 if (sync) { 298 if (mWaitingOnWallpaper != null) { 299 long start = SystemClock.uptimeMillis(); 300 if ((mLastWallpaperTimeoutTime + WALLPAPER_TIMEOUT_RECOVERY) 301 < start) { 302 try { 303 if (DEBUG_WALLPAPER) Slog.v(TAG, 304 "Waiting for offset complete..."); 305 mService.mWindowMap.wait(WALLPAPER_TIMEOUT); 306 } catch (InterruptedException e) { 307 } 308 if (DEBUG_WALLPAPER) Slog.v(TAG, "Offset complete!"); 309 if ((start + WALLPAPER_TIMEOUT) < SystemClock.uptimeMillis()) { 310 Slog.i(TAG, "Timeout waiting for wallpaper to offset: " 311 + wallpaperWin); 312 mLastWallpaperTimeoutTime = start; 313 } 314 } 315 mWaitingOnWallpaper = null; 316 } 317 } 318 } catch (RemoteException e) { 319 } 320 } 321 322 return changed; 323 } 324 setWindowWallpaperPosition( WindowState window, float x, float y, float xStep, float yStep)325 void setWindowWallpaperPosition( 326 WindowState window, float x, float y, float xStep, float yStep) { 327 if (window.mWallpaperX != x || window.mWallpaperY != y) { 328 window.mWallpaperX = x; 329 window.mWallpaperY = y; 330 window.mWallpaperXStep = xStep; 331 window.mWallpaperYStep = yStep; 332 updateWallpaperOffsetLocked(window, true); 333 } 334 } 335 setWindowWallpaperDisplayOffset(WindowState window, int x, int y)336 void setWindowWallpaperDisplayOffset(WindowState window, int x, int y) { 337 if (window.mWallpaperDisplayOffsetX != x || window.mWallpaperDisplayOffsetY != y) { 338 window.mWallpaperDisplayOffsetX = x; 339 window.mWallpaperDisplayOffsetY = y; 340 updateWallpaperOffsetLocked(window, true); 341 } 342 } 343 sendWindowWallpaperCommand( WindowState window, String action, int x, int y, int z, Bundle extras, boolean sync)344 Bundle sendWindowWallpaperCommand( 345 WindowState window, String action, int x, int y, int z, Bundle extras, boolean sync) { 346 if (window == mWallpaperTarget 347 || window == mLowerWallpaperTarget 348 || window == mUpperWallpaperTarget) { 349 boolean doWait = sync; 350 for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) { 351 final WindowList windows = mWallpaperTokens.get(curTokenNdx).windows; 352 for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) { 353 WindowState wallpaper = windows.get(wallpaperNdx); 354 try { 355 wallpaper.mClient.dispatchWallpaperCommand(action, 356 x, y, z, extras, sync); 357 // We only want to be synchronous with one wallpaper. 358 sync = false; 359 } catch (RemoteException e) { 360 } 361 } 362 } 363 364 if (doWait) { 365 // TODO: Need to wait for result. 366 } 367 } 368 369 return null; 370 } 371 updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync)372 void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) { 373 final DisplayContent displayContent = changingTarget.getDisplayContent(); 374 if (displayContent == null) { 375 return; 376 } 377 final DisplayInfo displayInfo = displayContent.getDisplayInfo(); 378 final int dw = displayInfo.logicalWidth; 379 final int dh = displayInfo.logicalHeight; 380 381 WindowState target = mWallpaperTarget; 382 if (target != null) { 383 if (target.mWallpaperX >= 0) { 384 mLastWallpaperX = target.mWallpaperX; 385 } else if (changingTarget.mWallpaperX >= 0) { 386 mLastWallpaperX = changingTarget.mWallpaperX; 387 } 388 if (target.mWallpaperY >= 0) { 389 mLastWallpaperY = target.mWallpaperY; 390 } else if (changingTarget.mWallpaperY >= 0) { 391 mLastWallpaperY = changingTarget.mWallpaperY; 392 } 393 if (target.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) { 394 mLastWallpaperDisplayOffsetX = target.mWallpaperDisplayOffsetX; 395 } else if (changingTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) { 396 mLastWallpaperDisplayOffsetX = changingTarget.mWallpaperDisplayOffsetX; 397 } 398 if (target.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) { 399 mLastWallpaperDisplayOffsetY = target.mWallpaperDisplayOffsetY; 400 } else if (changingTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) { 401 mLastWallpaperDisplayOffsetY = changingTarget.mWallpaperDisplayOffsetY; 402 } 403 if (target.mWallpaperXStep >= 0) { 404 mLastWallpaperXStep = target.mWallpaperXStep; 405 } else if (changingTarget.mWallpaperXStep >= 0) { 406 mLastWallpaperXStep = changingTarget.mWallpaperXStep; 407 } 408 if (target.mWallpaperYStep >= 0) { 409 mLastWallpaperYStep = target.mWallpaperYStep; 410 } else if (changingTarget.mWallpaperYStep >= 0) { 411 mLastWallpaperYStep = changingTarget.mWallpaperYStep; 412 } 413 } 414 415 for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) { 416 WindowList windows = mWallpaperTokens.get(curTokenNdx).windows; 417 for (int wallpaperNdx = windows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) { 418 WindowState wallpaper = windows.get(wallpaperNdx); 419 if (updateWallpaperOffset(wallpaper, dw, dh, sync)) { 420 WindowStateAnimator winAnimator = wallpaper.mWinAnimator; 421 winAnimator.computeShownFrameLocked(); 422 // No need to lay out the windows - we can just set the wallpaper position 423 // directly. 424 winAnimator.setWallpaperOffset(wallpaper.mShownPosition); 425 // We only want to be synchronous with one wallpaper. 426 sync = false; 427 } 428 } 429 } 430 } 431 clearLastWallpaperTimeoutTime()432 void clearLastWallpaperTimeoutTime() { 433 mLastWallpaperTimeoutTime = 0; 434 } 435 wallpaperCommandComplete(IBinder window)436 void wallpaperCommandComplete(IBinder window) { 437 if (mWaitingOnWallpaper != null && 438 mWaitingOnWallpaper.mClient.asBinder() == window) { 439 mWaitingOnWallpaper = null; 440 mService.mWindowMap.notifyAll(); 441 } 442 } 443 wallpaperOffsetsComplete(IBinder window)444 void wallpaperOffsetsComplete(IBinder window) { 445 if (mWaitingOnWallpaper != null && 446 mWaitingOnWallpaper.mClient.asBinder() == window) { 447 mWaitingOnWallpaper = null; 448 mService.mWindowMap.notifyAll(); 449 } 450 } 451 getAnimLayerAdjustment()452 int getAnimLayerAdjustment() { 453 return mWallpaperAnimLayerAdjustment; 454 } 455 setAnimLayerAdjustment(WindowState win, int adj)456 void setAnimLayerAdjustment(WindowState win, int adj) { 457 if (win != mWallpaperTarget || mLowerWallpaperTarget != null) { 458 return; 459 } 460 461 if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "Setting wallpaper layer adj to " + adj); 462 mWallpaperAnimLayerAdjustment = adj; 463 for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) { 464 WindowList windows = mWallpaperTokens.get(i).windows; 465 for (int j = windows.size() - 1; j >= 0; j--) { 466 WindowState wallpaper = windows.get(j); 467 wallpaper.mWinAnimator.mAnimLayer = wallpaper.mLayer + adj; 468 if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "setWallpaper win " 469 + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer); 470 } 471 } 472 } 473 findWallpaperTarget(WindowList windows, FindWallpaperTargetResult result)474 private void findWallpaperTarget(WindowList windows, FindWallpaperTargetResult result) { 475 final WindowAnimator winAnimator = mService.mAnimator; 476 result.reset(); 477 WindowState w = null; 478 int windowDetachedI = -1; 479 boolean resetTopWallpaper = false; 480 boolean inFreeformSpace = false; 481 boolean replacing = false; 482 for (int i = windows.size() - 1; i >= 0; i--) { 483 w = windows.get(i); 484 if ((w.mAttrs.type == TYPE_WALLPAPER)) { 485 if (result.topWallpaper == null || resetTopWallpaper) { 486 result.setTopWallpaper(w, i); 487 resetTopWallpaper = false; 488 } 489 continue; 490 } 491 resetTopWallpaper = true; 492 if (w != winAnimator.mWindowDetachedWallpaper && w.mAppToken != null) { 493 // If this window's app token is hidden and not animating, 494 // it is of no interest to us. 495 if (w.mAppToken.hidden && w.mAppToken.mAppAnimator.animation == null) { 496 if (DEBUG_WALLPAPER) Slog.v(TAG, 497 "Skipping hidden and not animating token: " + w); 498 continue; 499 } 500 } 501 if (DEBUG_WALLPAPER) Slog.v(TAG, "Win #" + i + " " + w + ": isOnScreen=" 502 + w.isOnScreen() + " mDrawState=" + w.mWinAnimator.mDrawState); 503 504 if (!inFreeformSpace) { 505 TaskStack stack = w.getStack(); 506 inFreeformSpace = stack != null && stack.mStackId == FREEFORM_WORKSPACE_STACK_ID; 507 } 508 509 replacing = replacing || w.mWillReplaceWindow; 510 511 // If the app is executing an animation because the keyguard is going away (and the 512 // keyguard was showing the wallpaper) keep the wallpaper during the animation so it 513 // doesn't flicker out. 514 final boolean hasWallpaper = (w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0 515 || (w.mAppToken != null && w.mWinAnimator.mKeyguardGoingAwayWithWallpaper); 516 if (hasWallpaper && w.isOnScreen() && (mWallpaperTarget == w || w.isDrawFinishedLw())) { 517 if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: #" + i + "=" + w); 518 result.setWallpaperTarget(w, i); 519 if (w == mWallpaperTarget && w.mWinAnimator.isAnimationSet()) { 520 // The current wallpaper target is animating, so we'll look behind it for 521 // another possible target and figure out what is going on later. 522 if (DEBUG_WALLPAPER) Slog.v(TAG, 523 "Win " + w + ": token animating, looking behind."); 524 continue; 525 } 526 break; 527 } else if (w == winAnimator.mWindowDetachedWallpaper) { 528 windowDetachedI = i; 529 } 530 } 531 532 if (result.wallpaperTarget == null && windowDetachedI >= 0) { 533 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, 534 "Found animating detached wallpaper activity: #" + windowDetachedI + "=" + w); 535 result.setWallpaperTarget(w, windowDetachedI); 536 } 537 if (result.wallpaperTarget == null 538 && (inFreeformSpace || (replacing && mWallpaperTarget != null))) { 539 // In freeform mode we set the wallpaper as its own target, so we don't need an 540 // additional window to make it visible. When we are replacing a window and there was 541 // wallpaper before replacement, we want to keep the window until the new windows fully 542 // appear and can determine the visibility, to avoid flickering. 543 result.setWallpaperTarget(result.topWallpaper, result.topWallpaperIndex); 544 } 545 } 546 updateWallpaperWindowsTarget( WindowList windows, FindWallpaperTargetResult result)547 private boolean updateWallpaperWindowsTarget( 548 WindowList windows, FindWallpaperTargetResult result) { 549 550 boolean targetChanged = false; 551 WindowState wallpaperTarget = result.wallpaperTarget; 552 int wallpaperTargetIndex = result.wallpaperTargetIndex; 553 554 if (mWallpaperTarget != wallpaperTarget 555 && (mLowerWallpaperTarget == null || mLowerWallpaperTarget != wallpaperTarget)) { 556 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, 557 "New wallpaper target: " + wallpaperTarget + " oldTarget: " + mWallpaperTarget); 558 559 mLowerWallpaperTarget = null; 560 mUpperWallpaperTarget = null; 561 562 WindowState oldW = mWallpaperTarget; 563 mWallpaperTarget = wallpaperTarget; 564 targetChanged = true; 565 566 // Now what is happening... if the current and new targets are animating, 567 // then we are in our super special mode! 568 if (wallpaperTarget != null && oldW != null) { 569 boolean oldAnim = oldW.isAnimatingLw(); 570 boolean foundAnim = wallpaperTarget.isAnimatingLw(); 571 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, 572 "New animation: " + foundAnim + " old animation: " + oldAnim); 573 if (foundAnim && oldAnim) { 574 int oldI = windows.indexOf(oldW); 575 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, 576 "New i: " + wallpaperTargetIndex + " old i: " + oldI); 577 if (oldI >= 0) { 578 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, 579 "Animating wallpapers: old#" + oldI + "=" + oldW + "; new#" 580 + wallpaperTargetIndex + "=" + wallpaperTarget); 581 582 // Set the new target correctly. 583 if (wallpaperTarget.mAppToken != null 584 && wallpaperTarget.mAppToken.hiddenRequested) { 585 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, 586 "Old wallpaper still the target."); 587 mWallpaperTarget = oldW; 588 wallpaperTarget = oldW; 589 wallpaperTargetIndex = oldI; 590 } 591 // Now set the upper and lower wallpaper targets correctly, 592 // and make sure that we are positioning the wallpaper below the lower. 593 else if (wallpaperTargetIndex > oldI) { 594 // The new target is on top of the old one. 595 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, 596 "Found target above old target."); 597 mUpperWallpaperTarget = wallpaperTarget; 598 mLowerWallpaperTarget = oldW; 599 wallpaperTarget = oldW; 600 wallpaperTargetIndex = oldI; 601 } else { 602 // The new target is below the old one. 603 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, 604 "Found target below old target."); 605 mUpperWallpaperTarget = oldW; 606 mLowerWallpaperTarget = wallpaperTarget; 607 } 608 } 609 } 610 } 611 612 } else if (mLowerWallpaperTarget != null) { 613 // Is it time to stop animating? 614 if (!mLowerWallpaperTarget.isAnimatingLw() || !mUpperWallpaperTarget.isAnimatingLw()) { 615 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "No longer animating wallpaper targets!"); 616 mLowerWallpaperTarget = null; 617 mUpperWallpaperTarget = null; 618 mWallpaperTarget = wallpaperTarget; 619 targetChanged = true; 620 } 621 } 622 623 result.setWallpaperTarget(wallpaperTarget, wallpaperTargetIndex); 624 return targetChanged; 625 } 626 updateWallpaperWindowsTargetByLayer( WindowList windows, FindWallpaperTargetResult result)627 boolean updateWallpaperWindowsTargetByLayer( 628 WindowList windows, FindWallpaperTargetResult result) { 629 630 WindowState wallpaperTarget = result.wallpaperTarget; 631 int wallpaperTargetIndex = result.wallpaperTargetIndex; 632 boolean visible = wallpaperTarget != null; 633 634 if (visible) { 635 // The window is visible to the compositor...but is it visible to the user? 636 // That is what the wallpaper cares about. 637 visible = isWallpaperVisible(wallpaperTarget); 638 if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper visibility: " + visible); 639 640 // If the wallpaper target is animating, we may need to copy its layer adjustment. 641 // Only do this if we are not transferring between two wallpaper targets. 642 mWallpaperAnimLayerAdjustment = 643 (mLowerWallpaperTarget == null && wallpaperTarget.mAppToken != null) 644 ? wallpaperTarget.mAppToken.mAppAnimator.animLayerAdjustment : 0; 645 646 final int maxLayer = (mService.mPolicy.getMaxWallpaperLayer() * TYPE_LAYER_MULTIPLIER) 647 + TYPE_LAYER_OFFSET; 648 649 // Now w is the window we are supposed to be behind... but we 650 // need to be sure to also be behind any of its attached windows, 651 // AND any starting window associated with it, AND below the 652 // maximum layer the policy allows for wallpapers. 653 while (wallpaperTargetIndex > 0) { 654 WindowState wb = windows.get(wallpaperTargetIndex - 1); 655 if (wb.mBaseLayer < maxLayer && 656 wb.mAttachedWindow != wallpaperTarget && 657 (wallpaperTarget.mAttachedWindow == null || 658 wb.mAttachedWindow != wallpaperTarget.mAttachedWindow) && 659 (wb.mAttrs.type != TYPE_APPLICATION_STARTING 660 || wallpaperTarget.mToken == null 661 || wb.mToken != wallpaperTarget.mToken)) { 662 // This window is not related to the previous one in any 663 // interesting way, so stop here. 664 break; 665 } 666 wallpaperTarget = wb; 667 wallpaperTargetIndex--; 668 } 669 } else { 670 if (DEBUG_WALLPAPER) Slog.v(TAG, "No wallpaper target"); 671 } 672 673 result.setWallpaperTarget(wallpaperTarget, wallpaperTargetIndex); 674 return visible; 675 } 676 updateWallpaperWindowsPlacement(WindowList windows, WindowState wallpaperTarget, int wallpaperTargetIndex, boolean visible)677 boolean updateWallpaperWindowsPlacement(WindowList windows, 678 WindowState wallpaperTarget, int wallpaperTargetIndex, boolean visible) { 679 680 // TODO(multidisplay): Wallpapers on main screen only. 681 final DisplayInfo displayInfo = mService.getDefaultDisplayContentLocked().getDisplayInfo(); 682 final int dw = displayInfo.logicalWidth; 683 final int dh = displayInfo.logicalHeight; 684 685 // Start stepping backwards from here, ensuring that our wallpaper windows 686 // are correctly placed. 687 boolean changed = false; 688 for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) { 689 WindowToken token = mWallpaperTokens.get(curTokenNdx); 690 if (token.hidden == visible) { 691 if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, 692 "Wallpaper token " + token + " hidden=" + !visible); 693 token.hidden = !visible; 694 // Need to do a layout to ensure the wallpaper now has the correct size. 695 mService.getDefaultDisplayContentLocked().layoutNeeded = true; 696 } 697 698 final WindowList tokenWindows = token.windows; 699 for (int wallpaperNdx = tokenWindows.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) { 700 WindowState wallpaper = tokenWindows.get(wallpaperNdx); 701 702 if (visible) { 703 updateWallpaperOffset(wallpaper, dw, dh, false); 704 } 705 706 // First, make sure the client has the current visibility state. 707 dispatchWallpaperVisibility(wallpaper, visible); 708 709 wallpaper.mWinAnimator.mAnimLayer = 710 wallpaper.mLayer + mWallpaperAnimLayerAdjustment; 711 if (DEBUG_LAYERS || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "adjustWallpaper win " 712 + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer); 713 714 // First, if this window is at the current index, then all is well. 715 if (wallpaper == wallpaperTarget) { 716 wallpaperTargetIndex--; 717 wallpaperTarget = wallpaperTargetIndex > 0 718 ? windows.get(wallpaperTargetIndex - 1) : null; 719 continue; 720 } 721 722 // The window didn't match... the current wallpaper window, 723 // wherever it is, is in the wrong place, so make sure it is not in the list. 724 int oldIndex = windows.indexOf(wallpaper); 725 if (oldIndex >= 0) { 726 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, 727 "Wallpaper removing at " + oldIndex + ": " + wallpaper); 728 windows.remove(oldIndex); 729 mService.mWindowsChanged = true; 730 if (oldIndex < wallpaperTargetIndex) { 731 wallpaperTargetIndex--; 732 } 733 } 734 735 // Now stick it in. For apps over wallpaper keep the wallpaper at the bottommost 736 // layer. For keyguard over wallpaper put the wallpaper under the keyguard. 737 int insertionIndex = 0; 738 if (visible && wallpaperTarget != null) { 739 final int type = wallpaperTarget.mAttrs.type; 740 final int privateFlags = wallpaperTarget.mAttrs.privateFlags; 741 if ((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 742 || type == TYPE_KEYGUARD_SCRIM) { 743 insertionIndex = windows.indexOf(wallpaperTarget); 744 } 745 } 746 if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT 747 || (DEBUG_ADD_REMOVE && oldIndex != insertionIndex)) Slog.v(TAG, 748 "Moving wallpaper " + wallpaper 749 + " from " + oldIndex + " to " + insertionIndex); 750 751 windows.add(insertionIndex, wallpaper); 752 mService.mWindowsChanged = true; 753 changed = true; 754 } 755 } 756 757 return changed; 758 } 759 adjustWallpaperWindows()760 boolean adjustWallpaperWindows() { 761 mService.mWindowPlacerLocked.mWallpaperMayChange = false; 762 763 final WindowList windows = mService.getDefaultWindowListLocked(); 764 // First find top-most window that has asked to be on top of the wallpaper; 765 // all wallpapers go behind it. 766 findWallpaperTarget(windows, mFindResults); 767 final boolean targetChanged = updateWallpaperWindowsTarget(windows, mFindResults); 768 final boolean visible = updateWallpaperWindowsTargetByLayer(windows, mFindResults); 769 WindowState wallpaperTarget = mFindResults.wallpaperTarget; 770 int wallpaperTargetIndex = mFindResults.wallpaperTargetIndex; 771 772 if (wallpaperTarget == null && mFindResults.topWallpaper != null) { 773 // There is no wallpaper target, so it goes at the bottom. 774 // We will assume it is the same place as last time, if known. 775 wallpaperTarget = mFindResults.topWallpaper; 776 wallpaperTargetIndex = mFindResults.topWallpaperIndex + 1; 777 } else { 778 // Okay i is the position immediately above the wallpaper. 779 // Look at what is below it for later. 780 wallpaperTarget = wallpaperTargetIndex > 0 781 ? windows.get(wallpaperTargetIndex - 1) : null; 782 } 783 784 if (visible) { 785 if (mWallpaperTarget.mWallpaperX >= 0) { 786 mLastWallpaperX = mWallpaperTarget.mWallpaperX; 787 mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep; 788 } 789 if (mWallpaperTarget.mWallpaperY >= 0) { 790 mLastWallpaperY = mWallpaperTarget.mWallpaperY; 791 mLastWallpaperYStep = mWallpaperTarget.mWallpaperYStep; 792 } 793 if (mWallpaperTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) { 794 mLastWallpaperDisplayOffsetX = mWallpaperTarget.mWallpaperDisplayOffsetX; 795 } 796 if (mWallpaperTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) { 797 mLastWallpaperDisplayOffsetY = mWallpaperTarget.mWallpaperDisplayOffsetY; 798 } 799 } 800 801 final boolean changed = updateWallpaperWindowsPlacement( 802 windows, wallpaperTarget, wallpaperTargetIndex, visible); 803 804 if (targetChanged && DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, "New wallpaper: target=" 805 + mWallpaperTarget + " lower=" + mLowerWallpaperTarget + " upper=" 806 + mUpperWallpaperTarget); 807 808 return changed; 809 } 810 processWallpaperDrawPendingTimeout()811 boolean processWallpaperDrawPendingTimeout() { 812 if (mWallpaperDrawState == WALLPAPER_DRAW_PENDING) { 813 mWallpaperDrawState = WALLPAPER_DRAW_TIMEOUT; 814 if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG, 815 "*** WALLPAPER DRAW TIMEOUT"); 816 return true; 817 } 818 return false; 819 } 820 wallpaperTransitionReady()821 boolean wallpaperTransitionReady() { 822 boolean transitionReady = true; 823 boolean wallpaperReady = true; 824 for (int curTokenIndex = mWallpaperTokens.size() - 1; 825 curTokenIndex >= 0 && wallpaperReady; curTokenIndex--) { 826 WindowToken token = mWallpaperTokens.get(curTokenIndex); 827 for (int curWallpaperIndex = token.windows.size() - 1; curWallpaperIndex >= 0; 828 curWallpaperIndex--) { 829 WindowState wallpaper = token.windows.get(curWallpaperIndex); 830 if (wallpaper.mWallpaperVisible && !wallpaper.isDrawnLw()) { 831 // We've told this wallpaper to be visible, but it is not drawn yet 832 wallpaperReady = false; 833 if (mWallpaperDrawState != WALLPAPER_DRAW_TIMEOUT) { 834 // wait for this wallpaper until it is drawn or timeout 835 transitionReady = false; 836 } 837 if (mWallpaperDrawState == WALLPAPER_DRAW_NORMAL) { 838 mWallpaperDrawState = WALLPAPER_DRAW_PENDING; 839 mService.mH.removeMessages(WALLPAPER_DRAW_PENDING_TIMEOUT); 840 mService.mH.sendEmptyMessageDelayed(WALLPAPER_DRAW_PENDING_TIMEOUT, 841 WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION); 842 } 843 if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG, 844 "Wallpaper should be visible but has not been drawn yet. " + 845 "mWallpaperDrawState=" + mWallpaperDrawState); 846 break; 847 } 848 } 849 } 850 if (wallpaperReady) { 851 mWallpaperDrawState = WALLPAPER_DRAW_NORMAL; 852 mService.mH.removeMessages(WALLPAPER_DRAW_PENDING_TIMEOUT); 853 } 854 855 return transitionReady; 856 } 857 addWallpaperToken(WindowToken token)858 void addWallpaperToken(WindowToken token) { 859 mWallpaperTokens.add(token); 860 } 861 removeWallpaperToken(WindowToken token)862 void removeWallpaperToken(WindowToken token) { 863 mWallpaperTokens.remove(token); 864 } 865 dump(PrintWriter pw, String prefix)866 void dump(PrintWriter pw, String prefix) { 867 pw.print(prefix); pw.print("mWallpaperTarget="); pw.println(mWallpaperTarget); 868 if (mLowerWallpaperTarget != null || mUpperWallpaperTarget != null) { 869 pw.print(prefix); pw.print("mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget); 870 pw.print(prefix); pw.print("mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget); 871 } 872 pw.print(prefix); pw.print("mLastWallpaperX="); pw.print(mLastWallpaperX); 873 pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY); 874 if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE 875 || mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) { 876 pw.print(prefix); 877 pw.print("mLastWallpaperDisplayOffsetX="); pw.print(mLastWallpaperDisplayOffsetX); 878 pw.print(" mLastWallpaperDisplayOffsetY="); pw.println(mLastWallpaperDisplayOffsetY); 879 } 880 } 881 dumpTokens(PrintWriter pw, String prefix, boolean dumpAll)882 void dumpTokens(PrintWriter pw, String prefix, boolean dumpAll) { 883 if (!mWallpaperTokens.isEmpty()) { 884 pw.println(); 885 pw.print(prefix); pw.println("Wallpaper tokens:"); 886 for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) { 887 WindowToken token = mWallpaperTokens.get(i); 888 pw.print(prefix); pw.print("Wallpaper #"); pw.print(i); 889 pw.print(' '); pw.print(token); 890 if (dumpAll) { 891 pw.println(':'); 892 token.dump(pw, " "); 893 } else { 894 pw.println(); 895 } 896 } 897 } 898 } 899 900 /** Helper class for storing the results of a wallpaper target find operation. */ 901 final private static class FindWallpaperTargetResult { 902 int topWallpaperIndex = 0; 903 WindowState topWallpaper = null; 904 int wallpaperTargetIndex = 0; 905 WindowState wallpaperTarget = null; 906 setTopWallpaper(WindowState win, int index)907 void setTopWallpaper(WindowState win, int index) { 908 topWallpaper = win; 909 topWallpaperIndex = index; 910 } 911 setWallpaperTarget(WindowState win, int index)912 void setWallpaperTarget(WindowState win, int index) { 913 wallpaperTarget = win; 914 wallpaperTargetIndex = index; 915 } 916 reset()917 void reset() { 918 topWallpaperIndex = 0; 919 topWallpaper = null; 920 wallpaperTargetIndex = 0; 921 wallpaperTarget = null; 922 } 923 } 924 } 925