From 4176f5fa5fc440a5b271a4baee3974c4fd263571 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Thu, 1 Apr 2021 15:16:45 -0700 Subject: [PATCH] Replace animator with render loop logic The animator had infinite duration, and was only cancelled during a render loop. It was possible that it would get stuck, leaking the drawable. Bug: 183950010 Test: TaplTestsLauncher3 (on sysui studio) Change-Id: I2cc0d69ef19bb4fb775d319befde9bfc9df8d0ae --- .../drawable/RippleAnimationSession.java | 31 +++++++++---------- .../graphics/drawable/RippleDrawable.java | 9 ++++++ 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/graphics/java/android/graphics/drawable/RippleAnimationSession.java b/graphics/java/android/graphics/drawable/RippleAnimationSession.java index 94d5c22653722..fb089741dfb21 100644 --- a/graphics/java/android/graphics/drawable/RippleAnimationSession.java +++ b/graphics/java/android/graphics/drawable/RippleAnimationSession.java @@ -49,23 +49,12 @@ public final class RippleAnimationSession { private Runnable mOnUpdate; private long mStartTime; private boolean mForceSoftware; - private final ValueAnimator mSparkle = ValueAnimator.ofFloat(0, 1); + private boolean mAnimateSparkle; RippleAnimationSession(@NonNull AnimationProperties properties, boolean forceSoftware) { mProperties = properties; mForceSoftware = forceSoftware; - - mSparkle.addUpdateListener(anim -> { - final long now = AnimationUtils.currentAnimationTimeMillis(); - final long elapsed = now - mStartTime - ENTER_ANIM_DURATION; - final float phase = (float) elapsed / 800; - mProperties.getShader().setNoisePhase(phase); - notifyUpdate(); - }); - mSparkle.setDuration(ENTER_ANIM_DURATION); - mSparkle.setInterpolator(LINEAR_INTERPOLATOR); - mSparkle.setRepeatCount(ValueAnimator.INFINITE); } @NonNull RippleAnimationSession enter(Canvas canvas) { @@ -99,6 +88,16 @@ public final class RippleAnimationSession { return this; } + public boolean shouldAnimateSparkle() { + return mAnimateSparkle; + } + + 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; } @@ -115,7 +114,7 @@ public final class RippleAnimationSession { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); - mSparkle.end(); + mAnimateSparkle = false; Consumer onEnd = mOnSessionEnd; if (onEnd != null) onEnd.accept(RippleAnimationSession.this); } @@ -149,7 +148,7 @@ public final class RippleAnimationSession { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); - mSparkle.end(); + mAnimateSparkle = false; Consumer onEnd = mOnSessionEnd; if (onEnd != null) onEnd.accept(RippleAnimationSession.this); } @@ -176,9 +175,7 @@ public final class RippleAnimationSession { expand.addListener(new AnimatorListener(this)); expand.setInterpolator(FAST_OUT_LINEAR_IN); expand.start(); - if (!mSparkle.isRunning()) { - mSparkle.start(); - } + mAnimateSparkle = true; } private void enterSoftware() { diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java index 3bd0a43652d22..b6897701a570d 100644 --- a/graphics/java/android/graphics/drawable/RippleDrawable.java +++ b/graphics/java/android/graphics/drawable/RippleDrawable.java @@ -861,6 +861,15 @@ 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>