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