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