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