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