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