AppWindowAnimator.java revision 8a2978c9ab5edd97e1de97fdc2ac6c6e2f7bb02b
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.Display; 28import android.view.SurfaceControl; 29import android.view.WindowManagerPolicy; 30import android.view.animation.Animation; 31import android.view.animation.Transformation; 32 33import java.io.PrintWriter; 34import java.util.ArrayList; 35 36public class AppWindowAnimator { 37 static final String TAG = "AppWindowAnimator"; 38 39 final AppWindowToken mAppToken; 40 final WindowManagerService mService; 41 final WindowAnimator mAnimator; 42 43 boolean animating; 44 boolean wasAnimating; 45 Animation animation; 46 boolean hasTransformation; 47 final Transformation transformation = new Transformation(); 48 49 // Have we been asked to have this token keep the screen frozen? 50 // Protect with mAnimator. 51 boolean freezingScreen; 52 53 /** 54 * How long we last kept the screen frozen. 55 */ 56 int lastFreezeDuration; 57 58 // Offset to the window of all layers in the token, for use by 59 // AppWindowToken animations. 60 int animLayerAdjustment; 61 62 // Propagated from AppWindowToken.allDrawn, to determine when 63 // the state changes. 64 boolean allDrawn; 65 66 // Special surface for thumbnail animation. If deferThumbnailDestruction is enabled, then we 67 // will make sure that the thumbnail is destroyed after the other surface is completed. This 68 // requires that the duration of the two animations are the same. 69 SurfaceControl thumbnail; 70 int thumbnailTransactionSeq; 71 int thumbnailX; 72 int thumbnailY; 73 int thumbnailLayer; 74 int thumbnailForceAboveLayer; 75 Animation thumbnailAnimation; 76 final Transformation thumbnailTransformation = new Transformation(); 77 // This flag indicates that the destruction of the thumbnail surface is synchronized with 78 // another animation, so defer the destruction of this thumbnail surface for a single frame 79 // after the secondary animation completes. 80 boolean deferThumbnailDestruction; 81 // This flag is set if the animator has deferThumbnailDestruction set and has reached the final 82 // frame of animation. It will extend the animation by one frame and then clean up afterwards. 83 boolean deferFinalFrameCleanup; 84 85 /** WindowStateAnimator from mAppAnimator.allAppWindows as of last performLayout */ 86 ArrayList<WindowStateAnimator> mAllAppWinAnimators = new ArrayList<>(); 87 88 /** True if the current animation was transferred from another AppWindowAnimator. 89 * See {@link #transferCurrentAnimation}*/ 90 boolean usingTransferredAnimation = false; 91 92 static final Animation sDummyAnimation = new DummyAnimation(); 93 94 public AppWindowAnimator(final AppWindowToken atoken) { 95 mAppToken = atoken; 96 mService = atoken.service; 97 mAnimator = atoken.mAnimator; 98 } 99 100 public void setAnimation(Animation anim, int width, int height) { 101 if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting animation in " + mAppToken 102 + ": " + anim + " wxh=" + width + "x" + height 103 + " isVisible=" + mAppToken.isVisible()); 104 animation = anim; 105 animating = false; 106 if (!anim.isInitialized()) { 107 anim.initialize(width, height, width, height); 108 } 109 anim.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION); 110 anim.scaleCurrentDuration(mService.getTransitionAnimationScaleLocked()); 111 int zorder = anim.getZAdjustment(); 112 int adj = 0; 113 if (zorder == Animation.ZORDER_TOP) { 114 adj = TYPE_LAYER_OFFSET; 115 } else if (zorder == Animation.ZORDER_BOTTOM) { 116 adj = -TYPE_LAYER_OFFSET; 117 } 118 119 if (animLayerAdjustment != adj) { 120 animLayerAdjustment = adj; 121 updateLayers(); 122 } 123 // Start out animation gone if window is gone, or visible if window is visible. 124 transformation.clear(); 125 transformation.setAlpha(mAppToken.isVisible() ? 1 : 0); 126 hasTransformation = true; 127 128 if (!mAppToken.appFullscreen) { 129 anim.setBackgroundColor(0); 130 } 131 } 132 133 public void setDummyAnimation() { 134 if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting dummy animation in " + mAppToken 135 + " isVisible=" + mAppToken.isVisible()); 136 animation = sDummyAnimation; 137 hasTransformation = true; 138 transformation.clear(); 139 transformation.setAlpha(mAppToken.isVisible() ? 1 : 0); 140 } 141 142 public void clearAnimation() { 143 if (animation != null) { 144 animation = null; 145 animating = true; 146 } 147 clearThumbnail(); 148 if (mAppToken.deferClearAllDrawn) { 149 mAppToken.allDrawn = false; 150 mAppToken.deferClearAllDrawn = false; 151 } 152 usingTransferredAnimation = false; 153 } 154 155 public boolean isAnimating() { 156 return animation != null || mAppToken.inPendingTransaction; 157 } 158 159 public void clearThumbnail() { 160 if (thumbnail != null) { 161 thumbnail.destroy(); 162 thumbnail = null; 163 } 164 deferThumbnailDestruction = false; 165 } 166 167 void transferCurrentAnimation( 168 AppWindowAnimator toAppAnimator, WindowStateAnimator transferWinAnimator) { 169 170 if (animation != null) { 171 toAppAnimator.animation = animation; 172 animation = null; 173 toAppAnimator.animating = animating; 174 toAppAnimator.animLayerAdjustment = animLayerAdjustment; 175 animLayerAdjustment = 0; 176 toAppAnimator.updateLayers(); 177 updateLayers(); 178 toAppAnimator.usingTransferredAnimation = true; 179 } 180 if (transferWinAnimator != null) { 181 mAllAppWinAnimators.remove(transferWinAnimator); 182 toAppAnimator.mAllAppWinAnimators.add(transferWinAnimator); 183 transferWinAnimator.mAppAnimator = toAppAnimator; 184 } 185 } 186 187 void updateLayers() { 188 final int windowCount = mAppToken.allAppWindows.size(); 189 final int adj = animLayerAdjustment; 190 thumbnailLayer = -1; 191 for (int i = 0; i < windowCount; i++) { 192 final WindowState w = mAppToken.allAppWindows.get(i); 193 final WindowStateAnimator winAnimator = w.mWinAnimator; 194 winAnimator.mAnimLayer = w.mLayer + adj; 195 if (winAnimator.mAnimLayer > thumbnailLayer) { 196 thumbnailLayer = winAnimator.mAnimLayer; 197 } 198 if (DEBUG_LAYERS) Slog.v(TAG, "Updating layer " + w + ": " + winAnimator.mAnimLayer); 199 if (w == mService.mInputMethodTarget && !mService.mInputMethodTargetWaitingAnim) { 200 mService.setInputMethodAnimLayerAdjustment(adj); 201 } 202 if (w == mService.mWallpaperTarget && mService.mLowerWallpaperTarget == null) { 203 mService.setWallpaperAnimLayerAdjustmentLocked(adj); 204 } 205 } 206 } 207 208 private void stepThumbnailAnimation(long currentTime) { 209 thumbnailTransformation.clear(); 210 thumbnailAnimation.getTransformation(currentTime, thumbnailTransformation); 211 thumbnailTransformation.getMatrix().preTranslate(thumbnailX, thumbnailY); 212 213 ScreenRotationAnimation screenRotationAnimation = 214 mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY); 215 final boolean screenAnimation = screenRotationAnimation != null 216 && screenRotationAnimation.isAnimating(); 217 if (screenAnimation) { 218 thumbnailTransformation.postCompose(screenRotationAnimation.getEnterTransformation()); 219 } 220 // cache often used attributes locally 221 final float tmpFloats[] = mService.mTmpFloats; 222 thumbnailTransformation.getMatrix().getValues(tmpFloats); 223 if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail, 224 "thumbnail", "POS " + tmpFloats[Matrix.MTRANS_X] 225 + ", " + tmpFloats[Matrix.MTRANS_Y], null); 226 thumbnail.setPosition(tmpFloats[Matrix.MTRANS_X], tmpFloats[Matrix.MTRANS_Y]); 227 if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail, 228 "thumbnail", "alpha=" + thumbnailTransformation.getAlpha() 229 + " layer=" + thumbnailLayer 230 + " matrix=[" + tmpFloats[Matrix.MSCALE_X] 231 + "," + tmpFloats[Matrix.MSKEW_Y] 232 + "][" + tmpFloats[Matrix.MSKEW_X] 233 + "," + tmpFloats[Matrix.MSCALE_Y] + "]", null); 234 thumbnail.setAlpha(thumbnailTransformation.getAlpha()); 235 if (thumbnailForceAboveLayer > 0) { 236 thumbnail.setLayer(thumbnailForceAboveLayer + 1); 237 } else { 238 // The thumbnail is layered below the window immediately above this 239 // token's anim layer. 240 thumbnail.setLayer(thumbnailLayer + WindowManagerService.WINDOW_LAYER_MULTIPLIER 241 - WindowManagerService.LAYER_OFFSET_THUMBNAIL); 242 } 243 thumbnail.setMatrix(tmpFloats[Matrix.MSCALE_X], tmpFloats[Matrix.MSKEW_Y], 244 tmpFloats[Matrix.MSKEW_X], tmpFloats[Matrix.MSCALE_Y]); 245 } 246 247 private boolean stepAnimation(long currentTime) { 248 if (animation == null) { 249 return false; 250 } 251 transformation.clear(); 252 boolean hasMoreFrames = animation.getTransformation(currentTime, transformation); 253 if (!hasMoreFrames) { 254 if (deferThumbnailDestruction && !deferFinalFrameCleanup) { 255 // We are deferring the thumbnail destruction, so extend the animation for one more 256 // (dummy) frame before we clean up 257 deferFinalFrameCleanup = true; 258 hasMoreFrames = true; 259 } else { 260 if (false && DEBUG_ANIM) Slog.v(TAG, 261 "Stepped animation in " + mAppToken + ": more=" + hasMoreFrames + 262 ", xform=" + transformation); 263 deferFinalFrameCleanup = false; 264 animation = null; 265 clearThumbnail(); 266 if (DEBUG_ANIM) Slog.v(TAG, 267 "Finished animation in " + mAppToken + " @ " + currentTime); 268 } 269 } 270 hasTransformation = hasMoreFrames; 271 return hasMoreFrames; 272 } 273 274 // This must be called while inside a transaction. 275 boolean stepAnimationLocked(long currentTime, final int displayId) { 276 if (mService.okToDisplay()) { 277 // We will run animations as long as the display isn't frozen. 278 279 if (animation == sDummyAnimation) { 280 // This guy is going to animate, but not yet. For now count 281 // it as not animating for purposes of scheduling transactions; 282 // when it is really time to animate, this will be set to 283 // a real animation and the next call will execute normally. 284 return false; 285 } 286 287 if ((mAppToken.allDrawn || animating || mAppToken.startingDisplayed) 288 && animation != null) { 289 if (!animating) { 290 if (DEBUG_ANIM) Slog.v(TAG, 291 "Starting animation in " + mAppToken + 292 " @ " + currentTime + " scale=" 293 + mService.getTransitionAnimationScaleLocked() 294 + " allDrawn=" + mAppToken.allDrawn + " animating=" + animating); 295 animation.setStartTime(currentTime); 296 animating = true; 297 if (thumbnail != null) { 298 thumbnail.show(); 299 thumbnailAnimation.setStartTime(currentTime); 300 } 301 } 302 if (stepAnimation(currentTime)) { 303 // animation isn't over, step any thumbnail and that's 304 // it for now. 305 if (thumbnail != null) { 306 stepThumbnailAnimation(currentTime); 307 } 308 return true; 309 } 310 } 311 } else if (animation != null) { 312 // If the display is frozen, and there is a pending animation, 313 // clear it and make sure we run the cleanup code. 314 animating = true; 315 animation = null; 316 } 317 318 hasTransformation = false; 319 320 if (!animating && animation == null) { 321 return false; 322 } 323 324 mAnimator.setAppLayoutChanges(this, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM, 325 "AppWindowToken", displayId); 326 327 clearAnimation(); 328 animating = false; 329 if (animLayerAdjustment != 0) { 330 animLayerAdjustment = 0; 331 updateLayers(); 332 } 333 if (mService.mInputMethodTarget != null 334 && mService.mInputMethodTarget.mAppToken == mAppToken) { 335 mService.moveInputMethodWindowsIfNeededLocked(true); 336 } 337 338 if (DEBUG_ANIM) Slog.v(TAG, 339 "Animation done in " + mAppToken 340 + ": reportedVisible=" + mAppToken.reportedVisible); 341 342 transformation.clear(); 343 344 final int numAllAppWinAnimators = mAllAppWinAnimators.size(); 345 for (int i = 0; i < numAllAppWinAnimators; i++) { 346 mAllAppWinAnimators.get(i).finishExit(); 347 } 348 mService.mAppTransition.notifyAppTransitionFinishedLocked(this); 349 return false; 350 } 351 352 boolean showAllWindowsLocked() { 353 boolean isAnimating = false; 354 final int NW = mAllAppWinAnimators.size(); 355 for (int i=0; i<NW; i++) { 356 WindowStateAnimator winAnimator = mAllAppWinAnimators.get(i); 357 if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG, 358 "performing show on: " + winAnimator); 359 winAnimator.performShowLocked(); 360 isAnimating |= winAnimator.isAnimating(); 361 } 362 return isAnimating; 363 } 364 365 void dump(PrintWriter pw, String prefix, boolean dumpAll) { 366 pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken); 367 pw.print(prefix); pw.print("mAnimator="); pw.println(mAnimator); 368 pw.print(prefix); pw.print("freezingScreen="); pw.print(freezingScreen); 369 pw.print(" allDrawn="); pw.print(allDrawn); 370 pw.print(" animLayerAdjustment="); pw.println(animLayerAdjustment); 371 if (lastFreezeDuration != 0) { 372 pw.print(prefix); pw.print("lastFreezeDuration="); 373 TimeUtils.formatDuration(lastFreezeDuration, pw); pw.println(); 374 } 375 if (animating || animation != null) { 376 pw.print(prefix); pw.print("animating="); pw.println(animating); 377 pw.print(prefix); pw.print("animation="); pw.println(animation); 378 } 379 if (hasTransformation) { 380 pw.print(prefix); pw.print("XForm: "); 381 transformation.printShortString(pw); 382 pw.println(); 383 } 384 if (thumbnail != null) { 385 pw.print(prefix); pw.print("thumbnail="); pw.print(thumbnail); 386 pw.print(" x="); pw.print(thumbnailX); 387 pw.print(" y="); pw.print(thumbnailY); 388 pw.print(" layer="); pw.println(thumbnailLayer); 389 pw.print(prefix); pw.print("thumbnailAnimation="); pw.println(thumbnailAnimation); 390 pw.print(prefix); pw.print("thumbnailTransformation="); 391 pw.println(thumbnailTransformation.toShortString()); 392 } 393 for (int i=0; i<mAllAppWinAnimators.size(); i++) { 394 WindowStateAnimator wanim = mAllAppWinAnimators.get(i); 395 pw.print(prefix); pw.print("App Win Anim #"); pw.print(i); 396 pw.print(": "); pw.println(wanim); 397 } 398 } 399 400 // This is an animation that does nothing: it just immediately finishes 401 // itself every time it is called. It is used as a stub animation in cases 402 // where we want to synchronize multiple things that may be animating. 403 static final class DummyAnimation extends Animation { 404 @Override 405 public boolean getTransformation(long currentTime, Transformation outTransformation) { 406 return false; 407 } 408 } 409 410} 411