Use bouncy grid option item

Use the grid option item bouncy selected animation background.

Test: Manully tested.
Bug: 362237825
Flag: com.android.systemui.shared.new_customization_picker_ui
Change-Id: Ia311cfe6a6be39a42f752ca4f0015d690b33dac6
diff --git a/res/layout/grid_option2.xml b/res/layout/grid_option2.xml
new file mode 100644
index 0000000..437b95b
--- /dev/null
+++ b/res/layout/grid_option2.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 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.
+  ~
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="@dimen/option_item_size"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:gravity="center_horizontal"
+    android:clipChildren="false">
+
+    <FrameLayout
+        android:layout_width="@dimen/option_item_size"
+        android:layout_height="@dimen/option_item_size"
+        android:clipChildren="false">
+
+        <com.android.wallpaper.picker.option.ui.view.OptionItemBackground
+            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/foreground"
+            android:layout_width="48dp"
+            android:layout_height="48dp"
+            android:layout_gravity="center" />
+
+    </FrameLayout>
+
+    <View
+        android:layout_width="0dp"
+        android:layout_height="8dp" />
+
+    <TextView
+        android:id="@id/text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textColor="@color/system_on_surface"
+        android:singleLine="true"
+        android:ellipsize="end"
+        android:textSize="12sp"
+        android:text="Placeholder for stable size calculation, please do not remove."
+        tools:ignore="HardcodedText" />
+
+</LinearLayout>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 0c36753..4f1062f 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -189,6 +189,7 @@
     <dimen name="floating_sheet_tab_clock_font_toolbar_top_margin">16dp</dimen>
     <dimen name="floating_sheet_tab_clock_font_toolbar_bottom_margin">8dp</dimen>
     <dimen name="floating_sheet_list_item_horizontal_space">4dp</dimen>
+    <dimen name="floating_sheet_grid_list_item_horizontal_space">10dp</dimen>
     <dimen name="floating_sheet_list_item_vertical_space">4dp</dimen>
     <dimen name="floating_sheet_clock_style_option_list_margin_bottom">8dp</dimen>
     <dimen name="floating_sheet_clock_style_option_width">80dp</dimen>
diff --git a/src/com/android/wallpaper/customization/ui/binder/ShapeGridFloatingSheetBinder.kt b/src/com/android/wallpaper/customization/ui/binder/ShapeGridFloatingSheetBinder.kt
index 5f292bd..138a253 100644
--- a/src/com/android/wallpaper/customization/ui/binder/ShapeGridFloatingSheetBinder.kt
+++ b/src/com/android/wallpaper/customization/ui/binder/ShapeGridFloatingSheetBinder.kt
@@ -43,6 +43,7 @@
 import com.android.wallpaper.picker.customization.ui.view.adapter.FloatingToolbarTabAdapter
 import com.android.wallpaper.picker.customization.ui.viewmodel.ColorUpdateViewModel
 import com.android.wallpaper.picker.option.ui.adapter.OptionItemAdapter
+import com.android.wallpaper.picker.option.ui.adapter.OptionItemAdapter2
 import com.android.wallpaper.picker.option.ui.binder.OptionItemBinder
 import java.lang.ref.WeakReference
 import kotlinx.coroutines.CoroutineDispatcher
@@ -97,7 +98,7 @@
 
         val gridContent = view.requireViewById<View>(R.id.app_grid_container)
         val gridOptionListAdapter =
-            createGridOptionItemAdapter(view.context, lifecycleOwner, backgroundDispatcher)
+            createGridOptionItemAdapter(lifecycleOwner, backgroundDispatcher)
         val gridOptionList =
             view.requireViewById<RecyclerView>(R.id.grid_options).also {
                 it.initGridOptionList(view.context, gridOptionListAdapter)
@@ -243,8 +244,7 @@
                         ),
                     itemHorizontalSpacePx =
                         context.resources.getDimensionPixelSize(
-                            com.android.themepicker.R.dimen
-                                .floating_sheet_list_item_horizontal_space
+                            R.dimen.floating_sheet_list_item_horizontal_space
                         ),
                 )
             )
@@ -253,30 +253,23 @@
     }
 
     private fun createGridOptionItemAdapter(
-        context: Context,
         lifecycleOwner: LifecycleOwner,
         backgroundDispatcher: CoroutineDispatcher,
-    ): OptionItemAdapter<GridIconViewModel> =
-        OptionItemAdapter(
-            layoutResourceId = R.layout.grid_option,
+    ): OptionItemAdapter2<GridIconViewModel> =
+        OptionItemAdapter2(
+            layoutResourceId = R.layout.grid_option2,
             lifecycleOwner = lifecycleOwner,
             backgroundDispatcher = backgroundDispatcher,
-            foregroundTintSpec =
-                OptionItemBinder.TintSpec(
-                    selectedColor =
-                        context.getColor(com.android.wallpaper.R.color.system_on_surface),
-                    unselectedColor =
-                        context.getColor(com.android.wallpaper.R.color.system_on_surface),
-                ),
-            bindIcon = { foregroundView: View, gridIcon: GridIconViewModel ->
-                val imageView = foregroundView as? ImageView
+            bindPayload = { view: View, gridIcon: GridIconViewModel ->
+                val imageView = view.findViewById(R.id.foreground) as? ImageView
                 imageView?.let { GridIconViewBinder.bind(imageView, gridIcon) }
+                return@OptionItemAdapter2 null
             },
         )
 
     private fun RecyclerView.initGridOptionList(
         context: Context,
-        adapter: OptionItemAdapter<GridIconViewModel>,
+        adapter: OptionItemAdapter2<GridIconViewModel>,
     ) {
         apply {
             this.layoutManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false)
@@ -288,8 +281,7 @@
                         ),
                     itemHorizontalSpacePx =
                         context.resources.getDimensionPixelSize(
-                            com.android.themepicker.R.dimen
-                                .floating_sheet_list_item_horizontal_space
+                            R.dimen.floating_sheet_grid_list_item_horizontal_space
                         ),
                 )
             )
