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