diff options
| author | 2025-01-23 14:58:26 -0800 | |
|---|---|---|
| committer | 2025-01-23 14:58:26 -0800 | |
| commit | ddbd217c3ae05f15d178a9c824643449035ee9df (patch) | |
| tree | 6051c18a1027e0cd90855cbe8f39d182899a90f9 | |
| parent | 2802b72fb11b142fc0b07bdbcb13384a65e22145 (diff) | |
| parent | 0d7e0b246031a784c3133178f595a6ccc9ac78f3 (diff) | |
Merge "Magic action button animation" into main
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt | 124 |
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 |