Snap for 9667109 from ea57f7b5df962663311bea3db219964c5d98dec2 to tm-qpr3-release

Change-Id: I40176c43c6dd31ca205b2b4a4708285e49f6efcb
diff --git a/res/layout/color_option_with_background.xml b/res/layout/color_option_with_background.xml
index 9d3be58..67079f7 100644
--- a/res/layout/color_option_with_background.xml
+++ b/res/layout/color_option_with_background.xml
@@ -14,65 +14,80 @@
      limitations under the License.
 -->
 <!-- Content description is set programmatically on the parent FrameLayout -->
-<FrameLayout
+<LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/icon_container"
-    android:layout_width="@dimen/option_tile_width"
-    android:layout_height="@dimen/option_tile_width"
-    android:importantForAccessibility="yes">
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:orientation="vertical" >
+    <FrameLayout
+        android:id="@+id/icon_container"
+        android:layout_width="@dimen/option_tile_width"
+        android:layout_height="@dimen/option_tile_width"
+        android:importantForAccessibility="yes">
 
-    <ImageView
-        android:id="@id/selection_border"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:background="@drawable/option_item_border"
-        android:alpha="0"
-        android:importantForAccessibility="no" />
+        <ImageView
+            android:id="@id/selection_border"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:background="@drawable/option_item_border"
+            android:alpha="0"
+            android:importantForAccessibility="no" />
 
-    <ImageView
-        android:id="@id/background"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:background="@drawable/option_item_background"
-        android:importantForAccessibility="no" />
+        <ImageView
+            android:id="@id/background"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:background="@drawable/option_item_background"
+            android:importantForAccessibility="no" />
 
-    <ImageView
-        android:id="@+id/color_preview_0"
-        android:layout_width="wrap_content"
+        <ImageView
+            android:id="@+id/color_preview_0"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:layout_marginRight="@dimen/color_seed_chip_margin"
+            android:layout_marginBottom="@dimen/color_seed_chip_margin"
+            android:src="@drawable/color_chip_seed_filled0"
+            android:importantForAccessibility="no"/>
+
+        <ImageView
+            android:id="@+id/color_preview_1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:layout_marginLeft="@dimen/color_seed_chip_margin"
+            android:layout_marginBottom="@dimen/color_seed_chip_margin"
+            android:src="@drawable/color_chip_seed_filled2"
+            android:importantForAccessibility="no"/>
+
+        <ImageView
+            android:id="@+id/color_preview_2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:layout_marginRight="@dimen/color_seed_chip_margin"
+            android:layout_marginTop="@dimen/color_seed_chip_margin"
+            android:src="@drawable/color_chip_seed_filled1"
+            android:importantForAccessibility="no"/>
+
+        <ImageView
+            android:id="@+id/color_preview_3"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:layout_marginLeft="@dimen/color_seed_chip_margin"
+            android:layout_marginTop="@dimen/color_seed_chip_margin"
+            android:src="@drawable/color_chip_seed_filled3"
+            android:importantForAccessibility="no" />
+    </FrameLayout>
+
+    <TextView
+        android:id="@+id/option_title"
+        android:layout_width="@dimen/option_tile_width"
         android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:layout_marginRight="@dimen/color_seed_chip_margin"
-        android:layout_marginBottom="@dimen/color_seed_chip_margin"
-        android:src="@drawable/color_chip_seed_filled0"
-        android:importantForAccessibility="no"/>
+        android:layout_marginTop="@dimen/option_bottom_margin"
+        android:textColor="@color/text_color_primary"
+        android:visibility="gone"
+        android:gravity="center" />
+</LinearLayout>
 
-    <ImageView
-        android:id="@+id/color_preview_1"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:layout_marginLeft="@dimen/color_seed_chip_margin"
-        android:layout_marginBottom="@dimen/color_seed_chip_margin"
-        android:src="@drawable/color_chip_seed_filled2"
-        android:importantForAccessibility="no"/>
-
-    <ImageView
-        android:id="@+id/color_preview_2"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:layout_marginRight="@dimen/color_seed_chip_margin"
-        android:layout_marginTop="@dimen/color_seed_chip_margin"
-        android:src="@drawable/color_chip_seed_filled1"
-        android:importantForAccessibility="no"/>
-
-    <ImageView
-        android:id="@+id/color_preview_3"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:layout_marginLeft="@dimen/color_seed_chip_margin"
-        android:layout_marginTop="@dimen/color_seed_chip_margin"
-        android:src="@drawable/color_chip_seed_filled3"
-        android:importantForAccessibility="no"/>
-</FrameLayout>
diff --git a/src/com/android/customization/module/CustomizationInjector.kt b/src/com/android/customization/module/CustomizationInjector.kt
index c5f0b76..306ef04 100644
--- a/src/com/android/customization/module/CustomizationInjector.kt
+++ b/src/com/android/customization/module/CustomizationInjector.kt
@@ -67,5 +67,8 @@
 
     fun getClockViewFactory(activity: Activity): ClockViewFactory
 
