AppWindowAnimator.java revision 1ad99155b37c0cb0b7d95f084a2bff0cbfc8e12d
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    int thumbnailForceAboveLayer;
68    Animation thumbnailAnimation;
69    final Transformation thumbnailTransformation = new Transformation();
70    // This flag indicates that the destruction of the thumbnail surface is synchronized with
71    // another animation, so do not pre-emptively destroy the thumbnail surface when the animation
72    // completes
73    boolean deferThumbnailDestruction;
74    // This is the thumbnail surface that has been bestowed upon this animator, and when the
75    // surface for this animator's animation is complete, we will destroy the thumbnail surface
76    // as well.  Do not animate or do anything with this surface.
77    SurfaceControl deferredThumbnail;
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        if (!deferThumbnailDestruction) {
138            clearThumbnail();
139        }
140        if (mAppToken.deferClearAllDrawn) {
141            mAppToken.allDrawn = false;
142            mAppToken.deferClearAllDrawn = false;
143        }
144    }
145
146    public void clearThumbnail() {
147        if (thumbnail != null) {
148            thumbnail.destroy();
149            thumbnail = null;
150        }
151    }
152
153    public void clearDeferredThumbnail() {
154        if (deferredThumbnail != null) {
155            deferredThumbnail.destroy();
156            deferredThumbnail = null;
157        }
158    }
159
160    void updateLayers() {
161        final int N = mAppToken.allAppWindows.size();
162        final int adj = animLayerAdjustment;
163        thumbnailLayer = -1;
164        for (int i=0; i<N; i++) {
165            final WindowState w = mAppToken.allAppWindows.get(i);
166            final WindowStateAnimator winAnimator = w.mWinAnimator;
167            winAnimator.mAnimLayer = w.mLayer + adj;
168            if (winAnimator.mAnimLayer > thumbnailLayer) {
169                thumbnailLayer = winAnimator.mAnimLayer;
170            }
171            if (WindowManagerService.DEBUG_LAYERS) Slog.v(TAG, "Updating layer " + w + ": "
172                    + winAnimator.mAnimLayer);
173            if (w == mService.mInputMethodTarget && !mService.mInputMethodTargetWaitingAnim) {
174                mService.setInputMethodAnimLayerAdjustment(adj);
175            }
176            if (w == mService.mWallpaperTarget && mService.mLowerWallpaperTarget == null) {
177                mService.setWallpaperAnimLayerAdjustmentLocked(adj);
178            }
179        }
180    }
181
182    private void stepThumbnailAnimation(long currentTime) {
183        thumbnailTransformation.clear();
184        thumbnailAnimation.getTransformation(currentTime, thumbnailTransformation);
185        thumbnailTransformation.getMatrix().preTranslate(thumbnailX, thumbnailY);
186
187        ScreenRotationAnimation screenRotationAnimation =
188                mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
189        final boolean screenAnimation = screenRotationAnimation != null
190                && screenRotationAnimation.isAnimating();
191        if (screenAnimation) {
192            thumbnailTransformation.postCompose(screenRotationAnimation.getEnterTransformation());
193        }
194        // cache often used attributes locally
195        final float tmpFloats[] = mService.mTmpFloats;
196        thumbnailTransformation.getMatrix().getValues(tmpFloats);
197        if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail,
198                "thumbnail", "POS " + tmpFloats[Matrix.MTRANS_X]
199                + ", " + tmpFloats[Matrix.MTRANS_Y], null);
200        thumbnail.setPosition(tmpFloats[Matrix.MTRANS_X], tmpFloats[Matrix.MTRANS_Y]);
201        if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail,
202                "thumbnail", "alpha=" + thumbnailTransformation.getAlpha()
203                + " layer=" + thumbnailLayer
204                + " matrix=[" + tmpFloats[Matrix.MSCALE_X]
205                + "," + tmpFloats[Matrix.MSKEW_Y]
206                + "][" + tmpFloats[Matrix.MSKEW_X]
207                + "," + tmpFloats[Matrix.MSCALE_Y] + "]", null);
208        thumbnail.setAlpha(thumbnailTransformation.getAlpha());
209        if (thumbnailForceAboveLayer > 0) {
210            thumbnail.setLayer(thumbnailForceAboveLayer + 1);
211        } else {
212            // The thumbnail is layered below the window immediately above this
213            // token's anim layer.
214            thumbnail.setLayer(thumbnailLayer + WindowManagerService.WINDOW_LAYER_MULTIPLIER
215                    - WindowManagerService.LAYER_OFFSET_THUMBNAIL);
216        }
217        thumbnail.setMatrix(tmpFloats[Matrix.MSCALE_X], tmpFloats[Matrix.MSKEW_Y],
218                tmpFloats[Matrix.MSKEW_X], tmpFloats[Matrix.MSCALE_Y]);
219    }
220
221    private boolean stepAnimation(long currentTime) {
222        if (animation == null) {
223            return false;
224        }
225        transformation.clear();
226        final boolean more = animation.getTransformation(currentTime, transformation);
227        if (false && WindowManagerService.DEBUG_ANIM) Slog.v(
228            TAG, "Stepped animation in " + mAppToken + ": more=" + more + ", xform=" + transformation);
229        if (!more) {
230            animation = null;
231            if (!deferThumbnailDestruction) {
232                clearThumbnail();
233            }
234            if (WindowManagerService.DEBUG_ANIM) Slog.v(
235                TAG, "Finished animation in " + mAppToken + " @ " + currentTime);
236        }
237        hasTransformation = more;
238        return more;
239    }
240
241    // This must be called while inside a transaction.
242    boolean stepAnimationLocked(long currentTime) {
243        if (mService.okToDisplay()) {
244            // We will run animations as long as the display isn't frozen.
245
246            if (animation == sDummyAnimation) {
247                // This guy is going to animate, but not yet.  For now count
248                // it as not animating for purposes of scheduling transactions;
249                // when it is really time to animate, this will be set to
250                // a real animation and the next call will execute normally.
251                return false;
252            }
253
254            if ((mAppToken.allDrawn || animating || mAppToken.startingDisplayed)
255                    && animation != null) {
256                if (!animating) {
257                    if (WindowManagerService.DEBUG_ANIM) Slog.v(
258                        TAG, "Starting animation in " + mAppToken +
259                        " @ " + currentTime + " scale="
260                        + mService.getTransitionAnimationScaleLocked()
261                        + " allDrawn=" + mAppToken.allDrawn + " animating=" + animating);
262                    animation.setStartTime(currentTime);
263                    animating = true;
264                    if (thumbnail != null) {
265                        thumbnail.show();
266                        thumbnailAnimation.setStartTime(currentTime);
267                    }
268                }
269                if (stepAnimation(currentTime)) {
270                    // animation isn't over, step any thumbnail and that's
271                    // it for now.
272                    if (thumbnail != null) {
273                        stepThumbnailAnimation(currentTime);
274                    }
275                    return true;
276                }
277            }
278        } else if (animation != null) {
279            // If the display is frozen, and there is a pending animation,
280            // clear it and make sure we run the cleanup code.
281            animating = true;
282            animation = null;
283        }
284
285        hasTransformation = false;
286
287        if (!animating && animation == null) {
288            return false;
289        }
290
291        mAnimator.setAppLayoutChanges(this, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
292                "AppWindowToken");
293
294        clearAnimation();
295        animating = false;
296        if (animLayerAdjustment != 0) {
297            animLayerAdjustment = 0;
298            updateLayers();
299        }
300        if (mService.mInputMethodTarget != null
301                && mService.mInputMethodTarget.mAppToken == mAppToken) {
302            mService.moveInputMethodWindowsIfNeededLocked(true);
303        }
304
305        if (WindowManagerService.DEBUG_ANIM) Slog.v(
306                TAG, "Animation done in " + mAppToken
307                + ": reportedVisible=" + mAppToken.reportedVisible);
308
309        transformation.clear();
310
311        final int N = mAllAppWinAnimators.size();
312        for (int i=0; i<N; i++) {
313            final WindowStateAnimator winAnim = mAllAppWinAnimators.get(i);
314            if (mAppToken.mLaunchTaskBehind) {
315                winAnim.mWin.mExiting = true;
316            }
317            winAnim.finishExit();
318        }
319        if (mAppToken.mLaunchTaskBehind) {
320            try {
321                mService.mActivityManager.notifyLaunchTaskBehindComplete(mAppToken.token);
322            } catch (RemoteException e) {
323            }
324            mAppToken.mLaunchTaskBehind = false;
325        } else {
326            mAppToken.updateReportedVisibilityLocked();
327            if (mAppToken.mEnteringAnimation) {
328                mAppToken.mEnteringAnimation = false;
329                try {
330                    mService.mActivityManager.notifyEnterAnimationComplete(mAppToken.token);
331                } catch (RemoteException e) {
332                }
333            }
334        }
335
336        return false;
337    }
338
339    boolean showAllWindowsLocked() {
340        boolean isAnimating = false;
341        final int NW = mAllAppWinAnimators.size();
342        for (int i=0; i<NW; i++) {
343            WindowStateAnimator winAnimator = mAllAppWinAnimators.get(i);
344            if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
345                    "performing show on: " + winAnimator);
346            winAnimator.performShowLocked();
347            isAnimating |= winAnimator.isAnimating();
348        }
349        return isAnimating;
350    }
351
352    void dump(PrintWriter pw, String prefix, boolean dumpAll) {
353        pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken);
354        pw.print(prefix); pw.print("mAnimator="); pw.println(mAnimator);
355        pw.print(prefix); pw.print("freezingScreen="); pw.print(freezingScreen);
356                pw.print(" allDrawn="); pw.print(allDrawn);
357                pw.print(" animLayerAdjustment="); pw.println(animLayerAdjustment);
358        if (lastFreezeDuration != 0) {
359            pw.print(prefix); pw.print("lastFreezeDuration=");
360                    TimeUtils.formatDuration(lastFreezeDuration, pw); pw.println();
361        }
362        if (animating || animation != null) {
363            pw.print(prefix); pw.print("animating="); pw.println(animating);
364            pw.print(prefix); pw.print("animation="); pw.println(animation);
365        }
366        if (hasTransformation) {
367            pw.print(prefix); pw.print("XForm: ");
368                    transformation.printShortString(pw);
369                    pw.println();
370        }
371        if (thumbnail != null) {
372            pw.print(prefix); pw.print("thumbnail="); pw.print(thumbnail);
373                    pw.print(" x="); pw.print(thumbnailX);
374                    pw.print(" y="); pw.print(thumbnailY);
375                    pw.print(" layer="); pw.println(thumbnailLayer);
376            pw.print(prefix); pw.print("thumbnailAnimation="); pw.println(thumbnailAnimation);
377            pw.print(prefix); pw.print("thumbnailTransformation=");
378                    pw.println(thumbnailTransformation.toShortString());
379        }
380        for (int i=0; i<mAllAppWinAnimators.size(); i++) {
381            WindowStateAnimator wanim = mAllAppWinAnimators.get(i);
382            pw.print(prefix); pw.print("App Win Anim #"); pw.print(i);
383                    pw.print(": "); pw.println(wanim);
384        }
385    }
386
387    // This is an animation that does nothing: it just immediately finishes
388    // itself every time it is called.  It is used as a stub animation in cases
389    // where we want to synchronize multiple things that may be animating.
390    static final class DummyAnimation extends Animation {
391        @Override
392        public boolean getTransformation(long currentTime, Transformation outTransformation) {
393            return false;
394        }
395    }
396
397}
398