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

Commit b9610108 authored by Lucas Dupin's avatar Lucas Dupin
Browse files

Fix issue where ripple would move

The correct behavior is for the circle to move inside the RenderNode
bounds. The RenderNode itself should not move at all.

Fixes: 182174260
Test: visual
Change-Id: I254138cada2586312530122fcb9ba4518d864cdf
parent c7a5fdd8
Loading
Loading
Loading
Loading
+8 −37
Original line number Diff line number Diff line
@@ -38,8 +38,7 @@ import java.util.function.Consumer;
 */
public final class RippleAnimationSession {
    private static final String TAG = "RippleAnimationSession";
    private static final int ENTER_ANIM_DURATION = 300;
    private static final int SLIDE_ANIM_DURATION = 450;
    private static final int ENTER_ANIM_DURATION = 450;
    private static final int EXIT_ANIM_DURATION = 300;
    private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
    private static final TimeInterpolator PATH_INTERPOLATOR =
@@ -50,16 +49,13 @@ public final class RippleAnimationSession {
    private Runnable mOnUpdate;
    private long mStartTime;
    private boolean mForceSoftware;
    private final float mWidth, mHeight;
    private final ValueAnimator mSparkle = ValueAnimator.ofFloat(0, 1);
    private final ArraySet<Animator> mActiveAnimations = new ArraySet<>(3);

    RippleAnimationSession(@NonNull AnimationProperties<Float, Paint> properties,
            boolean forceSoftware, float width, float height) {
            boolean forceSoftware) {
        mProperties = properties;
        mForceSoftware = forceSoftware;
        mWidth = width;
        mHeight = height;

        mSparkle.addUpdateListener(anim -> {
            final long now = AnimationUtils.currentAnimationTimeMillis();
@@ -134,7 +130,7 @@ public final class RippleAnimationSession {

    private long computeDelay() {
        final long timePassed =  AnimationUtils.currentAnimationTimeMillis() - mStartTime;
        return Math.max((long) SLIDE_ANIM_DURATION - timePassed, 0);
        return Math.max((long) ENTER_ANIM_DURATION - timePassed, 0);
    }

    private void notifyUpdate() {
@@ -175,54 +171,29 @@ public final class RippleAnimationSession {
                props = getCanvasProperties();
        RenderNodeAnimator expand =
                new RenderNodeAnimator(props.getProgress(), .5f);
        RenderNodeAnimator slideX =
                new RenderNodeAnimator(props.getX(), mWidth / 2);
        RenderNodeAnimator slideY =
                new RenderNodeAnimator(props.getY(), mHeight / 2);
        expand.setTarget(canvas);
        slideX.setTarget(canvas);
        slideY.setTarget(canvas);
        startAnimation(expand, slideX, slideY);
        startAnimation(expand);
    }

    private void startAnimation(Animator expand,
            Animator slideX, Animator slideY) {
        expand.setDuration(SLIDE_ANIM_DURATION);
        slideX.setDuration(SLIDE_ANIM_DURATION);
        slideY.setDuration(SLIDE_ANIM_DURATION);
        slideX.addListener(new AnimatorListener(this));
    private void startAnimation(Animator expand) {
        expand.setDuration(ENTER_ANIM_DURATION);
        expand.addListener(new AnimatorListener(this));
        expand.setInterpolator(LINEAR_INTERPOLATOR);
        slideX.setInterpolator(PATH_INTERPOLATOR);
        slideY.setInterpolator(PATH_INTERPOLATOR);
        expand.start();
        slideX.start();
        slideY.start();
        if (!mSparkle.isRunning()) {
            mSparkle.start();
            mActiveAnimations.add(mSparkle);
        }
        mActiveAnimations.add(expand);
        mActiveAnimations.add(slideX);
        mActiveAnimations.add(slideY);
    }

    private void enterSoftware() {
        ValueAnimator expand = ValueAnimator.ofFloat(0f, 0.5f);
        ValueAnimator slideX = ValueAnimator.ofFloat(
                mProperties.getX(), mWidth / 2);
        ValueAnimator slideY = ValueAnimator.ofFloat(
                mProperties.getY(), mHeight / 2);
        expand.addUpdateListener(updatedAnimation -> {
            notifyUpdate();
            mProperties.getShader().setProgress((Float) expand.getAnimatedValue());
        });
        slideX.addUpdateListener(anim -> {
            float x = (float) slideX.getAnimatedValue();
            float y = (float) slideY.getAnimatedValue();
            mProperties.setOrigin(x, y);
            mProperties.getShader().setOrigin(x, y);
        });
        startAnimation(expand, slideX, slideY);
        startAnimation(expand);
    }

    @NonNull AnimationProperties<Float, Paint> getProperties() {
+4 −4
Original line number Diff line number Diff line
@@ -842,7 +842,7 @@ public class RippleDrawable extends LayerDrawable {
        if (shouldAnimate && mRunningAnimations.size() <= MAX_RIPPLES) {
            RippleAnimationSession.AnimationProperties<Float, Paint> properties =
                    createAnimationProperties(x, y, w, h);
            mRunningAnimations.add(new RippleAnimationSession(properties, !useCanvasProps, w, h)
            mRunningAnimations.add(new RippleAnimationSession(properties, !useCanvasProps)
                    .setOnAnimationUpdated(() -> invalidateSelf(false))
                    .setOnSessionEnd(session -> {
                        mRunningAnimations.remove(session);
@@ -912,14 +912,14 @@ public class RippleDrawable extends LayerDrawable {
                ? mState.mColor.getColorForState(getState(), Color.BLACK)
                : mMaskColorFilter.getColor();
        shader.setColor(color);
        shader.setOrigin(x, y);
        shader.setOrigin(w / 2, y / 2);
        shader.setTouch(x, y);
        shader.setResolution(w, h);
        shader.setSecondsOffset(0);
        shader.setRadius(radius);
        shader.setProgress(.0f);
        properties = new RippleAnimationSession.AnimationProperties<>(
                x, y, radius, p, 0f,
                shader);
                w / 2, h / 2, radius, p, 0f, shader);
        if (mMaskShader == null) {
            shader.setShader(null);
        } else {
+8 −2
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.graphics.Shader;

final class RippleShader extends RuntimeShader {
    private static final String SHADER_UNIFORMS =  "uniform vec2 in_origin;\n"
            + "uniform vec2 in_touch;\n"
            + "uniform float in_progress;\n"
            + "uniform float in_maxRadius;\n"
            + "uniform vec2 in_resolution;\n"
@@ -79,12 +80,13 @@ final class RippleShader extends RuntimeShader {
            + "    float fadeIn = subProgress(0., 0.175, in_progress);\n"
            + "    float fadeOutNoise = subProgress(0.375, 1., in_progress);\n"
            + "    float fadeOutRipple = subProgress(0.375, 0.75, in_progress);\n"
            + "    float ring = getRingMask(p, in_origin, in_maxRadius, fadeIn);\n"
            + "    vec2 center = mix(in_touch, in_origin, fadeIn);\n"
            + "    float ring = getRingMask(p, center, in_maxRadius, fadeIn);\n"
            + "    float alpha = min(fadeIn, 1. - fadeOutNoise);\n"
            + "    float sparkle = sparkles(p, in_progress * 0.25 + in_secondsOffset)\n"
            + "        * ring * alpha;\n"
            + "    float fade = min(fadeIn, 1.-fadeOutRipple);\n"
            + "    vec4 circle = in_color * (softCircle(p, in_origin, in_maxRadius "
            + "    vec4 circle = in_color * (softCircle(p, center, in_maxRadius "
            + "      * fadeIn, 0.2) * fade);\n"
            + "    float mask = in_hasMask == 1. ? sample(in_shader).a > 0. ? 1. : 0. : 1.;\n"
            + "    return mix(circle, vec4(sparkle), sparkle) * mask;\n"
@@ -117,6 +119,10 @@ final class RippleShader extends RuntimeShader {
        setUniform("in_origin", new float[] {x, y});
    }

    public void setTouch(float x, float y) {
        setUniform("in_touch", new float[] {x, y});
    }

    public void setProgress(float progress) {
        setUniform("in_progress", progress);
    }