Update uniform params for the tablet docking animation.

Please find the recordings in the bug attached.

Bug: 269124200
Test: Manual
Test: adb shell cmd statusbar docking-ripple
Change-Id: I31f7baf272f67be4ab85b3e35fd0a0269cf0e0ed
This commit is contained in:
Yein Jo
2023-02-16 18:47:36 +00:00
parent fabc17ea4e
commit 6a731c2c8a
2 changed files with 162 additions and 21 deletions

View File

@@ -80,6 +80,87 @@ open class RippleView(context: Context?, attrs: AttributeSet?) : View(context, a
ripplePaint.shader = rippleShader
}
/**
* Sets the fade parameters for the base ring.
*
* <p>Base ring indicates a blurred ring below the sparkle ring. See
* [RippleShader.baseRingFadeParams].
*/
@JvmOverloads
fun setBaseRingFadeParams(
fadeInStart: Float = rippleShader.baseRingFadeParams.fadeInStart,
fadeInEnd: Float = rippleShader.baseRingFadeParams.fadeInEnd,
fadeOutStart: Float = rippleShader.baseRingFadeParams.fadeOutStart,
fadeOutEnd: Float = rippleShader.baseRingFadeParams.fadeOutEnd
) {
setFadeParams(
rippleShader.baseRingFadeParams,
fadeInStart,
fadeInEnd,
fadeOutStart,
fadeOutEnd
)
}
/**
* Sets the fade parameters for the sparkle ring.
*
* <p>Sparkle ring refers to the ring that's drawn on top of the base ring. See
* [RippleShader.sparkleRingFadeParams].
*/
@JvmOverloads
fun setSparkleRingFadeParams(
fadeInStart: Float = rippleShader.sparkleRingFadeParams.fadeInStart,
fadeInEnd: Float = rippleShader.sparkleRingFadeParams.fadeInEnd,
fadeOutStart: Float = rippleShader.sparkleRingFadeParams.fadeOutStart,
fadeOutEnd: Float = rippleShader.sparkleRingFadeParams.fadeOutEnd
) {
setFadeParams(
rippleShader.sparkleRingFadeParams,
fadeInStart,
fadeInEnd,
fadeOutStart,
fadeOutEnd
)
}
/**
* Sets the fade parameters for the center fill.
*
* <p>One common use case is set all the params to 1, which completely removes the center fill.
* See [RippleShader.centerFillFadeParams].
*/
@JvmOverloads
fun setCenterFillFadeParams(
fadeInStart: Float = rippleShader.centerFillFadeParams.fadeInStart,
fadeInEnd: Float = rippleShader.centerFillFadeParams.fadeInEnd,
fadeOutStart: Float = rippleShader.centerFillFadeParams.fadeOutStart,
fadeOutEnd: Float = rippleShader.centerFillFadeParams.fadeOutEnd
) {
setFadeParams(
rippleShader.centerFillFadeParams,
fadeInStart,
fadeInEnd,
fadeOutStart,
fadeOutEnd
)
}
private fun setFadeParams(
fadeParams: RippleShader.FadeParams,
fadeInStart: Float,
fadeInEnd: Float,
fadeOutStart: Float,
fadeOutEnd: Float
) {
with(fadeParams) {
this.fadeInStart = fadeInStart
this.fadeInEnd = fadeInEnd
this.fadeOutStart = fadeOutStart
this.fadeOutEnd = fadeOutEnd
}
}
/**
* Sets blur multiplier at start and end of the progress.
*
@@ -148,11 +229,11 @@ open class RippleView(context: Context?, attrs: AttributeSet?) : View(context, a
}
// To reduce overdraw, we mask the effect to a circle or a rectangle that's bigger than the
// active effect area. Values here should be kept in sync with the animation implementation
// in the ripple shader. (Twice bigger)
// in the ripple shader.
if (rippleShape == RippleShape.CIRCLE) {
val maskRadius = rippleShader.rippleSize.currentWidth
canvas.drawCircle(centerX, centerY, maskRadius, ripplePaint)
} else {
} else if (rippleShape == RippleShape.ELLIPSE) {
val maskWidth = rippleShader.rippleSize.currentWidth * 2
val maskHeight = rippleShader.rippleSize.currentHeight * 2
canvas.drawRect(
@@ -162,6 +243,10 @@ open class RippleView(context: Context?, attrs: AttributeSet?) : View(context, a
/* bottom= */ centerY + maskHeight,
ripplePaint
)
} else { // RippleShape.RoundedBox
// No masking for the rounded box, as it has more blur which requires larger bounds.
// Masking creates sharp bounds even when the masking is 4 times bigger.
canvas.drawPaint(ripplePaint)
}
}
}

