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