Loading packages/SystemUI/res/values/dimens.xml +3 −0 Original line number Diff line number Diff line Loading @@ -1216,6 +1216,7 @@ <dimen name="animated_action_button_corner_radius">24dp</dimen> <dimen name="animated_action_button_icon_size">20dp</dimen> <dimen name="animated_action_button_outline_stroke_width">1dp</dimen> <dimen name="animated_action_button_outline_stroke_width_emphasized">2dp</dimen> <dimen name="animated_action_button_padding_horizontal">12dp</dimen> <!-- The "inner" padding between the chip and the text should be 8dp, but since the chip drawable has an 8dp inset, we set the padding to be 8dp + 8dp to account for that. --> Loading @@ -1224,6 +1225,8 @@ <dimen name="animated_action_button_drawable_padding">8dp</dimen> <dimen name="animated_action_button_touch_target_height">48dp</dimen> <dimen name="animated_action_button_font_size">12sp</dimen> <dimen name="animated_action_button_glow_radius">8dp</dimen> <dimen name="animated_action_button_glow_radius_emphasized">7dp</dimen> <!-- A reasonable upper bound for the height of the smart reply button. The measuring code needs to start with a guess for the maximum size. Currently two-line smart reply buttons Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AnimatedActionBackgroundDrawable.kt +64 −36 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.animation.AnimatorListenerAdapter import android.animation.ValueAnimator import android.content.Context import android.content.res.ColorStateList import android.content.res.Configuration import android.graphics.Canvas import android.graphics.Color import android.graphics.ColorFilter Loading @@ -31,11 +32,14 @@ import android.graphics.Path import android.graphics.PixelFormat import android.graphics.Rect import android.graphics.RectF import android.graphics.RenderEffect import android.graphics.RenderNode import android.graphics.Shader import android.graphics.drawable.Drawable import android.graphics.drawable.RippleDrawable import androidx.core.content.ContextCompat import androidx.core.graphics.ColorUtils import androidx.core.graphics.withClip import com.android.systemui.res.R import com.android.wm.shell.shared.animation.Interpolators Loading Loading @@ -69,7 +73,7 @@ class AnimatedActionBackgroundDrawable( } class BaseBackgroundDrawable( context: Context, private val context: Context, onAnimationStarted: () -> Unit, onAnimationEnded: () -> Unit, onAnimationCancelled: () -> Unit, Loading @@ -86,33 +90,40 @@ class BaseBackgroundDrawable( context.resources .getDimensionPixelSize(R.dimen.animated_action_button_outline_stroke_width) .toFloat() private val emphasizedOutlineStrokeWidth = 2 * context.resources .getDimensionPixelSize( R.dimen.animated_action_button_outline_stroke_width_emphasized ) .toFloat() private val insetVertical = context.resources .getDimensionPixelSize(R.dimen.animated_action_button_inset_vertical) .toFloat() private val innerGlow = RenderNode("innerGlow").apply { val radiusResource = if (isNightMode(context)) { R.dimen.animated_action_button_glow_radius_emphasized } else { R.dimen.animated_action_button_glow_radius } val blurRadius = context.resources.getDimensionPixelSize(radiusResource).toFloat() val blurEffect = RenderEffect.createBlurEffect(blurRadius, blurRadius, Shader.TileMode.MIRROR) setRenderEffect(blurEffect) } private val buttonShape = Path() // Color and style private val outlineStaticColor = context.getColor(R.color.animated_action_button_stroke_color) private val bgPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { val bgColor = context.getColor(com.android.internal.R.color.materialColorSurfaceContainerHigh) color = bgColor style = Paint.Style.FILL } private val outlineGradientPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { color = outlineStaticColor style = Paint.Style.STROKE strokeWidth = outlineStrokeWidth } private val outlineSolidPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { color = outlineStaticColor style = Paint.Style.STROKE strokeWidth = outlineStrokeWidth } private val outlineStartColor = boostChroma(context.getColor(com.android.internal.R.color.materialColorTertiaryContainer)) Loading @@ -123,15 +134,15 @@ class BaseBackgroundDrawable( // Animation private var gradientAnimator: ValueAnimator private var rotationAngle = 20f // Start rotation at 20 degrees private val rotationStart = 35f // Start rotation at 35 degrees private var rotationAngle = rotationStart private var fadeAnimator: ValueAnimator? = null private var gradientAlpha = 255 // Fading out gradient private var solidAlpha = 0 // Fading in solid color private var innerGlowAlpha = 255 // Fading out gradient init { gradientAnimator = ValueAnimator.ofFloat(0f, 1f).apply { duration = 1750 duration = 5000 startDelay = 1000 interpolator = Interpolators.LINEAR repeatCount = 0 Loading @@ -148,7 +159,7 @@ class BaseBackgroundDrawable( ) addUpdateListener { animator -> val animatedValue = animator.animatedValue as Float rotationAngle = 20f + animatedValue * 360f // Rotate in a spiral rotationAngle = rotationStart + animatedValue * 720f // Rotate in a spiral invalidateSelf() } start() Loading @@ -156,11 +167,10 @@ class BaseBackgroundDrawable( fadeAnimator = ValueAnimator.ofFloat(0f, 1f).apply { duration = 500 startDelay = 2250 startDelay = 5000 addUpdateListener { animator -> val progress = animator.animatedValue as Float gradientAlpha = ((1 - progress) * 255).toInt() // Fade out gradient solidAlpha = (progress * 255).toInt() // Fade in color innerGlowAlpha = ((1 - progress) * 255).toInt() // Fade out inner glow invalidateSelf() } addListener( Loading @@ -177,14 +187,35 @@ class BaseBackgroundDrawable( override fun draw(canvas: Canvas) { val boundsF = RectF(bounds) boundsF.inset(0f, insetVertical) innerGlow.setPosition(0, 0, bounds.width(), bounds.height()) val glowCanvas = innerGlow.beginRecording(bounds.width(), bounds.height()) try { val strokeWidth = if (isNightMode(context)) { emphasizedOutlineStrokeWidth } else { outlineStrokeWidth } drawAnimatedOutline(glowCanvas, boundsF, innerGlowAlpha, strokeWidth) } finally { innerGlow.endRecording() } canvas.withClip(buttonShape) { drawAnimatedOutline(canvas, boundsF, 255, outlineStrokeWidth) canvas.drawRenderNode(innerGlow) } } private fun drawAnimatedOutline( canvas: Canvas, boundsF: RectF, alpha: Int, strokeWidth: Float, ) { buttonShape.reset() buttonShape.addRoundRect(boundsF, cornerRadius, cornerRadius, Path.Direction.CW) canvas.save() // Draw background canvas.clipPath(buttonShape) canvas.drawPath(buttonShape, bgPaint) // Set up outline gradient val gradientShader = LinearGradient( Loading @@ -203,13 +234,14 @@ class BaseBackgroundDrawable( // Apply gradient to outline outlineGradientPaint.shader = gradientShader outlineGradientPaint.alpha = gradientAlpha outlineGradientPaint.alpha = alpha outlineGradientPaint.strokeWidth = strokeWidth canvas.drawPath(buttonShape, outlineGradientPaint) // Apply solid color to outline outlineSolidPaint.alpha = solidAlpha canvas.drawPath(buttonShape, outlineSolidPaint) } canvas.restore() private fun isNightMode(context: Context): Boolean { val uiMode = context.resources.configuration.uiMode return uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES } override fun onBoundsChange(bounds: Rect) { Loading @@ -218,16 +250,12 @@ class BaseBackgroundDrawable( } override fun setAlpha(alpha: Int) { bgPaint.alpha = alpha outlineGradientPaint.alpha = alpha outlineSolidPaint.alpha = alpha invalidateSelf() } override fun setColorFilter(colorFilter: ColorFilter?) { bgPaint.colorFilter = colorFilter outlineGradientPaint.colorFilter = colorFilter outlineSolidPaint.colorFilter = colorFilter invalidateSelf() } Loading Loading
packages/SystemUI/res/values/dimens.xml +3 −0 Original line number Diff line number Diff line Loading @@ -1216,6 +1216,7 @@ <dimen name="animated_action_button_corner_radius">24dp</dimen> <dimen name="animated_action_button_icon_size">20dp</dimen> <dimen name="animated_action_button_outline_stroke_width">1dp</dimen> <dimen name="animated_action_button_outline_stroke_width_emphasized">2dp</dimen> <dimen name="animated_action_button_padding_horizontal">12dp</dimen> <!-- The "inner" padding between the chip and the text should be 8dp, but since the chip drawable has an 8dp inset, we set the padding to be 8dp + 8dp to account for that. --> Loading @@ -1224,6 +1225,8 @@ <dimen name="animated_action_button_drawable_padding">8dp</dimen> <dimen name="animated_action_button_touch_target_height">48dp</dimen> <dimen name="animated_action_button_font_size">12sp</dimen> <dimen name="animated_action_button_glow_radius">8dp</dimen> <dimen name="animated_action_button_glow_radius_emphasized">7dp</dimen> <!-- A reasonable upper bound for the height of the smart reply button. The measuring code needs to start with a guess for the maximum size. Currently two-line smart reply buttons Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AnimatedActionBackgroundDrawable.kt +64 −36 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.animation.AnimatorListenerAdapter import android.animation.ValueAnimator import android.content.Context import android.content.res.ColorStateList import android.content.res.Configuration import android.graphics.Canvas import android.graphics.Color import android.graphics.ColorFilter Loading @@ -31,11 +32,14 @@ import android.graphics.Path import android.graphics.PixelFormat import android.graphics.Rect import android.graphics.RectF import android.graphics.RenderEffect import android.graphics.RenderNode import android.graphics.Shader import android.graphics.drawable.Drawable import android.graphics.drawable.RippleDrawable import androidx.core.content.ContextCompat import androidx.core.graphics.ColorUtils import androidx.core.graphics.withClip import com.android.systemui.res.R import com.android.wm.shell.shared.animation.Interpolators Loading Loading @@ -69,7 +73,7 @@ class AnimatedActionBackgroundDrawable( } class BaseBackgroundDrawable( context: Context, private val context: Context, onAnimationStarted: () -> Unit, onAnimationEnded: () -> Unit, onAnimationCancelled: () -> Unit, Loading @@ -86,33 +90,40 @@ class BaseBackgroundDrawable( context.resources .getDimensionPixelSize(R.dimen.animated_action_button_outline_stroke_width) .toFloat() private val emphasizedOutlineStrokeWidth = 2 * context.resources .getDimensionPixelSize( R.dimen.animated_action_button_outline_stroke_width_emphasized ) .toFloat() private val insetVertical = context.resources .getDimensionPixelSize(R.dimen.animated_action_button_inset_vertical) .toFloat() private val innerGlow = RenderNode("innerGlow").apply { val radiusResource = if (isNightMode(context)) { R.dimen.animated_action_button_glow_radius_emphasized } else { R.dimen.animated_action_button_glow_radius } val blurRadius = context.resources.getDimensionPixelSize(radiusResource).toFloat() val blurEffect = RenderEffect.createBlurEffect(blurRadius, blurRadius, Shader.TileMode.MIRROR) setRenderEffect(blurEffect) } private val buttonShape = Path() // Color and style private val outlineStaticColor = context.getColor(R.color.animated_action_button_stroke_color) private val bgPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { val bgColor = context.getColor(com.android.internal.R.color.materialColorSurfaceContainerHigh) color = bgColor style = Paint.Style.FILL } private val outlineGradientPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { color = outlineStaticColor style = Paint.Style.STROKE strokeWidth = outlineStrokeWidth } private val outlineSolidPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { color = outlineStaticColor style = Paint.Style.STROKE strokeWidth = outlineStrokeWidth } private val outlineStartColor = boostChroma(context.getColor(com.android.internal.R.color.materialColorTertiaryContainer)) Loading @@ -123,15 +134,15 @@ class BaseBackgroundDrawable( // Animation private var gradientAnimator: ValueAnimator private var rotationAngle = 20f // Start rotation at 20 degrees private val rotationStart = 35f // Start rotation at 35 degrees private var rotationAngle = rotationStart private var fadeAnimator: ValueAnimator? = null private var gradientAlpha = 255 // Fading out gradient private var solidAlpha = 0 // Fading in solid color private var innerGlowAlpha = 255 // Fading out gradient init { gradientAnimator = ValueAnimator.ofFloat(0f, 1f).apply { duration = 1750 duration = 5000 startDelay = 1000 interpolator = Interpolators.LINEAR repeatCount = 0 Loading @@ -148,7 +159,7 @@ class BaseBackgroundDrawable( ) addUpdateListener { animator -> val animatedValue = animator.animatedValue as Float rotationAngle = 20f + animatedValue * 360f // Rotate in a spiral rotationAngle = rotationStart + animatedValue * 720f // Rotate in a spiral invalidateSelf() } start() Loading @@ -156,11 +167,10 @@ class BaseBackgroundDrawable( fadeAnimator = ValueAnimator.ofFloat(0f, 1f).apply { duration = 500 startDelay = 2250 startDelay = 5000 addUpdateListener { animator -> val progress = animator.animatedValue as Float gradientAlpha = ((1 - progress) * 255).toInt() // Fade out gradient solidAlpha = (progress * 255).toInt() // Fade in color innerGlowAlpha = ((1 - progress) * 255).toInt() // Fade out inner glow invalidateSelf() } addListener( Loading @@ -177,14 +187,35 @@ class BaseBackgroundDrawable( override fun draw(canvas: Canvas) { val boundsF = RectF(bounds) boundsF.inset(0f, insetVertical) innerGlow.setPosition(0, 0, bounds.width(), bounds.height()) val glowCanvas = innerGlow.beginRecording(bounds.width(), bounds.height()) try { val strokeWidth = if (isNightMode(context)) { emphasizedOutlineStrokeWidth } else { outlineStrokeWidth } drawAnimatedOutline(glowCanvas, boundsF, innerGlowAlpha, strokeWidth) } finally { innerGlow.endRecording() } canvas.withClip(buttonShape) { drawAnimatedOutline(canvas, boundsF, 255, outlineStrokeWidth) canvas.drawRenderNode(innerGlow) } } private fun drawAnimatedOutline( canvas: Canvas, boundsF: RectF, alpha: Int, strokeWidth: Float, ) { buttonShape.reset() buttonShape.addRoundRect(boundsF, cornerRadius, cornerRadius, Path.Direction.CW) canvas.save() // Draw background canvas.clipPath(buttonShape) canvas.drawPath(buttonShape, bgPaint) // Set up outline gradient val gradientShader = LinearGradient( Loading @@ -203,13 +234,14 @@ class BaseBackgroundDrawable( // Apply gradient to outline outlineGradientPaint.shader = gradientShader outlineGradientPaint.alpha = gradientAlpha outlineGradientPaint.alpha = alpha outlineGradientPaint.strokeWidth = strokeWidth canvas.drawPath(buttonShape, outlineGradientPaint) // Apply solid color to outline outlineSolidPaint.alpha = solidAlpha canvas.drawPath(buttonShape, outlineSolidPaint) } canvas.restore() private fun isNightMode(context: Context): Boolean { val uiMode = context.resources.configuration.uiMode return uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES } override fun onBoundsChange(bounds: Rect) { Loading @@ -218,16 +250,12 @@ class BaseBackgroundDrawable( } override fun setAlpha(alpha: Int) { bgPaint.alpha = alpha outlineGradientPaint.alpha = alpha outlineSolidPaint.alpha = alpha invalidateSelf() } override fun setColorFilter(colorFilter: ColorFilter?) { bgPaint.colorFilter = colorFilter outlineGradientPaint.colorFilter = colorFilter outlineSolidPaint.colorFilter = colorFilter invalidateSelf() } Loading