Home | History | Annotate | Download | only in wm
      1 /*
      2  * Copyright (C) 2014 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.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
     20 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
     21 
     22 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
     23 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR;
     24 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
     25 import static com.android.server.wm.WindowManagerService.DEBUG_KEYGUARD;
     26 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_UPDATE_ROTATION;
     27 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_WALLPAPER_MAY_CHANGE;
     28 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_FORCE_HIDING_CHANGED;
     29 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE;
     30 import static com.android.server.wm.WindowManagerService.LayoutFields.SET_WALLPAPER_ACTION_PENDING;
     31 
     32 import android.content.Context;
     33 import android.os.Debug;
     34 import android.os.SystemClock;
     35 import android.util.Slog;
     36 import android.util.SparseArray;
     37 import android.util.SparseIntArray;
     38 import android.util.TimeUtils;
     39 import android.view.Display;
     40 import android.view.SurfaceControl;
     41 import android.view.WindowManagerPolicy;
     42 import android.view.animation.AlphaAnimation;
     43 import android.view.animation.Animation;
     44 
     45 import com.android.server.wm.WindowManagerService.LayoutFields;
     46 
     47 import java.io.PrintWriter;
     48 import java.util.ArrayList;
     49 
     50 /**
     51  * Singleton class that carries out the animations and Surface operations in a separate task
     52  * on behalf of WindowManagerService.
     53  */
     54 public class WindowAnimator {
     55     private static final String TAG = "WindowAnimator";
     56 
     57     /** How long to give statusbar to clear the private keyguard flag when animating out */
     58     private static final long KEYGUARD_ANIM_TIMEOUT_MS = 1000;
     59 
     60     final WindowManagerService mService;
     61     final Context mContext;
     62     final WindowManagerPolicy mPolicy;
     63 
     64     boolean mAnimating;
     65 
     66     final Runnable mAnimationRunnable;
     67 
     68     /** Time of current animation step. Reset on each iteration */
     69     long mCurrentTime;
     70 
     71     /** Skip repeated AppWindowTokens initialization. Note that AppWindowsToken's version of this
     72      * is a long initialized to Long.MIN_VALUE so that it doesn't match this value on startup. */
     73     private int mAnimTransactionSequence;
     74 
     75     /** Window currently running an animation that has requested it be detached
     76      * from the wallpaper.  This means we need to ensure the wallpaper is
     77      * visible behind it in case it animates in a way that would allow it to be
     78      * seen. If multiple windows satisfy this, use the lowest window. */
     79     WindowState mWindowDetachedWallpaper = null;
     80 
     81     WindowStateAnimator mUniverseBackground = null;
     82     int mAboveUniverseLayer = 0;
     83 
     84     int mBulkUpdateParams = 0;
     85     Object mLastWindowFreezeSource;
     86 
     87     SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators =
     88             new SparseArray<DisplayContentsAnimator>(2);
     89 
     90     boolean mInitialized = false;
     91 
     92     boolean mKeyguardGoingAway;
     93     boolean mKeyguardGoingAwayToNotificationShade;
     94     boolean mKeyguardGoingAwayDisableWindowAnimations;
     95 
     96     /** Use one animation for all entering activities after keyguard is dismissed. */
     97     Animation mPostKeyguardExitAnimation;
     98 
     99     // forceHiding states.
    100     static final int KEYGUARD_NOT_SHOWN     = 0;
    101     static final int KEYGUARD_ANIMATING_IN  = 1;
    102     static final int KEYGUARD_SHOWN         = 2;
    103     static final int KEYGUARD_ANIMATING_OUT = 3;
    104     int mForceHiding = KEYGUARD_NOT_SHOWN;
    105 
    106     private String forceHidingToString() {
    107         switch (mForceHiding) {
    108             case KEYGUARD_NOT_SHOWN:    return "KEYGUARD_NOT_SHOWN";
    109             case KEYGUARD_ANIMATING_IN: return "KEYGUARD_ANIMATING_IN";
    110             case KEYGUARD_SHOWN:        return "KEYGUARD_SHOWN";
    111             case KEYGUARD_ANIMATING_OUT:return "KEYGUARD_ANIMATING_OUT";
    112             default: return "KEYGUARD STATE UNKNOWN " + mForceHiding;
    113         }
    114     }
    115 
    116     WindowAnimator(final WindowManagerService service) {
    117         mService = service;
    118         mContext = service.mContext;
    119         mPolicy = service.mPolicy;
    120 
    121         mAnimationRunnable = new Runnable() {
    122             @Override
    123             public void run() {
    124                 synchronized (mService.mWindowMap) {
    125                     mService.mAnimationScheduled = false;
    126                     animateLocked();
    127                 }
    128             }
    129         };
    130     }
    131 
    132     void addDisplayLocked(final int displayId) {
    133         // Create the DisplayContentsAnimator object by retrieving it.
    134         getDisplayContentsAnimatorLocked(displayId);
    135         if (displayId == Display.DEFAULT_DISPLAY) {
    136             mInitialized = true;
    137         }
    138     }
    139 
    140     void removeDisplayLocked(final int displayId) {
    141         final DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
    142         if (displayAnimator != null) {
    143             if (displayAnimator.mScreenRotationAnimation != null) {
    144                 displayAnimator.mScreenRotationAnimation.kill();
    145                 displayAnimator.mScreenRotationAnimation = null;
    146             }
    147         }
    148 
    149         mDisplayContentsAnimators.delete(displayId);
    150     }
    151 
    152     void hideWallpapersLocked(final WindowState w) {
    153         final WindowState wallpaperTarget = mService.mWallpaperTarget;
    154         final WindowState lowerWallpaperTarget = mService.mLowerWallpaperTarget;
    155         final ArrayList<WindowToken> wallpaperTokens = mService.mWallpaperTokens;
    156 
    157         if ((wallpaperTarget == w && lowerWallpaperTarget == null) || wallpaperTarget == null) {
    158             final int numTokens = wallpaperTokens.size();
    159             for (int i = numTokens - 1; i >= 0; i--) {
    160                 final WindowToken token = wallpaperTokens.get(i);
    161                 final int numWindows = token.windows.size();
    162                 for (int j = numWindows - 1; j >= 0; j--) {
    163                     final WindowState wallpaper = token.windows.get(j);
    164                     final WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
    165                     if (!winAnimator.mLastHidden) {
    166                         winAnimator.hide();
    167                         mService.dispatchWallpaperVisibility(wallpaper, false);
    168                         setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
    169                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
    170                     }
    171                 }
    172                 if (WindowManagerService.DEBUG_WALLPAPER_LIGHT && !token.hidden) Slog.d(TAG,
    173                         "Hiding wallpaper " + token + " from " + w
    174                         + " target=" + wallpaperTarget + " lower=" + lowerWallpaperTarget
    175                         + "\n" + Debug.getCallers(5, "  "));
    176                 token.hidden = true;
    177             }
    178         }
    179     }
    180 
    181     private void updateAppWindowsLocked(int displayId) {
    182         ArrayList<TaskStack> stacks = mService.getDisplayContentLocked(displayId).getStacks();
    183         for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
    184             final TaskStack stack = stacks.get(stackNdx);
    185             final ArrayList<Task> tasks = stack.getTasks();
    186             for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
    187                 final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
    188                 for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
    189                     final AppWindowAnimator appAnimator = tokens.get(tokenNdx).mAppAnimator;
    190                     final boolean wasAnimating = appAnimator.animation != null
    191                             && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
    192                     if (appAnimator.stepAnimationLocked(mCurrentTime)) {
    193                         mAnimating = true;
    194                     } else if (wasAnimating) {
    195                         // stopped animating, do one more pass through the layout
    196                         setAppLayoutChanges(appAnimator,
    197                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
    198                                 "appToken " + appAnimator.mAppToken + " done");
    199                         if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
    200                                 "updateWindowsApps...: done animating " + appAnimator.mAppToken);
    201                     }
    202                 }
    203             }
    204 
    205             final AppTokenList exitingAppTokens = stack.mExitingAppTokens;
    206             final int NEAT = exitingAppTokens.size();
    207             for (int i = 0; i < NEAT; i++) {
    208                 final AppWindowAnimator appAnimator = exitingAppTokens.get(i).mAppAnimator;
    209                 final boolean wasAnimating = appAnimator.animation != null
    210                         && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
    211                 if (appAnimator.stepAnimationLocked(mCurrentTime)) {
    212                     mAnimating = true;
    213                 } else if (wasAnimating) {
    214                     // stopped animating, do one more pass through the layout
    215                     setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
    216                         "exiting appToken " + appAnimator.mAppToken + " done");
    217                     if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
    218                             "updateWindowsApps...: done animating exiting " + appAnimator.mAppToken);
    219                 }
    220             }
    221         }
    222     }
    223 
    224     private boolean shouldForceHide(WindowState win) {
    225         final WindowState imeTarget = mService.mInputMethodTarget;
    226         final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisibleNow() &&
    227                 (imeTarget.getAttrs().flags & FLAG_SHOW_WHEN_LOCKED) != 0;
    228 
    229         final WindowState winShowWhenLocked = (WindowState) mPolicy.getWinShowWhenLockedLw();
    230         final AppWindowToken appShowWhenLocked = winShowWhenLocked == null ?
    231                 null : winShowWhenLocked.mAppToken;
    232         final boolean hideWhenLocked =
    233                 !(((win.mIsImWindow || imeTarget == win) && showImeOverKeyguard)
    234                         || (appShowWhenLocked != null && (appShowWhenLocked == win.mAppToken ||
    235                         // Show error dialogs over apps that dismiss keyguard.
    236                         (win.mAttrs.privateFlags & PRIVATE_FLAG_SYSTEM_ERROR) != 0)));
    237         return ((mForceHiding == KEYGUARD_ANIMATING_IN)
    238                 && (!win.mWinAnimator.isAnimating() || hideWhenLocked))
    239                 || ((mForceHiding == KEYGUARD_SHOWN) && hideWhenLocked);
    240     }
    241 
    242     private void updateWindowsLocked(final int displayId) {
    243         ++mAnimTransactionSequence;
    244 
    245         final WindowList windows = mService.getWindowListLocked(displayId);
    246 
    247         if (mKeyguardGoingAway) {
    248             for (int i = windows.size() - 1; i >= 0; i--) {
    249                 WindowState win = windows.get(i);
    250                 if (!mPolicy.isKeyguardHostWindow(win.mAttrs)) {
    251                     continue;
    252                 }
    253                 final WindowStateAnimator winAnimator = win.mWinAnimator;
    254                 if ((win.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
    255                     if (!winAnimator.mAnimating) {
    256                         if (DEBUG_KEYGUARD) Slog.d(TAG,
    257                                 "updateWindowsLocked: creating delay animation");
    258 
    259                         // Create a new animation to delay until keyguard is gone on its own.
    260                         winAnimator.mAnimation = new AlphaAnimation(1.0f, 1.0f);
    261                         winAnimator.mAnimation.setDuration(KEYGUARD_ANIM_TIMEOUT_MS);
    262                         winAnimator.mAnimationIsEntrance = false;
    263                         winAnimator.mAnimationStartTime = -1;
    264                     }
    265                 } else {
    266                     if (DEBUG_KEYGUARD) Slog.d(TAG,
    267                             "updateWindowsLocked: StatusBar is no longer keyguard");
    268                     mKeyguardGoingAway = false;
    269                     winAnimator.clearAnimation();
    270                 }
    271                 break;
    272             }
    273         }
    274 
    275         mForceHiding = KEYGUARD_NOT_SHOWN;
    276 
    277         boolean wallpaperInUnForceHiding = false;
    278         boolean startingInUnForceHiding = false;
    279         ArrayList<WindowStateAnimator> unForceHiding = null;
    280         WindowState wallpaper = null;
    281         for (int i = windows.size() - 1; i >= 0; i--) {
    282             WindowState win = windows.get(i);
    283             WindowStateAnimator winAnimator = win.mWinAnimator;
    284             final int flags = win.mAttrs.flags;
    285             boolean canBeForceHidden = mPolicy.canBeForceHidden(win, win.mAttrs);
    286             boolean shouldBeForceHidden = shouldForceHide(win);
    287             if (winAnimator.mSurfaceControl != null) {
    288                 final boolean wasAnimating = winAnimator.mWasAnimating;
    289                 final boolean nowAnimating = winAnimator.stepAnimationLocked(mCurrentTime);
    290                 mAnimating |= nowAnimating;
    291 
    292                 if (WindowManagerService.DEBUG_WALLPAPER) {
    293                     Slog.v(TAG, win + ": wasAnimating=" + wasAnimating +
    294                             ", nowAnimating=" + nowAnimating);
    295                 }
    296 
    297                 if (wasAnimating && !winAnimator.mAnimating && mService.mWallpaperTarget == win) {
    298                     mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
    299                     setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
    300                             WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
    301                     if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
    302                         mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 2",
    303                                 getPendingLayoutChanges(Display.DEFAULT_DISPLAY));
    304                     }
    305                 }
    306 
    307                 if (mPolicy.isForceHiding(win.mAttrs)) {
    308                     if (!wasAnimating && nowAnimating) {
    309                         if (DEBUG_KEYGUARD || WindowManagerService.DEBUG_ANIM ||
    310                                 WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
    311                                 "Animation started that could impact force hide: " + win);
    312                         mBulkUpdateParams |= SET_FORCE_HIDING_CHANGED;
    313                         setPendingLayoutChanges(displayId,
    314                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
    315                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
    316                             mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 3",
    317                                     getPendingLayoutChanges(displayId));
    318                         }
    319                         mService.mFocusMayChange = true;
    320                     } else if (mKeyguardGoingAway && !nowAnimating) {
    321                         // Timeout!!
    322                         Slog.e(TAG, "Timeout waiting for animation to startup");
    323                         mPolicy.startKeyguardExitAnimation(0, 0);
    324                         mKeyguardGoingAway = false;
    325                     }
    326                     if (win.isReadyForDisplay()) {
    327                         if (nowAnimating) {
    328                             if (winAnimator.mAnimationIsEntrance) {
    329                                 mForceHiding = KEYGUARD_ANIMATING_IN;
    330                             } else {
    331                                 mForceHiding = KEYGUARD_ANIMATING_OUT;
    332                             }
    333                         } else {
    334                             mForceHiding = win.isDrawnLw() ? KEYGUARD_SHOWN : KEYGUARD_NOT_SHOWN;
    335                         }
    336                     }
    337                     if (DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
    338                             "Force hide " + forceHidingToString()
    339                             + " hasSurface=" + win.mHasSurface
    340                             + " policyVis=" + win.mPolicyVisibility
    341                             + " destroying=" + win.mDestroying
    342                             + " attHidden=" + win.mAttachedHidden
    343                             + " vis=" + win.mViewVisibility
    344                             + " hidden=" + win.mRootToken.hidden
    345                             + " anim=" + win.mWinAnimator.mAnimation);
    346                 } else if (canBeForceHidden) {
    347                     if (shouldBeForceHidden) {
    348                         if (!win.hideLw(false, false)) {
    349                             // Was already hidden
    350                             continue;
    351                         }
    352                         if (DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
    353                                 "Now policy hidden: " + win);
    354                     } else {
    355                         boolean applyExistingExitAnimation = mPostKeyguardExitAnimation != null
    356                                 && !winAnimator.mKeyguardGoingAwayAnimation
    357                                 && win.hasDrawnLw()
    358                                 && win.mAttachedWindow == null
    359                                 && mForceHiding != KEYGUARD_NOT_SHOWN;
    360 
    361                         // If the window is already showing and we don't need to apply an existing
    362                         // Keyguard exit animation, skip.
    363                         if (!win.showLw(false, false) && !applyExistingExitAnimation) {
    364                             continue;
    365                         }
    366                         final boolean visibleNow = win.isVisibleNow();
    367                         if (!visibleNow) {
    368                             // Couldn't really show, must showLw() again when win becomes visible.
    369                             win.hideLw(false, false);
    370                             continue;
    371                         }
    372                         if (DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
    373                                 "Now policy shown: " + win);
    374                         if ((mBulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0
    375                                 && win.mAttachedWindow == null) {
    376                             if (unForceHiding == null) {
    377                                 unForceHiding = new ArrayList<>();
    378                             }
    379                             unForceHiding.add(winAnimator);
    380                             if ((flags & FLAG_SHOW_WALLPAPER) != 0) {
    381                                 wallpaperInUnForceHiding = true;
    382                             }
    383                             if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
    384                                 startingInUnForceHiding = true;
    385                             }
    386                         } else if (applyExistingExitAnimation) {
    387                             // We're already in the middle of an animation. Use the existing
    388                             // animation to bring in this window.
    389                             if (DEBUG_KEYGUARD) Slog.v(TAG,
    390                                     "Applying existing Keyguard exit animation to new window: win="
    391                                             + win);
    392                             Animation a = mPolicy.createForceHideEnterAnimation(
    393                                     false, mKeyguardGoingAwayToNotificationShade);
    394                             winAnimator.setAnimation(a, mPostKeyguardExitAnimation.getStartTime());
    395                             winAnimator.mKeyguardGoingAwayAnimation = true;
    396                         }
    397                         final WindowState currentFocus = mService.mCurrentFocus;
    398                         if (currentFocus == null || currentFocus.mLayer < win.mLayer) {
    399                             // We are showing on top of the current
    400                             // focus, so re-evaluate focus to make
    401                             // sure it is correct.
    402                             if (WindowManagerService.DEBUG_FOCUS_LIGHT) Slog.v(TAG,
    403                                     "updateWindowsLocked: setting mFocusMayChange true");
    404                             mService.mFocusMayChange = true;
    405                         }
    406                     }
    407                     if ((flags & FLAG_SHOW_WALLPAPER) != 0) {
    408                         mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
    409                         setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
    410                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
    411                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
    412                             mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 4",
    413                                     getPendingLayoutChanges(Display.DEFAULT_DISPLAY));
    414                         }
    415                     }
    416                 }
    417             }
    418 
    419             // If the window doesn't have a surface, the only thing we care about is the correct
    420             // policy visibility.
    421             else if (canBeForceHidden) {
    422                 if (shouldBeForceHidden) {
    423                     win.hideLw(false, false);
    424                 } else {
    425                     win.showLw(false, false);
    426                 }
    427             }
    428 
    429             final AppWindowToken atoken = win.mAppToken;
    430             if (winAnimator.mDrawState == WindowStateAnimator.READY_TO_SHOW) {
    431                 if (atoken == null || atoken.allDrawn) {
    432                     if (winAnimator.performShowLocked()) {
    433                         setPendingLayoutChanges(displayId,
    434                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
    435                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
    436                             mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 5",
    437                                     getPendingLayoutChanges(displayId));
    438                         }
    439                     }
    440                 }
    441             }
    442             final AppWindowAnimator appAnimator = winAnimator.mAppAnimator;
    443             if (appAnimator != null && appAnimator.thumbnail != null) {
    444                 if (appAnimator.thumbnailTransactionSeq != mAnimTransactionSequence) {
    445                     appAnimator.thumbnailTransactionSeq = mAnimTransactionSequence;
    446                     appAnimator.thumbnailLayer = 0;
    447                 }
    448                 if (appAnimator.thumbnailLayer < winAnimator.mAnimLayer) {
    449                     appAnimator.thumbnailLayer = winAnimator.mAnimLayer;
    450                 }
    451             }
    452             if (win.mIsWallpaper) {
    453                 wallpaper = win;
    454             }
    455         } // end forall windows
    456 
    457         // If we have windows that are being show due to them no longer
    458         // being force-hidden, apply the appropriate animation to them if animations are not
    459         // disabled.
    460         if (unForceHiding != null) {
    461             if (!mKeyguardGoingAwayDisableWindowAnimations) {
    462                 boolean first = true;
    463                 for (int i=unForceHiding.size()-1; i>=0; i--) {
    464                     final WindowStateAnimator winAnimator = unForceHiding.get(i);
    465                     Animation a = mPolicy.createForceHideEnterAnimation(
    466                             wallpaperInUnForceHiding && !startingInUnForceHiding,
    467                             mKeyguardGoingAwayToNotificationShade);
    468                     if (a != null) {
    469                         if (DEBUG_KEYGUARD) Slog.v(TAG,
    470                                 "Starting keyguard exit animation on window " + winAnimator.mWin);
    471                         winAnimator.setAnimation(a);
    472                         winAnimator.mKeyguardGoingAwayAnimation = true;
    473                         if (first) {
    474                             mPostKeyguardExitAnimation = a;
    475                             mPostKeyguardExitAnimation.setStartTime(mCurrentTime);
    476                             first = false;
    477                         }
    478                     }
    479                 }
    480             } else if (mKeyguardGoingAway) {
    481                 mPolicy.startKeyguardExitAnimation(mCurrentTime, 0 /* duration */);
    482                 mKeyguardGoingAway = false;
    483             }
    484 
    485 
    486             // Wallpaper is going away in un-force-hide motion, animate it as well.
    487             if (!wallpaperInUnForceHiding && wallpaper != null
    488                     && !mKeyguardGoingAwayDisableWindowAnimations) {
    489                 if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: wallpaper animating away");
    490                 Animation a = mPolicy.createForceHideWallpaperExitAnimation(
    491                         mKeyguardGoingAwayToNotificationShade);
    492                 if (a != null) {
    493                     wallpaper.mWinAnimator.setAnimation(a);
    494                 }
    495             }
    496         }
    497 
    498         if (mPostKeyguardExitAnimation != null) {
    499             // We're in the midst of a keyguard exit animation.
    500             if (mKeyguardGoingAway) {
    501                 mPolicy.startKeyguardExitAnimation(mCurrentTime +
    502                         mPostKeyguardExitAnimation.getStartOffset(),
    503                         mPostKeyguardExitAnimation.getDuration());
    504                 mKeyguardGoingAway = false;
    505             } else if (mCurrentTime - mPostKeyguardExitAnimation.getStartTime()
    506                     > mPostKeyguardExitAnimation.getDuration()) {
    507                 // Done with the animation, reset.
    508                 if (DEBUG_KEYGUARD) Slog.v(TAG, "Done with Keyguard exit animations.");
    509                 mPostKeyguardExitAnimation = null;
    510             }
    511         }
    512     }
    513 
    514     private void updateWallpaperLocked(int displayId) {
    515         mService.getDisplayContentLocked(displayId).resetAnimationBackgroundAnimator();
    516 
    517         final WindowList windows = mService.getWindowListLocked(displayId);
    518         WindowState detachedWallpaper = null;
    519 
    520         for (int i = windows.size() - 1; i >= 0; i--) {
    521             final WindowState win = windows.get(i);
    522             WindowStateAnimator winAnimator = win.mWinAnimator;
    523             if (winAnimator.mSurfaceControl == null) {
    524                 continue;
    525             }
    526 
    527             final int flags = win.mAttrs.flags;
    528 
    529             // If this window is animating, make a note that we have
    530             // an animating window and take care of a request to run
    531             // a detached wallpaper animation.
    532             if (winAnimator.mAnimating) {
    533                 if (winAnimator.mAnimation != null) {
    534                     if ((flags & FLAG_SHOW_WALLPAPER) != 0
    535                             && winAnimator.mAnimation.getDetachWallpaper()) {
    536                         detachedWallpaper = win;
    537                     }
    538                     final int color = winAnimator.mAnimation.getBackgroundColor();
    539                     if (color != 0) {
    540                         final TaskStack stack = win.getStack();
    541                         if (stack != null) {
    542                             stack.setAnimationBackground(winAnimator, color);
    543                         }
    544                     }
    545                 }
    546                 mAnimating = true;
    547             }
    548 
    549             // If this window's app token is running a detached wallpaper
    550             // animation, make a note so we can ensure the wallpaper is
    551             // displayed behind it.
    552             final AppWindowAnimator appAnimator = winAnimator.mAppAnimator;
    553             if (appAnimator != null && appAnimator.animation != null
    554                     && appAnimator.animating) {
    555                 if ((flags & FLAG_SHOW_WALLPAPER) != 0
    556                         && appAnimator.animation.getDetachWallpaper()) {
    557                     detachedWallpaper = win;
    558                 }
    559 
    560                 final int color = appAnimator.animation.getBackgroundColor();
    561                 if (color != 0) {
    562                     final TaskStack stack = win.getStack();
    563                     if (stack != null) {
    564                         stack.setAnimationBackground(winAnimator, color);
    565                     }
    566                 }
    567             }
    568         } // end forall windows
    569 
    570         if (mWindowDetachedWallpaper != detachedWallpaper) {
    571             if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
    572                     "Detached wallpaper changed from " + mWindowDetachedWallpaper
    573                     + " to " + detachedWallpaper);
    574             mWindowDetachedWallpaper = detachedWallpaper;
    575             mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
    576         }
    577     }
    578 
    579     /** See if any windows have been drawn, so they (and others associated with them) can now be
    580      *  shown. */
    581     private void testTokenMayBeDrawnLocked(int displayId) {
    582         // See if any windows have been drawn, so they (and others
    583         // associated with them) can now be shown.
    584         final ArrayList<Task> tasks = mService.getDisplayContentLocked(displayId).getTasks();
    585         final int numTasks = tasks.size();
    586         for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
    587             final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
    588             final int numTokens = tokens.size();
    589             for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
    590                 final AppWindowToken wtoken = tokens.get(tokenNdx);
    591                 AppWindowAnimator appAnimator = wtoken.mAppAnimator;
    592                 final boolean allDrawn = wtoken.allDrawn;
    593                 if (allDrawn != appAnimator.allDrawn) {
    594                     appAnimator.allDrawn = allDrawn;
    595                     if (allDrawn) {
    596                         // The token has now changed state to having all
    597                         // windows shown...  what to do, what to do?
    598                         if (appAnimator.freezingScreen) {
    599                             appAnimator.showAllWindowsLocked();
    600                             mService.unsetAppFreezingScreenLocked(wtoken, false, true);
    601                             if (WindowManagerService.DEBUG_ORIENTATION) Slog.i(TAG,
    602                                     "Setting mOrientationChangeComplete=true because wtoken "
    603                                     + wtoken + " numInteresting=" + wtoken.numInterestingWindows
    604                                     + " numDrawn=" + wtoken.numDrawnWindows);
    605                             // This will set mOrientationChangeComplete and cause a pass through layout.
    606                             setAppLayoutChanges(appAnimator,
    607                                     WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
    608                                     "testTokenMayBeDrawnLocked: freezingScreen");
    609                         } else {
    610                             setAppLayoutChanges(appAnimator,
    611                                     WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
    612                                     "testTokenMayBeDrawnLocked");
    613 
    614                             // We can now show all of the drawn windows!
    615                             if (!mService.mOpeningApps.contains(wtoken)) {
    616                                 mAnimating |= appAnimator.showAllWindowsLocked();
    617                             }
    618                         }
    619                     }
    620                 }
    621             }
    622         }
    623     }
    624 
    625 
    626     /** Locked on mService.mWindowMap. */
    627     private void animateLocked() {
    628         if (!mInitialized) {
    629             return;
    630         }
    631 
    632         mCurrentTime = SystemClock.uptimeMillis();
    633         mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
    634         boolean wasAnimating = mAnimating;
    635         mAnimating = false;
    636         if (WindowManagerService.DEBUG_WINDOW_TRACE) {
    637             Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
    638         }
    639 
    640         if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(
    641                 TAG, ">>> OPEN TRANSACTION animateLocked");
    642         SurfaceControl.openTransaction();
    643         SurfaceControl.setAnimationTransaction();
    644         try {
    645             final int numDisplays = mDisplayContentsAnimators.size();
    646             for (int i = 0; i < numDisplays; i++) {
    647                 final int displayId = mDisplayContentsAnimators.keyAt(i);
    648                 updateAppWindowsLocked(displayId);
    649                 DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
    650 
    651                 final ScreenRotationAnimation screenRotationAnimation =
    652                         displayAnimator.mScreenRotationAnimation;
    653                 if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
    654                     if (screenRotationAnimation.stepAnimationLocked(mCurrentTime)) {
    655                         mAnimating = true;
    656                     } else {
    657                         mBulkUpdateParams |= SET_UPDATE_ROTATION;
    658                         screenRotationAnimation.kill();
    659                         displayAnimator.mScreenRotationAnimation = null;
    660 
    661                         //TODO (multidisplay): Accessibility supported only for the default display.
    662                         if (mService.mAccessibilityController != null
    663                                 && displayId == Display.DEFAULT_DISPLAY) {
    664                             // We just finished rotation animation which means we did not
    665                             // anounce the rotation and waited for it to end, announce now.
    666                             mService.mAccessibilityController.onRotationChangedLocked(
    667                                     mService.getDefaultDisplayContentLocked(), mService.mRotation);
    668                         }
    669                     }
    670                 }
    671 
    672                 // Update animations of all applications, including those
    673                 // associated with exiting/removed apps
    674                 updateWindowsLocked(displayId);
    675                 updateWallpaperLocked(displayId);
    676 
    677                 final WindowList windows = mService.getWindowListLocked(displayId);
    678                 final int N = windows.size();
    679                 for (int j = 0; j < N; j++) {
    680                     windows.get(j).mWinAnimator.prepareSurfaceLocked(true);
    681                 }
    682             }
    683 
    684             for (int i = 0; i < numDisplays; i++) {
    685                 final int displayId = mDisplayContentsAnimators.keyAt(i);
    686 
    687                 testTokenMayBeDrawnLocked(displayId);
    688 
    689                 final ScreenRotationAnimation screenRotationAnimation =
    690                         mDisplayContentsAnimators.valueAt(i).mScreenRotationAnimation;
    691                 if (screenRotationAnimation != null) {
    692                     screenRotationAnimation.updateSurfacesInTransaction();
    693                 }
    694 
    695                 mAnimating |= mService.getDisplayContentLocked(displayId).animateDimLayers();
    696 
    697                 //TODO (multidisplay): Magnification is supported only for the default display.
    698                 if (mService.mAccessibilityController != null
    699                         && displayId == Display.DEFAULT_DISPLAY) {
    700                     mService.mAccessibilityController.drawMagnifiedRegionBorderIfNeededLocked();
    701                 }
    702             }
    703 
    704             if (mAnimating) {
    705                 mService.scheduleAnimationLocked();
    706             }
    707 
    708             mService.setFocusedStackLayer();
    709 
    710             if (mService.mWatermark != null) {
    711                 mService.mWatermark.drawIfNeeded();
    712             }
    713         } catch (RuntimeException e) {
    714             Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
    715         } finally {
    716             SurfaceControl.closeTransaction();
    717             if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(
    718                     TAG, "<<< CLOSE TRANSACTION animateLocked");
    719         }
    720 
    721         boolean hasPendingLayoutChanges = false;
    722         final int numDisplays = mService.mDisplayContents.size();
    723         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
    724             final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);
    725             final int pendingChanges = getPendingLayoutChanges(displayContent.getDisplayId());
    726             if ((pendingChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
    727                 mBulkUpdateParams |= SET_WALLPAPER_ACTION_PENDING;
    728             }
    729             if (pendingChanges != 0) {
    730                 hasPendingLayoutChanges = true;
    731             }
    732         }
    733 
    734         boolean doRequest = false;
    735         if (mBulkUpdateParams != 0) {
    736             doRequest = mService.copyAnimToLayoutParamsLocked();
    737         }
    738 
    739         if (hasPendingLayoutChanges || doRequest) {
    740             mService.requestTraversalLocked();
    741         }
    742 
    743         if (!mAnimating && wasAnimating) {
    744             mService.requestTraversalLocked();
    745         }
    746         if (WindowManagerService.DEBUG_WINDOW_TRACE) {
    747             Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating
    748                 + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams)
    749                 + " mPendingLayoutChanges(DEFAULT_DISPLAY)="
    750                 + Integer.toHexString(getPendingLayoutChanges(Display.DEFAULT_DISPLAY)));
    751         }
    752     }
    753 
    754     static String bulkUpdateParamsToString(int bulkUpdateParams) {
    755         StringBuilder builder = new StringBuilder(128);
    756         if ((bulkUpdateParams & LayoutFields.SET_UPDATE_ROTATION) != 0) {
    757             builder.append(" UPDATE_ROTATION");
    758         }
    759         if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) {
    760             builder.append(" WALLPAPER_MAY_CHANGE");
    761         }
    762         if ((bulkUpdateParams & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) {
    763             builder.append(" FORCE_HIDING_CHANGED");
    764         }
    765         if ((bulkUpdateParams & LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE) != 0) {
    766             builder.append(" ORIENTATION_CHANGE_COMPLETE");
    767         }
    768         if ((bulkUpdateParams & LayoutFields.SET_TURN_ON_SCREEN) != 0) {
    769             builder.append(" TURN_ON_SCREEN");
    770         }
    771         return builder.toString();
    772     }
    773 
    774     public void dumpLocked(PrintWriter pw, String prefix, boolean dumpAll) {
    775         final String subPrefix = "  " + prefix;
    776         final String subSubPrefix = "  " + subPrefix;
    777 
    778         for (int i = 0; i < mDisplayContentsAnimators.size(); i++) {
    779             pw.print(prefix); pw.print("DisplayContentsAnimator #");
    780                     pw.print(mDisplayContentsAnimators.keyAt(i));
    781                     pw.println(":");
    782             DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
    783             final WindowList windows =
    784                     mService.getWindowListLocked(mDisplayContentsAnimators.keyAt(i));
    785             final int N = windows.size();
    786             for (int j = 0; j < N; j++) {
    787                 WindowStateAnimator wanim = windows.get(j).mWinAnimator;
    788                 pw.print(subPrefix); pw.print("Window #"); pw.print(j);
    789                         pw.print(": "); pw.println(wanim);
    790             }
    791             if (displayAnimator.mScreenRotationAnimation != null) {
    792                 pw.print(subPrefix); pw.println("mScreenRotationAnimation:");
    793                 displayAnimator.mScreenRotationAnimation.printTo(subSubPrefix, pw);
    794             } else if (dumpAll) {
    795                 pw.print(subPrefix); pw.println("no ScreenRotationAnimation ");
    796             }
    797         }
    798 
    799         pw.println();
    800 
    801         if (dumpAll) {
    802             pw.print(prefix); pw.print("mAnimTransactionSequence=");
    803                     pw.print(mAnimTransactionSequence);
    804                     pw.print(" mForceHiding="); pw.println(forceHidingToString());
    805             pw.print(prefix); pw.print("mCurrentTime=");
    806                     pw.println(TimeUtils.formatUptime(mCurrentTime));
    807         }
    808         if (mBulkUpdateParams != 0) {
    809             pw.print(prefix); pw.print("mBulkUpdateParams=0x");
    810                     pw.print(Integer.toHexString(mBulkUpdateParams));
    811                     pw.println(bulkUpdateParamsToString(mBulkUpdateParams));
    812         }
    813         if (mWindowDetachedWallpaper != null) {
    814             pw.print(prefix); pw.print("mWindowDetachedWallpaper=");
    815                 pw.println(mWindowDetachedWallpaper);
    816         }
    817         if (mUniverseBackground != null) {
    818             pw.print(prefix); pw.print("mUniverseBackground="); pw.print(mUniverseBackground);
    819                     pw.print(" mAboveUniverseLayer="); pw.println(mAboveUniverseLayer);
    820         }
    821     }
    822 
    823     int getPendingLayoutChanges(final int displayId) {
    824         if (displayId < 0) {
    825             return 0;
    826         }
    827         DisplayContent displayContent = mService.getDisplayContentLocked(displayId);
    828         return (displayContent != null) ? displayContent.pendingLayoutChanges : 0;
    829     }
    830 
    831     void setPendingLayoutChanges(final int displayId, final int changes) {
    832         if (displayId >= 0) {
    833             DisplayContent displayContent = mService.getDisplayContentLocked(displayId);
    834             if (displayContent != null) {
    835                 displayContent.pendingLayoutChanges |= changes;
    836             }
    837         }
    838     }
    839 
    840     void setAppLayoutChanges(final AppWindowAnimator appAnimator, final int changes, String s) {
    841         // Used to track which displays layout changes have been done.
    842         SparseIntArray displays = new SparseIntArray(2);
    843         WindowList windows = appAnimator.mAppToken.allAppWindows;
    844         for (int i = windows.size() - 1; i >= 0; i--) {
    845             final int displayId = windows.get(i).getDisplayId();
    846             if (displayId >= 0 && displays.indexOfKey(displayId) < 0) {
    847                 setPendingLayoutChanges(displayId, changes);
    848                 if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
    849                     mService.debugLayoutRepeats(s, getPendingLayoutChanges(displayId));
    850                 }
    851                 // Keep from processing this display again.
    852                 displays.put(displayId, changes);
    853             }
    854         }
    855     }
    856 
    857     private DisplayContentsAnimator getDisplayContentsAnimatorLocked(int displayId) {
    858         DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
    859         if (displayAnimator == null) {
    860             displayAnimator = new DisplayContentsAnimator();
    861             mDisplayContentsAnimators.put(displayId, displayAnimator);
    862         }
    863         return displayAnimator;
    864     }
    865 
    866     void setScreenRotationAnimationLocked(int displayId, ScreenRotationAnimation animation) {
    867         if (displayId >= 0) {
    868             getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation = animation;
    869         }
    870     }
    871 
    872     ScreenRotationAnimation getScreenRotationAnimationLocked(int displayId) {
    873         if (displayId < 0) {
    874             return null;
    875         }
    876         return getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation;
    877     }
    878 
    879     private class DisplayContentsAnimator {
    880         ScreenRotationAnimation mScreenRotationAnimation = null;
    881     }
    882 }
    883