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