Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c352ec75 authored by Jordan Demeulenaere's avatar Jordan Demeulenaere
Browse files

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
parent 28745639
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -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(
+12 −0
Original line number Diff line number Diff line
@@ -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)) }
    }
}