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