Home | History | Annotate | Download | only in wm
      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 com.android.internal.util.ToBooleanFunction;
     20 
     21 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
     22 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
     23 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
     24 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
     25 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
     26 
     27 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
     28 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
     29 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
     30 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
     31 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
     32 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
     33 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
     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.graphics.Bitmap;
     39 import android.graphics.GraphicBuffer;
     40 import android.graphics.Rect;
     41 import android.os.Bundle;
     42 import android.os.Debug;
     43 import android.os.IBinder;
     44 import android.os.RemoteException;
     45 import android.os.SystemClock;
     46 import android.util.ArraySet;
     47 import android.util.Slog;
     48 import android.view.DisplayInfo;
     49 import android.view.SurfaceControl;
     50 import android.view.WindowManager;
     51 import android.view.animation.Animation;
     52 
     53 import java.io.PrintWriter;
     54 import java.util.ArrayList;
     55 
     56 /**
     57  * Controls wallpaper windows visibility, ordering, and so on.
     58  * NOTE: All methods in this class must be called with the window manager service lock held.
     59  */
     60 class WallpaperController {
     61     private static final String TAG = TAG_WITH_CLASS_NAME ? "WallpaperController" : TAG_WM;
     62     private WindowManagerService mService;
     63 
     64     private final ArrayList<WallpaperWindowToken> mWallpaperTokens = new ArrayList<>();
     65 
     66     // If non-null, this is the currently visible window that is associated
     67     // with the wallpaper.
     68     private WindowState mWallpaperTarget = null;
     69     // If non-null, we are in the middle of animating from one wallpaper target
     70     // to another, and this is the previous wallpaper target.
     71     private WindowState mPrevWallpaperTarget = null;
     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     private 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     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     /**
    105      * Temporary storage for taking a screenshot of the wallpaper.
    106      * @see #screenshotWallpaperLocked()
    107      */
    108     private WindowState mTmpTopWallpaper;
    109 
    110     private final FindWallpaperTargetResult mFindResults = new FindWallpaperTargetResult();
    111 
    112     private final ToBooleanFunction<WindowState> mFindWallpaperTargetFunction = w -> {
    113         final WindowAnimator winAnimator = mService.mAnimator;
    114         if ((w.mAttrs.type == TYPE_WALLPAPER)) {
    115             if (mFindResults.topWallpaper == null || mFindResults.resetTopWallpaper) {
    116                 mFindResults.setTopWallpaper(w);
    117                 mFindResults.resetTopWallpaper = false;
    118             }
    119             return false;
    120         }
    121 
    122         mFindResults.resetTopWallpaper = true;
    123         if (w != winAnimator.mWindowDetachedWallpaper && w.mAppToken != null) {
    124             // If this window's app token is hidden and not animating, it is of no interest to us.
    125             if (w.mAppToken.isHidden() && !w.mAppToken.isSelfAnimating()) {
    126                 if (DEBUG_WALLPAPER) Slog.v(TAG,
    127                         "Skipping hidden and not animating token: " + w);
    128                 return false;
    129             }
    130         }
    131         if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w + ": isOnScreen=" + w.isOnScreen()
    132                 + " mDrawState=" + w.mWinAnimator.mDrawState);
    133 
    134         if (w.mWillReplaceWindow && mWallpaperTarget == null
    135                 && !mFindResults.useTopWallpaperAsTarget) {
    136             // When we are replacing a window and there was wallpaper before replacement, we want to
    137             // keep the window until the new windows fully appear and can determine the visibility,
    138             // to avoid flickering.
    139             mFindResults.setUseTopWallpaperAsTarget(true);
    140         }
    141 
    142         final boolean keyguardGoingAwayWithWallpaper = (w.mAppToken != null
    143                 && w.mAppToken.isSelfAnimating()
    144                 && AppTransition.isKeyguardGoingAwayTransit(w.mAppToken.getTransit())
    145                 && (w.mAppToken.getTransitFlags()
    146                         & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0);
    147 
    148         boolean needsShowWhenLockedWallpaper = false;
    149         if ((w.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0
    150                 && mService.mPolicy.isKeyguardLocked()
    151                 && mService.mPolicy.isKeyguardOccluded()) {
    152             // The lowest show when locked window decides whether we need to put the wallpaper
    153             // behind.
    154             needsShowWhenLockedWallpaper = !isFullscreen(w.mAttrs)
    155                     || (w.mAppToken != null && !w.mAppToken.fillsParent());
    156         }
    157 
    158         if (keyguardGoingAwayWithWallpaper || needsShowWhenLockedWallpaper) {
    159             // Keep the wallpaper during Keyguard exit but also when it's needed for a
    160             // non-fullscreen show when locked activity.
    161             mFindResults.setUseTopWallpaperAsTarget(true);
    162         }
    163 
    164         final RecentsAnimationController recentsAnimationController =
    165                 mService.getRecentsAnimationController();
    166         final boolean animationWallpaper = w.mAppToken != null && w.mAppToken.getAnimation() != null
    167                 && w.mAppToken.getAnimation().getShowWallpaper();
    168         final boolean hasWallpaper = (w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0
    169                 || animationWallpaper;
    170         final boolean isRecentsTransitionTarget = (recentsAnimationController != null
    171                 && recentsAnimationController.isWallpaperVisible(w));
    172         if (isRecentsTransitionTarget) {
    173             if (DEBUG_WALLPAPER) Slog.v(TAG, "Found recents animation wallpaper target: " + w);
    174             mFindResults.setWallpaperTarget(w);
    175             return true;
    176         } else if (hasWallpaper && w.isOnScreen()
    177                 && (mWallpaperTarget == w || w.isDrawFinishedLw())) {
    178             if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: " + w);
    179             mFindResults.setWallpaperTarget(w);
    180             if (w == mWallpaperTarget && w.mWinAnimator.isAnimationSet()) {
    181                 // The current wallpaper target is animating, so we'll look behind it for
    182                 // another possible target and figure out what is going on later.
    183                 if (DEBUG_WALLPAPER) Slog.v(TAG,
    184                         "Win " + w + ": token animating, looking behind.");
    185             }
    186             // Found a target! End search.
    187             return true;
    188         } else if (w == winAnimator.mWindowDetachedWallpaper) {
    189             if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
    190                     "Found animating detached wallpaper target win: " + w);
    191             mFindResults.setUseTopWallpaperAsTarget(true);
    192         }
    193         return false;
    194     };
    195 
    196     public WallpaperController(WindowManagerService service) {
    197         mService = service;
    198     }
    199 
    200     WindowState getWallpaperTarget() {
    201         return mWallpaperTarget;
    202     }
    203 
    204     boolean isWallpaperTarget(WindowState win) {
    205         return win == mWallpaperTarget;
    206     }
    207 
    208     boolean isBelowWallpaperTarget(WindowState win) {
    209         return mWallpaperTarget != null && mWallpaperTarget.mLayer >= win.mBaseLayer;
    210     }
    211 
    212     boolean isWallpaperVisible() {
    213         return isWallpaperVisible(mWallpaperTarget);
    214     }
    215 
    216     /**
    217      * Starts {@param a} on all wallpaper windows.
    218      */
    219     void startWallpaperAnimation(Animation a) {
    220         for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
    221             final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
    222             token.startAnimation(a);
    223         }
    224     }
    225 
    226     private final boolean isWallpaperVisible(WindowState wallpaperTarget) {
    227         final RecentsAnimationController recentsAnimationController =
    228                 mService.getRecentsAnimationController();
    229         boolean isAnimatingWithRecentsComponent = recentsAnimationController != null
    230                 && recentsAnimationController.isWallpaperVisible(wallpaperTarget);
    231         if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper vis: target " + wallpaperTarget + ", obscured="
    232                 + (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??")
    233                 + " animating=" + ((wallpaperTarget != null && wallpaperTarget.mAppToken != null)
    234                 ? wallpaperTarget.mAppToken.isSelfAnimating() : null)
    235                 + " prev=" + mPrevWallpaperTarget
    236                 + " recentsAnimationWallpaperVisible=" + isAnimatingWithRecentsComponent);
    237         return (wallpaperTarget != null
    238                 && (!wallpaperTarget.mObscured
    239                         || isAnimatingWithRecentsComponent
    240                         || (wallpaperTarget.mAppToken != null
    241                                 && wallpaperTarget.mAppToken.isSelfAnimating())))
    242                 || mPrevWallpaperTarget != null;
    243     }
    244 
    245     boolean isWallpaperTargetAnimating() {
    246         return mWallpaperTarget != null && mWallpaperTarget.mWinAnimator.isAnimationSet()
    247                 && (mWallpaperTarget.mAppToken == null
    248                         || !mWallpaperTarget.mAppToken.isWaitingForTransitionStart());
    249     }
    250 
    251     void updateWallpaperVisibility() {
    252         final boolean visible = isWallpaperVisible(mWallpaperTarget);
    253 
    254         for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
    255             final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
    256             token.updateWallpaperVisibility(visible);
    257         }
    258     }
    259 
    260     void hideDeferredWallpapersIfNeeded() {
    261         if (mDeferredHideWallpaper != null) {
    262             hideWallpapers(mDeferredHideWallpaper);
    263             mDeferredHideWallpaper = null;
    264         }
    265     }
    266 
    267     void hideWallpapers(final WindowState winGoingAway) {
    268         if (mWallpaperTarget != null
    269                 && (mWallpaperTarget != winGoingAway || mPrevWallpaperTarget != null)) {
    270             return;
    271         }
    272         if (mService.mAppTransition.isRunning()) {
    273             // Defer hiding the wallpaper when app transition is running until the animations
    274             // are done.
    275             mDeferredHideWallpaper = winGoingAway;
    276             return;
    277         }
    278 
    279         final boolean wasDeferred = (mDeferredHideWallpaper == winGoingAway);
    280         for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
    281             final WallpaperWindowToken token = mWallpaperTokens.get(i);
    282             token.hideWallpaperToken(wasDeferred, "hideWallpapers");
    283             if (DEBUG_WALLPAPER_LIGHT && !token.isHidden()) Slog.d(TAG, "Hiding wallpaper " + token
    284                     + " from " + winGoingAway + " target=" + mWallpaperTarget + " prev="
    285                     + mPrevWallpaperTarget + "\n" + Debug.getCallers(5, "  "));
    286         }
    287     }
    288 
    289     boolean updateWallpaperOffset(WindowState wallpaperWin, int dw, int dh, boolean sync) {
    290         int xOffset = 0;
    291         int yOffset = 0;
    292         boolean rawChanged = false;
    293         // Set the default wallpaper x-offset to either edge of the screen (depending on RTL), to
    294         // match the behavior of most Launchers
    295         float defaultWallpaperX = wallpaperWin.isRtl() ? 1f : 0f;
    296         float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : defaultWallpaperX;
    297         float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f;
    298         int availw = wallpaperWin.mFrame.right - wallpaperWin.mFrame.left - dw;
    299         int offset = availw > 0 ? -(int)(availw * wpx + .5f) : 0;
    300         if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
    301             offset += mLastWallpaperDisplayOffsetX;
    302         }
    303         xOffset = offset;
    304 
    305         if (wallpaperWin.mWallpaperX != wpx || wallpaperWin.mWallpaperXStep != wpxs) {
    306             wallpaperWin.mWallpaperX = wpx;
    307             wallpaperWin.mWallpaperXStep = wpxs;
    308             rawChanged = true;
    309         }
    310 
    311         float wpy = mLastWallpaperY >= 0 ? mLastWallpaperY : 0.5f;
    312         float wpys = mLastWallpaperYStep >= 0 ? mLastWallpaperYStep : -1.0f;
    313         int availh = wallpaperWin.mFrame.bottom - wallpaperWin.mFrame.top - dh;
    314         offset = availh > 0 ? -(int)(availh * wpy + .5f) : 0;
    315         if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
    316             offset += mLastWallpaperDisplayOffsetY;
    317         }
    318         yOffset = offset;
    319 
    320         if (wallpaperWin.mWallpaperY != wpy || wallpaperWin.mWallpaperYStep != wpys) {
    321             wallpaperWin.mWallpaperY = wpy;
    322             wallpaperWin.mWallpaperYStep = wpys;
    323             rawChanged = true;
    324         }
    325 
    326         boolean changed = wallpaperWin.mWinAnimator.setWallpaperOffset(xOffset, yOffset);
    327 
    328         if (rawChanged && (wallpaperWin.mAttrs.privateFlags &
    329                 WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) != 0) {
    330             try {
    331                 if (DEBUG_WALLPAPER) Slog.v(TAG, "Report new wp offset "
    332                         + wallpaperWin + " x=" + wallpaperWin.mWallpaperX
    333                         + " y=" + wallpaperWin.mWallpaperY);
    334                 if (sync) {
    335                     mWaitingOnWallpaper = wallpaperWin;
    336                 }
    337                 wallpaperWin.mClient.dispatchWallpaperOffsets(
    338                         wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY,
    339                         wallpaperWin.mWallpaperXStep, wallpaperWin.mWallpaperYStep, sync);
    340                 if (sync) {
    341                     if (mWaitingOnWallpaper != null) {
    342                         long start = SystemClock.uptimeMillis();
    343                         if ((mLastWallpaperTimeoutTime + WALLPAPER_TIMEOUT_RECOVERY)
    344                                 < start) {
    345                             try {
    346                                 if (DEBUG_WALLPAPER) Slog.v(TAG,
    347                                         "Waiting for offset complete...");
    348                                 mService.mWindowMap.wait(WALLPAPER_TIMEOUT);
    349                             } catch (InterruptedException e) {
    350                             }
    351                             if (DEBUG_WALLPAPER) Slog.v(TAG, "Offset complete!");
    352                             if ((start + WALLPAPER_TIMEOUT) < SystemClock.uptimeMillis()) {
    353                                 Slog.i(TAG, "Timeout waiting for wallpaper to offset: "
    354                                         + wallpaperWin);
    355                                 mLastWallpaperTimeoutTime = start;
    356                             }
    357                         }
    358                         mWaitingOnWallpaper = null;
    359                     }
    360                 }
    361             } catch (RemoteException e) {
    362             }
    363         }
    364 
    365         return changed;
    366     }
    367 
    368     void setWindowWallpaperPosition(
    369             WindowState window, float x, float y, float xStep, float yStep) {
    370         if (window.mWallpaperX != x || window.mWallpaperY != y)  {
    371             window.mWallpaperX = x;
    372             window.mWallpaperY = y;
    373             window.mWallpaperXStep = xStep;
    374             window.mWallpaperYStep = yStep;
    375             updateWallpaperOffsetLocked(window, true);
    376         }
    377     }
    378 
    379     void setWindowWallpaperDisplayOffset(WindowState window, int x, int y) {
    380         if (window.mWallpaperDisplayOffsetX != x || window.mWallpaperDisplayOffsetY != y)  {
    381             window.mWallpaperDisplayOffsetX = x;
    382             window.mWallpaperDisplayOffsetY = y;
    383             updateWallpaperOffsetLocked(window, true);
    384         }
    385     }
    386 
    387     Bundle sendWindowWallpaperCommand(
    388             WindowState window, String action, int x, int y, int z, Bundle extras, boolean sync) {
    389         if (window == mWallpaperTarget || window == mPrevWallpaperTarget) {
    390             boolean doWait = sync;
    391             for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
    392                 final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
    393                 token.sendWindowWallpaperCommand(action, x, y, z, extras, sync);
    394             }
    395 
    396             if (doWait) {
    397                 // TODO: Need to wait for result.
    398             }
    399         }
    400 
    401         return null;
    402     }
    403 
    404     private void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) {
    405         final DisplayContent displayContent = changingTarget.getDisplayContent();
    406         if (displayContent == null) {
    407             return;
    408         }
    409         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
    410         final int dw = displayInfo.logicalWidth;
    411         final int dh = displayInfo.logicalHeight;
    412 
    413         WindowState target = mWallpaperTarget;
    414         if (target != null) {
    415             if (target.mWallpaperX >= 0) {
    416                 mLastWallpaperX = target.mWallpaperX;
    417             } else if (changingTarget.mWallpaperX >= 0) {
    418                 mLastWallpaperX = changingTarget.mWallpaperX;
    419             }
    420             if (target.mWallpaperY >= 0) {
    421                 mLastWallpaperY = target.mWallpaperY;
    422             } else if (changingTarget.mWallpaperY >= 0) {
    423                 mLastWallpaperY = changingTarget.mWallpaperY;
    424             }
    425             if (target.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
    426                 mLastWallpaperDisplayOffsetX = target.mWallpaperDisplayOffsetX;
    427             } else if (changingTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
    428                 mLastWallpaperDisplayOffsetX = changingTarget.mWallpaperDisplayOffsetX;
    429             }
    430             if (target.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
    431                 mLastWallpaperDisplayOffsetY = target.mWallpaperDisplayOffsetY;
    432             } else if (changingTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
    433                 mLastWallpaperDisplayOffsetY = changingTarget.mWallpaperDisplayOffsetY;
    434             }
    435             if (target.mWallpaperXStep >= 0) {
    436                 mLastWallpaperXStep = target.mWallpaperXStep;
    437             } else if (changingTarget.mWallpaperXStep >= 0) {
    438                 mLastWallpaperXStep = changingTarget.mWallpaperXStep;
    439             }
    440             if (target.mWallpaperYStep >= 0) {
    441                 mLastWallpaperYStep = target.mWallpaperYStep;
    442             } else if (changingTarget.mWallpaperYStep >= 0) {
    443                 mLastWallpaperYStep = changingTarget.mWallpaperYStep;
    444             }
    445         }
    446 
    447         for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
    448             mWallpaperTokens.get(curTokenNdx).updateWallpaperOffset(dw, dh, sync);
    449         }
    450     }
    451 
    452     void clearLastWallpaperTimeoutTime() {
    453         mLastWallpaperTimeoutTime = 0;
    454     }
    455 
    456     void wallpaperCommandComplete(IBinder window) {
    457         if (mWaitingOnWallpaper != null &&
    458                 mWaitingOnWallpaper.mClient.asBinder() == window) {
    459             mWaitingOnWallpaper = null;
    460             mService.mWindowMap.notifyAll();
    461         }
    462     }
    463 
    464     void wallpaperOffsetsComplete(IBinder window) {
    465         if (mWaitingOnWallpaper != null &&
    466                 mWaitingOnWallpaper.mClient.asBinder() == window) {
    467             mWaitingOnWallpaper = null;
    468             mService.mWindowMap.notifyAll();
    469         }
    470     }
    471 
    472     private void findWallpaperTarget(DisplayContent dc) {
    473         mFindResults.reset();
    474         if (dc.isStackVisible(WINDOWING_MODE_FREEFORM)) {
    475             // In freeform mode we set the wallpaper as its own target, so we don't need an
    476             // additional window to make it visible.
    477             mFindResults.setUseTopWallpaperAsTarget(true);
    478         }
    479 
    480         dc.forAllWindows(mFindWallpaperTargetFunction, true /* traverseTopToBottom */);
    481 
    482         if (mFindResults.wallpaperTarget == null && mFindResults.useTopWallpaperAsTarget) {
    483             mFindResults.setWallpaperTarget(mFindResults.topWallpaper);
    484         }
    485     }
    486 
    487     private boolean isFullscreen(WindowManager.LayoutParams attrs) {
    488         return attrs.x == 0 && attrs.y == 0
    489                 && attrs.width == MATCH_PARENT && attrs.height == MATCH_PARENT;
    490     }
    491 
    492     /** Updates the target wallpaper if needed and returns true if an update happened. */
    493     private void updateWallpaperWindowsTarget(DisplayContent dc,
    494             FindWallpaperTargetResult result) {
    495 
    496         WindowState wallpaperTarget = result.wallpaperTarget;
    497 
    498         if (mWallpaperTarget == wallpaperTarget
    499                 || (mPrevWallpaperTarget != null && mPrevWallpaperTarget == wallpaperTarget)) {
    500 
    501             if (mPrevWallpaperTarget == null) {
    502                 return;
    503             }
    504 
    505             // Is it time to stop animating?
    506             if (!mPrevWallpaperTarget.isAnimatingLw()) {
    507                 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "No longer animating wallpaper targets!");
    508                 mPrevWallpaperTarget = null;
    509                 mWallpaperTarget = wallpaperTarget;
    510             }
    511             return;
    512         }
    513 
    514         if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
    515                 "New wallpaper target: " + wallpaperTarget + " prevTarget: " + mWallpaperTarget);
    516 
    517         mPrevWallpaperTarget = null;
    518 
    519         final WindowState prevWallpaperTarget = mWallpaperTarget;
    520         mWallpaperTarget = wallpaperTarget;
    521 
    522         if (wallpaperTarget == null || prevWallpaperTarget == null) {
    523             return;
    524         }
    525 
    526         // Now what is happening...  if the current and new targets are animating,
    527         // then we are in our super special mode!
    528         boolean oldAnim = prevWallpaperTarget.isAnimatingLw();
    529         boolean foundAnim = wallpaperTarget.isAnimatingLw();
    530         if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
    531                 "New animation: " + foundAnim + " old animation: " + oldAnim);
    532 
    533         if (!foundAnim || !oldAnim) {
    534             return;
    535         }
    536 
    537         if (dc.getWindow(w -> w == prevWallpaperTarget) == null) {
    538             return;
    539         }
    540 
    541         final boolean newTargetHidden = wallpaperTarget.mAppToken != null
    542                 && wallpaperTarget.mAppToken.hiddenRequested;
    543         final boolean oldTargetHidden = prevWallpaperTarget.mAppToken != null
    544                 && prevWallpaperTarget.mAppToken.hiddenRequested;
    545 
    546         if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Animating wallpapers:" + " old: "
    547                 + prevWallpaperTarget + " hidden=" + oldTargetHidden + " new: " + wallpaperTarget
    548                 + " hidden=" + newTargetHidden);
    549 
    550         mPrevWallpaperTarget = prevWallpaperTarget;
    551 
    552         if (newTargetHidden && !oldTargetHidden) {
    553             if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Old wallpaper still the target.");
    554             // Use the old target if new target is hidden but old target
    555             // is not. If they're both hidden, still use the new target.
    556             mWallpaperTarget = prevWallpaperTarget;
    557         } else if (newTargetHidden == oldTargetHidden
    558                 && !mService.mOpeningApps.contains(wallpaperTarget.mAppToken)
    559                 && (mService.mOpeningApps.contains(prevWallpaperTarget.mAppToken)
    560                 || mService.mClosingApps.contains(prevWallpaperTarget.mAppToken))) {
    561             // If they're both hidden (or both not hidden), prefer the one that's currently in
    562             // opening or closing app list, this allows transition selection logic to better
    563             // determine the wallpaper status of opening/closing apps.
    564             mWallpaperTarget = prevWallpaperTarget;
    565         }
    566 
    567         result.setWallpaperTarget(wallpaperTarget);
    568     }
    569 
    570     private void updateWallpaperTokens(boolean visible) {
    571         for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
    572             final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
    573             token.updateWallpaperWindows(visible);
    574             token.getDisplayContent().assignWindowLayers(false);
    575         }
    576     }
    577 
    578     void adjustWallpaperWindows(DisplayContent dc) {
    579         mService.mRoot.mWallpaperMayChange = false;
    580 
    581         // First find top-most window that has asked to be on top of the wallpaper;
    582         // all wallpapers go behind it.
    583         findWallpaperTarget(dc);
    584         updateWallpaperWindowsTarget(dc, mFindResults);
    585 
    586         // The window is visible to the compositor...but is it visible to the user?
    587         // That is what the wallpaper cares about.
    588         final boolean visible = mWallpaperTarget != null && isWallpaperVisible(mWallpaperTarget);
    589         if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper visibility: " + visible);
    590 
    591         if (visible) {
    592             if (mWallpaperTarget.mWallpaperX >= 0) {
    593                 mLastWallpaperX = mWallpaperTarget.mWallpaperX;
    594                 mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep;
    595             }
    596             if (mWallpaperTarget.mWallpaperY >= 0) {
    597                 mLastWallpaperY = mWallpaperTarget.mWallpaperY;
    598                 mLastWallpaperYStep = mWallpaperTarget.mWallpaperYStep;
    599             }
    600             if (mWallpaperTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
    601                 mLastWallpaperDisplayOffsetX = mWallpaperTarget.mWallpaperDisplayOffsetX;
    602             }
    603             if (mWallpaperTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
    604                 mLastWallpaperDisplayOffsetY = mWallpaperTarget.mWallpaperDisplayOffsetY;
    605             }
    606         }
    607 
    608         updateWallpaperTokens(visible);
    609 
    610         if (DEBUG_WALLPAPER_LIGHT)  Slog.d(TAG, "New wallpaper: target=" + mWallpaperTarget
    611                 + " prev=" + mPrevWallpaperTarget);
    612     }
    613 
    614     boolean processWallpaperDrawPendingTimeout() {
    615         if (mWallpaperDrawState == WALLPAPER_DRAW_PENDING) {
    616             mWallpaperDrawState = WALLPAPER_DRAW_TIMEOUT;
    617             if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
    618                     "*** WALLPAPER DRAW TIMEOUT");
    619 
    620             // If there was a recents animation in progress, cancel that animation
    621             if (mService.getRecentsAnimationController() != null) {
    622                 mService.getRecentsAnimationController().cancelAnimation(
    623                         REORDER_MOVE_TO_ORIGINAL_POSITION, "wallpaperDrawPendingTimeout");
    624             }
    625             return true;
    626         }
    627         return false;
    628     }
    629 
    630     boolean wallpaperTransitionReady() {
    631         boolean transitionReady = true;
    632         boolean wallpaperReady = true;
    633         for (int curTokenIndex = mWallpaperTokens.size() - 1;
    634                 curTokenIndex >= 0 && wallpaperReady; curTokenIndex--) {
    635             final WallpaperWindowToken token = mWallpaperTokens.get(curTokenIndex);
    636             if (token.hasVisibleNotDrawnWallpaper()) {
    637                 // We've told this wallpaper to be visible, but it is not drawn yet
    638                 wallpaperReady = false;
    639                 if (mWallpaperDrawState != WALLPAPER_DRAW_TIMEOUT) {
    640                     // wait for this wallpaper until it is drawn or timeout
    641                     transitionReady = false;
    642                 }
    643                 if (mWallpaperDrawState == WALLPAPER_DRAW_NORMAL) {
    644                     mWallpaperDrawState = WALLPAPER_DRAW_PENDING;
    645                     mService.mH.removeMessages(WALLPAPER_DRAW_PENDING_TIMEOUT);
    646                     mService.mH.sendEmptyMessageDelayed(WALLPAPER_DRAW_PENDING_TIMEOUT,
    647                             WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION);
    648                 }
    649                 if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
    650                         "Wallpaper should be visible but has not been drawn yet. " +
    651                                 "mWallpaperDrawState=" + mWallpaperDrawState);
    652                 break;
    653             }
    654         }
    655         if (wallpaperReady) {
    656             mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
    657             mService.mH.removeMessages(WALLPAPER_DRAW_PENDING_TIMEOUT);
    658         }
    659 
    660         return transitionReady;
    661     }
    662 
    663     /**
    664      * Adjusts the wallpaper windows if the input display has a pending wallpaper layout or one of
    665      * the opening apps should be a wallpaper target.
    666      */
    667     void adjustWallpaperWindowsForAppTransitionIfNeeded(DisplayContent dc,
    668             ArraySet<AppWindowToken> openingApps) {
    669         boolean adjust = false;
    670         if ((dc.pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
    671             adjust = true;
    672         } else {
    673             for (int i = openingApps.size() - 1; i >= 0; --i) {
    674                 final AppWindowToken token = openingApps.valueAt(i);
    675                 if (token.windowsCanBeWallpaperTarget()) {
    676                     adjust = true;
    677                     break;
    678                 }
    679             }
    680         }
    681 
    682         if (adjust) {
    683             adjustWallpaperWindows(dc);
    684         }
    685     }
    686 
    687     void addWallpaperToken(WallpaperWindowToken token) {
    688         mWallpaperTokens.add(token);
    689     }
    690 
    691     void removeWallpaperToken(WallpaperWindowToken token) {
    692         mWallpaperTokens.remove(token);
    693     }
    694 
    695     /**
    696      * Take a screenshot of the wallpaper if it's visible.
    697      *
    698      * @return Bitmap of the wallpaper
    699      */
    700     Bitmap screenshotWallpaperLocked() {
    701         if (!mService.mPolicy.isScreenOn()) {
    702             if (DEBUG_SCREENSHOT) {
    703                 Slog.i(TAG_WM, "Attempted to take screenshot while display was off.");
    704             }
    705             return null;
    706         }
    707 
    708         final WindowState wallpaperWindowState = getTopVisibleWallpaper();
    709         if (wallpaperWindowState == null) {
    710             if (DEBUG_SCREENSHOT) {
    711                 Slog.i(TAG_WM, "No visible wallpaper to screenshot");
    712             }
    713             return null;
    714         }
    715 
    716         final Rect bounds = wallpaperWindowState.getBounds();
    717         bounds.offsetTo(0, 0);
    718 
    719         GraphicBuffer wallpaperBuffer = SurfaceControl.captureLayers(
    720                 wallpaperWindowState.getSurfaceControl().getHandle(), bounds, 1 /* frameScale */);
    721 
    722         if (wallpaperBuffer == null) {
    723             Slog.w(TAG_WM, "Failed to screenshot wallpaper");
    724             return null;
    725         }
    726         return Bitmap.createHardwareBitmap(wallpaperBuffer);
    727     }
    728 
    729     private WindowState getTopVisibleWallpaper() {
    730         mTmpTopWallpaper = null;
    731 
    732         for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
    733             final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
    734             token.forAllWindows(w -> {
    735                 final WindowStateAnimator winAnim = w.mWinAnimator;
    736                 if (winAnim != null && winAnim.getShown() && winAnim.mLastAlpha > 0f) {
    737                     mTmpTopWallpaper = w;
    738                     return true;
    739                 }
    740                 return false;
    741             }, true /* traverseTopToBottom */);
    742         }
    743 
    744         return mTmpTopWallpaper;
    745     }
    746 
    747     void dump(PrintWriter pw, String prefix) {
    748         pw.print(prefix); pw.print("mWallpaperTarget="); pw.println(mWallpaperTarget);
    749         if (mPrevWallpaperTarget != null) {
    750             pw.print(prefix); pw.print("mPrevWallpaperTarget="); pw.println(mPrevWallpaperTarget);
    751         }
    752         pw.print(prefix); pw.print("mLastWallpaperX="); pw.print(mLastWallpaperX);
    753         pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
    754         if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE
    755                 || mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
    756             pw.print(prefix);
    757             pw.print("mLastWallpaperDisplayOffsetX="); pw.print(mLastWallpaperDisplayOffsetX);
    758             pw.print(" mLastWallpaperDisplayOffsetY="); pw.println(mLastWallpaperDisplayOffsetY);
    759         }
    760     }
    761 
    762     /** Helper class for storing the results of a wallpaper target find operation. */
    763     final private static class FindWallpaperTargetResult {
    764         WindowState topWallpaper = null;
    765         boolean useTopWallpaperAsTarget = false;
    766         WindowState wallpaperTarget = null;
    767         boolean resetTopWallpaper = false;
    768 
    769         void setTopWallpaper(WindowState win) {
    770             topWallpaper = win;
    771         }
    772 
    773         void setWallpaperTarget(WindowState win) {
    774             wallpaperTarget = win;
    775         }
    776 
    777         void setUseTopWallpaperAsTarget(boolean topWallpaperAsTarget) {
    778             useTopWallpaperAsTarget = topWallpaperAsTarget;
    779         }
    780 
    781         void reset() {
    782             topWallpaper = null;
    783             wallpaperTarget = null;
    784             useTopWallpaperAsTarget = false;
    785             resetTopWallpaper = false;
    786         }
    787     }
    788 }
    789