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