Merge "Dynamic Color Tile Update" into udc-dev am: 441fd401ef

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/ThemePicker/+/22346998

Change-Id: Icb11e5f237cd75b29a5a1f0a76b9fa5484423e43
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/src/com/android/customization/model/color/ColorCustomizationManager.java b/src/com/android/customization/model/color/ColorCustomizationManager.java
index 29f6ba6..790c86f 100644
--- a/src/com/android/customization/model/color/ColorCustomizationManager.java
+++ b/src/com/android/customization/model/color/ColorCustomizationManager.java
@@ -181,7 +181,23 @@
         if (lockWallpaperColors != null && mLockWallpaperColors.equals(mHomeWallpaperColors)) {
             lockWallpaperColors = null;
         }
-        mProvider.fetch(callback, reload, mHomeWallpaperColors, lockWallpaperColors);
+        mProvider.fetch(callback, reload, mHomeWallpaperColors,
+                lockWallpaperColors,  /* shouldUseRevampedUi= */ false);
+    }
+
+    /**
+     * Fetch options function for the customization hub revamped UI
+     *
+     * TODO (b/276417460): refactor to reduce code repetition with the other fetch options function
+     */
+    public void fetchRevampedUIOptions(OptionsFetchedListener<ColorOption> callback,
+            boolean reload) {
+        WallpaperColors lockWallpaperColors = mLockWallpaperColors;
+        if (lockWallpaperColors != null && mLockWallpaperColors.equals(mHomeWallpaperColors)) {
+            lockWallpaperColors = null;
+        }
+        mProvider.fetch(callback, reload, mHomeWallpaperColors,
+                lockWallpaperColors,  /* shouldUseRevampedUi= */ true);
     }
 
     /**
diff --git a/src/com/android/customization/model/color/ColorOptionsProvider.java b/src/com/android/customization/model/color/ColorOptionsProvider.java
index 2803c7b..166b4da 100644
--- a/src/com/android/customization/model/color/ColorOptionsProvider.java
+++ b/src/com/android/customization/model/color/ColorOptionsProvider.java
@@ -70,8 +70,12 @@
      * @param homeWallpaperColors to get seed colors from
      * @param lockWallpaperColors WallpaperColors from the lockscreen wallpaper to get seeds from,
      *                            if different than homeWallpaperColors
+     * @param shouldUseRevampedUi fetches color options with new preview mappings for the revamped
+     *                            UI if set to true
      */
     void fetch(OptionsFetchedListener<ColorOption> callback, boolean reload,
             @Nullable WallpaperColors homeWallpaperColors,
-            @Nullable WallpaperColors lockWallpaperColors);
+            @Nullable WallpaperColors lockWallpaperColors,
+            boolean shouldUseRevampedUi
+    );
 }
diff --git a/src/com/android/customization/model/color/ColorProvider.kt b/src/com/android/customization/model/color/ColorProvider.kt
index f91ec6b..639a886 100644
--- a/src/com/android/customization/model/color/ColorProvider.kt
+++ b/src/com/android/customization/model/color/ColorProvider.kt
@@ -87,7 +87,8 @@
         callback: OptionsFetchedListener<ColorOption>?,
         reload: Boolean,
         homeWallpaperColors: WallpaperColors?,
