AppWindowAnimator.java revision 564a8f697b3f3a287d9a4cce14ac0fe1a046709e
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.wm; 18 19import static com.android.server.wm.WindowManagerService.DEBUG_ANIM; 20import static com.android.server.wm.WindowManagerService.DEBUG_LAYERS; 21import static com.android.server.wm.WindowManagerService.SHOW_TRANSACTIONS; 22import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET; 23 24import android.graphics.Matrix; 25import android.util.Slog; 26import android.util.TimeUtils; 27import android.view.Choreographer; 28import android.view.Display; 29import android.view.SurfaceControl; 30import android.view.WindowManagerPolicy; 31import android.view.animation.Animation; 32import android.view.animation.Transformation; 33 34import java.io.PrintWriter; 35import java.util.ArrayList; 36 37public class AppWindowAnimator { 38 static final String TAG = "AppWindowAnimator"; 39 40 private static final int PROLONG_ANIMATION_DISABLED = 0; 41 static final int PROLONG_ANIMATION_AT_END = 1; 42 static final int PROLONG_ANIMATION_AT_START = 2; 43 44 final AppWindowToken mAppToken; 45 final WindowManagerService mService; 46 final WindowAnimator mAnimator; 47 48 boolean animating; 49 boolean wasAnimating; 50 Animation animation; 51 boolean hasTransformation; 52 final Transformation transformation = new Transformation(); 53 54 // Have we been asked to have this token keep the screen frozen? 55 // Protect with mAnimator. 56 boolean freezingScreen; 57 58 /** 59 * How long we last kept the screen frozen. 60 */ 61 int lastFreezeDuration; 62 63 // Offset to the window of all layers in the token, for use by 64 // AppWindowToken animations. 65 int animLayerAdjustment; 66 67 // Propagated from AppWindowToken.allDrawn, to determine when 68 // the state changes. 69 boolean allDrawn; 70 71 // Special surface for thumbnail animation. If deferThumbnailDestruction is enabled, then we 72 // will make sure that the thumbnail is destroyed after the other surface is completed. This 73 // requires that the duration of the two animations are the same. 74 SurfaceControl thumbnail; 75 int thumbnailTransactionSeq; 76 int thumbnailX; 77 int thumbnailY; 78 int thumbnailLayer; 79 int thumbnailForceAboveLayer; 80 Animation thumbnailAnimation; 81 final Transformation thumbnailTransformation = new Transformation(); 82 // This flag indicates that the destruction of the thumbnail surface is synchronized with 83 // another animation, so defer the destruction of this thumbnail surface for a single frame 84 // after the secondary animation completes. 85 boolean deferThumbnailDestruction; 86 // This flag is set if the animator has deferThumbnailDestruction set and has reached the final 87 // frame of animation. It will extend the animation by one frame and then clean up afterwards. 88 boolean deferFinalFrameCleanup; 89 // If true when the animation hits the last frame, it will keep running on that last frame. 90 // This is used to synchronize animation with Recents and we wait for Recents to tell us to 91 // finish or for a new animation be set as fail-safe mechanism. 92 private int mProlongAnimation; 93 // Whether the prolong animation can be removed when animation is set. The purpose of this is 94 // that if recents doesn't tell us to remove the prolonged animation, we will get rid of it 95 // when new animation is set. 96 private boolean mClearProlongedAnimation; 97 98 /** WindowStateAnimator from mAppAnimator.allAppWindows as of last performLayout */ 99 ArrayList<WindowStateAnimator> mAllAppWinAnimators = new ArrayList<>(); 100 101 /** True if the current animation was transferred from another AppWindowAnimator. 102 * See {@link #transferCurrentAnimation}*/ 103 boolean usingTransferredAnimation = false; 104 105 private boolean mSkipFirstFrame = false; 106 107 static final Animation sDummyAnimation = new DummyAnimation(); 108 109 public AppWindowAnimator(final AppWindowToken atoken) { 110 mAppToken = atoken; 111 mService = atoken.service; 112 mAnimator = atoken.mAnimator; 113 } 114 115 public void setAnimation(Animation anim, int width, int height, boolean skipFirstFrame) { 116 if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting animation in " + mAppToken 117 + ": " + anim + " wxh=" + width + "x" + height 118 + " isVisible=" + mAppToken.isVisible()); 119 animation = anim; 120 animating = false; 121 if (!anim.isInitialized()) { 122 anim.initialize(width, height, width, height); 123 } 124 anim.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION); 125 anim.scaleCurrentDuration(mService.getTransitionAnimationScaleLocked()); 126 int zorder = anim.getZAdjustment(); 127 int adj = 0; 128 if (zorder == Animation.ZORDER_TOP) { 129 adj = TYPE_LAYER_OFFSET; 130 } else if (zorder == Animation.ZORDER_BOTTOM) { 131 adj = -TYPE_LAYER_OFFSET; 132 } 133 134 if (animLayerAdjustment != adj) { 135 animLayerAdjustment = adj; 136 updateLayers(); 137 } 138 // Start out animation gone if window is gone, or visible if window is visible. 139 transformation.clear(); 140 transformation.setAlpha(mAppToken.isVisible() ? 1 : 0); 141 hasTransformation = true; 142 143 this.mSkipFirstFrame = skipFirstFrame; 144 145 if (!mAppToken.appFullscreen) { 146 anim.setBackgroundColor(0); 147 } 148 if (mClearProlongedAnimation) { 149 mProlongAnimation = PROLONG_ANIMATION_DISABLED; 150 } else { 151 mClearProlongedAnimation = true; 152 } 153 } 154 155 public void setDummyAnimation() { 156 if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting dummy animation in " + mAppToken 157 + " isVisible=" + mAppToken.isVisible()); 158 animation = sDummyAnimation; 159 hasTransformation = true; 160 transformation.clear(); 161 transformation.setAlpha(mAppToken.isVisible() ? 1 : 0); 162 } 163 164 public void clearAnimation() { 165 if (animation != null) { 166 animation = null; 167 animating = true; 168 } 169 clearThumbnail(); 170 if (mAppToken.deferClearAllDrawn) { 171 mAppToken.allDrawn = false; 172 mAppToken.deferClearAllDrawn = false; 173 } 174 usingTransferredAnimation = false; 175 } 176 177 public boolean isAnimating() { 178 return animation != null || mAppToken.inPendingTransaction; 179 } 180 181 public void clearThumbnail() { 182 if (thumbnail != null) { 183 thumbnail.destroy(); 184 thumbnail = null; 185 } 186 deferThumbnailDestruction = false; 187 } 188 189 void transferCurrentAnimation( 190 AppWindowAnimator toAppAnimator, WindowStateAnimator transferWinAnimator) { 191 192 if (animation != null) { 193 toAppAnimator.animation = animation; 194 animation = null; 195 toAppAnimator.animating = animating; 196 toAppAnimator.animLayerAdjustment = animLayerAdjustment; 197 animLayerAdjustment = 0; 198 toAppAnimator.updateLayers(); 199 updateLayers(); 200 toAppAnimator.usingTransferredAnimation = true; 201 } 202 if (transferWinAnimator != null) { 203 mAllAppWinAnimators.remove(transferWinAnimator); 204 toAppAnimator.mAllAppWinAnimators.add(transferWinAnimator); 205 transferWinAnimator.mAppAnimator = toAppAnimator; 206 } 207 } 208 209 void updateLayers() { 210 final int windowCount = mAppToken.allAppWindows.size(); 211 final int adj = animLayerAdjustment; 212 thumbnailLayer = -1; 213 final WallpaperController wallpaperController = mService.mWallpaperControllerLocked; 214 for (int i = 0; i < windowCount; i++) { 215 final WindowState w = mAppToken.allAppWindows.get(i); 216 final WindowStateAnimator winAnimator = w.mWinAnimator; 217 winAnimator.mAnimLayer = w.mLayer + adj; 218 if (winAnimator.mAnimLayer > thumbnailLayer) { 219 thumbnailLayer = winAnimator.mAnimLayer; 220 } 221 if (DEBUG_LAYERS) Slog.v(TAG, "Updating layer " + w + ": " + winAnimator.mAnimLayer); 222 if (w == mService.mInputMethodTarget && !mService.mInputMethodTargetWaitingAnim) { 223 mService.setInputMethodAnimLayerAdjustment(adj); 224 } 225 wallpaperController.setAnimLayerAdjustment(w, adj); 226 } 227 } 228 229 private void stepThumbnailAnimation(long currentTime) { 230 thumbnailTransformation.clear(); 231 final long animationFrameTime = getAnimationFrameTime(thumbnailAnimation, currentTime); 232 thumbnailAnimation.getTransformation(animationFrameTime, thumbnailTransformation); 233 thumbnailTransformation.getMatrix().preTranslate(thumbnailX, thumbnailY); 234 235 ScreenRotationAnimation screenRotationAnimation = 236 mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY); 237 final boolean screenAnimation = screenRotationAnimation != null 238 && screenRotationAnimation.isAnimating(); 239 if (screenAnimation) { 240 thumbnailTransformation.postCompose(screenRotationAnimation.getEnterTransformation()); 241 } 242 // cache often used attributes locally 243 final float tmpFloats[] = mService.mTmpFloats; 244 thumbnailTransformation.getMatrix().getValues(tmpFloats); 245 if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail, 246 "thumbnail", "POS " + tmpFloats[Matrix.MTRANS_X] 247 + ", " + tmpFloats[Matrix.MTRANS_Y], null); 248 thumbnail.setPosition(tmpFloats[Matrix.MTRANS_X], tmpFloats[Matrix.MTRANS_Y]); 249 if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail, 250 "thumbnail", "alpha=" + thumbnailTransformation.getAlpha() 251 + " layer=" + thumbnailLayer 252 + " matrix=[" + tmpFloats[Matrix.MSCALE_X] 253 + "," + tmpFloats[Matrix.MSKEW_Y] 254 + "][" + tmpFloats[Matrix.MSKEW_X] 255 + "," + tmpFloats[Matrix.MSCALE_Y] + "]", null); 256 thumbnail.setAlpha(thumbnailTransformation.getAlpha()); 257 if (thumbnailForceAboveLayer > 0) { 258 thumbnail.setLayer(thumbnailForceAboveLayer + 1); 259 } else { 260 // The thumbnail is layered below the window immediately above this 261 // token's anim layer. 262 thumbnail.setLayer(thumbnailLayer + WindowManagerService.WINDOW_LAYER_MULTIPLIER 263 - WindowManagerService.LAYER_OFFSET_THUMBNAIL); 264 } 265 thumbnail.setMatrix(tmpFloats[Matrix.MSCALE_X], tmpFloats[Matrix.MSKEW_Y], 266 tmpFloats[Matrix.MSKEW_X], tmpFloats[Matrix.MSCALE_Y]); 267 } 268 269 /** 270 * Sometimes we need to synchronize the first frame of animation with some external event, e.g. 271 * Recents hiding some of its content. To achieve this, we prolong the start of the animaiton 272 * and keep producing the first frame of the animation. 273 */ 274 private long getAnimationFrameTime(Animation animation, long currentTime) { 275 if (mProlongAnimation == PROLONG_ANIMATION_AT_START) { 276 animation.setStartTime(currentTime); 277 return currentTime + 1; 278 } 279 return currentTime; 280 } 281 282 private boolean stepAnimation(long currentTime) { 283 if (animation == null) { 284 return false; 285 } 286 transformation.clear(); 287 final long animationFrameTime = getAnimationFrameTime(animation, currentTime); 288 boolean hasMoreFrames = animation.getTransformation(animationFrameTime, transformation); 289 if (!hasMoreFrames) { 290 if (deferThumbnailDestruction && !deferFinalFrameCleanup) { 291 // We are deferring the thumbnail destruction, so extend the animation for one more 292 // (dummy) frame before we clean up 293 deferFinalFrameCleanup = true; 294 hasMoreFrames = true; 295 } else { 296 if (false && DEBUG_ANIM) Slog.v(TAG, 297 "Stepped animation in " + mAppToken + ": more=" + hasMoreFrames + 298 ", xform=" + transformation + ", mProlongAnimation=" + mProlongAnimation); 299 deferFinalFrameCleanup = false; 300 if (mProlongAnimation == PROLONG_ANIMATION_AT_END) { 301 hasMoreFrames = true; 302 } else { 303 animation = null; 304 clearThumbnail(); 305 if (DEBUG_ANIM) Slog.v(TAG, "Finished animation in " + mAppToken + " @ " 306 + currentTime); 307 } 308 } 309 } 310 hasTransformation = hasMoreFrames; 311 return hasMoreFrames; 312 } 313 314 private long getStartTimeCorrection() { 315 if (mSkipFirstFrame) { 316 317 // If the transition is an animation in which the first frame doesn't change the screen 318 // contents at all, we can just skip it and start at the second frame. So we shift the 319 // start time of the animation forward by minus the frame duration. 320 return -Choreographer.getInstance().getFrameIntervalNanos() / TimeUtils.NANOS_PER_MS; 321 } else { 322 return 0; 323 } 324 } 325 326 // This must be called while inside a transaction. 327 boolean stepAnimationLocked(long currentTime, final int displayId) { 328 if (mService.okToDisplay()) { 329 // We will run animations as long as the display isn't frozen. 330 331 if (animation == sDummyAnimation) { 332 // This guy is going to animate, but not yet. For now count 333 // it as not animating for purposes of scheduling transactions; 334 // when it is really time to animate, this will be set to 335 // a real animation and the next call will execute normally. 336 return false; 337 } 338 339 if ((mAppToken.allDrawn || mAppToken.mAnimatingWithSavedSurface 340 || animating || mAppToken.startingDisplayed) 341 && animation != null) { 342 if (!animating) { 343 if (DEBUG_ANIM) Slog.v(TAG, 344 "Starting animation in " + mAppToken + 345 " @ " + currentTime + " scale=" 346 + mService.getTransitionAnimationScaleLocked() 347 + " allDrawn=" + mAppToken.allDrawn + " animating=" + animating); 348 long correction = getStartTimeCorrection(); 349 animation.setStartTime(currentTime + correction); 350 animating = true; 351 if (thumbnail != null) { 352 thumbnail.show(); 353 thumbnailAnimation.setStartTime(currentTime + correction); 354 } 355 mSkipFirstFrame = false; 356 } 357 if (stepAnimation(currentTime)) { 358 // animation isn't over, step any thumbnail and that's 359 // it for now. 360 if (thumbnail != null) { 361 stepThumbnailAnimation(currentTime); 362 } 363 return true; 364 } 365 } 366 } else if (animation != null) { 367 // If the display is frozen, and there is a pending animation, 368 // clear it and make sure we run the cleanup code. 369 animating = true; 370 animation = null; 371 } 372 373 hasTransformation = false; 374 375 if (!animating && animation == null) { 376 return false; 377 } 378 379 mAnimator.setAppLayoutChanges(this, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM, 380 "AppWindowToken", displayId); 381 382 clearAnimation(); 383 animating = false; 384 if (animLayerAdjustment != 0) { 385 animLayerAdjustment = 0; 386 updateLayers(); 387 } 388 if (mService.mInputMethodTarget != null 389 && mService.mInputMethodTarget.mAppToken == mAppToken) { 390 mService.moveInputMethodWindowsIfNeededLocked(true); 391 } 392 393 if (DEBUG_ANIM) Slog.v(TAG, 394 "Animation done in " + mAppToken 395 + ": reportedVisible=" + mAppToken.reportedVisible); 396 397 transformation.clear(); 398 399 final int numAllAppWinAnimators = mAllAppWinAnimators.size(); 400 for (int i = 0; i < numAllAppWinAnimators; i++) { 401 mAllAppWinAnimators.get(i).finishExit(); 402 } 403 mService.mAppTransition.notifyAppTransitionFinishedLocked(mAppToken.token); 404 return false; 405 } 406 407 // This must be called while inside a transaction. 408 boolean showAllWindowsLocked() { 409 boolean isAnimating = false; 410 final int NW = mAllAppWinAnimators.size(); 411 for (int i=0; i<NW; i++) { 412 WindowStateAnimator winAnimator = mAllAppWinAnimators.get(i); 413 if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG, 414 "performing show on: " + winAnimator); 415 winAnimator.performShowLocked(); 416 isAnimating |= winAnimator.isAnimating(); 417 } 418 return isAnimating; 419 } 420 421 void dump(PrintWriter pw, String prefix, boolean dumpAll) { 422 pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken); 423 pw.print(prefix); pw.print("mAnimator="); pw.println(mAnimator); 424 pw.print(prefix); pw.print("freezingScreen="); pw.print(freezingScreen); 425 pw.print(" allDrawn="); pw.print(allDrawn); 426 pw.print(" animLayerAdjustment="); pw.println(animLayerAdjustment); 427 if (lastFreezeDuration != 0) { 428 pw.print(prefix); pw.print("lastFreezeDuration="); 429 TimeUtils.formatDuration(lastFreezeDuration, pw); pw.println(); 430 } 431 if (animating || animation != null) { 432 pw.print(prefix); pw.print("animating="); pw.println(animating); 433 pw.print(prefix); pw.print("animation="); pw.println(animation); 434 } 435 if (hasTransformation) { 436 pw.print(prefix); pw.print("XForm: "); 437 transformation.printShortString(pw); 438 pw.println(); 439 } 440 if (thumbnail != null) { 441 pw.print(prefix); pw.print("thumbnail="); pw.print(thumbnail); 442 pw.print(" x="); pw.print(thumbnailX); 443 pw.print(" y="); pw.print(thumbnailY); 444 pw.print(" layer="); pw.println(thumbnailLayer); 445 pw.print(prefix); pw.print("thumbnailAnimation="); pw.println(thumbnailAnimation); 446 pw.print(prefix); pw.print("thumbnailTransformation="); 447 pw.println(thumbnailTransformation.toShortString()); 448 } 449 for (int i=0; i<mAllAppWinAnimators.size(); i++) { 450 WindowStateAnimator wanim = mAllAppWinAnimators.get(i); 451 pw.print(prefix); pw.print("App Win Anim #"); pw.print(i); 452 pw.print(": "); pw.println(wanim); 453 } 454 } 455 456 void startProlongAnimation(int prolongType) { 457 mProlongAnimation = prolongType; 458 mClearProlongedAnimation = false; 459 } 460 461 void endProlongedAnimation() { 462 mProlongAnimation = PROLONG_ANIMATION_DISABLED; 463 } 464 465 // This is an animation that does nothing: it just immediately finishes 466 // itself every time it is called. It is used as a stub animation in cases 467 // where we want to synchronize multiple things that may be animating. 468 static final class DummyAnimation extends Animation { 469 @Override 470 public boolean getTransformation(long currentTime, Transformation outTransformation) { 471 return false; 472 } 473 } 474 475} 476