-    fun getClockSettingsViewModelFactory(context: Context): ClockSettingsViewModel.Factory
+    fun getClockSettingsViewModelFactory(
+        context: Context,
+        wallpaperColorsViewModel: WallpaperColorsViewModel,
+    ): ClockSettingsViewModel.Factory
 }
diff --git a/src/com/android/customization/module/ThemePickerInjector.kt b/src/com/android/customization/module/ThemePickerInjector.kt
index 3d02c84..e166f2c 100644
--- a/src/com/android/customization/module/ThemePickerInjector.kt
+++ b/src/com/android/customization/module/ThemePickerInjector.kt
@@ -418,11 +418,16 @@
 
     override fun getClockSettingsViewModelFactory(
         context: Context,
+        wallpaperColorsViewModel: WallpaperColorsViewModel,
     ): ClockSettingsViewModel.Factory {
         return clockSettingsViewModelFactory
             ?: ClockSettingsViewModel.Factory(
                     context,
                     getClockPickerInteractor(context),
+                    getColorPickerInteractor(
+                        context,
+                        wallpaperColorsViewModel,
+                    ),
                 )
                 .also { clockSettingsViewModelFactory = it }
     }
diff --git a/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt b/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt
index 2ba03bd..9b6d737 100644
--- a/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt
+++ b/src/com/android/customization/picker/clock/ui/fragment/ClockSettingsFragment.kt
@@ -105,7 +105,10 @@
             view,
             ViewModelProvider(
                     requireActivity(),
-                    injector.getClockSettingsViewModelFactory(context),
+                    injector.getClockSettingsViewModelFactory(
+                        context,
+                        injector.getWallpaperColorsViewModel(),
+                    ),
                 )
                 .get(),
             this@ClockSettingsFragment,
diff --git a/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsViewModel.kt b/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsViewModel.kt
index 41b4010..f33cb4f 100644
--- a/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsViewModel.kt
+++ b/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsViewModel.kt
@@ -16,13 +16,15 @@
 package com.android.customization.picker.clock.ui.viewmodel
 
 import android.content.Context
-import android.graphics.Color
 import androidx.core.graphics.ColorUtils
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.ViewModelProvider
 import androidx.lifecycle.viewModelScope
+import com.android.customization.model.color.ColorSeedOption
 import com.android.customization.picker.clock.domain.interactor.ClockPickerInteractor
 import com.android.customization.picker.clock.shared.ClockSize
+import com.android.customization.picker.color.domain.interactor.ColorPickerInteractor
+import com.android.customization.picker.color.shared.model.ColorType
 import com.android.customization.picker.color.ui.viewmodel.ColorOptionViewModel
 import com.android.wallpaper.R
 import kotlin.math.abs
@@ -34,6 +36,7 @@
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.mapLatest
 import kotlinx.coroutines.flow.shareIn
@@ -42,7 +45,11 @@
 
 /** View model for the clock settings screen. */
 class ClockSettingsViewModel
