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