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.WallpaperManager.COMMAND_FREEZE; 20 import static android.app.WallpaperManager.COMMAND_UNFREEZE; 21 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 22 import static android.view.Display.DEFAULT_DISPLAY; 23 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; 24 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; 25 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; 26 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER; 27 28 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WALLPAPER; 29 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; 30 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; 31 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; 32 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT; 33 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER; 34 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 35 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 36 import static com.android.server.wm.WindowManagerService.H.WALLPAPER_DRAW_PENDING_TIMEOUT; 37 38 import android.annotation.Nullable; 39 import android.content.res.Resources; 40 import android.graphics.Bitmap; 41 import android.graphics.Point; 42 import android.graphics.Rect; 43 import android.os.Bundle; 44 import android.os.Debug; 45 import android.os.IBinder; 46 import android.os.RemoteException; 47 import android.os.SystemClock; 48 import android.os.SystemProperties; 49 import android.util.ArraySet; 50 import android.util.MathUtils; 51 import android.util.Slog; 52 import android.view.Display; 53 import android.view.DisplayInfo; 54 import android.view.SurfaceControl; 55 import android.view.WindowManager; 56 import android.view.animation.Animation; 57 import android.window.ScreenCapture; 58 59 import com.android.internal.annotations.VisibleForTesting; 60 import com.android.internal.protolog.ProtoLogImpl; 61 import com.android.internal.protolog.common.ProtoLog; 62 import com.android.internal.util.ToBooleanFunction; 63 64 import java.io.PrintWriter; 65 import java.util.ArrayList; 66 import java.util.List; 67 import java.util.function.Consumer; 68 69 /** 70 * Controls wallpaper windows visibility, ordering, and so on. 71 * NOTE: All methods in this class must be called with the window manager service lock held. 72 */ 73 class WallpaperController { 74 private static final String TAG = TAG_WITH_CLASS_NAME ? "WallpaperController" : TAG_WM; 75 private WindowManagerService mService; 76 private DisplayContent mDisplayContent; 77 78 private final ArrayList<WallpaperWindowToken> mWallpaperTokens = new ArrayList<>(); 79 80 // If non-null, this is the currently visible window that is associated 81 // with the wallpaper. 82 private WindowState mWallpaperTarget = null; 83 // If non-null, we are in the middle of animating from one wallpaper target 84 // to another, and this is the previous wallpaper target. 85 private WindowState mPrevWallpaperTarget = null; 86 87 private float mLastWallpaperX = -1; 88 private float mLastWallpaperY = -1; 89 private float mLastWallpaperXStep = -1; 90 private float mLastWallpaperYStep = -1; 91 private float mLastWallpaperZoomOut = 0; 92 private int mLastWallpaperDisplayOffsetX = Integer.MIN_VALUE; 93 private int mLastWallpaperDisplayOffsetY = Integer.MIN_VALUE; 94 private final float mMaxWallpaperScale; 95 // Whether COMMAND_FREEZE was dispatched. 96 private boolean mLastFrozen = false; 97 98 // This is set when we are waiting for a wallpaper to tell us it is done 99 // changing its scroll position. 100 private WindowState mWaitingOnWallpaper; 101 102 // The last time we had a timeout when waiting for a wallpaper. 103 private long mLastWallpaperTimeoutTime; 104 // We give a wallpaper up to 150ms to finish scrolling. 105 private static final long WALLPAPER_TIMEOUT = 150; 106 // Time we wait after a timeout before trying to wait again. 107 private static final long WALLPAPER_TIMEOUT_RECOVERY = 10000; 108 109 // We give a wallpaper up to 500ms to finish drawing before playing app transitions. 110 private static final long WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION = 500; 111 private static final int WALLPAPER_DRAW_NORMAL = 0; 112 private static final int WALLPAPER_DRAW_PENDING = 1; 113 private static final int WALLPAPER_DRAW_TIMEOUT = 2; 114 private int mWallpaperDrawState = WALLPAPER_DRAW_NORMAL; 115 116 private boolean mShouldUpdateZoom; 117 118 @Nullable private Point mLargestDisplaySize = null; 119 120 private final FindWallpaperTargetResult mFindResults = new FindWallpaperTargetResult(); 121 122 private boolean mShouldOffsetWallpaperCenter; 123 124 final boolean mIsLockscreenLiveWallpaperEnabled; 125 126 private final Consumer<WindowState> mFindWallpapers = w -> { 127 if (w.mAttrs.type == TYPE_WALLPAPER) { 128 WallpaperWindowToken token = w.mToken.asWallpaperToken(); 129 if (token.canShowWhenLocked() && !mFindResults.hasTopShowWhenLockedWallpaper()) { 130 mFindResults.setTopShowWhenLockedWallpaper(w); 131 } else if (!token.canShowWhenLocked() 132 && !mFindResults.hasTopHideWhenLockedWallpaper()) { 133 mFindResults.setTopHideWhenLockedWallpaper(w); 134 } 135 } 136 }; 137 138 private final ToBooleanFunction<WindowState> mFindWallpaperTargetFunction = w -> { 139 final boolean useShellTransition = w.mTransitionController.isShellTransitionsEnabled(); 140 if (!useShellTransition) { 141 if (w.mActivityRecord != null && !w.mActivityRecord.isVisible() 142 && !w.mActivityRecord.isAnimating(TRANSITION | PARENTS)) { 143 // If this window's app token is hidden and not animating, it is of no interest. 144 if (DEBUG_WALLPAPER) Slog.v(TAG, "Skipping hidden and not animating token: " + w); 145 return false; 146 } 147 } else { 148 final ActivityRecord ar = w.mActivityRecord; 149 // The animating window can still be visible on screen if it is in transition, so we 150 // should check whether this window can be wallpaper target even when visibleRequested 151 // is false. 152 if (ar != null && !ar.isVisibleRequested() && !ar.isVisible()) { 153 // An activity that is not going to remain visible shouldn't be the target. 154 return false; 155 } 156 } 157 if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w + ": isOnScreen=" + w.isOnScreen() 158 + " mDrawState=" + w.mWinAnimator.mDrawState); 159 160 final WindowContainer animatingContainer = w.mActivityRecord != null 161 ? w.mActivityRecord.getAnimatingContainer() : null; 162 if (!useShellTransition && animatingContainer != null 163 && animatingContainer.isAnimating(TRANSITION | PARENTS) 164 && AppTransition.isKeyguardGoingAwayTransitOld(animatingContainer.mTransit) 165 && (animatingContainer.mTransitFlags 166 & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0) { 167 // Keep the wallpaper visible when Keyguard is going away. 168 mFindResults.setUseTopWallpaperAsTarget(true); 169 } 170 171 if (mService.mPolicy.isKeyguardLocked() && w.canShowWhenLocked()) { 172 if (mService.mPolicy.isKeyguardOccluded() || (useShellTransition 173 ? w.inTransition() : mService.mPolicy.isKeyguardUnoccluding())) { 174 // The lowest show when locked window decides whether we need to put the wallpaper 175 // behind. 176 mFindResults.mNeedsShowWhenLockedWallpaper = !isFullscreen(w.mAttrs) 177 || (w.mActivityRecord != null && !w.mActivityRecord.fillsParent()); 178 } 179 } 180 181 final boolean animationWallpaper = animatingContainer != null 182 && animatingContainer.getAnimation() != null 183 && animatingContainer.getAnimation().getShowWallpaper(); 184 final boolean hasWallpaper = w.hasWallpaper() || animationWallpaper; 185 if (isRecentsTransitionTarget(w) || isBackNavigationTarget(w)) { 186 if (DEBUG_WALLPAPER) Slog.v(TAG, "Found recents animation wallpaper target: " + w); 187 mFindResults.setWallpaperTarget(w); 188 return true; 189 } else if (hasWallpaper && w.isOnScreen() 190 && (mWallpaperTarget == w || w.isDrawFinishedLw())) { 191 if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: " + w); 192 mFindResults.setWallpaperTarget(w); 193 if (w == mWallpaperTarget && w.isAnimating(TRANSITION | PARENTS)) { 194 // The current wallpaper target is animating, so we'll look behind it for 195 // another possible target and figure out what is going on later. 196 if (DEBUG_WALLPAPER) Slog.v(TAG, 197 "Win " + w + ": token animating, looking behind."); 198 } 199 mFindResults.setIsWallpaperTargetForLetterbox(w.hasWallpaperForLetterboxBackground()); 200 // While the keyguard is going away, both notification shade and a normal activity such 201 // as a launcher can satisfy criteria for a wallpaper target. In this case, we should 202 // chose the normal activity, otherwise wallpaper becomes invisible when a new animation 203 // starts before the keyguard going away animation finishes. 204 return w.mActivityRecord != null; 205 } 206 return false; 207 }; 208 isRecentsTransitionTarget(WindowState w)209 private boolean isRecentsTransitionTarget(WindowState w) { 210 if (w.mTransitionController.isShellTransitionsEnabled()) { 211 // Because the recents activity is invisible in background while keyguard is occluded 212 // (the activity window is on screen while keyguard is locked) with recents animation, 213 // the task animating by recents needs to be wallpaper target to make wallpaper visible. 214 // While for unlocked case, because recents activity will be moved to top, it can be 215 // the wallpaper target naturally. 216 return w.mActivityRecord != null && w.mAttrs.type == TYPE_BASE_APPLICATION 217 && mDisplayContent.isKeyguardLocked() 218 && w.mTransitionController.isTransientHide(w.getTask()); 219 } 220 // The window is either the recents activity or is in the task animating by the recents. 221 final RecentsAnimationController controller = mService.getRecentsAnimationController(); 222 return controller != null && controller.isWallpaperVisible(w); 223 } 224 isBackNavigationTarget(WindowState w)225 private boolean isBackNavigationTarget(WindowState w) { 226 // The window is in animating by back navigation and set to show wallpaper. 227 return mService.mAtmService.mBackNavigationController.isWallpaperVisible(w); 228 } 229 230 /** 231 * @see #computeLastWallpaperZoomOut() 232 */ 233 private Consumer<WindowState> mComputeMaxZoomOutFunction = windowState -> { 234 if (!windowState.mIsWallpaper 235 && Float.compare(windowState.mWallpaperZoomOut, mLastWallpaperZoomOut) > 0) { 236 mLastWallpaperZoomOut = windowState.mWallpaperZoomOut; 237 } 238 }; 239 WallpaperController(WindowManagerService service, DisplayContent displayContent)240 WallpaperController(WindowManagerService service, DisplayContent displayContent) { 241 mService = service; 242 mDisplayContent = displayContent; 243 Resources resources = service.mContext.getResources(); 244 mMaxWallpaperScale = 245 resources.getFloat(com.android.internal.R.dimen.config_wallpaperMaxScale); 246 mShouldOffsetWallpaperCenter = 247 resources.getBoolean( 248 com.android.internal.R.bool.config_offsetWallpaperToCenterOfLargestDisplay); 249 mIsLockscreenLiveWallpaperEnabled = 250 SystemProperties.getBoolean("persist.wm.debug.lockscreen_live_wallpaper", true); 251 } 252 resetLargestDisplay(Display display)253 void resetLargestDisplay(Display display) { 254 if (display != null && display.getType() == Display.TYPE_INTERNAL) { 255 mLargestDisplaySize = null; 256 } 257 } 258 setShouldOffsetWallpaperCenter(boolean shouldOffset)259 @VisibleForTesting void setShouldOffsetWallpaperCenter(boolean shouldOffset) { 260 mShouldOffsetWallpaperCenter = shouldOffset; 261 } 262 findLargestDisplaySize()263 @Nullable private Point findLargestDisplaySize() { 264 if (!mShouldOffsetWallpaperCenter) { 265 return null; 266 } 267 Point largestDisplaySize = new Point(); 268 List<DisplayInfo> possibleDisplayInfo = 269 mService.getPossibleDisplayInfoLocked(DEFAULT_DISPLAY); 270 for (int i = 0; i < possibleDisplayInfo.size(); i++) { 271 DisplayInfo displayInfo = possibleDisplayInfo.get(i); 272 if (displayInfo.type == Display.TYPE_INTERNAL 273 && Math.max(displayInfo.logicalWidth, displayInfo.logicalHeight) 274 > Math.max(largestDisplaySize.x, largestDisplaySize.y)) { 275 largestDisplaySize.set(displayInfo.logicalWidth, 276 displayInfo.logicalHeight); 277 } 278 } 279 return largestDisplaySize; 280 } 281 getWallpaperTarget()282 WindowState getWallpaperTarget() { 283 return mWallpaperTarget; 284 } 285 isWallpaperTarget(WindowState win)286 boolean isWallpaperTarget(WindowState win) { 287 return win == mWallpaperTarget; 288 } 289 isBelowWallpaperTarget(WindowState win)290 boolean isBelowWallpaperTarget(WindowState win) { 291 return mWallpaperTarget != null && mWallpaperTarget.mLayer >= win.mBaseLayer; 292 } 293 isWallpaperVisible()294 boolean isWallpaperVisible() { 295 for (int i = mWallpaperTokens.size() - 1; i >= 0; --i) { 296 if (mWallpaperTokens.get(i).isVisible()) return true; 297 } 298 return false; 299 } 300 301 /** 302 * Starts {@param a} on all wallpaper windows. 303 */ startWallpaperAnimation(Animation a)304 void startWallpaperAnimation(Animation a) { 305 for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) { 306 final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx); 307 token.startAnimation(a); 308 } 309 } 310 isWallpaperTargetAnimating()311 boolean isWallpaperTargetAnimating() { 312 return mWallpaperTarget != null && mWallpaperTarget.isAnimating(TRANSITION | PARENTS) 313 && (mWallpaperTarget.mActivityRecord == null 314 || !mWallpaperTarget.mActivityRecord.isWaitingForTransitionStart()); 315 } 316 hideDeferredWallpapersIfNeededLegacy()317 void hideDeferredWallpapersIfNeededLegacy() { 318 for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) { 319 final WallpaperWindowToken token = mWallpaperTokens.get(i); 320 if (!token.isVisibleRequested()) { 321 token.commitVisibility(false); 322 } 323 } 324 } 325 hideWallpapers(final WindowState winGoingAway)326 void hideWallpapers(final WindowState winGoingAway) { 327 if (mWallpaperTarget != null 328 && (mWallpaperTarget != winGoingAway || mPrevWallpaperTarget != null)) { 329 return; 330 } 331 if (mFindResults.useTopWallpaperAsTarget) { 332 // wallpaper target is going away but there has request to use top wallpaper 333 // Keep wallpaper visible. 334 return; 335 } 336 for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) { 337 final WallpaperWindowToken token = mWallpaperTokens.get(i); 338 token.setVisibility(false); 339 if (ProtoLogImpl.isEnabled(WM_DEBUG_WALLPAPER) && token.isVisible()) { 340 ProtoLog.d(WM_DEBUG_WALLPAPER, 341 "Hiding wallpaper %s from %s target=%s prev=%s callers=%s", 342 token, winGoingAway, mWallpaperTarget, mPrevWallpaperTarget, 343 Debug.getCallers(5)); 344 } 345 } 346 } 347 updateWallpaperOffset(WindowState wallpaperWin, boolean sync)348 boolean updateWallpaperOffset(WindowState wallpaperWin, boolean sync) { 349 // Size of the display the wallpaper is rendered on. 350 final Rect lastWallpaperBounds = wallpaperWin.getParentFrame(); 351 // Full size of the wallpaper (usually larger than bounds above to parallax scroll when 352 // swiping through Launcher pages). 353 final Rect wallpaperFrame = wallpaperWin.getFrame(); 354 355 final int diffWidth = wallpaperFrame.width() - lastWallpaperBounds.width(); 356 final int diffHeight = wallpaperFrame.height() - lastWallpaperBounds.height(); 357 if ((wallpaperWin.mAttrs.flags & WindowManager.LayoutParams.FLAG_SCALED) != 0 358 && Math.abs(diffWidth) > 1 && Math.abs(diffHeight) > 1) { 359 Slog.d(TAG, "Skip wallpaper offset with inconsistent orientation, bounds=" 360 + lastWallpaperBounds + " frame=" + wallpaperFrame); 361 // With FLAG_SCALED, the requested size should at least make the frame match one of 362 // side. If both sides contain differences, the client side may not have updated the 363 // latest size according to the current orientation. So skip calculating the offset to 364 // avoid the wallpaper not filling the screen. 365 return false; 366 } 367 368 int newXOffset = 0; 369 int newYOffset = 0; 370 boolean rawChanged = false; 371 // Set the default wallpaper x-offset to either edge of the screen (depending on RTL), to 372 // match the behavior of most Launchers 373 float defaultWallpaperX = wallpaperWin.isRtl() ? 1f : 0f; 374 // "Wallpaper X" is the previous x-offset of the wallpaper (in a 0 to 1 scale). 375 // The 0 to 1 scale is because the "length" varies depending on how many home screens you 376 // have, so 0 is the left of the first home screen, and 1 is the right of the last one (for 377 // LTR, and the opposite for RTL). 378 float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : defaultWallpaperX; 379 // "Wallpaper X step size" is how much of that 0-1 is one "page" of the home screen 380 // when scrolling. 381 float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f; 382 // Difference between width of wallpaper image, and the last size of the wallpaper. 383 // This is the horizontal surplus from the prior configuration. 384 int availw = diffWidth; 385 386 int displayOffset = getDisplayWidthOffset(availw, lastWallpaperBounds, 387 wallpaperWin.isRtl()); 388 availw -= displayOffset; 389 int offset = availw > 0 ? -(int)(availw * wpx + .5f) : 0; 390 if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) { 391 // if device is LTR, then offset wallpaper to the left (the wallpaper is drawn 392 // always starting from the left of the screen). 393 offset += mLastWallpaperDisplayOffsetX; 394 } else if (!wallpaperWin.isRtl()) { 395 // In RTL the offset is calculated so that the wallpaper ends up right aligned (see 396 // offset above). 397 offset -= displayOffset; 398 } 399 newXOffset = offset; 400 401 if (wallpaperWin.mWallpaperX != wpx || wallpaperWin.mWallpaperXStep != wpxs) { 402 wallpaperWin.mWallpaperX = wpx; 403 wallpaperWin.mWallpaperXStep = wpxs; 404 rawChanged = true; 405 } 406 407 float wpy = mLastWallpaperY >= 0 ? mLastWallpaperY : 0.5f; 408 float wpys = mLastWallpaperYStep >= 0 ? mLastWallpaperYStep : -1.0f; 409 offset = diffHeight > 0 ? -(int) (diffHeight * wpy + .5f) : 0; 410 if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) { 411 offset += mLastWallpaperDisplayOffsetY; 412 } 413 newYOffset = offset; 414 415 if (wallpaperWin.mWallpaperY != wpy || wallpaperWin.mWallpaperYStep != wpys) { 416 wallpaperWin.mWallpaperY = wpy; 417 wallpaperWin.mWallpaperYStep = wpys; 418 rawChanged = true; 419 } 420 421 if (Float.compare(wallpaperWin.mWallpaperZoomOut, mLastWallpaperZoomOut) != 0) { 422 wallpaperWin.mWallpaperZoomOut = mLastWallpaperZoomOut; 423 rawChanged = true; 424 } 425 426 boolean changed = wallpaperWin.setWallpaperOffset(newXOffset, newYOffset, 427 wallpaperWin.mShouldScaleWallpaper 428 ? zoomOutToScale(wallpaperWin.mWallpaperZoomOut) : 1); 429 430 if (rawChanged && (wallpaperWin.mAttrs.privateFlags & 431 WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) != 0) { 432 try { 433 if (DEBUG_WALLPAPER) Slog.v(TAG, "Report new wp offset " 434 + wallpaperWin + " x=" + wallpaperWin.mWallpaperX 435 + " y=" + wallpaperWin.mWallpaperY 436 + " zoom=" + wallpaperWin.mWallpaperZoomOut); 437 if (sync) { 438 mWaitingOnWallpaper = wallpaperWin; 439 } 440 wallpaperWin.mClient.dispatchWallpaperOffsets( 441 wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY, 442 wallpaperWin.mWallpaperXStep, wallpaperWin.mWallpaperYStep, 443 wallpaperWin.mWallpaperZoomOut, sync); 444 445 if (sync) { 446 if (mWaitingOnWallpaper != null) { 447 long start = SystemClock.uptimeMillis(); 448 if ((mLastWallpaperTimeoutTime + WALLPAPER_TIMEOUT_RECOVERY) 449 < start) { 450 try { 451 if (DEBUG_WALLPAPER) Slog.v(TAG, 452 "Waiting for offset complete..."); 453 mService.mGlobalLock.wait(WALLPAPER_TIMEOUT); 454 } catch (InterruptedException e) { 455 } 456 if (DEBUG_WALLPAPER) Slog.v(TAG, "Offset complete!"); 457 if ((start + WALLPAPER_TIMEOUT) < SystemClock.uptimeMillis()) { 458 Slog.i(TAG, "Timeout waiting for wallpaper to offset: " 459 + wallpaperWin); 460 mLastWallpaperTimeoutTime = start; 461 } 462 } 463 mWaitingOnWallpaper = null; 464 } 465 } 466 } catch (RemoteException e) { 467 } 468 } 469 470 return changed; 471 } 472 473 /** 474 * Get an extra offset if needed ({@link #mShouldOffsetWallpaperCenter} = true, typically on 475 * multiple display devices) so that the wallpaper in a smaller display ends up centered at the 476 * same position as in the largest display of the device. 477 * 478 * Note that the wallpaper has already been cropped when set by the user, so these calculations 479 * apply to the image size for the display the wallpaper was set for. 480 * 481 * @param availWidth width available for the wallpaper offset in the current display 482 * @param displayFrame size of the "display" (parent frame) 483 * @param isRtl whether we're in an RTL configuration 484 * @return an offset to apply to the width, or 0 if the current configuration doesn't require 485 * any adjustment (either @link #mShouldOffsetWallpaperCenter} is false or we're on the largest 486 * display). 487 */ getDisplayWidthOffset(int availWidth, Rect displayFrame, boolean isRtl)488 private int getDisplayWidthOffset(int availWidth, Rect displayFrame, boolean isRtl) { 489 if (!mShouldOffsetWallpaperCenter) { 490 return 0; 491 } 492 if (mLargestDisplaySize == null) { 493 mLargestDisplaySize = findLargestDisplaySize(); 494 } 495 if (mLargestDisplaySize == null) { 496 return 0; 497 } 498 // Page width is the width of a Launcher "page", for pagination when swiping right. 499 int pageWidth = displayFrame.width(); 500 // Only need offset if the current size is different from the largest display, and we're 501 // in a portrait configuration 502 if (mLargestDisplaySize.x != pageWidth && displayFrame.width() < displayFrame.height()) { 503 // The wallpaper will be scaled to fit the height of the wallpaper, so if the height 504 // of the displays are different, we need to account for that scaling when calculating 505 // the offset to the center 506 float sizeRatio = (float) displayFrame.height() / mLargestDisplaySize.y; 507 // Scale the width of the largest display to match the scale of the wallpaper size in 508 // the current display 509 int adjustedLargestWidth = Math.round(mLargestDisplaySize.x * sizeRatio); 510 // Finally, find the difference between the centers, taking into account that the 511 // size of the wallpaper frame could be smaller than the screen 512 return isRtl 513 ? adjustedLargestWidth - (adjustedLargestWidth + pageWidth) / 2 514 : Math.min(adjustedLargestWidth - pageWidth, availWidth) / 2; 515 } 516 return 0; 517 } 518 setWindowWallpaperPosition( WindowState window, float x, float y, float xStep, float yStep)519 void setWindowWallpaperPosition( 520 WindowState window, float x, float y, float xStep, float yStep) { 521 if (window.mWallpaperX != x || window.mWallpaperY != y) { 522 window.mWallpaperX = x; 523 window.mWallpaperY = y; 524 window.mWallpaperXStep = xStep; 525 window.mWallpaperYStep = yStep; 526 updateWallpaperOffsetLocked(window, true); 527 } 528 } 529 setWallpaperZoomOut(WindowState window, float zoom)530 void setWallpaperZoomOut(WindowState window, float zoom) { 531 if (Float.compare(window.mWallpaperZoomOut, zoom) != 0) { 532 window.mWallpaperZoomOut = zoom; 533 mShouldUpdateZoom = true; 534 updateWallpaperOffsetLocked(window, false); 535 } 536 } 537 setShouldZoomOutWallpaper(WindowState window, boolean shouldZoom)538 void setShouldZoomOutWallpaper(WindowState window, boolean shouldZoom) { 539 if (shouldZoom != window.mShouldScaleWallpaper) { 540 window.mShouldScaleWallpaper = shouldZoom; 541 updateWallpaperOffsetLocked(window, false); 542 } 543 } 544 setWindowWallpaperDisplayOffset(WindowState window, int x, int y)545 void setWindowWallpaperDisplayOffset(WindowState window, int x, int y) { 546 if (window.mWallpaperDisplayOffsetX != x || window.mWallpaperDisplayOffsetY != y) { 547 window.mWallpaperDisplayOffsetX = x; 548 window.mWallpaperDisplayOffsetY = y; 549 updateWallpaperOffsetLocked(window, true); 550 } 551 } 552 sendWindowWallpaperCommand( WindowState window, String action, int x, int y, int z, Bundle extras, boolean sync)553 Bundle sendWindowWallpaperCommand( 554 WindowState window, String action, int x, int y, int z, Bundle extras, boolean sync) { 555 if (window == mWallpaperTarget || window == mPrevWallpaperTarget) { 556 sendWindowWallpaperCommand(action, x, y, z, extras, sync); 557 } 558 559 return null; 560 } 561 sendWindowWallpaperCommand( String action, int x, int y, int z, Bundle extras, boolean sync)562 private void sendWindowWallpaperCommand( 563 String action, int x, int y, int z, Bundle extras, boolean sync) { 564 boolean doWait = sync; 565 for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) { 566 final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx); 567 token.sendWindowWallpaperCommand(action, x, y, z, extras, sync); 568 } 569 570 if (doWait) { 571 // TODO: Need to wait for result. 572 } 573 } 574 updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync)575 private void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) { 576 WindowState target = mWallpaperTarget; 577 if (target == null && changingTarget.mToken.isVisible() 578 && changingTarget.mTransitionController.inTransition()) { 579 // If the wallpaper target was cleared during transition, still allows the visible 580 // window which may have been requested to be invisible to update the offset, e.g. 581 // zoom effect from home. 582 target = changingTarget; 583 } 584 if (target != null) { 585 if (target.mWallpaperX >= 0) { 586 mLastWallpaperX = target.mWallpaperX; 587 } else if (changingTarget.mWallpaperX >= 0) { 588 mLastWallpaperX = changingTarget.mWallpaperX; 589 } 590 if (target.mWallpaperY >= 0) { 591 mLastWallpaperY = target.mWallpaperY; 592 } else if (changingTarget.mWallpaperY >= 0) { 593 mLastWallpaperY = changingTarget.mWallpaperY; 594 } 595 computeLastWallpaperZoomOut(); 596 if (target.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) { 597 mLastWallpaperDisplayOffsetX = target.mWallpaperDisplayOffsetX; 598 } else if (changingTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) { 599 mLastWallpaperDisplayOffsetX = changingTarget.mWallpaperDisplayOffsetX; 600 } 601 if (target.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) { 602 mLastWallpaperDisplayOffsetY = target.mWallpaperDisplayOffsetY; 603 } else if (changingTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) { 604 mLastWallpaperDisplayOffsetY = changingTarget.mWallpaperDisplayOffsetY; 605 } 606 if (target.mWallpaperXStep >= 0) { 607 mLastWallpaperXStep = target.mWallpaperXStep; 608 } else if (changingTarget.mWallpaperXStep >= 0) { 609 mLastWallpaperXStep = changingTarget.mWallpaperXStep; 610 } 611 if (target.mWallpaperYStep >= 0) { 612 mLastWallpaperYStep = target.mWallpaperYStep; 613 } else if (changingTarget.mWallpaperYStep >= 0) { 614 mLastWallpaperYStep = changingTarget.mWallpaperYStep; 615 } 616 } 617 618 for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) { 619 mWallpaperTokens.get(curTokenNdx).updateWallpaperOffset(sync); 620 } 621 } 622 clearLastWallpaperTimeoutTime()623 void clearLastWallpaperTimeoutTime() { 624 mLastWallpaperTimeoutTime = 0; 625 } 626 wallpaperCommandComplete(IBinder window)627 void wallpaperCommandComplete(IBinder window) { 628 if (mWaitingOnWallpaper != null && 629 mWaitingOnWallpaper.mClient.asBinder() == window) { 630 mWaitingOnWallpaper = null; 631 mService.mGlobalLock.notifyAll(); 632 } 633 } 634 wallpaperOffsetsComplete(IBinder window)635 void wallpaperOffsetsComplete(IBinder window) { 636 if (mWaitingOnWallpaper != null && 637 mWaitingOnWallpaper.mClient.asBinder() == window) { 638 mWaitingOnWallpaper = null; 639 mService.mGlobalLock.notifyAll(); 640 } 641 } 642 findWallpaperTarget()643 private void findWallpaperTarget() { 644 mFindResults.reset(); 645 if (mService.mAtmService.mSupportsFreeformWindowManagement 646 && mDisplayContent.getDefaultTaskDisplayArea() 647 .isRootTaskVisible(WINDOWING_MODE_FREEFORM)) { 648 // In freeform mode we set the wallpaper as its own target, so we don't need an 649 // additional window to make it visible. 650 mFindResults.setUseTopWallpaperAsTarget(true); 651 } 652 653 mDisplayContent.forAllWindows(mFindWallpapers, true /* traverseTopToBottom */); 654 mDisplayContent.forAllWindows(mFindWallpaperTargetFunction, true /* traverseTopToBottom */); 655 if (mFindResults.mNeedsShowWhenLockedWallpaper) { 656 // Keep wallpaper visible if the show-when-locked activities doesn't fill screen. 657 mFindResults.setUseTopWallpaperAsTarget(true); 658 } 659 660 if (mFindResults.wallpaperTarget == null && mFindResults.useTopWallpaperAsTarget) { 661 mFindResults.setWallpaperTarget( 662 mFindResults.getTopWallpaper(mDisplayContent.isKeyguardLocked())); 663 } 664 } 665 getAllTopWallpapers()666 List<WindowState> getAllTopWallpapers() { 667 ArrayList<WindowState> wallpapers = new ArrayList<>(2); 668 if (mFindResults.hasTopShowWhenLockedWallpaper()) { 669 wallpapers.add(mFindResults.mTopWallpaper.mTopShowWhenLockedWallpaper); 670 } 671 if (mFindResults.hasTopHideWhenLockedWallpaper()) { 672 wallpapers.add(mFindResults.mTopWallpaper.mTopHideWhenLockedWallpaper); 673 } 674 return wallpapers; 675 } 676 isFullscreen(WindowManager.LayoutParams attrs)677 private boolean isFullscreen(WindowManager.LayoutParams attrs) { 678 return attrs.x == 0 && attrs.y == 0 679 && attrs.width == MATCH_PARENT && attrs.height == MATCH_PARENT; 680 } 681 682 /** Updates the target wallpaper if needed and returns true if an update happened. */ updateWallpaperWindowsTarget(FindWallpaperTargetResult result)683 private void updateWallpaperWindowsTarget(FindWallpaperTargetResult result) { 684 685 WindowState wallpaperTarget = result.wallpaperTarget; 686 687 if (mWallpaperTarget == wallpaperTarget 688 || (mPrevWallpaperTarget != null && mPrevWallpaperTarget == wallpaperTarget)) { 689 690 if (mPrevWallpaperTarget == null) { 691 return; 692 } 693 694 // Is it time to stop animating? 695 if (!mPrevWallpaperTarget.isAnimatingLw()) { 696 ProtoLog.v(WM_DEBUG_WALLPAPER, "No longer animating wallpaper targets!"); 697 mPrevWallpaperTarget = null; 698 mWallpaperTarget = wallpaperTarget; 699 } 700 return; 701 } 702 703 ProtoLog.v(WM_DEBUG_WALLPAPER, "New wallpaper target: %s prevTarget: %s caller=%s", 704 wallpaperTarget, mWallpaperTarget, Debug.getCallers(5)); 705 706 mPrevWallpaperTarget = null; 707 708 final WindowState prevWallpaperTarget = mWallpaperTarget; 709 mWallpaperTarget = wallpaperTarget; 710 711 if (prevWallpaperTarget == null && wallpaperTarget != null) { 712 updateWallpaperOffsetLocked(mWallpaperTarget, false); 713 } 714 if (wallpaperTarget == null || prevWallpaperTarget == null) { 715 return; 716 } 717 718 // Now what is happening... if the current and new targets are animating, 719 // then we are in our super special mode! 720 boolean oldAnim = prevWallpaperTarget.isAnimatingLw(); 721 boolean foundAnim = wallpaperTarget.isAnimatingLw(); 722 ProtoLog.v(WM_DEBUG_WALLPAPER, "New animation: %s old animation: %s", 723 foundAnim, oldAnim); 724 725 if (!foundAnim || !oldAnim) { 726 return; 727 } 728 729 if (mDisplayContent.getWindow(w -> w == prevWallpaperTarget) == null) { 730 return; 731 } 732 733 final boolean newTargetHidden = wallpaperTarget.mActivityRecord != null 734 && !wallpaperTarget.mActivityRecord.isVisibleRequested(); 735 final boolean oldTargetHidden = prevWallpaperTarget.mActivityRecord != null 736 && !prevWallpaperTarget.mActivityRecord.isVisibleRequested(); 737 738 ProtoLog.v(WM_DEBUG_WALLPAPER, "Animating wallpapers: " 739 + "old: %s hidden=%b new: %s hidden=%b", 740 prevWallpaperTarget, oldTargetHidden, wallpaperTarget, newTargetHidden); 741 742 mPrevWallpaperTarget = prevWallpaperTarget; 743 744 if (newTargetHidden && !oldTargetHidden) { 745 ProtoLog.v(WM_DEBUG_WALLPAPER, "Old wallpaper still the target."); 746 // Use the old target if new target is hidden but old target 747 // is not. If they're both hidden, still use the new target. 748 mWallpaperTarget = prevWallpaperTarget; 749 } else if (newTargetHidden == oldTargetHidden 750 && !mDisplayContent.mOpeningApps.contains(wallpaperTarget.mActivityRecord) 751 && (mDisplayContent.mOpeningApps.contains(prevWallpaperTarget.mActivityRecord) 752 || mDisplayContent.mClosingApps.contains(prevWallpaperTarget.mActivityRecord))) { 753 // If they're both hidden (or both not hidden), prefer the one that's currently in 754 // opening or closing app list, this allows transition selection logic to better 755 // determine the wallpaper status of opening/closing apps. 756 mWallpaperTarget = prevWallpaperTarget; 757 } 758 759 result.setWallpaperTarget(wallpaperTarget); 760 } 761 updateWallpaperTokens(boolean keyguardLocked)762 public void updateWallpaperTokens(boolean keyguardLocked) { 763 if (DEBUG_WALLPAPER) { 764 Slog.v(TAG, "Wallpaper vis: target " + mWallpaperTarget + " prev=" 765 + mPrevWallpaperTarget); 766 } 767 updateWallpaperTokens(mWallpaperTarget != null || mPrevWallpaperTarget != null, 768 keyguardLocked); 769 } 770 771 /** 772 * Change the visibility of the top wallpaper to {@param visibility} and hide all the others. 773 */ updateWallpaperTokens(boolean visibility, boolean keyguardLocked)774 private void updateWallpaperTokens(boolean visibility, boolean keyguardLocked) { 775 WindowState topWallpaper = mFindResults.getTopWallpaper(keyguardLocked); 776 WallpaperWindowToken topWallpaperToken = 777 topWallpaper == null ? null : topWallpaper.mToken.asWallpaperToken(); 778 for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) { 779 final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx); 780 token.updateWallpaperWindows(visibility && (token == topWallpaperToken)); 781 } 782 } 783 adjustWallpaperWindows()784 void adjustWallpaperWindows() { 785 mDisplayContent.mWallpaperMayChange = false; 786 787 // First find top-most window that has asked to be on top of the wallpaper; 788 // all wallpapers go behind it. 789 findWallpaperTarget(); 790 updateWallpaperWindowsTarget(mFindResults); 791 792 // The window is visible to the compositor...but is it visible to the user? 793 // That is what the wallpaper cares about. 794 final boolean visible = mWallpaperTarget != null; 795 if (DEBUG_WALLPAPER) { 796 Slog.v(TAG, "Wallpaper visibility: " + visible + " at display " 797 + mDisplayContent.getDisplayId()); 798 } 799 800 if (visible) { 801 if (mWallpaperTarget.mWallpaperX >= 0) { 802 mLastWallpaperX = mWallpaperTarget.mWallpaperX; 803 mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep; 804 } 805 computeLastWallpaperZoomOut(); 806 if (mWallpaperTarget.mWallpaperY >= 0) { 807 mLastWallpaperY = mWallpaperTarget.mWallpaperY; 808 mLastWallpaperYStep = mWallpaperTarget.mWallpaperYStep; 809 } 810 if (mWallpaperTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) { 811 mLastWallpaperDisplayOffsetX = mWallpaperTarget.mWallpaperDisplayOffsetX; 812 } 813 if (mWallpaperTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) { 814 mLastWallpaperDisplayOffsetY = mWallpaperTarget.mWallpaperDisplayOffsetY; 815 } 816 } 817 818 updateWallpaperTokens(visible, mDisplayContent.isKeyguardLocked()); 819 820 if (DEBUG_WALLPAPER) { 821 Slog.v(TAG, "adjustWallpaperWindows: wallpaper visibility " + visible 822 + ", lock visibility " + mDisplayContent.isKeyguardLocked()); 823 } 824 825 if (visible && mLastFrozen != mFindResults.isWallpaperTargetForLetterbox) { 826 mLastFrozen = mFindResults.isWallpaperTargetForLetterbox; 827 sendWindowWallpaperCommand( 828 mFindResults.isWallpaperTargetForLetterbox ? COMMAND_FREEZE : COMMAND_UNFREEZE, 829 /* x= */ 0, /* y= */ 0, /* z= */ 0, /* extras= */ null, /* sync= */ false); 830 } 831 832 ProtoLog.d(WM_DEBUG_WALLPAPER, "New wallpaper: target=%s prev=%s", 833 mWallpaperTarget, mPrevWallpaperTarget); 834 } 835 processWallpaperDrawPendingTimeout()836 boolean processWallpaperDrawPendingTimeout() { 837 if (mWallpaperDrawState == WALLPAPER_DRAW_PENDING) { 838 mWallpaperDrawState = WALLPAPER_DRAW_TIMEOUT; 839 if (DEBUG_WALLPAPER) { 840 Slog.v(TAG, "*** WALLPAPER DRAW TIMEOUT"); 841 } 842 843 // If there was a pending recents animation, start the animation anyways (it's better 844 // to not see the wallpaper than for the animation to not start) 845 if (mService.getRecentsAnimationController() != null) { 846 mService.getRecentsAnimationController().startAnimation(); 847 } 848 849 // If there was a pending back navigation animation that would show wallpaper, start 850 // the animation due to it was skipped in previous surface placement. 851 mService.mAtmService.mBackNavigationController.startAnimation(); 852 return true; 853 } 854 return false; 855 } 856 wallpaperTransitionReady()857 boolean wallpaperTransitionReady() { 858 boolean transitionReady = true; 859 boolean wallpaperReady = true; 860 for (int curTokenIndex = mWallpaperTokens.size() - 1; 861 curTokenIndex >= 0 && wallpaperReady; curTokenIndex--) { 862 final WallpaperWindowToken token = mWallpaperTokens.get(curTokenIndex); 863 if (token.hasVisibleNotDrawnWallpaper()) { 864 // We've told this wallpaper to be visible, but it is not drawn yet 865 wallpaperReady = false; 866 if (mWallpaperDrawState != WALLPAPER_DRAW_TIMEOUT) { 867 // wait for this wallpaper until it is drawn or timeout 868 transitionReady = false; 869 } 870 if (mWallpaperDrawState == WALLPAPER_DRAW_NORMAL) { 871 mWallpaperDrawState = WALLPAPER_DRAW_PENDING; 872 mService.mH.removeMessages(WALLPAPER_DRAW_PENDING_TIMEOUT, this); 873 mService.mH.sendMessageDelayed( 874 mService.mH.obtainMessage(WALLPAPER_DRAW_PENDING_TIMEOUT, this), 875 WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION); 876 877 } 878 if (DEBUG_WALLPAPER) { 879 Slog.v(TAG, 880 "Wallpaper should be visible but has not been drawn yet. " 881 + "mWallpaperDrawState=" + mWallpaperDrawState); 882 } 883 break; 884 } 885 } 886 if (wallpaperReady) { 887 mWallpaperDrawState = WALLPAPER_DRAW_NORMAL; 888 mService.mH.removeMessages(WALLPAPER_DRAW_PENDING_TIMEOUT, this); 889 } 890 891 return transitionReady; 892 } 893 894 /** 895 * Adjusts the wallpaper windows if the input display has a pending wallpaper layout or one of 896 * the opening apps should be a wallpaper target. 897 */ adjustWallpaperWindowsForAppTransitionIfNeeded(ArraySet<ActivityRecord> openingApps)898 void adjustWallpaperWindowsForAppTransitionIfNeeded(ArraySet<ActivityRecord> openingApps) { 899 boolean adjust = false; 900 if ((mDisplayContent.pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) { 901 adjust = true; 902 } else { 903 for (int i = openingApps.size() - 1; i >= 0; --i) { 904 final ActivityRecord activity = openingApps.valueAt(i); 905 if (activity.windowsCanBeWallpaperTarget()) { 906 adjust = true; 907 break; 908 } 909 } 910 } 911 912 if (adjust) { 913 adjustWallpaperWindows(); 914 } 915 } 916 addWallpaperToken(WallpaperWindowToken token)917 void addWallpaperToken(WallpaperWindowToken token) { 918 mWallpaperTokens.add(token); 919 } 920 removeWallpaperToken(WallpaperWindowToken token)921 void removeWallpaperToken(WallpaperWindowToken token) { 922 mWallpaperTokens.remove(token); 923 } 924 925 @VisibleForTesting canScreenshotWallpaper()926 boolean canScreenshotWallpaper() { 927 return canScreenshotWallpaper(getTopVisibleWallpaper()); 928 } 929 canScreenshotWallpaper(WindowState wallpaperWindowState)930 private boolean canScreenshotWallpaper(WindowState wallpaperWindowState) { 931 if (!mService.mPolicy.isScreenOn()) { 932 if (DEBUG_SCREENSHOT) { 933 Slog.i(TAG_WM, "Attempted to take screenshot while display was off."); 934 } 935 return false; 936 } 937 938 if (wallpaperWindowState == null) { 939 if (DEBUG_SCREENSHOT) { 940 Slog.i(TAG_WM, "No visible wallpaper to screenshot"); 941 } 942 return false; 943 } 944 return true; 945 } 946 947 /** 948 * Take a screenshot of the wallpaper if it's visible. 949 * 950 * @return Bitmap of the wallpaper 951 */ screenshotWallpaperLocked()952 Bitmap screenshotWallpaperLocked() { 953 final WindowState wallpaperWindowState = getTopVisibleWallpaper(); 954 if (!canScreenshotWallpaper(wallpaperWindowState)) { 955 return null; 956 } 957 958 final Rect bounds = wallpaperWindowState.getBounds(); 959 bounds.offsetTo(0, 0); 960 961 ScreenCapture.ScreenshotHardwareBuffer wallpaperBuffer = ScreenCapture.captureLayers( 962 wallpaperWindowState.getSurfaceControl(), bounds, 1 /* frameScale */); 963 964 if (wallpaperBuffer == null) { 965 Slog.w(TAG_WM, "Failed to screenshot wallpaper"); 966 return null; 967 } 968 return Bitmap.wrapHardwareBuffer( 969 wallpaperBuffer.getHardwareBuffer(), wallpaperBuffer.getColorSpace()); 970 } 971 972 /** 973 * Mirrors the visible wallpaper if it's available. 974 * 975 * @return A SurfaceControl for the parent of the mirrored wallpaper. 976 */ mirrorWallpaperSurface()977 SurfaceControl mirrorWallpaperSurface() { 978 final WindowState wallpaperWindowState = getTopVisibleWallpaper(); 979 return wallpaperWindowState != null 980 ? SurfaceControl.mirrorSurface(wallpaperWindowState.getSurfaceControl()) 981 : null; 982 } 983 getTopVisibleWallpaper()984 WindowState getTopVisibleWallpaper() { 985 for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) { 986 final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx); 987 for (int i = token.getChildCount() - 1; i >= 0; i--) { 988 final WindowState w = token.getChildAt(i); 989 if (w.mWinAnimator.getShown() && w.mWinAnimator.mLastAlpha > 0f) { 990 return w; 991 } 992 } 993 } 994 return null; 995 } 996 997 /** 998 * Each window can request a zoom, example: 999 * - User is in overview, zoomed out. 1000 * - User also pulls down the shade. 1001 * 1002 * This means that we always have to choose the largest zoom out that we have, otherwise 1003 * we'll have conflicts and break the "depth system" mental model. 1004 */ computeLastWallpaperZoomOut()1005 private void computeLastWallpaperZoomOut() { 1006 if (mShouldUpdateZoom) { 1007 mLastWallpaperZoomOut = 0; 1008 mDisplayContent.forAllWindows(mComputeMaxZoomOutFunction, true); 1009 mShouldUpdateZoom = false; 1010 } 1011 } 1012 zoomOutToScale(float zoom)1013 private float zoomOutToScale(float zoom) { 1014 return MathUtils.lerp(1, mMaxWallpaperScale, 1 - zoom); 1015 } 1016 dump(PrintWriter pw, String prefix)1017 void dump(PrintWriter pw, String prefix) { 1018 pw.print(prefix); pw.print("displayId="); pw.println(mDisplayContent.getDisplayId()); 1019 pw.print(prefix); pw.print("mWallpaperTarget="); pw.println(mWallpaperTarget); 1020 if (mPrevWallpaperTarget != null) { 1021 pw.print(prefix); pw.print("mPrevWallpaperTarget="); pw.println(mPrevWallpaperTarget); 1022 } 1023 pw.print(prefix); pw.print("mLastWallpaperX="); pw.print(mLastWallpaperX); 1024 pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY); 1025 if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE 1026 || mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) { 1027 pw.print(prefix); 1028 pw.print("mLastWallpaperDisplayOffsetX="); pw.print(mLastWallpaperDisplayOffsetX); 1029 pw.print(" mLastWallpaperDisplayOffsetY="); pw.println(mLastWallpaperDisplayOffsetY); 1030 } 1031 } 1032 1033 /** Helper class for storing the results of a wallpaper target find operation. */ 1034 final private static class FindWallpaperTargetResult { 1035 1036 static final class TopWallpaper { 1037 // A wp that can be visible on home screen only 1038 WindowState mTopHideWhenLockedWallpaper = null; 1039 // A wallpaper that has permission to be visible on lock screen (lock or shared wp) 1040 WindowState mTopShowWhenLockedWallpaper = null; 1041 reset()1042 void reset() { 1043 mTopHideWhenLockedWallpaper = null; 1044 mTopShowWhenLockedWallpaper = null; 1045 } 1046 } 1047 1048 TopWallpaper mTopWallpaper = new TopWallpaper(); 1049 boolean mNeedsShowWhenLockedWallpaper; 1050 boolean useTopWallpaperAsTarget = false; 1051 WindowState wallpaperTarget = null; 1052 boolean isWallpaperTargetForLetterbox = false; 1053 setTopHideWhenLockedWallpaper(WindowState win)1054 void setTopHideWhenLockedWallpaper(WindowState win) { 1055 if (DEBUG_WALLPAPER) { 1056 Slog.v(TAG, "setTopHideWhenLockedWallpaper " + win); 1057 } 1058 mTopWallpaper.mTopHideWhenLockedWallpaper = win; 1059 } 1060 setTopShowWhenLockedWallpaper(WindowState win)1061 void setTopShowWhenLockedWallpaper(WindowState win) { 1062 if (DEBUG_WALLPAPER) { 1063 Slog.v(TAG, "setTopShowWhenLockedWallpaper " + win); 1064 } 1065 mTopWallpaper.mTopShowWhenLockedWallpaper = win; 1066 } 1067 hasTopHideWhenLockedWallpaper()1068 boolean hasTopHideWhenLockedWallpaper() { 1069 return mTopWallpaper.mTopHideWhenLockedWallpaper != null; 1070 } 1071 hasTopShowWhenLockedWallpaper()1072 boolean hasTopShowWhenLockedWallpaper() { 1073 return mTopWallpaper.mTopShowWhenLockedWallpaper != null; 1074 } 1075 getTopWallpaper(boolean isKeyguardLocked)1076 WindowState getTopWallpaper(boolean isKeyguardLocked) { 1077 if (!isKeyguardLocked && hasTopHideWhenLockedWallpaper()) { 1078 return mTopWallpaper.mTopHideWhenLockedWallpaper; 1079 } else { 1080 return mTopWallpaper.mTopShowWhenLockedWallpaper; 1081 } 1082 } 1083 setWallpaperTarget(WindowState win)1084 void setWallpaperTarget(WindowState win) { 1085 wallpaperTarget = win; 1086 } 1087 setUseTopWallpaperAsTarget(boolean topWallpaperAsTarget)1088 void setUseTopWallpaperAsTarget(boolean topWallpaperAsTarget) { 1089 useTopWallpaperAsTarget = topWallpaperAsTarget; 1090 } 1091 setIsWallpaperTargetForLetterbox(boolean isWallpaperTargetForLetterbox)1092 void setIsWallpaperTargetForLetterbox(boolean isWallpaperTargetForLetterbox) { 1093 this.isWallpaperTargetForLetterbox = isWallpaperTargetForLetterbox; 1094 } 1095 reset()1096 void reset() { 1097 mTopWallpaper.reset(); 1098 mNeedsShowWhenLockedWallpaper = false; 1099 wallpaperTarget = null; 1100 useTopWallpaperAsTarget = false; 1101 isWallpaperTargetForLetterbox = false; 1102 } 1103 } 1104 } 1105