diff --git a/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/AndroidColorScheme.kt b/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/AndroidColorScheme.kt new file mode 100644 index 0000000000000..4d5014cdbba77 --- /dev/null +++ b/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/AndroidColorScheme.kt @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.compose.theme + +import android.annotation.ColorInt +import android.content.Context +import androidx.compose.runtime.staticCompositionLocalOf +import androidx.compose.ui.graphics.Color +import com.android.internal.R + +/** CompositionLocal used to pass [AndroidColorScheme] down the tree. */ +val LocalAndroidColorScheme = + staticCompositionLocalOf { + throw IllegalStateException( + "No AndroidColorScheme configured. Make sure to use LocalAndroidColorScheme in a " + + "Composable surrounded by a SystemUITheme {}." + ) + } + +/** + * The Android color scheme. + * + * Important: Use M3 colors from MaterialTheme.colorScheme whenever possible instead. In the future, + * most of the colors in this class will be removed in favor of their M3 counterpart. + */ +class AndroidColorScheme internal constructor(private val context: Context) { + val colorPrimary = getColor(context, R.attr.colorPrimary) + val colorPrimaryDark = getColor(context, R.attr.colorPrimaryDark) + val colorAccent = getColor(context, R.attr.colorAccent) + val colorAccentPrimary = getColor(context, R.attr.colorAccentPrimary) + val colorAccentSecondary = getColor(context, R.attr.colorAccentSecondary) + val colorAccentTertiary = getColor(context, R.attr.colorAccentTertiary) + val colorAccentPrimaryVariant = getColor(context, R.attr.colorAccentPrimaryVariant) + val colorAccentSecondaryVariant = getColor(context, R.attr.colorAccentSecondaryVariant) + val colorAccentTertiaryVariant = getColor(context, R.attr.colorAccentTertiaryVariant) + val colorSurface = getColor(context, R.attr.colorSurface) + val colorSurfaceHighlight = getColor(context, R.attr.colorSurfaceHighlight) + val colorSurfaceVariant = getColor(context, R.attr.colorSurfaceVariant) + val colorSurfaceHeader = getColor(context, R.attr.colorSurfaceHeader) + val colorError = getColor(context, R.attr.colorError) + val colorBackground = getColor(context, R.attr.colorBackground) + val colorBackgroundFloating = getColor(context, R.attr.colorBackgroundFloating) + val panelColorBackground = getColor(context, R.attr.panelColorBackground) + val textColorPrimary = getColor(context, R.attr.textColorPrimary) + val textColorSecondary = getColor(context, R.attr.textColorSecondary) + val textColorTertiary = getColor(context, R.attr.textColorTertiary) + val textColorPrimaryInverse = getColor(context, R.attr.textColorPrimaryInverse) + val textColorSecondaryInverse = getColor(context, R.attr.textColorSecondaryInverse) + val textColorTertiaryInverse = getColor(context, R.attr.textColorTertiaryInverse) + val textColorOnAccent = getColor(context, R.attr.textColorOnAccent) + val colorForeground = getColor(context, R.attr.colorForeground) + val colorForegroundInverse = getColor(context, R.attr.colorForegroundInverse) + + private fun getColor(context: Context, attr: Int): Color { + val ta = context.obtainStyledAttributes(intArrayOf(attr)) + @ColorInt val color = ta.getColor(0, 0) + ta.recycle() + return Color(color) + } +} diff --git a/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/SystemUITheme.kt b/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/SystemUITheme.kt index de53c05c7f675..79e3d3d475a89 100644 --- a/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/SystemUITheme.kt +++ b/packages/SystemUI/compose/core/src/com/android/systemui/compose/theme/SystemUITheme.kt @@ -22,6 +22,7 @@ import androidx.compose.material3.Typography import androidx.compose.material3.dynamicDarkColorScheme import androidx.compose.material3.dynamicLightColorScheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.platform.LocalContext /** The Material 3 theme that should wrap all SystemUI Composables. */ @@ -39,7 +40,14 @@ fun SystemUITheme( } else { dynamicLightColorScheme(context) } + val androidColorScheme = AndroidColorScheme(context) val typography = Typography() - MaterialTheme(colorScheme, typography = typography) { content() } + MaterialTheme(colorScheme, typography = typography) { + CompositionLocalProvider( + LocalAndroidColorScheme provides androidColorScheme, + ) { + content() + } + } } diff --git a/packages/SystemUI/compose/core/tests/src/com/android/systemui/compose/theme/SystemUIThemeTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/systemui/compose/theme/SystemUIThemeTest.kt index 155b66c071100..20249f66d0d0b 100644 --- a/packages/SystemUI/compose/core/tests/src/com/android/systemui/compose/theme/SystemUIThemeTest.kt +++ b/packages/SystemUI/compose/core/tests/src/com/android/systemui/compose/theme/SystemUIThemeTest.kt @@ -21,6 +21,7 @@ import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.onNodeWithText import androidx.test.ext.junit.runners.AndroidJUnit4 +import org.junit.Assert.assertThrows import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -35,4 +36,22 @@ class SystemUIThemeTest { composeRule.onNodeWithText("foo").assertIsDisplayed() } + + @Test + fun testAndroidColorsAreAvailableInsideTheme() { + composeRule.setContent { + SystemUITheme { Text("foo", color = LocalAndroidColorScheme.current.colorAccent) } + } + + composeRule.onNodeWithText("foo").assertIsDisplayed() + } + + @Test + fun testAccessingAndroidColorsWithoutThemeThrows() { + assertThrows(IllegalStateException::class.java) { + composeRule.setContent { + Text("foo", color = LocalAndroidColorScheme.current.colorAccent) + } + } + } } diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ColorsScreen.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ColorsScreen.kt index b616753e423f9..dfa1b26f464ef 100644 --- a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ColorsScreen.kt +++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/ColorsScreen.kt @@ -20,6 +20,7 @@ import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width @@ -32,38 +33,88 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp +import com.android.systemui.compose.theme.LocalAndroidColorScheme /** The screen that shows all the Material 3 colors. */ @Composable -fun ColorsScreen() { +fun MaterialColorsScreen() { val colors = MaterialTheme.colorScheme - LazyColumn { - item { ColorTile(colors.primary, "primary") } - item { ColorTile(colors.onPrimary, "onPrimary") } - item { ColorTile(colors.primaryContainer, "primaryContainer") } - item { ColorTile(colors.onPrimaryContainer, "onPrimaryContainer") } - item { ColorTile(colors.inversePrimary, "inversePrimary") } - item { ColorTile(colors.secondary, "secondary") } - item { ColorTile(colors.onSecondary, "onSecondary") } - item { ColorTile(colors.secondaryContainer, "secondaryContainer") } - item { ColorTile(colors.onSecondaryContainer, "onSecondaryContainer") } - item { ColorTile(colors.tertiary, "tertiary") } - item { ColorTile(colors.onTertiary, "onTertiary") } - item { ColorTile(colors.tertiaryContainer, "tertiaryContainer") } - item { ColorTile(colors.onTertiaryContainer, "onTertiaryContainer") } - item { ColorTile(colors.background, "background") } - item { ColorTile(colors.onBackground, "onBackground") } - item { ColorTile(colors.surface, "surface") } - item { ColorTile(colors.onSurface, "onSurface") } - item { ColorTile(colors.surfaceVariant, "surfaceVariant") } - item { ColorTile(colors.onSurfaceVariant, "onSurfaceVariant") } - item { ColorTile(colors.inverseSurface, "inverseSurface") } - item { ColorTile(colors.inverseOnSurface, "inverseOnSurface") } - item { ColorTile(colors.error, "error") } - item { ColorTile(colors.onError, "onError") } - item { ColorTile(colors.errorContainer, "errorContainer") } - item { ColorTile(colors.onErrorContainer, "onErrorContainer") } - item { ColorTile(colors.outline, "outline") } + ColorsScreen( + listOf( + "primary" to colors.primary, + "onPrimary" to colors.onPrimary, + "primaryContainer" to colors.primaryContainer, + "onPrimaryContainer" to colors.onPrimaryContainer, + "inversePrimary" to colors.inversePrimary, + "secondary" to colors.secondary, + "onSecondary" to colors.onSecondary, + "secondaryContainer" to colors.secondaryContainer, + "onSecondaryContainer" to colors.onSecondaryContainer, + "tertiary" to colors.tertiary, + "onTertiary" to colors.onTertiary, + "tertiaryContainer" to colors.tertiaryContainer, + "onTertiaryContainer" to colors.onTertiaryContainer, + "background" to colors.background, + "onBackground" to colors.onBackground, + "surface" to colors.surface, + "onSurface" to colors.onSurface, + "surfaceVariant" to colors.surfaceVariant, + "onSurfaceVariant" to colors.onSurfaceVariant, + "inverseSurface" to colors.inverseSurface, + "inverseOnSurface" to colors.inverseOnSurface, + "error" to colors.error, + "onError" to colors.onError, + "errorContainer" to colors.errorContainer, + "onErrorContainer" to colors.onErrorContainer, + "outline" to colors.outline, + ) + ) +} + +/** The screen that shows all the Android colors. */ +@Composable +fun AndroidColorsScreen() { + val colors = LocalAndroidColorScheme.current + ColorsScreen( + listOf( + "colorPrimary" to colors.colorPrimary, + "colorPrimaryDark" to colors.colorPrimaryDark, + "colorAccent" to colors.colorAccent, + "colorAccentPrimary" to colors.colorAccentPrimary, + "colorAccentSecondary" to colors.colorAccentSecondary, + "colorAccentTertiary" to colors.colorAccentTertiary, + "colorAccentPrimaryVariant" to colors.colorAccentPrimaryVariant, + "colorAccentSecondaryVariant" to colors.colorAccentSecondaryVariant, + "colorAccentTertiaryVariant" to colors.colorAccentTertiaryVariant, + "colorSurface" to colors.colorSurface, + "colorSurfaceHighlight" to colors.colorSurfaceHighlight, + "colorSurfaceVariant" to colors.colorSurfaceVariant, + "colorSurfaceHeader" to colors.colorSurfaceHeader, + "colorError" to colors.colorError, + "colorBackground" to colors.colorBackground, + "colorBackgroundFloating" to colors.colorBackgroundFloating, + "panelColorBackground" to colors.panelColorBackground, + "textColorPrimary" to colors.textColorPrimary, + "textColorSecondary" to colors.textColorSecondary, + "textColorTertiary" to colors.textColorTertiary, + "textColorPrimaryInverse" to colors.textColorPrimaryInverse, + "textColorSecondaryInverse" to colors.textColorSecondaryInverse, + "textColorTertiaryInverse" to colors.textColorTertiaryInverse, + "textColorOnAccent" to colors.textColorOnAccent, + "colorForeground" to colors.colorForeground, + "colorForegroundInverse" to colors.colorForegroundInverse, + ) + ) +} + +@Composable +private fun ColorsScreen( + colors: List>, +) { + LazyColumn( + Modifier.fillMaxWidth(), + ) { + colors.forEach { (name, color) -> item { ColorTile(color, name) } } } } diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt index c8146b8ccc9ce..0ac3a63aa9972 100644 --- a/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt +++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/compose/gallery/GalleryApp.kt @@ -30,7 +30,8 @@ import com.android.systemui.compose.theme.SystemUITheme enum class Screen { Home, Typography, - Colors, + MaterialColors, + AndroidColors, ExampleFeature, } @@ -49,7 +50,8 @@ private fun MainContent() { ) } composable(Screen.Typography.name) { TypographyScreen() } - composable(Screen.Colors.name) { ColorsScreen() } + composable(Screen.MaterialColors.name) { MaterialColorsScreen() } + composable(Screen.AndroidColors.name) { AndroidColorsScreen() } composable(Screen.ExampleFeature.name) { ExampleFeatureScreen() } } }