ScreenRotationAnimation.java revision fd1c5ed3705b885ce50b5ecad04ce699248b1d84
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 17package com.android.server.wm; 18 19import android.content.Context; 20import android.graphics.Matrix; 21import android.graphics.PixelFormat; 22import android.graphics.Rect; 23import android.util.Slog; 24import android.view.Surface; 25import android.view.SurfaceSession; 26import android.view.animation.Animation; 27import android.view.animation.AnimationUtils; 28import android.view.animation.Transformation; 29 30class ScreenRotationAnimation { 31 static final String TAG = "ScreenRotationAnimation"; 32 static final boolean DEBUG_STATE = false; 33 static final boolean DEBUG_TRANSFORMS = false; 34 35 static final int FREEZE_LAYER = WindowManagerService.TYPE_LAYER_MULTIPLIER * 200; 36 37 final Context mContext; 38 Surface mSurface; 39 BlackFrame mBlackFrame; 40 int mWidth, mHeight; 41 42 int mSnapshotRotation; 43 int mSnapshotDeltaRotation; 44 int mOriginalRotation; 45 int mOriginalWidth, mOriginalHeight; 46 int mCurRotation; 47 48 // For all animations, "exit" is for the UI elements that are going 49 // away (that is the snapshot of the old screen), and "enter" is for 50 // the new UI elements that are appearing (that is the active windows 51 // in their final orientation). 52 53 // The starting animation for the exiting and entering elements. This 54 // animation applies a transformation while the rotation is in progress. 55 // It is started immediately, before the new entering UI is ready. 56 Animation mStartExitAnimation; 57 final Transformation mStartExitTransformation = new Transformation(); 58 Animation mStartEnterAnimation; 59 final Transformation mStartEnterTransformation = new Transformation(); 60 61 // The finishing animation for the exiting and entering elements. This 62 // animation needs to undo the transformation of the starting animation. 63 // It starts running once the new rotation UI elements are ready to be 64 // displayed. 65 Animation mFinishExitAnimation; 66 final Transformation mFinishExitTransformation = new Transformation(); 67 Animation mFinishEnterAnimation; 68 final Transformation mFinishEnterTransformation = new Transformation(); 69 70 // The current active animation to move from the old to the new rotated 71 // state. Which animation is run here will depend on the old and new 72 // rotations. 73 Animation mRotateExitAnimation; 74 final Transformation mRotateExitTransformation = new Transformation(); 75 Animation mRotateEnterAnimation; 76 final Transformation mRotateEnterTransformation = new Transformation(); 77 78 // A previously running rotate animation. This will be used if we need 79 // to switch to a new rotation before finishing the previous one. 80 Animation mLastRotateExitAnimation; 81 final Transformation mLastRotateExitTransformation = new Transformation(); 82 Animation mLastRotateEnterAnimation; 83 final Transformation mLastRotateEnterTransformation = new Transformation(); 84 85 // Complete transformations being applied. 86 final Transformation mExitTransformation = new Transformation(); 87 final Transformation mEnterTransformation = new Transformation(); 88 89 boolean mStarted; 90 boolean mAnimRunning; 91 boolean mFinishAnimReady; 92 long mFinishAnimStartTime; 93 94 final Matrix mSnapshotInitialMatrix = new Matrix(); 95 final Matrix mSnapshotFinalMatrix = new Matrix(); 96 final Matrix mTmpMatrix = new Matrix(); 97 final float[] mTmpFloats = new float[9]; 98 99 public ScreenRotationAnimation(Context context, SurfaceSession session, 100 boolean inTransaction, int originalWidth, int originalHeight, int originalRotation) { 101 mContext = context; 102 103 // Screenshot does NOT include rotation! 104 mSnapshotRotation = 0; 105 if (originalRotation == Surface.ROTATION_90 106 || originalRotation == Surface.ROTATION_270) { 107 mWidth = originalHeight; 108 mHeight = originalWidth; 109 } else { 110 mWidth = originalWidth; 111 mHeight = originalHeight; 112 } 113 114 mOriginalRotation = originalRotation; 115 mOriginalWidth = originalWidth; 116 mOriginalHeight = originalHeight; 117 118 if (!inTransaction) { 119 if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i(WindowManagerService.TAG, 120 ">>> OPEN TRANSACTION ScreenRotationAnimation"); 121 Surface.openTransaction(); 122 } 123 124 try { 125 try { 126 mSurface = new Surface(session, 0, "FreezeSurface", 127 -1, mWidth, mHeight, PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT | Surface.HIDDEN); 128 if (mSurface == null || !mSurface.isValid()) { 129 // Screenshot failed, punt. 130 mSurface = null; 131 return; 132 } 133 mSurface.setLayer(FREEZE_LAYER + 1); 134 mSurface.show(); 135 } catch (Surface.OutOfResourcesException e) { 136 Slog.w(TAG, "Unable to allocate freeze surface", e); 137 } 138 139 if (WindowManagerService.SHOW_TRANSACTIONS || 140 WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG, 141 " FREEZE " + mSurface + ": CREATE"); 142 143 setRotation(originalRotation); 144 } finally { 145 if (!inTransaction) { 146 Surface.closeTransaction(); 147 if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i(WindowManagerService.TAG, 148 "<<< CLOSE TRANSACTION ScreenRotationAnimation"); 149 } 150 } 151 } 152 153 boolean hasScreenshot() { 154 return mSurface != null; 155 } 156 157 static int deltaRotation(int oldRotation, int newRotation) { 158 int delta = newRotation - oldRotation; 159 if (delta < 0) delta += 4; 160 return delta; 161 } 162 163 void setSnapshotTransform(Matrix matrix, float alpha) { 164 if (mSurface != null) { 165 matrix.getValues(mTmpFloats); 166 mSurface.setPosition(mTmpFloats[Matrix.MTRANS_X], 167 mTmpFloats[Matrix.MTRANS_Y]); 168 mSurface.setMatrix( 169 mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y], 170 mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]); 171 mSurface.setAlpha(alpha); 172 if (DEBUG_TRANSFORMS) { 173 float[] srcPnts = new float[] { 0, 0, mWidth, mHeight }; 174 float[] dstPnts = new float[4]; 175 matrix.mapPoints(dstPnts, srcPnts); 176 Slog.i(TAG, "Original : (" + srcPnts[0] + "," + srcPnts[1] 177 + ")-(" + srcPnts[2] + "," + srcPnts[3] + ")"); 178 Slog.i(TAG, "Transformed: (" + dstPnts[0] + "," + dstPnts[1] 179 + ")-(" + dstPnts[2] + "," + dstPnts[3] + ")"); 180 } 181 } 182 } 183 184 public static void createRotationMatrix(int rotation, int width, int height, 185 Matrix outMatrix) { 186 switch (rotation) { 187 case Surface.ROTATION_0: 188 outMatrix.reset(); 189 break; 190 case Surface.ROTATION_90: 191 outMatrix.setRotate(90, 0, 0); 192 outMatrix.postTranslate(height, 0); 193 break; 194 case Surface.ROTATION_180: 195 outMatrix.setRotate(180, 0, 0); 196 outMatrix.postTranslate(width, height); 197 break; 198 case Surface.ROTATION_270: 199 outMatrix.setRotate(270, 0, 0); 200 outMatrix.postTranslate(0, width); 201 break; 202 } 203 } 204 205 // Must be called while in a transaction. 206 private void setRotation(int rotation) { 207 mCurRotation = rotation; 208 209 // Compute the transformation matrix that must be applied 210 // to the snapshot to make it stay in the same original position 211 // with the current screen rotation. 212 int delta = deltaRotation(rotation, mSnapshotRotation); 213 createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix); 214 215 if (DEBUG_STATE) Slog.v(TAG, "**** ROTATION: " + delta); 216 setSnapshotTransform(mSnapshotInitialMatrix, 1.0f); 217 } 218 219 // Must be called while in a transaction. 220 public boolean setRotation(int rotation, SurfaceSession session, 221 long maxAnimationDuration, float animationScale, int finalWidth, int finalHeight) { 222 setRotation(rotation); 223 return startAnimation(session, maxAnimationDuration, animationScale, 224 finalWidth, finalHeight, false); 225 } 226 227 /** 228 * Returns true if animating. 229 */ 230 private boolean startAnimation(SurfaceSession session, long maxAnimationDuration, 231 float animationScale, int finalWidth, int finalHeight, boolean dismissing) { 232 if (mSurface == null) { 233 // Can't do animation. 234 return false; 235 } 236 if (mStarted) { 237 return true; 238 } 239 240 mStarted = true; 241 242 boolean firstStart = false; 243 244 // Figure out how the screen has moved from the original rotation. 245 int delta = deltaRotation(mCurRotation, mOriginalRotation); 246 247 if (mFinishExitAnimation == null && (!dismissing || delta != Surface.ROTATION_0)) { 248 if (DEBUG_STATE) Slog.v(TAG, "Creating start and finish animations"); 249 firstStart = true; 250 mStartExitAnimation = AnimationUtils.loadAnimation(mContext, 251 com.android.internal.R.anim.screen_rotate_start_exit); 252 mStartEnterAnimation = AnimationUtils.loadAnimation(mContext, 253 com.android.internal.R.anim.screen_rotate_start_enter); 254 mFinishExitAnimation = AnimationUtils.loadAnimation(mContext, 255 com.android.internal.R.anim.screen_rotate_finish_exit); 256 mFinishEnterAnimation = AnimationUtils.loadAnimation(mContext, 257 com.android.internal.R.anim.screen_rotate_finish_enter); 258 } 259 260 if (DEBUG_STATE) Slog.v(TAG, "Rotation delta: " + delta + " finalWidth=" 261 + finalWidth + " finalHeight=" + finalHeight 262 + " origWidth=" + mOriginalWidth + " origHeight=" + mOriginalHeight); 263 264 switch (delta) { 265 case Surface.ROTATION_0: 266 mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, 267 com.android.internal.R.anim.screen_rotate_0_exit); 268 mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, 269 com.android.internal.R.anim.screen_rotate_0_enter); 270 break; 271 case Surface.ROTATION_90: 272 mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, 273 com.android.internal.R.anim.screen_rotate_plus_90_exit); 274 mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, 275 com.android.internal.R.anim.screen_rotate_plus_90_enter); 276 break; 277 case Surface.ROTATION_180: 278 mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, 279 com.android.internal.R.anim.screen_rotate_180_exit); 280 mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, 281 com.android.internal.R.anim.screen_rotate_180_enter); 282 break; 283 case Surface.ROTATION_270: 284 mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, 285 com.android.internal.R.anim.screen_rotate_minus_90_exit); 286 mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, 287 com.android.internal.R.anim.screen_rotate_minus_90_enter); 288 break; 289 } 290 291 // Initialize the animations. This is a hack, redefining what "parent" 292 // means to allow supplying the last and next size. In this definition 293 // "%p" is the original (let's call it "previous") size, and "%" is the 294 // screen's current/new size. 295 if (firstStart) { 296 if (DEBUG_STATE) Slog.v(TAG, "Initializing start and finish animations"); 297 mStartEnterAnimation.initialize(finalWidth, finalHeight, 298 mOriginalWidth, mOriginalHeight); 299 mStartExitAnimation.initialize(finalWidth, finalHeight, 300 mOriginalWidth, mOriginalHeight); 301 mFinishEnterAnimation.initialize(finalWidth, finalHeight, 302 mOriginalWidth, mOriginalHeight); 303 mFinishExitAnimation.initialize(finalWidth, finalHeight, 304 mOriginalWidth, mOriginalHeight); 305 } 306 mRotateEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight); 307 mRotateExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight); 308 mAnimRunning = false; 309 mFinishAnimReady = false; 310 mFinishAnimStartTime = -1; 311 312 if (firstStart) { 313 mStartExitAnimation.restrictDuration(maxAnimationDuration); 314 mStartExitAnimation.scaleCurrentDuration(animationScale); 315 mStartEnterAnimation.restrictDuration(maxAnimationDuration); 316 mStartEnterAnimation.scaleCurrentDuration(animationScale); 317 mFinishExitAnimation.restrictDuration(maxAnimationDuration); 318 mFinishExitAnimation.scaleCurrentDuration(animationScale); 319 mFinishEnterAnimation.restrictDuration(maxAnimationDuration); 320 mFinishEnterAnimation.scaleCurrentDuration(animationScale); 321 } 322 mRotateExitAnimation.restrictDuration(maxAnimationDuration); 323 mRotateExitAnimation.scaleCurrentDuration(animationScale); 324 mRotateEnterAnimation.restrictDuration(maxAnimationDuration); 325 mRotateEnterAnimation.scaleCurrentDuration(animationScale); 326 327 if (mBlackFrame == null) { 328 if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i( 329 WindowManagerService.TAG, 330 ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation"); 331 Surface.openTransaction(); 332 333 try { 334 Rect outer = new Rect(-finalWidth*1, -finalHeight*1, finalWidth*2, finalHeight*2); 335 Rect inner = new Rect(0, 0, finalWidth, finalHeight); 336 mBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER); 337 } catch (Surface.OutOfResourcesException e) { 338 Slog.w(TAG, "Unable to allocate black surface", e); 339 } finally { 340 Surface.closeTransaction(); 341 if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i( 342 WindowManagerService.TAG, 343 "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation"); 344 } 345 } 346 347 return true; 348 } 349 350 /** 351 * Returns true if animating. 352 */ 353 public boolean dismiss(SurfaceSession session, long maxAnimationDuration, 354 float animationScale, int finalWidth, int finalHeight) { 355 if (DEBUG_STATE) Slog.v(TAG, "Dismiss!"); 356 if (mSurface == null) { 357 // Can't do animation. 358 return false; 359 } 360 if (!mStarted) { 361 startAnimation(session, maxAnimationDuration, animationScale, finalWidth, finalHeight, 362 true); 363 } 364 if (!mStarted) { 365 return false; 366 } 367 if (DEBUG_STATE) Slog.v(TAG, "Setting mFinishAnimReady = true"); 368 mFinishAnimReady = true; 369 return true; 370 } 371 372 public void kill() { 373 if (DEBUG_STATE) Slog.v(TAG, "Kill!"); 374 if (mSurface != null) { 375 if (WindowManagerService.SHOW_TRANSACTIONS || 376 WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG, 377 " FREEZE " + mSurface + ": DESTROY"); 378 mSurface.destroy(); 379 mSurface = null; 380 } 381 if (mBlackFrame != null) { 382 mBlackFrame.kill(); 383 mBlackFrame = null; 384 } 385 if (mStartExitAnimation != null) { 386 mStartExitAnimation.cancel(); 387 mStartExitAnimation = null; 388 } 389 if (mStartEnterAnimation != null) { 390 mStartEnterAnimation.cancel(); 391 mStartEnterAnimation = null; 392 } 393 if (mFinishExitAnimation != null) { 394 mFinishExitAnimation.cancel(); 395 mFinishExitAnimation = null; 396 } 397 if (mStartEnterAnimation != null) { 398 mStartEnterAnimation.cancel(); 399 mStartEnterAnimation = null; 400 } 401 if (mRotateExitAnimation != null) { 402 mRotateExitAnimation.cancel(); 403 mRotateExitAnimation = null; 404 } 405 if (mRotateEnterAnimation != null) { 406 mRotateEnterAnimation.cancel(); 407 mRotateEnterAnimation = null; 408 } 409 } 410 411 public boolean isAnimating() { 412 return mStartEnterAnimation != null || mStartExitAnimation != null 413 && mFinishEnterAnimation != null || mFinishExitAnimation != null 414 && mRotateEnterAnimation != null || mRotateExitAnimation != null; 415 } 416 417 public boolean stepAnimation(long now) { 418 if (!isAnimating()) { 419 if (DEBUG_STATE) Slog.v(TAG, "Step: no animations running"); 420 return false; 421 } 422 423 if (!mAnimRunning) { 424 if (DEBUG_STATE) Slog.v(TAG, "Step: starting start, finish, rotate"); 425 if (mStartEnterAnimation != null) { 426 mStartEnterAnimation.setStartTime(now); 427 } 428 if (mStartExitAnimation != null) { 429 mStartExitAnimation.setStartTime(now); 430 } 431 if (mFinishEnterAnimation != null) { 432 mFinishEnterAnimation.setStartTime(0); 433 } 434 if (mFinishExitAnimation != null) { 435 mFinishExitAnimation.setStartTime(0); 436 } 437 if (mRotateEnterAnimation != null) { 438 mRotateEnterAnimation.setStartTime(now); 439 } 440 if (mRotateExitAnimation != null) { 441 mRotateExitAnimation.setStartTime(now); 442 } 443 mAnimRunning = true; 444 } 445 446 if (mFinishAnimReady && mFinishAnimStartTime < 0) { 447 if (DEBUG_STATE) Slog.v(TAG, "Step: finish anim now ready"); 448 mFinishAnimStartTime = now; 449 } 450 451 // If the start animation is no longer running, we want to keep its 452 // transformation intact until the finish animation also completes. 453 454 boolean moreStartExit = false; 455 if (mStartExitAnimation != null) { 456 mStartExitTransformation.clear(); 457 moreStartExit = mStartExitAnimation.getTransformation(now, mStartExitTransformation); 458 if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start exit: " + mStartExitTransformation); 459 if (!moreStartExit) { 460 if (DEBUG_STATE) Slog.v(TAG, "Start exit animation done!"); 461 mStartExitAnimation.cancel(); 462 mStartExitAnimation = null; 463 } 464 } 465 466 boolean moreStartEnter = false; 467 if (mStartEnterAnimation != null) { 468 mStartEnterTransformation.clear(); 469 moreStartEnter = mStartEnterAnimation.getTransformation(now, mStartEnterTransformation); 470 if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start enter: " + mStartEnterTransformation); 471 if (!moreStartEnter) { 472 if (DEBUG_STATE) Slog.v(TAG, "Start enter animation done!"); 473 mStartEnterAnimation.cancel(); 474 mStartEnterAnimation = null; 475 } 476 } 477 478 long finishNow = mFinishAnimReady ? (now - mFinishAnimStartTime) : 0; 479 if (DEBUG_STATE) Slog.v(TAG, "Step: finishNow=" + finishNow); 480 481 mFinishExitTransformation.clear(); 482 boolean moreFinishExit = false; 483 if (mFinishExitAnimation != null) { 484 moreFinishExit = mFinishExitAnimation.getTransformation(finishNow, mFinishExitTransformation); 485 if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish exit: " + mFinishExitTransformation); 486 if (!moreStartExit && !moreFinishExit) { 487 if (DEBUG_STATE) Slog.v(TAG, "Finish exit animation done, clearing start/finish anims!"); 488 mStartExitTransformation.clear(); 489 mFinishExitAnimation.cancel(); 490 mFinishExitAnimation = null; 491 mFinishExitTransformation.clear(); 492 } 493 } 494 495 mFinishEnterTransformation.clear(); 496 boolean moreFinishEnter = false; 497 if (mFinishEnterAnimation != null) { 498 moreFinishEnter = mFinishEnterAnimation.getTransformation(finishNow, mFinishEnterTransformation); 499 if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish enter: " + mFinishEnterTransformation); 500 if (!moreStartEnter && !moreFinishEnter) { 501 if (DEBUG_STATE) Slog.v(TAG, "Finish enter animation done, clearing start/finish anims!"); 502 mStartEnterTransformation.clear(); 503 mFinishEnterAnimation.cancel(); 504 mFinishEnterAnimation = null; 505 mFinishEnterTransformation.clear(); 506 } 507 } 508 509 mRotateExitTransformation.clear(); 510 boolean moreRotateExit = false; 511 if (mRotateExitAnimation != null) { 512 moreRotateExit = mRotateExitAnimation.getTransformation(now, mRotateExitTransformation); 513 if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate exit: " + mRotateExitTransformation); 514 } 515 516 if (!moreFinishExit && !moreRotateExit) { 517 if (DEBUG_STATE) Slog.v(TAG, "Rotate exit animation done!"); 518 mRotateExitAnimation.cancel(); 519 mRotateExitAnimation = null; 520 mRotateExitTransformation.clear(); 521 } 522 523 mRotateEnterTransformation.clear(); 524 boolean moreRotateEnter = false; 525 if (mRotateEnterAnimation != null) { 526 moreRotateEnter = mRotateEnterAnimation.getTransformation(now, mRotateEnterTransformation); 527 if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate enter: " + mRotateEnterTransformation); 528 } 529 530 if (!moreFinishEnter && !moreRotateEnter) { 531 if (DEBUG_STATE) Slog.v(TAG, "Rotate enter animation done!"); 532 mRotateEnterAnimation.cancel(); 533 mRotateEnterAnimation = null; 534 mRotateEnterTransformation.clear(); 535 } 536 537 mExitTransformation.set(mRotateExitTransformation); 538 mExitTransformation.compose(mStartExitTransformation); 539 mExitTransformation.compose(mFinishExitTransformation); 540 541 mEnterTransformation.set(mRotateEnterTransformation); 542 mEnterTransformation.compose(mStartEnterTransformation); 543 mEnterTransformation.compose(mFinishEnterTransformation); 544 545 if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final exit: " + mExitTransformation); 546 if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final enter: " + mEnterTransformation); 547 548 if (!moreStartExit && !moreFinishExit && !moreRotateExit) { 549 if (mSurface != null) { 550 if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, hiding screenshot surface"); 551 mSurface.hide(); 552 } 553 } 554 555 if (!moreStartEnter && !moreFinishEnter && !moreRotateEnter) { 556 if (mBlackFrame != null) { 557 if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, hiding black frame"); 558 mBlackFrame.hide(); 559 } 560 } else { 561 if (mBlackFrame != null) { 562 mBlackFrame.setMatrix(mEnterTransformation.getMatrix()); 563 } 564 } 565 566 mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix); 567 setSnapshotTransform(mSnapshotFinalMatrix, mExitTransformation.getAlpha()); 568 569 final boolean more = moreStartEnter || moreStartExit || moreFinishEnter || moreFinishExit 570 || moreRotateEnter || moreRotateExit || !mFinishAnimReady; 571 572 if (DEBUG_STATE) Slog.v(TAG, "Step: more=" + more); 573 574 return more; 575 } 576 577 public Transformation getEnterTransformation() { 578 return mEnterTransformation; 579 } 580} 581