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