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