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