blob: 847091843c526c94b2d4f8d5d055e4ebfd56f0e1 [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;
28import android.util.DisplayMetrics;
29import android.util.Slog;
30import android.view.Display;
31import android.view.Surface;
32import android.view.SurfaceSession;
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080033import android.view.animation.Animation;
34import android.view.animation.AnimationUtils;
35import android.view.animation.Transformation;
Dianne Hackborna1111872010-11-23 20:55:11 -080036
37class ScreenRotationAnimation {
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080038 static final String TAG = "ScreenRotationAnimation";
39 static final boolean DEBUG = false;
Dianne Hackborna1111872010-11-23 20:55:11 -080040
Dianne Hackborn50660e22011-02-02 17:12:25 -080041 static final int FREEZE_LAYER = WindowManagerService.TYPE_LAYER_MULTIPLIER * 200;
42
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080043 final Context mContext;
44 final Display mDisplay;
Dianne Hackborna1111872010-11-23 20:55:11 -080045 Surface mSurface;
Dianne Hackborn7916ac62011-05-16 20:45:48 -070046 BlackFrame mBlackFrame;
Dianne Hackborna1111872010-11-23 20:55:11 -080047 int mWidth, mHeight;
48
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080049 int mSnapshotRotation;
50 int mSnapshotDeltaRotation;
51 int mOriginalRotation;
52 int mOriginalWidth, mOriginalHeight;
Dianne Hackborna1111872010-11-23 20:55:11 -080053 int mCurRotation;
Dianne Hackborna1111872010-11-23 20:55:11 -080054
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080055 Animation mExitAnimation;
56 final Transformation mExitTransformation = new Transformation();
57 Animation mEnterAnimation;
58 final Transformation mEnterTransformation = new Transformation();
59 boolean mStarted;
60
61 final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
62 final Matrix mSnapshotInitialMatrix = new Matrix();
63 final Matrix mSnapshotFinalMatrix = new Matrix();
Dianne Hackborn50660e22011-02-02 17:12:25 -080064 final Matrix mTmpMatrix = new Matrix();
Dianne Hackborna1111872010-11-23 20:55:11 -080065 final float[] mTmpFloats = new float[9];
66
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -080067 public ScreenRotationAnimation(Context context, Display display, SurfaceSession session,
68 boolean inTransaction) {
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080069 mContext = context;
70 mDisplay = display;
71
Dianne Hackborn78470712011-05-27 17:09:19 -070072 display.getRealMetrics(mDisplayMetrics);
Dianne Hackborna1111872010-11-23 20:55:11 -080073
74 Bitmap screenshot = Surface.screenshot(0, 0);
75
Dianne Hackbornde75cb42011-03-02 17:11:21 -080076 if (screenshot == null) {
77 // Device is not capable of screenshots... we can't do an animation.
78 return;
Dianne Hackborna1111872010-11-23 20:55:11 -080079 }
80
Dianne Hackbornde75cb42011-03-02 17:11:21 -080081 // Screenshot does NOT include rotation!
82 mSnapshotRotation = 0;
83 mWidth = screenshot.getWidth();
84 mHeight = screenshot.getHeight();
85
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080086 mOriginalRotation = display.getRotation();
87 mOriginalWidth = mDisplayMetrics.widthPixels;
88 mOriginalHeight = mDisplayMetrics.heightPixels;
89
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -080090 if (!inTransaction) {
91 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
92 ">>> OPEN TRANSACTION ScreenRotationAnimation");
93 Surface.openTransaction();
94 }
Dianne Hackborn352cc982011-01-04 11:34:18 -080095
Dianne Hackborna1111872010-11-23 20:55:11 -080096 try {
Dianne Hackborn352cc982011-01-04 11:34:18 -080097 try {
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -080098 mSurface = new Surface(session, 0, "FreezeSurface",
99 -1, mWidth, mHeight, PixelFormat.OPAQUE, 0);
Dianne Hackborn50660e22011-02-02 17:12:25 -0800100 mSurface.setLayer(FREEZE_LAYER + 1);
Dianne Hackborn352cc982011-01-04 11:34:18 -0800101 } catch (Surface.OutOfResourcesException e) {
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800102 Slog.w(TAG, "Unable to allocate freeze surface", e);
Dianne Hackborn352cc982011-01-04 11:34:18 -0800103 }
Dianne Hackborna1111872010-11-23 20:55:11 -0800104
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700105 if (WindowManagerService.SHOW_TRANSACTIONS ||
106 WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
107 " FREEZE " + mSurface + ": CREATE");
108
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800109 setRotation(display.getRotation());
110
111 if (mSurface != null) {
112 Rect dirty = new Rect(0, 0, mWidth, mHeight);
113 Canvas c = null;
114 try {
115 c = mSurface.lockCanvas(dirty);
116 } catch (IllegalArgumentException e) {
117 Slog.w(TAG, "Unable to lock surface", e);
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800118 } catch (Surface.OutOfResourcesException e) {
119 Slog.w(TAG, "Unable to lock surface", e);
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800120 }
121 if (c == null) {
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800122 Slog.w(TAG, "Null surface canvas");
123 mSurface.destroy();
124 mSurface = null;
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800125 return;
126 }
127
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800128 Paint paint = new Paint(0);
129 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
130 c.drawBitmap(screenshot, 0, 0, paint);
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800131
132 mSurface.unlockCanvasAndPost(c);
133 }
134 } finally {
135 if (!inTransaction) {
136 Surface.closeTransaction();
137 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
138 "<<< CLOSE TRANSACTION ScreenRotationAnimation");
Dianne Hackborn352cc982011-01-04 11:34:18 -0800139 }
140
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800141 screenshot.recycle();
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800142 }
Dianne Hackborna1111872010-11-23 20:55:11 -0800143 }
144
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800145 boolean hasScreenshot() {
146 return mSurface != null;
147 }
148
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800149 static int deltaRotation(int oldRotation, int newRotation) {
150 int delta = newRotation - oldRotation;
Dianne Hackborna1111872010-11-23 20:55:11 -0800151 if (delta < 0) delta += 4;
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800152 return delta;
153 }
Dianne Hackborna1111872010-11-23 20:55:11 -0800154
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800155 void setSnapshotTransform(Matrix matrix, float alpha) {
Dianne Hackborn352cc982011-01-04 11:34:18 -0800156 if (mSurface != null) {
157 matrix.getValues(mTmpFloats);
158 mSurface.setPosition((int)mTmpFloats[Matrix.MTRANS_X],
159 (int)mTmpFloats[Matrix.MTRANS_Y]);
160 mSurface.setMatrix(
161 mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
162 mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
163 mSurface.setAlpha(alpha);
164 if (DEBUG) {
165 float[] srcPnts = new float[] { 0, 0, mWidth, mHeight };
166 float[] dstPnts = new float[4];
167 matrix.mapPoints(dstPnts, srcPnts);
168 Slog.i(TAG, "Original : (" + srcPnts[0] + "," + srcPnts[1]
169 + ")-(" + srcPnts[2] + "," + srcPnts[3] + ")");
170 Slog.i(TAG, "Transformed: (" + dstPnts[0] + "," + dstPnts[1]
171 + ")-(" + dstPnts[2] + "," + dstPnts[3] + ")");
172 }
Dianne Hackborna1111872010-11-23 20:55:11 -0800173 }
174 }
175
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800176 public static void createRotationMatrix(int rotation, int width, int height,
177 Matrix outMatrix) {
178 switch (rotation) {
179 case Surface.ROTATION_0:
180 outMatrix.reset();
181 break;
182 case Surface.ROTATION_90:
183 outMatrix.setRotate(90, 0, 0);
184 outMatrix.postTranslate(height, 0);
185 break;
186 case Surface.ROTATION_180:
187 outMatrix.setRotate(180, 0, 0);
188 outMatrix.postTranslate(width, height);
189 break;
190 case Surface.ROTATION_270:
191 outMatrix.setRotate(270, 0, 0);
192 outMatrix.postTranslate(0, width);
193 break;
194 }
195 }
196
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800197 // Must be called while in a transaction.
198 public void setRotation(int rotation) {
199 mCurRotation = rotation;
200
201 // Compute the transformation matrix that must be applied
202 // to the snapshot to make it stay in the same original position
203 // with the current screen rotation.
204 int delta = deltaRotation(rotation, mSnapshotRotation);
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800205 createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800206
207 if (DEBUG) Slog.v(TAG, "**** ROTATION: " + delta);
208 setSnapshotTransform(mSnapshotInitialMatrix, 1.0f);
209 }
210
211 /**
212 * Returns true if animating.
213 */
Dianne Hackborn50660e22011-02-02 17:12:25 -0800214 public boolean dismiss(SurfaceSession session, long maxAnimationDuration,
215 float animationScale) {
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800216 if (mSurface == null) {
217 // Can't do animation.
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800218 return false;
219 }
220
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800221 // Figure out how the screen has moved from the original rotation.
222 int delta = deltaRotation(mCurRotation, mOriginalRotation);
223
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800224 switch (delta) {
225 case Surface.ROTATION_0:
226 mExitAnimation = AnimationUtils.loadAnimation(mContext,
227 com.android.internal.R.anim.screen_rotate_0_exit);
228 mEnterAnimation = AnimationUtils.loadAnimation(mContext,
229 com.android.internal.R.anim.screen_rotate_0_enter);
230 break;
231 case Surface.ROTATION_90:
232 mExitAnimation = AnimationUtils.loadAnimation(mContext,
233 com.android.internal.R.anim.screen_rotate_plus_90_exit);
234 mEnterAnimation = AnimationUtils.loadAnimation(mContext,
235 com.android.internal.R.anim.screen_rotate_plus_90_enter);
236 break;
237 case Surface.ROTATION_180:
238 mExitAnimation = AnimationUtils.loadAnimation(mContext,
239 com.android.internal.R.anim.screen_rotate_180_exit);
240 mEnterAnimation = AnimationUtils.loadAnimation(mContext,
241 com.android.internal.R.anim.screen_rotate_180_enter);
242 break;
243 case Surface.ROTATION_270:
244 mExitAnimation = AnimationUtils.loadAnimation(mContext,
245 com.android.internal.R.anim.screen_rotate_minus_90_exit);
246 mEnterAnimation = AnimationUtils.loadAnimation(mContext,
247 com.android.internal.R.anim.screen_rotate_minus_90_enter);
248 break;
249 }
250
Dianne Hackborn78470712011-05-27 17:09:19 -0700251 mDisplay.getRealMetrics(mDisplayMetrics);
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800252
253 // Initialize the animations. This is a hack, redefining what "parent"
254 // means to allow supplying the last and next size. In this definition
255 // "%p" is the original (let's call it "previous") size, and "%" is the
256 // screen's current/new size.
257 mEnterAnimation.initialize(mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
258 mOriginalWidth, mOriginalHeight);
259 mExitAnimation.initialize(mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
260 mOriginalWidth, mOriginalHeight);
261 mStarted = false;
262
263 mExitAnimation.restrictDuration(maxAnimationDuration);
264 mExitAnimation.scaleCurrentDuration(animationScale);
265 mEnterAnimation.restrictDuration(maxAnimationDuration);
266 mEnterAnimation.scaleCurrentDuration(animationScale);
267
Dianne Hackborn50660e22011-02-02 17:12:25 -0800268 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
269 ">>> OPEN TRANSACTION ScreenRotationAnimation.dismiss");
270 Surface.openTransaction();
271
Dianne Hackborn50660e22011-02-02 17:12:25 -0800272 try {
273 final int w = mDisplayMetrics.widthPixels;
274 final int h = mDisplayMetrics.heightPixels;
Dianne Hackborn7916ac62011-05-16 20:45:48 -0700275 Rect outer = new Rect(-w, -h, w*2, h*2);
276 Rect inner = new Rect(0, 0, w, h);
277 mBlackFrame = new BlackFrame(session, outer, inner, FREEZE_LAYER);
Dianne Hackborn50660e22011-02-02 17:12:25 -0800278 } catch (Surface.OutOfResourcesException e) {
279 Slog.w(TAG, "Unable to allocate black surface", e);
280 } finally {
281 Surface.closeTransaction();
282 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
283 "<<< CLOSE TRANSACTION ScreenRotationAnimation.dismiss");
284 }
285
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800286 return true;
287 }
288
289 public void kill() {
290 if (mSurface != null) {
Dianne Hackborn5fd21692011-06-07 14:09:47 -0700291 if (WindowManagerService.SHOW_TRANSACTIONS ||
292 WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
293 " FREEZE " + mSurface + ": DESTROY");
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800294 mSurface.destroy();
295 mSurface = null;
296 }
Dianne Hackborn7916ac62011-05-16 20:45:48 -0700297 if (mBlackFrame != null) {
298 mBlackFrame.kill();
Dianne Hackborn352cc982011-01-04 11:34:18 -0800299 }
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800300 if (mExitAnimation != null) {
301 mExitAnimation.cancel();
302 mExitAnimation = null;
303 }
304 if (mEnterAnimation != null) {
305 mEnterAnimation.cancel();
306 mEnterAnimation = null;
307 }
308 }
309
310 public boolean isAnimating() {
311 return mEnterAnimation != null || mExitAnimation != null;
312 }
313
314 public boolean stepAnimation(long now) {
315 if (mEnterAnimation == null && mExitAnimation == null) {
316 return false;
317 }
318
319 if (!mStarted) {
320 mEnterAnimation.setStartTime(now);
321 mExitAnimation.setStartTime(now);
322 mStarted = true;
323 }
324
325 mExitTransformation.clear();
326 boolean moreExit = false;
327 if (mExitAnimation != null) {
328 moreExit = mExitAnimation.getTransformation(now, mExitTransformation);
329 if (DEBUG) Slog.v(TAG, "Stepped exit: " + mExitTransformation);
330 if (!moreExit) {
331 if (DEBUG) Slog.v(TAG, "Exit animation done!");
332 mExitAnimation.cancel();
333 mExitAnimation = null;
334 mExitTransformation.clear();
335 if (mSurface != null) {
Dianne Hackborn50660e22011-02-02 17:12:25 -0800336 mSurface.hide();
Dianne Hackborn352cc982011-01-04 11:34:18 -0800337 }
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800338 }
339 }
340
341 mEnterTransformation.clear();
342 boolean moreEnter = false;
343 if (mEnterAnimation != null) {
344 moreEnter = mEnterAnimation.getTransformation(now, mEnterTransformation);
345 if (!moreEnter) {
346 mEnterAnimation.cancel();
347 mEnterAnimation = null;
348 mEnterTransformation.clear();
Dianne Hackborn7916ac62011-05-16 20:45:48 -0700349 if (mBlackFrame != null) {
350 mBlackFrame.hide();
Dianne Hackborn50660e22011-02-02 17:12:25 -0800351 }
352 } else {
Dianne Hackborn7916ac62011-05-16 20:45:48 -0700353 if (mBlackFrame != null) {
354 mBlackFrame.setMatrix(mEnterTransformation.getMatrix());
Dianne Hackborn50660e22011-02-02 17:12:25 -0800355 }
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800356 }
357 }
358
Dianne Hackborn352cc982011-01-04 11:34:18 -0800359 mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix);
360 setSnapshotTransform(mSnapshotFinalMatrix, mExitTransformation.getAlpha());
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800361
362 return moreEnter || moreExit;
363 }
364
365 public Transformation getEnterTransformation() {
366 return mEnterTransformation;
Dianne Hackborna1111872010-11-23 20:55:11 -0800367 }
368}