summaryrefslogtreecommitdiffstats
path: root/services/java
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2010-11-24 12:35:25 -0800
committerDianne Hackborn <hackbod@google.com>2010-11-28 18:28:57 -0800
commitf9d0be917b6f80efad29dce88ad2d2f117986c57 (patch)
tree6615af240495c9e61cd97218c3ba1fad62321528 /services/java
parent5a6b4f826515c65d816e711266f0eac5ae3d37df (diff)
downloadframeworks_base-f9d0be917b6f80efad29dce88ad2d2f117986c57.zip
frameworks_base-f9d0be917b6f80efad29dce88ad2d2f117986c57.tar.gz
frameworks_base-f9d0be917b6f80efad29dce88ad2d2f117986c57.tar.bz2
Implement rotation animations.
This introduces a small new feature for ScaleAnimation allowing the scaling factor to be expressed as a percentage of the object (which is the same as the existing float interpretation), a percentage of the container, or a fixed dimension. Maybe not useful for anything else, but I needed it for this. Also fix a bug in how transformation matrices were propagated from the Animation to Surface Flinger, so that rotate and skew animations will actually work. :p Change-Id: I301f4caa2147aa35564b5e511cb9c0b368d2425d
Diffstat (limited to 'services/java')
-rw-r--r--services/java/com/android/server/ScreenRotationAnimation.java238
-rw-r--r--services/java/com/android/server/WindowManagerService.java41
2 files changed, 235 insertions, 44 deletions
diff --git a/services/java/com/android/server/ScreenRotationAnimation.java b/services/java/com/android/server/ScreenRotationAnimation.java
index 299567a..1cc6a2a 100644
--- a/services/java/com/android/server/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/ScreenRotationAnimation.java
@@ -16,6 +16,7 @@
package com.android.server; // TODO: use com.android.server.wm, once things move there
+import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -28,38 +29,60 @@ import android.util.Slog;
import android.view.Display;
import android.view.Surface;
import android.view.SurfaceSession;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Transformation;
class ScreenRotationAnimation {
- private static final String TAG = "ScreenRotationAnimation";
+ static final String TAG = "ScreenRotationAnimation";
+ static final boolean DEBUG = false;
+ final Context mContext;
+ final Display mDisplay;
Surface mSurface;
int mWidth, mHeight;
- int mBaseRotation;
+ int mSnapshotRotation;
+ int mSnapshotDeltaRotation;
+ int mOriginalRotation;
+ int mOriginalWidth, mOriginalHeight;
int mCurRotation;
- int mDeltaRotation;
- final Matrix mMatrix = new Matrix();
+ Animation mExitAnimation;
+ final Transformation mExitTransformation = new Transformation();
+ Animation mEnterAnimation;
+ final Transformation mEnterTransformation = new Transformation();
+ boolean mStarted;
+
+ final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
+ final Matrix mSnapshotInitialMatrix = new Matrix();
+ final Matrix mSnapshotFinalMatrix = new Matrix();
final float[] mTmpFloats = new float[9];
- public ScreenRotationAnimation(Display display, SurfaceSession session) {
- final DisplayMetrics dm = new DisplayMetrics();
- display.getMetrics(dm);
+ public ScreenRotationAnimation(Context context, Display display, SurfaceSession session) {
+ mContext = context;
+ mDisplay = display;
+
+ display.getMetrics(mDisplayMetrics);
Bitmap screenshot = Surface.screenshot(0, 0);
if (screenshot != null) {
// Screenshot does NOT include rotation!
- mBaseRotation = 0;
+ mSnapshotRotation = 0;
mWidth = screenshot.getWidth();
mHeight = screenshot.getHeight();
} else {
// Just in case.
- mBaseRotation = display.getRotation();
- mWidth = dm.widthPixels;
- mHeight = dm.heightPixels;
+ mSnapshotRotation = display.getRotation();
+ mWidth = mDisplayMetrics.widthPixels;
+ mHeight = mDisplayMetrics.heightPixels;
}
+ mOriginalRotation = display.getRotation();
+ mOriginalWidth = mDisplayMetrics.widthPixels;
+ mOriginalHeight = mDisplayMetrics.heightPixels;
+
Surface.openTransaction();
if (mSurface != null) {
mSurface.destroy();
@@ -102,51 +125,190 @@ class ScreenRotationAnimation {
screenshot.recycle();
}
+ static int deltaRotation(int oldRotation, int newRotation) {
+ int delta = newRotation - oldRotation;
+ if (delta < 0) delta += 4;
+ return delta;
+ }
+
+ void setSnapshotTransform(Matrix matrix, float alpha) {
+ matrix.getValues(mTmpFloats);
+ mSurface.setPosition((int)mTmpFloats[Matrix.MTRANS_X],
+ (int)mTmpFloats[Matrix.MTRANS_Y]);
+ mSurface.setMatrix(
+ mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
+ mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
+ mSurface.setAlpha(alpha);
+ if (DEBUG) {
+ float[] srcPnts = new float[] { 0, 0, mWidth, mHeight };
+ float[] dstPnts = new float[4];
+ matrix.mapPoints(dstPnts, srcPnts);
+ Slog.i(TAG, "Original : (" + srcPnts[0] + "," + srcPnts[1]
+ + ")-(" + srcPnts[2] + "," + srcPnts[3] + ")");
+ Slog.i(TAG, "Transformed: (" + dstPnts[0] + "," + dstPnts[1]
+ + ")-(" + dstPnts[2] + "," + dstPnts[3] + ")");
+ }
+ }
+
// Must be called while in a transaction.
public void setRotation(int rotation) {
mCurRotation = rotation;
- int delta = mCurRotation - mBaseRotation;
- if (delta < 0) delta += 4;
- mDeltaRotation = delta;
+ // Compute the transformation matrix that must be applied
+ // to the snapshot to make it stay in the same original position
+ // with the current screen rotation.
+ int delta = deltaRotation(rotation, mSnapshotRotation);
switch (delta) {
case Surface.ROTATION_0:
- mMatrix.reset();
+ mSnapshotInitialMatrix.reset();
break;
case Surface.ROTATION_90:
- mMatrix.setRotate(90, 0, 0);
- mMatrix.postTranslate(0, mWidth);
+ mSnapshotInitialMatrix.setRotate(90, 0, 0);
+ mSnapshotInitialMatrix.postTranslate(mHeight, 0);
break;
case Surface.ROTATION_180:
- mMatrix.setRotate(180, 0, 0);
- mMatrix.postTranslate(mWidth, mHeight);
+ mSnapshotInitialMatrix.setRotate(180, 0, 0);
+ mSnapshotInitialMatrix.postTranslate(mWidth, mHeight);
break;
case Surface.ROTATION_270:
- mMatrix.setRotate(270, 0, 0);
- mMatrix.postTranslate(mHeight, 0);
+ mSnapshotInitialMatrix.setRotate(270, 0, 0);
+ mSnapshotInitialMatrix.postTranslate(0, mWidth);
break;
}
- mMatrix.getValues(mTmpFloats);
- mSurface.setPosition((int)mTmpFloats[Matrix.MTRANS_X],
- (int)mTmpFloats[Matrix.MTRANS_Y]);
- mSurface.setMatrix(
- mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_X],
- mTmpFloats[Matrix.MSKEW_Y], mTmpFloats[Matrix.MSCALE_Y]);
+ if (DEBUG) Slog.v(TAG, "**** ROTATION: " + delta);
+ setSnapshotTransform(mSnapshotInitialMatrix, 1.0f);
+ }
- if (false) {
- float[] srcPnts = new float[] { 0, 0, mWidth, mHeight };
- float[] dstPnts = new float[8];
- mMatrix.mapPoints(dstPnts, srcPnts);
- Slog.i(TAG, "**** ROTATION: " + delta);
- Slog.i(TAG, "Original : (" + srcPnts[0] + "," + srcPnts[1]
- + ")-(" + srcPnts[2] + "," + srcPnts[3] + ")");
- Slog.i(TAG, "Transformed: (" + dstPnts[0] + "," + dstPnts[1]
- + ")-(" + dstPnts[2] + "," + dstPnts[3] + ")");
+ /**
+ * Returns true if animating.
+ */
+ public boolean dismiss(long maxAnimationDuration, float animationScale) {
+ // Figure out how the screen has moved from the original rotation.
+ int delta = deltaRotation(mCurRotation, mOriginalRotation);
+ if (false && delta == 0) {
+ // Nothing changed, just remove the snapshot.
+ if (mSurface != null) {
+ mSurface.destroy();
+ mSurface = null;
+ }
+ return false;
}
+
+ switch (delta) {
+ case Surface.ROTATION_0:
+ mExitAnimation = AnimationUtils.loadAnimation(mContext,
+ com.android.internal.R.anim.screen_rotate_0_exit);
+ mEnterAnimation = AnimationUtils.loadAnimation(mContext,
+ com.android.internal.R.anim.screen_rotate_0_enter);
+ break;
+ case Surface.ROTATION_90:
+ mExitAnimation = AnimationUtils.loadAnimation(mContext,
+ com.android.internal.R.anim.screen_rotate_plus_90_exit);
+ mEnterAnimation = AnimationUtils.loadAnimation(mContext,
+ com.android.internal.R.anim.screen_rotate_plus_90_enter);
+ break;
+ case Surface.ROTATION_180:
+ mExitAnimation = AnimationUtils.loadAnimation(mContext,
+ com.android.internal.R.anim.screen_rotate_180_exit);
+ mEnterAnimation = AnimationUtils.loadAnimation(mContext,
+ com.android.internal.R.anim.screen_rotate_180_enter);
+ break;
+ case Surface.ROTATION_270:
+ mExitAnimation = AnimationUtils.loadAnimation(mContext,
+ com.android.internal.R.anim.screen_rotate_minus_90_exit);
+ mEnterAnimation = AnimationUtils.loadAnimation(mContext,
+ com.android.internal.R.anim.screen_rotate_minus_90_enter);
+ break;
+ }
+
+ mDisplay.getMetrics(mDisplayMetrics);
+
+ // Initialize the animations. This is a hack, redefining what "parent"
+ // means to allow supplying the last and next size. In this definition
+ // "%p" is the original (let's call it "previous") size, and "%" is the
+ // screen's current/new size.
+ mEnterAnimation.initialize(mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
+ mOriginalWidth, mOriginalHeight);
+ mExitAnimation.initialize(mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
+ mOriginalWidth, mOriginalHeight);
+ mStarted = false;
+
+ mExitAnimation.restrictDuration(maxAnimationDuration);
+ mExitAnimation.scaleCurrentDuration(animationScale);
+ mEnterAnimation.restrictDuration(maxAnimationDuration);
+ mEnterAnimation.scaleCurrentDuration(animationScale);
+
+ return true;
+ }
+
+ public void kill() {
+ if (mSurface != null) {
+ mSurface.destroy();
+ mSurface = null;
+ }
+ if (mExitAnimation != null) {
+ mExitAnimation.cancel();
+ mExitAnimation = null;
+ }
+ if (mEnterAnimation != null) {
+ mEnterAnimation.cancel();
+ mEnterAnimation = null;
+ }
+ }
+
+ public boolean isAnimating() {
+ return mEnterAnimation != null || mExitAnimation != null;
+ }
+
+ public boolean stepAnimation(long now) {
+ if (mEnterAnimation == null && mExitAnimation == null) {
+ return false;
+ }
+
+ if (!mStarted) {
+ mEnterAnimation.setStartTime(now);
+ mExitAnimation.setStartTime(now);
+ mStarted = true;
+ }
+
+ mExitTransformation.clear();
+ boolean moreExit = false;
+ if (mExitAnimation != null) {
+ moreExit = mExitAnimation.getTransformation(now, mExitTransformation);
+ if (DEBUG) Slog.v(TAG, "Stepped exit: " + mExitTransformation);
+ if (!moreExit) {
+ if (DEBUG) Slog.v(TAG, "Exit animation done!");
+ mExitAnimation.cancel();
+ mExitAnimation = null;
+ mExitTransformation.clear();
+ if (mSurface != null) {
+ mSurface.destroy();
+ mSurface = null;
+ }
+ }
+ }
+
+ mEnterTransformation.clear();
+ boolean moreEnter = false;
+ if (mEnterAnimation != null) {
+ moreEnter = mEnterAnimation.getTransformation(now, mEnterTransformation);
+ if (!moreEnter) {
+ mEnterAnimation.cancel();
+ mEnterAnimation = null;
+ mEnterTransformation.clear();
+ }
+ }
+
+ if (mSurface != null) {
+ mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix);
+ setSnapshotTransform(mSnapshotFinalMatrix, mExitTransformation.getAlpha());
+ }
+
+ return moreEnter || moreExit;
}
- public void dismiss() {
- mSurface.destroy();
+ public Transformation getEnterTransformation() {
+ return mEnterTransformation;
}
}
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 89512ae..cbb35c6 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -7487,8 +7487,10 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ final boolean screenAnimation = mScreenRotationAnimation != null
+ && mScreenRotationAnimation.isAnimating();
if (selfTransformation || attachedTransformation != null
- || appTransformation != null) {
+ || appTransformation != null || screenAnimation) {
// cache often used attributes locally
final Rect frame = mFrame;
final float tmpFloats[] = mTmpFloats;
@@ -7506,6 +7508,10 @@ public class WindowManagerService extends IWindowManager.Stub
if (appTransformation != null) {
tmpMatrix.postConcat(appTransformation.getMatrix());
}
+ if (screenAnimation) {
+ tmpMatrix.postConcat(
+ mScreenRotationAnimation.getEnterTransformation().getMatrix());
+ }
// "convert" it into SurfaceFlinger's format
// (a 2x2 matrix + an offset)
@@ -7515,8 +7521,8 @@ public class WindowManagerService extends IWindowManager.Stub
tmpMatrix.getValues(tmpFloats);
mDsDx = tmpFloats[Matrix.MSCALE_X];
- mDtDx = tmpFloats[Matrix.MSKEW_X];
- mDsDy = tmpFloats[Matrix.MSKEW_Y];
+ mDtDx = tmpFloats[Matrix.MSKEW_Y];
+ mDsDy = tmpFloats[Matrix.MSKEW_X];
mDtDy = tmpFloats[Matrix.MSCALE_Y];
int x = (int)tmpFloats[Matrix.MTRANS_X] + mXOffset;
int y = (int)tmpFloats[Matrix.MTRANS_Y] + mYOffset;
@@ -7544,6 +7550,10 @@ public class WindowManagerService extends IWindowManager.Stub
if (appTransformation != null) {
mShownAlpha *= appTransformation.getAlpha();
}
+ if (screenAnimation) {
+ mShownAlpha *=
+ mScreenRotationAnimation.getEnterTransformation().getAlpha();
+ }
} else {
//Slog.i(TAG, "Not applying alpha transform");
}
@@ -9397,6 +9407,16 @@ public class WindowManagerService extends IWindowManager.Stub
animating = tokensAnimating;
+ if (mScreenRotationAnimation != null) {
+ if (mScreenRotationAnimation.isAnimating()) {
+ if (mScreenRotationAnimation.stepAnimation(currentTime)) {
+ animating = true;
+ } else {
+ mScreenRotationAnimation = null;
+ }
+ }
+ }
+
boolean tokenMayBeDrawn = false;
boolean wallpaperMayChange = false;
boolean forceHiding = false;
@@ -10841,8 +10861,13 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (CUSTOM_SCREEN_ROTATION) {
+ if (mScreenRotationAnimation != null && mScreenRotationAnimation.isAnimating()) {
+ mScreenRotationAnimation.kill();
+ mScreenRotationAnimation = null;
+ }
if (mScreenRotationAnimation == null) {
- mScreenRotationAnimation = new ScreenRotationAnimation(mDisplay, mFxSession);
+ mScreenRotationAnimation = new ScreenRotationAnimation(mContext,
+ mDisplay, mFxSession);
}
} else {
Surface.freezeDisplay(0);
@@ -10866,8 +10891,12 @@ public class WindowManagerService extends IWindowManager.Stub
if (CUSTOM_SCREEN_ROTATION) {
if (mScreenRotationAnimation != null) {
- mScreenRotationAnimation.dismiss();
- mScreenRotationAnimation = null;
+ if (mScreenRotationAnimation.dismiss(MAX_ANIMATION_DURATION,
+ mTransitionAnimationScale)) {
+ requestAnimationLocked(0);
+ } else {
+ mScreenRotationAnimation = null;
+ }
}
} else {
Surface.unfreezeDisplay(0);