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