blob: 4356ce5ae427e85fe112edf264c38977d7ef3c14 [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
113 if (screenshot != null) {
114 // Screenshot does NOT include rotation!
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800115 mSnapshotRotation = 0;
Dianne Hackborna1111872010-11-23 20:55:11 -0800116 mWidth = screenshot.getWidth();
117 mHeight = screenshot.getHeight();
118 } else {
119 // Just in case.
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800120 mSnapshotRotation = display.getRotation();
121 mWidth = mDisplayMetrics.widthPixels;
122 mHeight = mDisplayMetrics.heightPixels;
Dianne Hackborna1111872010-11-23 20:55:11 -0800123 }
124
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800125 mOriginalRotation = display.getRotation();
126 mOriginalWidth = mDisplayMetrics.widthPixels;
127 mOriginalHeight = mDisplayMetrics.heightPixels;
128
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800129 if (!inTransaction) {
130 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
131 ">>> OPEN TRANSACTION ScreenRotationAnimation");
132 Surface.openTransaction();
133 }
Dianne Hackborn352cc982011-01-04 11:34:18 -0800134
Dianne Hackborna1111872010-11-23 20:55:11 -0800135 try {
Dianne Hackborn352cc982011-01-04 11:34:18 -0800136 try {
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800137 mSurface = new Surface(session, 0, "FreezeSurface",
138 -1, mWidth, mHeight, PixelFormat.OPAQUE, 0);
Dianne Hackborn50660e22011-02-02 17:12:25 -0800139 mSurface.setLayer(FREEZE_LAYER + 1);
Dianne Hackborn352cc982011-01-04 11:34:18 -0800140 } catch (Surface.OutOfResourcesException e) {
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800141 Slog.w(TAG, "Unable to allocate freeze surface", e);
Dianne Hackborn352cc982011-01-04 11:34:18 -0800142 }
Dianne Hackborna1111872010-11-23 20:55:11 -0800143
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800144 setRotation(display.getRotation());
145
146 if (mSurface != null) {
147 Rect dirty = new Rect(0, 0, mWidth, mHeight);
148 Canvas c = null;
149 try {
150 c = mSurface.lockCanvas(dirty);
151 } catch (IllegalArgumentException e) {
152 Slog.w(TAG, "Unable to lock surface", e);
153 return;
154 } catch (Surface.OutOfResourcesException e) {
155 Slog.w(TAG, "Unable to lock surface", e);
156 return;
157 }
158 if (c == null) {
159 Slog.w(TAG, "Null surface");
160 return;
161 }
162
163 if (screenshot != null) {
Jeff Brown8db9ac42011-01-21 14:39:52 -0800164 Paint paint = new Paint(0);
165 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
166 c.drawBitmap(screenshot, 0, 0, paint);
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800167 } else {
Dianne Hackborn50660e22011-02-02 17:12:25 -0800168 c.drawColor(Color.BLACK, PorterDuff.Mode.SRC);
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800169 }
170
171 mSurface.unlockCanvasAndPost(c);
172 }
173 } finally {
174 if (!inTransaction) {
175 Surface.closeTransaction();
176 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
177 "<<< CLOSE TRANSACTION ScreenRotationAnimation");
Dianne Hackborn352cc982011-01-04 11:34:18 -0800178 }
179
180 if (screenshot != null) {
Dianne Hackborn94cb2eb2011-01-13 21:09:44 -0800181 screenshot.recycle();
Dianne Hackborn352cc982011-01-04 11:34:18 -0800182 }
Dianne Hackborn0f761d62010-11-30 22:06:10 -0800183 }
Dianne Hackborna1111872010-11-23 20:55:11 -0800184 }
185
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800186 static int deltaRotation(int oldRotation, int newRotation) {
187 int delta = newRotation - oldRotation;
Dianne Hackborna1111872010-11-23 20:55:11 -0800188 if (delta < 0) delta += 4;
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800189 return delta;
190 }
Dianne Hackborna1111872010-11-23 20:55:11 -0800191
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800192 void setSnapshotTransform(Matrix matrix, float alpha) {
Dianne Hackborn352cc982011-01-04 11:34:18 -0800193 if (mSurface != null) {
194 matrix.getValues(mTmpFloats);
195 mSurface.setPosition((int)mTmpFloats[Matrix.MTRANS_X],
196 (int)mTmpFloats[Matrix.MTRANS_Y]);
197 mSurface.setMatrix(
198 mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
199 mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
200 mSurface.setAlpha(alpha);
201 if (DEBUG) {
202 float[] srcPnts = new float[] { 0, 0, mWidth, mHeight };
203 float[] dstPnts = new float[4];
204 matrix.mapPoints(dstPnts, srcPnts);
205 Slog.i(TAG, "Original : (" + srcPnts[0] + "," + srcPnts[1]
206 + ")-(" + srcPnts[2] + "," + srcPnts[3] + ")");
207 Slog.i(TAG, "Transformed: (" + dstPnts[0] + "," + dstPnts[1]
208 + ")-(" + dstPnts[2] + "," + dstPnts[3] + ")");
209 }
Dianne Hackborna1111872010-11-23 20:55:11 -0800210 }
211 }
212
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800213 public static void createRotationMatrix(int rotation, int width, int height,
214 Matrix outMatrix) {
215 switch (rotation) {
216 case Surface.ROTATION_0:
217 outMatrix.reset();
218 break;
219 case Surface.ROTATION_90:
220 outMatrix.setRotate(90, 0, 0);
221 outMatrix.postTranslate(height, 0);
222 break;
223 case Surface.ROTATION_180:
224 outMatrix.setRotate(180, 0, 0);
225 outMatrix.postTranslate(width, height);
226 break;
227 case Surface.ROTATION_270:
228 outMatrix.setRotate(270, 0, 0);
229 outMatrix.postTranslate(0, width);
230 break;
231 }
232 }
233
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800234 // Must be called while in a transaction.
235 public void setRotation(int rotation) {
236 mCurRotation = rotation;
237
238 // Compute the transformation matrix that must be applied
239 // to the snapshot to make it stay in the same original position
240 // with the current screen rotation.
241 int delta = deltaRotation(rotation, mSnapshotRotation);
Dianne Hackborn0aae2d42010-12-07 23:51:29 -0800242 createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800243
244 if (DEBUG) Slog.v(TAG, "**** ROTATION: " + delta);
245 setSnapshotTransform(mSnapshotInitialMatrix, 1.0f);
246 }
247
248 /**
249 * Returns true if animating.
250 */
Dianne Hackborn50660e22011-02-02 17:12:25 -0800251 public boolean dismiss(SurfaceSession session, long maxAnimationDuration,
252 float animationScale) {
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800253 // Figure out how the screen has moved from the original rotation.
254 int delta = deltaRotation(mCurRotation, mOriginalRotation);
255 if (false && delta == 0) {
256 // Nothing changed, just remove the snapshot.
257 if (mSurface != null) {
258 mSurface.destroy();
259 mSurface = null;
260 }
261 return false;
262 }
263
264 switch (delta) {
265 case Surface.ROTATION_0:
266 mExitAnimation = AnimationUtils.loadAnimation(mContext,
267 com.android.internal.R.anim.screen_rotate_0_exit);
268 mEnterAnimation = AnimationUtils.loadAnimation(mContext,
269 com.android.internal.R.anim.screen_rotate_0_enter);
270 break;
271 case Surface.ROTATION_90:
272 mExitAnimation = AnimationUtils.loadAnimation(mContext,
273 com.android.internal.R.anim.screen_rotate_plus_90_exit);
274 mEnterAnimation = AnimationUtils.loadAnimation(mContext,
275 com.android.internal.R.anim.screen_rotate_plus_90_enter);
276 break;
277 case Surface.ROTATION_180:
278 mExitAnimation = AnimationUtils.loadAnimation(mContext,
279 com.android.internal.R.anim.screen_rotate_180_exit);
280 mEnterAnimation = AnimationUtils.loadAnimation(mContext,
281 com.android.internal.R.anim.screen_rotate_180_enter);
282 break;
283 case Surface.ROTATION_270:
284 mExitAnimation = AnimationUtils.loadAnimation(mContext,
285 com.android.internal.R.anim.screen_rotate_minus_90_exit);
286 mEnterAnimation = AnimationUtils.loadAnimation(mContext,
287 com.android.internal.R.anim.screen_rotate_minus_90_enter);
288 break;
289 }
290
291 mDisplay.getMetrics(mDisplayMetrics);
292
293 // Initialize the animations. This is a hack, redefining what "parent"
294 // means to allow supplying the last and next size. In this definition
295 // "%p" is the original (let's call it "previous") size, and "%" is the
296 // screen's current/new size.
297 mEnterAnimation.initialize(mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
298 mOriginalWidth, mOriginalHeight);
299 mExitAnimation.initialize(mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
300 mOriginalWidth, mOriginalHeight);
301 mStarted = false;
302
303 mExitAnimation.restrictDuration(maxAnimationDuration);
304 mExitAnimation.scaleCurrentDuration(animationScale);
305 mEnterAnimation.restrictDuration(maxAnimationDuration);
306 mEnterAnimation.scaleCurrentDuration(animationScale);
307
Dianne Hackborn50660e22011-02-02 17:12:25 -0800308 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
309 ">>> OPEN TRANSACTION ScreenRotationAnimation.dismiss");
310 Surface.openTransaction();
311
312 mBlackSurfaces = new BlackSurface[4];
313 try {
314 final int w = mDisplayMetrics.widthPixels;
315 final int h = mDisplayMetrics.heightPixels;
316 mBlackSurfaces[0] = new BlackSurface(session, FREEZE_LAYER, -w, -h, w, h*2);
317 mBlackSurfaces[1] = new BlackSurface(session, FREEZE_LAYER, 0, -h, w*2, h);
318 mBlackSurfaces[2] = new BlackSurface(session, FREEZE_LAYER, w, 0, w, h*2);
319 mBlackSurfaces[3] = new BlackSurface(session, FREEZE_LAYER, -w, h, w*2, h);
320 } catch (Surface.OutOfResourcesException e) {
321 Slog.w(TAG, "Unable to allocate black surface", e);
322 } finally {
323 Surface.closeTransaction();
324 if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
325 "<<< CLOSE TRANSACTION ScreenRotationAnimation.dismiss");
326 }
327
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800328 return true;
329 }
330
331 public void kill() {
332 if (mSurface != null) {
333 mSurface.destroy();
334 mSurface = null;
335 }
Dianne Hackborn50660e22011-02-02 17:12:25 -0800336 if (mBlackSurfaces != null) {
337 for (int i=0; i<mBlackSurfaces.length; i++) {
338 if (mBlackSurfaces[i] != null) {
339 mBlackSurfaces[i].surface.destroy();
340 }
341 }
342 mBlackSurfaces = null;
Dianne Hackborn352cc982011-01-04 11:34:18 -0800343 }
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800344 if (mExitAnimation != null) {
345 mExitAnimation.cancel();
346 mExitAnimation = null;
347 }
348 if (mEnterAnimation != null) {
349 mEnterAnimation.cancel();
350 mEnterAnimation = null;
351 }
352 }
353
354 public boolean isAnimating() {
355 return mEnterAnimation != null || mExitAnimation != null;
356 }
357
358 public boolean stepAnimation(long now) {
359 if (mEnterAnimation == null && mExitAnimation == null) {
360 return false;
361 }
362
363 if (!mStarted) {
364 mEnterAnimation.setStartTime(now);
365 mExitAnimation.setStartTime(now);
366 mStarted = true;
367 }
368
369 mExitTransformation.clear();
370 boolean moreExit = false;
371 if (mExitAnimation != null) {
372 moreExit = mExitAnimation.getTransformation(now, mExitTransformation);
373 if (DEBUG) Slog.v(TAG, "Stepped exit: " + mExitTransformation);
374 if (!moreExit) {
375 if (DEBUG) Slog.v(TAG, "Exit animation done!");
376 mExitAnimation.cancel();
377 mExitAnimation = null;
378 mExitTransformation.clear();
379 if (mSurface != null) {
Dianne Hackborn50660e22011-02-02 17:12:25 -0800380 mSurface.hide();
Dianne Hackborn352cc982011-01-04 11:34:18 -0800381 }
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800382 }
383 }
384
385 mEnterTransformation.clear();
386 boolean moreEnter = false;
387 if (mEnterAnimation != null) {
388 moreEnter = mEnterAnimation.getTransformation(now, mEnterTransformation);
389 if (!moreEnter) {
390 mEnterAnimation.cancel();
391 mEnterAnimation = null;
392 mEnterTransformation.clear();
Dianne Hackborn50660e22011-02-02 17:12:25 -0800393 if (mBlackSurfaces != null) {
394 for (int i=0; i<mBlackSurfaces.length; i++) {
395 if (mBlackSurfaces[i] != null) {
396 mBlackSurfaces[i].surface.hide();
397 }
398 }
399 }
400 } else {
401 if (mBlackSurfaces != null) {
402 for (int i=0; i<mBlackSurfaces.length; i++) {
403 if (mBlackSurfaces[i] != null) {
404 mBlackSurfaces[i].setMatrix(mEnterTransformation.getMatrix());
405 }
406 }
407 }
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800408 }
409 }
410
Dianne Hackborn352cc982011-01-04 11:34:18 -0800411 mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix);
412 setSnapshotTransform(mSnapshotFinalMatrix, mExitTransformation.getAlpha());
Dianne Hackbornf9d0be92010-11-24 12:35:25 -0800413
414 return moreEnter || moreExit;
415 }
416
417 public Transformation getEnterTransformation() {
418 return mEnterTransformation;
Dianne Hackborna1111872010-11-23 20:55:11 -0800419 }
420}