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