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