diff options
| author | 2024-12-04 10:44:27 +0100 | |
|---|---|---|
| committer | 2024-12-04 10:56:50 +0100 | |
| commit | c352ec75c90656c85d5743318a996b12d995a6bc (patch) | |
| tree | abb70d4e0ae3a6e0af273000141b2e0841bbf7e2 | |
| parent | 2874563914f1a2101900b2d2589dbca4609ea925 (diff) | |
Convert interpolated colors to original color space
This CL fixes a crash that can happen when animating a Color using
animateElementColorAsState(): the interpolated Color will end up in the
Oklab color space (instead of the original color space), which is not
supported by the Android platform.
Bug: 382043554
Test: atest AnimatedSharedAsStateTest
Flag: com.android.systemui.scene_container
Change-Id: I6b32af10534f6112560bc174e734c00ce442688b
2 files changed, 16 insertions, 4 deletions
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt index 0fc88b22a4d0..a4237f36ab58 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt @@ -225,7 +225,7 @@ fun ElementScope<*>.animateElementColorAsState(value: Color, key: ValueKey): Ani return animateElementValueAsState(value, key, SharedColorType, canOverflow = false) } -private object SharedColorType : SharedValueType<Color, ColorDelta> { +internal object SharedColorType : SharedValueType<Color, ColorDelta> { override val unspecifiedValue: Color = Color.Unspecified override val zeroDeltaValue: ColorDelta = ColorDelta(0f, 0f, 0f, 0f) @@ -255,17 +255,17 @@ private object SharedColorType : SharedValueType<Color, ColorDelta> { alpha = aOklab.alpha + b.alpha * bWeight, colorSpace = ColorSpaces.Oklab, ) - .convert(aOklab.colorSpace) + .convert(a.colorSpace) } } /** - * Represents the diff between two colors in the same color space. + * Represents the diff between two colors in the Oklab color space. * * Note: This class is necessary because Color() checks the bounds of its values and UncheckedColor * is internal. */ -private class ColorDelta(val red: Float, val green: Float, val blue: Float, val alpha: Float) +internal class ColorDelta(val red: Float, val green: Float, val blue: Float, val alpha: Float) @Composable internal fun <T> animateSharedValueAsState( diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt index 3644b3069fb3..2fd1d8d8573a 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/AnimatedSharedAsStateTest.kt @@ -18,7 +18,10 @@ package com.android.compose.animation.scene import androidx.compose.animation.core.LinearEasing import androidx.compose.animation.core.tween +import androidx.compose.foundation.background import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.SideEffect @@ -495,4 +498,13 @@ class AnimatedSharedAsStateTest { assertThat(lastValues[SceneA]).isWithin(0.001f).of(100f) assertThat(lastValues[SceneB]).isWithin(0.001f).of(100f) } + + @Test + fun interpolatedColor() { + val a = Color.Red + val b = Color.Green + val delta = SharedColorType.diff(b, a) // b - a + val interpolated = SharedColorType.addWeighted(a, delta, 0.5f) // a + (b - a) * 0.5f + rule.setContent { Box(Modifier.fillMaxSize().background(interpolated)) } + } } |