Merge "Save and restore recycler view state on app refresh" into udc-dev am: 49c4e2d4c0 am: 36e418bf01 am: 9c99e353f1

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

Change-Id: Idd76034ab96b165f43c4155b59845f05b90b8a79
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
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 3eadec5..cd9dd54 100644
--- a/src/com/android/customization/picker/color/ui/binder/ColorPickerBinder.kt
+++ b/src/com/android/customization/picker/color/ui/binder/ColorPickerBinder.kt
@@ -18,6 +18,8 @@
 package com.android.customization.picker.color.ui.binder
 
 import android.content.res.Configuration
+import android.os.Bundle
+import android.os.Parcelable
 import android.view.View
 import android.widget.TextView
 import androidx.lifecycle.Lifecycle
@@ -48,7 +50,7 @@
         view: View,
         viewModel: ColorPickerViewModel,
         lifecycleOwner: LifecycleOwner,
-    ) {
+    ): Binding {
         val colorTypeTabView: RecyclerView = view.requireViewById(R.id.color_type_tabs)
         val colorTypeTabSubheaderView: TextView = view.requireViewById(R.id.color_type_tab_subhead)
         val colorOptionContainerView: RecyclerView = view.requireViewById(R.id.color_options)
@@ -94,23 +96,50 @@
                         colorOptionAdapter.setItems(colorOptions)
                         // the same recycler view is used for different color types tabs
                         // the scroll state of each tab should be independent of others
-                        var indexToFocus = 0
-                        colorOptions.forEachIndexed { index, colorOption ->
-                            if (colorOption.isSelected.value) {
-                                indexToFocus = index
+                        if (layoutManagerSavedState != null) {
+                            colorOptionContainerView.post {
+                                (colorOptionContainerView.layoutManager as LinearLayoutManager)
+                                    .onRestoreInstanceState(layoutManagerSavedState)
+                                layoutManagerSavedState = null
                             }
-                        }
-                        val linearLayoutManager =
-                            object : LinearLayoutManager(view.context, HORIZONTAL, false) {
-                                override fun onLayoutCompleted(state: RecyclerView.State?) {
-                                    super.onLayoutCompleted(state)
-                                    scrollToPosition(indexToFocus)
+                        } else {
+                            var indexToFocus = colorOptions.indexOfFirst { it.isSelected.value }
+                            indexToFocus = if (indexToFocus < 0) 0 else indexToFocus
+                            val linearLayoutManager =
+                                object : LinearLayoutManager(view.context, HORIZONTAL, false) {
+                                    override fun onLayoutCompleted(state: RecyclerView.State?) {
+                                        super.onLayoutCompleted(state)
+                                        // scrollToPosition seems to be inconsistently moving
+                                        // selected
+                                        // color to different positions
+                                        scrollToPositionWithOffset(indexToFocus, 0)
+                                    }
                                 }
-                            }
-                        colorOptionContainerView.layoutManager = linearLayoutManager
+                            colorOptionContainerView.layoutManager = linearLayoutManager
+                        }
                     }
                 }
             }
         }
+        return object : Binding {
+            override fun saveInstanceState(savedState: Bundle) {
+                savedState.putParcelable(
+                    LAYOUT_MANAGER_SAVED_STATE,
+                    colorOptionContainerView.layoutManager?.onSaveInstanceState()
+                )
+            }
+
+            override fun restoreInstanceState(savedState: Bundle) {
+                layoutManagerSavedState = savedState.getParcelable(LAYOUT_MANAGER_SAVED_STATE)
+            }
+        }
     }
+
+    interface Binding {
+        fun saveInstanceState(savedState: Bundle)
+        fun restoreInstanceState(savedState: Bundle)
+    }
+
+    private val LAYOUT_MANAGER_SAVED_STATE: String = "layout_manager_state"
+    private var layoutManagerSavedState: Parcelable? = null
 }
diff --git a/src/com/android/customization/picker/color/ui/fragment/ColorPickerFragment.kt b/src/com/android/customization/picker/color/ui/fragment/ColorPickerFragment.kt
index b2b9c66..23ad037 100644
--- a/src/com/android/customization/picker/color/ui/fragment/ColorPickerFragment.kt
+++ b/src/com/android/customization/picker/color/ui/fragment/ColorPickerFragment.kt
@@ -39,6 +39,8 @@
 
 @OptIn(ExperimentalCoroutinesApi::class)
 class ColorPickerFragment : AppbarFragment() {
+    private var binding: ColorPickerBinder.Binding? = null
+
     companion object {
         @JvmStatic
         fun newInstance(): ColorPickerFragment {
@@ -64,19 +66,24 @@
         val wallpaperInfoFactory = injector.getCurrentWallpaperInfoFactory(requireContext())
         val displayUtils: DisplayUtils = injector.getDisplayUtils(requireContext())
         val wcViewModel = injector.getWallpaperColorsViewModel()
-        ColorPickerBinder.bind(
-            view = view,
-            viewModel =
-                ViewModelProvider(
-                        requireActivity(),
-                        injector.getColorPickerViewModelFactory(
-                            context = requireContext(),
-                            wallpaperColorsViewModel = wcViewModel,
-                        ),
-                    )
-                    .get(),
-            lifecycleOwner = this,
-        )
+
+        binding =
+            ColorPickerBinder.bind(
+                view = view,
+                viewModel =
+                    ViewModelProvider(
+                            requireActivity(),
+                            injector.getColorPickerViewModelFactory(
+                                context = requireContext(),
+                                wallpaperColorsViewModel = wcViewModel,
+                            ),
+                        )
+                        .get(),
+                lifecycleOwner = this,
+            )
+
+        savedInstanceState?.let { binding?.restoreInstanceState(it) }
+
         ScreenPreviewBinder.bind(
             activity = requireActivity(),
             previewView = lockScreenView,
@@ -161,6 +168,11 @@
         return view
     }
 
+    override fun onSaveInstanceState(savedInstanceState: Bundle) {
+        super.onSaveInstanceState(savedInstanceState)
+        binding?.saveInstanceState(savedInstanceState)
+    }
+
     override fun getDefaultTitle(): CharSequence {
         return requireContext().getString(R.string.color_picker_title)
     }