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