From f9d0be917b6f80efad29dce88ad2d2f117986c57 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 24 Nov 2010 12:35:25 -0800 Subject: [PATCH] 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 --- api/current.xml | 2 +- .../view/animation/ScaleAnimation.java | 93 ++++++- core/res/res/anim/screen_rotate_0_enter.xml | 25 ++ core/res/res/anim/screen_rotate_0_exit.xml | 25 ++ core/res/res/anim/screen_rotate_180_enter.xml | 27 ++ core/res/res/anim/screen_rotate_180_exit.xml | 30 +++ .../res/anim/screen_rotate_minus_90_enter.xml | 31 +++ .../res/anim/screen_rotate_minus_90_exit.xml | 34 +++ .../res/anim/screen_rotate_plus_90_enter.xml | 31 +++ .../res/anim/screen_rotate_plus_90_exit.xml | 34 +++ core/res/res/values/attrs.xml | 8 +- .../server/ScreenRotationAnimation.java | 250 +++++++++++++++--- .../android/server/WindowManagerService.java | 41 ++- 13 files changed, 572 insertions(+), 59 deletions(-) create mode 100644 core/res/res/anim/screen_rotate_0_enter.xml create mode 100644 core/res/res/anim/screen_rotate_0_exit.xml create mode 100644 core/res/res/anim/screen_rotate_180_enter.xml create mode 100644 core/res/res/anim/screen_rotate_180_exit.xml create mode 100644 core/res/res/anim/screen_rotate_minus_90_enter.xml create mode 100644 core/res/res/anim/screen_rotate_minus_90_exit.xml create mode 100644 core/res/res/anim/screen_rotate_plus_90_enter.xml create mode 100644 core/res/res/anim/screen_rotate_plus_90_exit.xml diff --git a/api/current.xml b/api/current.xml index 35d283e17046f..b62c689dbc549 100644 --- a/api/current.xml +++ b/api/current.xml @@ -249201,7 +249201,7 @@ deprecated="not deprecated" visibility="public" > - + diff --git a/core/java/android/view/animation/ScaleAnimation.java b/core/java/android/view/animation/ScaleAnimation.java index 8537d4213d7c0..1dd250f94f5d5 100644 --- a/core/java/android/view/animation/ScaleAnimation.java +++ b/core/java/android/view/animation/ScaleAnimation.java @@ -17,8 +17,10 @@ package android.view.animation; import android.content.Context; +import android.content.res.Resources; import android.content.res.TypedArray; import android.util.AttributeSet; +import android.util.TypedValue; /** * An animation that controls the scale of an object. You can specify the point @@ -26,11 +28,23 @@ import android.util.AttributeSet; * */ public class ScaleAnimation extends Animation { + private final Resources mResources; + private float mFromX; private float mToX; private float mFromY; private float mToY; + private int mFromXType = TypedValue.TYPE_NULL; + private int mToXType = TypedValue.TYPE_NULL; + private int mFromYType = TypedValue.TYPE_NULL; + private int mToYType = TypedValue.TYPE_NULL; + + private int mFromXData = 0; + private int mToXData = 0; + private int mFromYData = 0; + private int mToYData = 0; + private int mPivotXType = ABSOLUTE; private int mPivotYType = ABSOLUTE; private float mPivotXValue = 0.0f; @@ -48,14 +62,60 @@ public class ScaleAnimation extends Animation { public ScaleAnimation(Context context, AttributeSet attrs) { super(context, attrs); + mResources = context.getResources(); + TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.ScaleAnimation); - mFromX = a.getFloat(com.android.internal.R.styleable.ScaleAnimation_fromXScale, 0.0f); - mToX = a.getFloat(com.android.internal.R.styleable.ScaleAnimation_toXScale, 0.0f); + TypedValue tv = a.peekValue( + com.android.internal.R.styleable.ScaleAnimation_fromXScale); + mFromX = 0.0f; + if (tv != null) { + if (tv.type == TypedValue.TYPE_FLOAT) { + // This is a scaling factor. + mFromX = tv.getFloat(); + } else { + mFromXType = tv.type; + mFromXData = tv.data; + } + } + tv = a.peekValue( + com.android.internal.R.styleable.ScaleAnimation_toXScale); + mToX = 0.0f; + if (tv != null) { + if (tv.type == TypedValue.TYPE_FLOAT) { + // This is a scaling factor. + mToX = tv.getFloat(); + } else { + mToXType = tv.type; + mToXData = tv.data; + } + } - mFromY = a.getFloat(com.android.internal.R.styleable.ScaleAnimation_fromYScale, 0.0f); - mToY = a.getFloat(com.android.internal.R.styleable.ScaleAnimation_toYScale, 0.0f); + tv = a.peekValue( + com.android.internal.R.styleable.ScaleAnimation_fromYScale); + mFromY = 0.0f; + if (tv != null) { + if (tv.type == TypedValue.TYPE_FLOAT) { + // This is a scaling factor. + mFromY = tv.getFloat(); + } else { + mFromYType = tv.type; + mFromYData = tv.data; + } + } + tv = a.peekValue( + com.android.internal.R.styleable.ScaleAnimation_toYScale); + mToY = 0.0f; + if (tv != null) { + if (tv.type == TypedValue.TYPE_FLOAT) { + // This is a scaling factor. + mToY = tv.getFloat(); + } else { + mToYType = tv.type; + mToYData = tv.data; + } + } Description d = Description.parseValue(a.peekValue( com.android.internal.R.styleable.ScaleAnimation_pivotX)); @@ -81,6 +141,7 @@ public class ScaleAnimation extends Animation { * @param toY Vertical scaling factor to apply at the end of the animation */ public ScaleAnimation(float fromX, float toX, float fromY, float toY) { + mResources = null; mFromX = fromX; mToX = toX; mFromY = fromY; @@ -107,6 +168,7 @@ public class ScaleAnimation extends Animation { */ public ScaleAnimation(float fromX, float toX, float fromY, float toY, float pivotX, float pivotY) { + mResources = null; mFromX = fromX; mToX = toX; mFromY = fromY; @@ -146,6 +208,7 @@ public class ScaleAnimation extends Animation { */ public ScaleAnimation(float fromX, float toX, float fromY, float toY, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue) { + mResources = null; mFromX = fromX; mToX = toX; mFromY = fromY; @@ -177,10 +240,32 @@ public class ScaleAnimation extends Animation { } } + float resolveScale(float scale, int type, int data, int size, int psize) { + float targetSize; + if (type == TypedValue.TYPE_FRACTION) { + targetSize = TypedValue.complexToFraction(data, size, psize); + } else if (type == TypedValue.TYPE_DIMENSION) { + targetSize = TypedValue.complexToDimension(data, mResources.getDisplayMetrics()); + } else { + return scale; + } + + if (size == 0) { + return 1; + } + + return targetSize/(float)size; + } + @Override public void initialize(int width, int height, int parentWidth, int parentHeight) { super.initialize(width, height, parentWidth, parentHeight); + mFromX = resolveScale(mFromX, mFromXType, mFromXData, width, parentWidth); + mToX = resolveScale(mToX, mToXType, mToXData, width, parentWidth); + mFromY = resolveScale(mFromY, mFromYType, mFromYData, height, parentHeight); + mToY = resolveScale(mToY, mToYType, mToYData, height, parentHeight); + mPivotX = resolveSize(mPivotXType, mPivotXValue, width, parentWidth); mPivotY = resolveSize(mPivotYType, mPivotYValue, height, parentHeight); } diff --git a/core/res/res/anim/screen_rotate_0_enter.xml b/core/res/res/anim/screen_rotate_0_enter.xml new file mode 100644 index 0000000000000..9e9a8ad0f21ee --- /dev/null +++ b/core/res/res/anim/screen_rotate_0_enter.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/core/res/res/anim/screen_rotate_0_exit.xml b/core/res/res/anim/screen_rotate_0_exit.xml new file mode 100644 index 0000000000000..09d0ac34cab90 --- /dev/null +++ b/core/res/res/anim/screen_rotate_0_exit.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/core/res/res/anim/screen_rotate_180_enter.xml b/core/res/res/anim/screen_rotate_180_enter.xml new file mode 100644 index 0000000000000..bfc8c6de877b8 --- /dev/null +++ b/core/res/res/anim/screen_rotate_180_enter.xml @@ -0,0 +1,27 @@ + + + + + + diff --git a/core/res/res/anim/screen_rotate_180_exit.xml b/core/res/res/anim/screen_rotate_180_exit.xml new file mode 100644 index 0000000000000..f1ce1cf38a370 --- /dev/null +++ b/core/res/res/anim/screen_rotate_180_exit.xml @@ -0,0 +1,30 @@ + + + + + + + diff --git a/core/res/res/anim/screen_rotate_minus_90_enter.xml b/core/res/res/anim/screen_rotate_minus_90_enter.xml new file mode 100644 index 0000000000000..92a7779691dcf --- /dev/null +++ b/core/res/res/anim/screen_rotate_minus_90_enter.xml @@ -0,0 +1,31 @@ + + + + + + + diff --git a/core/res/res/anim/screen_rotate_minus_90_exit.xml b/core/res/res/anim/screen_rotate_minus_90_exit.xml new file mode 100644 index 0000000000000..c530759ba3247 --- /dev/null +++ b/core/res/res/anim/screen_rotate_minus_90_exit.xml @@ -0,0 +1,34 @@ + + + + + + + + diff --git a/core/res/res/anim/screen_rotate_plus_90_enter.xml b/core/res/res/anim/screen_rotate_plus_90_enter.xml new file mode 100644 index 0000000000000..f4ffaa8619548 --- /dev/null +++ b/core/res/res/anim/screen_rotate_plus_90_enter.xml @@ -0,0 +1,31 @@ + + + + + + + diff --git a/core/res/res/anim/screen_rotate_plus_90_exit.xml b/core/res/res/anim/screen_rotate_plus_90_exit.xml new file mode 100644 index 0000000000000..0728bfb39afab --- /dev/null +++ b/core/res/res/anim/screen_rotate_plus_90_exit.xml @@ -0,0 +1,34 @@ + + + + + + + + diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index eacd14e00665c..a8099e3fab266 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -3233,10 +3233,10 @@ - - - - + + + + diff --git a/services/java/com/android/server/ScreenRotationAnimation.java b/services/java/com/android/server/ScreenRotationAnimation.java index 299567a9163a2..1cc6a2a551219 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,43 +125,24 @@ class ScreenRotationAnimation { screenshot.recycle(); } - // Must be called while in a transaction. - public void setRotation(int rotation) { - mCurRotation = rotation; - int delta = mCurRotation - mBaseRotation; + static int deltaRotation(int oldRotation, int newRotation) { + int delta = newRotation - oldRotation; if (delta < 0) delta += 4; - mDeltaRotation = delta; + return delta; + } - switch (delta) { - case Surface.ROTATION_0: - mMatrix.reset(); - break; - case Surface.ROTATION_90: - mMatrix.setRotate(90, 0, 0); - mMatrix.postTranslate(0, mWidth); - break; - case Surface.ROTATION_180: - mMatrix.setRotate(180, 0, 0); - mMatrix.postTranslate(mWidth, mHeight); - break; - case Surface.ROTATION_270: - mMatrix.setRotate(270, 0, 0); - mMatrix.postTranslate(mHeight, 0); - break; - } - - mMatrix.getValues(mTmpFloats); + 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_X], - mTmpFloats[Matrix.MSKEW_Y], mTmpFloats[Matrix.MSCALE_Y]); - - if (false) { + 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[8]; - mMatrix.mapPoints(dstPnts, srcPnts); - Slog.i(TAG, "**** ROTATION: " + delta); + 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] @@ -146,7 +150,165 @@ class ScreenRotationAnimation { } } - public void dismiss() { - mSurface.destroy(); + // Must be called while in a transaction. + public void setRotation(int rotation) { + mCurRotation = rotation; + + // 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: + mSnapshotInitialMatrix.reset(); + break; + case Surface.ROTATION_90: + mSnapshotInitialMatrix.setRotate(90, 0, 0); + mSnapshotInitialMatrix.postTranslate(mHeight, 0); + break; + case Surface.ROTATION_180: + mSnapshotInitialMatrix.setRotate(180, 0, 0); + mSnapshotInitialMatrix.postTranslate(mWidth, mHeight); + break; + case Surface.ROTATION_270: + mSnapshotInitialMatrix.setRotate(270, 0, 0); + mSnapshotInitialMatrix.postTranslate(0, mWidth); + break; + } + + if (DEBUG) Slog.v(TAG, "**** ROTATION: " + delta); + setSnapshotTransform(mSnapshotInitialMatrix, 1.0f); + } + + /** + * 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 Transformation getEnterTransformation() { + return mEnterTransformation; } } diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index 89512aebf2f92..cbb35c656bb39 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);