ScreenRotationAnimation.java revision 98365d7663cbd82979a5700faf0050220b01084d
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, 0, "FreezeSurface",
219                            mDisplay.getLayerStack(), mWidth, mHeight,
220                            PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT | Surface.HIDDEN);
221                } else {
222                    mSurface = new Surface(session, 0, "FreezeSurface",
223                            mDisplay.getLayerStack(), 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.setLayer(FREEZE_LAYER + 1);
232                mSurface.setAlpha(0);
233                mSurface.show();
234            } catch (Surface.OutOfResourcesException e) {
235                Slog.w(TAG, "Unable to allocate freeze surface", e);
236            }
237
238            if (WindowManagerService.SHOW_TRANSACTIONS ||
239                    WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
240                            "  FREEZE " + mSurface + ": CREATE");
241
242            setRotation(originalRotation);
243        } finally {
244            if (!inTransaction) {
245                Surface.closeTransaction();
246                if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
247                        "<<< CLOSE TRANSACTION ScreenRotationAnimation");
248            }
249        }
250    }
251
252    boolean hasScreenshot() {
253        return mSurface != null;
254    }
255
256    static int deltaRotation(int oldRotation, int newRotation) {
257        int delta = newRotation - oldRotation;
258        if (delta < 0) delta += 4;
259        return delta;
260    }
261
262    void setSnapshotTransform(Matrix matrix, float alpha) {
263        if (mSurface != null) {
264            matrix.getValues(mTmpFloats);
265            mSurface.setPosition(mTmpFloats[Matrix.MTRANS_X],
266                    mTmpFloats[Matrix.MTRANS_Y]);
267            mSurface.setMatrix(
268                    mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
269                    mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
270            mSurface.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 setRotation(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        setSnapshotTransform(mSnapshotInitialMatrix, 1.0f);
316    }
317
318    // Must be called while in a transaction.
319    public boolean setRotation(int rotation, SurfaceSession session,
320            long maxAnimationDuration, float animationScale, int finalWidth, int finalHeight) {
321        setRotation(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 (mSurface == 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        switch (delta) {
378            case Surface.ROTATION_0:
379                mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
380                        com.android.internal.R.anim.screen_rotate_0_exit);
381                mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
382                        com.android.internal.R.anim.screen_rotate_0_enter);
383                if (USE_CUSTOM_BLACK_FRAME) {
384                    mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext,
385                            com.android.internal.R.anim.screen_rotate_0_frame);
386                }
387                break;
388            case Surface.ROTATION_90:
389                mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
390                        com.android.internal.R.anim.screen_rotate_plus_90_exit);
391                mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
392                        com.android.internal.R.anim.screen_rotate_plus_90_enter);
393                if (USE_CUSTOM_BLACK_FRAME) {
394                    mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext,
395                            com.android.internal.R.anim.screen_rotate_plus_90_frame);
396                }
397                break;
398            case Surface.ROTATION_180:
399                mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
400                        com.android.internal.R.anim.screen_rotate_180_exit);
401                mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
402                        com.android.internal.R.anim.screen_rotate_180_enter);
403                mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext,
404                        com.android.internal.R.anim.screen_rotate_180_frame);
405                break;
406            case Surface.ROTATION_270:
407                mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
408                        com.android.internal.R.anim.screen_rotate_minus_90_exit);
409                mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
410                        com.android.internal.R.anim.screen_rotate_minus_90_enter);
411                if (USE_CUSTOM_BLACK_FRAME) {
412                    mRotateFrameAnimation = AnimationUtils.loadAnimation(mContext,
413                            com.android.internal.R.anim.screen_rotate_minus_90_frame);
414                }
415                break;
416        }
417
418        // Compute partial steps between original and final sizes.  These
419        // are used for the dimensions of the exiting and entering elements,
420        // so they are never stretched too significantly.
421        final int halfWidth = (finalWidth + mOriginalWidth) / 2;
422        final int halfHeight = (finalHeight + mOriginalHeight) / 2;
423
424        // Initialize the animations.  This is a hack, redefining what "parent"
425        // means to allow supplying the last and next size.  In this definition
426        // "%p" is the original (let's call it "previous") size, and "%" is the
427        // screen's current/new size.
428        if (TWO_PHASE_ANIMATION && firstStart) {
429            if (DEBUG_STATE) Slog.v(TAG, "Initializing start and finish animations");
430            mStartEnterAnimation.initialize(finalWidth, finalHeight,
431                    halfWidth, halfHeight);
432            mStartExitAnimation.initialize(halfWidth, halfHeight,
433                    mOriginalWidth, mOriginalHeight);
434            mFinishEnterAnimation.initialize(finalWidth, finalHeight,
435                    halfWidth, halfHeight);
436            mFinishExitAnimation.initialize(halfWidth, halfHeight,
437                    mOriginalWidth, mOriginalHeight);
438            if (USE_CUSTOM_BLACK_FRAME) {
439                mStartFrameAnimation.initialize(finalWidth, finalHeight,
440                        mOriginalWidth, mOriginalHeight);
441                mFinishFrameAnimation.initialize(finalWidth, finalHeight,
442                        mOriginalWidth, mOriginalHeight);
443            }
444        }
445        mRotateEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
446        mRotateExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
447        if (USE_CUSTOM_BLACK_FRAME) {
448            mRotateFrameAnimation.initialize(finalWidth, finalHeight, mOriginalWidth,
449                    mOriginalHeight);
450        }
451        mAnimRunning = false;
452        mFinishAnimReady = false;
453        mFinishAnimStartTime = -1;
454
455        if (TWO_PHASE_ANIMATION && firstStart) {
456            mStartExitAnimation.restrictDuration(maxAnimationDuration);
457            mStartExitAnimation.scaleCurrentDuration(animationScale);
458            mStartEnterAnimation.restrictDuration(maxAnimationDuration);
459            mStartEnterAnimation.scaleCurrentDuration(animationScale);
460            mFinishExitAnimation.restrictDuration(maxAnimationDuration);
461            mFinishExitAnimation.scaleCurrentDuration(animationScale);
462            mFinishEnterAnimation.restrictDuration(maxAnimationDuration);
463            mFinishEnterAnimation.scaleCurrentDuration(animationScale);
464            if (USE_CUSTOM_BLACK_FRAME) {
465                mStartFrameAnimation.restrictDuration(maxAnimationDuration);
466                mStartFrameAnimation.scaleCurrentDuration(animationScale);
467                mFinishFrameAnimation.restrictDuration(maxAnimationDuration);
468                mFinishFrameAnimation.scaleCurrentDuration(animationScale);
469            }
470        }
471        mRotateExitAnimation.restrictDuration(maxAnimationDuration);
472        mRotateExitAnimation.scaleCurrentDuration(animationScale);
473        mRotateEnterAnimation.restrictDuration(maxAnimationDuration);
474        mRotateEnterAnimation.scaleCurrentDuration(animationScale);
475        if (USE_CUSTOM_BLACK_FRAME) {
476            mRotateFrameAnimation.restrictDuration(maxAnimationDuration);
477            mRotateFrameAnimation.scaleCurrentDuration(animationScale);
478        }
479
480        if (USE_CUSTOM_BLACK_FRAME && mCustomBlackFrame == null) {
481            if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
482                    WindowManagerService.TAG,
483                    ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
484            Surface.openTransaction();
485
486            // Compute the transformation matrix that must be applied
487            // the the black frame to make it stay in the initial position
488            // before the new screen rotation.  This is different than the
489            // snapshot transformation because the snapshot is always based
490            // of the native orientation of the screen, not the orientation
491            // we were last in.
492            createRotationMatrix(delta, mOriginalWidth, mOriginalHeight, mFrameInitialMatrix);
493
494            try {
495                Rect outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1,
496                        mOriginalWidth*2, mOriginalHeight*2);
497                Rect inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
498                mCustomBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER + 3);
499                mCustomBlackFrame.setMatrix(mFrameInitialMatrix);
500            } catch (Surface.OutOfResourcesException e) {
501                Slog.w(TAG, "Unable to allocate black surface", e);
502            } finally {
503                Surface.closeTransaction();
504                if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
505                        WindowManagerService.TAG,
506                        "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
507            }
508        }
509
510        if (mExitingBlackFrame == null) {
511            if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
512                    WindowManagerService.TAG,
513                    ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
514            Surface.openTransaction();
515
516            // Compute the transformation matrix that must be applied
517            // the the black frame to make it stay in the initial position
518            // before the new screen rotation.  This is different than the
519            // snapshot transformation because the snapshot is always based
520            // of the native orientation of the screen, not the orientation
521            // we were last in.
522            createRotationMatrix(delta, mOriginalWidth, mOriginalHeight, mFrameInitialMatrix);
523
524            try {
525                Rect outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1,
526                        mOriginalWidth*2, mOriginalHeight*2);
527                Rect inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
528                mExitingBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER + 2);
529                mExitingBlackFrame.setMatrix(mFrameInitialMatrix);
530            } catch (Surface.OutOfResourcesException e) {
531                Slog.w(TAG, "Unable to allocate black surface", e);
532            } finally {
533                Surface.closeTransaction();
534                if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
535                        WindowManagerService.TAG,
536                        "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
537            }
538        }
539
540        if (false && mEnteringBlackFrame == null) {
541            if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
542                    WindowManagerService.TAG,
543                    ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
544            Surface.openTransaction();
545
546            try {
547                Rect outer = new Rect(-finalWidth*1, -finalHeight*1,
548                        finalWidth*2, finalHeight*2);
549                Rect inner = new Rect(0, 0, finalWidth, finalHeight);
550                mEnteringBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER);
551            } catch (Surface.OutOfResourcesException e) {
552                Slog.w(TAG, "Unable to allocate black surface", e);
553            } finally {
554                Surface.closeTransaction();
555                if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
556                        WindowManagerService.TAG,
557                        "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
558            }
559        }
560
561        return true;
562    }
563
564    /**
565     * Returns true if animating.
566     */
567    public boolean dismiss(SurfaceSession session, long maxAnimationDuration,
568            float animationScale, int finalWidth, int finalHeight) {
569        if (DEBUG_STATE) Slog.v(TAG, "Dismiss!");
570        if (mSurface == null) {
571            // Can't do animation.
572            return false;
573        }
574        if (!mStarted) {
575            startAnimation(session, maxAnimationDuration, animationScale, finalWidth, finalHeight,
576                    true);
577        }
578        if (!mStarted) {
579            return false;
580        }
581        if (DEBUG_STATE) Slog.v(TAG, "Setting mFinishAnimReady = true");
582        mFinishAnimReady = true;
583        return true;
584    }
585
586    public void kill() {
587        if (DEBUG_STATE) Slog.v(TAG, "Kill!");
588        if (mSurface != null) {
589            if (WindowManagerService.SHOW_TRANSACTIONS ||
590                    WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
591                            "  FREEZE " + mSurface + ": DESTROY");
592            mSurface.destroy();
593            mSurface = null;
594        }
595        if (mCustomBlackFrame != null) {
596            mCustomBlackFrame.kill();
597            mCustomBlackFrame = null;
598        }
599        if (mExitingBlackFrame != null) {
600            mExitingBlackFrame.kill();
601            mExitingBlackFrame = null;
602        }
603        if (mEnteringBlackFrame != null) {
604            mEnteringBlackFrame.kill();
605            mEnteringBlackFrame = null;
606        }
607        if (TWO_PHASE_ANIMATION) {
608            if (mStartExitAnimation != null) {
609                mStartExitAnimation.cancel();
610                mStartExitAnimation = null;
611            }
612            if (mStartEnterAnimation != null) {
613                mStartEnterAnimation.cancel();
614                mStartEnterAnimation = null;
615            }
616            if (mFinishExitAnimation != null) {
617                mFinishExitAnimation.cancel();
618                mFinishExitAnimation = null;
619            }
620            if (mFinishEnterAnimation != null) {
621                mFinishEnterAnimation.cancel();
622                mFinishEnterAnimation = null;
623            }
624        }
625        if (USE_CUSTOM_BLACK_FRAME) {
626            if (mStartFrameAnimation != null) {
627                mStartFrameAnimation.cancel();
628                mStartFrameAnimation = null;
629            }
630            if (mRotateFrameAnimation != null) {
631                mRotateFrameAnimation.cancel();
632                mRotateFrameAnimation = null;
633            }
634            if (mFinishFrameAnimation != null) {
635                mFinishFrameAnimation.cancel();
636                mFinishFrameAnimation = null;
637            }
638        }
639        if (mRotateExitAnimation != null) {
640            mRotateExitAnimation.cancel();
641            mRotateExitAnimation = null;
642        }
643        if (mRotateEnterAnimation != null) {
644            mRotateEnterAnimation.cancel();
645            mRotateEnterAnimation = null;
646        }
647    }
648
649    public boolean isAnimating() {
650        return hasAnimations() || (TWO_PHASE_ANIMATION && mFinishAnimReady);
651    }
652
653    private boolean hasAnimations() {
654        return (TWO_PHASE_ANIMATION &&
655                    (mStartEnterAnimation != null || mStartExitAnimation != null
656                    || mFinishEnterAnimation != null || mFinishExitAnimation != null))
657                || (USE_CUSTOM_BLACK_FRAME &&
658                        (mStartFrameAnimation != null || mRotateFrameAnimation != null
659                        || mFinishFrameAnimation != null))
660                || mRotateEnterAnimation != null || mRotateExitAnimation != null;
661    }
662
663    private boolean stepAnimation(long now) {
664        if (now > mHalfwayPoint) {
665            mHalfwayPoint = Long.MAX_VALUE;
666        }
667        if (mFinishAnimReady && mFinishAnimStartTime < 0) {
668            if (DEBUG_STATE) Slog.v(TAG, "Step: finish anim now ready");
669            mFinishAnimStartTime = now;
670        }
671
672        if (TWO_PHASE_ANIMATION) {
673            mMoreStartExit = false;
674            if (mStartExitAnimation != null) {
675                mMoreStartExit = mStartExitAnimation.getTransformation(now, mStartExitTransformation);
676                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start exit: " + mStartExitTransformation);
677            }
678
679            mMoreStartEnter = false;
680            if (mStartEnterAnimation != null) {
681                mMoreStartEnter = mStartEnterAnimation.getTransformation(now, mStartEnterTransformation);
682                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start enter: " + mStartEnterTransformation);
683            }
684        }
685        if (USE_CUSTOM_BLACK_FRAME) {
686            mMoreStartFrame = false;
687            if (mStartFrameAnimation != null) {
688                mMoreStartFrame = mStartFrameAnimation.getTransformation(now, mStartFrameTransformation);
689                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start frame: " + mStartFrameTransformation);
690            }
691        }
692
693        long finishNow = mFinishAnimReady ? (now - mFinishAnimStartTime) : 0;
694        if (DEBUG_STATE) Slog.v(TAG, "Step: finishNow=" + finishNow);
695
696        if (TWO_PHASE_ANIMATION) {
697            mMoreFinishExit = false;
698            if (mFinishExitAnimation != null) {
699                mMoreFinishExit = mFinishExitAnimation.getTransformation(finishNow, mFinishExitTransformation);
700                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish exit: " + mFinishExitTransformation);
701            }
702
703            mMoreFinishEnter = false;
704            if (mFinishEnterAnimation != null) {
705                mMoreFinishEnter = mFinishEnterAnimation.getTransformation(finishNow, mFinishEnterTransformation);
706                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish enter: " + mFinishEnterTransformation);
707            }
708        }
709        if (USE_CUSTOM_BLACK_FRAME) {
710            mMoreFinishFrame = false;
711            if (mFinishFrameAnimation != null) {
712                mMoreFinishFrame = mFinishFrameAnimation.getTransformation(finishNow, mFinishFrameTransformation);
713                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish frame: " + mFinishFrameTransformation);
714            }
715        }
716
717        mMoreRotateExit = false;
718        if (mRotateExitAnimation != null) {
719            mMoreRotateExit = mRotateExitAnimation.getTransformation(now, mRotateExitTransformation);
720            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate exit: " + mRotateExitTransformation);
721        }
722
723        mMoreRotateEnter = false;
724        if (mRotateEnterAnimation != null) {
725            mMoreRotateEnter = mRotateEnterAnimation.getTransformation(now, mRotateEnterTransformation);
726            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate enter: " + mRotateEnterTransformation);
727        }
728
729        if (USE_CUSTOM_BLACK_FRAME) {
730            mMoreRotateFrame = false;
731            if (mRotateFrameAnimation != null) {
732                mMoreRotateFrame = mRotateFrameAnimation.getTransformation(now, mRotateFrameTransformation);
733                if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate frame: " + mRotateFrameTransformation);
734            }
735        }
736
737        if (!mMoreRotateExit && (!TWO_PHASE_ANIMATION || (!mMoreStartExit && !mMoreFinishExit))) {
738            if (TWO_PHASE_ANIMATION) {
739                if (mStartExitAnimation != null) {
740                    if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing start exit anim!");
741                    mStartExitAnimation.cancel();
742                    mStartExitAnimation = null;
743                    mStartExitTransformation.clear();
744                }
745                if (mFinishExitAnimation != null) {
746                    if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing finish exit anim!");
747                    mFinishExitAnimation.cancel();
748                    mFinishExitAnimation = null;
749                    mFinishExitTransformation.clear();
750                }
751            }
752            if (mRotateExitAnimation != null) {
753                if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, clearing rotate exit anim!");
754                mRotateExitAnimation.cancel();
755                mRotateExitAnimation = null;
756                mRotateExitTransformation.clear();
757            }
758        }
759
760        if (!mMoreRotateEnter && (!TWO_PHASE_ANIMATION || (!mMoreStartEnter && !mMoreFinishEnter))) {
761            if (TWO_PHASE_ANIMATION) {
762                if (mStartEnterAnimation != null) {
763                    if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing start enter anim!");
764                    mStartEnterAnimation.cancel();
765                    mStartEnterAnimation = null;
766                    mStartEnterTransformation.clear();
767                }
768                if (mFinishEnterAnimation != null) {
769                    if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing finish enter anim!");
770                    mFinishEnterAnimation.cancel();
771                    mFinishEnterAnimation = null;
772                    mFinishEnterTransformation.clear();
773                }
774            }
775            if (mRotateEnterAnimation != null) {
776                if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, clearing rotate enter anim!");
777                mRotateEnterAnimation.cancel();
778                mRotateEnterAnimation = null;
779                mRotateEnterTransformation.clear();
780            }
781        }
782
783        if (USE_CUSTOM_BLACK_FRAME && !mMoreStartFrame && !mMoreRotateFrame && !mMoreFinishFrame) {
784            if (mStartFrameAnimation != null) {
785                if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, clearing start frame anim!");
786                mStartFrameAnimation.cancel();
787                mStartFrameAnimation = null;
788                mStartFrameTransformation.clear();
789            }
790            if (mFinishFrameAnimation != null) {
791                if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, clearing finish frame anim!");
792                mFinishFrameAnimation.cancel();
793                mFinishFrameAnimation = null;
794                mFinishFrameTransformation.clear();
795            }
796            if (mRotateFrameAnimation != null) {
797                if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, clearing rotate frame anim!");
798                mRotateFrameAnimation.cancel();
799                mRotateFrameAnimation = null;
800                mRotateFrameTransformation.clear();
801            }
802        }
803
804        mExitTransformation.set(mRotateExitTransformation);
805        mEnterTransformation.set(mRotateEnterTransformation);
806        if (TWO_PHASE_ANIMATION) {
807            mExitTransformation.compose(mStartExitTransformation);
808            mExitTransformation.compose(mFinishExitTransformation);
809
810            mEnterTransformation.compose(mStartEnterTransformation);
811            mEnterTransformation.compose(mFinishEnterTransformation);
812        }
813
814        if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final exit: " + mExitTransformation);
815        if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final enter: " + mEnterTransformation);
816
817        if (USE_CUSTOM_BLACK_FRAME) {
818            //mFrameTransformation.set(mRotateExitTransformation);
819            //mFrameTransformation.compose(mStartExitTransformation);
820            //mFrameTransformation.compose(mFinishExitTransformation);
821            mFrameTransformation.set(mRotateFrameTransformation);
822            mFrameTransformation.compose(mStartFrameTransformation);
823            mFrameTransformation.compose(mFinishFrameTransformation);
824            mFrameTransformation.getMatrix().preConcat(mFrameInitialMatrix);
825            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final frame: " + mFrameTransformation);
826        }
827
828        final boolean more = (TWO_PHASE_ANIMATION
829                    && (mMoreStartEnter || mMoreStartExit || mMoreFinishEnter || mMoreFinishExit))
830                || (USE_CUSTOM_BLACK_FRAME
831                        && (mMoreStartFrame || mMoreRotateFrame || mMoreFinishFrame))
832                || mMoreRotateEnter || mMoreRotateExit
833                || !mFinishAnimReady;
834
835        mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix);
836
837        if (DEBUG_STATE) Slog.v(TAG, "Step: more=" + more);
838
839        return more;
840    }
841
842    void updateSurfaces() {
843        if (!mStarted) {
844            return;
845        }
846
847        if (mSurface != null) {
848            if (!mMoreStartExit && !mMoreFinishExit && !mMoreRotateExit) {
849                if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, hiding screenshot surface");
850                mSurface.hide();
851            }
852        }
853
854        if (mCustomBlackFrame != null) {
855            if (!mMoreStartFrame && !mMoreFinishFrame && !mMoreRotateFrame) {
856                if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding black frame");
857                mCustomBlackFrame.hide();
858            } else {
859                mCustomBlackFrame.setMatrix(mFrameTransformation.getMatrix());
860            }
861        }
862
863        if (mExitingBlackFrame != null) {
864            if (!mMoreStartExit && !mMoreFinishExit && !mMoreRotateExit) {
865                if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding exiting frame");
866                mExitingBlackFrame.hide();
867            } else {
868                mExitFrameFinalMatrix.setConcat(mExitTransformation.getMatrix(), mFrameInitialMatrix);
869                mExitingBlackFrame.setMatrix(mExitFrameFinalMatrix);
870            }
871        }
872
873        if (mEnteringBlackFrame != null) {
874            if (!mMoreStartEnter && !mMoreFinishEnter && !mMoreRotateEnter) {
875                if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding entering frame");
876                mEnteringBlackFrame.hide();
877            } else {
878                mEnteringBlackFrame.setMatrix(mEnterTransformation.getMatrix());
879            }
880        }
881
882        setSnapshotTransform(mSnapshotFinalMatrix, mExitTransformation.getAlpha());
883    }
884
885    public boolean stepAnimationLocked(long now) {
886        if (!hasAnimations()) {
887            if (DEBUG_STATE) Slog.v(TAG, "Step: no animations running");
888            mFinishAnimReady = false;
889            return false;
890        }
891
892        if (!mAnimRunning) {
893            if (DEBUG_STATE) Slog.v(TAG, "Step: starting start, finish, rotate");
894            if (TWO_PHASE_ANIMATION) {
895                if (mStartEnterAnimation != null) {
896                    mStartEnterAnimation.setStartTime(now);
897                }
898                if (mStartExitAnimation != null) {
899                    mStartExitAnimation.setStartTime(now);
900                }
901                if (mFinishEnterAnimation != null) {
902                    mFinishEnterAnimation.setStartTime(0);
903                }
904                if (mFinishExitAnimation != null) {
905                    mFinishExitAnimation.setStartTime(0);
906                }
907            }
908            if (USE_CUSTOM_BLACK_FRAME) {
909                if (mStartFrameAnimation != null) {
910                    mStartFrameAnimation.setStartTime(now);
911                }
912                if (mFinishFrameAnimation != null) {
913                    mFinishFrameAnimation.setStartTime(0);
914                }
915                if (mRotateFrameAnimation != null) {
916                    mRotateFrameAnimation.setStartTime(now);
917                }
918            }
919            if (mRotateEnterAnimation != null) {
920                mRotateEnterAnimation.setStartTime(now);
921            }
922            if (mRotateExitAnimation != null) {
923                mRotateExitAnimation.setStartTime(now);
924            }
925            mAnimRunning = true;
926            mHalfwayPoint = now + mRotateEnterAnimation.getDuration() / 2;
927        }
928
929        return stepAnimation(now);
930    }
931
932    public Transformation getEnterTransformation() {
933        return mEnterTransformation;
934    }
935}
936