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