AppWindowAnimator.java revision 9158825f9c41869689d6b1786d7c7aa8bdd524ce
1// Copyright 2012 Google Inc. All Rights Reserved.
2
3package com.android.server.wm;
4
5import android.graphics.Matrix;
6import android.util.Slog;
7import android.util.TimeUtils;
8import android.view.Display;
9import android.view.SurfaceControl;
10import android.view.WindowManagerPolicy;
11import android.view.animation.Animation;
12import android.view.animation.Transformation;
13
14import java.io.PrintWriter;
15import java.util.ArrayList;
16
17public class AppWindowAnimator {
18    static final String TAG = "AppWindowAnimator";
19
20    final AppWindowToken mAppToken;
21    final WindowManagerService mService;
22    final WindowAnimator mAnimator;
23
24    boolean animating;
25    Animation animation;
26    boolean hasTransformation;
27    final Transformation transformation = new Transformation();
28
29    // Have we been asked to have this token keep the screen frozen?
30    // Protect with mAnimator.
31    boolean freezingScreen;
32
33    /**
34     * How long we last kept the screen frozen.
35     */
36    int lastFreezeDuration;
37
38    // Offset to the window of all layers in the token, for use by
39    // AppWindowToken animations.
40    int animLayerAdjustment;
41
42    // Propagated from AppWindowToken.allDrawn, to determine when
43    // the state changes.
44    boolean allDrawn;
45
46    // Special surface for thumbnail animation.
47    SurfaceControl thumbnail;
48    int thumbnailTransactionSeq;
49    int thumbnailX;
50    int thumbnailY;
51    int thumbnailLayer;
52    Animation thumbnailAnimation;
53    final Transformation thumbnailTransformation = new Transformation();
54
55    /** WindowStateAnimator from mAppAnimator.allAppWindows as of last performLayout */
56    ArrayList<WindowStateAnimator> mAllAppWinAnimators = new ArrayList<WindowStateAnimator>();
57
58    static final Animation sDummyAnimation = new DummyAnimation();
59
60    public AppWindowAnimator(final AppWindowToken atoken) {
61        mAppToken = atoken;
62        mService = atoken.service;
63        mAnimator = atoken.mAnimator;
64    }
65
66    public void setAnimation(Animation anim, int width, int height) {
67        if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting animation in " + mAppToken
68                + ": " + anim + " wxh=" + width + "x" + height
69                + " isVisible=" + mAppToken.isVisible());
70        animation = anim;
71        animating = false;
72        if (!anim.isInitialized()) {
73            anim.initialize(width, height, width, height);
74        }
75        anim.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION);
76        anim.scaleCurrentDuration(mService.mTransitionAnimationScale);
77        int zorder = anim.getZAdjustment();
78        int adj = 0;
79        if (zorder == Animation.ZORDER_TOP) {
80            adj = WindowManagerService.TYPE_LAYER_OFFSET;
81        } else if (zorder == Animation.ZORDER_BOTTOM) {
82            adj = -WindowManagerService.TYPE_LAYER_OFFSET;
83        }
84
85        if (animLayerAdjustment != adj) {
86            animLayerAdjustment = adj;
87            updateLayers();
88        }
89        // Start out animation gone if window is gone, or visible if window is visible.
90        transformation.clear();
91        transformation.setAlpha(mAppToken.isVisible() ? 1 : 0);
92        hasTransformation = true;
93    }
94
95    public void setDummyAnimation() {
96        if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting dummy animation in " + mAppToken
97                + " isVisible=" + mAppToken.isVisible());
98        animation = sDummyAnimation;
99        hasTransformation = true;
100        transformation.clear();
101        transformation.setAlpha(mAppToken.isVisible() ? 1 : 0);
102    }
103
104    public void clearAnimation() {
105        if (animation != null) {
106            animation = null;
107            animating = true;
108        }
109        clearThumbnail();
110        if (mAppToken.deferClearAllDrawn) {
111            mAppToken.allDrawn = false;
112            mAppToken.deferClearAllDrawn = false;
113        }
114    }
115
116    public void clearThumbnail() {
117        if (thumbnail != null) {
118            thumbnail.destroy();
119            thumbnail = null;
120        }
121    }
122
123    void updateLayers() {
124        final int N = mAppToken.allAppWindows.size();
125        final int adj = animLayerAdjustment;
126        thumbnailLayer = -1;
127        for (int i=0; i<N; i++) {
128            final WindowState w = mAppToken.allAppWindows.get(i);
129            final WindowStateAnimator winAnimator = w.mWinAnimator;
130            winAnimator.mAnimLayer = w.mLayer + adj;
131            if (winAnimator.mAnimLayer > thumbnailLayer) {
132                thumbnailLayer = winAnimator.mAnimLayer;
133            }
134            if (WindowManagerService.DEBUG_LAYERS) Slog.v(TAG, "Updating layer " + w + ": "
135                    + winAnimator.mAnimLayer);
136            if (w == mService.mInputMethodTarget && !mService.mInputMethodTargetWaitingAnim) {
137                mService.setInputMethodAnimLayerAdjustment(adj);
138            }
139            if (w == mService.mWallpaperTarget && mService.mLowerWallpaperTarget == null) {
140                mService.setWallpaperAnimLayerAdjustmentLocked(adj);
141            }
142        }
143    }
144
145    private void stepThumbnailAnimation(long currentTime) {
146        thumbnailTransformation.clear();
147        thumbnailAnimation.getTransformation(currentTime, thumbnailTransformation);
148        thumbnailTransformation.getMatrix().preTranslate(thumbnailX, thumbnailY);
149
150        ScreenRotationAnimation screenRotationAnimation =
151                mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
152        final boolean screenAnimation = screenRotationAnimation != null
153                && screenRotationAnimation.isAnimating();
154        if (screenAnimation) {
155            thumbnailTransformation.postCompose(screenRotationAnimation.getEnterTransformation());
156        }
157        // cache often used attributes locally
158        final float tmpFloats[] = mService.mTmpFloats;
159        thumbnailTransformation.getMatrix().getValues(tmpFloats);
160        if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail,
161                "thumbnail", "POS " + tmpFloats[Matrix.MTRANS_X]
162                + ", " + tmpFloats[Matrix.MTRANS_Y], null);
163        thumbnail.setPosition(tmpFloats[Matrix.MTRANS_X], tmpFloats[Matrix.MTRANS_Y]);
164        if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail,
165                "thumbnail", "alpha=" + thumbnailTransformation.getAlpha()
166                + " layer=" + thumbnailLayer
167                + " matrix=[" + tmpFloats[Matrix.MSCALE_X]
168                + "," + tmpFloats[Matrix.MSKEW_Y]
169                + "][" + tmpFloats[Matrix.MSKEW_X]
170                + "," + tmpFloats[Matrix.MSCALE_Y] + "]", null);
171        thumbnail.setAlpha(thumbnailTransformation.getAlpha());
172        // The thumbnail is layered below the window immediately above this
173        // token's anim layer.
174        thumbnail.setLayer(thumbnailLayer + WindowManagerService.WINDOW_LAYER_MULTIPLIER
175                - WindowManagerService.LAYER_OFFSET_THUMBNAIL);
176        thumbnail.setMatrix(tmpFloats[Matrix.MSCALE_X], tmpFloats[Matrix.MSKEW_Y],
177                tmpFloats[Matrix.MSKEW_X], tmpFloats[Matrix.MSCALE_Y]);
178    }
179
180    private boolean stepAnimation(long currentTime) {
181        if (animation == null) {
182            return false;
183        }
184        transformation.clear();
185        final boolean more = animation.getTransformation(currentTime, transformation);
186        if (false && WindowManagerService.DEBUG_ANIM) Slog.v(
187            TAG, "Stepped animation in " + mAppToken + ": more=" + more + ", xform=" + transformation);
188        if (!more) {
189            animation = null;
190            clearThumbnail();
191            if (WindowManagerService.DEBUG_ANIM) Slog.v(
192                TAG, "Finished animation in " + mAppToken + " @ " + currentTime);
193        }
194        hasTransformation = more;
195        return more;
196    }
197
198    // This must be called while inside a transaction.
199    boolean stepAnimationLocked(long currentTime) {
200        if (mService.okToDisplay()) {
201            // We will run animations as long as the display isn't frozen.
202
203            if (animation == sDummyAnimation) {
204                // This guy is going to animate, but not yet.  For now count
205                // it as not animating for purposes of scheduling transactions;
206                // when it is really time to animate, this will be set to
207                // a real animation and the next call will execute normally.
208                return false;
209            }
210
211            if ((mAppToken.allDrawn || animating || mAppToken.startingDisplayed)
212                    && animation != null) {
213                if (!animating) {
214                    if (WindowManagerService.DEBUG_ANIM) Slog.v(
215                        TAG, "Starting animation in " + mAppToken +
216                        " @ " + currentTime + " scale=" + mService.mTransitionAnimationScale
217                        + " allDrawn=" + mAppToken.allDrawn + " animating=" + animating);
218                    animation.setStartTime(currentTime);
219                    animating = true;
220                    if (thumbnail != null) {
221                        thumbnail.show();
222                        thumbnailAnimation.setStartTime(currentTime);
223                    }
224                }
225                if (stepAnimation(currentTime)) {
226                    // animation isn't over, step any thumbnail and that's
227                    // it for now.
228                    if (thumbnail != null) {
229                        stepThumbnailAnimation(currentTime);
230                    }
231                    return true;
232                }
233            }
234        } else if (animation != null) {
235            // If the display is frozen, and there is a pending animation,
236            // clear it and make sure we run the cleanup code.
237            animating = true;
238            animation = null;
239        }
240
241        hasTransformation = false;
242
243        if (!animating && animation == null) {
244            return false;
245        }
246
247        mAnimator.setAppLayoutChanges(this, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
248                "AppWindowToken");
249
250        clearAnimation();
251        animating = false;
252        if (animLayerAdjustment != 0) {
253            animLayerAdjustment = 0;
254            updateLayers();
255        }
256        if (mService.mInputMethodTarget != null
257                && mService.mInputMethodTarget.mAppToken == mAppToken) {
258            mService.moveInputMethodWindowsIfNeededLocked(true);
259        }
260
261        if (WindowManagerService.DEBUG_ANIM) Slog.v(
262                TAG, "Animation done in " + mAppToken
263                + ": reportedVisible=" + mAppToken.reportedVisible);
264
265        transformation.clear();
266
267        final int N = mAllAppWinAnimators.size();
268        for (int i=0; i<N; i++) {
269            mAllAppWinAnimators.get(i).finishExit();
270        }
271        mAppToken.updateReportedVisibilityLocked();
272
273        return false;
274    }
275
276    boolean showAllWindowsLocked() {
277        boolean isAnimating = false;
278        final int NW = mAllAppWinAnimators.size();
279        for (int i=0; i<NW; i++) {
280            WindowStateAnimator winAnimator = mAllAppWinAnimators.get(i);
281            if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
282                    "performing show on: " + winAnimator);
283            winAnimator.performShowLocked();
284            isAnimating |= winAnimator.isAnimating();
285        }
286        return isAnimating;
287    }
288
289    void dump(PrintWriter pw, String prefix, boolean dumpAll) {
290        pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken);
291        pw.print(prefix); pw.print("mAnimator="); pw.println(mAnimator);
292        pw.print(prefix); pw.print("freezingScreen="); pw.print(freezingScreen);
293                pw.print(" allDrawn="); pw.print(allDrawn);
294                pw.print(" animLayerAdjustment="); pw.println(animLayerAdjustment);
295        if (lastFreezeDuration != 0) {
296            pw.print(prefix); pw.print("lastFreezeDuration=");
297                    TimeUtils.formatDuration(lastFreezeDuration, pw); pw.println();
298        }
299        if (animating || animation != null) {
300            pw.print(prefix); pw.print("animating="); pw.println(animating);
301            pw.print(prefix); pw.print("animation="); pw.println(animation);
302        }
303        if (hasTransformation) {
304            pw.print(prefix); pw.print("XForm: ");
305                    transformation.printShortString(pw);
306                    pw.println();
307        }
308        if (thumbnail != null) {
309            pw.print(prefix); pw.print("thumbnail="); pw.print(thumbnail);
310                    pw.print(" x="); pw.print(thumbnailX);
311                    pw.print(" y="); pw.print(thumbnailY);
312                    pw.print(" layer="); pw.println(thumbnailLayer);
313            pw.print(prefix); pw.print("thumbnailAnimation="); pw.println(thumbnailAnimation);
314            pw.print(prefix); pw.print("thumbnailTransformation=");
315                    pw.println(thumbnailTransformation.toShortString());
316        }
317        for (int i=0; i<mAllAppWinAnimators.size(); i++) {
318            WindowStateAnimator wanim = mAllAppWinAnimators.get(i);
319            pw.print(prefix); pw.print("App Win Anim #"); pw.print(i);
320                    pw.print(": "); pw.println(wanim);
321        }
322    }
323
324    // This is an animation that does nothing: it just immediately finishes
325    // itself every time it is called.  It is used as a stub animation in cases
326    // where we want to synchronize multiple things that may be animating.
327    static final class DummyAnimation extends Animation {
328        @Override
329        public boolean getTransformation(long currentTime, Transformation outTransformation) {
330            return false;
331        }
332    }
333
334}
335