summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Chaohui Wang <chaohuiw@google.com> 2023-08-08 14:41:46 +0800
committer Chaohui Wang <chaohuiw@google.com> 2023-09-11 11:52:06 +0800
commitc09b8cfa1a9064ddac119e8229f36ea68459e3b4 (patch)
tree1bebe6cb10ffb3d63ce7edc51b2412ecf766895a
parent4565a43c59d5952836729742e385cbab9a8141db (diff)
[Spa] Support stack bar chart
Fix: 294951338 Test: unit test Test: visual - with gallery Change-Id: Icd1c14d79490f10d595ebc40679bffb6f015c4d7
-rw-r--r--packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt2
-rw-r--r--packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/chart/BarChartEntry.kt55
-rw-r--r--packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/chart/ChartPageProvider.kt (renamed from packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ChartPage.kt)38
-rw-r--r--packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt2
-rw-r--r--packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/chart/BarChartScreenshotTest.kt17
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/chart/BarChart.kt150
-rw-r--r--packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/chart/ChartTest.kt31
-rw-r--r--packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/ImageAssertions.kt42
8 files changed, 202 insertions, 135 deletions
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
index 4a252a91b12f..471f3b93b8aa 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
@@ -22,6 +22,7 @@ import com.android.settingslib.spa.framework.common.SettingsPageProviderReposito
import com.android.settingslib.spa.framework.common.SpaEnvironment
import com.android.settingslib.spa.framework.common.createSettingsPage
import com.android.settingslib.spa.gallery.button.ActionButtonPageProvider
+import com.android.settingslib.spa.gallery.chart.ChartPageProvider
import com.android.settingslib.spa.gallery.dialog.AlertDialogPageProvider
import com.android.settingslib.spa.gallery.editor.EditorMainPageProvider
import com.android.settingslib.spa.gallery.editor.SettingsExposedDropdownMenuBoxPageProvider
@@ -32,7 +33,6 @@ import com.android.settingslib.spa.gallery.itemList.ItemOperatePageProvider
import com.android.settingslib.spa.gallery.itemList.OperateListPageProvider
import com.android.settingslib.spa.gallery.editor.SettingsOutlinedTextFieldPageProvider
import com.android.settingslib.spa.gallery.page.ArgumentPageProvider
-import com.android.settingslib.spa.gallery.page.ChartPageProvider
import com.android.settingslib.spa.gallery.page.FooterPageProvider
import com.android.settingslib.spa.gallery.page.IllustrationPageProvider
import com.android.settingslib.spa.gallery.page.LoadingBarPageProvider
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/chart/BarChartEntry.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/chart/BarChartEntry.kt
new file mode 100644
index 000000000000..bf7a8e14514b
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/chart/BarChartEntry.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 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.settingslib.spa.gallery.chart
+
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
+import com.android.settingslib.spa.widget.chart.BarChart
+import com.android.settingslib.spa.widget.chart.BarChartData
+import com.android.settingslib.spa.widget.chart.BarChartModel
+import com.android.settingslib.spa.widget.chart.ColorPalette
+import com.android.settingslib.spa.widget.preference.Preference
+import com.android.settingslib.spa.widget.preference.PreferenceModel
+import com.github.mikephil.charting.formatter.IAxisValueFormatter
+
+fun createBarChartEntry(owner: SettingsPage) = SettingsEntryBuilder.create("Bar Chart", owner)
+ .setUiLayoutFn {
+ Preference(object : PreferenceModel {
+ override val title = "Bar Chart"
+ })
+ BarChart(
+ barChartModel = object : BarChartModel {
+ override val chartDataList = listOf(
+ BarChartData(x = 0f, y = listOf(12f, 2f)),
+ BarChartData(x = 1f, y = listOf(5f, 1f)),
+ BarChartData(x = 2f, y = listOf(21f, 2f)),
+ BarChartData(x = 3f, y = listOf(5f, 1f)),
+ BarChartData(x = 4f, y = listOf(10f, 0f)),
+ BarChartData(x = 5f, y = listOf(9f, 1f)),
+ BarChartData(x = 6f, y = listOf(1f, 1f)),
+ )
+ override val colors = listOf(ColorPalette.green, ColorPalette.yellow)
+ override val xValueFormatter = IAxisValueFormatter { value, _ ->
+ "4/${value.toInt() + 1}"
+ }
+ override val yValueFormatter = IAxisValueFormatter { value, _ ->
+ "${value.toInt()}m"
+ }
+ override val yAxisMaxValue = 30f
+ }
+ )
+ }.build()
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ChartPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/chart/ChartPageProvider.kt
index 69c47050e684..7a6ae2cee6ad 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ChartPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/chart/ChartPageProvider.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settingslib.spa.gallery.page
+package com.android.settingslib.spa.gallery.chart
import android.os.Bundle
import androidx.compose.runtime.Composable
@@ -25,9 +25,6 @@ import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.common.createSettingsPage
import com.android.settingslib.spa.framework.compose.navigator
import com.android.settingslib.spa.framework.theme.SettingsTheme
-import com.android.settingslib.spa.widget.chart.BarChart
-import com.android.settingslib.spa.widget.chart.BarChartData
-import com.android.settingslib.spa.widget.chart.BarChartModel
import com.android.settingslib.spa.widget.chart.LineChart
import com.android.settingslib.spa.widget.chart.LineChartData
import com.android.settingslib.spa.widget.chart.LineChartModel
@@ -83,36 +80,7 @@ object ChartPageProvider : SettingsPageProvider {
)
}.build()
)
- entryList.add(
- SettingsEntryBuilder.create("Bar Chart", owner)
- .setUiLayoutFn {
- Preference(object : PreferenceModel {
- override val title = "Bar Chart"
- })
- BarChart(
- barChartModel = object : BarChartModel {
- override val chartDataList = listOf(
- BarChartData(x = 0f, y = 12f),
- BarChartData(x = 1f, y = 5f),
- BarChartData(x = 2f, y = 21f),
- BarChartData(x = 3f, y = 5f),
- BarChartData(x = 4f, y = 10f),
- BarChartData(x = 5f, y = 9f),
- BarChartData(x = 6f, y = 1f),
- )
- override val xValueFormatter =
- IAxisValueFormatter { value, _ ->
- "${WeekDay.values()[value.toInt()]}"
- }
- override val yValueFormatter =
- IAxisValueFormatter { value, _ ->
- "${value.toInt()}m"
- }
- override val yAxisMaxValue = 30f
- }
- )
- }.build()
- )
+ entryList.add(createBarChartEntry(owner))
entryList.add(
SettingsEntryBuilder.create("Pie Chart", owner)
.setUiLayoutFn {
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt
index bb311a52052a..6cac2202742a 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePageProvider.kt
@@ -28,12 +28,12 @@ import com.android.settingslib.spa.framework.theme.SettingsTheme
import com.android.settingslib.spa.gallery.R
import com.android.settingslib.spa.gallery.SettingsPageProviderEnum
import com.android.settingslib.spa.gallery.button.ActionButtonPageProvider
+import com.android.settingslib.spa.gallery.chart.ChartPageProvider
import com.android.settingslib.spa.gallery.dialog.AlertDialogPageProvider
import com.android.settingslib.spa.gallery.editor.EditorMainPageProvider
import com.android.settingslib.spa.gallery.itemList.OperateListPageProvider
import com.android.settingslib.spa.gallery.page.ArgumentPageModel
import com.android.settingslib.spa.gallery.page.ArgumentPageProvider
-import com.android.settingslib.spa.gallery.page.ChartPageProvider
import com.android.settingslib.spa.gallery.page.FooterPageProvider
import com.android.settingslib.spa.gallery.page.IllustrationPageProvider
import com.android.settingslib.spa.gallery.page.LoadingBarPageProvider
diff --git a/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/chart/BarChartScreenshotTest.kt b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/chart/BarChartScreenshotTest.kt
index 27d270c5d58e..e6decb13c2b9 100644
--- a/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/chart/BarChartScreenshotTest.kt
+++ b/packages/SettingsLib/Spa/screenshot/src/com/android/settingslib/spa/screenshot/widget/chart/BarChartScreenshotTest.kt
@@ -16,6 +16,7 @@
package com.android.settingslib.spa.screenshot
+import androidx.compose.material3.MaterialTheme
import com.android.settingslib.spa.widget.chart.BarChart
import com.android.settingslib.spa.widget.chart.BarChartData
import com.android.settingslib.spa.widget.chart.BarChartModel
@@ -45,17 +46,19 @@ class BarChartScreenshotTest(emulationSpec: DeviceEmulationSpec) {
@Test
fun test() {
screenshotRule.screenshotTest("barChart") {
+ val color = MaterialTheme.colorScheme.surfaceVariant
BarChart(
barChartModel = object : BarChartModel {
override val chartDataList = listOf(
- BarChartData(x = 0f, y = 12f),
- BarChartData(x = 1f, y = 5f),
- BarChartData(x = 2f, y = 21f),
- BarChartData(x = 3f, y = 5f),
- BarChartData(x = 4f, y = 10f),
- BarChartData(x = 5f, y = 9f),
- BarChartData(x = 6f, y = 1f),
+ BarChartData(x = 0f, y = listOf(12f)),
+ BarChartData(x = 1f, y = listOf(5f)),
+ BarChartData(x = 2f, y = listOf(21f)),
+ BarChartData(x = 3f, y = listOf(5f)),
+ BarChartData(x = 4f, y = listOf(10f)),
+ BarChartData(x = 5f, y = listOf(9f)),
+ BarChartData(x = 6f, y = listOf(1f)),
)
+ override val colors = listOf(color)
override val xValueFormatter =
IAxisValueFormatter { value, _ ->
"${WeekDay.values()[value.toInt()]}"
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/chart/BarChart.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/chart/BarChart.kt
index 0b0f07e670ee..7ca15d95cee1 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/chart/BarChart.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/chart/BarChart.kt
@@ -31,6 +31,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
@@ -52,6 +53,11 @@ interface BarChartModel {
val chartDataList: List<BarChartData>
/**
+ * The color list for [BarChart].
+ */
+ val colors: List<Color>
+
+ /**
* The label text formatter for x value.
*/
val xValueFormatter: IAxisValueFormatter?
@@ -83,34 +89,14 @@ interface BarChartModel {
}
data class BarChartData(
- var x: Float?,
- var y: Float?,
+ var x: Float,
+ var y: List<Float>,
)
@Composable
fun BarChart(barChartModel: BarChartModel) {
- BarChart(
- chartDataList = barChartModel.chartDataList,
- xValueFormatter = barChartModel.xValueFormatter,
- yValueFormatter = barChartModel.yValueFormatter,
- yAxisMinValue = barChartModel.yAxisMinValue,
- yAxisMaxValue = barChartModel.yAxisMaxValue,
- yAxisLabelCount = barChartModel.yAxisLabelCount,
- )
-}
-
-@Composable
-fun BarChart(
- chartDataList: List<BarChartData>,
- modifier: Modifier = Modifier,
- xValueFormatter: IAxisValueFormatter? = null,
- yValueFormatter: IAxisValueFormatter? = null,
- yAxisMinValue: Float = 0f,
- yAxisMaxValue: Float = 30f,
- yAxisLabelCount: Int = 4,
-) {
Column(
- modifier = modifier
+ modifier = Modifier
.fillMaxWidth()
.wrapContentHeight(),
horizontalAlignment = Alignment.CenterHorizontally,
@@ -126,50 +112,61 @@ fun BarChart(
val colorScheme = MaterialTheme.colorScheme
val labelTextColor = colorScheme.onSurfaceVariant.toArgb()
val labelTextSize = MaterialTheme.typography.bodyMedium.fontSize.value
- Crossfade(targetState = chartDataList) { barChartData ->
- AndroidView(factory = { context ->
- BarChart(context).apply {
- // Fixed Settings.
- layoutParams = LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT,
- )
- this.description.isEnabled = false
- this.legend.isEnabled = false
- this.extraBottomOffset = 4f
- this.setScaleEnabled(false)
-
- this.xAxis.position = XAxis.XAxisPosition.BOTTOM
- this.xAxis.setDrawGridLines(false)
- this.xAxis.setDrawAxisLine(false)
- this.xAxis.textColor = labelTextColor
- this.xAxis.textSize = labelTextSize
- this.xAxis.yOffset = 10f
-
- this.axisLeft.isEnabled = false
- this.axisRight.setDrawAxisLine(false)
- this.axisRight.textSize = labelTextSize
- this.axisRight.textColor = labelTextColor
- this.axisRight.gridColor = colorScheme.divider.toArgb()
- this.axisRight.xOffset = 10f
-
- // Customizable Settings.
- this.xAxis.valueFormatter = xValueFormatter
- this.axisRight.valueFormatter = yValueFormatter
-
- this.axisLeft.axisMinimum = yAxisMinValue
- this.axisLeft.axisMaximum = yAxisMaxValue
- this.axisRight.axisMinimum = yAxisMinValue
- this.axisRight.axisMaximum = yAxisMaxValue
-
- this.axisRight.setLabelCount(yAxisLabelCount, true)
- }
- },
+ Crossfade(
+ targetState = barChartModel.chartDataList,
+ label = "chartDataList",
+ ) { barChartData ->
+ AndroidView(
+ factory = { context ->
+ BarChart(context).apply {
+ layoutParams = LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ )
+ description.isEnabled = false
+ legend.isEnabled = false
+ extraBottomOffset = 4f
+ setScaleEnabled(false)
+
+ xAxis.apply {
+ position = XAxis.XAxisPosition.BOTTOM
+ setDrawAxisLine(false)
+ setDrawGridLines(false)
+ textColor = labelTextColor
+ textSize = labelTextSize
+ valueFormatter = barChartModel.xValueFormatter
+ yOffset = 10f
+ }
+
+ axisLeft.apply {
+ axisMaximum = barChartModel.yAxisMaxValue
+ axisMinimum = barChartModel.yAxisMinValue
+ isEnabled = false
+ }
+
+ axisRight.apply {
+ axisMaximum = barChartModel.yAxisMaxValue
+ axisMinimum = barChartModel.yAxisMinValue
+ gridColor = colorScheme.divider.toArgb()
+ setDrawAxisLine(false)
+ setLabelCount(barChartModel.yAxisLabelCount, true)
+ textColor = labelTextColor
+ textSize = labelTextSize
+ valueFormatter = barChartModel.yValueFormatter
+ xOffset = 10f
+ }
+ }
+ },
modifier = Modifier
.wrapContentSize()
.padding(4.dp),
- update = {
- updateBarChartWithData(it, barChartData, colorScheme)
+ update = { barChart ->
+ updateBarChartWithData(
+ chart = barChart,
+ data = barChartData,
+ colorList = barChartModel.colors,
+ colorScheme = colorScheme,
+ )
}
)
}
@@ -177,26 +174,25 @@ fun BarChart(
}
}
-fun updateBarChartWithData(
+private fun updateBarChartWithData(
chart: BarChart,
data: List<BarChartData>,
+ colorList: List<Color>,
colorScheme: ColorScheme
) {
- val entries = ArrayList<BarEntry>()
- for (i in data.indices) {
- val item = data[i]
- entries.add(BarEntry(item.x ?: 0.toFloat(), item.y ?: 0.toFloat()))
+ val entries = data.map { item ->
+ BarEntry(item.x, item.y.toFloatArray())
}
- val ds = BarDataSet(entries, "")
- ds.colors = arrayListOf(colorScheme.surfaceVariant.toArgb())
- ds.setDrawValues(false)
- ds.isHighlightEnabled = true
- ds.highLightColor = colorScheme.primary.toArgb()
- ds.highLightAlpha = 255
+ val ds = BarDataSet(entries, "").apply {
+ colors = colorList.map(Color::toArgb)
+ setDrawValues(false)
+ isHighlightEnabled = true
+ highLightColor = colorScheme.primary.toArgb()
+ highLightAlpha = 255
+ }
// TODO: Sets round corners for bars.
- val d = BarData(ds)
- chart.data = d
+ chart.data = BarData(ds)
chart.invalidate()
}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/chart/ChartTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/chart/ChartTest.kt
index 2230d6c96bbb..0fe755f09b66 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/chart/ChartTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/chart/ChartTest.kt
@@ -17,13 +17,17 @@
package com.android.settingslib.spa.widget.chart
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.semantics.SemanticsPropertyKey
import androidx.compose.ui.semantics.SemanticsPropertyReceiver
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.test.SemanticsMatcher
import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.captureToImage
import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onRoot
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.testutils.assertContainsColor
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -61,22 +65,21 @@ class ChartTest {
@Test
fun bar_chart_displayed() {
composeTestRule.setContent {
- BarChart(
- chartDataList = listOf(
- BarChartData(x = 0f, y = 12f),
- BarChartData(x = 1f, y = 5f),
- BarChartData(x = 2f, y = 21f),
- BarChartData(x = 3f, y = 5f),
- BarChartData(x = 4f, y = 10f),
- BarChartData(x = 5f, y = 9f),
- BarChartData(x = 6f, y = 1f),
- ),
- yAxisMaxValue = 30f,
- modifier = Modifier.semantics { chart = "bar" }
- )
+ BarChart(object : BarChartModel {
+ override val chartDataList = listOf(
+ BarChartData(x = 0f, y = listOf(12f)),
+ BarChartData(x = 1f, y = listOf(5f)),
+ BarChartData(x = 2f, y = listOf(21f)),
+ BarChartData(x = 3f, y = listOf(5f)),
+ BarChartData(x = 4f, y = listOf(10f)),
+ BarChartData(x = 5f, y = listOf(9f)),
+ BarChartData(x = 6f, y = listOf(1f)),
+ )
+ override val colors = listOf(Color.Blue)
+ })
}
- composeTestRule.onNode(hasChart("bar")).assertIsDisplayed()
+ composeTestRule.onRoot().captureToImage().assertContainsColor(Color.Blue)
}
@Test
diff --git a/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/ImageAssertions.kt b/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/ImageAssertions.kt
new file mode 100644
index 000000000000..0190989ef628
--- /dev/null
+++ b/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/ImageAssertions.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 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.settingslib.spa.testutils
+
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.graphics.toPixelMap
+
+/**
+ * Asserts that the expected color is present in this bitmap.
+ *
+ * @throws AssertionError if the expected color is not present.
+ */
+fun ImageBitmap.assertContainsColor(expectedColor: Color) {
+ assert(containsColor(expectedColor)) {
+ "The given color $expectedColor was not found in the bitmap."
+ }
+}
+
+private fun ImageBitmap.containsColor(expectedColor: Color): Boolean {
+ val pixels = toPixelMap()
+ for (x in 0 until width) {
+ for (y in 0 until height) {
+ if (pixels[x, y] == expectedColor) return true
+ }
+ }
+ return false
+}