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