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