blob: bef64b3bf0ff32dd1737ca8de5cdf610fea1f178 [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
17package com.android.server; // TODO: use com.android.server.wm, once things move there
18
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;
22import android.graphics.Color;
23import android.graphics.Matrix;
24import android.graphics.Paint;
25import android.graphics.PixelFormat;
Jeff Brown8db9ac42011-01-21 14:39:52 -080026import android.graphics.PorterDuff;
27import android.graphics.PorterDuffXfermode;
Dianne Hackborna1111872010-11-23 20:55:11 -080028import android.graphics.Rect;
29import android.util.DisplayMetrics;
30import android.util.Slog;
31import android.view.Display;
32import android.view.Surface;
33import android.view.SurfaceSession;
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080034import android.view.animation.Animation;
35import android.view.animation.AnimationUtils;
36import android.view.animation.Transformation;
Dianne Hackborna1111872010-11-23 20:55:11 -080037
38class ScreenRotationAnimation {
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080039 static final String TAG = "ScreenRotationAnimation";
40 static final boolean DEBUG = false;
Dianne Hackborna1111872010-11-23 20:55:11 -080041
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080042 final Context mContext;
43 final Display mDisplay;
Dianne Hackborna1111872010-11-23 20:55:11 -080044 Surface mSurface;
Dianne Hackborn352cc982011-01-04 11:34:18 -080045 Surface mBlackSurface;
Dianne Hackborna1111872010-11-23 20:55:11 -080046 int mWidth, mHeight;
47
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080048 int mSnapshotRotation;
49 int mSnapshotDeltaRotation;
50 int mOriginalRotation;
51 int mOriginalWidth, mOriginalHeight;
Dianne Hackborna1111872010-11-23 20:55:11 -080052 int mCurRotation;
Dianne Hackborna1111872010-11-23 20:55:11 -080053
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080054 Animation mExitAnimation;
55 final Transformation mExitTransformation = new Transformation();
56 Animation mEnterAnimation;
57 final Transformation mEnterTransformation = new Transformation();
58 boolean mStarted;
59
60 final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
61 final Matrix mSnapshotInitialMatrix = new Matrix();
62 final Matrix mSnapshotFinalMatrix = new Matrix();
Dianne Hackborna1111872010-11-23 20:55:11 -080063 final float[] mTmpFloats = new float[9];
64
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -080065 public ScreenRotationAnimation(Context context, Display display, SurfaceSession session,
66 boolean inTransaction) {
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080067 mContext = context;
68 mDisplay = display;
69
70 display.getMetrics(mDisplayMetrics);
Dianne Hackborna1111872010-11-23 20:55:11 -080071
72 Bitmap screenshot = Surface.screenshot(0, 0);
73
74 if (screenshot != null) {
75 // Screenshot does NOT include rotation!
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080076 mSnapshotRotation = 0;
Dianne Hackborna1111872010-11-23 20:55:11 -080077 mWidth = screenshot.getWidth();
78 mHeight = screenshot.getHeight();
79 } else {
80 // Just in case.
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080081 mSnapshotRotation = display.getRotation();
82 mWidth = mDisplayMetrics.widthPixels;
83 mHeight = mDisplayMetrics.heightPixels;
Dianne Hackborna1111872010-11-23 20:55:11 -080084 }
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);
100 mSurface.setLayer(WindowManagerService.TYPE_LAYER_MULTIPLIER * 200);
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 Hackborn94cb2eb2011-01-13 21:09:44 -0800105 if (false) {
106 try {
107 int size = mOriginalWidth > mOriginalHeight ? mOriginalWidth : mOriginalHeight;
108 mBlackSurface = new Surface(session, 0, "BlackSurface",
109 -1, size, size, PixelFormat.OPAQUE, Surface.FX_SURFACE_DIM);
110 mBlackSurface.setAlpha(1.0f);
111 mBlackSurface.setLayer(0);
112 } catch (Surface.OutOfResourcesException e) {
113 Slog.w(TAG, "Unable to allocate black surface", e);
114 }
Dianne Hackborn352cc982011-01-04 11:34:18 -0800115 }
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800116
117 setRotation(display.getRotation());
118
119 if (mSurface != null) {
120 Rect dirty = new Rect(0, 0, mWidth, mHeight);
121 Canvas c = null;
122 try {
123 c = mSurface.lockCanvas(dirty);
124 } catch (IllegalArgumentException e) {
125 Slog.w(TAG, "Unable to lock surface", e);
126 return;
127 } catch (Surface.OutOfResourcesException e) {
128 Slog.w(TAG, "Unable to lock surface", e);
129 return;
130 }
131 if (c == null) {
132 Slog.w(TAG, "Null surface");
133 return;
134 }
135
136 if (screenshot != null) {
Jeff Brown8db9ac42011-01-21 14:39:52 -0800137 Paint paint = new Paint(0);
138 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
139 c.drawBitmap(screenshot, 0, 0, paint);
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800140 } else {
Jeff Brown8db9ac42011-01-21 14:39:52 -0800141 c.drawColor(Color.GREEN, PorterDuff.Mode.SRC);
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800142 }
143
144 mSurface.unlockCanvasAndPost(c);
145 }
146 } finally {
147 if (!inTransaction) {
148 Surface.closeTransaction();
149 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
150 "<<< CLOSE TRANSACTION ScreenRotationAnimation");
Dianne Hackborn352cc982011-01-04 11:34:18 -0800151 }
152
153 if (screenshot != null) {
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800154 screenshot.recycle();
Dianne Hackborn352cc982011-01-04 11:34:18 -0800155 }
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800156 }
Dianne Hackborna1111872010-11-23 20:55:11 -0800157 }
158
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800159 static int deltaRotation(int oldRotation, int newRotation) {
160 int delta = newRotation - oldRotation;
Dianne Hackborna1111872010-11-23 20:55:11 -0800161 if (delta < 0) delta += 4;
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800162 return delta;
163 }
Dianne Hackborna1111872010-11-23 20:55:11 -0800164
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800165 void setSnapshotTransform(Matrix matrix, float alpha) {
Dianne Hackborn352cc982011-01-04 11:34:18 -0800166 if (mSurface != null) {
167 matrix.getValues(mTmpFloats);
168 mSurface.setPosition((int)mTmpFloats[Matrix.MTRANS_X],
169 (int)mTmpFloats[Matrix.MTRANS_Y]);
170 mSurface.setMatrix(
171 mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
172 mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
173 mSurface.setAlpha(alpha);
174 if (DEBUG) {
175 float[] srcPnts = new float[] { 0, 0, mWidth, mHeight };
176 float[] dstPnts = new float[4];
177 matrix.mapPoints(dstPnts, srcPnts);
178 Slog.i(TAG, "Original : (" + srcPnts[0] + "," + srcPnts[1]
179 + ")-(" + srcPnts[2] + "," + srcPnts[3] + ")");
180 Slog.i(TAG, "Transformed: (" + dstPnts[0] + "," + dstPnts[1]
181 + ")-(" + dstPnts[2] + "," + dstPnts[3] + ")");
182 }
Dianne Hackborna1111872010-11-23 20:55:11 -0800183 }
184 }
185
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800186 public static void createRotationMatrix(int rotation, int width, int height,
187 Matrix outMatrix) {
188 switch (rotation) {
189 case Surface.ROTATION_0:
190 outMatrix.reset();
191 break;
192 case Surface.ROTATION_90:
193 outMatrix.setRotate(90, 0, 0);
194 outMatrix.postTranslate(height, 0);
195 break;
196 case Surface.ROTATION_180:
197 outMatrix.setRotate(180, 0, 0);
198 outMatrix.postTranslate(width, height);
199 break;
200 case Surface.ROTATION_270:
201 outMatrix.setRotate(270, 0, 0);
202 outMatrix.postTranslate(0, width);
203 break;
204 }
205 }
206
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800207 // Must be called while in a transaction.
208 public void setRotation(int rotation) {
209 mCurRotation = rotation;
210
211 // Compute the transformation matrix that must be applied
212 // to the snapshot to make it stay in the same original position
213 // with the current screen rotation.
214 int delta = deltaRotation(rotation, mSnapshotRotation);
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800215 createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800216
217 if (DEBUG) Slog.v(TAG, "**** ROTATION: " + delta);
218 setSnapshotTransform(mSnapshotInitialMatrix, 1.0f);
219 }
220
221 /**
222 * Returns true if animating.
223 */
224 public boolean dismiss(long maxAnimationDuration, float animationScale) {
225 // Figure out how the screen has moved from the original rotation.
226 int delta = deltaRotation(mCurRotation, mOriginalRotation);
227 if (false && delta == 0) {
228 // Nothing changed, just remove the snapshot.
229 if (mSurface != null) {
230 mSurface.destroy();
231 mSurface = null;
232 }
233 return false;
234 }
235
236 switch (delta) {
237 case Surface.ROTATION_0:
238 mExitAnimation = AnimationUtils.loadAnimation(mContext,
239 com.android.internal.R.anim.screen_rotate_0_exit);
240 mEnterAnimation = AnimationUtils.loadAnimation(mContext,
241 com.android.internal.R.anim.screen_rotate_0_enter);
242 break;
243 case Surface.ROTATION_90:
244 mExitAnimation = AnimationUtils.loadAnimation(mContext,
245 com.android.internal.R.anim.screen_rotate_plus_90_exit);
246 mEnterAnimation = AnimationUtils.loadAnimation(mContext,
247 com.android.internal.R.anim.screen_rotate_plus_90_enter);
248 break;
249 case Surface.ROTATION_180:
250 mExitAnimation = AnimationUtils.loadAnimation(mContext,
251 com.android.internal.R.anim.screen_rotate_180_exit);
252 mEnterAnimation = AnimationUtils.loadAnimation(mContext,
253 com.android.internal.R.anim.screen_rotate_180_enter);
254 break;
255 case Surface.ROTATION_270:
256 mExitAnimation = AnimationUtils.loadAnimation(mContext,
257 com.android.internal.R.anim.screen_rotate_minus_90_exit);
258 mEnterAnimation = AnimationUtils.loadAnimation(mContext,
259 com.android.internal.R.anim.screen_rotate_minus_90_enter);
260 break;
261 }
262
263 mDisplay.getMetrics(mDisplayMetrics);
264
265 // Initialize the animations. This is a hack, redefining what "parent"
266 // means to allow supplying the last and next size. In this definition
267 // "%p" is the original (let's call it "previous") size, and "%" is the
268 // screen's current/new size.
269 mEnterAnimation.initialize(mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
270 mOriginalWidth, mOriginalHeight);
271 mExitAnimation.initialize(mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
272 mOriginalWidth, mOriginalHeight);
273 mStarted = false;
274
275 mExitAnimation.restrictDuration(maxAnimationDuration);
276 mExitAnimation.scaleCurrentDuration(animationScale);
277 mEnterAnimation.restrictDuration(maxAnimationDuration);
278 mEnterAnimation.scaleCurrentDuration(animationScale);
279
280 return true;
281 }
282
283 public void kill() {
284 if (mSurface != null) {
285 mSurface.destroy();
286 mSurface = null;
287 }
Dianne Hackborn352cc982011-01-04 11:34:18 -0800288 if (mBlackSurface != null) {
289 mBlackSurface.destroy();
290 mBlackSurface = null;
291 }
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800292 if (mExitAnimation != null) {
293 mExitAnimation.cancel();
294 mExitAnimation = null;
295 }
296 if (mEnterAnimation != null) {
297 mEnterAnimation.cancel();
298 mEnterAnimation = null;
299 }
300 }
301
302 public boolean isAnimating() {
303 return mEnterAnimation != null || mExitAnimation != null;
304 }
305
306 public boolean stepAnimation(long now) {
307 if (mEnterAnimation == null && mExitAnimation == null) {
308 return false;
309 }
310
311 if (!mStarted) {
312 mEnterAnimation.setStartTime(now);
313 mExitAnimation.setStartTime(now);
314 mStarted = true;
315 }
316
317 mExitTransformation.clear();
318 boolean moreExit = false;
319 if (mExitAnimation != null) {
320 moreExit = mExitAnimation.getTransformation(now, mExitTransformation);
321 if (DEBUG) Slog.v(TAG, "Stepped exit: " + mExitTransformation);
322 if (!moreExit) {
323 if (DEBUG) Slog.v(TAG, "Exit animation done!");
324 mExitAnimation.cancel();
325 mExitAnimation = null;
326 mExitTransformation.clear();
327 if (mSurface != null) {
328 mSurface.destroy();
329 mSurface = null;
330 }
Dianne Hackborn352cc982011-01-04 11:34:18 -0800331 if (mBlackSurface != null) {
332 mBlackSurface.destroy();
333 mBlackSurface = null;
334 }
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800335 }
336 }
337
338 mEnterTransformation.clear();
339 boolean moreEnter = false;
340 if (mEnterAnimation != null) {
341 moreEnter = mEnterAnimation.getTransformation(now, mEnterTransformation);
342 if (!moreEnter) {
343 mEnterAnimation.cancel();
344 mEnterAnimation = null;
345 mEnterTransformation.clear();
346 }
347 }
348
Dianne Hackborn352cc982011-01-04 11:34:18 -0800349 mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix);
350 setSnapshotTransform(mSnapshotFinalMatrix, mExitTransformation.getAlpha());
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800351
352 return moreEnter || moreExit;
353 }
354
355 public Transformation getEnterTransformation() {
356 return mEnterTransformation;
Dianne Hackborna1111872010-11-23 20:55:11 -0800357 }
358}