blob: b3dbee192cfd5b38f76580ee556b7a2ee488bc94 [file] [log] [blame]
Craig Mautner764983d2012-03-22 11:37:36 -07001// Copyright 2012 Google Inc. All Rights Reserved.
2
3package com.android.server.wm;
4
5import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
6
7import android.content.Context;
8import android.os.SystemClock;
9import android.util.Log;
10import android.util.Slog;
11import android.view.Surface;
12import android.view.WindowManager;
13import android.view.WindowManager.LayoutParams;
14import android.view.WindowManagerPolicy;
15import android.view.animation.Animation;
16import android.view.animation.AnimationUtils;
17
18import com.android.internal.policy.impl.PhoneWindowManager;
19
20/**
21 * @author cmautner@google.com (Craig Mautner)
22 * Singleton class that carries out the animations and Surface operations in a separate task
23 * on behalf of WindowManagerService.
24 */
25public class WindowAnimator {
26 private static final String TAG = "WindowAnimations";
27
28 final WindowManagerService mService;
29 final Context mContext;
30 final WindowManagerPolicy mPolicy;
31
32 boolean mAnimating;
33 boolean mUpdateRotation;
34 boolean mTokenMayBeDrawn;
35 boolean mForceHiding;
36 WindowState mWindowAnimationBackground;
37 int mWindowAnimationBackgroundColor;
38 int mAdjResult;
39
40 int mPendingLayoutChanges;
41
42 /** Overall window dimensions */
43 int mDw, mDh;
44
45 /** Interior window dimensions */
46 int mInnerDw, mInnerDh;
47
48 /** Time of current animation step. Reset on each iteration */
49 long mCurrentTime;
50
51 /** Skip repeated AppWindowTokens initialization. Note that AppWindowsToken's version of this
52 * is a long initialized to Long.MIN_VALUE so that it doesn't match this value on startup. */
53 private int mTransactionSequence;
54
55 /** The one and only screen rotation if one is happening */
56 ScreenRotationAnimation mScreenRotationAnimation = null;
57
58 WindowAnimator(final WindowManagerService service, final Context context,
59 final WindowManagerPolicy policy) {
60 mService = service;
61 mContext = context;
62 mPolicy = policy;
63 }
64
65 private void updateWindowsAppsAndRotationAnimationsLocked() {
66 int i;
67 final int NAT = mService.mAppTokens.size();
68 for (i=0; i<NAT; i++) {
69 final AppWindowToken appToken = mService.mAppTokens.get(i);
70 if (appToken.stepAnimationLocked(mCurrentTime, mInnerDw, mInnerDh)) {
71 mAnimating = true;
72 }
73 }
74
75 if (mScreenRotationAnimation != null &&
76 (mScreenRotationAnimation.isAnimating() ||
77 mScreenRotationAnimation.mFinishAnimReady)) {
78 if (mScreenRotationAnimation.stepAnimationLocked(mCurrentTime)) {
79 mUpdateRotation = false;
80 mAnimating = true;
81 } else {
82 mUpdateRotation = true;
83 mScreenRotationAnimation.kill();
84 mScreenRotationAnimation = null;
85 }
86 }
87 }
88
89 private void updateWindowsAndWallpaperLocked() {
90 ++mTransactionSequence;
91
92 for (int i = mService.mWindows.size() - 1; i >= 0; i--) {
93 WindowState w = mService.mWindows.get(i);
94
95 final WindowManager.LayoutParams attrs = w.mAttrs;
96
97 if (w.mSurface != null) {
98 // Take care of the window being ready to display.
99 if (w.commitFinishDrawingLocked(mCurrentTime)) {
100 if ((w.mAttrs.flags
101 & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
102 if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
103 "First draw done in potential wallpaper target " + w);
104 mService.mInnerFields.mWallpaperMayChange = true;
105 mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
106 }
107 }
108
109 // If the window has moved due to its containing
110 // content frame changing, then we'd like to animate
111 // it. The checks here are ordered by what is least
112 // likely to be true first.
113 if (w.shouldAnimateMove()) {
114 // Frame has moved, containing content frame
115 // has also moved, and we're not currently animating...
116 // let's do something.
117 Animation a = AnimationUtils.loadAnimation(mContext,
118 com.android.internal.R.anim.window_move_from_decor);
119 w.setAnimation(a);
120 w.mAnimDw = w.mLastFrame.left - w.mFrame.left;
121 w.mAnimDh = w.mLastFrame.top - w.mFrame.top;
122 } else {
123 w.mAnimDw = mInnerDw;
124 w.mAnimDh = mInnerDh;
125 }
126
127 final boolean wasAnimating = w.mWasAnimating;
128 final boolean nowAnimating = w.stepAnimationLocked(mCurrentTime);
129
130 if (WindowManagerService.DEBUG_WALLPAPER) {
131 Slog.v(TAG, w + ": wasAnimating=" + wasAnimating +
132 ", nowAnimating=" + nowAnimating);
133 }
134
135 // If this window is animating, make a note that we have
136 // an animating window and take care of a request to run
137 // a detached wallpaper animation.
138 if (nowAnimating) {
139 if (w.mAnimation != null) {
140 if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
141 && w.mAnimation.getDetachWallpaper()) {
142 mService.mInnerFields.mDetachedWallpaper = w;
143 }
144 if (w.mAnimation.getBackgroundColor() != 0) {
145 if (mWindowAnimationBackground == null
146 || (w.mAnimLayer < mWindowAnimationBackground.mAnimLayer)) {
147 mWindowAnimationBackground = w;
148 mWindowAnimationBackgroundColor =
149 w.mAnimation.getBackgroundColor();
150 }
151 }
152 }
153 mAnimating = true;
154 }
155
156 // If this window's app token is running a detached wallpaper
157 // animation, make a note so we can ensure the wallpaper is
158 // displayed behind it.
159 if (w.mAppToken != null && w.mAppToken.animation != null
160 && w.mAppToken.animating) {
161 if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
162 && w.mAppToken.animation.getDetachWallpaper()) {
163 mService.mInnerFields.mDetachedWallpaper = w;
164 }
165 if (w.mAppToken.animation.getBackgroundColor() != 0) {
166 if (mWindowAnimationBackground == null
167 || (w.mAnimLayer <
168 mWindowAnimationBackground.mAnimLayer)) {
169 mWindowAnimationBackground = w;
170 mWindowAnimationBackgroundColor =
171 w.mAppToken.animation.getBackgroundColor();
172 }
173 }
174 }
175
176 if (wasAnimating && !w.mAnimating && mService.mWallpaperTarget == w) {
177 mService.mInnerFields.mWallpaperMayChange = true;
178 mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
179 }
180
181 if (mPolicy.doesForceHide(w, attrs)) {
182 if (!wasAnimating && nowAnimating) {
183 if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
184 "Animation started that could impact force hide: "
185 + w);
186 mService.mInnerFields.mWallpaperForceHidingChanged = true;
187 mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
188 mService.mFocusMayChange = true;
189 } else if (w.isReadyForDisplay() && w.mAnimation == null) {
190 mForceHiding = true;
191 }
192 } else if (mPolicy.canBeForceHidden(w, attrs)) {
193 boolean changed;
194 if (mForceHiding) {
195 changed = w.hideLw(false, false);
196 if (WindowManagerService.DEBUG_VISIBILITY && changed) Slog.v(TAG,
197 "Now policy hidden: " + w);
198 } else {
199 changed = w.showLw(false, false);
200 if (WindowManagerService.DEBUG_VISIBILITY && changed) Slog.v(TAG,
201 "Now policy shown: " + w);
202 if (changed) {
203 if (mService.mInnerFields.mWallpaperForceHidingChanged
204 && w.isVisibleNow() /*w.isReadyForDisplay()*/) {
205 // Assume we will need to animate. If
206 // we don't (because the wallpaper will
207 // stay with the lock screen), then we will
208 // clean up later.
209 Animation a = mPolicy.createForceHideEnterAnimation();
210 if (a != null) {
211 w.setAnimation(a);
212 }
213 }
214 if (mCurrentFocus == null || mCurrentFocus.mLayer < w.mLayer) {
215 // We are showing on to of the current
216 // focus, so re-evaluate focus to make
217 // sure it is correct.
218 mService.mFocusMayChange = true;
219 }
220 }
221 }
222 if (changed && (attrs.flags
223 & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
224 mService.mInnerFields.mWallpaperMayChange = true;
225 mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
226 }
227 }
228 }
229
230 final AppWindowToken atoken = w.mAppToken;
231 if (atoken != null && (!atoken.allDrawn || atoken.freezingScreen)) {
232 if (atoken.lastTransactionSequence != mTransactionSequence) {
233 atoken.lastTransactionSequence = mTransactionSequence;
234 atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
235 atoken.startingDisplayed = false;
236 }
237 if ((w.isOnScreen() || w.mAttrs.type
238 == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
239 && !w.mExiting && !w.mDestroying) {
240 if (WindowManagerService.DEBUG_VISIBILITY ||
241 WindowManagerService.DEBUG_ORIENTATION) {
242 Slog.v(TAG, "Eval win " + w + ": isDrawn="
243 + w.isDrawnLw()
244 + ", isAnimating=" + w.isAnimating());
245 if (!w.isDrawnLw()) {
246 Slog.v(TAG, "Not displayed: s=" + w.mSurface
247 + " pv=" + w.mPolicyVisibility
248 + " dp=" + w.mDrawPending
249 + " cdp=" + w.mCommitDrawPending
250 + " ah=" + w.mAttachedHidden
251 + " th=" + atoken.hiddenRequested
252 + " a=" + w.mAnimating);
253 }
254 }
255 if (w != atoken.startingWindow) {
256 if (!atoken.freezingScreen || !w.mAppFreezing) {
257 atoken.numInterestingWindows++;
258 if (w.isDrawnLw()) {
259 atoken.numDrawnWindows++;
260 if (WindowManagerService.DEBUG_VISIBILITY ||
261 WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
262 "tokenMayBeDrawn: " + atoken
263 + " freezingScreen=" + atoken.freezingScreen
264 + " mAppFreezing=" + w.mAppFreezing);
265 mTokenMayBeDrawn = true;
266 }
267 }
268 } else if (w.isDrawnLw()) {
269 atoken.startingDisplayed = true;
270 }
271 }
272 } else if (w.mReadyToShow) {
273 w.performShowLocked();
274 mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
275 }
276 } // end forall windows
277 }
278
279 private void testTokenMayBeDrawnLocked() {
280 // See if any windows have been drawn, so they (and others
281 // associated with them) can now be shown.
282 final int NT = mService.mAppTokens.size();
283 for (int i=0; i<NT; i++) {
284 AppWindowToken wtoken = mService.mAppTokens.get(i);
285 if (wtoken.freezingScreen) {
286 int numInteresting = wtoken.numInterestingWindows;
287 if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
288 if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
289 "allDrawn: " + wtoken
290 + " interesting=" + numInteresting
291 + " drawn=" + wtoken.numDrawnWindows);
292 wtoken.showAllWindowsLocked();
293 mService.unsetAppFreezingScreenLocked(wtoken, false, true);
294 if (WindowManagerService.DEBUG_ORIENTATION) Slog.i(TAG,
295 "Setting mOrientationChangeComplete=true because wtoken "
296 + wtoken + " numInteresting=" + numInteresting
297 + " numDrawn=" + wtoken.numDrawnWindows);
298 mService.mInnerFields.mOrientationChangeComplete = true;
299 }
300 } else if (!wtoken.allDrawn) {
301 int numInteresting = wtoken.numInterestingWindows;
302 if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
303 if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
304 "allDrawn: " + wtoken
305 + " interesting=" + numInteresting
306 + " drawn=" + wtoken.numDrawnWindows);
307 wtoken.allDrawn = true;
308 mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
309
310 // We can now show all of the drawn windows!
311 if (!mService.mOpeningApps.contains(wtoken)) {
312 mAnimating |= wtoken.showAllWindowsLocked();
313 }
314 }
315 }
316 }
317 }
318
319 private void performAnimationsLocked() {
320 if (WindowManagerService.DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: seq="
321 + mTransactionSequence + " mAnimating="
322 + mAnimating);
323
324 mTokenMayBeDrawn = false;
325 mService.mInnerFields.mWallpaperMayChange = false;
326 mForceHiding = false;
327 mService.mInnerFields.mDetachedWallpaper = null;
328 mWindowAnimationBackground = null;
329 mWindowAnimationBackgroundColor = 0;
330
331 updateWindowsAndWallpaperLocked();
332
333 if (mTokenMayBeDrawn) {
334 testTokenMayBeDrawnLocked();
335 }
336
337 if (WindowManagerService.DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: changes=0x"
338 + Integer.toHexString(mPendingLayoutChanges));
339 }
340
341 public void prepareSurfaceLocked(final WindowState w, final boolean recoveringMemory) {
342 if (w.mSurface == null) {
343 if (w.mOrientationChanging) {
344 if (WindowManagerService.DEBUG_ORIENTATION) {
345 Slog.v(TAG, "Orientation change skips hidden " + w);
346 }
347 w.mOrientationChanging = false;
348 }
349 return;
350 }
351
352 boolean displayed = false;
353
354 w.computeShownFrameLocked();
355
356 int width, height;
357 if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
358 // for a scaled surface, we just want to use
359 // the requested size.
360 width = w.mRequestedWidth;
361 height = w.mRequestedHeight;
362 } else {
363 width = w.mCompatFrame.width();
364 height = w.mCompatFrame.height();
365 }
366
367 if (width < 1) {
368 width = 1;
369 }
370 if (height < 1) {
371 height = 1;
372 }
373 final boolean surfaceResized = w.mSurfaceW != width || w.mSurfaceH != height;
374 if (surfaceResized) {
375 w.mSurfaceW = width;
376 w.mSurfaceH = height;
377 }
378
379 if (w.mSurfaceX != w.mShownFrame.left
380 || w.mSurfaceY != w.mShownFrame.top) {
381 try {
382 if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
383 "POS " + w.mShownFrame.left
384 + ", " + w.mShownFrame.top, null);
385 w.mSurfaceX = w.mShownFrame.left;
386 w.mSurfaceY = w.mShownFrame.top;
387 w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
388 } catch (RuntimeException e) {
389 Slog.w(TAG, "Error positioning surface of " + w
390 + " pos=(" + w.mShownFrame.left
391 + "," + w.mShownFrame.top + ")", e);
392 if (!recoveringMemory) {
393 mService.reclaimSomeSurfaceMemoryLocked(w, "position", true);
394 }
395 }
396 }
397
398 if (surfaceResized) {
399 try {
400 if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
401 "SIZE " + width + "x" + height, null);
402 w.mSurfaceResized = true;
403 w.mSurface.setSize(width, height);
404 } catch (RuntimeException e) {
405 // If something goes wrong with the surface (such
406 // as running out of memory), don't take down the
407 // entire system.
408 Slog.e(TAG, "Error resizing surface of " + w
409 + " size=(" + width + "x" + height + ")", e);
410 if (!recoveringMemory) {
411 mService.reclaimSomeSurfaceMemoryLocked(w, "size", true);
412 }
413 }
414 }
415
416 if (w.mAttachedHidden || !w.isReadyForDisplay()) {
417 if (!w.mLastHidden) {
418 //dump();
419 w.mLastHidden = true;
420 if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
421 "HIDE (performLayout)", null);
422 if (w.mSurface != null) {
423 w.mSurfaceShown = false;
424 try {
425 w.mSurface.hide();
426 } catch (RuntimeException e) {
427 Slog.w(TAG, "Exception hiding surface in " + w);
428 }
429 }
430 }
431 // If we are waiting for this window to handle an
432 // orientation change, well, it is hidden, so
433 // doesn't really matter. Note that this does
434 // introduce a potential glitch if the window
435 // becomes unhidden before it has drawn for the
436 // new orientation.
437 if (w.mOrientationChanging) {
438 w.mOrientationChanging = false;
439 if (WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
440 "Orientation change skips hidden " + w);
441 }
442 } else if (w.mLastLayer != w.mAnimLayer
443 || w.mLastAlpha != w.mShownAlpha
444 || w.mLastDsDx != w.mDsDx
445 || w.mLastDtDx != w.mDtDx
446 || w.mLastDsDy != w.mDsDy
447 || w.mLastDtDy != w.mDtDy
448 || w.mLastHScale != w.mHScale
449 || w.mLastVScale != w.mVScale
450 || w.mLastHidden) {
451 displayed = true;
452 w.mLastAlpha = w.mShownAlpha;
453 w.mLastLayer = w.mAnimLayer;
454 w.mLastDsDx = w.mDsDx;
455 w.mLastDtDx = w.mDtDx;
456 w.mLastDsDy = w.mDsDy;
457 w.mLastDtDy = w.mDtDy;
458 w.mLastHScale = w.mHScale;
459 w.mLastVScale = w.mVScale;
460 if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
461 "alpha=" + w.mShownAlpha + " layer=" + w.mAnimLayer
462 + " matrix=[" + (w.mDsDx*w.mHScale)
463 + "," + (w.mDtDx*w.mVScale)
464 + "][" + (w.mDsDy*w.mHScale)
465 + "," + (w.mDtDy*w.mVScale) + "]", null);
466 if (w.mSurface != null) {
467 try {
468 w.mSurfaceAlpha = w.mShownAlpha;
469 w.mSurface.setAlpha(w.mShownAlpha);
470 w.mSurfaceLayer = w.mAnimLayer;
471 w.mSurface.setLayer(w.mAnimLayer);
472 w.mSurface.setMatrix(
473 w.mDsDx*w.mHScale, w.mDtDx*w.mVScale,
474 w.mDsDy*w.mHScale, w.mDtDy*w.mVScale);
475 } catch (RuntimeException e) {
476 Slog.w(TAG, "Error updating surface in " + w, e);
477 if (!recoveringMemory) {
478 mService.reclaimSomeSurfaceMemoryLocked(w, "update", true);
479 }
480 }
481 }
482
483 if (w.mLastHidden && w.isDrawnLw()
484 && !w.mReadyToShow) {
485 if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
486 "SHOW (performLayout)", null);
487 if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w
488 + " during relayout");
489 if (mService.showSurfaceRobustlyLocked(w)) {
490 w.mHasDrawn = true;
491 w.mLastHidden = false;
492 } else {
493 w.mOrientationChanging = false;
494 }
495 }
496 if (w.mSurface != null) {
497 w.mToken.hasVisible = true;
498 }
499 } else {
500 displayed = true;
501 }
502
503 if (displayed) {
504 if (w.mOrientationChanging) {
505 if (!w.isDrawnLw()) {
506 mService.mInnerFields.mOrientationChangeComplete = false;
507 if (WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
508 "Orientation continue waiting for draw in " + w);
509 } else {
510 w.mOrientationChanging = false;
511 if (WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
512 "Orientation change complete in " + w);
513 }
514 }
515 w.mToken.hasVisible = true;
516 }
517 }
518
519 void animate() {
520 mCurrentTime = SystemClock.uptimeMillis();
521
522 // Update animations of all applications, including those
523 // associated with exiting/removed apps
524 Surface.openTransaction();
525
526 try {
527 updateWindowsAppsAndRotationAnimationsLocked();
528 performAnimationsLocked();
529
530 // THIRD LOOP: Update the surfaces of all windows.
531
532 if (mScreenRotationAnimation != null) {
533 mScreenRotationAnimation.updateSurfaces();
534 }
535
536 final int N = mService.mWindows.size();
537 for (int i=N-1; i>=0; i--) {
538 WindowState w = mService.mWindows.get(i);
539 prepareSurfaceLocked(w, true);
540 }
541
542 if (mService.mDimAnimator != null && mService.mDimAnimator.mDimShown) {
543 mAnimating |= mService.mDimAnimator.updateSurface(mService.mInnerFields.mDimming,
544 mCurrentTime, !mService.okToDisplay());
545 }
546
547 if (mService.mBlackFrame != null) {
548 if (mScreenRotationAnimation != null) {
549 mService.mBlackFrame.setMatrix(
550 mScreenRotationAnimation.getEnterTransformation().getMatrix());
551 } else {
552 mService.mBlackFrame.clearMatrix();
553 }
554 }
555 } catch (RuntimeException e) {
556 Log.wtf(TAG, "Unhandled exception in Window Manager", e);
557 } finally {
558 Surface.closeTransaction();
559 }
560 }
561
562 WindowState mCurrentFocus;
563 void setCurrentFocus(WindowState currentFocus) {
564 mCurrentFocus = currentFocus;
565 }
566
567 void setDisplayDimensions(final int curWidth, final int curHeight,
568 final int appWidth, final int appHeight) {
569 mDw = curWidth;
570 mDh = curHeight;
571 mInnerDw = appWidth;
572 mInnerDh = appHeight;
573 }
574
575}