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

Commit a3c0b0aa authored by Jon Miranda's avatar Jon Miranda
Browse files

Swipe up to home animation changes.

* Tracks either the top or bottom of the rect for the fling/spring in the
Y direction.
- This allows us to have the icon always animate downwards.

* Scales the spring velocity for the Y component.

Bug: 124510042
Change-Id: I47571f906c8aa1beca4dd703d67d013ab6a1161f
parent 57730ed0
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -23,4 +23,8 @@

    <!-- Minimum distance to swipe to trigger accessibility gesture -->
    <dimen name="accessibility_gesture_min_swipe_distance">80dp</dimen>

    <!-- Swipe up to home related -->
    <dimen name="swipe_up_fling_min_visible_change">18dp</dimen>
    <dimen name="swipe_up_y_overshoot">10dp</dimen>
</resources>
 No newline at end of file
+1 −2
Original line number Diff line number Diff line
@@ -1077,8 +1077,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>

        final View floatingView = homeAnimationFactory.getFloatingView();
        final boolean isFloatingIconView = floatingView instanceof FloatingIconView;

        RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect);
        RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mActivity.getResources());
        if (isFloatingIconView) {
            FloatingIconView fiv = (FloatingIconView) floatingView;
            anim.addAnimatorListener(fiv);
+51 −16
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.content.res.Resources;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.FloatProperty;
@@ -26,6 +27,7 @@ import android.util.FloatProperty;
import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener;
import androidx.dynamicanimation.animation.FloatPropertyCompat;

import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.FlingSpringAnim;
@@ -63,16 +65,16 @@ public class RectFSpringAnim {
                }
            };

    private static final FloatPropertyCompat<RectFSpringAnim> RECT_CENTER_Y =
            new FloatPropertyCompat<RectFSpringAnim>("rectCenterYSpring") {
    private static final FloatPropertyCompat<RectFSpringAnim> RECT_Y =
            new FloatPropertyCompat<RectFSpringAnim>("rectYSpring") {
                @Override
                public float getValue(RectFSpringAnim anim) {
                    return anim.mCurrentCenterY;
                    return anim.mCurrentY;
                }

                @Override
                public void setValue(RectFSpringAnim anim, float currentCenterY) {
                    anim.mCurrentCenterY = currentCenterY;
                public void setValue(RectFSpringAnim anim, float y) {
                    anim.mCurrentY = y;
                    anim.onUpdate();
                }
            };
@@ -98,7 +100,9 @@ public class RectFSpringAnim {
    private final List<Animator.AnimatorListener> mAnimatorListeners = new ArrayList<>();

    private float mCurrentCenterX;
    private float mCurrentCenterY;
    private float mCurrentY;
    // If true, tracking the bottom of the rects, else tracking the top.
    private boolean mTrackingBottomY;
    private float mCurrentScaleProgress;
    private FlingSpringAnim mRectXAnim;
    private FlingSpringAnim mRectYAnim;
@@ -108,19 +112,32 @@ public class RectFSpringAnim {
    private boolean mRectYAnimEnded;
    private boolean mRectScaleAnimEnded;

    public RectFSpringAnim(RectF startRect, RectF targetRect) {
    private float mMinVisChange;
    private float mYOvershoot;

    public RectFSpringAnim(RectF startRect, RectF targetRect, Resources resources) {
        mStartRect = startRect;
        mTargetRect = targetRect;
        mCurrentCenterX = mStartRect.centerX();
        mCurrentCenterY = mStartRect.centerY();

        mTrackingBottomY = startRect.bottom < targetRect.bottom;
        mCurrentY = mTrackingBottomY ? mStartRect.bottom : mStartRect.top;

        mMinVisChange = resources.getDimensionPixelSize(R.dimen.swipe_up_fling_min_visible_change);
        mYOvershoot = resources.getDimensionPixelSize(R.dimen.swipe_up_y_overshoot);
    }

    public void onTargetPositionChanged() {
        if (mRectXAnim != null && mRectXAnim.getTargetPosition() != mTargetRect.centerX()) {
            mRectXAnim.updatePosition(mCurrentCenterX, mTargetRect.centerX());
        }
        if (mRectYAnim != null && mRectYAnim.getTargetPosition() != mTargetRect.centerY()) {
            mRectYAnim.updatePosition(mCurrentCenterY, mTargetRect.centerY());

        if (mRectYAnim != null) {
            if (mTrackingBottomY && mRectYAnim.getTargetPosition() != mTargetRect.bottom) {
                mRectYAnim.updatePosition(mCurrentY, mTargetRect.bottom);
            } else if (!mTrackingBottomY && mRectYAnim.getTargetPosition() != mTargetRect.top) {
                mRectYAnim.updatePosition(mCurrentY, mTargetRect.top);
            }
        }
    }

@@ -142,10 +159,23 @@ public class RectFSpringAnim {
            mRectYAnimEnded = true;
            maybeOnEnd();
        });
        mRectXAnim = new FlingSpringAnim(this, RECT_CENTER_X, mCurrentCenterX,
                mTargetRect.centerX(), velocityPxPerMs.x * 1000, onXEndListener);
        mRectYAnim = new FlingSpringAnim(this, RECT_CENTER_Y, mCurrentCenterY,
                mTargetRect.centerY(), velocityPxPerMs.y * 1000, onYEndListener);

        float startX = mCurrentCenterX;
        float endX = mTargetRect.centerX();
        float minXValue = Math.min(startX, endX);
        float maxXValue = Math.max(startX, endX);
        mRectXAnim = new FlingSpringAnim(this, RECT_CENTER_X, startX, endX,
                velocityPxPerMs.x * 1000, mMinVisChange, minXValue, maxXValue, 1f, onXEndListener);

        float startVelocityY = velocityPxPerMs.y * 1000;
        // Scale the Y velocity based on the initial velocity to tune the curves.
        float springVelocityFactor = 0.1f + 0.9f * Math.abs(startVelocityY) / 20000.0f;
        float startY = mCurrentY;
        float endY = mTrackingBottomY ? mTargetRect.bottom : mTargetRect.top;
        float minYValue = Math.min(startY, endY - mYOvershoot);
        float maxYValue = Math.max(startY, endY);
        mRectYAnim = new FlingSpringAnim(this, RECT_Y, startY, endY, startVelocityY,
                mMinVisChange, minYValue, maxYValue, springVelocityFactor, onYEndListener);

        mRectScaleAnim = ObjectAnimator.ofPropertyValuesHolder(this,
                PropertyValuesHolder.ofFloat(RECT_SCALE_PROGRESS, 1))
@@ -182,8 +212,13 @@ public class RectFSpringAnim {
                    mTargetRect.width());
            float currentHeight = Utilities.mapRange(mCurrentScaleProgress, mStartRect.height(),
                    mTargetRect.height());
            mCurrentRect.set(mCurrentCenterX - currentWidth / 2, mCurrentCenterY - currentHeight / 2,
                    mCurrentCenterX + currentWidth / 2, mCurrentCenterY + currentHeight / 2);
            if (mTrackingBottomY) {
                mCurrentRect.set(mCurrentCenterX - currentWidth / 2, mCurrentY - currentHeight,
                        mCurrentCenterX + currentWidth / 2, mCurrentY);
            } else {
                mCurrentRect.set(mCurrentCenterX - currentWidth / 2, mCurrentY,
                        mCurrentCenterX + currentWidth / 2, mCurrentY + currentHeight);
            }
            for (OnUpdateListener onUpdateListener : mOnUpdateListeners) {
                onUpdateListener.onUpdate(mCurrentRect, mCurrentScaleProgress);
            }
+10 −8
Original line number Diff line number Diff line
@@ -28,8 +28,6 @@ import androidx.dynamicanimation.animation.SpringForce;
public class FlingSpringAnim {

    private static final float FLING_FRICTION = 1.5f;
    // Have the spring pull towards the target if we've slowed down too much before reaching it.
    private static final float FLING_END_THRESHOLD_PX = 50f;
    private static final float SPRING_STIFFNESS = 200;
    private static final float SPRING_DAMPING = 0.85f;

@@ -39,23 +37,27 @@ public class FlingSpringAnim {
    private float mTargetPosition;

    public <K> FlingSpringAnim(K object, FloatPropertyCompat<K> property, float startPosition,
            float targetPosition, float startVelocity, OnAnimationEndListener onEndListener) {
            float targetPosition, float startVelocity, float minVisChange, float minValue,
            float maxValue, float springVelocityFactor, OnAnimationEndListener onEndListener) {
        mFlingAnim = new FlingAnimation(object, property)
                .setFriction(FLING_FRICTION)
                .setMinimumVisibleChange(FLING_END_THRESHOLD_PX)
                // Have the spring pull towards the target if we've slowed down too much before
                // reaching it.
                .setMinimumVisibleChange(minVisChange)
                .setStartVelocity(startVelocity)
                .setMinValue(Math.min(startPosition, targetPosition))
                .setMaxValue(Math.max(startPosition, targetPosition));
                .setMinValue(minValue)
                .setMaxValue(maxValue);
        mTargetPosition = targetPosition;

        mFlingAnim.addEndListener(((animation, canceled, value, velocity) -> {
            mSpringAnim = new SpringAnimation(object, property)
                    .setStartVelocity(velocity)
                    .setStartValue(value)
                    .setStartVelocity(velocity * springVelocityFactor)
                    .setSpring(new SpringForce(mTargetPosition)
                            .setStiffness(SPRING_STIFFNESS)
                            .setDampingRatio(SPRING_DAMPING));
            mSpringAnim.addEndListener(onEndListener);
            mSpringAnim.start();
            mSpringAnim.animateToFinalPosition(mTargetPosition);
        }));
    }