-        lockWallpaperColors: WallpaperColors?
+        lockWallpaperColors: WallpaperColors?,
+        shouldUseRevampedUi: Boolean
     ) {
         val wallpaperColorsChanged =
             this.homeWallpaperColors != homeWallpaperColors ||
@@ -103,7 +104,11 @@
                         loadPreset()
                     }
                     if (wallpaperColorsChanged || reload) {
-                        loadSeedColors(homeWallpaperColors, lockWallpaperColors)
+                        loadSeedColors(
+                            homeWallpaperColors,
+                            lockWallpaperColors,
+                            shouldUseRevampedUi
+                        )
                     }
                 } catch (e: Throwable) {
                     colorsAvailable = false
@@ -127,7 +132,8 @@
 
     private fun loadSeedColors(
         homeWallpaperColors: WallpaperColors?,
-        lockWallpaperColors: WallpaperColors?
+        lockWallpaperColors: WallpaperColors?,
+        shouldUseRevampedUi: Boolean,
     ) {
         if (homeWallpaperColors == null) return
 
@@ -147,7 +153,8 @@
                 colorsPerSource,
                 if (shouldLockColorsGoFirst) COLOR_SOURCE_LOCK else COLOR_SOURCE_HOME,
                 true,
-                bundles
+                bundles,
+                shouldUseRevampedUi
             )
             // Second half of the colors
             buildColorSeeds(
@@ -155,10 +162,18 @@
                 MAX_SEED_COLORS - bundles.size / styleSize,
                 if (shouldLockColorsGoFirst) COLOR_SOURCE_HOME else COLOR_SOURCE_LOCK,
                 false,
-                bundles
+                bundles,
+                shouldUseRevampedUi
             )
         } else {
-            buildColorSeeds(homeWallpaperColors, colorsPerSource, COLOR_SOURCE_HOME, true, bundles)
+            buildColorSeeds(
+                homeWallpaperColors,
+                colorsPerSource,
+                COLOR_SOURCE_HOME,
+                true,
+                bundles,
+                shouldUseRevampedUi
+            )
         }
 
         bundles.addAll(colorBundles?.filterNot { it is ColorSeedOption } ?: emptyList())
@@ -170,13 +185,14 @@
         maxColors: Int,
         source: String,
         containsDefault: Boolean,
-        bundles: MutableList<ColorOption>
+        bundles: MutableList<ColorOption>,
+        shouldUseRevampedUi: Boolean,
     ) {
         val seedColors = ColorScheme.getSeedColors(wallpaperColors)
         val defaultSeed = seedColors.first()
-        buildBundle(defaultSeed, 0, containsDefault, source, bundles)
+        buildBundle(defaultSeed, 0, containsDefault, source, bundles, shouldUseRevampedUi)
         for ((i, colorInt) in seedColors.drop(1).take(maxColors - 1).withIndex()) {
-            buildBundle(colorInt, i + 1, false, source, bundles)
+            buildBundle(colorInt, i + 1, false, source, bundles, shouldUseRevampedUi)
         }
     }
 
@@ -185,7 +201,8 @@
         i: Int,
         isDefault: Boolean,
         source: String,
