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