summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2025-01-23 14:58:26 -0800
committer Android (Google) Code Review <android-gerrit@google.com> 2025-01-23 14:58:26 -0800
commitddbd217c3ae05f15d178a9c824643449035ee9df (patch)
tree6051c18a1027e0cd90855cbe8f39d182899a90f9
parent2802b72fb11b142fc0b07bdbcb13384a65e22145 (diff)
parent0d7e0b246031a784c3133178f595a6ccc9ac78f3 (diff)
Merge "Magic action button animation" into main
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt124
1 files changed, 79 insertions, 45 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt
index 793b3b8b1e42..6aa5e405f29c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.row
+import android.animation.ValueAnimator
import android.content.Context
import android.graphics.BlendMode
import android.graphics.Canvas
@@ -38,8 +39,8 @@ import androidx.compose.ui.viewinterop.AndroidView
import com.android.internal.graphics.ColorUtils
import com.android.systemui.res.R
import com.android.systemui.surfaceeffects.shaderutil.ShaderUtilLibrary
-import kotlin.math.max
-import kotlin.math.roundToInt
+import com.android.wm.shell.shared.animation.Interpolators
+import kotlin.math.min
/**
* A background style for smarter-smart-actions. The style is composed by a simplex3d noise,
@@ -48,7 +49,7 @@ import kotlin.math.roundToInt
class MagicActionBackgroundDrawable(
context: Context,
primaryContainer: Int? = null,
- private val seed: Float = 0f,
+ seed: Float = 0f,
) : Drawable() {
private val pixelDensity = context.resources.displayMetrics.density
@@ -60,17 +61,15 @@ class MagicActionBackgroundDrawable(
.toFloat()
private val buttonShape = Path()
private val paddingVertical =
- context.resources
- .getDimensionPixelSize(R.dimen.smart_reply_button_padding_vertical)
- .toFloat()
+ context.resources.getDimensionPixelSize(R.dimen.smart_action_button_icon_padding).toFloat()
/** The color of the button background. */
private val mainColor =
primaryContainer
?: context.getColor(com.android.internal.R.color.materialColorPrimaryContainer)
- /** Slightly dimmed down version of [mainColor] used on the simplex noise. */
- private val dimColor: Int
+ /** Slightly brighter version of [mainColor] used on the simplex noise. */
+ private val effectColor: Int
get() {
val labColor = arrayOf(0.0, 0.0, 0.0).toDoubleArray()
ColorUtils.colorToLAB(mainColor, labColor)
@@ -78,56 +77,97 @@ class MagicActionBackgroundDrawable(
return ColorUtils.CAMToColor(
camColor.hue,
camColor.chroma,
- max(0f, (labColor[0] - 20).toFloat()),
+ min(100f, (labColor[0] + 10).toFloat()),
)
}
private val bgShader = MagicActionBackgroundShader()
private val bgPaint = Paint()
private val outlinePaint = Paint()
+ private val gradientAnimator =
+ ValueAnimator.ofFloat(0f, 1f).apply {
+ duration = 2500
+ interpolator = Interpolators.LINEAR
+ addUpdateListener { invalidateSelf() }
+ }
+ private val turbulenceAnimator =
+ ValueAnimator.ofFloat(seed, seed + TURBULENCE_MOVEMENT).apply {
+ duration = ANIMATION_DURATION
+ interpolator = Interpolators.LINEAR
+ addUpdateListener { invalidateSelf() }
+ start()
+ }
+ private val effectFadeAnimation =
+ ValueAnimator.ofFloat(0f, 1f).apply {
+ duration = 1000
+ startDelay = ANIMATION_DURATION - 1000L
+ interpolator = Interpolators.STANDARD_DECELERATE
+ addUpdateListener { invalidateSelf() }
+ }
init {
bgShader.setColorUniform("in_color", mainColor)
- bgShader.setColorUniform("in_dimColor", dimColor)
+ bgShader.setColorUniform("in_effectColor", effectColor)
bgPaint.shader = bgShader
outlinePaint.style = Paint.Style.STROKE
// Stroke is doubled in width and then clipped, to avoid anti-aliasing artifacts at the edge
// of the rectangle.
outlinePaint.strokeWidth = outlineStrokeWidth * 2
outlinePaint.blendMode = BlendMode.SCREEN
- outlinePaint.alpha = (255 * 0.32f).roundToInt()
+ outlinePaint.alpha = OUTLINE_ALPHA
+
+ animate()
+ }
+
+ private fun animate() {
+ turbulenceAnimator.start()
+ gradientAnimator.start()
+ effectFadeAnimation.start()
}
override fun draw(canvas: Canvas) {
+ updateShaders()
+
// We clip instead of drawing 2 rounded rects, otherwise there will be artifacts where
// around the button background and the outline.
+ canvas.save()
canvas.clipPath(buttonShape)
+ canvas.drawPath(buttonShape, bgPaint)
+ canvas.drawPath(buttonShape, outlinePaint)
+ canvas.restore()
+ }
- canvas.drawRect(bounds, bgPaint)
- canvas.drawRoundRect(
- bounds.left.toFloat(),
- bounds.top + paddingVertical,
- bounds.right.toFloat(),
- bounds.bottom - paddingVertical,
- cornerRadius,
- cornerRadius,
- outlinePaint,
- )
+ private fun updateShaders() {
+ val effectAlpha = 1f - effectFadeAnimation.animatedValue as Float
+ val turbulenceZ = turbulenceAnimator.animatedValue as Float
+ bgShader.setFloatUniform("in_sparkleMove", turbulenceZ * 1000)
+ bgShader.setFloatUniform("in_noiseMove", 0f, 0f, turbulenceZ)
+ bgShader.setFloatUniform("in_turbulenceAlpha", effectAlpha)
+ bgShader.setFloatUniform("in_spkarkleAlpha", SPARKLE_ALPHA * effectAlpha)
+ val gradientOffset = gradientAnimator.animatedValue as Float * bounds.width()
+ val outlineGradient =
+ LinearGradient(
+ gradientOffset + bounds.left.toFloat(),
+ 0f,
+ gradientOffset + bounds.right.toFloat(),
+ 0f,
+ mainColor,
+ ColorUtils.setAlphaComponent(mainColor, 0),
+ Shader.TileMode.MIRROR,
+ )
+ outlinePaint.shader = outlineGradient
}
override fun onBoundsChange(bounds: Rect) {
super.onBoundsChange(bounds)
val width = bounds.width().toFloat()
- val height = bounds.height() - paddingVertical * 2
+ val height = bounds.height().toFloat()
if (width == 0f || height == 0f) return
bgShader.setFloatUniform("in_gridNum", NOISE_SIZE)
- bgShader.setFloatUniform("in_spkarkleAlpha", SPARKLE_ALPHA)
- bgShader.setFloatUniform("in_noiseMove", 0f, 0f, 0f)
bgShader.setFloatUniform("in_size", width, height)
bgShader.setFloatUniform("in_aspectRatio", width / height)
- bgShader.setFloatUniform("in_time", seed)
bgShader.setFloatUniform("in_pixelDensity", pixelDensity)
buttonShape.reset()
@@ -140,18 +180,6 @@ class MagicActionBackgroundDrawable(
cornerRadius,
Path.Direction.CW,
)
-
- val outlineGradient =
- LinearGradient(
- bounds.left.toFloat(),
- 0f,
- bounds.right.toFloat(),
- 0f,
- mainColor,
- ColorUtils.setAlphaComponent(mainColor, 0),
- Shader.TileMode.CLAMP,
- )
- outlinePaint.shader = outlineGradient
}
override fun setAlpha(alpha: Int) {
@@ -168,10 +196,15 @@ class MagicActionBackgroundDrawable(
companion object {
/** Smoothness of the turbulence. Larger numbers yield more detail. */
- private const val NOISE_SIZE = 0.7f
-
+ private const val NOISE_SIZE = 0.57f
/** Strength of the sparkles overlaid on the turbulence. */
private const val SPARKLE_ALPHA = 0.15f
+ /** Alpha (0..255) of the button outline */
+ private const val OUTLINE_ALPHA = 82
+ /** Turbulence grid size */
+ private const val TURBULENCE_MOVEMENT = 4.3f
+ /** Total animation duration in millis */
+ private const val ANIMATION_DURATION = 5000L
}
}
@@ -183,24 +216,25 @@ private class MagicActionBackgroundShader : RuntimeShader(SHADER) {
"""
uniform float in_gridNum;
uniform vec3 in_noiseMove;
+ uniform half in_sparkleMove;
uniform vec2 in_size;
uniform float in_aspectRatio;
- uniform half in_time;
uniform half in_pixelDensity;
+ uniform float in_turbulenceAlpha;
uniform float in_spkarkleAlpha;
layout(color) uniform vec4 in_color;
- layout(color) uniform vec4 in_dimColor;
+ layout(color) uniform vec4 in_effectColor;
"""
private const val MAIN_SHADER =
"""vec4 main(vec2 p) {
vec2 uv = p / in_size.xy;
uv.x *= in_aspectRatio;
vec3 noiseP = vec3(uv + in_noiseMove.xy, in_noiseMove.z) * in_gridNum;
- half luma = 1.0 - getLuminosity(half3(simplex3d(noiseP)));
- half4 turbulenceColor = mix(in_color, in_dimColor, luma);
- float sparkle = sparkles(p - mod(p, in_pixelDensity * 0.8), in_time);
+ half luma = getLuminosity(half3(simplex3d(noiseP)));
+ half4 turbulenceColor = mix(in_color, in_effectColor, luma * in_turbulenceAlpha);
+ float sparkle = sparkles(p - mod(p, in_pixelDensity * 0.8), in_sparkleMove);
sparkle = min(sparkle * in_spkarkleAlpha, in_spkarkleAlpha);
- return turbulenceColor + half4(half3(sparkle), 1.0);
+ return saturate(turbulenceColor + half4(sparkle));
}
"""
private const val SHADER = UNIFORMS + ShaderUtilLibrary.SHADER_LIB + MAIN_SHADER