1// Copyright 2012 Google Inc. All Rights Reserved.
2
3package com.android.server.wm;
4
5import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
6import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
7
8import static com.android.server.wm.WindowManagerService.LayoutFields.SET_UPDATE_ROTATION;
9import static com.android.server.wm.WindowManagerService.LayoutFields.SET_WALLPAPER_MAY_CHANGE;
10import static com.android.server.wm.WindowManagerService.LayoutFields.SET_FORCE_HIDING_CHANGED;
11import static com.android.server.wm.WindowManagerService.LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE;
12
13import static com.android.server.wm.WindowManagerService.H.UPDATE_ANIM_PARAMETERS;
14
15import android.content.Context;
16import android.os.Debug;
17import android.os.SystemClock;
18import android.util.Log;
19import android.util.Slog;
20import android.util.SparseArray;
21import android.util.SparseIntArray;
22import android.util.TimeUtils;
23import android.view.Display;
24import android.view.Surface;
25import android.view.WindowManagerPolicy;
26import android.view.animation.Animation;
27
28import com.android.server.wm.WindowManagerService.AppWindowAnimParams;
29import com.android.server.wm.WindowManagerService.LayoutFields;
30import com.android.server.wm.WindowManagerService.LayoutToAnimatorParams;
31
32import java.io.PrintWriter;
33import java.util.ArrayList;
34
35/**
36 * Singleton class that carries out the animations and Surface operations in a separate task
37 * on behalf of WindowManagerService.
38 */
39public class WindowAnimator {
40    private static final String TAG = "WindowAnimator";
41
42    final WindowManagerService mService;
43    final Context mContext;
44    final WindowManagerPolicy mPolicy;
45
46    boolean mAnimating;
47
48    final Runnable mAnimationRunnable;
49
50    int mAdjResult;
51
52    // Layout changes for individual Displays. Indexed by displayId.
53    SparseIntArray mPendingLayoutChanges = new SparseIntArray();
54
55    // TODO: Assign these from each iteration through DisplayContent. Only valid between loops.
56    /** Overall window dimensions */
57    int mDw, mDh;
58
59    /** Interior window dimensions */
60    int mInnerDw, mInnerDh;
61
62    /** Time of current animation step. Reset on each iteration */
63    long mCurrentTime;
64
65    /** Skip repeated AppWindowTokens initialization. Note that AppWindowsToken's version of this
66     * is a long initialized to Long.MIN_VALUE so that it doesn't match this value on startup. */
67    private int mAnimTransactionSequence;
68
69    // Window currently running an animation that has requested it be detached
70    // from the wallpaper.  This means we need to ensure the wallpaper is
71    // visible behind it in case it animates in a way that would allow it to be
72    // seen. If multiple windows satisfy this, use the lowest window.
73    WindowState mWindowDetachedWallpaper = null;
74
75    WindowStateAnimator mUniverseBackground = null;
76    int mAboveUniverseLayer = 0;
77
78    int mBulkUpdateParams = 0;
79
80    SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators =
81            new SparseArray<WindowAnimator.DisplayContentsAnimator>();
82
83    static final int WALLPAPER_ACTION_PENDING = 1;
84    int mPendingActions;
85
86    WindowState mWallpaperTarget = null;
87    AppWindowAnimator mWpAppAnimator = null;
88    WindowState mLowerWallpaperTarget = null;
89    WindowState mUpperWallpaperTarget = null;
90
91    ArrayList<AppWindowAnimator> mAppAnimators = new ArrayList<AppWindowAnimator>();
92
93    ArrayList<WindowToken> mWallpaperTokens = new ArrayList<WindowToken>();
94
95    /** Parameters being passed from this into mService. */
96    static class AnimatorToLayoutParams {
97        boolean mUpdateQueued;
98        int mBulkUpdateParams;
99        SparseIntArray mPendingLayoutChanges;
100        WindowState mWindowDetachedWallpaper;
101    }
102    /** Do not modify unless holding mService.mWindowMap or this and mAnimToLayout in that order */
103    final AnimatorToLayoutParams mAnimToLayout = new AnimatorToLayoutParams();
104
105    boolean mInitialized = false;
106
107    // forceHiding states.
108    static final int KEYGUARD_NOT_SHOWN     = 0;
109    static final int KEYGUARD_ANIMATING_IN  = 1;
110    static final int KEYGUARD_SHOWN         = 2;
111    static final int KEYGUARD_ANIMATING_OUT = 3;
112    int mForceHiding = KEYGUARD_NOT_SHOWN;
113
114    private String forceHidingToString() {
115        switch (mForceHiding) {
116            case KEYGUARD_NOT_SHOWN:    return "KEYGUARD_NOT_SHOWN";
117            case KEYGUARD_ANIMATING_IN: return "KEYGUARD_ANIMATING_IN";
118            case KEYGUARD_SHOWN:        return "KEYGUARD_SHOWN";
119            case KEYGUARD_ANIMATING_OUT:return "KEYGUARD_ANIMATING_OUT";
120            default: return "KEYGUARD STATE UNKNOWN " + mForceHiding;
121        }
122    }
123
124    WindowAnimator(final WindowManagerService service) {
125        mService = service;
126        mContext = service.mContext;
127        mPolicy = service.mPolicy;
128
129        mAnimationRunnable = new Runnable() {
130            @Override
131            public void run() {
132                // TODO(cmautner): When full isolation is achieved for animation, the first lock
133                // goes away and only the WindowAnimator.this remains.
134                synchronized(mService.mWindowMap) {
135                    synchronized(WindowAnimator.this) {
136                        copyLayoutToAnimParamsLocked();
137                        animateLocked();
138                    }
139                }
140            }
141        };
142    }
143
144    void addDisplayLocked(final int displayId) {
145        // Create the DisplayContentsAnimator object by retrieving it.
146        getDisplayContentsAnimatorLocked(displayId);
147        if (displayId == Display.DEFAULT_DISPLAY) {
148            mInitialized = true;
149        }
150    }
151
152    void removeDisplayLocked(final int displayId) {
153        final DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
154        if (displayAnimator != null) {
155            if (displayAnimator.mWindowAnimationBackgroundSurface != null) {
156                displayAnimator.mWindowAnimationBackgroundSurface.kill();
157                displayAnimator.mWindowAnimationBackgroundSurface = null;
158            }
159            if (displayAnimator.mScreenRotationAnimation != null) {
160                displayAnimator.mScreenRotationAnimation.kill();
161                displayAnimator.mScreenRotationAnimation = null;
162            }
163            if (displayAnimator.mDimAnimator != null) {
164                displayAnimator.mDimAnimator.kill();
165                displayAnimator.mDimAnimator = null;
166            }
167        }
168
169        mDisplayContentsAnimators.delete(displayId);
170    }
171
172    /** Locked on mAnimToLayout */
173    void updateAnimToLayoutLocked() {
174        final AnimatorToLayoutParams animToLayout = mAnimToLayout;
175        synchronized (animToLayout) {
176            animToLayout.mBulkUpdateParams = mBulkUpdateParams;
177            animToLayout.mPendingLayoutChanges = mPendingLayoutChanges.clone();
178            animToLayout.mWindowDetachedWallpaper = mWindowDetachedWallpaper;
179
180            if (!animToLayout.mUpdateQueued) {
181                animToLayout.mUpdateQueued = true;
182                mService.mH.sendMessage(mService.mH.obtainMessage(UPDATE_ANIM_PARAMETERS));
183            }
184        }
185    }
186
187    /** Copy all WindowManagerService params into local params here. Locked on 'this'. */
188    private void copyLayoutToAnimParamsLocked() {
189        final LayoutToAnimatorParams layoutToAnim = mService.mLayoutToAnim;
190        synchronized(layoutToAnim) {
191            layoutToAnim.mAnimationScheduled = false;
192
193            if (!layoutToAnim.mParamsModified) {
194                return;
195            }
196            layoutToAnim.mParamsModified = false;
197
198            if ((layoutToAnim.mChanges & LayoutToAnimatorParams.WALLPAPER_TOKENS_CHANGED) != 0) {
199                layoutToAnim.mChanges &= ~LayoutToAnimatorParams.WALLPAPER_TOKENS_CHANGED;
200                mWallpaperTokens = new ArrayList<WindowToken>(layoutToAnim.mWallpaperTokens);
201            }
202
203            if (WindowManagerService.DEBUG_WALLPAPER_LIGHT) {
204                if (mWallpaperTarget != layoutToAnim.mWallpaperTarget
205                        || mLowerWallpaperTarget != layoutToAnim.mLowerWallpaperTarget
206                        || mUpperWallpaperTarget != layoutToAnim.mUpperWallpaperTarget) {
207                    Slog.d(TAG, "Pulling anim wallpaper: target=" + layoutToAnim.mWallpaperTarget
208                            + " lower=" + layoutToAnim.mLowerWallpaperTarget + " upper="
209                            + layoutToAnim.mUpperWallpaperTarget);
210                }
211            }
212            mWallpaperTarget = layoutToAnim.mWallpaperTarget;
213            mWpAppAnimator = mWallpaperTarget == null
214                    ? null : mWallpaperTarget.mAppToken == null
215                            ? null : mWallpaperTarget.mAppToken.mAppAnimator;
216            mLowerWallpaperTarget = layoutToAnim.mLowerWallpaperTarget;
217            mUpperWallpaperTarget = layoutToAnim.mUpperWallpaperTarget;
218
219            // Set the new DimAnimator params.
220            final int numDisplays = mDisplayContentsAnimators.size();
221            for (int i = 0; i < numDisplays; i++) {
222                final int displayId = mDisplayContentsAnimators.keyAt(i);
223                DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
224
225                displayAnimator.mWinAnimators.clear();
226                final WinAnimatorList winAnimators = layoutToAnim.mWinAnimatorLists.get(displayId);
227                if (winAnimators != null) {
228                    displayAnimator.mWinAnimators.addAll(winAnimators);
229                }
230
231                DimAnimator.Parameters dimParams = layoutToAnim.mDimParams.get(displayId);
232                if (dimParams == null) {
233                    displayAnimator.mDimParams = null;
234                } else {
235                    final WindowStateAnimator newWinAnimator = dimParams.mDimWinAnimator;
236
237                    // Only set dim params on the highest dimmed layer.
238                    final WindowStateAnimator existingDimWinAnimator =
239                            displayAnimator.mDimParams == null ?
240                                    null : displayAnimator.mDimParams.mDimWinAnimator;
241                    // Don't turn on for an unshown surface, or for any layer but the highest
242                    // dimmed layer.
243                    if (newWinAnimator.mSurfaceShown && (existingDimWinAnimator == null
244                            || !existingDimWinAnimator.mSurfaceShown
245                            || existingDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) {
246                        displayAnimator.mDimParams = new DimAnimator.Parameters(dimParams);
247                    }
248                }
249            }
250
251            mAppAnimators.clear();
252            final int N = layoutToAnim.mAppWindowAnimParams.size();
253            for (int i = 0; i < N; i++) {
254                final AppWindowAnimParams params = layoutToAnim.mAppWindowAnimParams.get(i);
255                AppWindowAnimator appAnimator = params.mAppAnimator;
256                appAnimator.mAllAppWinAnimators.clear();
257                appAnimator.mAllAppWinAnimators.addAll(params.mWinAnimators);
258                mAppAnimators.add(appAnimator);
259            }
260        }
261    }
262
263    void hideWallpapersLocked(final WindowState w, boolean fromAnimator) {
264        // There is an issue where this function can be called either from
265        // the animation or the layout side of the window manager.  The problem
266        // is that if it is called from the layout side, we may not yet have
267        // propagated the current layout wallpaper state over into the animation
268        // state.  If that is the case, we can do bad things like hide the
269        // wallpaper when we had just made it shown because the animation side
270        // doesn't yet see that there is now a wallpaper target.  As a temporary
271        // work-around, we tell the function here which side of the window manager
272        // is calling so it can use the right state.
273        if (fromAnimator) {
274            hideWallpapersLocked(w, mWallpaperTarget, mLowerWallpaperTarget, mWallpaperTokens);
275        } else {
276            hideWallpapersLocked(w, mService.mWallpaperTarget,
277                    mService.mLowerWallpaperTarget, mService.mWallpaperTokens);
278        }
279    }
280
281    void hideWallpapersLocked(final WindowState w, final WindowState wallpaperTarget,
282            final WindowState lowerWallpaperTarget, final ArrayList<WindowToken> wallpaperTokens) {
283        if ((wallpaperTarget == w && lowerWallpaperTarget == null) || wallpaperTarget == null) {
284            final int numTokens = wallpaperTokens.size();
285            for (int i = numTokens - 1; i >= 0; i--) {
286                final WindowToken token = wallpaperTokens.get(i);
287                final int numWindows = token.windows.size();
288                for (int j = numWindows - 1; j >= 0; j--) {
289                    final WindowState wallpaper = token.windows.get(j);
290                    final WindowStateAnimator winAnimator = wallpaper.mWinAnimator;
291                    if (!winAnimator.mLastHidden) {
292                        winAnimator.hide();
293                        mService.dispatchWallpaperVisibility(wallpaper, false);
294                        setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
295                                WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
296                    }
297                }
298                if (WindowManagerService.DEBUG_WALLPAPER_LIGHT && !token.hidden) Slog.d(TAG,
299                        "Hiding wallpaper " + token + " from " + w
300                        + " target=" + wallpaperTarget + " lower=" + lowerWallpaperTarget
301                        + "\n" + Debug.getCallers(5, "  "));
302                token.hidden = true;
303            }
304        }
305    }
306
307    private void updateAppWindowsLocked() {
308        int i;
309        final int NAT = mAppAnimators.size();
310        for (i=0; i<NAT; i++) {
311            final AppWindowAnimator appAnimator = mAppAnimators.get(i);
312            final boolean wasAnimating = appAnimator.animation != null
313                    && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
314            if (appAnimator.stepAnimationLocked(mCurrentTime, mInnerDw, mInnerDh)) {
315                mAnimating = true;
316            } else if (wasAnimating) {
317                // stopped animating, do one more pass through the layout
318                setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
319                        "appToken " + appAnimator.mAppToken + " done");
320                if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
321                        "updateWindowsApps...: done animating " + appAnimator.mAppToken);
322            }
323        }
324
325        final int NEAT = mService.mExitingAppTokens.size();
326        for (i=0; i<NEAT; i++) {
327            final AppWindowAnimator appAnimator = mService.mExitingAppTokens.get(i).mAppAnimator;
328            final boolean wasAnimating = appAnimator.animation != null
329                    && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
330            if (appAnimator.stepAnimationLocked(mCurrentTime, mInnerDw, mInnerDh)) {
331                mAnimating = true;
332            } else if (wasAnimating) {
333                // stopped animating, do one more pass through the layout
334                setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
335                    "exiting appToken " + appAnimator.mAppToken + " done");
336                if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
337                        "updateWindowsApps...: done animating exiting " + appAnimator.mAppToken);
338            }
339        }
340    }
341
342    private void updateWindowsLocked(final int displayId) {
343        ++mAnimTransactionSequence;
344
345        final WinAnimatorList winAnimatorList =
346                getDisplayContentsAnimatorLocked(displayId).mWinAnimators;
347        ArrayList<WindowStateAnimator> unForceHiding = null;
348        boolean wallpaperInUnForceHiding = false;
349        mForceHiding = KEYGUARD_NOT_SHOWN;
350
351        for (int i = winAnimatorList.size() - 1; i >= 0; i--) {
352            WindowStateAnimator winAnimator = winAnimatorList.get(i);
353            WindowState win = winAnimator.mWin;
354            final int flags = winAnimator.mAttrFlags;
355
356            if (winAnimator.mSurface != null) {
357                final boolean wasAnimating = winAnimator.mWasAnimating;
358                final boolean nowAnimating = winAnimator.stepAnimationLocked(mCurrentTime);
359
360                if (WindowManagerService.DEBUG_WALLPAPER) {
361                    Slog.v(TAG, win + ": wasAnimating=" + wasAnimating +
362                            ", nowAnimating=" + nowAnimating);
363                }
364
365                if (wasAnimating && !winAnimator.mAnimating && mWallpaperTarget == win) {
366                    mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
367                    setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
368                            WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
369                    if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
370                        mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 2",
371                            mPendingLayoutChanges.get(Display.DEFAULT_DISPLAY));
372                    }
373                }
374
375                if (mPolicy.doesForceHide(win, win.mAttrs)) {
376                    if (!wasAnimating && nowAnimating) {
377                        if (WindowManagerService.DEBUG_ANIM ||
378                                WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
379                                "Animation started that could impact force hide: " + win);
380                        mBulkUpdateParams |= SET_FORCE_HIDING_CHANGED;
381                        setPendingLayoutChanges(displayId,
382                                WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
383                        if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
384                            mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 3",
385                                mPendingLayoutChanges.get(displayId));
386                        }
387                        mService.mFocusMayChange = true;
388                    }
389                    if (win.isReadyForDisplay()) {
390                        if (nowAnimating) {
391                            if (winAnimator.mAnimationIsEntrance) {
392                                mForceHiding = KEYGUARD_ANIMATING_IN;
393                            } else {
394                                mForceHiding = KEYGUARD_ANIMATING_OUT;
395                            }
396                        } else {
397                            mForceHiding = KEYGUARD_SHOWN;
398                        }
399                    }
400                    if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
401                            "Force hide " + mForceHiding
402                            + " hasSurface=" + win.mHasSurface
403                            + " policyVis=" + win.mPolicyVisibility
404                            + " destroying=" + win.mDestroying
405                            + " attHidden=" + win.mAttachedHidden
406                            + " vis=" + win.mViewVisibility
407                            + " hidden=" + win.mRootToken.hidden
408                            + " anim=" + win.mWinAnimator.mAnimation);
409                } else if (mPolicy.canBeForceHidden(win, win.mAttrs)) {
410                    final boolean hideWhenLocked =
411                            (winAnimator.mAttrFlags & FLAG_SHOW_WHEN_LOCKED) == 0;
412                    final boolean changed;
413                    if (((mForceHiding == KEYGUARD_ANIMATING_IN)
414                                && (!winAnimator.isAnimating() || hideWhenLocked))
415                            || ((mForceHiding == KEYGUARD_SHOWN) && hideWhenLocked)) {
416                        changed = win.hideLw(false, false);
417                        if (WindowManagerService.DEBUG_VISIBILITY && changed) Slog.v(TAG,
418                                "Now policy hidden: " + win);
419                    } else {
420                        changed = win.showLw(false, false);
421                        if (WindowManagerService.DEBUG_VISIBILITY && changed) Slog.v(TAG,
422                                "Now policy shown: " + win);
423                        if (changed) {
424                            if ((mBulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0
425                                    && win.isVisibleNow() /*w.isReadyForDisplay()*/) {
426                                if (unForceHiding == null) {
427                                    unForceHiding = new ArrayList<WindowStateAnimator>();
428                                }
429                                unForceHiding.add(winAnimator);
430                                if ((flags & FLAG_SHOW_WALLPAPER) != 0) {
431                                    wallpaperInUnForceHiding = true;
432                                }
433                            }
434                            if (mCurrentFocus == null || mCurrentFocus.mLayer < win.mLayer) {
435                                // We are showing on to of the current
436                                // focus, so re-evaluate focus to make
437                                // sure it is correct.
438                                mService.mFocusMayChange = true;
439                            }
440                        }
441                    }
442                    if (changed && (flags & FLAG_SHOW_WALLPAPER) != 0) {
443                        mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
444                        setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
445                                WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
446                        if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
447                            mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 4",
448                                mPendingLayoutChanges.get(Display.DEFAULT_DISPLAY));
449                        }
450                    }
451                }
452            }
453
454            final AppWindowToken atoken = win.mAppToken;
455            if (winAnimator.mDrawState == WindowStateAnimator.READY_TO_SHOW) {
456                if (atoken == null || atoken.allDrawn) {
457                    if (winAnimator.performShowLocked()) {
458                        mPendingLayoutChanges.put(displayId,
459                                WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
460                        if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
461                            mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 5",
462                                mPendingLayoutChanges.get(displayId));
463                        }
464                    }
465                }
466            }
467            final AppWindowAnimator appAnimator = winAnimator.mAppAnimator;
468            if (appAnimator != null && appAnimator.thumbnail != null) {
469                if (appAnimator.thumbnailTransactionSeq != mAnimTransactionSequence) {
470                    appAnimator.thumbnailTransactionSeq = mAnimTransactionSequence;
471                    appAnimator.thumbnailLayer = 0;
472                }
473                if (appAnimator.thumbnailLayer < winAnimator.mAnimLayer) {
474                    appAnimator.thumbnailLayer = winAnimator.mAnimLayer;
475                }
476            }
477        } // end forall windows
478
479        // If we have windows that are being show due to them no longer
480        // being force-hidden, apply the appropriate animation to them.
481        if (unForceHiding != null) {
482            for (int i=unForceHiding.size()-1; i>=0; i--) {
483                Animation a = mPolicy.createForceHideEnterAnimation(wallpaperInUnForceHiding);
484                if (a != null) {
485                    final WindowStateAnimator winAnimator = unForceHiding.get(i);
486                    winAnimator.setAnimation(a);
487                    winAnimator.mAnimationIsEntrance = true;
488                }
489            }
490        }
491    }
492
493    private void updateWallpaperLocked(int displayId) {
494        final DisplayContentsAnimator displayAnimator =
495                getDisplayContentsAnimatorLocked(displayId);
496        final WinAnimatorList winAnimatorList = displayAnimator.mWinAnimators;
497        WindowStateAnimator windowAnimationBackground = null;
498        int windowAnimationBackgroundColor = 0;
499        WindowState detachedWallpaper = null;
500        final DimSurface windowAnimationBackgroundSurface =
501                displayAnimator.mWindowAnimationBackgroundSurface;
502
503        for (int i = winAnimatorList.size() - 1; i >= 0; i--) {
504            WindowStateAnimator winAnimator = winAnimatorList.get(i);
505            if (winAnimator.mSurface == null) {
506                continue;
507            }
508
509            final int flags = winAnimator.mAttrFlags;
510            final WindowState win = winAnimator.mWin;
511
512            // If this window is animating, make a note that we have
513            // an animating window and take care of a request to run
514            // a detached wallpaper animation.
515            if (winAnimator.mAnimating) {
516                if (winAnimator.mAnimation != null) {
517                    if ((flags & FLAG_SHOW_WALLPAPER) != 0
518                            && winAnimator.mAnimation.getDetachWallpaper()) {
519                        detachedWallpaper = win;
520                    }
521                    final int backgroundColor = winAnimator.mAnimation.getBackgroundColor();
522                    if (backgroundColor != 0) {
523                        if (windowAnimationBackground == null || (winAnimator.mAnimLayer <
524                                windowAnimationBackground.mAnimLayer)) {
525                            windowAnimationBackground = winAnimator;
526                            windowAnimationBackgroundColor = backgroundColor;
527                        }
528                    }
529                }
530                mAnimating = true;
531            }
532
533            // If this window's app token is running a detached wallpaper
534            // animation, make a note so we can ensure the wallpaper is
535            // displayed behind it.
536            final AppWindowAnimator appAnimator = winAnimator.mAppAnimator;
537            if (appAnimator != null && appAnimator.animation != null
538                    && appAnimator.animating) {
539                if ((flags & FLAG_SHOW_WALLPAPER) != 0
540                        && appAnimator.animation.getDetachWallpaper()) {
541                    detachedWallpaper = win;
542                }
543
544                final int backgroundColor = appAnimator.animation.getBackgroundColor();
545                if (backgroundColor != 0) {
546                    if (windowAnimationBackground == null || (winAnimator.mAnimLayer <
547                            windowAnimationBackground.mAnimLayer)) {
548                        windowAnimationBackground = winAnimator;
549                        windowAnimationBackgroundColor = backgroundColor;
550                    }
551                }
552            }
553        } // end forall windows
554
555        if (mWindowDetachedWallpaper != detachedWallpaper) {
556            if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
557                    "Detached wallpaper changed from " + mWindowDetachedWallpaper
558                    + " to " + detachedWallpaper);
559            mWindowDetachedWallpaper = detachedWallpaper;
560            mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
561        }
562
563        if (windowAnimationBackgroundColor != 0) {
564            // If the window that wants black is the current wallpaper
565            // target, then the black goes *below* the wallpaper so we
566            // don't cause the wallpaper to suddenly disappear.
567            int animLayer = windowAnimationBackground.mAnimLayer;
568            WindowState win = windowAnimationBackground.mWin;
569            if (mWallpaperTarget == win
570                    || mLowerWallpaperTarget == win || mUpperWallpaperTarget == win) {
571                final int N = winAnimatorList.size();
572                for (int i = 0; i < N; i++) {
573                    WindowStateAnimator winAnimator = winAnimatorList.get(i);
574                    if (winAnimator.mIsWallpaper) {
575                        animLayer = winAnimator.mAnimLayer;
576                        break;
577                    }
578                }
579            }
580
581            if (windowAnimationBackgroundSurface != null) {
582                windowAnimationBackgroundSurface.show(mDw, mDh,
583                        animLayer - WindowManagerService.LAYER_OFFSET_DIM,
584                        windowAnimationBackgroundColor);
585            }
586        } else {
587            if (windowAnimationBackgroundSurface != null) {
588                windowAnimationBackgroundSurface.hide();
589            }
590        }
591    }
592
593    private void testTokenMayBeDrawnLocked() {
594        // See if any windows have been drawn, so they (and others
595        // associated with them) can now be shown.
596        final int NT = mAppAnimators.size();
597        for (int i=0; i<NT; i++) {
598            AppWindowAnimator appAnimator = mAppAnimators.get(i);
599            AppWindowToken wtoken = appAnimator.mAppToken;
600            final boolean allDrawn = wtoken.allDrawn;
601            if (allDrawn != appAnimator.allDrawn) {
602                appAnimator.allDrawn = allDrawn;
603                if (allDrawn) {
604                    // The token has now changed state to having all
605                    // windows shown...  what to do, what to do?
606                    if (appAnimator.freezingScreen) {
607                        appAnimator.showAllWindowsLocked();
608                        mService.unsetAppFreezingScreenLocked(wtoken, false, true);
609                        if (WindowManagerService.DEBUG_ORIENTATION) Slog.i(TAG,
610                                "Setting mOrientationChangeComplete=true because wtoken "
611                                + wtoken + " numInteresting=" + wtoken.numInterestingWindows
612                                + " numDrawn=" + wtoken.numDrawnWindows);
613                        // This will set mOrientationChangeComplete and cause a pass through layout.
614                        setAppLayoutChanges(appAnimator,
615                                WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
616                                "testTokenMayBeDrawnLocked: freezingScreen");
617                    } else {
618                        setAppLayoutChanges(appAnimator,
619                                WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
620                                "testTokenMayBeDrawnLocked");
621
622                        // We can now show all of the drawn windows!
623                        if (!mService.mOpeningApps.contains(wtoken)) {
624                            mAnimating |= appAnimator.showAllWindowsLocked();
625                        }
626                    }
627                }
628            }
629        }
630    }
631
632    private void performAnimationsLocked(final int displayId) {
633        updateWindowsLocked(displayId);
634        updateWallpaperLocked(displayId);
635    }
636
637    // TODO(cmautner): Change the following comment when no longer locked on mWindowMap */
638    /** Locked on mService.mWindowMap and this. */
639    private void animateLocked() {
640        if (!mInitialized) {
641            return;
642        }
643
644        mPendingLayoutChanges.clear();
645        mCurrentTime = SystemClock.uptimeMillis();
646        mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
647        boolean wasAnimating = mAnimating;
648        mAnimating = false;
649        if (WindowManagerService.DEBUG_WINDOW_TRACE) {
650            Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
651        }
652
653        if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(
654                TAG, ">>> OPEN TRANSACTION animateLocked");
655        Surface.openTransaction();
656        Surface.setAnimationTransaction();
657        try {
658            updateAppWindowsLocked();
659
660            final int numDisplays = mDisplayContentsAnimators.size();
661            for (int i = 0; i < numDisplays; i++) {
662                final int displayId = mDisplayContentsAnimators.keyAt(i);
663                DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
664
665                final ScreenRotationAnimation screenRotationAnimation =
666                        displayAnimator.mScreenRotationAnimation;
667                if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
668                    if (screenRotationAnimation.stepAnimationLocked(mCurrentTime)) {
669                        mAnimating = true;
670                    } else {
671                        mBulkUpdateParams |= SET_UPDATE_ROTATION;
672                        screenRotationAnimation.kill();
673                        displayAnimator.mScreenRotationAnimation = null;
674                    }
675                }
676
677                // Update animations of all applications, including those
678                // associated with exiting/removed apps
679                performAnimationsLocked(displayId);
680
681                final WinAnimatorList winAnimatorList = displayAnimator.mWinAnimators;
682                final int N = winAnimatorList.size();
683                for (int j = 0; j < N; j++) {
684                    winAnimatorList.get(j).prepareSurfaceLocked(true);
685                }
686            }
687
688            testTokenMayBeDrawnLocked();
689
690            for (int i = 0; i < numDisplays; i++) {
691                final int displayId = mDisplayContentsAnimators.keyAt(i);
692                DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
693
694                final ScreenRotationAnimation screenRotationAnimation =
695                        displayAnimator.mScreenRotationAnimation;
696                if (screenRotationAnimation != null) {
697                    screenRotationAnimation.updateSurfacesInTransaction();
698                }
699
700                final DimAnimator.Parameters dimParams = displayAnimator.mDimParams;
701                final DimAnimator dimAnimator = displayAnimator.mDimAnimator;
702                if (dimAnimator != null && dimParams != null) {
703                    dimAnimator.updateParameters(mContext.getResources(), dimParams, mCurrentTime);
704                }
705                if (dimAnimator != null && dimAnimator.mDimShown) {
706                    mAnimating |= dimAnimator.updateSurface(isDimmingLocked(displayId),
707                            mCurrentTime, !mService.okToDisplay());
708                }
709            }
710
711            if (mService.mWatermark != null) {
712                mService.mWatermark.drawIfNeeded();
713            }
714        } catch (RuntimeException e) {
715            Log.wtf(TAG, "Unhandled exception in Window Manager", e);
716        } finally {
717            Surface.closeTransaction();
718            if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(
719                    TAG, "<<< CLOSE TRANSACTION animateLocked");
720        }
721
722        for (int i = mPendingLayoutChanges.size() - 1; i >= 0; i--) {
723            if ((mPendingLayoutChanges.valueAt(i)
724                    & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
725                mPendingActions |= WALLPAPER_ACTION_PENDING;
726            }
727        }
728
729        if (mBulkUpdateParams != 0 || mPendingLayoutChanges.size() > 0) {
730            updateAnimToLayoutLocked();
731        }
732
733        if (mAnimating) {
734            synchronized (mService.mLayoutToAnim) {
735                mService.scheduleAnimationLocked();
736            }
737        } else if (wasAnimating) {
738            mService.requestTraversalLocked();
739        }
740        if (WindowManagerService.DEBUG_WINDOW_TRACE) {
741            Slog.i(TAG, "!!! animate: exit mAnimating=" + mAnimating
742                + " mBulkUpdateParams=" + Integer.toHexString(mBulkUpdateParams)
743                + " mPendingLayoutChanges(DEFAULT_DISPLAY)="
744                + Integer.toHexString(mPendingLayoutChanges.get(Display.DEFAULT_DISPLAY)));
745        }
746    }
747
748    WindowState mCurrentFocus;
749    void setCurrentFocus(final WindowState currentFocus) {
750        mCurrentFocus = currentFocus;
751    }
752
753    void setDisplayDimensions(final int curWidth, final int curHeight,
754                        final int appWidth, final int appHeight) {
755        mDw = curWidth;
756        mDh = curHeight;
757        mInnerDw = appWidth;
758        mInnerDh = appHeight;
759    }
760
761    boolean isDimmingLocked(int displayId) {
762        return getDisplayContentsAnimatorLocked(displayId).mDimParams != null;
763    }
764
765    boolean isDimmingLocked(final WindowStateAnimator winAnimator) {
766        DimAnimator.Parameters dimParams =
767                getDisplayContentsAnimatorLocked(winAnimator.mWin.getDisplayId()).mDimParams;
768        return dimParams != null && dimParams.mDimWinAnimator == winAnimator;
769    }
770
771    static String bulkUpdateParamsToString(int bulkUpdateParams) {
772        StringBuilder builder = new StringBuilder(128);
773        if ((bulkUpdateParams & LayoutFields.SET_UPDATE_ROTATION) != 0) {
774            builder.append(" UPDATE_ROTATION");
775        }
776        if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) {
777            builder.append(" WALLPAPER_MAY_CHANGE");
778        }
779        if ((bulkUpdateParams & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) {
780            builder.append(" FORCE_HIDING_CHANGED");
781        }
782        if ((bulkUpdateParams & LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE) != 0) {
783            builder.append(" ORIENTATION_CHANGE_COMPLETE");
784        }
785        if ((bulkUpdateParams & LayoutFields.SET_TURN_ON_SCREEN) != 0) {
786            builder.append(" TURN_ON_SCREEN");
787        }
788        return builder.toString();
789    }
790
791    public void dumpLocked(PrintWriter pw, String prefix, boolean dumpAll) {
792        final String subPrefix = "  " + prefix;
793        final String subSubPrefix = "  " + subPrefix;
794
795        boolean needSep = false;
796        if (mAppAnimators.size() > 0) {
797            needSep = true;
798            pw.println("  App Animators:");
799            for (int i=mAppAnimators.size()-1; i>=0; i--) {
800                AppWindowAnimator anim = mAppAnimators.get(i);
801                pw.print(prefix); pw.print("App Animator #"); pw.print(i);
802                        pw.print(' '); pw.print(anim);
803                if (dumpAll) {
804                    pw.println(':');
805                    anim.dump(pw, subPrefix, dumpAll);
806                } else {
807                    pw.println();
808                }
809            }
810        }
811        if (mWallpaperTokens.size() > 0) {
812            if (needSep) {
813                pw.println();
814            }
815            needSep = true;
816            pw.print(prefix); pw.println("Wallpaper tokens:");
817            for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
818                WindowToken token = mWallpaperTokens.get(i);
819                pw.print(prefix); pw.print("Wallpaper #"); pw.print(i);
820                        pw.print(' '); pw.print(token);
821                if (dumpAll) {
822                    pw.println(':');
823                    token.dump(pw, subPrefix);
824                } else {
825                    pw.println();
826                }
827            }
828        }
829
830        if (needSep) {
831            pw.println();
832        }
833        for (int i = 0; i < mDisplayContentsAnimators.size(); i++) {
834            pw.print(prefix); pw.print("DisplayContentsAnimator #");
835                    pw.print(mDisplayContentsAnimators.keyAt(i));
836                    pw.println(":");
837            DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
838            for (int j=0; j<displayAnimator.mWinAnimators.size(); j++) {
839                WindowStateAnimator wanim = displayAnimator.mWinAnimators.get(j);
840                pw.print(subPrefix); pw.print("Window #"); pw.print(j);
841                        pw.print(": "); pw.println(wanim);
842            }
843            if (displayAnimator.mWindowAnimationBackgroundSurface != null) {
844                if (dumpAll || displayAnimator.mWindowAnimationBackgroundSurface.mDimShown) {
845                    pw.print(subPrefix); pw.println("mWindowAnimationBackgroundSurface:");
846                    displayAnimator.mWindowAnimationBackgroundSurface.printTo(subSubPrefix, pw);
847                }
848            }
849            if (displayAnimator.mDimAnimator != null) {
850                if (dumpAll || displayAnimator.mDimAnimator.mDimShown) {
851                    pw.print(subPrefix); pw.println("mDimAnimator:");
852                    displayAnimator.mDimAnimator.printTo(subSubPrefix, pw);
853                }
854            } else if (dumpAll) {
855                pw.print(subPrefix); pw.println("no DimAnimator ");
856            }
857            if (displayAnimator.mDimParams != null) {
858                pw.print(subPrefix); pw.println("mDimParams:");
859                displayAnimator.mDimParams.printTo(subSubPrefix, pw);
860            } else if (dumpAll) {
861                pw.print(subPrefix); pw.println("no DimParams ");
862            }
863            if (displayAnimator.mScreenRotationAnimation != null) {
864                pw.print(subPrefix); pw.println("mScreenRotationAnimation:");
865                displayAnimator.mScreenRotationAnimation.printTo(subSubPrefix, pw);
866            } else if (dumpAll) {
867                pw.print(subPrefix); pw.println("no ScreenRotationAnimation ");
868            }
869        }
870
871        pw.println();
872
873        if (dumpAll) {
874            pw.print(prefix); pw.print("mAnimTransactionSequence=");
875                    pw.print(mAnimTransactionSequence);
876                    pw.print(" mForceHiding="); pw.println(forceHidingToString());
877            pw.print(prefix); pw.print("mCurrentTime=");
878                    pw.println(TimeUtils.formatUptime(mCurrentTime));
879            pw.print(prefix); pw.print("mDw=");
880                    pw.print(mDw); pw.print(" mDh="); pw.print(mDh);
881                    pw.print(" mInnerDw="); pw.print(mInnerDw);
882                    pw.print(" mInnerDh="); pw.println(mInnerDh);
883        }
884        if (mBulkUpdateParams != 0) {
885            pw.print(prefix); pw.print("mBulkUpdateParams=0x");
886                    pw.print(Integer.toHexString(mBulkUpdateParams));
887                    pw.println(bulkUpdateParamsToString(mBulkUpdateParams));
888        }
889        if (mPendingActions != 0) {
890            pw.print(prefix); pw.print("mPendingActions=0x");
891                    pw.println(Integer.toHexString(mPendingActions));
892        }
893        if (mWindowDetachedWallpaper != null) {
894            pw.print(prefix); pw.print("mWindowDetachedWallpaper=");
895                pw.println(mWindowDetachedWallpaper);
896        }
897        pw.print(prefix); pw.print("mWallpaperTarget="); pw.println(mWallpaperTarget);
898        pw.print(prefix); pw.print("mWpAppAnimator="); pw.println(mWpAppAnimator);
899        if (mLowerWallpaperTarget != null || mUpperWallpaperTarget != null) {
900            pw.print(prefix); pw.print("mLowerWallpaperTarget=");
901                    pw.println(mLowerWallpaperTarget);
902            pw.print(prefix); pw.print("mUpperWallpaperTarget=");
903                    pw.println(mUpperWallpaperTarget);
904        }
905        if (mUniverseBackground != null) {
906            pw.print(prefix); pw.print("mUniverseBackground="); pw.print(mUniverseBackground);
907                    pw.print(" mAboveUniverseLayer="); pw.println(mAboveUniverseLayer);
908        }
909    }
910
911    void clearPendingActions() {
912        synchronized (this) {
913            mPendingActions = 0;
914        }
915    }
916
917    void setPendingLayoutChanges(final int displayId, final int changes) {
918        mPendingLayoutChanges.put(displayId, mPendingLayoutChanges.get(displayId) | changes);
919    }
920
921    void setAppLayoutChanges(final AppWindowAnimator appAnimator, final int changes, String s) {
922        // Used to track which displays layout changes have been done.
923        SparseIntArray displays = new SparseIntArray();
924        for (int i = appAnimator.mAllAppWinAnimators.size() - 1; i >= 0; i--) {
925            WindowStateAnimator winAnimator = appAnimator.mAllAppWinAnimators.get(i);
926            final int displayId = winAnimator.mWin.mDisplayContent.getDisplayId();
927            if (displays.indexOfKey(displayId) < 0) {
928                setPendingLayoutChanges(displayId, changes);
929                if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
930                    mService.debugLayoutRepeats(s, mPendingLayoutChanges.get(displayId));
931                }
932                // Keep from processing this display again.
933                displays.put(displayId, changes);
934            }
935        }
936    }
937
938    private DisplayContentsAnimator getDisplayContentsAnimatorLocked(int displayId) {
939        DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.get(displayId);
940        if (displayAnimator == null) {
941            displayAnimator = new DisplayContentsAnimator(displayId);
942            mDisplayContentsAnimators.put(displayId, displayAnimator);
943        }
944        return displayAnimator;
945    }
946
947    void setScreenRotationAnimationLocked(int displayId, ScreenRotationAnimation animation) {
948        getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation = animation;
949    }
950
951    ScreenRotationAnimation getScreenRotationAnimationLocked(int displayId) {
952        return getDisplayContentsAnimatorLocked(displayId).mScreenRotationAnimation;
953    }
954
955    private class DisplayContentsAnimator {
956        WinAnimatorList mWinAnimators = new WinAnimatorList();
957        DimAnimator mDimAnimator = null;
958        DimAnimator.Parameters mDimParams = null;
959        DimSurface mWindowAnimationBackgroundSurface = null;
960        ScreenRotationAnimation mScreenRotationAnimation = null;
961
962        public DisplayContentsAnimator(int displayId) {
963            mDimAnimator = new DimAnimator(mService.mFxSession, displayId);
964            mWindowAnimationBackgroundSurface =
965                    new DimSurface(mService.mFxSession, displayId);
966        }
967    }
968}
969