Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 699be317 authored by Johannes Gallmann's avatar Johannes Gallmann
Browse files

Respect velocity for cross activity back animations

Bug: 341292615
Flag: com.android.window.flags.predictive_back_system_anims NEXTFOOD
Test: Manual, i.e. testing flings on device and analysing screen recordings
Change-Id: Iafcaa4999daa7323a3b458a2821a18822dc19bb4
parent f3900f1b
Loading
Loading
Loading
Loading
+19 −5
Original line number Diff line number Diff line
@@ -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;
        }
+33 −4
Original line number Diff line number Diff line
@@ -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
    }
}

+2 −2
Original line number Diff line number Diff line
@@ -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) {