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