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