diff --git a/src/com/android/wallpaper/customization/ui/viewmodel/ShapeGridPickerViewModel.kt b/src/com/android/wallpaper/customization/ui/viewmodel/ShapeGridPickerViewModel.kt
index 7f3c4cb..1e19e80 100644
--- a/src/com/android/wallpaper/customization/ui/viewmodel/ShapeGridPickerViewModel.kt
+++ b/src/com/android/wallpaper/customization/ui/viewmodel/ShapeGridPickerViewModel.kt
@@ -29,6 +29,7 @@
 import com.android.wallpaper.picker.common.text.ui.viewmodel.Text
 import com.android.wallpaper.picker.customization.ui.viewmodel.FloatingToolbarTabViewModel
 import com.android.wallpaper.picker.option.ui.viewmodel.OptionItemViewModel
+import com.android.wallpaper.picker.option.ui.viewmodel.OptionItemViewModel2
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
@@ -126,7 +127,7 @@
             overridingGridOptionKey ?: selectedGridOption.key.value
         }
 
-    val gridOptions: Flow<List<OptionItemViewModel<GridIconViewModel>>> =
+    val gridOptions: Flow<List<OptionItemViewModel2<GridIconViewModel>>> =
         interactor.gridOptions
             .filterNotNull()
             .map { gridOptions -> gridOptions.map { toGridOptionItemViewModel(it) } }
@@ -184,7 +185,7 @@
 
     private fun toGridOptionItemViewModel(
         option: GridOptionModel
-    ): OptionItemViewModel<GridIconViewModel> {
+    ): OptionItemViewModel2<GridIconViewModel> {
         val iconShapePath =
             context.resources.getString(
                 Resources.getSystem()
@@ -203,7 +204,7 @@
                     initialValue = false,
                 )
 
-        return OptionItemViewModel(
+        return OptionItemViewModel2(
             key = MutableStateFlow(option.key),
             payload =
                 GridIconViewModel(columns = option.cols, rows = option.rows, path = iconShapePath),
diff --git a/tests/robotests/src/com/android/wallpaper/customization/ui/viewmodel/ShapeGridPickerViewModelTest.kt b/tests/robotests/src/com/android/wallpaper/customization/ui/viewmodel/ShapeGridPickerViewModelTest.kt
index c99acca..71ea0d9 100644
--- a/tests/robotests/src/com/android/wallpaper/customization/ui/viewmodel/ShapeGridPickerViewModelTest.kt
+++ b/tests/robotests/src/com/android/wallpaper/customization/ui/viewmodel/ShapeGridPickerViewModelTest.kt
@@ -27,6 +27,7 @@
 import com.android.customization.picker.grid.ui.viewmodel.ShapeIconViewModel
 import com.android.wallpaper.picker.common.text.ui.viewmodel.Text
 import com.android.wallpaper.picker.option.ui.viewmodel.OptionItemViewModel
+import com.android.wallpaper.picker.option.ui.viewmodel.OptionItemViewModel2
 import com.android.wallpaper.testing.collectLastValue
 import com.google.common.truth.Truth.assertThat
 import dagger.hilt.android.qualifiers.ApplicationContext
@@ -159,7 +160,7 @@
         testScope.runTest {
             val selectedGridOption = collectLastValue(underTest.selectedGridOption)
 
-            assertOptionItem(
+            assertGridItem(
                 optionItem = selectedGridOption(),
                 key = "normal",
                 payload = GridIconViewModel(5, 5, iconShapePath),
@@ -183,7 +184,7 @@
             onPracticalOptionClick()?.invoke()
             onApply()?.invoke()
 
-            assertOptionItem(
+            assertGridItem(
                 optionItem = selectedGridOption(),
                 key = "practical",
                 payload = GridIconViewModel(4, 5, iconShapePath),
@@ -199,7 +200,7 @@
         testScope.runTest {
             val optionItems = collectLastValue(underTest.gridOptions)
 
-            assertOptionItem(
+            assertGridItem(
                 optionItem = optionItems()?.get(0),
                 key = "normal",
                 payload = GridIconViewModel(5, 5, iconShapePath),
@@ -208,7 +209,7 @@
                 isSelected = true,
                 isEnabled = true,
             )
-            assertOptionItem(
+            assertGridItem(
                 optionItem = optionItems()?.get(1),
                 key = "practical",
                 payload = GridIconViewModel(4, 5, iconShapePath),
@@ -229,7 +230,7 @@
 
             onPracticalOptionClick()?.invoke()
 
-            assertOptionItem(
+            assertGridItem(
                 optionItem = optionItems()?.get(0),
                 key = "normal",
                 payload = GridIconViewModel(5, 5, iconShapePath),
@@ -238,7 +239,7 @@
                 isSelected = false,
                 isEnabled = true,
             )
-            assertOptionItem(
+            assertGridItem(
                 optionItem = optionItems()?.get(1),
                 key = "practical",
                 payload = GridIconViewModel(4, 5, iconShapePath),
@@ -267,8 +268,8 @@
         assertThat(optionItem.isEnabled).isEqualTo(isEnabled)
     }
 
-    private fun TestScope.assertOptionItem(
-        optionItem: OptionItemViewModel<GridIconViewModel>?,
+    private fun TestScope.assertGridItem(
+        optionItem: OptionItemViewModel2<GridIconViewModel>?,
         key: String,
         payload: GridIconViewModel?,
         text: Text,