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