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