blob: 399c5d3ae45fd2090043fd29eb8798e7d0861676 [file] [log] [blame]
Dianne Hackborna1111872010-11-23 20:55:11 -08001/*
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
Dianne Hackborn6e1eb762011-02-17 16:07:28 -080017package com.android.server.wm;
Dianne Hackborna1111872010-11-23 20:55:11 -080018
Vadim Caen311fef72019-11-05 14:53:06 +010019import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
Adrian Roosb125e0b2019-10-02 14:55:14 +020020import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
Peiyong Lin67f3ba12018-08-23 10:26:45 -070021import static com.android.server.wm.ScreenRotationAnimationProto.ANIMATION_RUNNING;
22import static com.android.server.wm.ScreenRotationAnimationProto.STARTED;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080023import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
24import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Chong Zhang97782b42015-10-07 16:01:23 -070025import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
Chong Zhang97782b42015-10-07 16:01:23 -070026import static com.android.server.wm.WindowStateAnimator.WINDOW_FREEZE_LAYER;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080027
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080028import android.content.Context;
Dianne Hackborna1111872010-11-23 20:55:11 -080029import android.graphics.Matrix;
Vadim Caenf8474262019-08-12 17:52:01 +020030import android.graphics.Point;
Dianne Hackborna1111872010-11-23 20:55:11 -080031import android.graphics.Rect;
Dianne Hackborna1111872010-11-23 20:55:11 -080032import android.util.Slog;
Steven Timotiusf2d68892017-08-28 17:00:01 -070033import android.util.proto.ProtoOutputStream;
Craig Mautner6881a102012-07-27 13:04:51 -070034import android.view.Display;
Craig Mautner46ac6fa2013-08-01 10:06:34 -070035import android.view.DisplayInfo;
Dianne Hackborna1111872010-11-23 20:55:11 -080036import android.view.Surface;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080037import android.view.Surface.OutOfResourcesException;
Mathias Agopian3866f0d2013-02-11 22:08:48 -080038import android.view.SurfaceControl;
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080039import android.view.animation.Animation;
40import android.view.animation.AnimationUtils;
41import android.view.animation.Transformation;
Dianne Hackborna1111872010-11-23 20:55:11 -080042
Adrian Roosb125e0b2019-10-02 14:55:14 +020043import com.android.server.protolog.common.ProtoLog;
44
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080045import java.io.PrintWriter;
46
Vadim Caenf8474262019-08-12 17:52:01 +020047/**
48 * This class handles the rotation animation when the device is rotated.
49 *
50 * <p>
51 * The screen rotation animation is composed of 4 different part:
52 * <ul>
53 * <li> The screenshot: <p>
54 * A screenshot of the whole screen prior the change of orientation is taken to hide the
55 * element resizing below. The screenshot is then animated to rotate and cross-fade to
56 * the new orientation with the content in the new orientation.
57 *
58 * <li> The windows on the display: <p>y
59 * Once the device is rotated, the screen and its content are in the new orientation. The
60 * animation first rotate the new content into the old orientation to then be able to
61 * animate to the new orientation
62 *
63 * <li> The exiting Blackframe: <p>
64 * Because the change of orientation might change the width and height of the content (i.e
65 * when rotating from portrait to landscape) we "crop" the new content using black frames
66 * around the screenshot so the new content does not go beyond the screenshot's bounds
67 *
68 * <li> The entering Blackframe: <p>
69 * The enter Blackframe is similar to the exit Blackframe but is only used when a custom
70 * rotation animation is used and matches the new content size instead of the screenshot.
71 * </ul>
72 *
73 * Each part has its own Surface which are then animated by {@link SurfaceAnimator}s.
74 */
Craig Mautnere32c3072012-03-12 15:25:35 -070075class ScreenRotationAnimation {
Vadim Caen2ada9a92019-07-30 11:39:44 +020076 private static final String TAG = TAG_WITH_CLASS_NAME ? "ScreenRotationAnimation" : TAG_WM;
Dianne Hackborna1111872010-11-23 20:55:11 -080077
Chong Zhang97782b42015-10-07 16:01:23 -070078 /*
79 * Layers for screen rotation animation. We put these layers above
80 * WINDOW_FREEZE_LAYER so that screen freeze will cover all windows.
81 */
Vadim Caen2ada9a92019-07-30 11:39:44 +020082 private static final int SCREEN_FREEZE_LAYER_BASE = WINDOW_FREEZE_LAYER + TYPE_LAYER_MULTIPLIER;
83 private static final int SCREEN_FREEZE_LAYER_ENTER = SCREEN_FREEZE_LAYER_BASE;
84 private static final int SCREEN_FREEZE_LAYER_SCREENSHOT = SCREEN_FREEZE_LAYER_BASE + 1;
85 private static final int SCREEN_FREEZE_LAYER_EXIT = SCREEN_FREEZE_LAYER_BASE + 2;
Dianne Hackborn50660e22011-02-02 17:12:25 -080086
Vadim Caen2ada9a92019-07-30 11:39:44 +020087 private final Context mContext;
88 private final DisplayContent mDisplayContent;
89 private final float[] mTmpFloats = new float[9];
90 private final Transformation mRotateExitTransformation = new Transformation();
91 private final Transformation mRotateEnterTransformation = new Transformation();
92 // Complete transformations being applied.
93 private final Transformation mExitTransformation = new Transformation();
94 private final Transformation mEnterTransformation = new Transformation();
95 private final Matrix mFrameInitialMatrix = new Matrix();
96 private final Matrix mSnapshotInitialMatrix = new Matrix();
97 private final Matrix mSnapshotFinalMatrix = new Matrix();
98 private final Matrix mExitFrameFinalMatrix = new Matrix();
99 private final WindowManagerService mService;
Vadim Caenf8474262019-08-12 17:52:01 +0200100 private SurfaceControl mEnterBlackFrameLayer;
101 private SurfaceControl mRotationLayer;
Vadim Caen2ada9a92019-07-30 11:39:44 +0200102 private SurfaceControl mSurfaceControl;
103 private BlackFrame mEnteringBlackFrame;
104 private int mWidth, mHeight;
Dianne Hackborna1111872010-11-23 20:55:11 -0800105
Vadim Caen2ada9a92019-07-30 11:39:44 +0200106 private int mOriginalRotation;
107 private int mOriginalWidth, mOriginalHeight;
108 private int mCurRotation;
Dianne Hackborna1111872010-11-23 20:55:11 -0800109
Vadim Caen2ada9a92019-07-30 11:39:44 +0200110 private Rect mOriginalDisplayRect = new Rect();
111 private Rect mCurrentDisplayRect = new Rect();
Dianne Hackbornfd1c5ed2012-01-13 13:09:16 -0800112 // The current active animation to move from the old to the new rotated
113 // state. Which animation is run here will depend on the old and new
114 // rotations.
Vadim Caen2ada9a92019-07-30 11:39:44 +0200115 private Animation mRotateExitAnimation;
116 private Animation mRotateEnterAnimation;
Vadim Caenf8474262019-08-12 17:52:01 +0200117 private Animation mRotateAlphaAnimation;
Vadim Caen2ada9a92019-07-30 11:39:44 +0200118 private boolean mStarted;
119 private boolean mAnimRunning;
120 private boolean mFinishAnimReady;
121 private long mFinishAnimStartTime;
122 private boolean mForceDefaultOrientation;
123 private BlackFrame mExitingBlackFrame;
Vadim Caenf8474262019-08-12 17:52:01 +0200124 private SurfaceRotationAnimationController mSurfaceRotationAnimationController;
Steven Timotiusf2d68892017-08-28 17:00:01 -0700125
Craig Mautner46ac6fa2013-08-01 10:06:34 -0700126 public ScreenRotationAnimation(Context context, DisplayContent displayContent,
Garfield Tanff362222018-11-14 17:52:32 -0800127 boolean fixedToUserRotation, boolean isSecure, WindowManagerService service) {
Robert Carr68e5c9e2016-09-14 10:50:09 -0700128 mService = service;
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800129 mContext = context;
Craig Mautner46ac6fa2013-08-01 10:06:34 -0700130 mDisplayContent = displayContent;
Bryce Leef3c6a472017-11-14 14:53:06 -0800131 displayContent.getBounds(mOriginalDisplayRect);
Dianne Hackborna1111872010-11-23 20:55:11 -0800132
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800133 // Screenshot does NOT include rotation!
Craig Mautner46ac6fa2013-08-01 10:06:34 -0700134 final Display display = displayContent.getDisplay();
135 int originalRotation = display.getRotation();
136 final int originalWidth;
137 final int originalHeight;
138 DisplayInfo displayInfo = displayContent.getDisplayInfo();
Garfield Tanff362222018-11-14 17:52:32 -0800139 if (fixedToUserRotation) {
Craig Mautner46ac6fa2013-08-01 10:06:34 -0700140 // Emulated orientation.
141 mForceDefaultOrientation = true;
142 originalWidth = displayContent.mBaseDisplayWidth;
143 originalHeight = displayContent.mBaseDisplayHeight;
144 } else {
145 // Normal situation
146 originalWidth = displayInfo.logicalWidth;
147 originalHeight = displayInfo.logicalHeight;
148 }
Mathias Agopian0ab84ef2011-10-13 16:02:48 -0700149 if (originalRotation == Surface.ROTATION_90
150 || originalRotation == Surface.ROTATION_270) {
151 mWidth = originalHeight;
152 mHeight = originalWidth;
153 } else {
154 mWidth = originalWidth;
155 mHeight = originalHeight;
156 }
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800157
Jeff Brownbc68a592011-07-25 12:58:12 -0700158 mOriginalRotation = originalRotation;
159 mOriginalWidth = originalWidth;
160 mOriginalHeight = originalHeight;
Vadim Caenf8474262019-08-12 17:52:01 +0200161 mSurfaceRotationAnimationController = new SurfaceRotationAnimationController();
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800162
Vishnu Nair33197392019-08-30 10:29:37 -0700163 final SurfaceControl.Transaction t = mService.mTransactionFactory.get();
Dianne Hackborna1111872010-11-23 20:55:11 -0800164 try {
Vadim Caenf8474262019-08-12 17:52:01 +0200165 mRotationLayer = displayContent.makeOverlay()
166 .setName("RotationLayer")
167 .setContainerLayer()
168 .build();
169
170 mEnterBlackFrameLayer = displayContent.makeOverlay()
171 .setName("EnterBlackFrameLayer")
172 .setContainerLayer()
173 .build();
174
chaviw8065f442019-11-18 13:20:58 -0800175 mSurfaceControl = mService.makeSurfaceBuilder(null)
Robert Carrae606b42018-02-15 15:36:23 -0800176 .setName("ScreenshotSurface")
Vadim Caenf8474262019-08-12 17:52:01 +0200177 .setParent(mRotationLayer)
Vishnu Naire86bd982018-11-28 13:23:17 -0800178 .setBufferSize(mWidth, mHeight)
Robert Carrae606b42018-02-15 15:36:23 -0800179 .setSecure(isSecure)
180 .build();
Robert Carre13b58e2017-08-31 14:50:44 -0700181
Peiyong Lin67f3ba12018-08-23 10:26:45 -0700182 // In case display bounds change, screenshot buffer and surface may mismatch so set a
183 // scaling mode.
Vishnu Nair33197392019-08-30 10:29:37 -0700184 SurfaceControl.Transaction t2 = mService.mTransactionFactory.get();
Peiyong Lin67f3ba12018-08-23 10:26:45 -0700185 t2.setOverrideScalingMode(mSurfaceControl, Surface.SCALING_MODE_SCALE_TO_WINDOW);
186 t2.apply(true /* sync */);
187
Riddle Hsu654a6f92018-07-13 22:59:36 +0800188 // Capture a screenshot into the surface we just created.
189 final int displayId = display.getDisplayId();
Vishnu Nair33197392019-08-30 10:29:37 -0700190 final Surface surface = mService.mSurfaceFactory.get();
Riddle Hsu654a6f92018-07-13 22:59:36 +0800191 surface.copyFrom(mSurfaceControl);
Robert Carr66b5664f2019-04-02 14:18:56 -0700192 SurfaceControl.ScreenshotGraphicBuffer gb =
Vadim Caen2ada9a92019-07-30 11:39:44 +0200193 mService.mDisplayManagerInternal.screenshot(displayId);
Robert Carr66b5664f2019-04-02 14:18:56 -0700194 if (gb != null) {
195 try {
Peiyong Linccc06b62019-06-25 17:31:09 -0700196 surface.attachAndQueueBufferWithColorSpace(gb.getGraphicBuffer(),
197 gb.getColorSpace());
Robert Carr66b5664f2019-04-02 14:18:56 -0700198 } catch (RuntimeException e) {
199 Slog.w(TAG, "Failed to attach screenshot - " + e.getMessage());
200 }
201 // If the screenshot contains secure layers, we have to make sure the
202 // screenshot surface we display it in also has FLAG_SECURE so that
203 // the user can not screenshot secure layers via the screenshot surface.
204 if (gb.containsSecureLayers()) {
205 t.setSecure(mSurfaceControl, true);
206 }
Vadim Caenf8474262019-08-12 17:52:01 +0200207 t.setLayer(mRotationLayer, SCREEN_FREEZE_LAYER_BASE);
Garfield Tanf4ac3072018-03-16 13:03:52 -0700208 t.setLayer(mSurfaceControl, SCREEN_FREEZE_LAYER_SCREENSHOT);
209 t.setAlpha(mSurfaceControl, 0);
Vadim Caenf8474262019-08-12 17:52:01 +0200210 t.show(mRotationLayer);
Garfield Tanf4ac3072018-03-16 13:03:52 -0700211 t.show(mSurfaceControl);
Garfield Tanf4ac3072018-03-16 13:03:52 -0700212 } else {
Riddle Hsu654a6f92018-07-13 22:59:36 +0800213 Slog.w(TAG, "Unable to take screenshot of display " + displayId);
Garfield Tanf4ac3072018-03-16 13:03:52 -0700214 }
Riddle Hsu654a6f92018-07-13 22:59:36 +0800215 surface.destroy();
Robert Carrae606b42018-02-15 15:36:23 -0800216 } catch (OutOfResourcesException e) {
217 Slog.w(TAG, "Unable to allocate freeze surface", e);
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800218 }
Robert Carrae606b42018-02-15 15:36:23 -0800219
Adrian Roosb125e0b2019-10-02 14:55:14 +0200220 ProtoLog.i(WM_SHOW_SURFACE_ALLOC,
221 " FREEZE %s: CREATE", mSurfaceControl);
Robert Carrae606b42018-02-15 15:36:23 -0800222 setRotation(t, originalRotation);
223 t.apply();
Dianne Hackborna1111872010-11-23 20:55:11 -0800224 }
225
Vadim Caen2ada9a92019-07-30 11:39:44 +0200226 private static void createRotationMatrix(int rotation, int width, int height,
227 Matrix outMatrix) {
228 switch (rotation) {
229 case Surface.ROTATION_0:
230 outMatrix.reset();
231 break;
232 case Surface.ROTATION_90:
233 outMatrix.setRotate(90, 0, 0);
234 outMatrix.postTranslate(height, 0);
235 break;
236 case Surface.ROTATION_180:
237 outMatrix.setRotate(180, 0, 0);
238 outMatrix.postTranslate(width, height);
239 break;
240 case Surface.ROTATION_270:
241 outMatrix.setRotate(270, 0, 0);
242 outMatrix.postTranslate(0, width);
243 break;
244 }
245 }
246
Jeffrey Huangcb782852019-12-05 11:28:11 -0800247 public void dumpDebug(ProtoOutputStream proto, long fieldId) {
Vadim Caen2ada9a92019-07-30 11:39:44 +0200248 final long token = proto.start(fieldId);
249 proto.write(STARTED, mStarted);
250 proto.write(ANIMATION_RUNNING, mAnimRunning);
251 proto.end(token);
252 }
253
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800254 boolean hasScreenshot() {
Mathias Agopian29479eb2013-02-14 14:36:04 -0800255 return mSurfaceControl != null;
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800256 }
257
Vadim Caenf8474262019-08-12 17:52:01 +0200258 private void setRotationTransform(SurfaceControl.Transaction t, Matrix matrix) {
259 if (mRotationLayer == null) {
260 return;
Dianne Hackborna1111872010-11-23 20:55:11 -0800261 }
Vadim Caenf8474262019-08-12 17:52:01 +0200262 matrix.getValues(mTmpFloats);
263 float x = mTmpFloats[Matrix.MTRANS_X];
264 float y = mTmpFloats[Matrix.MTRANS_Y];
265 if (mForceDefaultOrientation) {
266 mDisplayContent.getBounds(mCurrentDisplayRect);
267 x -= mCurrentDisplayRect.left;
268 y -= mCurrentDisplayRect.top;
269 }
270 t.setPosition(mRotationLayer, x, y);
271 t.setMatrix(mRotationLayer,
272 mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
273 mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
274
275 t.setAlpha(mSurfaceControl, (float) 1.0);
276 t.setAlpha(mRotationLayer, (float) 1.0);
277 t.show(mRotationLayer);
Dianne Hackborna1111872010-11-23 20:55:11 -0800278 }
279
Vadim Caen2ada9a92019-07-30 11:39:44 +0200280 public void printTo(String prefix, PrintWriter pw) {
281 pw.print(prefix); pw.print("mSurface="); pw.print(mSurfaceControl);
282 pw.print(" mWidth="); pw.print(mWidth);
283 pw.print(" mHeight="); pw.println(mHeight);
284 pw.print(prefix); pw.print("mExitingBlackFrame="); pw.println(mExitingBlackFrame);
285 if (mExitingBlackFrame != null) {
286 mExitingBlackFrame.printTo(prefix + " ", pw);
287 }
Vadim Caenf8474262019-08-12 17:52:01 +0200288 pw.print(prefix);
289 pw.print("mEnteringBlackFrame=");
290 pw.println(mEnteringBlackFrame);
Vadim Caen2ada9a92019-07-30 11:39:44 +0200291 if (mEnteringBlackFrame != null) {
292 mEnteringBlackFrame.printTo(prefix + " ", pw);
293 }
294 pw.print(prefix); pw.print("mCurRotation="); pw.print(mCurRotation);
295 pw.print(" mOriginalRotation="); pw.println(mOriginalRotation);
296 pw.print(prefix); pw.print("mOriginalWidth="); pw.print(mOriginalWidth);
297 pw.print(" mOriginalHeight="); pw.println(mOriginalHeight);
298 pw.print(prefix); pw.print("mStarted="); pw.print(mStarted);
299 pw.print(" mAnimRunning="); pw.print(mAnimRunning);
300 pw.print(" mFinishAnimReady="); pw.print(mFinishAnimReady);
301 pw.print(" mFinishAnimStartTime="); pw.println(mFinishAnimStartTime);
302 pw.print(prefix); pw.print("mRotateExitAnimation="); pw.print(mRotateExitAnimation);
303 pw.print(" "); mRotateExitTransformation.printShortString(pw); pw.println();
304 pw.print(prefix); pw.print("mRotateEnterAnimation="); pw.print(mRotateEnterAnimation);
305 pw.print(" "); mRotateEnterTransformation.printShortString(pw); pw.println();
306 pw.print(prefix); pw.print("mExitTransformation=");
307 mExitTransformation.printShortString(pw); pw.println();
308 pw.print(prefix); pw.print("mEnterTransformation=");
309 mEnterTransformation.printShortString(pw); pw.println();
310 pw.print(prefix); pw.print("mFrameInitialMatrix=");
311 mFrameInitialMatrix.printShortString(pw);
312 pw.println();
313 pw.print(prefix); pw.print("mSnapshotInitialMatrix=");
314 mSnapshotInitialMatrix.printShortString(pw);
315 pw.print(" mSnapshotFinalMatrix="); mSnapshotFinalMatrix.printShortString(pw);
316 pw.println();
317 pw.print(prefix); pw.print("mExitFrameFinalMatrix=");
318 mExitFrameFinalMatrix.printShortString(pw);
319 pw.println();
320 pw.print(prefix); pw.print("mForceDefaultOrientation="); pw.print(mForceDefaultOrientation);
321 if (mForceDefaultOrientation) {
322 pw.print(" mOriginalDisplayRect="); pw.print(mOriginalDisplayRect.toShortString());
323 pw.print(" mCurrentDisplayRect="); pw.println(mCurrentDisplayRect.toShortString());
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800324 }
325 }
326
Vadim Caen2ada9a92019-07-30 11:39:44 +0200327 public void setRotation(SurfaceControl.Transaction t, int rotation) {
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800328 mCurRotation = rotation;
329
330 // Compute the transformation matrix that must be applied
331 // to the snapshot to make it stay in the same original position
332 // with the current screen rotation.
Wale Ogunwale4a02d812015-02-12 23:01:38 -0800333 int delta = DisplayContent.deltaRotation(rotation, Surface.ROTATION_0);
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800334 createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800335
Vadim Caenf8474262019-08-12 17:52:01 +0200336 setRotationTransform(t, mSnapshotInitialMatrix);
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800337 }
338
339 /**
340 * Returns true if animating.
341 */
Robert Carrae606b42018-02-15 15:36:23 -0800342 private boolean startAnimation(SurfaceControl.Transaction t, long maxAnimationDuration,
Vadim Caenba4fd6c2019-08-05 16:45:46 +0200343 float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) {
Mathias Agopian29479eb2013-02-14 14:36:04 -0800344 if (mSurfaceControl == null) {
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800345 // Can't do animation.
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800346 return false;
347 }
Dianne Hackbornfd1c5ed2012-01-13 13:09:16 -0800348 if (mStarted) {
349 return true;
350 }
351
352 mStarted = true;
353
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800354 // Figure out how the screen has moved from the original rotation.
Wale Ogunwale4a02d812015-02-12 23:01:38 -0800355 int delta = DisplayContent.deltaRotation(mCurRotation, mOriginalRotation);
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800356
Vadim Caenf8474262019-08-12 17:52:01 +0200357 mRotateAlphaAnimation = AnimationUtils.loadAnimation(mContext,
358 com.android.internal.R.anim.screen_rotate_alpha);
359
Dianne Hackborn9d9ece32012-09-10 15:33:52 -0700360 final boolean customAnim;
Craig Mautner3c174372013-02-21 17:54:37 -0800361 if (exitAnim != 0 && enterAnim != 0) {
Dianne Hackborn9d9ece32012-09-10 15:33:52 -0700362 customAnim = true;
Craig Mautner3c174372013-02-21 17:54:37 -0800363 mRotateExitAnimation = AnimationUtils.loadAnimation(mContext, exitAnim);
364 mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext, enterAnim);
Dianne Hackborn9d9ece32012-09-10 15:33:52 -0700365 } else {
366 customAnim = false;
367 switch (delta) {
368 case Surface.ROTATION_0:
369 mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
370 com.android.internal.R.anim.screen_rotate_0_exit);
371 mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
372 com.android.internal.R.anim.screen_rotate_0_enter);
Dianne Hackborn9d9ece32012-09-10 15:33:52 -0700373 break;
374 case Surface.ROTATION_90:
375 mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
376 com.android.internal.R.anim.screen_rotate_plus_90_exit);
377 mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
378 com.android.internal.R.anim.screen_rotate_plus_90_enter);
Dianne Hackborn9d9ece32012-09-10 15:33:52 -0700379 break;
380 case Surface.ROTATION_180:
381 mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
382 com.android.internal.R.anim.screen_rotate_180_exit);
383 mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
384 com.android.internal.R.anim.screen_rotate_180_enter);
Dianne Hackborn9d9ece32012-09-10 15:33:52 -0700385 break;
386 case Surface.ROTATION_270:
387 mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
388 com.android.internal.R.anim.screen_rotate_minus_90_exit);
389 mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
390 com.android.internal.R.anim.screen_rotate_minus_90_enter);
Dianne Hackborn9d9ece32012-09-10 15:33:52 -0700391 break;
392 }
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800393 }
394
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800395 // Initialize the animations. This is a hack, redefining what "parent"
396 // means to allow supplying the last and next size. In this definition
397 // "%p" is the original (let's call it "previous") size, and "%" is the
398 // screen's current/new size.
Dianne Hackbornfd1c5ed2012-01-13 13:09:16 -0800399 mRotateEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
400 mRotateExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
401 mAnimRunning = false;
402 mFinishAnimReady = false;
403 mFinishAnimStartTime = -1;
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800404
Dianne Hackbornfd1c5ed2012-01-13 13:09:16 -0800405 mRotateExitAnimation.restrictDuration(maxAnimationDuration);
406 mRotateExitAnimation.scaleCurrentDuration(animationScale);
407 mRotateEnterAnimation.restrictDuration(maxAnimationDuration);
408 mRotateEnterAnimation.scaleCurrentDuration(animationScale);
Vadim Caenf8474262019-08-12 17:52:01 +0200409 mRotateAlphaAnimation.restrictDuration(maxAnimationDuration);
410 mRotateAlphaAnimation.scaleCurrentDuration(animationScale);
Dianne Hackbornd6b32b62012-03-16 11:54:51 -0700411
Dianne Hackborn9d9ece32012-09-10 15:33:52 -0700412 if (!customAnim && mExitingBlackFrame == null) {
Dianne Hackbornd6b32b62012-03-16 11:54:51 -0700413 try {
Jeff Brown4ed8fe72012-08-30 18:18:29 -0700414 // Compute the transformation matrix that must be applied
415 // the the black frame to make it stay in the initial position
416 // before the new screen rotation. This is different than the
417 // snapshot transformation because the snapshot is always based
418 // of the native orientation of the screen, not the orientation
419 // we were last in.
420 createRotationMatrix(delta, mOriginalWidth, mOriginalHeight, mFrameInitialMatrix);
421
Craig Mautner46ac6fa2013-08-01 10:06:34 -0700422 final Rect outer;
423 final Rect inner;
424 if (mForceDefaultOrientation) {
425 // Going from a smaller Display to a larger Display, add curtains to sides
426 // or top and bottom. Going from a larger to smaller display will result in
427 // no BlackSurfaces being constructed.
428 outer = mCurrentDisplayRect;
429 inner = mOriginalDisplayRect;
430 } else {
Vadim Caenf8474262019-08-12 17:52:01 +0200431 outer = new Rect(-mWidth, -mHeight, mWidth * 2, mHeight * 2);
432 inner = new Rect(0, 0, mWidth, mHeight);
Craig Mautner46ac6fa2013-08-01 10:06:34 -0700433 }
chaviw9f6171e2019-06-07 16:33:50 -0700434 mExitingBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner,
Vadim Caenf8474262019-08-12 17:52:01 +0200435 SCREEN_FREEZE_LAYER_EXIT, mDisplayContent, mForceDefaultOrientation,
436 mRotationLayer);
Igor Murashkina86ab6402013-08-30 12:58:36 -0700437 } catch (OutOfResourcesException e) {
Dianne Hackbornd6b32b62012-03-16 11:54:51 -0700438 Slog.w(TAG, "Unable to allocate black surface", e);
Dianne Hackbornd6b32b62012-03-16 11:54:51 -0700439 }
440 }
441
Dianne Hackborn9d9ece32012-09-10 15:33:52 -0700442 if (customAnim && mEnteringBlackFrame == null) {
Dianne Hackbornd6b32b62012-03-16 11:54:51 -0700443 try {
Vadim Caenf8474262019-08-12 17:52:01 +0200444 Rect outer = new Rect(-finalWidth, -finalHeight,
Vadim Caen2ada9a92019-07-30 11:39:44 +0200445 finalWidth * 2, finalHeight * 2);
Dianne Hackbornd6b32b62012-03-16 11:54:51 -0700446 Rect inner = new Rect(0, 0, finalWidth, finalHeight);
chaviw9f6171e2019-06-07 16:33:50 -0700447 mEnteringBlackFrame = new BlackFrame(mService.mTransactionFactory, t, outer, inner,
Vadim Caenf8474262019-08-12 17:52:01 +0200448 SCREEN_FREEZE_LAYER_ENTER, mDisplayContent, false, mEnterBlackFrameLayer);
Igor Murashkina86ab6402013-08-30 12:58:36 -0700449 } catch (OutOfResourcesException e) {
Dianne Hackbornfd1c5ed2012-01-13 13:09:16 -0800450 Slog.w(TAG, "Unable to allocate black surface", e);
Dianne Hackbornfd1c5ed2012-01-13 13:09:16 -0800451 }
Dianne Hackborn50660e22011-02-02 17:12:25 -0800452 }
453
Vadim Caenf8474262019-08-12 17:52:01 +0200454 mSurfaceRotationAnimationController.startAnimation();
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800455 return true;
456 }
457
Dianne Hackbornfd1c5ed2012-01-13 13:09:16 -0800458 /**
459 * Returns true if animating.
460 */
Robert Carrae606b42018-02-15 15:36:23 -0800461 public boolean dismiss(SurfaceControl.Transaction t, long maxAnimationDuration,
Craig Mautner3c174372013-02-21 17:54:37 -0800462 float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) {
Mathias Agopian29479eb2013-02-14 14:36:04 -0800463 if (mSurfaceControl == null) {
Dianne Hackbornfd1c5ed2012-01-13 13:09:16 -0800464 // Can't do animation.
465 return false;
466 }
467 if (!mStarted) {
Robert Carrae606b42018-02-15 15:36:23 -0800468 startAnimation(t, maxAnimationDuration, animationScale, finalWidth, finalHeight,
Vadim Caenba4fd6c2019-08-05 16:45:46 +0200469 exitAnim, enterAnim);
Dianne Hackbornfd1c5ed2012-01-13 13:09:16 -0800470 }
471 if (!mStarted) {
472 return false;
473 }
Dianne Hackbornfd1c5ed2012-01-13 13:09:16 -0800474 mFinishAnimReady = true;
475 return true;
476 }
477
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800478 public void kill() {
Vadim Caenf8474262019-08-12 17:52:01 +0200479 if (mSurfaceRotationAnimationController != null) {
480 mSurfaceRotationAnimationController.cancel();
481 mSurfaceRotationAnimationController = null;
482 }
Mathias Agopian29479eb2013-02-14 14:36:04 -0800483 if (mSurfaceControl != null) {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200484 ProtoLog.i(WM_SHOW_SURFACE_ALLOC, " FREEZE %s: DESTROY", mSurfaceControl);
Mathias Agopian29479eb2013-02-14 14:36:04 -0800485 mSurfaceControl = null;
Vadim Caenf8474262019-08-12 17:52:01 +0200486 SurfaceControl.Transaction t = mService.mTransactionFactory.get();
487 if (mRotationLayer != null) {
488 if (mRotationLayer.isValid()) {
489 t.remove(mRotationLayer);
490 }
491 mRotationLayer = null;
492 }
493 if (mEnterBlackFrameLayer != null) {
494 if (mEnterBlackFrameLayer.isValid()) {
495 t.remove(mEnterBlackFrameLayer);
496 }
497 mEnterBlackFrameLayer = null;
498 }
499 t.apply();
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800500 }
Dianne Hackbornd6b32b62012-03-16 11:54:51 -0700501 if (mExitingBlackFrame != null) {
502 mExitingBlackFrame.kill();
503 mExitingBlackFrame = null;
504 }
505 if (mEnteringBlackFrame != null) {
506 mEnteringBlackFrame.kill();
507 mEnteringBlackFrame = null;
Dianne Hackborn352cc982011-01-04 11:34:18 -0800508 }
Dianne Hackbornfd1c5ed2012-01-13 13:09:16 -0800509 if (mRotateExitAnimation != null) {
510 mRotateExitAnimation.cancel();
511 mRotateExitAnimation = null;
512 }
513 if (mRotateEnterAnimation != null) {
514 mRotateEnterAnimation.cancel();
515 mRotateEnterAnimation = null;
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800516 }
Vadim Caenf8474262019-08-12 17:52:01 +0200517 if (mRotateAlphaAnimation != null) {
518 mRotateAlphaAnimation.cancel();
519 mRotateAlphaAnimation = null;
520 }
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800521 }
522
523 public boolean isAnimating() {
Vadim Caenf8474262019-08-12 17:52:01 +0200524 return mSurfaceRotationAnimationController != null
525 && mSurfaceRotationAnimationController.isAnimating();
Dianne Hackborn187ae2102012-04-11 18:12:06 -0700526 }
527
Dianne Hackborn4b169692012-11-29 17:51:24 -0800528 public boolean isRotating() {
529 return mCurRotation != mOriginalRotation;
530 }
531
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800532 public Transformation getEnterTransformation() {
533 return mEnterTransformation;
Dianne Hackborna1111872010-11-23 20:55:11 -0800534 }
Vadim Caenf8474262019-08-12 17:52:01 +0200535
536 /**
537 * Utility class that runs a {@link ScreenRotationAnimation} on the {@link
538 * SurfaceAnimationRunner}.
539 * <p>
540 * The rotation animation is divided into the following hierarchy:
541 * <ul>
542 * <li> A first rotation layer, containing the blackframes. This layer is animated by the
543 * "screen_rotate_X_exit" that applies a scale and rotate and where X is value of the rotation.
544 * <ul>
545 * <li> A child layer containing the screenshot on which is added an animation of it's
546 * alpha channel ("screen_rotate_alpha") and that will rotate with his parent layer.</li>
547 * </ul>
548 * <li> A second rotation layer used when custom animations are passed in
549 * {@link ScreenRotationAnimation#startAnimation(
550 * SurfaceControl.Transaction, long, float, int, int, int, int)}.
551 * </ul>
552 * <p>
553 * Thus an {@link LocalAnimationAdapter.AnimationSpec} is created for each of
554 * this three {@link SurfaceControl}s which then delegates the animation to the
555 * {@link ScreenRotationAnimation}.
556 */
557 class SurfaceRotationAnimationController {
558 private SurfaceAnimator mDisplayAnimator;
559 private SurfaceAnimator mEnterBlackFrameAnimator;
560 private SurfaceAnimator mScreenshotRotationAnimator;
561 private SurfaceAnimator mRotateScreenAnimator;
Vadim Caenf8474262019-08-12 17:52:01 +0200562
563 /**
564 * Start the rotation animation of the display and the screenshot on the
565 * {@link SurfaceAnimationRunner}.
566 */
567 void startAnimation() {
568 mRotateScreenAnimator = startScreenshotAlphaAnimation();
569 mDisplayAnimator = startDisplayRotation();
570 if (mExitingBlackFrame != null) {
571 mScreenshotRotationAnimator = startScreenshotRotationAnimation();
572 }
573 if (mEnteringBlackFrame != null) {
574 mEnterBlackFrameAnimator = startEnterBlackFrameAnimation();
575 }
576 }
577
578 private SimpleSurfaceAnimatable.Builder initializeBuilder() {
579 return new SimpleSurfaceAnimatable.Builder()
580 .setPendingTransactionSupplier(mDisplayContent::getPendingTransaction)
581 .setCommitTransactionRunnable(mDisplayContent::commitPendingTransaction)
582 .setAnimationLeashSupplier(mDisplayContent::makeOverlay);
583 }
584
585 private SurfaceAnimator startDisplayRotation() {
586 return startAnimation(initializeBuilder()
587 .setAnimationLeashParent(mDisplayContent.getSurfaceControl())
588 .setSurfaceControl(mDisplayContent.getWindowingLayer())
589 .setParentSurfaceControl(mDisplayContent.getSurfaceControl())
590 .setWidth(mDisplayContent.getSurfaceWidth())
591 .setHeight(mDisplayContent.getSurfaceHeight())
592 .build(),
593 createWindowAnimationSpec(mRotateEnterAnimation),
Vadim Caen311fef72019-11-05 14:53:06 +0100594 this::onAnimationEnd);
Vadim Caenf8474262019-08-12 17:52:01 +0200595 }
596
597 private SurfaceAnimator startScreenshotAlphaAnimation() {
598 return startAnimation(initializeBuilder()
599 .setSurfaceControl(mSurfaceControl)
600 .setAnimationLeashParent(mRotationLayer)
601 .setWidth(mWidth)
602 .setHeight(mHeight)
603 .build(),
604 createWindowAnimationSpec(mRotateAlphaAnimation),
Vadim Caen311fef72019-11-05 14:53:06 +0100605 this::onAnimationEnd);
Vadim Caenf8474262019-08-12 17:52:01 +0200606 }
607
608 private SurfaceAnimator startEnterBlackFrameAnimation() {
609 return startAnimation(initializeBuilder()
610 .setSurfaceControl(mEnterBlackFrameLayer)
611 .setAnimationLeashParent(mDisplayContent.getOverlayLayer())
612 .build(),
613 createWindowAnimationSpec(mRotateEnterAnimation),
Vadim Caen311fef72019-11-05 14:53:06 +0100614 this::onAnimationEnd);
Vadim Caenf8474262019-08-12 17:52:01 +0200615 }
616
617 private SurfaceAnimator startScreenshotRotationAnimation() {
618 return startAnimation(initializeBuilder()
619 .setSurfaceControl(mRotationLayer)
620 .setAnimationLeashParent(mDisplayContent.getOverlayLayer())
621 .build(),
622 createWindowAnimationSpec(mRotateExitAnimation),
623 this::onAnimationEnd);
624 }
625
626 private WindowAnimationSpec createWindowAnimationSpec(Animation mAnimation) {
627 return new WindowAnimationSpec(mAnimation, new Point(0, 0) /* position */,
628 false /* canSkipFirstFrame */, 0 /* WindowCornerRadius */);
629 }
630
631 /**
632 * Start an animation defined by animationSpec on a new {@link SurfaceAnimator}.
633 *
634 * @param animatable The animatable used for the animation.
635 * @param animationSpec The spec of the animation.
636 * @param animationFinishedCallback Callback passed to the {@link SurfaceAnimator} and
637 * called when the animation finishes.
638 * @return The newly created {@link SurfaceAnimator} that as been started.
639 */
640 private SurfaceAnimator startAnimation(
641 SurfaceAnimator.Animatable animatable,
642 LocalAnimationAdapter.AnimationSpec animationSpec,
643 Runnable animationFinishedCallback) {
644 SurfaceAnimator animator = new SurfaceAnimator(
645 animatable, animationFinishedCallback, mService);
646
647 LocalAnimationAdapter localAnimationAdapter = new LocalAnimationAdapter(
648 animationSpec, mService.mSurfaceAnimationRunner);
649
650 animator.startAnimation(mDisplayContent.getPendingTransaction(),
651 localAnimationAdapter, false);
652 return animator;
653 }
654
655 private void onAnimationEnd() {
Vadim Caen311fef72019-11-05 14:53:06 +0100656 synchronized (mService.mGlobalLock) {
657 if (isAnimating()) {
658 ProtoLog.v(WM_DEBUG_ORIENTATION,
659 "ScreenRotation sill animating: mDisplayAnimator: %s\n"
660 + "mEnterBlackFrameAnimator: "
661 + "%s\nmRotateScreenAnimator: %s\n"
662 + "mScreenshotRotationAnimator: %s",
663 mDisplayAnimator != null
664 ? mDisplayAnimator.isAnimating() : null,
665 mEnterBlackFrameAnimator != null
666 ? mEnterBlackFrameAnimator.isAnimating() : null,
667 mRotateScreenAnimator != null
668 ? mRotateScreenAnimator.isAnimating() : null,
669 mScreenshotRotationAnimator != null
670 ? mScreenshotRotationAnimator.isAnimating() : null
671 );
672 return;
673 }
674 ProtoLog.d(WM_DEBUG_ORIENTATION, "ScreenRotationAnimation onAnimationEnd");
675 mEnterBlackFrameAnimator = null;
676 mScreenshotRotationAnimator = null;
677 mRotateScreenAnimator = null;
678 mService.mAnimator.mBulkUpdateParams |= WindowSurfacePlacer.SET_UPDATE_ROTATION;
679 kill();
680 mService.updateRotation(false, false);
681 AccessibilityController accessibilityController = mService.mAccessibilityController;
Vadim Caenf8474262019-08-12 17:52:01 +0200682
Vadim Caen311fef72019-11-05 14:53:06 +0100683 if (accessibilityController != null) {
684 // We just finished rotation animation which means we did not
685 // announce the rotation and waited for it to end, announce now.
686 accessibilityController.onRotationChangedLocked(mDisplayContent);
687 }
Vadim Caenf8474262019-08-12 17:52:01 +0200688 }
689 }
690
691 public void cancel() {
692 if (mEnterBlackFrameAnimator != null) {
693 mEnterBlackFrameAnimator.cancelAnimation();
694 }
695
696 if (mScreenshotRotationAnimator != null) {
697 mScreenshotRotationAnimator.cancelAnimation();
698 }
699
700 if (mRotateScreenAnimator != null) {
701 mRotateScreenAnimator.cancelAnimation();
702 }
703
704 if (mDisplayAnimator != null) {
705 mDisplayAnimator.cancelAnimation();
706 }
707 }
708
709 public boolean isAnimating() {
710 return mDisplayAnimator != null && mDisplayAnimator.isAnimating()
711 || mEnterBlackFrameAnimator != null && mEnterBlackFrameAnimator.isAnimating()
712 || mRotateScreenAnimator != null && mRotateScreenAnimator.isAnimating()
713 || mScreenshotRotationAnimator != null
714 && mScreenshotRotationAnimator.isAnimating();
715 }
716 }
Dianne Hackborna1111872010-11-23 20:55:11 -0800717}