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