-private constructor(context: Context, private val interactor: ClockPickerInteractor) : ViewModel() {
+private constructor(
+    context: Context,
+    private val clockPickerInteractor: ClockPickerInteractor,
+    private val colorPickerInteractor: ColorPickerInteractor,
+) : ViewModel() {
 
     enum class Tab {
         COLOR,
@@ -58,7 +65,7 @@
      * level of the system theme color.
      */
     private val saturationLevel: Flow<Float?> =
-        interactor.selectedClockColor
+        clockPickerInteractor.selectedClockColor
             .map { selectedColor ->
                 if (selectedColor == null) {
                     null
@@ -95,38 +102,48 @@
         selectedOption?.let { option ->
             ColorUtils.colorToHSL(option.color0, helperColorHsl)
             helperColorHsl[1] = saturation
-            interactor.setClockColor(ColorUtils.HSLToColor(helperColorHsl))
+            clockPickerInteractor.setClockColor(ColorUtils.HSLToColor(helperColorHsl))
         }
     }
 
     @OptIn(ExperimentalCoroutinesApi::class)
     val colorOptions: StateFlow<List<ColorOptionViewModel>> =
-        interactor.selectedClockColor
-            .mapLatest { selectedColor ->
+        combine(
+                colorPickerInteractor.colorOptions,
+                clockPickerInteractor.selectedClockColor,
+                ::Pair,
+            )
+            .mapLatest { (colorOptions, selectedColor) ->
                 // Use mapLatest and delay(100) here to prevent too many selectedClockColor update
                 // events from ClockRegistry upstream, caused by sliding the saturation level bar.
                 delay(COLOR_OPTIONS_EVENT_UPDATE_DELAY_MILLIS)
                 buildList {
-                    // TODO (b/241966062) Change design of the placeholder for default theme color
-                    add(
-                        ColorOptionViewModel(
-                            color0 = Color.TRANSPARENT,
-                            color1 = Color.TRANSPARENT,
-                            color2 = Color.TRANSPARENT,
-                            color3 = Color.TRANSPARENT,
-                            contentDescription =
-                                context.getString(
-                                    R.string.content_description_color_option,
-                                ),
-                            isSelected = selectedColor == null,
-                            onClick =
-                                if (selectedColor == null) {
-                                    null
-                                } else {
-                                    { interactor.setClockColor(null) }
-                                },
+                    val defaultThemeColor =
+                        colorOptions[ColorType.WALLPAPER_COLOR]?.find { it.isSelected }
+                            ?: colorOptions[ColorType.BASIC_COLOR]?.find { it.isSelected }
+                    if (defaultThemeColor != null) {
+                        val colorSeedOption: ColorSeedOption =
+                            defaultThemeColor.colorOption as ColorSeedOption
+                        val colors = colorSeedOption.previewInfo.resolveColors(context.resources)
+                        add(
+                            ColorOptionViewModel(
+                                color0 = colors[0],
+                                color1 = colors[1],
+                                color2 = colors[2],
+                                color3 = colors[3],
+                                contentDescription =
+                                    colorSeedOption.getContentDescription(context).toString(),
+                                title = context.getString(R.string.default_theme_title),
+                                isSelected = selectedColor == null,
+                                onClick =
+                                    if (selectedColor == null) {
+                                        null
+                                    } else {
+                                        { clockPickerInteractor.setClockColor(null) }
+                                    },
+                            )
                         )
-                    )
+                    }
 
                     if (selectedColor != null) {
                         ColorUtils.colorToHSL(selectedColor, helperColorHsl)
@@ -174,7 +191,7 @@
                                     if (isSelected) {
                                         null
                                     } else {
-                                        { interactor.setClockColor(colorToSet) }
+                                        { clockPickerInteractor.setClockColor(colorToSet) }
                                     },
                             )
                         )
@@ -187,10 +204,10 @@
                 initialValue = emptyList(),
             )
 
-    val selectedClockSize: Flow<ClockSize> = interactor.selectedClockSize
+    val selectedClockSize: Flow<ClockSize> = clockPickerInteractor.selectedClockSize
 
     fun setClockSize(size: ClockSize) {
-        viewModelScope.launch { interactor.setClockSize(size) }
+        viewModelScope.launch { clockPickerInteractor.setClockSize(size) }
     }
 
     private val _selectedTabPosition = MutableStateFlow(Tab.COLOR)
@@ -241,13 +258,15 @@
 
     class Factory(
         private val context: Context,
-        private val interactor: ClockPickerInteractor,
+        private val clockPickerInteractor: ClockPickerInteractor,
+        private val colorPickerInteractor: ColorPickerInteractor,
     ) : ViewModelProvider.Factory {
         override fun <T : ViewModel> create(modelClass: Class<T>): T {
             @Suppress("UNCHECKED_CAST")
             return ClockSettingsViewModel(
                 context = context,
-                interactor = interactor,
+                clockPickerInteractor = clockPickerInteractor,
+                colorPickerInteractor = colorPickerInteractor,
             )
                 as T
         }
diff --git a/src/com/android/customization/picker/color/ui/adapter/ColorOptionAdapter.kt b/src/com/android/customization/picker/color/ui/adapter/ColorOptionAdapter.kt
index 791811d..0e53766 100644
--- a/src/com/android/customization/picker/color/ui/adapter/ColorOptionAdapter.kt
+++ b/src/com/android/customization/picker/color/ui/adapter/ColorOptionAdapter.kt
@@ -23,6 +23,8 @@
 import android.view.View
 import android.view.ViewGroup
 import android.widget.ImageView
+import android.widget.TextView
+import androidx.core.view.isVisible
 import androidx.recyclerview.widget.RecyclerView
 import com.android.customization.picker.color.ui.viewmodel.ColorOptionViewModel
 import com.android.wallpaper.R
@@ -35,10 +37,12 @@
 class ColorOptionAdapter : RecyclerView.Adapter<ColorOptionAdapter.ViewHolder>() {
 
     private val items = mutableListOf<ColorOptionViewModel>()
+    private var isTitleVisible = false
 
     fun setItems(items: List<ColorOptionViewModel>) {
         this.items.clear()
         this.items.addAll(items)
+        isTitleVisible = items.any { item -> item.title != null }
         notifyDataSetChanged()
     }
 
@@ -49,6 +53,7 @@
         val color1View: ImageView = itemView.requireViewById(R.id.color_preview_1)
         val color2View: ImageView = itemView.requireViewById(R.id.color_preview_2)
         val color3View: ImageView = itemView.requireViewById(R.id.color_preview_3)
+        val optionTitleView: TextView = itemView.requireViewById(R.id.option_title)
     }
 
     override fun getItemCount(): Int {
@@ -92,5 +97,7 @@
         holder.color2View.drawable.colorFilter = BlendModeColorFilter(item.color2, BlendMode.SRC)
         holder.color3View.drawable.colorFilter = BlendModeColorFilter(item.color3, BlendMode.SRC)
         holder.itemView.contentDescription = item.contentDescription
+        holder.optionTitleView.isVisible = isTitleVisible
+        holder.optionTitleView.text = item.title
     }
 }
diff --git a/src/com/android/customization/picker/color/ui/viewmodel/ColorOptionViewModel.kt b/src/com/android/customization/picker/color/ui/viewmodel/ColorOptionViewModel.kt
index 0ebc74b..784ec2e 100644
--- a/src/com/android/customization/picker/color/ui/viewmodel/ColorOptionViewModel.kt
+++ b/src/com/android/customization/picker/color/ui/viewmodel/ColorOptionViewModel.kt
@@ -30,6 +30,9 @@
     /** A content description for the color. */
     val contentDescription: String,
 
+    /** Nullable option title. Null by default. */
+    val title: String? = null,
+
     /** Whether this color is selected. */
     val isSelected: Boolean,
 
diff --git a/tests/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsTabViewModelTest.kt b/tests/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsTabViewModelTest.kt
index 215e178..8f61d8b 100644
--- a/tests/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsTabViewModelTest.kt
+++ b/tests/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsTabViewModelTest.kt
@@ -6,11 +6,16 @@
 import com.android.customization.picker.clock.data.repository.FakeClockPickerRepository
 import com.android.customization.picker.clock.domain.interactor.ClockPickerInteractor
 import com.android.customization.picker.clock.shared.ClockSize
+import com.android.customization.picker.color.data.repository.FakeColorPickerRepository
+import com.android.customization.picker.color.domain.interactor.ColorPickerInteractor
+import com.android.customization.picker.color.domain.interactor.ColorPickerSnapshotRestorer
+import com.android.wallpaper.testing.FakeSnapshotStore
 import com.android.wallpaper.testing.collectLastValue
 import com.google.common.collect.Range
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.advanceTimeBy
 import kotlinx.coroutines.test.resetMain
@@ -28,7 +33,8 @@
 class ClockSettingsViewModelTest {
 
     private lateinit var underTest: ClockSettingsViewModel
-
+    private lateinit var colorPickerInteractor: ColorPickerInteractor
+    private lateinit var store: FakeSnapshotStore
     private lateinit var context: Context
 
     @Before
@@ -36,10 +42,20 @@
         val testDispatcher = StandardTestDispatcher()
         Dispatchers.setMain(testDispatcher)
         context = InstrumentationRegistry.getInstrumentation().targetContext
+        colorPickerInteractor =
+            ColorPickerInteractor(
+                repository = FakeColorPickerRepository(context = context),
+                snapshotRestorer = {
+                    ColorPickerSnapshotRestorer(interactor = colorPickerInteractor).apply {
+                        runBlocking { setUpSnapshotRestorer(store = store) }
+                    }
+                },
+            )
         underTest =
             ClockSettingsViewModel.Factory(
                     context = context,
-                    interactor = ClockPickerInteractor(FakeClockPickerRepository()),
+                    clockPickerInteractor = ClockPickerInteractor(FakeClockPickerRepository()),
+                    colorPickerInteractor = colorPickerInteractor,
                 )
                 .create(ClockSettingsViewModel::class.java)
     }
diff --git a/tests/src/com/android/customization/testing/TestCustomizationInjector.kt b/tests/src/com/android/customization/testing/TestCustomizationInjector.kt
index 98cbe68..af0be95 100644
--- a/tests/src/com/android/customization/testing/TestCustomizationInjector.kt
+++ b/tests/src/com/android/customization/testing/TestCustomizationInjector.kt
@@ -218,11 +218,16 @@
 
     override fun getClockSettingsViewModelFactory(
         context: Context,
+        wallpaperColorsViewModel: WallpaperColorsViewModel,
     ): ClockSettingsViewModel.Factory {
         return clockSettingsViewModelFactory
             ?: ClockSettingsViewModel.Factory(
                     context,
                     getClockPickerInteractor(context),
+                    getColorPickerInteractor(
+                        context,
+                        wallpaperColorsViewModel,
+                    ),
                 )
                 .also { clockSettingsViewModelFactory = it }
     }