• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.server.wm;
18 
19 import java.io.PrintWriter;
20 
21 import static com.android.server.wm.WindowStateAnimator.SurfaceTrace;
22 
23 import android.content.Context;
24 import android.graphics.Matrix;
25 import android.graphics.PixelFormat;
26 import android.graphics.Rect;
27 import android.util.Slog;
28 import android.view.Surface;
29 import android.view.SurfaceSession;
30 import android.view.animation.Animation;
31 import android.view.animation.AnimationUtils;
32 import android.view.animation.Transformation;
33 
34 class 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 
printTo(String prefix, PrintWriter pw)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 
ScreenRotationAnimation(Context context, SurfaceSession session, boolean inTransaction, int originalWidth, int originalHeight, int originalRotation)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 
hasScreenshot()247     boolean hasScreenshot() {
248         return mSurface != null;
249     }
250 
deltaRotation(int oldRotation, int newRotation)251     static int deltaRotation(int oldRotation, int newRotation) {
252         int delta = newRotation - oldRotation;
253         if (delta < 0) delta += 4;
254         return delta;
255     }
256 
setSnapshotTransform(Matrix matrix, float alpha)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 
createRotationMatrix(int rotation, int width, int height, Matrix outMatrix)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.
setRotation(int rotation)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.
setRotation(int rotation, SurfaceSession session, long maxAnimationDuration, float animationScale, int finalWidth, int finalHeight)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      */
startAnimation(SurfaceSession session, long maxAnimationDuration, float animationScale, int finalWidth, int finalHeight, boolean dismissing)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      */
dismiss(SurfaceSession session, long maxAnimationDuration, float animationScale, int finalWidth, int finalHeight)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 
kill()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 
isAnimating()644     public boolean isAnimating() {
645         return hasAnimations() || (TWO_PHASE_ANIMATION && mFinishAnimReady);
646     }
647 
hasAnimations()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 
stepAnimation(long now)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 
updateSurfaces()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 
stepAnimationLocked(long now)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 
getEnterTransformation()927     public Transformation getEnterTransformation() {
928         return mEnterTransformation;
929     }
930 }
931