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