Introduce LocalAndroidColorScheme to expose Android colors
This CL introduces the AndroidColorScheme and its CompositionLocal to access any Android color from a Composable. The list of colors was taken from [1]. Ideally we would only use M3 colors but given that M3 and Android colors have not been aligned yet, our current UI specs are still using the Android colors. In the long term, this class will be deleted or slimmed down to contain only the few colors missing from M3. [1] http://cs/android-internal/frameworks/base/core/res/res/values/themes_device_defaults.xml;l=214;rcl=fa86dc4ca511d27ae2d32749d180466404c18218 Bug: 230605885 Test: atest SystemUIThemeTest Change-Id: I45927f23eb8256987b4e5c6ae48e33ce581aabb3
This commit is contained in:
@@ -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<AndroidColorScheme> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Pair<String, Color>>,
|
||||
) {
|
||||
LazyColumn(
|
||||
Modifier.fillMaxWidth(),
|
||||
) {
|
||||
colors.forEach { (name, color) -> item { ColorTile(color, name) } }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user