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