blob: fbf1ec3b095f50bdde5bf6d36a6f4e2093abe3b6 [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;
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 Hackborn50660e22011-02-02 17:12:25 -080042 static final int FREEZE_LAYER = WindowManagerService.TYPE_LAYER_MULTIPLIER * 200;
43
44 class BlackSurface {
45 final int left;
46 final int top;
47 final Surface surface;
48
49 BlackSurface(SurfaceSession session, int layer, int l, int t, int w, int h)
50 throws Surface.OutOfResourcesException {
51 left = l;
52 top = t;
53 surface = new Surface(session, 0, "BlackSurface",
54 -1, w, h, PixelFormat.OPAQUE, Surface.FX_SURFACE_DIM);
55 surface.setAlpha(1.0f);
56 surface.setLayer(FREEZE_LAYER);
57 }
58
59 void setMatrix(Matrix matrix) {
60 mTmpMatrix.setTranslate(left, top);
61 mTmpMatrix.postConcat(matrix);
62 mTmpMatrix.getValues(mTmpFloats);
63 surface.setPosition((int)mTmpFloats[Matrix.MTRANS_X],
64 (int)mTmpFloats[Matrix.MTRANS_Y]);
65 surface.setMatrix(
66 mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
67 mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
68 if (false) {
69 Slog.i(TAG, "Black Surface @ (" + left + "," + top + "): ("
70 + mTmpFloats[Matrix.MTRANS_X] + ","
71 + mTmpFloats[Matrix.MTRANS_Y] + ") matrix=["
72 + mTmpFloats[Matrix.MSCALE_X] + ","
73 + mTmpFloats[Matrix.MSCALE_Y] + "]["
74 + mTmpFloats[Matrix.MSKEW_X] + ","
75 + mTmpFloats[Matrix.MSKEW_Y] + "]");
76 }
77 }
78 }
79
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080080 final Context mContext;
81 final Display mDisplay;
Dianne Hackborna1111872010-11-23 20:55:11 -080082 Surface mSurface;
Dianne Hackborn50660e22011-02-02 17:12:25 -080083 BlackSurface[] mBlackSurfaces;
Dianne Hackborna1111872010-11-23 20:55:11 -080084 int mWidth, mHeight;
85
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080086 int mSnapshotRotation;
87 int mSnapshotDeltaRotation;
88 int mOriginalRotation;
89 int mOriginalWidth, mOriginalHeight;
Dianne Hackborna1111872010-11-23 20:55:11 -080090 int mCurRotation;
Dianne Hackborna1111872010-11-23 20:55:11 -080091
Dianne Hackbornf9d0be92010-11-24 12:35:25 -080092 Animation mExitAnimation;
93 final Transformation mExitTransformation = new Transformation();
94 Animation mEnterAnimation;
95 final Transformation mEnterTransformation = new Transformation();
96 boolean mStarted;
97
98 final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
99 final Matrix mSnapshotInitialMatrix = new Matrix();
100 final Matrix mSnapshotFinalMatrix = new Matrix();
Dianne Hackborn50660e22011-02-02 17:12:25 -0800101 final Matrix mTmpMatrix = new Matrix();
Dianne Hackborna1111872010-11-23 20:55:11 -0800102 final float[] mTmpFloats = new float[9];
103
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800104 public ScreenRotationAnimation(Context context, Display display, SurfaceSession session,
105 boolean inTransaction) {
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800106 mContext = context;
107 mDisplay = display;
108
109 display.getMetrics(mDisplayMetrics);
Dianne Hackborna1111872010-11-23 20:55:11 -0800110
111 Bitmap screenshot = Surface.screenshot(0, 0);
112
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800113 if (screenshot == null) {
114 // Device is not capable of screenshots... we can't do an animation.
115 return;
Dianne Hackborna1111872010-11-23 20:55:11 -0800116 }
117
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800118 // Screenshot does NOT include rotation!
119 mSnapshotRotation = 0;
120 mWidth = screenshot.getWidth();
121 mHeight = screenshot.getHeight();
122
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800123 mOriginalRotation = display.getRotation();
124 mOriginalWidth = mDisplayMetrics.widthPixels;
125 mOriginalHeight = mDisplayMetrics.heightPixels;
126
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800127 if (!inTransaction) {
128 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
129 ">>> OPEN TRANSACTION ScreenRotationAnimation");
130 Surface.openTransaction();
131 }
Dianne Hackborn352cc982011-01-04 11:34:18 -0800132
Dianne Hackborna1111872010-11-23 20:55:11 -0800133 try {
Dianne Hackborn352cc982011-01-04 11:34:18 -0800134 try {
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800135 mSurface = new Surface(session, 0, "FreezeSurface",
136 -1, mWidth, mHeight, PixelFormat.OPAQUE, 0);
Dianne Hackborn50660e22011-02-02 17:12:25 -0800137 mSurface.setLayer(FREEZE_LAYER + 1);
Dianne Hackborn352cc982011-01-04 11:34:18 -0800138 } catch (Surface.OutOfResourcesException e) {
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800139 Slog.w(TAG, "Unable to allocate freeze surface", e);
Dianne Hackborn352cc982011-01-04 11:34:18 -0800140 }
Dianne Hackborna1111872010-11-23 20:55:11 -0800141
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800142 setRotation(display.getRotation());
143
144 if (mSurface != null) {
145 Rect dirty = new Rect(0, 0, mWidth, mHeight);
146 Canvas c = null;
147 try {
148 c = mSurface.lockCanvas(dirty);
149 } catch (IllegalArgumentException e) {
150 Slog.w(TAG, "Unable to lock surface", e);
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800151 } catch (Surface.OutOfResourcesException e) {
152 Slog.w(TAG, "Unable to lock surface", e);
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800153 }
154 if (c == null) {
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800155 Slog.w(TAG, "Null surface canvas");
156 mSurface.destroy();
157 mSurface = null;
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800158 return;
159 }
160
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800161 Paint paint = new Paint(0);
162 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
163 c.drawBitmap(screenshot, 0, 0, paint);
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800164
165 mSurface.unlockCanvasAndPost(c);
166 }
167 } finally {
168 if (!inTransaction) {
169 Surface.closeTransaction();
170 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
171 "<<< CLOSE TRANSACTION ScreenRotationAnimation");
Dianne Hackborn352cc982011-01-04 11:34:18 -0800172 }
173
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800174 screenshot.recycle();
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800175 }
Dianne Hackborna1111872010-11-23 20:55:11 -0800176 }
177
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800178 boolean hasScreenshot() {
179 return mSurface != null;
180 }
181
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800182 static int deltaRotation(int oldRotation, int newRotation) {
183 int delta = newRotation - oldRotation;
Dianne Hackborna1111872010-11-23 20:55:11 -0800184 if (delta < 0) delta += 4;
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800185 return delta;
186 }
Dianne Hackborna1111872010-11-23 20:55:11 -0800187
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800188 void setSnapshotTransform(Matrix matrix, float alpha) {
Dianne Hackborn352cc982011-01-04 11:34:18 -0800189 if (mSurface != null) {
190 matrix.getValues(mTmpFloats);
191 mSurface.setPosition((int)mTmpFloats[Matrix.MTRANS_X],
192 (int)mTmpFloats[Matrix.MTRANS_Y]);
193 mSurface.setMatrix(
194 mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
195 mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
196 mSurface.setAlpha(alpha);
197 if (DEBUG) {
198 float[] srcPnts = new float[] { 0, 0, mWidth, mHeight };
199 float[] dstPnts = new float[4];
200 matrix.mapPoints(dstPnts, srcPnts);
201 Slog.i(TAG, "Original : (" + srcPnts[0] + "," + srcPnts[1]
202 + ")-(" + srcPnts[2] + "," + srcPnts[3] + ")");
203 Slog.i(TAG, "Transformed: (" + dstPnts[0] + "," + dstPnts[1]
204 + ")-(" + dstPnts[2] + "," + dstPnts[3] + ")");
205 }
Dianne Hackborna1111872010-11-23 20:55:11 -0800206 }
207 }
208
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800209 public static void createRotationMatrix(int rotation, int width, int height,
210 Matrix outMatrix) {
211 switch (rotation) {
212 case Surface.ROTATION_0:
213 outMatrix.reset();
214 break;
215 case Surface.ROTATION_90:
216 outMatrix.setRotate(90, 0, 0);
217 outMatrix.postTranslate(height, 0);
218 break;
219 case Surface.ROTATION_180:
220 outMatrix.setRotate(180, 0, 0);
221 outMatrix.postTranslate(width, height);
222 break;
223 case Surface.ROTATION_270:
224 outMatrix.setRotate(270, 0, 0);
225 outMatrix.postTranslate(0, width);
226 break;
227 }
228 }
229
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800230 // Must be called while in a transaction.
231 public void setRotation(int rotation) {
232 mCurRotation = rotation;
233
234 // Compute the transformation matrix that must be applied
235 // to the snapshot to make it stay in the same original position
236 // with the current screen rotation.
237 int delta = deltaRotation(rotation, mSnapshotRotation);
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800238 createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800239
240 if (DEBUG) Slog.v(TAG, "**** ROTATION: " + delta);
241 setSnapshotTransform(mSnapshotInitialMatrix, 1.0f);
242 }
243
244 /**
245 * Returns true if animating.
246 */
Dianne Hackborn50660e22011-02-02 17:12:25 -0800247 public boolean dismiss(SurfaceSession session, long maxAnimationDuration,
248 float animationScale) {
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800249 if (mSurface == null) {
250 // Can't do animation.
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800251 return false;
252 }
253
Dianne Hackbornde75cb42011-03-02 17:11:21 -0800254 // Figure out how the screen has moved from the original rotation.
255 int delta = deltaRotation(mCurRotation, mOriginalRotation);
256
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800257 switch (delta) {
258 case Surface.ROTATION_0:
259 mExitAnimation = AnimationUtils.loadAnimation(mContext,
260 com.android.internal.R.anim.screen_rotate_0_exit);
261 mEnterAnimation = AnimationUtils.loadAnimation(mContext,
262 com.android.internal.R.anim.screen_rotate_0_enter);
263 break;
264 case Surface.ROTATION_90:
265 mExitAnimation = AnimationUtils.loadAnimation(mContext,
266 com.android.internal.R.anim.screen_rotate_plus_90_exit);
267 mEnterAnimation = AnimationUtils.loadAnimation(mContext,
268 com.android.internal.R.anim.screen_rotate_plus_90_enter);
269 break;
270 case Surface.ROTATION_180:
271 mExitAnimation = AnimationUtils.loadAnimation(mContext,
272 com.android.internal.R.anim.screen_rotate_180_exit);
273 mEnterAnimation = AnimationUtils.loadAnimation(mContext,
274 com.android.internal.R.anim.screen_rotate_180_enter);
275 break;
276 case Surface.ROTATION_270:
277 mExitAnimation = AnimationUtils.loadAnimation(mContext,
278 com.android.internal.R.anim.screen_rotate_minus_90_exit);
279 mEnterAnimation = AnimationUtils.loadAnimation(mContext,
280 com.android.internal.R.anim.screen_rotate_minus_90_enter);
281 break;
282 }
283
284 mDisplay.getMetrics(mDisplayMetrics);
285
286 // Initialize the animations. This is a hack, redefining what "parent"
287 // means to allow supplying the last and next size. In this definition
288 // "%p" is the original (let's call it "previous") size, and "%" is the
289 // screen's current/new size.
290 mEnterAnimation.initialize(mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
291 mOriginalWidth, mOriginalHeight);
292 mExitAnimation.initialize(mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
293 mOriginalWidth, mOriginalHeight);
294 mStarted = false;
295
296 mExitAnimation.restrictDuration(maxAnimationDuration);
297 mExitAnimation.scaleCurrentDuration(animationScale);
298 mEnterAnimation.restrictDuration(maxAnimationDuration);
299 mEnterAnimation.scaleCurrentDuration(animationScale);
300
Dianne Hackborn50660e22011-02-02 17:12:25 -0800301 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
302 ">>> OPEN TRANSACTION ScreenRotationAnimation.dismiss");
303 Surface.openTransaction();
304
305 mBlackSurfaces = new BlackSurface[4];
306 try {
307 final int w = mDisplayMetrics.widthPixels;
308 final int h = mDisplayMetrics.heightPixels;
309 mBlackSurfaces[0] = new BlackSurface(session, FREEZE_LAYER, -w, -h, w, h*2);
310 mBlackSurfaces[1] = new BlackSurface(session, FREEZE_LAYER, 0, -h, w*2, h);
311 mBlackSurfaces[2] = new BlackSurface(session, FREEZE_LAYER, w, 0, w, h*2);
312 mBlackSurfaces[3] = new BlackSurface(session, FREEZE_LAYER, -w, h, w*2, h);
313 } catch (Surface.OutOfResourcesException e) {
314 Slog.w(TAG, "Unable to allocate black surface", e);
315 } finally {
316 Surface.closeTransaction();
317 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
318 "<<< CLOSE TRANSACTION ScreenRotationAnimation.dismiss");
319 }
320
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800321 return true;
322 }
323
324 public void kill() {
325 if (mSurface != null) {
326 mSurface.destroy();
327 mSurface = null;
328 }
Dianne Hackborn50660e22011-02-02 17:12:25 -0800329 if (mBlackSurfaces != null) {
330 for (int i=0; i<mBlackSurfaces.length; i++) {
331 if (mBlackSurfaces[i] != null) {
332 mBlackSurfaces[i].surface.destroy();
333 }
334 }
335 mBlackSurfaces = null;
Dianne Hackborn352cc982011-01-04 11:34:18 -0800336 }
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800337 if (mExitAnimation != null) {
338 mExitAnimation.cancel();
339 mExitAnimation = null;
340 }
341 if (mEnterAnimation != null) {
342 mEnterAnimation.cancel();
343 mEnterAnimation = null;
344 }
345 }
346
347 public boolean isAnimating() {
348 return mEnterAnimation != null || mExitAnimation != null;
349 }
350
351 public boolean stepAnimation(long now) {
352 if (mEnterAnimation == null && mExitAnimation == null) {
353 return false;
354 }
355
356 if (!mStarted) {
357 mEnterAnimation.setStartTime(now);
358 mExitAnimation.setStartTime(now);
359 mStarted = true;
360 }
361
362 mExitTransformation.clear();
363 boolean moreExit = false;
364 if (mExitAnimation != null) {
365 moreExit = mExitAnimation.getTransformation(now, mExitTransformation);
366 if (DEBUG) Slog.v(TAG, "Stepped exit: " + mExitTransformation);
367 if (!moreExit) {
368 if (DEBUG) Slog.v(TAG, "Exit animation done!");
369 mExitAnimation.cancel();
370 mExitAnimation = null;
371 mExitTransformation.clear();
372 if (mSurface != null) {
Dianne Hackborn50660e22011-02-02 17:12:25 -0800373 mSurface.hide();
Dianne Hackborn352cc982011-01-04 11:34:18 -0800374 }
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800375 }
376 }
377
378 mEnterTransformation.clear();
379 boolean moreEnter = false;
380 if (mEnterAnimation != null) {
381 moreEnter = mEnterAnimation.getTransformation(now, mEnterTransformation);
382 if (!moreEnter) {
383 mEnterAnimation.cancel();
384 mEnterAnimation = null;
385 mEnterTransformation.clear();
Dianne Hackborn50660e22011-02-02 17:12:25 -0800386 if (mBlackSurfaces != null) {
387 for (int i=0; i<mBlackSurfaces.length; i++) {
388 if (mBlackSurfaces[i] != null) {
389 mBlackSurfaces[i].surface.hide();
390 }
391 }
392 }
393 } else {
394 if (mBlackSurfaces != null) {
395 for (int i=0; i<mBlackSurfaces.length; i++) {
396 if (mBlackSurfaces[i] != null) {
397 mBlackSurfaces[i].setMatrix(mEnterTransformation.getMatrix());
398 }
399 }
400 }
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800401 }
402 }
403
Dianne Hackborn352cc982011-01-04 11:34:18 -0800404 mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix);
405 setSnapshotTransform(mSnapshotFinalMatrix, mExitTransformation.getAlpha());
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800406
407 return moreEnter || moreExit;
408 }
409
410 public Transformation getEnterTransformation() {
411 return mEnterTransformation;
Dianne Hackborna1111872010-11-23 20:55:11 -0800412 }
413}