Loading packages/SystemUI/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModel.kt +22 −6 Original line number Original line Diff line number Diff line Loading @@ -42,9 +42,9 @@ import kotlinx.coroutines.flow.asStateFlow * * * Example adb commands: * Example adb commands: * * * To show a chip with the SysUI icon and custom text: * To show a chip with the SysUI icon and custom text and color: * ``` * ``` * adb shell cmd statusbar demo-ron -p com.android.systemui -t 10min * adb shell cmd statusbar demo-ron -p com.android.systemui -t 10min -c "\\#434343" * ``` * ``` * * * To hide the chip: * To hide the chip: Loading Loading @@ -87,6 +87,17 @@ constructor( valueParser = Type.String, valueParser = Type.String, ) ) private val backgroundColor: Int? by param( longName = "color", shortName = "c", description = "The color to show as the chip background color. " + "You can either just write a basic color like 'red' or 'green', " + "or you can include a #RRGGBB string in this format: \"\\\\#434343\".", valueParser = Type.Color, ) private val hide by private val hide by flag( flag( longName = "hide", longName = "hide", Loading Loading @@ -119,21 +130,26 @@ constructor( return return } } val colors = if (backgroundColor != null) { ColorsModel.Custom(backgroundColorInt = backgroundColor!!) } else { ColorsModel.Themed } val currentText = text val currentText = text if (currentText != null) { if (currentText != null) { _chip.value = _chip.value = OngoingActivityChipModel.Shown.Text( OngoingActivityChipModel.Shown.Text( icon = appIcon, icon = appIcon, // TODO(b/361346412): Include a demo with a custom color theme. colors = colors, colors = ColorsModel.Themed, text = currentText, text = currentText, ) ) } else { } else { _chip.value = _chip.value = OngoingActivityChipModel.Shown.Timer( OngoingActivityChipModel.Shown.Timer( icon = appIcon, icon = appIcon, // TODO(b/361346412): Include a demo with a custom color theme. colors = colors, colors = ColorsModel.Themed, startTimeMs = systemClock.elapsedRealtime(), startTimeMs = systemClock.elapsedRealtime(), onClickListener = null, onClickListener = null, ) ) Loading packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt +18 −0 Original line number Original line Diff line number Diff line Loading @@ -39,6 +39,24 @@ sealed interface ColorsModel { Utils.getColorAttrDefaultColor(context, com.android.internal.R.attr.colorPrimary) Utils.getColorAttrDefaultColor(context, com.android.internal.R.attr.colorPrimary) } } /** * The chip should have the given background color, and text color that matches dark/light * theme. */ data class Custom(val backgroundColorInt: Int) : ColorsModel { override fun background(context: Context): ColorStateList = ColorStateList.valueOf(backgroundColorInt) // TODO(b/361346412): When dark theme changes, the chip should automatically re-render with // the right text color. Right now, it has the right text color when the chip is first // created but the color doesn't update if dark theme changes. override fun text(context: Context) = Utils.getColorAttrDefaultColor( context, com.android.internal.R.attr.materialColorOnSurface, ) } /** The chip should have a red background with white text. */ /** The chip should have a red background with white text. */ data object Red : ColorsModel { data object Red : ColorsModel { override fun background(context: Context): ColorStateList { override fun background(context: Context): ColorStateList { Loading packages/SystemUI/src/com/android/systemui/statusbar/commandline/ValueParser.kt +14 −0 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.commandline package com.android.systemui.statusbar.commandline import androidx.core.graphics.toColorInt import kotlin.contracts.ExperimentalContracts import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.contracts.contract Loading Loading @@ -164,10 +165,23 @@ private val parseFloat: ValueParser<Float> = ValueParser { value -> ?: Result.failure(ArgParseError("Failed to parse $value as a float")) ?: Result.failure(ArgParseError("Failed to parse $value as a float")) } } // See https://developer.android.com/reference/android/graphics/Color#parseColor(java.lang.String) // for the supported formats of the color string. tl;dr: #RRGGBB, #AARRGGBB, or a basic color name // like "red" or "green". For the RRGGBB values, the `#` needs to be escaped. Use `"\\#RRGGBB"` in // the command to escape the `#` correctly. private val parseColor: ValueParser<Int> = ValueParser { value -> try { Result.success(value.toColorInt()) } catch (e: IllegalArgumentException) { Result.failure(ArgParseError("Failed to parse $value as a color: $e")) } } /** Default parsers that can be use as-is, or [map]ped to another type */ /** Default parsers that can be use as-is, or [map]ped to another type */ object Type { object Type { val Boolean = parseBoolean val Boolean = parseBoolean val Int = parseInt val Int = parseInt val Float = parseFloat val Float = parseFloat val String = parseString val String = parseString val Color = parseColor } } packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModelTest.kt +17 −0 Original line number Original line Diff line number Diff line Loading @@ -25,6 +25,7 @@ import com.android.systemui.Flags.FLAG_STATUS_BAR_RON_CHIPS import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.testScope import com.android.systemui.statusbar.chips.ui.model.ColorsModel import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel import com.android.systemui.statusbar.commandline.CommandRegistry import com.android.systemui.statusbar.commandline.CommandRegistry import com.android.systemui.statusbar.commandline.commandRegistry import com.android.systemui.statusbar.commandline.commandRegistry Loading Loading @@ -101,6 +102,22 @@ class DemoRonChipViewModelTest : SysuiTestCase() { assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.Text::class.java) assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.Text::class.java) } } @Test @EnableFlags(FLAG_STATUS_BAR_RON_CHIPS) fun chip_supportsColor() = testScope.runTest { val latest by collectLastValue(underTest.chip) commandRegistry.onShellCommand( pw, arrayOf("demo-ron", "-p", "com.android.systemui", "-c", "#434343") ) assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java) assertThat((latest as OngoingActivityChipModel.Shown).colors) .isInstanceOf(ColorsModel.Custom::class.java) } @Test @Test @EnableFlags(FLAG_STATUS_BAR_RON_CHIPS) @EnableFlags(FLAG_STATUS_BAR_RON_CHIPS) fun chip_hasHideArg_hidden() = fun chip_hasHideArg_hidden() = Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ValueParserTest.kt +9 −0 Original line number Original line Diff line number Diff line Loading @@ -39,6 +39,15 @@ class ValueParserTest : SysuiTestCase() { assertTrue(Type.Boolean.parseValue("not a Boolean").isFailure) assertTrue(Type.Boolean.parseValue("not a Boolean").isFailure) } } @Test fun parseColor() { assertThat(Type.Color.parseValue("#434343").isSuccess).isTrue() assertThat(Type.Color.parseValue("#aa123456").isSuccess).isTrue() assertThat(Type.Color.parseValue("red").isSuccess).isTrue() assertThat(Type.Color.parseValue("not a color").isFailure).isTrue() } @Test @Test fun mapToComplexType() { fun mapToComplexType() { val parseSquare = Type.Int.map { Rect(it, it, it, it) } val parseSquare = Type.Int.map { Rect(it, it, it, it) } Loading Loading
packages/SystemUI/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModel.kt +22 −6 Original line number Original line Diff line number Diff line Loading @@ -42,9 +42,9 @@ import kotlinx.coroutines.flow.asStateFlow * * * Example adb commands: * Example adb commands: * * * To show a chip with the SysUI icon and custom text: * To show a chip with the SysUI icon and custom text and color: * ``` * ``` * adb shell cmd statusbar demo-ron -p com.android.systemui -t 10min * adb shell cmd statusbar demo-ron -p com.android.systemui -t 10min -c "\\#434343" * ``` * ``` * * * To hide the chip: * To hide the chip: Loading Loading @@ -87,6 +87,17 @@ constructor( valueParser = Type.String, valueParser = Type.String, ) ) private val backgroundColor: Int? by param( longName = "color", shortName = "c", description = "The color to show as the chip background color. " + "You can either just write a basic color like 'red' or 'green', " + "or you can include a #RRGGBB string in this format: \"\\\\#434343\".", valueParser = Type.Color, ) private val hide by private val hide by flag( flag( longName = "hide", longName = "hide", Loading Loading @@ -119,21 +130,26 @@ constructor( return return } } val colors = if (backgroundColor != null) { ColorsModel.Custom(backgroundColorInt = backgroundColor!!) } else { ColorsModel.Themed } val currentText = text val currentText = text if (currentText != null) { if (currentText != null) { _chip.value = _chip.value = OngoingActivityChipModel.Shown.Text( OngoingActivityChipModel.Shown.Text( icon = appIcon, icon = appIcon, // TODO(b/361346412): Include a demo with a custom color theme. colors = colors, colors = ColorsModel.Themed, text = currentText, text = currentText, ) ) } else { } else { _chip.value = _chip.value = OngoingActivityChipModel.Shown.Timer( OngoingActivityChipModel.Shown.Timer( icon = appIcon, icon = appIcon, // TODO(b/361346412): Include a demo with a custom color theme. colors = colors, colors = ColorsModel.Themed, startTimeMs = systemClock.elapsedRealtime(), startTimeMs = systemClock.elapsedRealtime(), onClickListener = null, onClickListener = null, ) ) Loading
packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/ColorsModel.kt +18 −0 Original line number Original line Diff line number Diff line Loading @@ -39,6 +39,24 @@ sealed interface ColorsModel { Utils.getColorAttrDefaultColor(context, com.android.internal.R.attr.colorPrimary) Utils.getColorAttrDefaultColor(context, com.android.internal.R.attr.colorPrimary) } } /** * The chip should have the given background color, and text color that matches dark/light * theme. */ data class Custom(val backgroundColorInt: Int) : ColorsModel { override fun background(context: Context): ColorStateList = ColorStateList.valueOf(backgroundColorInt) // TODO(b/361346412): When dark theme changes, the chip should automatically re-render with // the right text color. Right now, it has the right text color when the chip is first // created but the color doesn't update if dark theme changes. override fun text(context: Context) = Utils.getColorAttrDefaultColor( context, com.android.internal.R.attr.materialColorOnSurface, ) } /** The chip should have a red background with white text. */ /** The chip should have a red background with white text. */ data object Red : ColorsModel { data object Red : ColorsModel { override fun background(context: Context): ColorStateList { override fun background(context: Context): ColorStateList { Loading
packages/SystemUI/src/com/android/systemui/statusbar/commandline/ValueParser.kt +14 −0 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.commandline package com.android.systemui.statusbar.commandline import androidx.core.graphics.toColorInt import kotlin.contracts.ExperimentalContracts import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.contracts.contract Loading Loading @@ -164,10 +165,23 @@ private val parseFloat: ValueParser<Float> = ValueParser { value -> ?: Result.failure(ArgParseError("Failed to parse $value as a float")) ?: Result.failure(ArgParseError("Failed to parse $value as a float")) } } // See https://developer.android.com/reference/android/graphics/Color#parseColor(java.lang.String) // for the supported formats of the color string. tl;dr: #RRGGBB, #AARRGGBB, or a basic color name // like "red" or "green". For the RRGGBB values, the `#` needs to be escaped. Use `"\\#RRGGBB"` in // the command to escape the `#` correctly. private val parseColor: ValueParser<Int> = ValueParser { value -> try { Result.success(value.toColorInt()) } catch (e: IllegalArgumentException) { Result.failure(ArgParseError("Failed to parse $value as a color: $e")) } } /** Default parsers that can be use as-is, or [map]ped to another type */ /** Default parsers that can be use as-is, or [map]ped to another type */ object Type { object Type { val Boolean = parseBoolean val Boolean = parseBoolean val Int = parseInt val Int = parseInt val Float = parseFloat val Float = parseFloat val String = parseString val String = parseString val Color = parseColor } }
packages/SystemUI/tests/src/com/android/systemui/statusbar/chips/ron/demo/ui/viewmodel/DemoRonChipViewModelTest.kt +17 −0 Original line number Original line Diff line number Diff line Loading @@ -25,6 +25,7 @@ import com.android.systemui.Flags.FLAG_STATUS_BAR_RON_CHIPS import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.testScope import com.android.systemui.statusbar.chips.ui.model.ColorsModel import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel import com.android.systemui.statusbar.commandline.CommandRegistry import com.android.systemui.statusbar.commandline.CommandRegistry import com.android.systemui.statusbar.commandline.commandRegistry import com.android.systemui.statusbar.commandline.commandRegistry Loading Loading @@ -101,6 +102,22 @@ class DemoRonChipViewModelTest : SysuiTestCase() { assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.Text::class.java) assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown.Text::class.java) } } @Test @EnableFlags(FLAG_STATUS_BAR_RON_CHIPS) fun chip_supportsColor() = testScope.runTest { val latest by collectLastValue(underTest.chip) commandRegistry.onShellCommand( pw, arrayOf("demo-ron", "-p", "com.android.systemui", "-c", "#434343") ) assertThat(latest).isInstanceOf(OngoingActivityChipModel.Shown::class.java) assertThat((latest as OngoingActivityChipModel.Shown).colors) .isInstanceOf(ColorsModel.Custom::class.java) } @Test @Test @EnableFlags(FLAG_STATUS_BAR_RON_CHIPS) @EnableFlags(FLAG_STATUS_BAR_RON_CHIPS) fun chip_hasHideArg_hidden() = fun chip_hasHideArg_hidden() = Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/commandline/ValueParserTest.kt +9 −0 Original line number Original line Diff line number Diff line Loading @@ -39,6 +39,15 @@ class ValueParserTest : SysuiTestCase() { assertTrue(Type.Boolean.parseValue("not a Boolean").isFailure) assertTrue(Type.Boolean.parseValue("not a Boolean").isFailure) } } @Test fun parseColor() { assertThat(Type.Color.parseValue("#434343").isSuccess).isTrue() assertThat(Type.Color.parseValue("#aa123456").isSuccess).isTrue() assertThat(Type.Color.parseValue("red").isSuccess).isTrue() assertThat(Type.Color.parseValue("not a color").isFailure).isTrue() } @Test @Test fun mapToComplexType() { fun mapToComplexType() { val parseSquare = Type.Int.map { Rect(it, it, it, it) } val parseSquare = Type.Int.map { Rect(it, it, it, it) } Loading