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