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