AppWindowAnimator.java revision 378756154fce86b53e91746583bfe15996ef680b
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.util.Slog;
21import android.util.TimeUtils;
22import android.view.Display;
23import android.view.SurfaceControl;
24import android.view.WindowManagerPolicy;
25import android.view.animation.Animation;
26import android.view.animation.Transformation;
27
28import java.io.PrintWriter;
29import java.util.ArrayList;
30
31public class AppWindowAnimator {
32    static final String TAG = "AppWindowAnimator";
33
34    final AppWindowToken mAppToken;
35    final WindowManagerService mService;
36    final WindowAnimator mAnimator;
37
38    boolean animating;
39    Animation animation;
40    boolean hasTransformation;
41    final Transformation transformation = new Transformation();
42
43    // 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.  If deferThumbnailDestruction is enabled, then we
61    // will make sure that the thumbnail is destroyed after the other surface is completed.  This
62    // requires that the duration of the two animations are the same.
63    SurfaceControl thumbnail;
64    int thumbnailTransactionSeq;
65    int thumbnailX;
66    int thumbnailY;
67    int thumbnailLayer;
68    int thumbnailForceAboveLayer;
69    Animation thumbnailAnimation;
70    final Transformation thumbnailTransformation = new Transformation();
71    // This flag indicates that the destruction of the thumbnail surface is synchronized with
72    // another animation, so defer the destruction of this thumbnail surface for a single frame
73    // after the secondary animation completes.
74    boolean deferThumbnailDestruction;
75    // This flag is set if the animator has deferThumbnailDestruction set and has reached the final
76    // frame of animation.  It will extend the animation by one frame and then clean up afterwards.
77    boolean deferFinalFrameCleanup;
78
79    /** WindowStateAnimator from mAppAnimator.allAppWindows as of last performLayout */
80    ArrayList<WindowStateAnimator> mAllAppWinAnimators = new ArrayList<WindowStateAnimator>();
81
82    static final Animation sDummyAnimation = new DummyAnimation();
83
84    public AppWindowAnimator(final AppWindowToken atoken) {
85        mAppToken = atoken;
86        mService = atoken.service;
87        mAnimator = atoken.mAnimator;
88    }
89
90    public void setAnimation(Animation anim, int width, int height) {
91        if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting animation in " + mAppToken
92                + ": " + anim + " wxh=" + width + "x" + height
93                + " isVisible=" + mAppToken.isVisible());
94        animation = anim;
95        animating = false;
96        if (!anim.isInitialized()) {
97            anim.initialize(width, height, width, height);
98        }
99        anim.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION);
100        anim.scaleCurrentDuration(mService.getTransitionAnimationScaleLocked());
101        int zorder = anim.getZAdjustment();
102        int adj = 0;
103        if (zorder == Animation.ZORDER_TOP) {
104            adj = WindowManagerService.TYPE_LAYER_OFFSET;
105        } else if (zorder == Animation.ZORDER_BOTTOM) {
106            adj = -WindowManagerService.TYPE_LAYER_OFFSET;
107        }
108
109        if (animLayerAdjustment != adj) {
110            animLayerAdjustment = adj;
111            updateLayers();
112        }
113        // Start out animation gone if window is gone, or visible if window is visible.
114        transformation.clear();
115        transformation.setAlpha(mAppToken.isVisible() ? 1 : 0);
116        hasTransformation = true;
117
118        if (!mAppToken.appFullscreen) {
119            anim.setBackgroundColor(0);
120        }
121    }
122
123    public void setDummyAnimation() {
124        if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting dummy animation in " + mAppToken
125                + " isVisible=" + mAppToken.isVisible());
126        animation = sDummyAnimation;
127        hasTransformation = true;
128        transformation.clear();
129        transformation.setAlpha(mAppToken.isVisible() ? 1 : 0);
130    }
131
132    public void clearAnimation() {
133        if (animation != null) {
134            animation = null;
135            animating = true;
136        }
137        clearThumbnail();
138        if (mAppToken.deferClearAllDrawn) {
139            mAppToken.allDrawn = false;
140            mAppToken.deferClearAllDrawn = false;
141        }
142    }
143
144    public boolean isAnimating() {
145        return animation != null || mAppToken.inPendingTransaction;
146    }
147
148    public void clearThumbnail() {
149        if (thumbnail != null) {
150            thumbnail.destroy();
151            thumbnail = null;
152        }
153        deferThumbnailDestruction = false;
154    }
155
156    void updateLayers() {
157        final int N = mAppToken.allAppWindows.size();
158        final int adj = animLayerAdjustment;
159        thumbnailLayer = -1;
160        for (int i=0; i<N; i++) {
161            final WindowState w = mAppToken.allAppWindows.get(i);
162            final WindowStateAnimator winAnimator = w.mWinAnimator;
163            winAnimator.mAnimLayer = w.mLayer + adj;
164            if (winAnimator.mAnimLayer > thumbnailLayer) {
165                thumbnailLayer = winAnimator.mAnimLayer;
166            }
167            if (WindowManagerService.DEBUG_LAYERS) Slog.v(TAG, "Updating layer " + w + ": "
168                    + winAnimator.mAnimLayer);
169            if (w == mService.mInputMethodTarget && !mService.mInputMethodTargetWaitingAnim) {
170                mService.setInputMethodAnimLayerAdjustment(adj);
171            }
172            if (w == mService.mWallpaperTarget && mService.mLowerWallpaperTarget == null) {
173                mService.setWallpaperAnimLayerAdjustmentLocked(adj);
174            }
175        }
176    }
177
178    private void stepThumbnailAnimation(long currentTime) {
179        thumbnailTransformation.clear();
180        thumbnailAnimation.getTransformation(currentTime, thumbnailTransformation);
181        thumbnailTransformation.getMatrix().preTranslate(thumbnailX, thumbnailY);
182
183        ScreenRotationAnimation screenRotationAnimation =
184                mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
185        final boolean screenAnimation = screenRotationAnimation != null
186                && screenRotationAnimation.isAnimating();
187        if (screenAnimation) {
188            thumbnailTransformation.postCompose(screenRotationAnimation.getEnterTransformation());
189        }
190        // cache often used attributes locally
191        final float tmpFloats[] = mService.mTmpFloats;
192        thumbnailTransformation.getMatrix().getValues(tmpFloats);
193        if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail,
194                "thumbnail", "POS " + tmpFloats[Matrix.MTRANS_X]
195                + ", " + tmpFloats[Matrix.MTRANS_Y], null);
196        thumbnail.setPosition(tmpFloats[Matrix.MTRANS_X], tmpFloats[Matrix.MTRANS_Y]);
197        if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail,
198                "thumbnail", "alpha=" + thumbnailTransformation.getAlpha()
199                + " layer=" + thumbnailLayer
200                + " matrix=[" + tmpFloats[Matrix.MSCALE_X]
201                + "," + tmpFloats[Matrix.MSKEW_Y]
202                + "][" + tmpFloats[Matrix.MSKEW_X]
203                + "," + tmpFloats[Matrix.MSCALE_Y] + "]", null);
204        thumbnail.setAlpha(thumbnailTransformation.getAlpha());
205        if (thumbnailForceAboveLayer > 0) {
206            thumbnail.setLayer(thumbnailForceAboveLayer + 1);
207        } else {
208            // The thumbnail is layered below the window immediately above this
209            // token's anim layer.
210            thumbnail.setLayer(thumbnailLayer + WindowManagerService.WINDOW_LAYER_MULTIPLIER
211                    - WindowManagerService.LAYER_OFFSET_THUMBNAIL);
212        }
213        thumbnail.setMatrix(tmpFloats[Matrix.MSCALE_X], tmpFloats[Matrix.MSKEW_Y],
214                tmpFloats[Matrix.MSKEW_X], tmpFloats[Matrix.MSCALE_Y]);
215    }
216
217    private boolean stepAnimation(long currentTime) {
218        if (animation == null) {
219            return false;
220        }
221        transformation.clear();
222        boolean hasMoreFrames = animation.getTransformation(currentTime, transformation);
223        if (!hasMoreFrames) {
224            if (deferThumbnailDestruction && !deferFinalFrameCleanup) {
225                // We are deferring the thumbnail destruction, so extend the animation for one more
226                // (dummy) frame before we clean up
227                deferFinalFrameCleanup = true;
228                hasMoreFrames = true;
229            } else {
230                if (false && WindowManagerService.DEBUG_ANIM) Slog.v(
231                        TAG, "Stepped animation in " + mAppToken + ": more=" + hasMoreFrames +
232                                ", xform=" + transformation);
233                deferFinalFrameCleanup = false;
234                animation = null;
235                clearThumbnail();
236                if (WindowManagerService.DEBUG_ANIM) Slog.v(
237                        TAG, "Finished animation in " + mAppToken + " @ " + currentTime);
238            }
239        }
240        hasTransformation = hasMoreFrames;
241        return hasMoreFrames;
242    }
243
244    // This must be called while inside a transaction.
245    boolean stepAnimationLocked(long currentTime) {
246        if (mService.okToDisplay()) {
247            // We will run animations as long as the display isn't frozen.
248
249            if (animation == sDummyAnimation) {
250                // This guy is going to animate, but not yet.  For now count
251                // it as not animating for purposes of scheduling transactions;
252                // when it is really time to animate, this will be set to
253                // a real animation and the next call will execute normally.
254                return false;
255            }
256
257            if ((mAppToken.allDrawn || animating || mAppToken.startingDisplayed)
258                    && animation != null) {
259                if (!animating) {
260                    if (WindowManagerService.DEBUG_ANIM) Slog.v(
261                        TAG, "Starting animation in " + mAppToken +
262                        " @ " + currentTime + " scale="
263                        + mService.getTransitionAnimationScaleLocked()
264                        + " allDrawn=" + mAppToken.allDrawn + " animating=" + animating);
265                    animation.setStartTime(currentTime);
266                    animating = true;
267                    if (thumbnail != null) {
268                        thumbnail.show();
269                        thumbnailAnimation.setStartTime(currentTime);
270                    }
271                }
272                if (stepAnimation(currentTime)) {
273                    // animation isn't over, step any thumbnail and that's
274                    // it for now.
275                    if (thumbnail != null) {
276                        stepThumbnailAnimation(currentTime);
277                    }
278                    return true;
279                }
280            }
281        } else if (animation != null) {
282            // If the display is frozen, and there is a pending animation,
283            // clear it and make sure we run the cleanup code.
284            animating = true;
285            animation = null;
286        }
287
288        hasTransformation = false;
289
290        if (!animating && animation == null) {
291            return false;
292        }
293
294        mAnimator.setAppLayoutChanges(this, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
295                "AppWindowToken");
296
297        clearAnimation();
298        animating = false;
299        if (animLayerAdjustment != 0) {
300            animLayerAdjustment = 0;
301            updateLayers();
302        }
303        if (mService.mInputMethodTarget != null
304                && mService.mInputMethodTarget.mAppToken == mAppToken) {
305            mService.moveInputMethodWindowsIfNeededLocked(true);
306        }
307
308        if (WindowManagerService.DEBUG_ANIM) Slog.v(
309                TAG, "Animation done in " + mAppToken
310                + ": reportedVisible=" + mAppToken.reportedVisible);
311
312        transformation.clear();
313
314        final int numAllAppWinAnimators = mAllAppWinAnimators.size();
315        for (int i = 0; i < numAllAppWinAnimators; i++) {
316            mAllAppWinAnimators.get(i).finishExit();
317        }
318        mService.mAppTransition.notifyAppTransitionFinishedLocked(this);
319        return false;
320    }
321
322    boolean showAllWindowsLocked() {
323        boolean isAnimating = false;
324        final int NW = mAllAppWinAnimators.size();
325        for (int i=0; i<NW; i++) {
326            WindowStateAnimator winAnimator = mAllAppWinAnimators.get(i);
327            if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
328                    "performing show on: " + winAnimator);
329            winAnimator.performShowLocked();
330            isAnimating |= winAnimator.isAnimating();
331        }
332        return isAnimating;
333    }
334
335    void dump(PrintWriter pw, String prefix, boolean dumpAll) {
336        pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken);
337        pw.print(prefix); pw.print("mAnimator="); pw.println(mAnimator);
338        pw.print(prefix); pw.print("freezingScreen="); pw.print(freezingScreen);
339                pw.print(" allDrawn="); pw.print(allDrawn);
340                pw.print(" animLayerAdjustment="); pw.println(animLayerAdjustment);
341        if (lastFreezeDuration != 0) {
342            pw.print(prefix); pw.print("lastFreezeDuration=");
343                    TimeUtils.formatDuration(lastFreezeDuration, pw); pw.println();
344        }
345        if (animating || animation != null) {
346            pw.print(prefix); pw.print("animating="); pw.println(animating);
347            pw.print(prefix); pw.print("animation="); pw.println(animation);
348        }
349        if (hasTransformation) {
350            pw.print(prefix); pw.print("XForm: ");
351                    transformation.printShortString(pw);
352                    pw.println();
353        }
354        if (thumbnail != null) {
355            pw.print(prefix); pw.print("thumbnail="); pw.print(thumbnail);
356                    pw.print(" x="); pw.print(thumbnailX);
357                    pw.print(" y="); pw.print(thumbnailY);
358                    pw.print(" layer="); pw.println(thumbnailLayer);
359            pw.print(prefix); pw.print("thumbnailAnimation="); pw.println(thumbnailAnimation);
360            pw.print(prefix); pw.print("thumbnailTransformation=");
361                    pw.println(thumbnailTransformation.toShortString());
362        }
363        for (int i=0; i<mAllAppWinAnimators.size(); i++) {
364            WindowStateAnimator wanim = mAllAppWinAnimators.get(i);
365            pw.print(prefix); pw.print("App Win Anim #"); pw.print(i);
366                    pw.print(": "); pw.println(wanim);
367        }
368    }
369
370    // This is an animation that does nothing: it just immediately finishes
371    // itself every time it is called.  It is used as a stub animation in cases
372    // where we want to synchronize multiple things that may be animating.
373    static final class DummyAnimation extends Animation {
374        @Override
375        public boolean getTransformation(long currentTime, Transformation outTransformation) {
376            return false;
377        }
378    }
379
380}
381