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