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