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