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