Loading graphics/java/android/graphics/RecordingCanvas.java +5 −3 Original line number Diff line number Diff line Loading @@ -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()); } /** Loading Loading @@ -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); Loading graphics/java/android/graphics/drawable/RippleAnimationSession.java +36 −19 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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) { Loading Loading @@ -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; } Loading @@ -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); } Loading Loading @@ -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); } Loading @@ -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() { Loading @@ -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()); Loading Loading @@ -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; Loading Loading @@ -279,5 +292,9 @@ public final class RippleAnimationSession { RippleShader getShader() { return mShader; } FloatType getNoisePhase() { return mNoisePhase; } } } graphics/java/android/graphics/drawable/RippleDrawable.java +2 −11 Original line number Diff line number Diff line Loading @@ -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>> Loading @@ -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(); Loading Loading @@ -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 { Loading graphics/java/android/graphics/drawable/RippleShader.java +3 −0 Original line number Diff line number Diff line Loading @@ -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))), Loading libs/hwui/SkiaCanvas.cpp +2 −1 Original line number Diff line number Diff line Loading @@ -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 Loading
graphics/java/android/graphics/RecordingCanvas.java +5 −3 Original line number Diff line number Diff line Loading @@ -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()); } /** Loading Loading @@ -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); Loading
graphics/java/android/graphics/drawable/RippleAnimationSession.java +36 −19 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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) { Loading Loading @@ -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; } Loading @@ -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); } Loading Loading @@ -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); } Loading @@ -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() { Loading @@ -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()); Loading Loading @@ -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; Loading Loading @@ -279,5 +292,9 @@ public final class RippleAnimationSession { RippleShader getShader() { return mShader; } FloatType getNoisePhase() { return mNoisePhase; } } }
graphics/java/android/graphics/drawable/RippleDrawable.java +2 −11 Original line number Diff line number Diff line Loading @@ -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>> Loading @@ -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(); Loading Loading @@ -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 { Loading
graphics/java/android/graphics/drawable/RippleShader.java +3 −0 Original line number Diff line number Diff line Loading @@ -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))), Loading
libs/hwui/SkiaCanvas.cpp +2 −1 Original line number Diff line number Diff line Loading @@ -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