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