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