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