blob: d86d4115de9fb7ed9125cbad5df8bb6a6afa5fc3 [file] [log] [blame]
Craig Mautnera2c77052012-03-26 12:14:43 -07001// Copyright 2012 Google Inc. All Rights Reserved.
2
3package com.android.server.wm;
4
5import android.util.Slog;
6import android.view.WindowManager;
7import android.view.WindowManagerPolicy;
8import android.view.animation.Animation;
9import android.view.animation.Transformation;
10
11import com.android.server.wm.WindowManagerService.H;
12
13import java.io.PrintWriter;
14
15/**
16 * @author cmautner@google.com (Craig Mautner)
17 *
18 */
19class WindowStateAnimator {
20
21 final WindowManagerService mService;
22 final WindowState mWin;
23 final WindowState mAttachedWindow;
24
25 // Currently running animation.
26 boolean mAnimating;
27 boolean mLocalAnimating;
28 Animation mAnimation;
29 boolean mAnimationIsEntrance;
30 boolean mHasTransformation;
31 boolean mHasLocalTransformation;
32 final Transformation mTransformation = new Transformation();
33 boolean mWasAnimating; // Were we animating going into the most recent animation step?
34
35 public WindowStateAnimator(final WindowManagerService service, final WindowState win,
36 final WindowState attachedWindow) {
37 mService = service;
38 mWin = win;
39 mAttachedWindow = attachedWindow;
40 }
41
42 public void setAnimation(Animation anim) {
43 if (WindowManagerService.localLOGV) Slog.v(
44 WindowManagerService.TAG, "Setting animation in " + this + ": " + anim);
45 mAnimating = false;
46 mLocalAnimating = false;
47 mAnimation = anim;
48 mAnimation.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION);
49 mAnimation.scaleCurrentDuration(mService.mWindowAnimationScale);
50 // Start out animation gone if window is gone, or visible if window is visible.
51 mTransformation.clear();
52 mTransformation.setAlpha(mWin.mLastHidden ? 0 : 1);
53 mHasLocalTransformation = true;
54 }
55
56 public void clearAnimation() {
57 if (mAnimation != null) {
58 mAnimating = true;
59 mLocalAnimating = false;
60 mAnimation.cancel();
61 mAnimation = null;
62 }
63 }
64
65 /** Is the window or its container currently animating? */
66 boolean isAnimating() {
67 final WindowState attached = mAttachedWindow;
68 final AppWindowToken atoken = mWin.mAppToken;
69 return mAnimation != null
70 || (attached != null && attached.mWinAnimator.mAnimation != null)
71 || (atoken != null &&
72 (atoken.animation != null
73 || atoken.inPendingTransaction));
74 }
75
76 /** Is this window currently animating? */
77 boolean isWindowAnimating() {
78 return mAnimation != null;
79 }
80
81 // TODO: Fix and call finishExit() instead of cancelExitAnimationForNextAnimationLocked()
82 // for avoiding the code duplication.
83 void cancelExitAnimationForNextAnimationLocked() {
84 if (!mWin.mExiting) return;
85 if (mAnimation != null) {
86 mAnimation.cancel();
87 mAnimation = null;
88 mWin.destroySurfaceLocked();
89 }
90 mWin.mExiting = false;
91 }
92
93 private boolean stepAnimation(long currentTime) {
94 if ((mAnimation == null) || !mLocalAnimating) {
95 return false;
96 }
97 mTransformation.clear();
98 final boolean more = mAnimation.getTransformation(currentTime, mTransformation);
99 if (WindowManagerService.DEBUG_ANIM) Slog.v(
100 WindowManagerService.TAG, "Stepped animation in " + this +
101 ": more=" + more + ", xform=" + mTransformation);
102 return more;
103 }
104
105 // This must be called while inside a transaction. Returns true if
106 // there is more animation to run.
107 boolean stepAnimationLocked(long currentTime) {
108 // Save the animation state as it was before this step so WindowManagerService can tell if
109 // we just started or just stopped animating by comparing mWasAnimating with isAnimating().
110 mWasAnimating = mAnimating;
111 if (mService.okToDisplay()) {
112 // We will run animations as long as the display isn't frozen.
113
114 if (mWin.isDrawnLw() && mAnimation != null) {
115 mHasTransformation = true;
116 mHasLocalTransformation = true;
117 if (!mLocalAnimating) {
118 if (WindowManagerService.DEBUG_ANIM) Slog.v(
119 WindowManagerService.TAG, "Starting animation in " + this +
120 " @ " + currentTime + ": ww=" + mWin.mFrame.width() +
121 " wh=" + mWin.mFrame.height() +
122 " dw=" + mWin.mAnimDw + " dh=" + mWin.mAnimDh +
123 " scale=" + mService.mWindowAnimationScale);
124 mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(), mWin.mAnimDw,
125 mWin.mAnimDh);
126 mAnimation.setStartTime(currentTime);
127 mLocalAnimating = true;
128 mAnimating = true;
129 }
130 if ((mAnimation != null) && mLocalAnimating) {
131 if (stepAnimation(currentTime)) {
132 return true;
133 }
134 }
135 if (WindowManagerService.DEBUG_ANIM) Slog.v(
136 WindowManagerService.TAG, "Finished animation in " + this +
137 " @ " + currentTime);
138 //WindowManagerService.this.dump();
139 }
140 mHasLocalTransformation = false;
141 if ((!mLocalAnimating || mAnimationIsEntrance) && mWin.mAppToken != null
142 && mWin.mAppToken.animation != null) {
143 // When our app token is animating, we kind-of pretend like
144 // we are as well. Note the mLocalAnimating mAnimationIsEntrance
145 // part of this check means that we will only do this if
146 // our window is not currently exiting, or it is not
147 // locally animating itself. The idea being that one that
148 // is exiting and doing a local animation should be removed
149 // once that animation is done.
150 mAnimating = true;
151 mHasTransformation = true;
152 mTransformation.clear();
153 return false;
154 } else if (mHasTransformation) {
155 // Little trick to get through the path below to act like
156 // we have finished an animation.
157 mAnimating = true;
158 } else if (isAnimating()) {
159 mAnimating = true;
160 }
161 } else if (mAnimation != null) {
162 // If the display is frozen, and there is a pending animation,
163 // clear it and make sure we run the cleanup code.
164 mAnimating = true;
165 mLocalAnimating = true;
166 mAnimation.cancel();
167 mAnimation = null;
168 }
169
170 if (!mAnimating && !mLocalAnimating) {
171 return false;
172 }
173
174 if (WindowManagerService.DEBUG_ANIM) Slog.v(
175 WindowManagerService.TAG, "Animation done in " + this + ": exiting=" + mWin.mExiting
176 + ", reportedVisible="
177 + (mWin.mAppToken != null ? mWin.mAppToken.reportedVisible : false));
178
179 mAnimating = false;
180 mLocalAnimating = false;
181 if (mAnimation != null) {
182 mAnimation.cancel();
183 mAnimation = null;
184 }
185 if (mService.mWindowDetachedWallpaper == mWin) {
186 mService.mWindowDetachedWallpaper = null;
187 }
188 mWin.mAnimLayer = mWin.mLayer;
189 if (mWin.mIsImWindow) {
190 mWin.mAnimLayer += mService.mInputMethodAnimLayerAdjustment;
191 } else if (mWin.mIsWallpaper) {
192 mWin.mAnimLayer += mService.mWallpaperAnimLayerAdjustment;
193 }
194 if (WindowManagerService.DEBUG_LAYERS) Slog.v(WindowManagerService.TAG, "Stepping win " + this
195 + " anim layer: " + mWin.mAnimLayer);
196 mHasTransformation = false;
197 mHasLocalTransformation = false;
198 if (mWin.mPolicyVisibility != mWin.mPolicyVisibilityAfterAnim) {
199 if (WindowState.DEBUG_VISIBILITY) {
200 Slog.v(WindowManagerService.TAG, "Policy visibility changing after anim in " + this + ": "
201 + mWin.mPolicyVisibilityAfterAnim);
202 }
203 mWin.mPolicyVisibility = mWin.mPolicyVisibilityAfterAnim;
204 mService.mLayoutNeeded = true;
205 if (!mWin.mPolicyVisibility) {
206 if (mService.mCurrentFocus == mWin) {
207 mService.mFocusMayChange = true;
208 }
209 // Window is no longer visible -- make sure if we were waiting
210 // for it to be displayed before enabling the display, that
211 // we allow the display to be enabled now.
212 mService.enableScreenIfNeededLocked();
213 }
214 }
215 mTransformation.clear();
216 if (mWin.mHasDrawn
217 && mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
218 && mWin.mAppToken != null
219 && mWin.mAppToken.firstWindowDrawn
220 && mWin.mAppToken.startingData != null) {
221 if (WindowManagerService.DEBUG_STARTING_WINDOW) Slog.v(WindowManagerService.TAG, "Finish starting "
222 + mWin.mToken + ": first real window done animating");
223 mService.mFinishedStarting.add(mWin.mAppToken);
224 mService.mH.sendEmptyMessage(H.FINISHED_STARTING);
225 }
226
227 finishExit();
228 mService.mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
229 if (WindowManagerService.DEBUG_LAYOUT_REPEATS) mService.debugLayoutRepeats("WindowState");
230
231 if (mWin.mAppToken != null) {
232 mWin.mAppToken.updateReportedVisibilityLocked();
233 }
234
235 return false;
236 }
237
238 void finishExit() {
239 if (WindowManagerService.DEBUG_ANIM) Slog.v(
240 WindowManagerService.TAG, "finishExit in " + this
241 + ": exiting=" + mWin.mExiting
242 + " remove=" + mWin.mRemoveOnExit
243 + " windowAnimating=" + isWindowAnimating());
244
245 final int N = mWin.mChildWindows.size();
246 for (int i=0; i<N; i++) {
247 mWin.mChildWindows.get(i).mWinAnimator.finishExit();
248 }
249
250 if (!mWin.mExiting) {
251 return;
252 }
253
254 if (isWindowAnimating()) {
255 return;
256 }
257
258 if (WindowManagerService.localLOGV) Slog.v(
259 WindowManagerService.TAG, "Exit animation finished in " + this
260 + ": remove=" + mWin.mRemoveOnExit);
261 if (mWin.mSurface != null) {
262 mService.mDestroySurface.add(mWin);
263 mWin.mDestroying = true;
264 if (WindowState.SHOW_TRANSACTIONS) WindowManagerService.logSurface(
265 mWin, "HIDE (finishExit)", null);
266 mWin.mSurfaceShown = false;
267 try {
268 mWin.mSurface.hide();
269 } catch (RuntimeException e) {
270 Slog.w(WindowManagerService.TAG, "Error hiding surface in " + this, e);
271 }
272 mWin.mLastHidden = true;
273 }
274 mWin.mExiting = false;
275 if (mWin.mRemoveOnExit) {
276 mService.mPendingRemove.add(mWin);
277 mWin.mRemoveOnExit = false;
278 }
279 }
280
281 public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
282 if (mAnimating || mLocalAnimating || mAnimationIsEntrance
283 || mAnimation != null) {
284 pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating);
285 pw.print(" mLocalAnimating="); pw.print(mLocalAnimating);
286 pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
287 pw.print(" mAnimation="); pw.println(mAnimation);
288 }
289 if (mHasTransformation || mHasLocalTransformation) {
290 pw.print(prefix); pw.print("XForm: has=");
291 pw.print(mHasTransformation);
292 pw.print(" hasLocal="); pw.print(mHasLocalTransformation);
293 pw.print(" "); mTransformation.printShortString(pw);
294 pw.println();
295 }
296 }
297
298}