-        bundles: MutableList<ColorOption>
+        bundles: MutableList<ColorOption>,
+        shouldUseRevampedUi: Boolean,
     ) {
         // TODO(b/202145216): Measure time cost in the loop.
         for (style in styleList) {
@@ -193,8 +210,14 @@
             val lightColorScheme = ColorScheme(colorInt, /* darkTheme= */ false, style)
             val darkColorScheme = ColorScheme(colorInt, /* darkTheme= */ true, style)
             builder
-                .setLightColors(lightColorScheme.getLightColorPreview())
-                .setDarkColors(darkColorScheme.getDarkColorPreview())
+                .setLightColors(
+                    if (shouldUseRevampedUi) lightColorScheme.getRevampedUILightColorPreview()
+                    else lightColorScheme.getLightColorPreview()
+                )
+                .setDarkColors(
+                    if (shouldUseRevampedUi) darkColorScheme.getRevampedUIDarkColorPreview()
+                    else darkColorScheme.getDarkColorPreview()
+                )
                 .addOverlayPackage(
                     OVERLAY_CATEGORY_SYSTEM_PALETTE,
                     if (isDefault) "" else toColorString(colorInt)
@@ -247,6 +270,30 @@
         return getLightColorPreview()
     }
 
+    @ColorInt
+    private fun ColorScheme.getRevampedUILightColorPreview(): IntArray {
+        return intArrayOf(
+            setAlphaComponent(this.accent1.s600, ALPHA_MASK),
+            setAlphaComponent(this.accent1.s600, ALPHA_MASK),
+            setAlphaComponent(this.accent2.s100, ALPHA_MASK),
+            ColorStateList.valueOf(this.accent3.s500).withLStar(59f).colors[0],
+        )
+    }
+
+    /**
+     * Returns the color for the dark theme version of the preview of a ColorScheme based on this
+     * order: |-------| | 0 | 1 | |---+---| | 2 | 3 | |-------|
+     */
+    @ColorInt
+    private fun ColorScheme.getRevampedUIDarkColorPreview(): IntArray {
+        return intArrayOf(
+            setAlphaComponent(this.accent1.s200, ALPHA_MASK),
+            setAlphaComponent(this.accent1.s200, ALPHA_MASK),
+            setAlphaComponent(this.accent2.s700, ALPHA_MASK),
+            setAlphaComponent(this.accent3.s100, ALPHA_MASK),
+        )
+    }
+
     private fun ColorScheme.getPresetColorPreview(seed: Int): IntArray {
         return when (this.style) {
             Style.FRUIT_SALAD -> intArrayOf(seed, this.accent1.s100)
diff --git a/src/com/android/customization/model/color/ColorSeedOption.java b/src/com/android/customization/model/color/ColorSeedOption.java
index ba61ed1..ed38049 100644
--- a/src/com/android/customization/model/color/ColorSeedOption.java
+++ b/src/com/android/customization/model/color/ColorSeedOption.java
@@ -100,6 +100,7 @@
         /**
          * Returns the colors to be applied corresponding with the current
          * configuration's UI mode.
+         * @param res resources to read to the UI mode configuration from
          * @return one of {@link #lightColors} or {@link #darkColors}
          */
         @ColorInt
@@ -108,6 +109,17 @@
                     == Configuration.UI_MODE_NIGHT_YES;
             return night ? darkColors : lightColors;
         }
+
+        /**
+         * Returns the preview colors based on whether dark theme or light theme colors are
+         * requested.
+         * @param darkTheme if true, returns dark theme colors, otherwise returns light theme colors
+         * @return one of {@link #lightColors} or {@link #darkColors}
+         */
+        @ColorInt
+        public int[] resolveColors(boolean darkTheme) {
+            return darkTheme ? darkColors : lightColors;
+        }
     }
 
     /**
diff --git a/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt b/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt
index 7de45e9..4664bd0 100644
--- a/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt
+++ b/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt
@@ -15,6 +15,7 @@
  */
 package com.android.customization.picker.clock.ui.binder
 
+import android.content.res.Configuration
 import android.view.View
 import android.view.ViewGroup
 import android.widget.FrameLayout
@@ -67,7 +68,10 @@
                 lifecycleOwner = lifecycleOwner,
                 bindIcon = { foregroundView: View, colorIcon: ColorOptionIconViewModel ->
                     val viewGroup = foregroundView as? ViewGroup
-                    viewGroup?.let { ColorOptionIconBinder.bind(viewGroup, colorIcon) }
+                    val night =
+                        (view.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK ==
+                            Configuration.UI_MODE_NIGHT_YES)
+                    viewGroup?.let { ColorOptionIconBinder.bind(viewGroup, colorIcon, night) }
                 }
             )
         colorOptionContainerView.adapter = colorOptionAdapter
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 b66f977..a0ac370 100644
--- a/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsViewModel.kt
+++ b/src/com/android/customization/picker/clock/ui/viewmodel/ClockSettingsViewModel.kt
@@ -145,10 +145,14 @@
                             key = MutableStateFlow(colorModel.colorId) as StateFlow<String>,
                             payload =
                                 ColorOptionIconViewModel(
-                                    colorModel.color,
-                                    colorModel.color,
-                                    colorModel.color,
-                                    colorModel.color,
+                                    lightThemeColor0 = colorModel.color,
+                                    lightThemeColor1 = colorModel.color,
+                                    lightThemeColor2 = colorModel.color,
+                                    lightThemeColor3 = colorModel.color,
+                                    darkThemeColor0 = colorModel.color,
+                                    darkThemeColor1 = colorModel.color,
+                                    darkThemeColor2 = colorModel.color,
+                                    darkThemeColor3 = colorModel.color,
                                 ),
                             text =
                                 Text.Loaded(
@@ -200,8 +204,26 @@
         val optionItemPayload =
             when (colorOption) {
                 is ColorSeedOption -> {
-                    val colors = colorOption.previewInfo.resolveColors(context.resources)
-                    ColorOptionIconViewModel(colors[0], colors[1], colors[2], colors[3])
+                    val lightThemeColors =
+                        colorOption.previewInfo.resolveColors(
+                            /** darkTheme= */
+                            false
+                        )
+                    val darkThemeColors =
+                        colorOption.previewInfo.resolveColors(
+                            /** darkTheme= */
+                            true
+                        )
+                    ColorOptionIconViewModel(
+                        lightThemeColor0 = lightThemeColors[0],
+                        lightThemeColor1 = lightThemeColors[1],
+                        lightThemeColor2 = lightThemeColors[2],
+                        lightThemeColor3 = lightThemeColors[3],
+                        darkThemeColor0 = darkThemeColors[0],
+                        darkThemeColor1 = darkThemeColors[1],
+                        darkThemeColor2 = darkThemeColors[2],
+                        darkThemeColor3 = darkThemeColors[3],
+                    )
                 }
                 is ColorBundle -> {
                     val primaryColor =
@@ -209,10 +231,14 @@
                     val secondaryColor =
                         colorOption.previewInfo.resolveSecondaryColor(context.resources)
                     ColorOptionIconViewModel(
-                        primaryColor,
-                        secondaryColor,
-                        primaryColor,
-                        secondaryColor
+                        lightThemeColor0 = primaryColor,
+                        lightThemeColor1 = secondaryColor,
+                        lightThemeColor2 = primaryColor,
+                        lightThemeColor3 = secondaryColor,
+                        darkThemeColor0 = primaryColor,
+                        darkThemeColor1 = secondaryColor,
+                        darkThemeColor2 = primaryColor,
+                        darkThemeColor3 = secondaryColor,
                     )
                 }
                 else -> null
diff --git a/src/com/android/customization/picker/color/data/repository/ColorPickerRepositoryImpl.kt b/src/com/android/customization/picker/color/data/repository/ColorPickerRepositoryImpl.kt
index 512a500..a044174 100644
--- a/src/com/android/customization/picker/color/data/repository/ColorPickerRepositoryImpl.kt
+++ b/src/com/android/customization/picker/color/data/repository/ColorPickerRepositoryImpl.kt
@@ -52,7 +52,7 @@
             .map { (homeColors, lockColors) ->
                 suspendCancellableCoroutine { continuation ->
                     colorManager.setWallpaperColors(homeColors, lockColors)
-                    colorManager.fetchOptions(
+                    colorManager.fetchRevampedUIOptions(
                         object : CustomizationManager.OptionsFetchedListener<ColorOption?> {
                             override fun onOptionsLoaded(options: MutableList<ColorOption?>?) {
                                 val wallpaperColorOptions: MutableList<ColorOptionModel> =
diff --git a/src/com/android/customization/picker/color/ui/binder/ColorOptionIconBinder.kt b/src/com/android/customization/picker/color/ui/binder/ColorOptionIconBinder.kt
index 1478cc4..d238180 100644
--- a/src/com/android/customization/picker/color/ui/binder/ColorOptionIconBinder.kt
+++ b/src/com/android/customization/picker/color/ui/binder/ColorOptionIconBinder.kt
@@ -28,14 +28,30 @@
     fun bind(
         view: ViewGroup,
         viewModel: ColorOptionIconViewModel,
+        darkTheme: Boolean,
     ) {
         val color0View: ImageView = view.requireViewById(R.id.color_preview_0)
         val color1View: ImageView = view.requireViewById(R.id.color_preview_1)
         val color2View: ImageView = view.requireViewById(R.id.color_preview_2)
         val color3View: ImageView = view.requireViewById(R.id.color_preview_3)
-        color0View.drawable.colorFilter = BlendModeColorFilter(viewModel.color0, BlendMode.SRC)
-        color1View.drawable.colorFilter = BlendModeColorFilter(viewModel.color1, BlendMode.SRC)
-        color2View.drawable.colorFilter = BlendModeColorFilter(viewModel.color2, BlendMode.SRC)
-        color3View.drawable.colorFilter = BlendModeColorFilter(viewModel.color3, BlendMode.SRC)
+        if (darkTheme) {
+            color0View.drawable.colorFilter =
+                BlendModeColorFilter(viewModel.darkThemeColor0, BlendMode.SRC)
+            color1View.drawable.colorFilter =
+                BlendModeColorFilter(viewModel.darkThemeColor1, BlendMode.SRC)
+            color2View.drawable.colorFilter =
+                BlendModeColorFilter(viewModel.darkThemeColor2, BlendMode.SRC)
+            color3View.drawable.colorFilter =
+                BlendModeColorFilter(viewModel.darkThemeColor3, BlendMode.SRC)
+        } else {
+            color0View.drawable.colorFilter =
+                BlendModeColorFilter(viewModel.lightThemeColor0, BlendMode.SRC)
+            color1View.drawable.colorFilter =
+                BlendModeColorFilter(viewModel.lightThemeColor1, BlendMode.SRC)
+            color2View.drawable.colorFilter =
+                BlendModeColorFilter(viewModel.lightThemeColor2, BlendMode.SRC)
+            color3View.drawable.colorFilter =
+                BlendModeColorFilter(viewModel.lightThemeColor3, BlendMode.SRC)
+        }
     }
 }
diff --git a/src/com/android/customization/picker/color/ui/binder/ColorPickerBinder.kt b/src/com/android/customization/picker/color/ui/binder/ColorPickerBinder.kt
index 7623048..452e8b6 100644
--- a/src/com/android/customization/picker/color/ui/binder/ColorPickerBinder.kt
+++ b/src/com/android/customization/picker/color/ui/binder/ColorPickerBinder.kt
@@ -17,6 +17,7 @@
 
 package com.android.customization.picker.color.ui.binder
 
+import android.content.res.Configuration
 import android.view.View
 import android.view.ViewGroup
 import android.widget.TextView
@@ -32,7 +33,6 @@
 import com.android.customization.picker.common.ui.view.ItemSpacing
 import com.android.wallpaper.R
 import com.android.wallpaper.picker.option.ui.adapter.OptionItemAdapter
-import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.launch
 
@@ -64,7 +64,10 @@
                 lifecycleOwner = lifecycleOwner,
                 bindIcon = { foregroundView: View, colorIcon: ColorOptionIconViewModel ->
                     val viewGroup = foregroundView as? ViewGroup
-                    viewGroup?.let { ColorOptionIconBinder.bind(viewGroup, colorIcon) }
+                    val night =
+                        (view.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK ==
+                            Configuration.UI_MODE_NIGHT_YES)
+                    viewGroup?.let { ColorOptionIconBinder.bind(viewGroup, colorIcon, night) }
                 }
             )
         colorOptionContainerView.adapter = colorOptionAdapter
diff --git a/src/com/android/customization/picker/color/ui/binder/ColorSectionViewBinder.kt b/src/com/android/customization/picker/color/ui/binder/ColorSectionViewBinder.kt
index 05b0916..10013e6 100644
--- a/src/com/android/customization/picker/color/ui/binder/ColorSectionViewBinder.kt
+++ b/src/com/android/customization/picker/color/ui/binder/ColorSectionViewBinder.kt
@@ -17,6 +17,7 @@
 
 package com.android.customization.picker.color.ui.binder
 
+import android.content.res.Configuration
 import android.view.LayoutInflater
 import android.view.View
 import android.view.ViewGroup
@@ -91,10 +92,15 @@
                 })
                 .let { if (it < 0) 0 else it }
         options.subList(0, colorOptionSlotSize).forEach { item ->
+            val night =
+                (view.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK ==
+                    Configuration.UI_MODE_NIGHT_YES)
             val itemView =
                 LayoutInflater.from(view.context)
                     .inflate(R.layout.color_option_no_background, view, false)
-            item.payload?.let { ColorOptionIconBinder.bind(itemView as ViewGroup, item.payload) }
+            item.payload?.let {
+                ColorOptionIconBinder.bind(itemView as ViewGroup, item.payload, night)
+            }
             val optionSelectedView = itemView.findViewById<ImageView>(R.id.option_selected)
 
             lifecycleOwner.lifecycleScope.launch {
diff --git a/src/com/android/customization/picker/color/ui/viewmodel/ColorOptionIconViewModel.kt b/src/com/android/customization/picker/color/ui/viewmodel/ColorOptionIconViewModel.kt
index d32538d..8723c8c 100644
--- a/src/com/android/customization/picker/color/ui/viewmodel/ColorOptionIconViewModel.kt
+++ b/src/com/android/customization/picker/color/ui/viewmodel/ColorOptionIconViewModel.kt
@@ -20,8 +20,12 @@
 import android.annotation.ColorInt
 
 data class ColorOptionIconViewModel(
-    @ColorInt val color0: Int,
-    @ColorInt val color1: Int,
-    @ColorInt val color2: Int,
-    @ColorInt val color3: Int,
+    @ColorInt val lightThemeColor0: Int,
+    @ColorInt val lightThemeColor1: Int,
+    @ColorInt val lightThemeColor2: Int,
+    @ColorInt val lightThemeColor3: Int,
+    @ColorInt val darkThemeColor0: Int,
+    @ColorInt val darkThemeColor1: Int,
+    @ColorInt val darkThemeColor2: Int,
+    @ColorInt val darkThemeColor3: Int,
 )
diff --git a/src/com/android/customization/picker/color/ui/viewmodel/ColorPickerViewModel.kt b/src/com/android/customization/picker/color/ui/viewmodel/ColorPickerViewModel.kt
index 73c1ac6..97dbba6 100644
--- a/src/com/android/customization/picker/color/ui/viewmodel/ColorPickerViewModel.kt
+++ b/src/com/android/customization/picker/color/ui/viewmodel/ColorPickerViewModel.kt
@@ -101,8 +101,14 @@
                                 colorOptionEntry.value.map { colorOptionModel ->
                                     val colorSeedOption: ColorSeedOption =
                                         colorOptionModel.colorOption as ColorSeedOption
-                                    val colors =
-                                        colorSeedOption.previewInfo.resolveColors(context.resources)
+                                    val lightThemeColors =
+                                        colorSeedOption.previewInfo.resolveColors(
+                                            /* darkTheme= */ false
+                                        )
+                                    val darkThemeColors =
+                                        colorSeedOption.previewInfo.resolveColors(
+                                            /* darkTheme= */ true
+                                        )
                                     val isSelectedFlow: StateFlow<Boolean> =
                                         interactor.activeColorOption
                                             .map {
@@ -118,10 +124,14 @@
                                                 as StateFlow<String>,
                                         payload =
                                             ColorOptionIconViewModel(
-                                                colors[0],
-                                                colors[1],
-                                                colors[2],
-                                                colors[3]
+                                                lightThemeColor0 = lightThemeColors[0],
+                                                lightThemeColor1 = lightThemeColors[1],
+                                                lightThemeColor2 = lightThemeColors[2],
+                                                lightThemeColor3 = lightThemeColors[3],
+                                                darkThemeColor0 = darkThemeColors[0],
+                                                darkThemeColor1 = darkThemeColors[1],
+                                                darkThemeColor2 = darkThemeColors[2],
+                                                darkThemeColor3 = darkThemeColors[3],
                                             ),
                                         text =
                                             Text.Loaded(
@@ -173,10 +183,14 @@
                                                 as StateFlow<String>,
                                         payload =
                                             ColorOptionIconViewModel(
-                                                primaryColor,
-                                                secondaryColor,
-                                                primaryColor,
-                                                secondaryColor
+                                                lightThemeColor0 = primaryColor,
+                                                lightThemeColor1 = secondaryColor,
+                                                lightThemeColor2 = primaryColor,
+                                                lightThemeColor3 = secondaryColor,
+                                                darkThemeColor0 = primaryColor,
+                                                darkThemeColor1 = secondaryColor,
+                                                darkThemeColor2 = primaryColor,
+                                                darkThemeColor3 = secondaryColor,
                                             ),
                                         text =
                                             Text.Loaded(