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