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

Commit 6d1601a7 authored by Lucas Dupin's avatar Lucas Dupin
Browse files

Move sparkle animation to RenderThread

The sparkle loop animation was happening on the UI thread and is poses
some interesting challengers:
- Animations freezes when UI thread is busy, for example when
  startActivity is called.
- onDraw calls add unnecessary work to the UI thread, leading to jank
  in some cases, like PIP

Test: manual
Fixes: 184760248
Change-Id: Ie2840c767da61476678839eaac215dc3aff95b5c
parent 514f8b70
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -226,10 +226,12 @@ public final class RecordingCanvas extends BaseRecordingCanvas {
     */
    public void drawRipple(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
            CanvasProperty<Float> radius, CanvasProperty<Paint> paint,
            CanvasProperty<Float> progress, RuntimeShader shader) {
            CanvasProperty<Float> progress, CanvasProperty<Float> turbulencePhase,
            RuntimeShader shader) {
        nDrawRipple(mNativeCanvasWrapper, cx.getNativeContainer(), cy.getNativeContainer(),
                radius.getNativeContainer(), paint.getNativeContainer(),
                progress.getNativeContainer(), shader.getNativeShaderBuilder());
                progress.getNativeContainer(), turbulencePhase.getNativeContainer(),
                shader.getNativeShaderBuilder());
    }

    /**
@@ -290,7 +292,7 @@ public final class RecordingCanvas extends BaseRecordingCanvas {
            long propCy, long propRadius, long propPaint);
    @CriticalNative
    private static native void nDrawRipple(long renderer, long propCx, long propCy, long propRadius,
            long propPaint, long propProgress, long runtimeEffect);
            long propPaint, long propProgress, long turbulencePhase, long runtimeEffect);
    @CriticalNative
    private static native void nDrawRoundRect(long renderer, long propLeft, long propTop,
            long propRight, long propBottom, long propRx, long propRy, long propPaint);
+36 −19
Original line number Diff line number Diff line
@@ -40,6 +40,8 @@ public final class RippleAnimationSession {
    private static final String TAG = "RippleAnimationSession";
    private static final int ENTER_ANIM_DURATION = 450;
    private static final int EXIT_ANIM_DURATION = 300;
    private static final long NOISE_ANIMATION_DURATION = 7000;
    private static final long MAX_NOISE_PHASE = NOISE_ANIMATION_DURATION / 120;
    private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
    private static final Interpolator FAST_OUT_SLOW_IN =
            new PathInterpolator(0.4f, 0f, 0.2f, 1f);
@@ -49,7 +51,7 @@ public final class RippleAnimationSession {
    private Runnable mOnUpdate;
    private long mStartTime;
    private boolean mForceSoftware;
    private boolean mAnimateSparkle;
    private Animator mLoopAnimation;

    RippleAnimationSession(@NonNull AnimationProperties<Float, Paint> properties,
            boolean forceSoftware) {
@@ -88,16 +90,6 @@ public final class RippleAnimationSession {
        return this;
    }

    public boolean shouldAnimateSparkle() {
        return mAnimateSparkle && ValueAnimator.getDurationScale() > 0;
    }

    public float getSparklePhase() {
        final long now = AnimationUtils.currentAnimationTimeMillis();
        final long elapsed = now - mStartTime;
        return  (float) elapsed / 800;
    }

    private boolean isHwAccelerated(Canvas canvas) {
        return canvas.isHardwareAccelerated() && !mForceSoftware;
    }
@@ -114,7 +106,7 @@ public final class RippleAnimationSession {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                mAnimateSparkle = false;
                if (mLoopAnimation != null) mLoopAnimation.cancel();
                Consumer<RippleAnimationSession> onEnd = mOnSessionEnd;
                if (onEnd != null) onEnd.accept(RippleAnimationSession.this);
            }
@@ -148,7 +140,7 @@ public final class RippleAnimationSession {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                mAnimateSparkle = false;
                if (mLoopAnimation != null) mLoopAnimation.cancel();
                Consumer<RippleAnimationSession> onEnd = mOnSessionEnd;
                if (onEnd != null) onEnd.accept(RippleAnimationSession.this);
            }
@@ -167,24 +159,42 @@ public final class RippleAnimationSession {
        RenderNodeAnimator expand =
                new RenderNodeAnimator(props.getProgress(), .5f);
        expand.setTarget(canvas);
        startAnimation(expand);
        RenderNodeAnimator loop = new RenderNodeAnimator(props.getNoisePhase(), MAX_NOISE_PHASE);
        loop.setTarget(canvas);
        startAnimation(expand, loop);
    }

    private void startAnimation(Animator expand) {
    private void startAnimation(Animator expand, Animator loop) {
        expand.setDuration(ENTER_ANIM_DURATION);
        expand.addListener(new AnimatorListener(this));
        expand.setInterpolator(FAST_OUT_SLOW_IN);
        expand.start();
        mAnimateSparkle = true;
        loop.setDuration(NOISE_ANIMATION_DURATION);
        loop.addListener(new AnimatorListener(this) {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                mLoopAnimation = null;
            }
        });
        loop.setInterpolator(LINEAR_INTERPOLATOR);
        loop.start();
        if (mLoopAnimation != null) mLoopAnimation.cancel();
        mLoopAnimation = loop;
    }

    private void enterSoftware() {
        ValueAnimator expand = ValueAnimator.ofFloat(0f, 0.5f);
        expand.addUpdateListener(updatedAnimation -> {
            notifyUpdate();
            mProperties.getShader().setProgress((Float) expand.getAnimatedValue());
            mProperties.getShader().setProgress((float) expand.getAnimatedValue());
        });
        startAnimation(expand);
        ValueAnimator loop = ValueAnimator.ofFloat(0f, MAX_NOISE_PHASE);
        loop.addUpdateListener(updatedAnimation -> {
            notifyUpdate();
            mProperties.getShader().setNoisePhase((float) loop.getAnimatedValue());
        });
        startAnimation(expand, loop);
    }

    @NonNull AnimationProperties<Float, Paint> getProperties() {
@@ -198,6 +208,7 @@ public final class RippleAnimationSession {
                    CanvasProperty.createFloat(mProperties.getX()),
                    CanvasProperty.createFloat(mProperties.getY()),
                    CanvasProperty.createFloat(mProperties.getMaxRadius()),
                    CanvasProperty.createFloat(mProperties.getNoisePhase()),
                    CanvasProperty.createPaint(mProperties.getPaint()),
                    CanvasProperty.createFloat(mProperties.getProgress()),
                    mProperties.getShader());
@@ -236,16 +247,18 @@ public final class RippleAnimationSession {
    static class AnimationProperties<FloatType, PaintType> {
        private final FloatType mProgress;
        private final FloatType mMaxRadius;
        private final FloatType mNoisePhase;
        private final PaintType mPaint;
        private final RippleShader mShader;
        private FloatType mX;
        private FloatType mY;

        AnimationProperties(FloatType x, FloatType y, FloatType maxRadius,
        AnimationProperties(FloatType x, FloatType y, FloatType maxRadius, FloatType noisePhase,
                PaintType paint, FloatType progress, RippleShader shader) {
            mY = y;
            mX = x;
            mMaxRadius = maxRadius;
            mNoisePhase = noisePhase;
            mPaint = paint;
            mShader = shader;
            mProgress = progress;
@@ -279,5 +292,9 @@ public final class RippleAnimationSession {
        RippleShader getShader() {
            return mShader;
        }

        FloatType getNoisePhase() {
            return mNoisePhase;
        }
    }
}
+2 −11
Original line number Diff line number Diff line
@@ -858,15 +858,6 @@ public class RippleDrawable extends LayerDrawable {
        }
        for (int i = 0; i < mRunningAnimations.size(); i++) {
            RippleAnimationSession s = mRunningAnimations.get(i);
            if (s.shouldAnimateSparkle()) {
                final float phase = s.getSparklePhase();
                if (useCanvasProps) {
                    s.getCanvasProperties().getShader().setNoisePhase(phase);
                } else {
                    s.getProperties().getShader().setNoisePhase(phase);
                }
                invalidateSelf();
            }
            if (useCanvasProps) {
                RippleAnimationSession.AnimationProperties<CanvasProperty<Float>,
                        CanvasProperty<Paint>>
@@ -883,7 +874,7 @@ public class RippleDrawable extends LayerDrawable {
                    yProp = p.getY();
                }
                can.drawRipple(xProp, yProp, p.getMaxRadius(), p.getPaint(),
                        p.getProgress(), p.getShader());
                        p.getProgress(), p.getNoisePhase(), p.getShader());
            } else {
                RippleAnimationSession.AnimationProperties<Float, Paint> p =
                        s.getProperties();
@@ -953,7 +944,7 @@ public class RippleDrawable extends LayerDrawable {
        shader.setRadius(radius);
        shader.setProgress(.0f);
        properties = new RippleAnimationSession.AnimationProperties<>(
                cx, cy, radius, p, 0f, shader);
                cx, cy, radius, 0f, p, 0f, shader);
        if (mMaskShader == null) {
            shader.setShader(null);
        } else {
+3 −0
Original line number Diff line number Diff line
@@ -167,6 +167,9 @@ final class RippleShader extends RuntimeShader {
        final float turbulencePhase = (float) ((mProgress + mNoisePhase * 0.333f) * 5f * Math.PI);
        setUniform("in_turbulencePhase", turbulencePhase);

        //
        // Keep in sync with: frameworks/base/libs/hwui/pipeline/skia/AnimatedDrawables.h
        //
        final float scale = 1.5f;
        setUniform("in_tCircle1", new float[]{
                (float) (scale * 0.5 + (turbulencePhase * 0.01 * Math.cos(scale * 0.55))),
+2 −1
Original line number Diff line number Diff line
@@ -820,10 +820,11 @@ void SkiaCanvas::drawRipple(uirenderer::CanvasPropertyPrimitive* x,
                            uirenderer::CanvasPropertyPrimitive* radius,
                            uirenderer::CanvasPropertyPaint* paint,
                            uirenderer::CanvasPropertyPrimitive* progress,
                            uirenderer::CanvasPropertyPrimitive* turbulencePhase,
                            const SkRuntimeShaderBuilder& effectBuilder) {
    sk_sp<uirenderer::skiapipeline::AnimatedRipple> drawable(
            new uirenderer::skiapipeline::AnimatedRipple(x, y, radius, paint, progress,
                                                         effectBuilder));
                                                         turbulencePhase, effectBuilder));
    mCanvas->drawDrawable(drawable.get());
}

Loading