Merge "Save and restore recycler view state on app refresh" into udc-dev am: 49c4e2d4c0 am: 1eafd15440
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/ThemePicker/+/22958236
Change-Id: I2f55967bc21cb92b3997f8c5e0144362a20a5853
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)
}