1 /* 2 * Copyright (C) 2010 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 static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE; 20 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; 21 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC; 22 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS; 23 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 24 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 25 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER; 26 import static com.android.server.wm.WindowStateAnimator.WINDOW_FREEZE_LAYER; 27 import static com.android.server.wm.WindowSurfaceController.SurfaceTrace; 28 29 import android.content.Context; 30 import android.graphics.Matrix; 31 import android.graphics.PixelFormat; 32 import android.graphics.Rect; 33 import android.util.Slog; 34 import android.view.Display; 35 import android.view.DisplayInfo; 36 import android.view.Surface; 37 import android.view.Surface.OutOfResourcesException; 38 import android.view.SurfaceControl; 39 import android.view.SurfaceSession; 40 import android.view.animation.Animation; 41 import android.view.animation.AnimationUtils; 42 import android.view.animation.Transformation; 43 44 import java.io.PrintWriter; 45 46 class ScreenRotationAnimation { 47 static final String TAG = TAG_WITH_CLASS_NAME ? "ScreenRotationAnimation" : TAG_WM; 48 static final boolean DEBUG_STATE = false; 49 static final boolean DEBUG_TRANSFORMS = false; 50 static final boolean TWO_PHASE_ANIMATION = false; 51 static final boolean USE_CUSTOM_BLACK_FRAME = false; 52 53 /* 54 * Layers for screen rotation animation. We put these layers above 55 * WINDOW_FREEZE_LAYER so that screen freeze will cover all windows. 56 */ 57 static final int SCREEN_FREEZE_LAYER_BASE = WINDOW_FREEZE_LAYER + TYPE_LAYER_MULTIPLIER; 58 static final int SCREEN_FREEZE_LAYER_ENTER = SCREEN_FREEZE_LAYER_BASE; 59 static final int SCREEN_FREEZE_LAYER_SCREENSHOT = SCREEN_FREEZE_LAYER_BASE + 1; 60 static final int SCREEN_FREEZE_LAYER_EXIT = SCREEN_FREEZE_LAYER_BASE + 2; 61 static final int SCREEN_FREEZE_LAYER_CUSTOM = SCREEN_FREEZE_LAYER_BASE + 3; 62 63 final Context mContext; 64 final DisplayContent mDisplayContent; 65 SurfaceControl mSurfaceControl; 66 BlackFrame mCustomBlackFrame; 67 BlackFrame mExitingBlackFrame; 68 BlackFrame mEnteringBlackFrame; 69 int mWidth, mHeight; 70 71 int mOriginalRotation; 72 int mOriginalWidth, mOriginalHeight; 73 int mCurRotation; 74 Rect mOriginalDisplayRect = new Rect(); 75 Rect mCurrentDisplayRect = new Rect(); 76 77 // For all animations, "exit" is for the UI elements that are going 78 // away (that is the snapshot of the old screen), and "enter" is for 79 // the new UI elements that are appearing (that is the active windows 80 // in their final orientation). 81 82 // The starting animation for the exiting and entering elements. This 83 // animation applies a transformation while the rotation is in progress. 84 // It is started immediately, before the new entering UI is ready. 85 Animation mStartExitAnimation; 86 final Transformation mStartExitTransformation = new Transformation(); 87 Animation mStartEnterAnimation; 88 final Transformation mStartEnterTransformation = new Transformation(); 89 Animation mStartFrameAnimation; 90 final Transformation mStartFrameTransformation = new Transformation(); 91 92 // The finishing animation for the exiting and entering elements. This 93 // animation needs to undo the transformation of the starting animation. 94 // It starts running once the new rotation UI elements are ready to be 95 // displayed. 96 Animation mFinishExitAnimation; 97 final Transformation mFinishExitTransformation = new Transformation(); 98 Animation mFinishEnterAnimation; 99 final Transformation mFinishEnterTransformation = new Transformation(); 100 Animation mFinishFrameAnimation; 101 final Transformation mFinishFrameTransformation = new Transformation(); 102 103 // The current active animation to move from the old to the new rotated 104 // state. Which animation is run here will depend on the old and new 105 // rotations. 106 Animation mRotateExitAnimation; 107 final Transformation mRotateExitTransformation = new Transformation(); 108 Animation mRotateEnterAnimation; 109 final Transformation mRotateEnterTransformation = new Transformation(); 110 Animation mRotateFrameAnimation; 111 final Transformation mRotateFrameTransformation = new Transformation(); 112 113 // A previously running rotate animation. This will be used if we need 114 // to switch to a new rotation before finishing the previous one. 115 Animation mLastRotateExitAnimation; 116 final Transformation mLastRotateExitTransformation = new Transformation(); 117 Animation mLastRotateEnterAnimation; 118 final Transformation mLastRotateEnterTransformation = new Transformation(); 119 Animation mLastRotateFrameAnimation; 120 final Transformation mLastRotateFrameTransformation = new Transformation(); 121 122 // Complete transformations being applied. 123 final Transformation mExitTransformation = new Transformation(); 124 final Transformation mEnterTransformation = new Transformation(); 125 final Transformation mFrameTransformation = new Transformation(); 126 127 boolean mStarted; 128 boolean mAnimRunning; 129 boolean mFinishAnimReady; 130 long mFinishAnimStartTime; 131 boolean mForceDefaultOrientation; 132 133 final Matrix mFrameInitialMatrix = new Matrix(); 134 final Matrix mSnapshotInitialMatrix = new Matrix(); 135 final Matrix mSnapshotFinalMatrix = new Matrix(); 136 final Matrix mExitFrameFinalMatrix = new Matrix(); 137 final Matrix mTmpMatrix = new Matrix(); 138 final float[] mTmpFloats = new float[9]; 139 private boolean mMoreRotateEnter; 140 private boolean mMoreRotateExit; 141 private boolean mMoreRotateFrame; 142 private boolean mMoreFinishEnter; 143 private boolean mMoreFinishExit; 144 private boolean mMoreFinishFrame; 145 private boolean mMoreStartEnter; 146 private boolean mMoreStartExit; 147 private boolean mMoreStartFrame; 148 long mHalfwayPoint; 149 printTo(String prefix, PrintWriter pw)150 public void printTo(String prefix, PrintWriter pw) { 151 pw.print(prefix); pw.print("mSurface="); pw.print(mSurfaceControl); 152 pw.print(" mWidth="); pw.print(mWidth); 153 pw.print(" mHeight="); pw.println(mHeight); 154 if (USE_CUSTOM_BLACK_FRAME) { 155 pw.print(prefix); pw.print("mCustomBlackFrame="); pw.println(mCustomBlackFrame); 156 if (mCustomBlackFrame != null) { 157 mCustomBlackFrame.printTo(prefix + " ", pw); 158 } 159 } 160 pw.print(prefix); pw.print("mExitingBlackFrame="); pw.println(mExitingBlackFrame); 161 if (mExitingBlackFrame != null) { 162 mExitingBlackFrame.printTo(prefix + " ", pw); 163 } 164 pw.print(prefix); pw.print("mEnteringBlackFrame="); pw.println(mEnteringBlackFrame); 165 if (mEnteringBlackFrame != null) { 166 mEnteringBlackFrame.printTo(prefix + " ", pw); 167 } 168 pw.print(prefix); pw.print("mCurRotation="); pw.print(mCurRotation); 169 pw.print(" mOriginalRotation="); pw.println(mOriginalRotation); 170 pw.print(prefix); pw.print("mOriginalWidth="); pw.print(mOriginalWidth); 171 pw.print(" mOriginalHeight="); pw.println(mOriginalHeight); 172 pw.print(prefix); pw.print("mStarted="); pw.print(mStarted); 173 pw.print(" mAnimRunning="); pw.print(mAnimRunning); 174 pw.print(" mFinishAnimReady="); pw.print(mFinishAnimReady); 175 pw.print(" mFinishAnimStartTime="); pw.println(mFinishAnimStartTime); 176 pw.print(prefix); pw.print("mStartExitAnimation="); pw.print(mStartExitAnimation); 177 pw.print(" "); mStartExitTransformation.printShortString(pw); pw.println(); 178 pw.print(prefix); pw.print("mStartEnterAnimation="); pw.print(mStartEnterAnimation); 179 pw.print(" "); mStartEnterTransformation.printShortString(pw); pw.println(); 180 pw.print(prefix); pw.print("mStartFrameAnimation="); pw.print(mStartFrameAnimation); 181 pw.print(" "); mStartFrameTransformation.printShortString(pw); pw.println(); 182 pw.print(prefix); pw.print("mFinishExitAnimation="); pw.print(mFinishExitAnimation); 183 pw.print(" "); mFinishExitTransformation.printShortString(pw); pw.println(); 184 pw.print(prefix); pw.print("mFinishEnterAnimation="); pw.print(mFinishEnterAnimation); 185 pw.print(" "); mFinishEnterTransformation.printShortString(pw); pw.println(); 186 pw.print(prefix); pw.print("mFinishFrameAnimation="); pw.print(mFinishFrameAnimation); 187 pw.print(" "); mFinishFrameTransformation.printShortString(pw); pw.println(); 188 pw.print(prefix); pw.print("mRotateExitAnimation="); pw.print(mRotateExitAnimation); 189 pw.print(" "); mRotateExitTransformation.printShortString(pw); pw.println(); 190 pw.print(prefix); pw.print("mRotateEnterAnimation="); pw.print(mRotateEnterAnimation); 191 pw.print(" "); mRotateEnterTransformation.printShortString(pw); pw.println(); 192 pw.print(prefix); pw.print("mRotateFrameAnimation="); pw.print(mRotateFrameAnimation); 193 pw.print(" "); mRotateFrameTransformation.printShortString(pw); pw.println(); 194 pw.print(prefix); pw.print("mExitTransformation="); 195 mExitTransformation.printShortString(pw); pw.println(); 196 pw.print(prefix); pw.print("mEnterTransformation="); 197 mEnterTransformation.printShortString(pw); pw.println(); 198 pw.print(prefix); pw.print("mFrameTransformation="); 199 mEnterTransformation.printShortString(pw); pw.println(); 200 pw.print(prefix); pw.print("mFrameInitialMatrix="); 201 mFrameInitialMatrix.printShortString(pw); 202 pw.println(); 203 pw.print(prefix); pw.print("mSnapshotInitialMatrix="); 204 mSnapshotInitialMatrix.printShortString(pw); 205 pw.print(" mSnapshotFinalMatrix="); mSnapshotFinalMatrix.printShortString(pw); 206 pw.println(); 207 pw.print(prefix); pw.print("mExitFrameFinalMatrix="); 208 mExitFrameFinalMatrix.printShortString(pw); 209 pw.println(); 210 pw.print(prefix); pw.print("mForceDefaultOrientation="); pw.print(mForceDefaultOrientation); 211 if (mForceDefaultOrientation) { 212 pw.print(" mOriginalDisplayRect="); pw.print(mOriginalDisplayRect.toShortString()); 213 pw.print(" mCurrentDisplayRect="); pw.println(mCurrentDisplayRect.toShortString()); 214 } 215 } 216 ScreenRotationAnimation(Context context, DisplayContent displayContent, SurfaceSession session, boolean inTransaction, boolean forceDefaultOrientation, boolean isSecure)217 public ScreenRotationAnimation(Context context, DisplayContent displayContent, 218 SurfaceSession session, boolean inTransaction, boolean forceDefaultOrientation, 219 boolean isSecure) { 220 mContext = context; 221 mDisplayContent = displayContent; 222 displayContent.getLogicalDisplayRect(mOriginalDisplayRect); 223 224 // Screenshot does NOT include rotation! 225 final Display display = displayContent.getDisplay(); 226 int originalRotation = display.getRotation(); 227 final int originalWidth; 228 final int originalHeight; 229 DisplayInfo displayInfo = displayContent.getDisplayInfo(); 230 if (forceDefaultOrientation) { 231 // Emulated orientation. 232 mForceDefaultOrientation = true; 233 originalWidth = displayContent.mBaseDisplayWidth; 234 originalHeight = displayContent.mBaseDisplayHeight; 235 } else { 236 // Normal situation 237 originalWidth = displayInfo.logicalWidth; 238 originalHeight = displayInfo.logicalHeight; 239 } 240 if (originalRotation == Surface.ROTATION_90 241 || originalRotation == Surface.ROTATION_270) { 242 mWidth = originalHeight; 243 mHeight = originalWidth; 244 } else { 245 mWidth = originalWidth; 246 mHeight = originalHeight; 247 } 248 249 mOriginalRotation = originalRotation; 250 mOriginalWidth = originalWidth; 251 mOriginalHeight = originalHeight; 252 253 if (!inTransaction) { 254 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, 255 ">>> OPEN TRANSACTION ScreenRotationAnimation"); 256 SurfaceControl.openTransaction(); 257 } 258 259 try { 260 try { 261 int flags = SurfaceControl.HIDDEN; 262 if (isSecure) { 263 flags |= SurfaceControl.SECURE; 264 } 265 266 if (DEBUG_SURFACE_TRACE) { 267 mSurfaceControl = new SurfaceTrace(session, "ScreenshotSurface", 268 mWidth, mHeight, 269 PixelFormat.OPAQUE, flags); 270 Slog.w(TAG, "ScreenRotationAnimation ctor: displayOffset=" 271 + mOriginalDisplayRect.toShortString()); 272 } else { 273 mSurfaceControl = new SurfaceControl(session, "ScreenshotSurface", 274 mWidth, mHeight, 275 PixelFormat.OPAQUE, flags); 276 } 277 // capture a screenshot into the surface we just created 278 Surface sur = new Surface(); 279 sur.copyFrom(mSurfaceControl); 280 // FIXME: we should use the proper display 281 SurfaceControl.screenshot(SurfaceControl.getBuiltInDisplay( 282 SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN), sur); 283 mSurfaceControl.setLayerStack(display.getLayerStack()); 284 mSurfaceControl.setLayer(SCREEN_FREEZE_LAYER_SCREENSHOT); 285 mSurfaceControl.setAlpha(0); 286 mSurfaceControl.show(); 287 sur.destroy(); 288 } catch (OutOfResourcesException e) { 289 Slog.w(TAG, "Unable to allocate freeze surface", e); 290 } 291 292 if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG_WM, 293 " FREEZE " + mSurfaceControl + ": CREATE"); 294 295 setRotationInTransaction(originalRotation); 296 } finally { 297 if (!inTransaction) { 298 SurfaceControl.closeTransaction(); 299 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, 300 "<<< CLOSE TRANSACTION ScreenRotationAnimation"); 301 } 302 } 303 } 304 hasScreenshot()305 boolean hasScreenshot() { 306 return mSurfaceControl != null; 307 } 308 setSnapshotTransformInTransaction(Matrix matrix, float alpha)309 private void setSnapshotTransformInTransaction(Matrix matrix, float alpha) { 310 if (mSurfaceControl != null) { 311 matrix.getValues(mTmpFloats); 312 float x = mTmpFloats[Matrix.MTRANS_X]; 313 float y = mTmpFloats[Matrix.MTRANS_Y]; 314 if (mForceDefaultOrientation) { 315 mDisplayContent.getLogicalDisplayRect(mCurrentDisplayRect); 316 x -= mCurrentDisplayRect.left; 317 y -= mCurrentDisplayRect.top; 318 } 319 mSurfaceControl.setPosition(x, y); 320 mSurfaceControl.setMatrix( 321 mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y], 322 mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]); 323 mSurfaceControl.setAlpha(alpha); 324 if (DEBUG_TRANSFORMS) { 325 float[] srcPnts = new float[] { 0, 0, mWidth, mHeight }; 326 float[] dstPnts = new float[4]; 327 matrix.mapPoints(dstPnts, srcPnts); 328 Slog.i(TAG, "Original : (" + srcPnts[0] + "," + srcPnts[1] 329 + ")-(" + srcPnts[2] + "," + srcPnts[3] + ")"); 330 Slog.i(TAG, "Transformed: (" + dstPnts[0] + "," + dstPnts[1] 331 + ")-(" + dstPnts[2] + "," + dstPnts[3] + ")"); 332 } 333 } 334 } 335 createRotationMatrix(int rotation, int width, int height, Matrix outMatrix)336 public static void createRotationMatrix(int rotation, int width, int height, 337 Matrix outMatrix) { 338 switch (rotation) { 339 case Surface.ROTATION_0: 340 outMatrix.reset(); 341 break; 342 case Surface.ROTATION_90: 343 outMatrix.setRotate(90, 0, 0); 344 outMatrix.postTranslate(height, 0); 345 break; 346 case Surface.ROTATION_180: 347 outMatrix.setRotate(180, 0, 0); 348 outMatrix.postTranslate(width, height); 349 break; 350 case Surface.ROTATION_270: 351 outMatrix.setRotate(270, 0, 0); 352 outMatrix.postTranslate(0, width); 353 break; 354 } 355 } 356 357 // Must be called while in a transaction. setRotationInTransaction(int rotation)358 private void setRotationInTransaction(int rotation) { 359 mCurRotation = rotation; 360 361 // Compute the transformation matrix that must be applied 362 // to the snapshot to make it stay in the same original position 363 // with the current screen rotation. 364 int delta = DisplayContent.deltaRotation(rotation, Surface.ROTATION_0); 365 createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix); 366 367 if (DEBUG_STATE) Slog.v(TAG, "**** ROTATION: " + delta); 368 setSnapshotTransformInTransaction(mSnapshotInitialMatrix, 1.0f); 369 } 370 371 // Must be called while in a transaction. setRotationInTransaction(int rotation, SurfaceSession session, long maxAnimationDuration, float animationScale, int finalWidth, int finalHeight)372 public boolean setRotationInTransaction(int rotation, SurfaceSession session, 373 long maxAnimationDuration, float animationScale, int finalWidth, int finalHeight) { 374 setRotationInTransaction(rotation); 375 if (TWO_PHASE_ANIMATION) { 376 return startAnimation(session, maxAnimationDuration, animationScale, 377 finalWidth, finalHeight, false, 0, 0); 378 } 379 380 // Don't start animation yet. 381 return false; 382 } 383 384 /** 385 * Returns true if animating. 386 */ startAnimation(SurfaceSession session, long maxAnimationDuration, float animationScale, int finalWidth, int finalHeight, boolean dismissing, int exitAnim, int enterAnim)387 private boolean startAnimation(SurfaceSession session, long maxAnimationDuration, 388 float animationScale, int finalWidth, int finalHeight, boolean dismissing, 389 int exitAnim, int enterAnim) { 390 if (mSurfaceControl == null) { 391 // Can't do animation. 392 return false; 393 } 394 if (mStarted) { 395 return true; 396 } 397 398 mStarted = true; 399 400 boolean firstStart = false; 401 402 // Figure out how the screen has moved from the original rotation. 403 int delta = DisplayContent.deltaRotation(mCurRotation, mOriginalRotation); 404 405 if (TWO_PHASE_ANIMATION && mFinishExitAnimation == null 406 && (!dismissing || delta != Surface.ROTATION_0)) { 407 if (DEBUG_STATE) Slog.v(TAG, "Creating start and finish animations"); 408 firstStart = true; 409 mStartExitAnimation = AnimationUtils.loadAnimation(mContext, 410 com.android.internal.R.anim.screen_rotate_start_exit); 411 mStartEnterAnimation = AnimationUtils.loadAnimation(mContext, 412 com.android.internal.R.anim.screen_rotate_start_enter); 413 if (USE_CUSTOM_BLACK_FRAME) { 414 mStartFrameAnimation = AnimationUtils.loadAnimation(mContext, 415 com.android.internal.R.anim.screen_rotate_start_frame); 416 } 417 mFinishExitAnimation = AnimationUtils.loadAnimation(mContext, 418 com.android.internal.R.anim.screen_rotate_finish_exit); 419 mFinishEnterAnimation = AnimationUtils.loadAnimation(mContext, 420 com.android.internal.R.anim.screen_rotate_finish_enter); 421 if (USE_CUSTOM_BLACK_FRAME) { 422 mFinishFrameAnimation = AnimationUtils.loadAnimation(mContext, 423 com.android.internal.R.anim.screen_rotate_finish_frame); 424 } 425 } 426 427 if (DEBUG_STATE) Slog.v(TAG, "Rotation delta: " + delta + " finalWidth=" 428 + finalWidth + " finalHeight=" + finalHeight 429 + " origWidth=" + mOriginalWidth + " origHeight=" + mOriginalHeight); 430 431 final boolean customAnim; 432 if (exitAnim != 0 && enterAnim != 0) { 433 customAnim = true; 434 mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, exitAnim); 435 mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, enterAnim); 436 } else { 437 customAnim = false; 438 switch (delta) { 439 case Surface.ROTATION_0: 440 mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, 441 com.android.internal.R.anim.screen_rotate_0_exit); 442 mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, 443 com.android.internal.R.anim.screen_rotate_0_enter); 444 if (USE_CUSTOM_BLACK_FRAME) { 445 mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext, 446 com.android.internal.R.anim.screen_rotate_0_frame); 447 } 448 break; 449 case Surface.ROTATION_90: 450 mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, 451 com.android.internal.R.anim.screen_rotate_plus_90_exit); 452 mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, 453 com.android.internal.R.anim.screen_rotate_plus_90_enter); 454 if (USE_CUSTOM_BLACK_FRAME) { 455 mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext, 456 com.android.internal.R.anim.screen_rotate_plus_90_frame); 457 } 458 break; 459 case Surface.ROTATION_180: 460 mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, 461 com.android.internal.R.anim.screen_rotate_180_exit); 462 mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, 463 com.android.internal.R.anim.screen_rotate_180_enter); 464 if (USE_CUSTOM_BLACK_FRAME) { 465 mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext, 466 com.android.internal.R.anim.screen_rotate_180_frame); 467 } 468 break; 469 case Surface.ROTATION_270: 470 mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, 471 com.android.internal.R.anim.screen_rotate_minus_90_exit); 472 mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, 473 com.android.internal.R.anim.screen_rotate_minus_90_enter); 474 if (USE_CUSTOM_BLACK_FRAME) { 475 mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext, 476 com.android.internal.R.anim.screen_rotate_minus_90_frame); 477 } 478 break; 479 } 480 } 481 482 // Initialize the animations. This is a hack, redefining what "parent" 483 // means to allow supplying the last and next size. In this definition 484 // "%p" is the original (let's call it "previous") size, and "%" is the 485 // screen's current/new size. 486 if (TWO_PHASE_ANIMATION && firstStart) { 487 // Compute partial steps between original and final sizes. These 488 // are used for the dimensions of the exiting and entering elements, 489 // so they are never stretched too significantly. 490 final int halfWidth = (finalWidth + mOriginalWidth) / 2; 491 final int halfHeight = (finalHeight + mOriginalHeight) / 2; 492 493 if (DEBUG_STATE) Slog.v(TAG, "Initializing start and finish animations"); 494 mStartEnterAnimation.initialize(finalWidth, finalHeight, 495 halfWidth, halfHeight); 496 mStartExitAnimation.initialize(halfWidth, halfHeight, 497 mOriginalWidth, mOriginalHeight); 498 mFinishEnterAnimation.initialize(finalWidth, finalHeight, 499 halfWidth, halfHeight); 500 mFinishExitAnimation.initialize(halfWidth, halfHeight, 501 mOriginalWidth, mOriginalHeight); 502 if (USE_CUSTOM_BLACK_FRAME) { 503 mStartFrameAnimation.initialize(finalWidth, finalHeight, 504 mOriginalWidth, mOriginalHeight); 505 mFinishFrameAnimation.initialize(finalWidth, finalHeight, 506 mOriginalWidth, mOriginalHeight); 507 } 508 } 509 mRotateEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight); 510 mRotateExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight); 511 if (USE_CUSTOM_BLACK_FRAME) { 512 mRotateFrameAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, 513 mOriginalHeight); 514 } 515 mAnimRunning = false; 516 mFinishAnimReady = false; 517 mFinishAnimStartTime = -1; 518 519 if (TWO_PHASE_ANIMATION && firstStart) { 520 mStartExitAnimation.restrictDuration(maxAnimationDuration); 521 mStartExitAnimation.scaleCurrentDuration(animationScale); 522 mStartEnterAnimation.restrictDuration(maxAnimationDuration); 523 mStartEnterAnimation.scaleCurrentDuration(animationScale); 524 mFinishExitAnimation.restrictDuration(maxAnimationDuration); 525 mFinishExitAnimation.scaleCurrentDuration(animationScale); 526 mFinishEnterAnimation.restrictDuration(maxAnimationDuration); 527 mFinishEnterAnimation.scaleCurrentDuration(animationScale); 528 if (USE_CUSTOM_BLACK_FRAME) { 529 mStartFrameAnimation.restrictDuration(maxAnimationDuration); 530 mStartFrameAnimation.scaleCurrentDuration(animationScale); 531 mFinishFrameAnimation.restrictDuration(maxAnimationDuration); 532 mFinishFrameAnimation.scaleCurrentDuration(animationScale); 533 } 534 } 535 mRotateExitAnimation.restrictDuration(maxAnimationDuration); 536 mRotateExitAnimation.scaleCurrentDuration(animationScale); 537 mRotateEnterAnimation.restrictDuration(maxAnimationDuration); 538 mRotateEnterAnimation.scaleCurrentDuration(animationScale); 539 if (USE_CUSTOM_BLACK_FRAME) { 540 mRotateFrameAnimation.restrictDuration(maxAnimationDuration); 541 mRotateFrameAnimation.scaleCurrentDuration(animationScale); 542 } 543 544 final int layerStack = mDisplayContent.getDisplay().getLayerStack(); 545 if (USE_CUSTOM_BLACK_FRAME && mCustomBlackFrame == null) { 546 if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i( 547 TAG_WM, 548 ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation"); 549 SurfaceControl.openTransaction(); 550 551 // Compute the transformation matrix that must be applied 552 // the the black frame to make it stay in the initial position 553 // before the new screen rotation. This is different than the 554 // snapshot transformation because the snapshot is always based 555 // of the native orientation of the screen, not the orientation 556 // we were last in. 557 createRotationMatrix(delta, mOriginalWidth, mOriginalHeight, mFrameInitialMatrix); 558 559 try { 560 Rect outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1, 561 mOriginalWidth*2, mOriginalHeight*2); 562 Rect inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight); 563 mCustomBlackFrame = new BlackFrame(session, outer, inner, 564 SCREEN_FREEZE_LAYER_CUSTOM, layerStack, false); 565 mCustomBlackFrame.setMatrix(mFrameInitialMatrix); 566 } catch (OutOfResourcesException e) { 567 Slog.w(TAG, "Unable to allocate black surface", e); 568 } finally { 569 SurfaceControl.closeTransaction(); 570 if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i( 571 TAG_WM, 572 "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation"); 573 } 574 } 575 576 if (!customAnim && mExitingBlackFrame == null) { 577 if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i( 578 TAG_WM, 579 ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation"); 580 SurfaceControl.openTransaction(); 581 try { 582 // Compute the transformation matrix that must be applied 583 // the the black frame to make it stay in the initial position 584 // before the new screen rotation. This is different than the 585 // snapshot transformation because the snapshot is always based 586 // of the native orientation of the screen, not the orientation 587 // we were last in. 588 createRotationMatrix(delta, mOriginalWidth, mOriginalHeight, mFrameInitialMatrix); 589 590 final Rect outer; 591 final Rect inner; 592 if (mForceDefaultOrientation) { 593 // Going from a smaller Display to a larger Display, add curtains to sides 594 // or top and bottom. Going from a larger to smaller display will result in 595 // no BlackSurfaces being constructed. 596 outer = mCurrentDisplayRect; 597 inner = mOriginalDisplayRect; 598 } else { 599 outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1, 600 mOriginalWidth*2, mOriginalHeight*2); 601 inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight); 602 } 603 mExitingBlackFrame = new BlackFrame(session, outer, inner, 604 SCREEN_FREEZE_LAYER_EXIT, layerStack, mForceDefaultOrientation); 605 mExitingBlackFrame.setMatrix(mFrameInitialMatrix); 606 } catch (OutOfResourcesException e) { 607 Slog.w(TAG, "Unable to allocate black surface", e); 608 } finally { 609 SurfaceControl.closeTransaction(); 610 if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i( 611 TAG_WM, 612 "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation"); 613 } 614 } 615 616 if (customAnim && mEnteringBlackFrame == null) { 617 if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i( 618 TAG_WM, 619 ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation"); 620 SurfaceControl.openTransaction(); 621 622 try { 623 Rect outer = new Rect(-finalWidth*1, -finalHeight*1, 624 finalWidth*2, finalHeight*2); 625 Rect inner = new Rect(0, 0, finalWidth, finalHeight); 626 mEnteringBlackFrame = new BlackFrame(session, outer, inner, 627 SCREEN_FREEZE_LAYER_ENTER, layerStack, false); 628 } catch (OutOfResourcesException e) { 629 Slog.w(TAG, "Unable to allocate black surface", e); 630 } finally { 631 SurfaceControl.closeTransaction(); 632 if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i( 633 TAG_WM, 634 "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation"); 635 } 636 } 637 638 return true; 639 } 640 641 /** 642 * Returns true if animating. 643 */ dismiss(SurfaceSession session, long maxAnimationDuration, float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim)644 public boolean dismiss(SurfaceSession session, long maxAnimationDuration, 645 float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) { 646 if (DEBUG_STATE) Slog.v(TAG, "Dismiss!"); 647 if (mSurfaceControl == null) { 648 // Can't do animation. 649 return false; 650 } 651 if (!mStarted) { 652 startAnimation(session, maxAnimationDuration, animationScale, finalWidth, finalHeight, 653 true, exitAnim, enterAnim); 654 } 655 if (!mStarted) { 656 return false; 657 } 658 if (DEBUG_STATE) Slog.v(TAG, "Setting mFinishAnimReady = true"); 659 mFinishAnimReady = true; 660 return true; 661 } 662 kill()663 public void kill() { 664 if (DEBUG_STATE) Slog.v(TAG, "Kill!"); 665 if (mSurfaceControl != null) { 666 if (SHOW_TRANSACTIONS || 667 SHOW_SURFACE_ALLOC) Slog.i(TAG_WM, 668 " FREEZE " + mSurfaceControl + ": DESTROY"); 669 mSurfaceControl.destroy(); 670 mSurfaceControl = null; 671 } 672 if (mCustomBlackFrame != null) { 673 mCustomBlackFrame.kill(); 674 mCustomBlackFrame = null; 675 } 676 if (mExitingBlackFrame != null) { 677 mExitingBlackFrame.kill(); 678 mExitingBlackFrame = null; 679 } 680 if (mEnteringBlackFrame != null) { 681 mEnteringBlackFrame.kill(); 682 mEnteringBlackFrame = null; 683 } 684 if (TWO_PHASE_ANIMATION) { 685 if (mStartExitAnimation != null) { 686 mStartExitAnimation.cancel(); 687 mStartExitAnimation = null; 688 } 689 if (mStartEnterAnimation != null) { 690 mStartEnterAnimation.cancel(); 691 mStartEnterAnimation = null; 692 } 693 if (mFinishExitAnimation != null) { 694 mFinishExitAnimation.cancel(); 695 mFinishExitAnimation = null; 696 } 697 if (mFinishEnterAnimation != null) { 698 mFinishEnterAnimation.cancel(); 699 mFinishEnterAnimation = null; 700 } 701 } 702 if (USE_CUSTOM_BLACK_FRAME) { 703 if (mStartFrameAnimation != null) { 704 mStartFrameAnimation.cancel(); 705 mStartFrameAnimation = null; 706 } 707 if (mRotateFrameAnimation != null) { 708 mRotateFrameAnimation.cancel(); 709 mRotateFrameAnimation = null; 710 } 711 if (mFinishFrameAnimation != null) { 712 mFinishFrameAnimation.cancel(); 713 mFinishFrameAnimation = null; 714 } 715 } 716 if (mRotateExitAnimation != null) { 717 mRotateExitAnimation.cancel(); 718 mRotateExitAnimation = null; 719 } 720 if (mRotateEnterAnimation != null) { 721 mRotateEnterAnimation.cancel(); 722 mRotateEnterAnimation = null; 723 } 724 } 725 isAnimating()726 public boolean isAnimating() { 727 return hasAnimations() || (TWO_PHASE_ANIMATION && mFinishAnimReady); 728 } 729 isRotating()730 public boolean isRotating() { 731 return mCurRotation != mOriginalRotation; 732 } 733 hasAnimations()734 private boolean hasAnimations() { 735 return (TWO_PHASE_ANIMATION && 736 (mStartEnterAnimation != null || mStartExitAnimation != null 737 || mFinishEnterAnimation != null || mFinishExitAnimation != null)) 738 || (USE_CUSTOM_BLACK_FRAME && 739 (mStartFrameAnimation != null || mRotateFrameAnimation != null 740 || mFinishFrameAnimation != null)) 741 || mRotateEnterAnimation != null || mRotateExitAnimation != null; 742 } 743 stepAnimation(long now)744 private boolean stepAnimation(long now) { 745 if (now > mHalfwayPoint) { 746 mHalfwayPoint = Long.MAX_VALUE; 747 } 748 if (mFinishAnimReady && mFinishAnimStartTime < 0) { 749 if (DEBUG_STATE) Slog.v(TAG, "Step: finish anim now ready"); 750 mFinishAnimStartTime = now; 751 } 752 753 if (TWO_PHASE_ANIMATION) { 754 mMoreStartExit = false; 755 if (mStartExitAnimation != null) { 756 mMoreStartExit = mStartExitAnimation.getTransformation(now, mStartExitTransformation); 757 if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start exit: " + mStartExitTransformation); 758 } 759 760 mMoreStartEnter = false; 761 if (mStartEnterAnimation != null) { 762 mMoreStartEnter = mStartEnterAnimation.getTransformation(now, mStartEnterTransformation); 763 if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start enter: " + mStartEnterTransformation); 764 } 765 } 766 if (USE_CUSTOM_BLACK_FRAME) { 767 mMoreStartFrame = false; 768 if (mStartFrameAnimation != null) { 769 mMoreStartFrame = mStartFrameAnimation.getTransformation(now, mStartFrameTransformation); 770 if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start frame: " + mStartFrameTransformation); 771 } 772 } 773 774 long finishNow = mFinishAnimReady ? (now - mFinishAnimStartTime) : 0; 775 if (DEBUG_STATE) Slog.v(TAG, "Step: finishNow=" + finishNow); 776 777 if (TWO_PHASE_ANIMATION) { 778 mMoreFinishExit = false; 779 if (mFinishExitAnimation != null) { 780 mMoreFinishExit = mFinishExitAnimation.getTransformation(finishNow, mFinishExitTransformation); 781 if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish exit: " + mFinishExitTransformation); 782 } 783 784 mMoreFinishEnter = false; 785 if (mFinishEnterAnimation != null) { 786 mMoreFinishEnter = mFinishEnterAnimation.getTransformation(finishNow, mFinishEnterTransformation); 787 if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish enter: " + mFinishEnterTransformation); 788 } 789 } 790 if (USE_CUSTOM_BLACK_FRAME) { 791 mMoreFinishFrame = false; 792 if (mFinishFrameAnimation != null) { 793 mMoreFinishFrame = mFinishFrameAnimation.getTransformation(finishNow, mFinishFrameTransformation); 794 if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish frame: " + mFinishFrameTransformation); 795 } 796 } 797 798 mMoreRotateExit = false; 799 if (mRotateExitAnimation != null) { 800 mMoreRotateExit = mRotateExitAnimation.getTransformation(now, mRotateExitTransformation); 801 if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate exit: " + mRotateExitTransformation); 802 } 803 804 mMoreRotateEnter = false; 805 if (mRotateEnterAnimation != null) { 806 mMoreRotateEnter = mRotateEnterAnimation.getTransformation(now, mRotateEnterTransformation); 807 if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate enter: " + mRotateEnterTransformation); 808 } 809 810 if (USE_CUSTOM_BLACK_FRAME) { 811 mMoreRotateFrame = false; 812 if (mRotateFrameAnimation != null) { 813 mMoreRotateFrame = mRotateFrameAnimation.getTransformation(now, mRotateFrameTransformation); 814 if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate frame: " + mRotateFrameTransformation); 815 } 816 } 817 818 if (!mMoreRotateExit && (!TWO_PHASE_ANIMATION || (!mMoreStartExit && !mMoreFinishExit))) { 819 if (TWO_PHASE_ANIMATION) { 820 if (mStartExitAnimation != null) { 821 if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing start exit anim!"); 822 mStartExitAnimation.cancel(); 823 mStartExitAnimation = null; 824 mStartExitTransformation.clear(); 825 } 826 if (mFinishExitAnimation != null) { 827 if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing finish exit anim!"); 828 mFinishExitAnimation.cancel(); 829 mFinishExitAnimation = null; 830 mFinishExitTransformation.clear(); 831 } 832 } 833 if (mRotateExitAnimation != null) { 834 if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing rotate exit anim!"); 835 mRotateExitAnimation.cancel(); 836 mRotateExitAnimation = null; 837 mRotateExitTransformation.clear(); 838 } 839 } 840 841 if (!mMoreRotateEnter && (!TWO_PHASE_ANIMATION || (!mMoreStartEnter && !mMoreFinishEnter))) { 842 if (TWO_PHASE_ANIMATION) { 843 if (mStartEnterAnimation != null) { 844 if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing start enter anim!"); 845 mStartEnterAnimation.cancel(); 846 mStartEnterAnimation = null; 847 mStartEnterTransformation.clear(); 848 } 849 if (mFinishEnterAnimation != null) { 850 if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing finish enter anim!"); 851 mFinishEnterAnimation.cancel(); 852 mFinishEnterAnimation = null; 853 mFinishEnterTransformation.clear(); 854 } 855 } 856 if (mRotateEnterAnimation != null) { 857 if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing rotate enter anim!"); 858 mRotateEnterAnimation.cancel(); 859 mRotateEnterAnimation = null; 860 mRotateEnterTransformation.clear(); 861 } 862 } 863 864 if (USE_CUSTOM_BLACK_FRAME && !mMoreStartFrame && !mMoreRotateFrame && !mMoreFinishFrame) { 865 if (mStartFrameAnimation != null) { 866 if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, clearing start frame anim!"); 867 mStartFrameAnimation.cancel(); 868 mStartFrameAnimation = null; 869 mStartFrameTransformation.clear(); 870 } 871 if (mFinishFrameAnimation != null) { 872 if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, clearing finish frame anim!"); 873 mFinishFrameAnimation.cancel(); 874 mFinishFrameAnimation = null; 875 mFinishFrameTransformation.clear(); 876 } 877 if (mRotateFrameAnimation != null) { 878 if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, clearing rotate frame anim!"); 879 mRotateFrameAnimation.cancel(); 880 mRotateFrameAnimation = null; 881 mRotateFrameTransformation.clear(); 882 } 883 } 884 885 mExitTransformation.set(mRotateExitTransformation); 886 mEnterTransformation.set(mRotateEnterTransformation); 887 if (TWO_PHASE_ANIMATION) { 888 mExitTransformation.compose(mStartExitTransformation); 889 mExitTransformation.compose(mFinishExitTransformation); 890 891 mEnterTransformation.compose(mStartEnterTransformation); 892 mEnterTransformation.compose(mFinishEnterTransformation); 893 } 894 895 if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final exit: " + mExitTransformation); 896 if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final enter: " + mEnterTransformation); 897 898 if (USE_CUSTOM_BLACK_FRAME) { 899 //mFrameTransformation.set(mRotateExitTransformation); 900 //mFrameTransformation.compose(mStartExitTransformation); 901 //mFrameTransformation.compose(mFinishExitTransformation); 902 mFrameTransformation.set(mRotateFrameTransformation); 903 mFrameTransformation.compose(mStartFrameTransformation); 904 mFrameTransformation.compose(mFinishFrameTransformation); 905 mFrameTransformation.getMatrix().preConcat(mFrameInitialMatrix); 906 if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final frame: " + mFrameTransformation); 907 } 908 909 final boolean more = (TWO_PHASE_ANIMATION 910 && (mMoreStartEnter || mMoreStartExit || mMoreFinishEnter || mMoreFinishExit)) 911 || (USE_CUSTOM_BLACK_FRAME 912 && (mMoreStartFrame || mMoreRotateFrame || mMoreFinishFrame)) 913 || mMoreRotateEnter || mMoreRotateExit 914 || !mFinishAnimReady; 915 916 mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix); 917 918 if (DEBUG_STATE) Slog.v(TAG, "Step: more=" + more); 919 920 return more; 921 } 922 updateSurfacesInTransaction()923 void updateSurfacesInTransaction() { 924 if (!mStarted) { 925 return; 926 } 927 928 if (mSurfaceControl != null) { 929 if (!mMoreStartExit && !mMoreFinishExit && !mMoreRotateExit) { 930 if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, hiding screenshot surface"); 931 mSurfaceControl.hide(); 932 } 933 } 934 935 if (mCustomBlackFrame != null) { 936 if (!mMoreStartFrame && !mMoreFinishFrame && !mMoreRotateFrame) { 937 if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding black frame"); 938 mCustomBlackFrame.hide(); 939 } else { 940 mCustomBlackFrame.setMatrix(mFrameTransformation.getMatrix()); 941 } 942 } 943 944 if (mExitingBlackFrame != null) { 945 if (!mMoreStartExit && !mMoreFinishExit && !mMoreRotateExit) { 946 if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding exiting frame"); 947 mExitingBlackFrame.hide(); 948 } else { 949 mExitFrameFinalMatrix.setConcat(mExitTransformation.getMatrix(), mFrameInitialMatrix); 950 mExitingBlackFrame.setMatrix(mExitFrameFinalMatrix); 951 if (mForceDefaultOrientation) { 952 mExitingBlackFrame.setAlpha(mExitTransformation.getAlpha()); 953 } 954 } 955 } 956 957 if (mEnteringBlackFrame != null) { 958 if (!mMoreStartEnter && !mMoreFinishEnter && !mMoreRotateEnter) { 959 if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding entering frame"); 960 mEnteringBlackFrame.hide(); 961 } else { 962 mEnteringBlackFrame.setMatrix(mEnterTransformation.getMatrix()); 963 } 964 } 965 966 setSnapshotTransformInTransaction(mSnapshotFinalMatrix, mExitTransformation.getAlpha()); 967 } 968 stepAnimationLocked(long now)969 public boolean stepAnimationLocked(long now) { 970 if (!hasAnimations()) { 971 if (DEBUG_STATE) Slog.v(TAG, "Step: no animations running"); 972 mFinishAnimReady = false; 973 return false; 974 } 975 976 if (!mAnimRunning) { 977 if (DEBUG_STATE) Slog.v(TAG, "Step: starting start, finish, rotate"); 978 if (TWO_PHASE_ANIMATION) { 979 if (mStartEnterAnimation != null) { 980 mStartEnterAnimation.setStartTime(now); 981 } 982 if (mStartExitAnimation != null) { 983 mStartExitAnimation.setStartTime(now); 984 } 985 if (mFinishEnterAnimation != null) { 986 mFinishEnterAnimation.setStartTime(0); 987 } 988 if (mFinishExitAnimation != null) { 989 mFinishExitAnimation.setStartTime(0); 990 } 991 } 992 if (USE_CUSTOM_BLACK_FRAME) { 993 if (mStartFrameAnimation != null) { 994 mStartFrameAnimation.setStartTime(now); 995 } 996 if (mFinishFrameAnimation != null) { 997 mFinishFrameAnimation.setStartTime(0); 998 } 999 if (mRotateFrameAnimation != null) { 1000 mRotateFrameAnimation.setStartTime(now); 1001 } 1002 } 1003 if (mRotateEnterAnimation != null) { 1004 mRotateEnterAnimation.setStartTime(now); 1005 } 1006 if (mRotateExitAnimation != null) { 1007 mRotateExitAnimation.setStartTime(now); 1008 } 1009 mAnimRunning = true; 1010 mHalfwayPoint = now + mRotateEnterAnimation.getDuration() / 2; 1011 } 1012 1013 return stepAnimation(now); 1014 } 1015 getEnterTransformation()1016 public Transformation getEnterTransformation() { 1017 return mEnterTransformation; 1018 } 1019 } 1020