blob: 058e09ec76838529fc1cac1ccbbabd78895636f3 [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 }
Dianne Hackborn8078d8c2012-03-20 11:11:26 -0700276 if (atoken != null && atoken.thumbnail != null) {
277 if (atoken.thumbnailTransactionSeq != mTransactionSequence) {
278 atoken.thumbnailTransactionSeq = mTransactionSequence;
279 atoken.thumbnailLayer = 0;
280 }
281 if (atoken.thumbnailLayer < w.mAnimLayer) {
282 atoken.thumbnailLayer = w.mAnimLayer;
283 }
284 }
Craig Mautner764983d2012-03-22 11:37:36 -0700285 } // end forall windows
286 }
287
288 private void testTokenMayBeDrawnLocked() {
289 // See if any windows have been drawn, so they (and others
290 // associated with them) can now be shown.
291 final int NT = mService.mAppTokens.size();
292 for (int i=0; i<NT; i++) {
293 AppWindowToken wtoken = mService.mAppTokens.get(i);
294 if (wtoken.freezingScreen) {
295 int numInteresting = wtoken.numInterestingWindows;
296 if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
297 if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
298 "allDrawn: " + wtoken
299 + " interesting=" + numInteresting
300 + " drawn=" + wtoken.numDrawnWindows);
301 wtoken.showAllWindowsLocked();
302 mService.unsetAppFreezingScreenLocked(wtoken, false, true);
303 if (WindowManagerService.DEBUG_ORIENTATION) Slog.i(TAG,
304 "Setting mOrientationChangeComplete=true because wtoken "
305 + wtoken + " numInteresting=" + numInteresting
306 + " numDrawn=" + wtoken.numDrawnWindows);
307 mService.mInnerFields.mOrientationChangeComplete = true;
308 }
309 } else if (!wtoken.allDrawn) {
310 int numInteresting = wtoken.numInterestingWindows;
311 if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
312 if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
313 "allDrawn: " + wtoken
314 + " interesting=" + numInteresting
315 + " drawn=" + wtoken.numDrawnWindows);
316 wtoken.allDrawn = true;
317 mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
318
319 // We can now show all of the drawn windows!
320 if (!mService.mOpeningApps.contains(wtoken)) {
321 mAnimating |= wtoken.showAllWindowsLocked();
322 }
323 }
324 }
325 }
326 }
327
328 private void performAnimationsLocked() {
329 if (WindowManagerService.DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: seq="
330 + mTransactionSequence + " mAnimating="
331 + mAnimating);
332
333 mTokenMayBeDrawn = false;
334 mService.mInnerFields.mWallpaperMayChange = false;
335 mForceHiding = false;
336 mService.mInnerFields.mDetachedWallpaper = null;
337 mWindowAnimationBackground = null;
338 mWindowAnimationBackgroundColor = 0;
339
340 updateWindowsAndWallpaperLocked();
341
342 if (mTokenMayBeDrawn) {
343 testTokenMayBeDrawnLocked();
344 }
345
346 if (WindowManagerService.DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: changes=0x"
347 + Integer.toHexString(mPendingLayoutChanges));
348 }
349
350 public void prepareSurfaceLocked(final WindowState w, final boolean recoveringMemory) {
351 if (w.mSurface == null) {
352 if (w.mOrientationChanging) {
353 if (WindowManagerService.DEBUG_ORIENTATION) {
354 Slog.v(TAG, "Orientation change skips hidden " + w);
355 }
356 w.mOrientationChanging = false;
357 }
358 return;
359 }
360
361 boolean displayed = false;
362
363 w.computeShownFrameLocked();
364
365 int width, height;
366 if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
367 // for a scaled surface, we just want to use
368 // the requested size.
369 width = w.mRequestedWidth;
370 height = w.mRequestedHeight;
371 } else {
372 width = w.mCompatFrame.width();
373 height = w.mCompatFrame.height();
374 }
375
376 if (width < 1) {
377 width = 1;
378 }
379 if (height < 1) {
380 height = 1;
381 }
382 final boolean surfaceResized = w.mSurfaceW != width || w.mSurfaceH != height;
383 if (surfaceResized) {
384 w.mSurfaceW = width;
385 w.mSurfaceH = height;
386 }
387
388 if (w.mSurfaceX != w.mShownFrame.left
389 || w.mSurfaceY != w.mShownFrame.top) {
390 try {
391 if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
392 "POS " + w.mShownFrame.left
393 + ", " + w.mShownFrame.top, null);
394 w.mSurfaceX = w.mShownFrame.left;
395 w.mSurfaceY = w.mShownFrame.top;
396 w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
397 } catch (RuntimeException e) {
398 Slog.w(TAG, "Error positioning surface of " + w
399 + " pos=(" + w.mShownFrame.left
400 + "," + w.mShownFrame.top + ")", e);
401 if (!recoveringMemory) {
402 mService.reclaimSomeSurfaceMemoryLocked(w, "position", true);
403 }
404 }
405 }
406
407 if (surfaceResized) {
408 try {
409 if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
410 "SIZE " + width + "x" + height, null);
411 w.mSurfaceResized = true;
412 w.mSurface.setSize(width, height);
413 } catch (RuntimeException e) {
414 // If something goes wrong with the surface (such
415 // as running out of memory), don't take down the
416 // entire system.
417 Slog.e(TAG, "Error resizing surface of " + w
418 + " size=(" + width + "x" + height + ")", e);
419 if (!recoveringMemory) {
420 mService.reclaimSomeSurfaceMemoryLocked(w, "size", true);
421 }
422 }
423 }
424
425 if (w.mAttachedHidden || !w.isReadyForDisplay()) {
426 if (!w.mLastHidden) {
427 //dump();
428 w.mLastHidden = true;
429 if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
430 "HIDE (performLayout)", null);
431 if (w.mSurface != null) {
432 w.mSurfaceShown = false;
433 try {
434 w.mSurface.hide();
435 } catch (RuntimeException e) {
436 Slog.w(TAG, "Exception hiding surface in " + w);
437 }
438 }
439 }
440 // If we are waiting for this window to handle an
441 // orientation change, well, it is hidden, so
442 // doesn't really matter. Note that this does
443 // introduce a potential glitch if the window
444 // becomes unhidden before it has drawn for the
445 // new orientation.
446 if (w.mOrientationChanging) {
447 w.mOrientationChanging = false;
448 if (WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
449 "Orientation change skips hidden " + w);
450 }
451 } else if (w.mLastLayer != w.mAnimLayer
452 || w.mLastAlpha != w.mShownAlpha
453 || w.mLastDsDx != w.mDsDx
454 || w.mLastDtDx != w.mDtDx
455 || w.mLastDsDy != w.mDsDy
456 || w.mLastDtDy != w.mDtDy
457 || w.mLastHScale != w.mHScale
458 || w.mLastVScale != w.mVScale
459 || w.mLastHidden) {
460 displayed = true;
461 w.mLastAlpha = w.mShownAlpha;
462 w.mLastLayer = w.mAnimLayer;
463 w.mLastDsDx = w.mDsDx;
464 w.mLastDtDx = w.mDtDx;
465 w.mLastDsDy = w.mDsDy;
466 w.mLastDtDy = w.mDtDy;
467 w.mLastHScale = w.mHScale;
468 w.mLastVScale = w.mVScale;
469 if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
470 "alpha=" + w.mShownAlpha + " layer=" + w.mAnimLayer
471 + " matrix=[" + (w.mDsDx*w.mHScale)
472 + "," + (w.mDtDx*w.mVScale)
473 + "][" + (w.mDsDy*w.mHScale)
474 + "," + (w.mDtDy*w.mVScale) + "]", null);
475 if (w.mSurface != null) {
476 try {
477 w.mSurfaceAlpha = w.mShownAlpha;
478 w.mSurface.setAlpha(w.mShownAlpha);
479 w.mSurfaceLayer = w.mAnimLayer;
480 w.mSurface.setLayer(w.mAnimLayer);
481 w.mSurface.setMatrix(
482 w.mDsDx*w.mHScale, w.mDtDx*w.mVScale,
483 w.mDsDy*w.mHScale, w.mDtDy*w.mVScale);
484 } catch (RuntimeException e) {
485 Slog.w(TAG, "Error updating surface in " + w, e);
486 if (!recoveringMemory) {
487 mService.reclaimSomeSurfaceMemoryLocked(w, "update", true);
488 }
489 }
490 }
491
492 if (w.mLastHidden && w.isDrawnLw()
493 && !w.mReadyToShow) {
494 if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
495 "SHOW (performLayout)", null);
496 if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w
497 + " during relayout");
498 if (mService.showSurfaceRobustlyLocked(w)) {
499 w.mHasDrawn = true;
500 w.mLastHidden = false;
501 } else {
502 w.mOrientationChanging = false;
503 }
504 }
505 if (w.mSurface != null) {
506 w.mToken.hasVisible = true;
507 }
508 } else {
509 displayed = true;
510 }
511
512 if (displayed) {
513 if (w.mOrientationChanging) {
514 if (!w.isDrawnLw()) {
515 mService.mInnerFields.mOrientationChangeComplete = false;
516 if (WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
517 "Orientation continue waiting for draw in " + w);
518 } else {
519 w.mOrientationChanging = false;
520 if (WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
521 "Orientation change complete in " + w);
522 }
523 }
524 w.mToken.hasVisible = true;
525 }
526 }
527
528 void animate() {
529 mCurrentTime = SystemClock.uptimeMillis();
530
531 // Update animations of all applications, including those
532 // associated with exiting/removed apps
533 Surface.openTransaction();
534
535 try {
536 updateWindowsAppsAndRotationAnimationsLocked();
537 performAnimationsLocked();
538
539 // THIRD LOOP: Update the surfaces of all windows.
540
541 if (mScreenRotationAnimation != null) {
542 mScreenRotationAnimation.updateSurfaces();
543 }
544
545 final int N = mService.mWindows.size();
546 for (int i=N-1; i>=0; i--) {
547 WindowState w = mService.mWindows.get(i);
548 prepareSurfaceLocked(w, true);
549 }
550
551 if (mService.mDimAnimator != null && mService.mDimAnimator.mDimShown) {
552 mAnimating |= mService.mDimAnimator.updateSurface(mService.mInnerFields.mDimming,
553 mCurrentTime, !mService.okToDisplay());
554 }
555
556 if (mService.mBlackFrame != null) {
557 if (mScreenRotationAnimation != null) {
558 mService.mBlackFrame.setMatrix(
559 mScreenRotationAnimation.getEnterTransformation().getMatrix());
560 } else {
561 mService.mBlackFrame.clearMatrix();
562 }
563 }
564 } catch (RuntimeException e) {
565 Log.wtf(TAG, "Unhandled exception in Window Manager", e);
566 } finally {
567 Surface.closeTransaction();
568 }
569 }
570
571 WindowState mCurrentFocus;
572 void setCurrentFocus(WindowState currentFocus) {
573 mCurrentFocus = currentFocus;
574 }
575
576 void setDisplayDimensions(final int curWidth, final int curHeight,
577 final int appWidth, final int appHeight) {
578 mDw = curWidth;
579 mDh = curHeight;
580 mInnerDw = appWidth;
581 mInnerDh = appHeight;
582 }
583
584}