diff options
3 files changed, 54 insertions, 11 deletions
diff --git a/core/java/android/window/BackProgressAnimator.java b/core/java/android/window/BackProgressAnimator.java index 6fe0784a2fa5..94d7811677ae 100644 --- a/core/java/android/window/BackProgressAnimator.java +++ b/core/java/android/window/BackProgressAnimator.java @@ -33,7 +33,7 @@ import com.android.internal.dynamicanimation.animation.SpringForce; * * @hide */ -public class BackProgressAnimator { +public class BackProgressAnimator implements DynamicAnimation.OnAnimationUpdateListener { /** * A factor to scale the input progress by, so that it works better with the spring. * We divide the output progress by this value before sending it to apps, so that apps @@ -43,6 +43,7 @@ public class BackProgressAnimator { private final SpringAnimation mSpring; private ProgressCallback mCallback; private float mProgress = 0; + private float mVelocity = 0; private BackMotionEvent mLastBackEvent; private boolean mBackAnimationInProgress = false; @Nullable @@ -67,7 +68,6 @@ public class BackProgressAnimator { @Override public void setValue(BackProgressAnimator animator, float value) { animator.setProgress(value); - animator.updateProgressValue(value); } @Override @@ -76,6 +76,11 @@ public class BackProgressAnimator { } }; + @Override + public void onAnimationUpdate(DynamicAnimation animation, float value, float velocity) { + updateProgressValue(value, velocity); + } + /** A callback to be invoked when there's a progress value update from the animator. */ public interface ProgressCallback { @@ -85,6 +90,7 @@ public class BackProgressAnimator { public BackProgressAnimator() { mSpring = new SpringAnimation(this, PROGRESS_PROP); + mSpring.addUpdateListener(this); mSpring.setSpring(new SpringForce() .setStiffness(SpringForce.STIFFNESS_MEDIUM) .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY)); @@ -117,7 +123,7 @@ public class BackProgressAnimator { mLastBackEvent = event; mCallback = callback; mBackAnimationInProgress = true; - updateProgressValue(0); + updateProgressValue(0, 0); } /** @@ -126,7 +132,7 @@ public class BackProgressAnimator { public void reset() { if (mBackCancelledFinishRunnable != null) { // Ensure that last progress value that apps see is 0 - updateProgressValue(0); + updateProgressValue(0, 0); invokeBackCancelledRunnable(); } mSpring.animateToFinalPosition(0); @@ -167,7 +173,15 @@ public class BackProgressAnimator { return mBackAnimationInProgress; } - private void updateProgressValue(float progress) { + /** + * @return The last recorded velocity. Unit: change in progress per second + */ + public float getVelocity() { + return mVelocity / SCALE_FACTOR; + } + + private void updateProgressValue(float progress, float velocity) { + mVelocity = velocity; if (mLastBackEvent == null || mCallback == null || !mBackAnimationInProgress) { return; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt index c988c2fb5103..71fc8c3a01ea 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt @@ -41,6 +41,9 @@ import android.window.BackMotionEvent import android.window.BackNavigationInfo import android.window.BackProgressAnimator import android.window.IOnBackInvokedCallback +import com.android.internal.dynamicanimation.animation.FloatValueHolder +import com.android.internal.dynamicanimation.animation.SpringAnimation +import com.android.internal.dynamicanimation.animation.SpringForce import com.android.internal.jank.Cuj import com.android.internal.policy.ScreenDecorationsUtils import com.android.internal.protolog.common.ProtoLog @@ -70,6 +73,7 @@ abstract class CrossActivityBackAnimation( protected val backAnimRect = Rect() private val cropRect = Rect() + private val tempRectF = RectF() private var cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context) @@ -98,6 +102,12 @@ abstract class CrossActivityBackAnimation( private var rightLetterboxLayer: SurfaceControl? = null private var letterboxColor: Int = 0 + private val postCommitFlingScale = FloatValueHolder(SPRING_SCALE) + private var lastPostCommitFlingScale = SPRING_SCALE + private val postCommitFlingSpring = SpringForce(SPRING_SCALE) + .setStiffness(SpringForce.STIFFNESS_LOW) + .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY) + /** Background color to be used during the animation, also see [getBackgroundColor] */ protected var customizedBackgroundColor = 0 @@ -231,7 +241,7 @@ abstract class CrossActivityBackAnimation( return deltaY } - protected open fun onGestureCommitted() { + protected open fun onGestureCommitted(velocity: Float) { if ( closingTarget?.leash == null || enteringTarget?.leash == null || @@ -242,6 +252,14 @@ abstract class CrossActivityBackAnimation( return } + // kick off spring animation with the current velocity from the pre-commit phase, this + // affects the scaling of the closing activity during post-commit + val flingAnimation = SpringAnimation(postCommitFlingScale, SPRING_SCALE) + .setStartVelocity(min(0f, -velocity * SPRING_SCALE)) + .setStartValue(SPRING_SCALE) + .setSpring(postCommitFlingSpring) + flingAnimation.start() + val valueAnimator = ValueAnimator.ofFloat(1f, 0f).setDuration(POST_COMMIT_DURATION) valueAnimator.addUpdateListener { animation: ValueAnimator -> val progress = animation.animatedFraction @@ -291,6 +309,7 @@ abstract class CrossActivityBackAnimation( removeLetterbox() isLetterboxed = false enteringHasSameLetterbox = false + lastPostCommitFlingScale = SPRING_SCALE } protected fun applyTransform( @@ -300,7 +319,15 @@ abstract class CrossActivityBackAnimation( baseTransformation: Transformation? = null ) { if (leash == null || !leash.isValid) return - val scale = rect.width() / backAnimRect.width() + tempRectF.set(rect) + if (leash == closingTarget?.leash) { + lastPostCommitFlingScale = (postCommitFlingScale.value / SPRING_SCALE).coerceIn( + minimumValue = MAX_FLING_SCALE, maximumValue = lastPostCommitFlingScale + ) + // apply an additional scale to the closing target to account for fling velocity + tempRectF.scaleCentered(lastPostCommitFlingScale) + } + val scale = tempRectF.width() / backAnimRect.width() val matrix = baseTransformation?.matrix ?: transformMatrix.apply { reset() } val scalePivotX = if (isLetterboxed && enteringHasSameLetterbox) { @@ -309,7 +336,7 @@ abstract class CrossActivityBackAnimation( 0f } matrix.postScale(scale, scale, scalePivotX, 0f) - matrix.postTranslate(rect.left, rect.top) + matrix.postTranslate(tempRectF.left, tempRectF.top) transaction .setAlpha(leash, keepMinimumAlpha(alpha)) .setMatrix(leash, matrix, tmpFloat9) @@ -461,7 +488,7 @@ abstract class CrossActivityBackAnimation( override fun onBackInvoked() { progressAnimator.reset() - onGestureCommitted() + onGestureCommitted(progressAnimator.velocity) } } @@ -497,6 +524,8 @@ abstract class CrossActivityBackAnimation( private const val MAX_SCRIM_ALPHA_DARK = 0.8f private const val MAX_SCRIM_ALPHA_LIGHT = 0.2f private const val POST_COMMIT_DURATION = 300L + private const val SPRING_SCALE = 100f + private const val MAX_FLING_SCALE = 0.6f } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt index f33c5b9bd183..d6c5349201b8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt @@ -56,7 +56,7 @@ constructor( targetEnteringRect.scaleCentered(MAX_SCALE) } - override fun onGestureCommitted() { + override fun onGestureCommitted(velocity: Float) { // We enter phase 2 of the animation, the starting coordinates for phase 2 are the current // coordinate of the gesture driven phase. Let's update the start and target rects and kick // off the animator in the superclass @@ -65,7 +65,7 @@ constructor( targetEnteringRect.set(backAnimRect) targetClosingRect.set(backAnimRect) targetClosingRect.offset(currentClosingRect.left + enteringStartOffset, 0f) - super.onGestureCommitted() + super.onGestureCommitted(velocity) } override fun onPostCommitProgress(linearProgress: Float) { |