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