blob: 8fc9a70faad93dc0a33fcace7da629573dfbc8e7 [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
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080019import android.content.Context;
Dianne Hackborna1111872010-11-23 20:55:11 -080020import android.graphics.Bitmap;
21import android.graphics.Canvas;
Dianne Hackborna1111872010-11-23 20:55:11 -080022import android.graphics.Matrix;
23import android.graphics.Paint;
24import android.graphics.PixelFormat;
Jeff Brown8db9ac42011-01-21 14:39:52 -080025import android.graphics.PorterDuff;
26import android.graphics.PorterDuffXfermode;
Dianne Hackborna1111872010-11-23 20:55:11 -080027import android.graphics.Rect;
Dianne Hackborna1111872010-11-23 20:55:11 -080028import android.util.Slog;
Dianne Hackborna1111872010-11-23 20:55:11 -080029import android.view.Surface;
30import android.view.SurfaceSession;
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080031import android.view.animation.Animation;
32import android.view.animation.AnimationUtils;
33import android.view.animation.Transformation;
Dianne Hackborna1111872010-11-23 20:55:11 -080034
35class ScreenRotationAnimation {
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080036 static final String TAG = "ScreenRotationAnimation";
37 static final boolean DEBUG = false;
Dianne Hackborna1111872010-11-23 20:55:11 -080038
Dianne Hackborn50660e22011-02-02 17:12:25 -080039 static final int FREEZE_LAYER = WindowManagerService.TYPE_LAYER_MULTIPLIER * 200;
40
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080041 final Context mContext;
Dianne Hackborna1111872010-11-23 20:55:11 -080042 Surface mSurface;
Dianne Hackborn7916ac62011-05-16 20:45:48 -070043 BlackFrame mBlackFrame;
Dianne Hackborna1111872010-11-23 20:55:11 -080044 int mWidth, mHeight;
45
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080046 int mSnapshotRotation;
47 int mSnapshotDeltaRotation;
48 int mOriginalRotation;
49 int mOriginalWidth, mOriginalHeight;
Dianne Hackborna1111872010-11-23 20:55:11 -080050 int mCurRotation;
Dianne Hackborna1111872010-11-23 20:55:11 -080051
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080052 Animation mExitAnimation;
53 final Transformation mExitTransformation = new Transformation();
54 Animation mEnterAnimation;
55 final Transformation mEnterTransformation = new Transformation();
56 boolean mStarted;
57
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080058 final Matrix mSnapshotInitialMatrix = new Matrix();
59 final Matrix mSnapshotFinalMatrix = new Matrix();
Dianne Hackborn50660e22011-02-02 17:12:25 -080060 final Matrix mTmpMatrix = new Matrix();
Dianne Hackborna1111872010-11-23 20:55:11 -080061 final float[] mTmpFloats = new float[9];
62
Jeff Brownbc68a592011-07-25 12:58:12 -070063 public ScreenRotationAnimation(Context context, SurfaceSession session,
64 boolean inTransaction, int originalWidth, int originalHeight, int originalRotation) {
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080065 mContext = context;
Dianne Hackborna1111872010-11-23 20:55:11 -080066
Dianne Hackbornde75cb42011-03-02 17:11:21 -080067 // Screenshot does NOT include rotation!
68 mSnapshotRotation = 0;
Mathias Agopian0ab84ef2011-10-13 16:02:48 -070069 if (originalRotation == Surface.ROTATION_90
70 || originalRotation == Surface.ROTATION_270) {
71 mWidth = originalHeight;
72 mHeight = originalWidth;
73 } else {
74 mWidth = originalWidth;
75 mHeight = originalHeight;
76 }
Dianne Hackbornde75cb42011-03-02 17:11:21 -080077
Jeff Brownbc68a592011-07-25 12:58:12 -070078 mOriginalRotation = originalRotation;
79 mOriginalWidth = originalWidth;
80 mOriginalHeight = originalHeight;
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080081
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -080082 if (!inTransaction) {
Dianne Hackborn36991742011-10-11 21:35:26 -070083 if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -080084 ">>> OPEN TRANSACTION ScreenRotationAnimation");
85 Surface.openTransaction();
86 }
Dianne Hackborn352cc982011-01-04 11:34:18 -080087
Dianne Hackborna1111872010-11-23 20:55:11 -080088 try {
Dianne Hackborn352cc982011-01-04 11:34:18 -080089 try {
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -080090 mSurface = new Surface(session, 0, "FreezeSurface",
Mathias Agopiane65beaa2011-11-01 14:39:06 -070091 -1, mWidth, mHeight, PixelFormat.OPAQUE, Surface.FX_SURFACE_SCREENSHOT | Surface.HIDDEN);
Mathias Agopian0ab84ef2011-10-13 16:02:48 -070092 if (mSurface == null || !mSurface.isValid()) {
93 // Screenshot failed, punt.
94 mSurface = null;
95 return;
96 }
Dianne Hackborn50660e22011-02-02 17:12:25 -080097 mSurface.setLayer(FREEZE_LAYER + 1);
Mathias Agopiane65beaa2011-11-01 14:39:06 -070098 mSurface.show();
Dianne Hackborn352cc982011-01-04 11:34:18 -080099 } catch (Surface.OutOfResourcesException e) {
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800100 Slog.w(TAG, "Unable to allocate freeze surface", e);
Dianne Hackborn352cc982011-01-04 11:34:18 -0800101 }
Dianne Hackborna1111872010-11-23 20:55:11 -0800102
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700103 if (WindowManagerService.SHOW_TRANSACTIONS ||
104 WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
105 " FREEZE " + mSurface + ": CREATE");
106
Jeff Brownbc68a592011-07-25 12:58:12 -0700107 setRotation(originalRotation);
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800108 } finally {
109 if (!inTransaction) {
110 Surface.closeTransaction();
Dianne Hackborn36991742011-10-11 21:35:26 -0700111 if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800112 "<<< CLOSE TRANSACTION ScreenRotationAnimation");
Dianne Hackborn352cc982011-01-04 11:34:18 -0800113 }
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800114 }
Dianne Hackborna1111872010-11-23 20:55:11 -0800115 }
116
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800117 boolean hasScreenshot() {
118 return mSurface != null;
119 }
120
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800121 static int deltaRotation(int oldRotation, int newRotation) {
122 int delta = newRotation - oldRotation;
Dianne Hackborna1111872010-11-23 20:55:11 -0800123 if (delta < 0) delta += 4;
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800124 return delta;
125 }
Dianne Hackborna1111872010-11-23 20:55:11 -0800126
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800127 void setSnapshotTransform(Matrix matrix, float alpha) {
Dianne Hackborn352cc982011-01-04 11:34:18 -0800128 if (mSurface != null) {
129 matrix.getValues(mTmpFloats);
Dianne Hackbornd040edb2011-08-31 12:47:58 -0700130 mSurface.setPosition(mTmpFloats[Matrix.MTRANS_X],
131 mTmpFloats[Matrix.MTRANS_Y]);
Dianne Hackborn352cc982011-01-04 11:34:18 -0800132 mSurface.setMatrix(
133 mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
134 mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
135 mSurface.setAlpha(alpha);
136 if (DEBUG) {
137 float[] srcPnts = new float[] { 0, 0, mWidth, mHeight };
138 float[] dstPnts = new float[4];
139 matrix.mapPoints(dstPnts, srcPnts);
140 Slog.i(TAG, "Original : (" + srcPnts[0] + "," + srcPnts[1]
141 + ")-(" + srcPnts[2] + "," + srcPnts[3] + ")");
142 Slog.i(TAG, "Transformed: (" + dstPnts[0] + "," + dstPnts[1]
143 + ")-(" + dstPnts[2] + "," + dstPnts[3] + ")");
144 }
Dianne Hackborna1111872010-11-23 20:55:11 -0800145 }
146 }
147
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800148 public static void createRotationMatrix(int rotation, int width, int height,
149 Matrix outMatrix) {
150 switch (rotation) {
151 case Surface.ROTATION_0:
152 outMatrix.reset();
153 break;
154 case Surface.ROTATION_90:
155 outMatrix.setRotate(90, 0, 0);
156 outMatrix.postTranslate(height, 0);
157 break;
158 case Surface.ROTATION_180:
159 outMatrix.setRotate(180, 0, 0);
160 outMatrix.postTranslate(width, height);
161 break;
162 case Surface.ROTATION_270:
163 outMatrix.setRotate(270, 0, 0);
164 outMatrix.postTranslate(0, width);
165 break;
166 }
167 }
168
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800169 // Must be called while in a transaction.
170 public void setRotation(int rotation) {
171 mCurRotation = rotation;
172
173 // Compute the transformation matrix that must be applied
174 // to the snapshot to make it stay in the same original position
175 // with the current screen rotation.
176 int delta = deltaRotation(rotation, mSnapshotRotation);
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800177 createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800178
179 if (DEBUG) Slog.v(TAG, "**** ROTATION: " + delta);
180 setSnapshotTransform(mSnapshotInitialMatrix, 1.0f);
181 }
182
183 /**
184 * Returns true if animating.
185 */
Dianne Hackborn50660e22011-02-02 17:12:25 -0800186 public boolean dismiss(SurfaceSession session, long maxAnimationDuration,
Jeff Brownbc68a592011-07-25 12:58:12 -0700187 float animationScale, int finalWidth, int finalHeight) {
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800188 if (mSurface == null) {
189 // Can't do animation.
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800190 return false;
191 }
192
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800193 // Figure out how the screen has moved from the original rotation.
194 int delta = deltaRotation(mCurRotation, mOriginalRotation);
195
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800196 switch (delta) {
197 case Surface.ROTATION_0:
198 mExitAnimation = AnimationUtils.loadAnimation(mContext,
199 com.android.internal.R.anim.screen_rotate_0_exit);
200 mEnterAnimation = AnimationUtils.loadAnimation(mContext,
201 com.android.internal.R.anim.screen_rotate_0_enter);
202 break;
203 case Surface.ROTATION_90:
204 mExitAnimation = AnimationUtils.loadAnimation(mContext,
205 com.android.internal.R.anim.screen_rotate_plus_90_exit);
206 mEnterAnimation = AnimationUtils.loadAnimation(mContext,
207 com.android.internal.R.anim.screen_rotate_plus_90_enter);
208 break;
209 case Surface.ROTATION_180:
210 mExitAnimation = AnimationUtils.loadAnimation(mContext,
211 com.android.internal.R.anim.screen_rotate_180_exit);
212 mEnterAnimation = AnimationUtils.loadAnimation(mContext,
213 com.android.internal.R.anim.screen_rotate_180_enter);
214 break;
215 case Surface.ROTATION_270:
216 mExitAnimation = AnimationUtils.loadAnimation(mContext,
217 com.android.internal.R.anim.screen_rotate_minus_90_exit);
218 mEnterAnimation = AnimationUtils.loadAnimation(mContext,
219 com.android.internal.R.anim.screen_rotate_minus_90_enter);
220 break;
221 }
222
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800223 // Initialize the animations. This is a hack, redefining what "parent"
224 // means to allow supplying the last and next size. In this definition
225 // "%p" is the original (let's call it "previous") size, and "%" is the
226 // screen's current/new size.
Jeff Brownbc68a592011-07-25 12:58:12 -0700227 mEnterAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
228 mExitAnimation.initialize(finalWidth, finalHeight, mOriginalWidth, mOriginalHeight);
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800229 mStarted = false;
230
231 mExitAnimation.restrictDuration(maxAnimationDuration);
232 mExitAnimation.scaleCurrentDuration(animationScale);
233 mEnterAnimation.restrictDuration(maxAnimationDuration);
234 mEnterAnimation.scaleCurrentDuration(animationScale);
235
Dianne Hackborn36991742011-10-11 21:35:26 -0700236 if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
Dianne Hackborn50660e22011-02-02 17:12:25 -0800237 ">>> OPEN TRANSACTION ScreenRotationAnimation.dismiss");
238 Surface.openTransaction();
239
Dianne Hackborn50660e22011-02-02 17:12:25 -0800240 try {
Jeff Brownbc68a592011-07-25 12:58:12 -0700241 Rect outer = new Rect(-finalWidth, -finalHeight, finalWidth * 2, finalHeight * 2);
242 Rect inner = new Rect(0, 0, finalWidth, finalHeight);
Dianne Hackborn7916ac62011-05-16 20:45:48 -0700243 mBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER);
Dianne Hackborn50660e22011-02-02 17:12:25 -0800244 } catch (Surface.OutOfResourcesException e) {
245 Slog.w(TAG, "Unable to allocate black surface", e);
246 } finally {
247 Surface.closeTransaction();
Dianne Hackborn36991742011-10-11 21:35:26 -0700248 if (WindowManagerService.SHOW_LIGHT_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
Dianne Hackborn50660e22011-02-02 17:12:25 -0800249 "<<< CLOSE TRANSACTION ScreenRotationAnimation.dismiss");
250 }
251
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800252 return true;
253 }
254
255 public void kill() {
256 if (mSurface != null) {
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700257 if (WindowManagerService.SHOW_TRANSACTIONS ||
258 WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
259 " FREEZE " + mSurface + ": DESTROY");
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800260 mSurface.destroy();
261 mSurface = null;
262 }
Dianne Hackborn7916ac62011-05-16 20:45:48 -0700263 if (mBlackFrame != null) {
264 mBlackFrame.kill();
Dianne Hackborn352cc982011-01-04 11:34:18 -0800265 }
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800266 if (mExitAnimation != null) {
267 mExitAnimation.cancel();
268 mExitAnimation = null;
269 }
270 if (mEnterAnimation != null) {
271 mEnterAnimation.cancel();
272 mEnterAnimation = null;
273 }
274 }
275
276 public boolean isAnimating() {
277 return mEnterAnimation != null || mExitAnimation != null;
278 }
279
280 public boolean stepAnimation(long now) {
281 if (mEnterAnimation == null && mExitAnimation == null) {
282 return false;
283 }
284
285 if (!mStarted) {
Dianne Hackborn89620282011-09-11 12:47:45 -0700286 if (mEnterAnimation != null) {
287 mEnterAnimation.setStartTime(now);
288 }
289 if (mExitAnimation != null) {
290 mExitAnimation.setStartTime(now);
291 }
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800292 mStarted = true;
293 }
294
295 mExitTransformation.clear();
296 boolean moreExit = false;
297 if (mExitAnimation != null) {
298 moreExit = mExitAnimation.getTransformation(now, mExitTransformation);
299 if (DEBUG) Slog.v(TAG, "Stepped exit: " + mExitTransformation);
300 if (!moreExit) {
301 if (DEBUG) Slog.v(TAG, "Exit animation done!");
302 mExitAnimation.cancel();
303 mExitAnimation = null;
304 mExitTransformation.clear();
305 if (mSurface != null) {
Dianne Hackborn50660e22011-02-02 17:12:25 -0800306 mSurface.hide();
Dianne Hackborn352cc982011-01-04 11:34:18 -0800307 }
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800308 }
309 }
310
311 mEnterTransformation.clear();
312 boolean moreEnter = false;
313 if (mEnterAnimation != null) {
314 moreEnter = mEnterAnimation.getTransformation(now, mEnterTransformation);
315 if (!moreEnter) {
316 mEnterAnimation.cancel();
317 mEnterAnimation = null;
318 mEnterTransformation.clear();
Dianne Hackborn7916ac62011-05-16 20:45:48 -0700319 if (mBlackFrame != null) {
320 mBlackFrame.hide();
Dianne Hackborn50660e22011-02-02 17:12:25 -0800321 }
322 } else {
Dianne Hackborn7916ac62011-05-16 20:45:48 -0700323 if (mBlackFrame != null) {
324 mBlackFrame.setMatrix(mEnterTransformation.getMatrix());
Dianne Hackborn50660e22011-02-02 17:12:25 -0800325 }
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800326 }
327 }
328
Dianne Hackborn352cc982011-01-04 11:34:18 -0800329 mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix);
330 setSnapshotTransform(mSnapshotFinalMatrix, mExitTransformation.getAlpha());
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800331
332 return moreEnter || moreExit;
333 }
334
335 public Transformation getEnterTransformation() {
336 return mEnterTransformation;
Dianne Hackborna1111872010-11-23 20:55:11 -0800337 }
338}