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