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