AppWindowAnimator.java revision eb94fa7975b1e8742f3b00cec6bd4f9d6b329e3a
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2014 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.server.wm;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199ecfee03fa188aebfbd9778b4e020323903495eeJeff Sharkeyimport android.graphics.Matrix;
209ecfee03fa188aebfbd9778b4e020323903495eeJeff Sharkeyimport android.util.Slog;
219ecfee03fa188aebfbd9778b4e020323903495eeJeff Sharkeyimport android.util.TimeUtils;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.Display;
239ecfee03fa188aebfbd9778b4e020323903495eeJeff Sharkeyimport android.view.SurfaceControl;
249ecfee03fa188aebfbd9778b4e020323903495eeJeff Sharkeyimport android.view.WindowManagerPolicy;
259ecfee03fa188aebfbd9778b4e020323903495eeJeff Sharkeyimport android.view.animation.Animation;
269ecfee03fa188aebfbd9778b4e020323903495eeJeff Sharkeyimport android.view.animation.Transformation;
279ecfee03fa188aebfbd9778b4e020323903495eeJeff Sharkey
289ecfee03fa188aebfbd9778b4e020323903495eeJeff Sharkeyimport java.io.PrintWriter;
299ecfee03fa188aebfbd9778b4e020323903495eeJeff Sharkeyimport java.util.ArrayList;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class AppWindowAnimator {
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static final String TAG = "AppWindowAnimator";
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final AppWindowToken mAppToken;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final WindowManagerService mService;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final WindowAnimator mAnimator;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean animating;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    Animation animation;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean hasTransformation;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final Transformation transformation = new Transformation();
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Have we been asked to have this token keep the screen frozen?
44    // Protect with mAnimator.
45    boolean freezingScreen;
46
47    /**
48     * How long we last kept the screen frozen.
49     */
50    int lastFreezeDuration;
51
52    // Offset to the window of all layers in the token, for use by
53    // AppWindowToken animations.
54    int animLayerAdjustment;
55
56    // Propagated from AppWindowToken.allDrawn, to determine when
57    // the state changes.
58    boolean allDrawn;
59
60    // Special surface for thumbnail animation.
61    SurfaceControl thumbnail;
62    int thumbnailTransactionSeq;
63    int thumbnailX;
64    int thumbnailY;
65    int thumbnailLayer;
66    Animation thumbnailAnimation;
67    final Transformation thumbnailTransformation = new Transformation();
68
69    /** WindowStateAnimator from mAppAnimator.allAppWindows as of last performLayout */
70    ArrayList<WindowStateAnimator> mAllAppWinAnimators = new ArrayList<WindowStateAnimator>();
71
72    static final Animation sDummyAnimation = new DummyAnimation();
73
74    public AppWindowAnimator(final AppWindowToken atoken) {
75        mAppToken = atoken;
76        mService = atoken.service;
77        mAnimator = atoken.mAnimator;
78    }
79
80    public void setAnimation(Animation anim, int width, int height) {
81        if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting animation in " + mAppToken
82                + ": " + anim + " wxh=" + width + "x" + height
83                + " isVisible=" + mAppToken.isVisible());
84        animation = anim;
85        animating = false;
86        if (!anim.isInitialized()) {
87            anim.initialize(width, height, width, height);
88        }
89        anim.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION);
90        anim.scaleCurrentDuration(mService.getTransitionAnimationScaleLocked());
91        int zorder = anim.getZAdjustment();
92        int adj = 0;
93        if (zorder == Animation.ZORDER_TOP) {
94            adj = WindowManagerService.TYPE_LAYER_OFFSET;
95        } else if (zorder == Animation.ZORDER_BOTTOM) {
96            adj = -WindowManagerService.TYPE_LAYER_OFFSET;
97        }
98
99        if (animLayerAdjustment != adj) {
100            animLayerAdjustment = adj;
101            updateLayers();
102        }
103        // Start out animation gone if window is gone, or visible if window is visible.
104        transformation.clear();
105        transformation.setAlpha(mAppToken.isVisible() ? 1 : 0);
106        hasTransformation = true;
107    }
108
109    public void setDummyAnimation() {
110        if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting dummy animation in " + mAppToken
111                + " isVisible=" + mAppToken.isVisible());
112        animation = sDummyAnimation;
113        hasTransformation = true;
114        transformation.clear();
115        transformation.setAlpha(mAppToken.isVisible() ? 1 : 0);
116    }
117
118    public void clearAnimation() {
119        if (animation != null) {
120            animation = null;
121            animating = true;
122        }
123        clearThumbnail();
124        if (mAppToken.deferClearAllDrawn) {
125            mAppToken.allDrawn = false;
126            mAppToken.deferClearAllDrawn = false;
127        }
128    }
129
130    public void clearThumbnail() {
131        if (thumbnail != null) {
132            thumbnail.destroy();
133            thumbnail = null;
134        }
135    }
136
137    void updateLayers() {
138        final int N = mAppToken.allAppWindows.size();
139        final int adj = animLayerAdjustment;
140        thumbnailLayer = -1;
141        for (int i=0; i<N; i++) {
142            final WindowState w = mAppToken.allAppWindows.get(i);
143            final WindowStateAnimator winAnimator = w.mWinAnimator;
144            winAnimator.mAnimLayer = w.mLayer + adj;
145            if (winAnimator.mAnimLayer > thumbnailLayer) {
146                thumbnailLayer = winAnimator.mAnimLayer;
147            }
148            if (WindowManagerService.DEBUG_LAYERS) Slog.v(TAG, "Updating layer " + w + ": "
149                    + winAnimator.mAnimLayer);
150            if (w == mService.mInputMethodTarget && !mService.mInputMethodTargetWaitingAnim) {
151                mService.setInputMethodAnimLayerAdjustment(adj);
152            }
153            if (w == mService.mWallpaperTarget && mService.mLowerWallpaperTarget == null) {
154                mService.setWallpaperAnimLayerAdjustmentLocked(adj);
155            }
156        }
157    }
158
159    private void stepThumbnailAnimation(long currentTime) {
160        thumbnailTransformation.clear();
161        thumbnailAnimation.getTransformation(currentTime, thumbnailTransformation);
162        thumbnailTransformation.getMatrix().preTranslate(thumbnailX, thumbnailY);
163
164        ScreenRotationAnimation screenRotationAnimation =
165                mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
166        final boolean screenAnimation = screenRotationAnimation != null
167                && screenRotationAnimation.isAnimating();
168        if (screenAnimation) {
169            thumbnailTransformation.postCompose(screenRotationAnimation.getEnterTransformation());
170        }
171        // cache often used attributes locally
172        final float tmpFloats[] = mService.mTmpFloats;
173        thumbnailTransformation.getMatrix().getValues(tmpFloats);
174        if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail,
175                "thumbnail", "POS " + tmpFloats[Matrix.MTRANS_X]
176                + ", " + tmpFloats[Matrix.MTRANS_Y], null);
177        thumbnail.setPosition(tmpFloats[Matrix.MTRANS_X], tmpFloats[Matrix.MTRANS_Y]);
178        if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail,
179                "thumbnail", "alpha=" + thumbnailTransformation.getAlpha()
180                + " layer=" + thumbnailLayer
181                + " matrix=[" + tmpFloats[Matrix.MSCALE_X]
182                + "," + tmpFloats[Matrix.MSKEW_Y]
183                + "][" + tmpFloats[Matrix.MSKEW_X]
184                + "," + tmpFloats[Matrix.MSCALE_Y] + "]", null);
185        thumbnail.setAlpha(thumbnailTransformation.getAlpha());
186        // The thumbnail is layered below the window immediately above this
187        // token's anim layer.
188        thumbnail.setLayer(thumbnailLayer + WindowManagerService.WINDOW_LAYER_MULTIPLIER
189                - WindowManagerService.LAYER_OFFSET_THUMBNAIL);
190        thumbnail.setMatrix(tmpFloats[Matrix.MSCALE_X], tmpFloats[Matrix.MSKEW_Y],
191                tmpFloats[Matrix.MSKEW_X], tmpFloats[Matrix.MSCALE_Y]);
192    }
193
194    private boolean stepAnimation(long currentTime) {
195        if (animation == null) {
196            return false;
197        }
198        transformation.clear();
199        final boolean more = animation.getTransformation(currentTime, transformation);
200        if (false && WindowManagerService.DEBUG_ANIM) Slog.v(
201            TAG, "Stepped animation in " + mAppToken + ": more=" + more + ", xform=" + transformation);
202        if (!more) {
203            animation = null;
204            clearThumbnail();
205            if (WindowManagerService.DEBUG_ANIM) Slog.v(
206                TAG, "Finished animation in " + mAppToken + " @ " + currentTime);
207        }
208        hasTransformation = more;
209        return more;
210    }
211
212    // This must be called while inside a transaction.
213    boolean stepAnimationLocked(long currentTime) {
214        if (mService.okToDisplay()) {
215            // We will run animations as long as the display isn't frozen.
216
217            if (animation == sDummyAnimation) {
218                // This guy is going to animate, but not yet.  For now count
219                // it as not animating for purposes of scheduling transactions;
220                // when it is really time to animate, this will be set to
221                // a real animation and the next call will execute normally.
222                return false;
223            }
224
225            if ((mAppToken.allDrawn || animating || mAppToken.startingDisplayed)
226                    && animation != null) {
227                if (!animating) {
228                    if (WindowManagerService.DEBUG_ANIM) Slog.v(
229                        TAG, "Starting animation in " + mAppToken +
230                        " @ " + currentTime + " scale="
231                        + mService.getTransitionAnimationScaleLocked()
232                        + " allDrawn=" + mAppToken.allDrawn + " animating=" + animating);
233                    animation.setStartTime(currentTime);
234                    animating = true;
235                    if (thumbnail != null) {
236                        thumbnail.show();
237                        thumbnailAnimation.setStartTime(currentTime);
238                    }
239                }
240                if (stepAnimation(currentTime)) {
241                    // animation isn't over, step any thumbnail and that's
242                    // it for now.
243                    if (thumbnail != null) {
244                        stepThumbnailAnimation(currentTime);
245                    }
246                    return true;
247                }
248            }
249        } else if (animation != null) {
250            // If the display is frozen, and there is a pending animation,
251            // clear it and make sure we run the cleanup code.
252            animating = true;
253            animation = null;
254        }
255
256        hasTransformation = false;
257
258        if (!animating && animation == null) {
259            return false;
260        }
261
262        mAnimator.setAppLayoutChanges(this, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
263                "AppWindowToken");
264
265        clearAnimation();
266        animating = false;
267        if (animLayerAdjustment != 0) {
268            animLayerAdjustment = 0;
269            updateLayers();
270        }
271        if (mService.mInputMethodTarget != null
272                && mService.mInputMethodTarget.mAppToken == mAppToken) {
273            mService.moveInputMethodWindowsIfNeededLocked(true);
274        }
275
276        if (WindowManagerService.DEBUG_ANIM) Slog.v(
277                TAG, "Animation done in " + mAppToken
278                + ": reportedVisible=" + mAppToken.reportedVisible);
279
280        transformation.clear();
281
282        final int N = mAllAppWinAnimators.size();
283        for (int i=0; i<N; i++) {
284            mAllAppWinAnimators.get(i).finishExit();
285        }
286        mAppToken.updateReportedVisibilityLocked();
287
288        return false;
289    }
290
291    boolean showAllWindowsLocked() {
292        boolean isAnimating = false;
293        final int NW = mAllAppWinAnimators.size();
294        for (int i=0; i<NW; i++) {
295            WindowStateAnimator winAnimator = mAllAppWinAnimators.get(i);
296            if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
297                    "performing show on: " + winAnimator);
298            winAnimator.performShowLocked();
299            isAnimating |= winAnimator.isAnimating();
300        }
301        return isAnimating;
302    }
303
304    void dump(PrintWriter pw, String prefix, boolean dumpAll) {
305        pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken);
306        pw.print(prefix); pw.print("mAnimator="); pw.println(mAnimator);
307        pw.print(prefix); pw.print("freezingScreen="); pw.print(freezingScreen);
308                pw.print(" allDrawn="); pw.print(allDrawn);
309                pw.print(" animLayerAdjustment="); pw.println(animLayerAdjustment);
310        if (lastFreezeDuration != 0) {
311            pw.print(prefix); pw.print("lastFreezeDuration=");
312                    TimeUtils.formatDuration(lastFreezeDuration, pw); pw.println();
313        }
314        if (animating || animation != null) {
315            pw.print(prefix); pw.print("animating="); pw.println(animating);
316            pw.print(prefix); pw.print("animation="); pw.println(animation);
317        }
318        if (hasTransformation) {
319            pw.print(prefix); pw.print("XForm: ");
320                    transformation.printShortString(pw);
321                    pw.println();
322        }
323        if (thumbnail != null) {
324            pw.print(prefix); pw.print("thumbnail="); pw.print(thumbnail);
325                    pw.print(" x="); pw.print(thumbnailX);
326                    pw.print(" y="); pw.print(thumbnailY);
327                    pw.print(" layer="); pw.println(thumbnailLayer);
328            pw.print(prefix); pw.print("thumbnailAnimation="); pw.println(thumbnailAnimation);
329            pw.print(prefix); pw.print("thumbnailTransformation=");
330                    pw.println(thumbnailTransformation.toShortString());
331        }
332        for (int i=0; i<mAllAppWinAnimators.size(); i++) {
333            WindowStateAnimator wanim = mAllAppWinAnimators.get(i);
334            pw.print(prefix); pw.print("App Win Anim #"); pw.print(i);
335                    pw.print(": "); pw.println(wanim);
336        }
337    }
338
339    // This is an animation that does nothing: it just immediately finishes
340    // itself every time it is called.  It is used as a stub animation in cases
341    // where we want to synchronize multiple things that may be animating.
342    static final class DummyAnimation extends Animation {
343        @Override
344        public boolean getTransformation(long currentTime, Transformation outTransformation) {
345            return false;
346        }
347    }
348
349}
350