ScreenRotationAnimation.java revision dbb7991b4e4638b284814b50e79cacc1e1c9d8cd
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 implements WindowManagerService.StepAnimator {
33    static final String TAG = "ScreenRotationAnimation";
34    static final boolean DEBUG_STATE = false;
35    static final boolean DEBUG_TRANSFORMS = false;
36
37    static final int FREEZE_LAYER = WindowManagerService.TYPE_LAYER_MULTIPLIER * 200;
38
39    final Context mContext;
40    Surface mSurface;
41    BlackFrame mBlackFrame;
42    int mWidth, mHeight;
43
44    int mSnapshotRotation;
45    int mSnapshotDeltaRotation;
46    int mOriginalRotation;
47    int mOriginalWidth, mOriginalHeight;
48    int mCurRotation;
49
50    // For all animations, "exit" is for the UI elements that are going
51    // away (that is the snapshot of the old screen), and "enter" is for
52    // the new UI elements that are appearing (that is the active windows
53    // in their final orientation).
54
55    // The starting animation for the exiting and entering elements.  This
56    // animation applies a transformation while the rotation is in progress.
57    // It is started immediately, before the new entering UI is ready.
58    Animation mStartExitAnimation;
59    final Transformation mStartExitTransformation = new Transformation();
60    Animation mStartEnterAnimation;
61    final Transformation mStartEnterTransformation = new Transformation();
62
63    // The finishing animation for the exiting and entering elements.  This
64    // animation needs to undo the transformation of the starting animation.
65    // It starts running once the new rotation UI elements are ready to be
66    // displayed.
67    Animation mFinishExitAnimation;
68    final Transformation mFinishExitTransformation = new Transformation();
69    Animation mFinishEnterAnimation;
70    final Transformation mFinishEnterTransformation = new Transformation();
71
72    // The current active animation to move from the old to the new rotated
73    // state.  Which animation is run here will depend on the old and new
74    // rotations.
75    Animation mRotateExitAnimation;
76    final Transformation mRotateExitTransformation = new Transformation();
77    Animation mRotateEnterAnimation;
78    final Transformation mRotateEnterTransformation = new Transformation();
79
80    // A previously running rotate animation.  This will be used if we need
81    // to switch to a new rotation before finishing the previous one.
82    Animation mLastRotateExitAnimation;
83    final Transformation mLastRotateExitTransformation = new Transformation();
84    Animation mLastRotateEnterAnimation;
85    final Transformation mLastRotateEnterTransformation = new Transformation();
86
87    // Complete transformations being applied.
88    final Transformation mExitTransformation = new Transformation();
89    final Transformation mEnterTransformation = new Transformation();
90
91    boolean mStarted;
92    boolean mAnimRunning;
93    boolean mFinishAnimReady;
94    long mFinishAnimStartTime;
95
96    final Matrix mSnapshotInitialMatrix = new Matrix();
97    final Matrix mSnapshotFinalMatrix = new Matrix();
98    final Matrix mTmpMatrix = new Matrix();
99    final float[] mTmpFloats = new float[9];
100    private boolean mMoreRotateEnter;
101    private boolean mMoreRotateExit;
102    private boolean mMoreFinishEnter;
103    private boolean mMoreFinishExit;
104    private boolean mMoreStartEnter;
105    private boolean mMoreStartExit;
106
107    public void printTo(String prefix, PrintWriter pw) {
108        pw.print(prefix); pw.print("mSurface="); pw.print(mSurface);
109                pw.print(" mWidth="); pw.print(mWidth);
110                pw.print(" mHeight="); pw.println(mHeight);
111        pw.print(prefix); pw.print("mBlackFrame="); pw.println(mBlackFrame);
112        pw.print(prefix); pw.print("mSnapshotRotation="); pw.print(mSnapshotRotation);
113                pw.print(" mSnapshotDeltaRotation="); pw.print(mSnapshotDeltaRotation);
114                pw.print(" mCurRotation="); pw.println(mCurRotation);
115        pw.print(prefix); pw.print("mOriginalRotation="); pw.print(mOriginalRotation);
116                pw.print(" mOriginalWidth="); pw.print(mOriginalWidth);
117                pw.print(" mOriginalHeight="); pw.println(mOriginalHeight);
118        pw.print(prefix); pw.print("mStarted="); pw.print(mStarted);
119                pw.print(" mAnimRunning="); pw.print(mAnimRunning);
120                pw.print(" mFinishAnimReady="); pw.print(mFinishAnimReady);
121                pw.print(" mFinishAnimStartTime="); pw.println(mFinishAnimStartTime);
122        pw.print(prefix); pw.print("mStartExitAnimation="); pw.print(mStartExitAnimation);
123                pw.print(" "); mStartExitTransformation.printShortString(pw); pw.println();
124        pw.print(prefix); pw.print("mStartEnterAnimation="); pw.print(mStartEnterAnimation);
125                pw.print(" "); mStartEnterTransformation.printShortString(pw); pw.println();
126        pw.print(prefix); pw.print("mFinishExitAnimation="); pw.print(mFinishExitAnimation);
127                pw.print(" "); mFinishExitTransformation.printShortString(pw); pw.println();
128        pw.print(prefix); pw.print("mFinishEnterAnimation="); pw.print(mFinishEnterAnimation);
129                pw.print(" "); mFinishEnterTransformation.printShortString(pw); pw.println();
130        pw.print(prefix); pw.print("mRotateExitAnimation="); pw.print(mRotateExitAnimation);
131                pw.print(" "); mRotateExitTransformation.printShortString(pw); pw.println();
132        pw.print(prefix); pw.print("mRotateEnterAnimation="); pw.print(mRotateEnterAnimation);
133                pw.print(" "); mRotateEnterTransformation.printShortString(pw); pw.println();
134        pw.print(prefix); pw.print("mLastRotateExitAnimation=");
135                pw.print(mLastRotateExitAnimation);
136                pw.print(" "); mLastRotateExitTransformation.printShortString(pw); pw.println();
137        pw.print(prefix); pw.print("mExitTransformation=");
138                mExitTransformation.printShortString(pw); pw.println();
139        pw.print(prefix); pw.print("mEnterTransformation=");
140                mEnterTransformation.printShortString(pw); pw.println();
141        pw.print(prefix); pw.print("mSnapshotInitialMatrix=");
142                mSnapshotInitialMatrix.printShortString(pw);
143                pw.print(" mSnapshotFinalMatrix="); mSnapshotFinalMatrix.printShortString(pw);
144                pw.println();
145    }
146
147    public ScreenRotationAnimation(Context context, SurfaceSession session,
148            boolean inTransaction, int originalWidth, int originalHeight, int originalRotation) {
149        mContext = context;
150
151        // Screenshot does NOT include rotation!
152        mSnapshotRotation = 0;
153        if (originalRotation == Surface.ROTATION_90
154                || originalRotation == Surface.ROTATION_270) {
155            mWidth = originalHeight;
156            mHeight = originalWidth;
157        } else {
158            mWidth = originalWidth;
159            mHeight = originalHeight;
160        }
161
162        mOriginalRotation = originalRotation;
163        mOriginalWidth = originalWidth;
164        mOriginalHeight = originalHeight;
165
166        if (!inTransaction) {
167            if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
168                    ">>> OPEN TRANSACTION ScreenRotationAnimation");
169            Surface.openTransaction();
170        }
171
172        try {
173            try {
174                mSurface = new Surface(session, 0, "FreezeSurface",
175                        -1, mWidth, mHeight, PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT | Surface.HIDDEN);
176                if (mSurface == null || !mSurface.isValid()) {
177                    // Screenshot failed, punt.
178                    mSurface = null;
179                    return;
180                }
181                mSurface.setLayer(FREEZE_LAYER + 1);
182                mSurface.show();
183            } catch (Surface.OutOfResourcesException e) {
184                Slog.w(TAG, "Unable to allocate freeze surface", e);
185            }
186
187            if (WindowManagerService.SHOW_TRANSACTIONS ||
188                    WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
189                            "  FREEZE " + mSurface + ": CREATE");
190
191            setRotation(originalRotation);
192        } finally {
193            if (!inTransaction) {
194                Surface.closeTransaction();
195                if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
196                        "<<< CLOSE TRANSACTION ScreenRotationAnimation");
197            }
198        }
199    }
200
201    boolean hasScreenshot() {
202        return mSurface != null;
203    }
204
205    static int deltaRotation(int oldRotation, int newRotation) {
206        int delta = newRotation - oldRotation;
207        if (delta < 0) delta += 4;
208        return delta;
209    }
210
211    void setSnapshotTransform(Matrix matrix, float alpha) {
212        if (mSurface != null) {
213            matrix.getValues(mTmpFloats);
214            mSurface.setPosition(mTmpFloats[Matrix.MTRANS_X],
215                    mTmpFloats[Matrix.MTRANS_Y]);
216            mSurface.setMatrix(
217                    mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
218                    mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
219            mSurface.setAlpha(alpha);
220            if (DEBUG_TRANSFORMS) {
221                float[] srcPnts = new float[] { 0, 0, mWidth, mHeight };
222                float[] dstPnts = new float[4];
223                matrix.mapPoints(dstPnts, srcPnts);
224                Slog.i(TAG, "Original  : (" + srcPnts[0] + "," + srcPnts[1]
225                        + ")-(" + srcPnts[2] + "," + srcPnts[3] + ")");
226                Slog.i(TAG, "Transformed: (" + dstPnts[0] + "," + dstPnts[1]
227                        + ")-(" + dstPnts[2] + "," + dstPnts[3] + ")");
228            }
229        }
230    }
231
232    public static void createRotationMatrix(int rotation, int width, int height,
233            Matrix outMatrix) {
234        switch (rotation) {
235            case Surface.ROTATION_0:
236                outMatrix.reset();
237                break;
238            case Surface.ROTATION_90:
239                outMatrix.setRotate(90, 0, 0);
240                outMatrix.postTranslate(height, 0);
241                break;
242            case Surface.ROTATION_180:
243                outMatrix.setRotate(180, 0, 0);
244                outMatrix.postTranslate(width, height);
245                break;
246            case Surface.ROTATION_270:
247                outMatrix.setRotate(270, 0, 0);
248                outMatrix.postTranslate(0, width);
249                break;
250        }
251    }
252
253    // Must be called while in a transaction.
254    private void setRotation(int rotation) {
255        mCurRotation = rotation;
256
257        // Compute the transformation matrix that must be applied
258        // to the snapshot to make it stay in the same original position
259        // with the current screen rotation.
260        int delta = deltaRotation(rotation, mSnapshotRotation);
261        createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
262
263        if (DEBUG_STATE) Slog.v(TAG, "**** ROTATION: " + delta);
264        setSnapshotTransform(mSnapshotInitialMatrix, 1.0f);
265    }
266
267    // Must be called while in a transaction.
268    public boolean setRotation(int rotation, SurfaceSession session,
269            long maxAnimationDuration, float animationScale, int finalWidth, int finalHeight) {
270        setRotation(rotation);
271        return startAnimation(session, maxAnimationDuration, animationScale,
272                finalWidth, finalHeight, false);
273    }
274
275    /**
276     * Returns true if animating.
277     */
278    private boolean startAnimation(SurfaceSession session, long maxAnimationDuration,
279            float animationScale, int finalWidth, int finalHeight, boolean dismissing) {
280        if (mSurface == null) {
281            // Can't do animation.
282            return false;
283        }
284        if (mStarted) {
285            return true;
286        }
287
288        mStarted = true;
289
290        boolean firstStart = false;
291
292        // Figure out how the screen has moved from the original rotation.
293        int delta = deltaRotation(mCurRotation, mOriginalRotation);
294
295        if (mFinishExitAnimation == null && (!dismissing || delta != Surface.ROTATION_0)) {
296            if (DEBUG_STATE) Slog.v(TAG, "Creating start and finish animations");
297            firstStart = true;
298            mStartExitAnimation = AnimationUtils.loadAnimation(mContext,
299                    com.android.internal.R.anim.screen_rotate_start_exit);
300            mStartEnterAnimation = AnimationUtils.loadAnimation(mContext,
301                    com.android.internal.R.anim.screen_rotate_start_enter);
302            mFinishExitAnimation = AnimationUtils.loadAnimation(mContext,
303                    com.android.internal.R.anim.screen_rotate_finish_exit);
304            mFinishEnterAnimation = AnimationUtils.loadAnimation(mContext,
305                    com.android.internal.R.anim.screen_rotate_finish_enter);
306        }
307
308        if (DEBUG_STATE) Slog.v(TAG, "Rotation delta: " + delta + " finalWidth="
309                + finalWidth + " finalHeight=" + finalHeight
310                + " origWidth=" + mOriginalWidth + " origHeight=" + mOriginalHeight);
311
312        switch (delta) {
313            case Surface.ROTATION_0:
314                mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
315                        com.android.internal.R.anim.screen_rotate_0_exit);
316                mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
317                        com.android.internal.R.anim.screen_rotate_0_enter);
318                break;
319            case Surface.ROTATION_90:
320                mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
321                        com.android.internal.R.anim.screen_rotate_plus_90_exit);
322                mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
323                        com.android.internal.R.anim.screen_rotate_plus_90_enter);
324                break;
325            case Surface.ROTATION_180:
326                mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
327                        com.android.internal.R.anim.screen_rotate_180_exit);
328                mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
329                        com.android.internal.R.anim.screen_rotate_180_enter);
330                break;
331            case Surface.ROTATION_270:
332                mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
333                        com.android.internal.R.anim.screen_rotate_minus_90_exit);
334                mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
335                        com.android.internal.R.anim.screen_rotate_minus_90_enter);
336                break;
337        }
338
339        // Initialize the animations.  This is a hack, redefining what "parent"
340        // means to allow supplying the last and next size.  In this definition
341        // "%p" is the original (let's call it "previous") size, and "%" is the
342        // screen's current/new size.
343        if (firstStart) {
344            if (DEBUG_STATE) Slog.v(TAG, "Initializing start and finish animations");
345            mStartEnterAnimation.initialize(finalWidth, finalHeight,
346                    mOriginalWidth, mOriginalHeight);
347            mStartExitAnimation.initialize(finalWidth, finalHeight,
348                    mOriginalWidth, mOriginalHeight);
349            mFinishEnterAnimation.initialize(finalWidth, finalHeight,
350                    mOriginalWidth, mOriginalHeight);
351            mFinishExitAnimation.initialize(finalWidth, finalHeight,
352                    mOriginalWidth, mOriginalHeight);
353        }
354        mRotateEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
355        mRotateExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
356        mAnimRunning = false;
357        mFinishAnimReady = false;
358        mFinishAnimStartTime = -1;
359
360        if (firstStart) {
361            mStartExitAnimation.restrictDuration(maxAnimationDuration);
362            mStartExitAnimation.scaleCurrentDuration(animationScale);
363            mStartEnterAnimation.restrictDuration(maxAnimationDuration);
364            mStartEnterAnimation.scaleCurrentDuration(animationScale);
365            mFinishExitAnimation.restrictDuration(maxAnimationDuration);
366            mFinishExitAnimation.scaleCurrentDuration(animationScale);
367            mFinishEnterAnimation.restrictDuration(maxAnimationDuration);
368            mFinishEnterAnimation.scaleCurrentDuration(animationScale);
369        }
370        mRotateExitAnimation.restrictDuration(maxAnimationDuration);
371        mRotateExitAnimation.scaleCurrentDuration(animationScale);
372        mRotateEnterAnimation.restrictDuration(maxAnimationDuration);
373        mRotateEnterAnimation.scaleCurrentDuration(animationScale);
374
375        if (mBlackFrame == null) {
376            if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
377                    WindowManagerService.TAG,
378                    ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
379            Surface.openTransaction();
380
381            try {
382                Rect outer = new Rect(-finalWidth*1, -finalHeight*1, finalWidth*2, finalHeight*2);
383                Rect inner = new Rect(0, 0, finalWidth, finalHeight);
384                mBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER);
385            } catch (Surface.OutOfResourcesException e) {
386                Slog.w(TAG, "Unable to allocate black surface", e);
387            } finally {
388                Surface.closeTransaction();
389                if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
390                        WindowManagerService.TAG,
391                        "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
392            }
393        }
394
395        return true;
396    }
397
398    /**
399     * Returns true if animating.
400     */
401    public boolean dismiss(SurfaceSession session, long maxAnimationDuration,
402            float animationScale, int finalWidth, int finalHeight) {
403        if (DEBUG_STATE) Slog.v(TAG, "Dismiss!");
404        if (mSurface == null) {
405            // Can't do animation.
406            return false;
407        }
408        if (!mStarted) {
409            startAnimation(session, maxAnimationDuration, animationScale, finalWidth, finalHeight,
410                    true);
411        }
412        if (!mStarted) {
413            return false;
414        }
415        if (DEBUG_STATE) Slog.v(TAG, "Setting mFinishAnimReady = true");
416        mFinishAnimReady = true;
417        return true;
418    }
419
420    public void kill() {
421        if (DEBUG_STATE) Slog.v(TAG, "Kill!");
422        if (mSurface != null) {
423            if (WindowManagerService.SHOW_TRANSACTIONS ||
424                    WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
425                            "  FREEZE " + mSurface + ": DESTROY");
426            mSurface.destroy();
427            mSurface = null;
428        }
429        if (mBlackFrame != null) {
430            mBlackFrame.kill();
431            mBlackFrame = null;
432        }
433        if (mStartExitAnimation != null) {
434            mStartExitAnimation.cancel();
435            mStartExitAnimation = null;
436        }
437        if (mStartEnterAnimation != null) {
438            mStartEnterAnimation.cancel();
439            mStartEnterAnimation = null;
440        }
441        if (mFinishExitAnimation != null) {
442            mFinishExitAnimation.cancel();
443            mFinishExitAnimation = null;
444        }
445        if (mStartEnterAnimation != null) {
446            mStartEnterAnimation.cancel();
447            mStartEnterAnimation = null;
448        }
449        if (mRotateExitAnimation != null) {
450            mRotateExitAnimation.cancel();
451            mRotateExitAnimation = null;
452        }
453        if (mRotateEnterAnimation != null) {
454            mRotateEnterAnimation.cancel();
455            mRotateEnterAnimation = null;
456        }
457    }
458
459    public boolean isAnimating() {
460        return mStartEnterAnimation != null || mStartExitAnimation != null
461                && mFinishEnterAnimation != null || mFinishExitAnimation != null
462                && mRotateEnterAnimation != null || mRotateExitAnimation != null;
463    }
464
465    @Override
466    public boolean stepAnimation(long now) {
467
468        if (mFinishAnimReady && mFinishAnimStartTime < 0) {
469            if (DEBUG_STATE) Slog.v(TAG, "Step: finish anim now ready");
470            mFinishAnimStartTime = now;
471        }
472
473        // If the start animation is no longer running, we want to keep its
474        // transformation intact until the finish animation also completes.
475
476        mMoreStartExit = false;
477        if (mStartExitAnimation != null) {
478            mStartExitTransformation.clear();
479            mMoreStartExit = mStartExitAnimation.getTransformation(now, mStartExitTransformation);
480            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start exit: " + mStartExitTransformation);
481            if (!mMoreStartExit) {
482                if (DEBUG_STATE) Slog.v(TAG, "Start exit animation done!");
483                mStartExitAnimation.cancel();
484                mStartExitAnimation = null;
485            }
486        }
487
488        mMoreStartEnter = false;
489        if (mStartEnterAnimation != null) {
490            mStartEnterTransformation.clear();
491            mMoreStartEnter = mStartEnterAnimation.getTransformation(now, mStartEnterTransformation);
492            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start enter: " + mStartEnterTransformation);
493            if (!mMoreStartEnter) {
494                if (DEBUG_STATE) Slog.v(TAG, "Start enter animation done!");
495                mStartEnterAnimation.cancel();
496                mStartEnterAnimation = null;
497            }
498        }
499
500        long finishNow = mFinishAnimReady ? (now - mFinishAnimStartTime) : 0;
501        if (DEBUG_STATE) Slog.v(TAG, "Step: finishNow=" + finishNow);
502
503        mFinishExitTransformation.clear();
504        mMoreFinishExit = false;
505        if (mFinishExitAnimation != null) {
506            mMoreFinishExit = mFinishExitAnimation.getTransformation(finishNow, mFinishExitTransformation);
507            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish exit: " + mFinishExitTransformation);
508            if (!mMoreStartExit && !mMoreFinishExit) {
509                if (DEBUG_STATE) Slog.v(TAG, "Finish exit animation done, clearing start/finish anims!");
510                mStartExitTransformation.clear();
511                mFinishExitAnimation.cancel();
512                mFinishExitAnimation = null;
513                mFinishExitTransformation.clear();
514            }
515        }
516
517        mFinishEnterTransformation.clear();
518        mMoreFinishEnter = false;
519        if (mFinishEnterAnimation != null) {
520            mMoreFinishEnter = mFinishEnterAnimation.getTransformation(finishNow, mFinishEnterTransformation);
521            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish enter: " + mFinishEnterTransformation);
522            if (!mMoreStartEnter && !mMoreFinishEnter) {
523                if (DEBUG_STATE) Slog.v(TAG, "Finish enter animation done, clearing start/finish anims!");
524                mStartEnterTransformation.clear();
525                mFinishEnterAnimation.cancel();
526                mFinishEnterAnimation = null;
527                mFinishEnterTransformation.clear();
528            }
529        }
530
531        mRotateExitTransformation.clear();
532        mMoreRotateExit = false;
533        if (mRotateExitAnimation != null) {
534            mMoreRotateExit = mRotateExitAnimation.getTransformation(now, mRotateExitTransformation);
535            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate exit: " + mRotateExitTransformation);
536        }
537
538        if (!mMoreFinishExit && !mMoreRotateExit) {
539            if (DEBUG_STATE) Slog.v(TAG, "Rotate exit animation done!");
540            mRotateExitAnimation.cancel();
541            mRotateExitAnimation = null;
542            mRotateExitTransformation.clear();
543        }
544
545        mRotateEnterTransformation.clear();
546        mMoreRotateEnter = false;
547        if (mRotateEnterAnimation != null) {
548            mMoreRotateEnter = mRotateEnterAnimation.getTransformation(now, mRotateEnterTransformation);
549            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate enter: " + mRotateEnterTransformation);
550        }
551
552        if (!mMoreFinishEnter && !mMoreRotateEnter) {
553            if (DEBUG_STATE) Slog.v(TAG, "Rotate enter animation done!");
554            mRotateEnterAnimation.cancel();
555            mRotateEnterAnimation = null;
556            mRotateEnterTransformation.clear();
557        }
558
559        mExitTransformation.set(mRotateExitTransformation);
560        mExitTransformation.compose(mStartExitTransformation);
561        mExitTransformation.compose(mFinishExitTransformation);
562
563        mEnterTransformation.set(mRotateEnterTransformation);
564        mEnterTransformation.compose(mStartEnterTransformation);
565        mEnterTransformation.compose(mFinishEnterTransformation);
566
567        if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final exit: " + mExitTransformation);
568        if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final enter: " + mEnterTransformation);
569
570        final boolean more = mMoreStartEnter || mMoreStartExit || mMoreFinishEnter
571                || mMoreFinishExit || mMoreRotateEnter || mMoreRotateExit || !mFinishAnimReady;
572
573        mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix);
574
575        if (DEBUG_STATE) Slog.v(TAG, "Step: more=" + more);
576
577        return more;
578    }
579
580    void updateSurfaces() {
581        if (!mMoreStartExit && !mMoreFinishExit && !mMoreRotateExit) {
582            if (mSurface != null) {
583                if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, hiding screenshot surface");
584                mSurface.hide();
585            }
586        }
587
588        if (!mMoreStartEnter && !mMoreFinishEnter && !mMoreRotateEnter) {
589            if (mBlackFrame != null) {
590                if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, hiding black frame");
591                mBlackFrame.hide();
592            }
593        } else {
594            if (mBlackFrame != null) {
595                mBlackFrame.setMatrix(mEnterTransformation.getMatrix());
596            }
597        }
598
599        setSnapshotTransform(mSnapshotFinalMatrix, mExitTransformation.getAlpha());
600    }
601
602    public boolean startAndFinishAnimationLocked(long now) {
603        if (!isAnimating()) {
604            if (DEBUG_STATE) Slog.v(TAG, "Step: no animations running");
605            return false;
606        }
607
608        if (!mAnimRunning) {
609            if (DEBUG_STATE) Slog.v(TAG, "Step: starting start, finish, rotate");
610            if (mStartEnterAnimation != null) {
611                mStartEnterAnimation.setStartTime(now);
612            }
613            if (mStartExitAnimation != null) {
614                mStartExitAnimation.setStartTime(now);
615            }
616            if (mFinishEnterAnimation != null) {
617                mFinishEnterAnimation.setStartTime(0);
618            }
619            if (mFinishExitAnimation != null) {
620                mFinishExitAnimation.setStartTime(0);
621            }
622            if (mRotateEnterAnimation != null) {
623                mRotateEnterAnimation.setStartTime(now);
624            }
625            if (mRotateExitAnimation != null) {
626                mRotateExitAnimation.setStartTime(now);
627            }
628            mAnimRunning = true;
629        }
630
631        return true;
632    }
633
634    public Transformation getEnterTransformation() {
635        return mEnterTransformation;
636    }
637}
638