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