View File

@@ -33,7 +33,9 @@ import android.widget.TextView;
import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.surfaceeffects.ripple.RippleAnimationConfig;
import com.android.systemui.surfaceeffects.ripple.RippleShader;
import com.android.systemui.surfaceeffects.ripple.RippleShader.RippleShape;
import com.android.systemui.surfaceeffects.ripple.RippleView;
@@ -44,10 +46,12 @@ import java.text.NumberFormat;
*/
final class WirelessChargingLayout extends FrameLayout {
private static final long CIRCLE_RIPPLE_ANIMATION_DURATION = 1500;
private static final long ROUNDED_BOX_RIPPLE_ANIMATION_DURATION = 1750;
private static final long ROUNDED_BOX_RIPPLE_ANIMATION_DURATION = 3000;
private static final int SCRIM_COLOR = 0x4C000000;
private static final int SCRIM_FADE_DURATION = 300;
private RippleView mRippleView;
// This is only relevant to the rounded box ripple.
private RippleShader.SizeAtProgress[] mSizeAtProgressArray;
WirelessChargingLayout(Context context, int transmittingBatteryLevel, int batteryLevel,
boolean isDozing, RippleShape rippleShape) {
@@ -125,20 +129,23 @@ final class WirelessChargingLayout extends FrameLayout {
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(textSizeAnimator, textOpacityAnimator, textFadeAnimator);
ValueAnimator scrimFadeInAnimator = ObjectAnimator.ofArgb(this,
"backgroundColor", Color.TRANSPARENT, SCRIM_COLOR);
scrimFadeInAnimator.setDuration(SCRIM_FADE_DURATION);
scrimFadeInAnimator.setInterpolator(Interpolators.LINEAR);
ValueAnimator scrimFadeOutAnimator = ObjectAnimator.ofArgb(this,
"backgroundColor", SCRIM_COLOR, Color.TRANSPARENT);
scrimFadeOutAnimator.setDuration(SCRIM_FADE_DURATION);
scrimFadeOutAnimator.setInterpolator(Interpolators.LINEAR);
scrimFadeOutAnimator.setStartDelay((rippleShape == RippleShape.CIRCLE
? CIRCLE_RIPPLE_ANIMATION_DURATION : ROUNDED_BOX_RIPPLE_ANIMATION_DURATION)
- SCRIM_FADE_DURATION);
AnimatorSet animatorSetScrim = new AnimatorSet();
animatorSetScrim.playTogether(scrimFadeInAnimator, scrimFadeOutAnimator);
animatorSetScrim.start();
// For tablet docking animation, we don't play the background scrim.
if (!Utilities.isTablet(context)) {
ValueAnimator scrimFadeInAnimator = ObjectAnimator.ofArgb(this,
"backgroundColor", Color.TRANSPARENT, SCRIM_COLOR);
scrimFadeInAnimator.setDuration(SCRIM_FADE_DURATION);
scrimFadeInAnimator.setInterpolator(Interpolators.LINEAR);
ValueAnimator scrimFadeOutAnimator = ObjectAnimator.ofArgb(this,
"backgroundColor", SCRIM_COLOR, Color.TRANSPARENT);
scrimFadeOutAnimator.setDuration(SCRIM_FADE_DURATION);
scrimFadeOutAnimator.setInterpolator(Interpolators.LINEAR);
scrimFadeOutAnimator.setStartDelay((rippleShape == RippleShape.CIRCLE
? CIRCLE_RIPPLE_ANIMATION_DURATION : ROUNDED_BOX_RIPPLE_ANIMATION_DURATION)
- SCRIM_FADE_DURATION);
AnimatorSet animatorSetScrim = new AnimatorSet();
animatorSetScrim.playTogether(scrimFadeInAnimator, scrimFadeOutAnimator);
animatorSetScrim.start();
}
mRippleView = findViewById(R.id.wireless_charging_ripple);
mRippleView.setupShader(rippleShape);
@@ -147,7 +154,26 @@ final class WirelessChargingLayout extends FrameLayout {
if (mRippleView.getRippleShape() == RippleShape.ROUNDED_BOX) {
mRippleView.setDuration(ROUNDED_BOX_RIPPLE_ANIMATION_DURATION);
mRippleView.setSparkleStrength(0.22f);
mRippleView.setColor(color, 28);
mRippleView.setColor(color, 102); // 40% of opacity.
mRippleView.setBaseRingFadeParams(
/* fadeInStart = */ 0f,
/* fadeInEnd = */ 0f,
/* fadeOutStart = */ 0.2f,
/* fadeOutEnd= */ 0.47f
);
mRippleView.setSparkleRingFadeParams(
/* fadeInStart = */ 0f,
/* fadeInEnd = */ 0f,
/* fadeOutStart = */ 0.2f,
/* fadeOutEnd= */ 1f
);
mRippleView.setCenterFillFadeParams(
/* fadeInStart = */ 0f,
/* fadeInEnd = */ 0f,
/* fadeOutStart = */ 0f,
/* fadeOutEnd= */ 0.2f
);
mRippleView.setBlur(6.5f, 2.5f);
} else {
mRippleView.setDuration(CIRCLE_RIPPLE_ANIMATION_DURATION);
mRippleView.setColor(color, RippleAnimationConfig.RIPPLE_DEFAULT_ALPHA);
@@ -246,9 +272,7 @@ final class WirelessChargingLayout extends FrameLayout {
int height = getMeasuredHeight();
mRippleView.setCenter(width * 0.5f, height * 0.5f);
if (mRippleView.getRippleShape() == RippleShape.ROUNDED_BOX) {
// Those magic numbers are introduced for visual polish. This aspect ratio maps with
// the tablet's docking station.
mRippleView.setMaxSize(width * 1.36f, height * 1.46f);
updateRippleSizeAtProgressList(width, height);
} else {
float maxSize = Math.max(width, height);
mRippleView.setMaxSize(maxSize, maxSize);
@@ -257,4 +281,36 @@ final class WirelessChargingLayout extends FrameLayout {
super.onLayout(changed, left, top, right, bottom);
}
private void updateRippleSizeAtProgressList(float width, float height) {
if (mSizeAtProgressArray == null) {
float maxSize = Math.max(width, height);
mSizeAtProgressArray = new RippleShader.SizeAtProgress[] {
// Those magic numbers are introduced for visual polish. It starts from a pill
// shape and expand to a full circle.
new RippleShader.SizeAtProgress(0f, 0f, 0f),
new RippleShader.SizeAtProgress(0.3f, width * 0.4f, height * 0.4f),
new RippleShader.SizeAtProgress(1f, maxSize, maxSize)
};
} else {
// Same multipliers, just need to recompute with the new width and height.
RippleShader.SizeAtProgress first = mSizeAtProgressArray[0];
first.setT(0f);
first.setWidth(0f);
first.setHeight(0f);
RippleShader.SizeAtProgress second = mSizeAtProgressArray[1];
second.setT(0.3f);
second.setWidth(width * 0.4f);
second.setHeight(height * 0.4f);
float maxSize = Math.max(width, height);
RippleShader.SizeAtProgress last = mSizeAtProgressArray[2];
last.setT(1f);
last.setWidth(maxSize);
last.setHeight(maxSize);
}
mRippleView.setSizeAtProgresses(mSizeAtProgressArray);
}
}