summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt23
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt17
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt34
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt5
7 files changed, 121 insertions, 4 deletions
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index f6535ec0b710..8f247f60bfc4 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -94,6 +94,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
@@ -171,7 +172,11 @@ fun CommunalHub(
var removeButtonCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) }
var toolbarSize: IntSize? by remember { mutableStateOf(null) }
var gridCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) }
- val gridState = rememberLazyGridState()
+
+ val gridState =
+ rememberLazyGridState(viewModel.savedFirstScrollIndex, viewModel.savedFirstScrollOffset)
+ viewModel.clearPersistedScrollPosition()
+
val contentListState = rememberContentListState(widgetConfigurator, communalContent, viewModel)
val reorderingWidgets by viewModel.reorderingWidgets.collectAsStateWithLifecycle()
val selectedKey = viewModel.selectedKey.collectAsStateWithLifecycle()
@@ -187,6 +192,8 @@ fun CommunalHub(
val contentPadding = gridContentPadding(viewModel.isEditMode, toolbarSize)
val contentOffset = beforeContentPadding(contentPadding).toOffset()
+ ObserveScrollEffect(gridState, viewModel)
+
if (!viewModel.isEditMode) {
ScrollOnUpdatedLiveContentEffect(communalContent, gridState)
}
@@ -420,6 +427,20 @@ private fun DisclaimerBottomSheetContent(onButtonClicked: () -> Unit) {
}
}
+@Composable
+private fun ObserveScrollEffect(
+ gridState: LazyGridState,
+ communalViewModel: BaseCommunalViewModel
+) {
+
+ LaunchedEffect(gridState) {
+ snapshotFlow {
+ Pair(gridState.firstVisibleItemIndex, gridState.firstVisibleItemScrollOffset)
+ }
+ .collect { communalViewModel.onScrollPositionUpdated(it.first, it.second) }
+ }
+}
+
/**
* Observes communal content and scrolls to any added or updated live content, e.g. a new media
* session is started, or a paused timer is resumed.
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
index 0190ccba3caa..91c5ba6acf75 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
@@ -38,6 +38,7 @@ import com.android.systemui.communal.data.repository.FakeCommunalWidgetRepositor
import com.android.systemui.communal.data.repository.fakeCommunalMediaRepository
import com.android.systemui.communal.data.repository.fakeCommunalTutorialRepository
import com.android.systemui.communal.data.repository.fakeCommunalWidgetRepository
+import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.communalPrefsInteractor
@@ -76,6 +77,8 @@ import org.mockito.Mockito
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.spy
@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -94,6 +97,7 @@ class CommunalEditModeViewModelTest : SysuiTestCase() {
private lateinit var smartspaceRepository: FakeSmartspaceRepository
private lateinit var mediaRepository: FakeCommunalMediaRepository
private lateinit var communalSceneInteractor: CommunalSceneInteractor
+ private lateinit var communalInteractor: CommunalInteractor
private val testableResources = context.orCreateTestableResources
@@ -108,6 +112,7 @@ class CommunalEditModeViewModelTest : SysuiTestCase() {
smartspaceRepository = kosmos.fakeSmartspaceRepository
mediaRepository = kosmos.fakeCommunalMediaRepository
communalSceneInteractor = kosmos.communalSceneInteractor
+ communalInteractor = spy(kosmos.communalInteractor)
kosmos.fakeUserRepository.setUserInfos(listOf(MAIN_USER_INFO))
kosmos.fakeUserTracker.set(
userInfos = listOf(MAIN_USER_INFO),
@@ -119,7 +124,7 @@ class CommunalEditModeViewModelTest : SysuiTestCase() {
underTest =
CommunalEditModeViewModel(
communalSceneInteractor,
- kosmos.communalInteractor,
+ communalInteractor,
kosmos.communalSettingsInteractor,
kosmos.keyguardTransitionInteractor,
mediaHost,
@@ -342,6 +347,16 @@ class CommunalEditModeViewModelTest : SysuiTestCase() {
assertThat(showDisclaimer).isFalse()
}
+ @Test
+ fun scrollPosition_persistedOnEditCleanup() {
+ val index = 2
+ val offset = 30
+ underTest.onScrollPositionUpdated(index, offset)
+ underTest.cleanupEditModeState()
+
+ verify(communalInteractor).setScrollPosition(eq(index), eq(offset))
+ }
+
private companion object {
val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN)
const val WIDGET_PICKER_PACKAGE_NAME = "widget_picker_package_name"
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
index d33877462ec6..d06cb7faa337 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
@@ -35,6 +35,7 @@ import com.android.systemui.communal.data.repository.fakeCommunalMediaRepository
import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository
import com.android.systemui.communal.data.repository.fakeCommunalTutorialRepository
import com.android.systemui.communal.data.repository.fakeCommunalWidgetRepository
+import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.communalInteractor
import com.android.systemui.communal.domain.interactor.communalSceneInteractor
import com.android.systemui.communal.domain.interactor.communalSettingsInteractor
@@ -97,7 +98,9 @@ import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
import org.mockito.kotlin.whenever
import platform.test.runner.parameterized.ParameterizedAndroidJunit4
import platform.test.runner.parameterized.Parameters
@@ -121,6 +124,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
private lateinit var shadeTestUtil: ShadeTestUtil
private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
private lateinit var communalRepository: FakeCommunalSceneRepository
+ private lateinit var communalInteractor: CommunalInteractor
private lateinit var underTest: CommunalViewModel
@@ -154,6 +158,8 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
kosmos.powerInteractor.setAwakeForTest()
+ communalInteractor = spy(kosmos.communalInteractor)
+
underTest =
CommunalViewModel(
kosmos.testDispatcher,
@@ -164,7 +170,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
kosmos.keyguardInteractor,
mock<KeyguardIndicationController>(),
kosmos.communalSceneInteractor,
- kosmos.communalInteractor,
+ communalInteractor,
kosmos.communalSettingsInteractor,
kosmos.communalTutorialInteractor,
kosmos.shadeInteractor,
@@ -767,6 +773,16 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
.isInstanceOf(CommunalContentModel.CtaTileInViewMode::class.java)
}
+ @Test
+ fun scrollPosition_persistedOnEditEntry() {
+ val index = 2
+ val offset = 30
+ underTest.onScrollPositionUpdated(index, offset)
+ underTest.onOpenWidgetEditor(false)
+
+ verify(communalInteractor).setScrollPosition(eq(index), eq(offset))
+ }
+
private suspend fun setIsMainUser(isMainUser: Boolean) {
val user = if (isMainUser) MAIN_USER_INFO else SECONDARY_USER_INFO
with(userRepository) {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index 86f5fe1cac57..35e546f4388d 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -556,4 +556,29 @@ constructor(
)
}
}
+
+ /**
+ * {@link #setScrollPosition} persists the current communal grid scroll position (to volatile
+ * memory) so that the next presentation of the grid (either as glanceable hub or edit mode) can
+ * restore position.
+ */
+ fun setScrollPosition(firstVisibleItemIndex: Int, firstVisibleItemOffset: Int) {
+ _firstVisibleItemIndex = firstVisibleItemIndex
+ _firstVisibleItemOffset = firstVisibleItemOffset
+ }
+
+ fun resetScrollPosition() {
+ _firstVisibleItemIndex = 0
+ _firstVisibleItemOffset = 0
+ }
+
+ val firstVisibleItemIndex: Int
+ get() = _firstVisibleItemIndex
+
+ private var _firstVisibleItemIndex: Int = 0
+
+ val firstVisibleItemOffset: Int
+ get() = _firstVisibleItemOffset
+
+ private var _firstVisibleItemOffset: Int = 0
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
index 6ec6ec1113a0..19d7ceba2310 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
@@ -59,6 +59,18 @@ abstract class BaseCommunalViewModel(
/** Accessibility delegate to be set on CommunalAppWidgetHostView. */
open val widgetAccessibilityDelegate: View.AccessibilityDelegate? = null
+ /**
+ * The up-to-date value of the grid scroll offset. persisted to interactor on
+ * {@link #persistScrollPosition}
+ */
+ private var currentScrollOffset = 0
+
+ /**
+ * The up-to-date value of the grid scroll index. persisted to interactor on
+ * {@link #persistScrollPosition}
+ */
+ private var currentScrollIndex = 0
+
fun signalUserInteraction() {
communalInteractor.signalUserInteraction()
}
@@ -147,6 +159,28 @@ abstract class BaseCommunalViewModel(
/** Called as the user request to show the customize widget button. */
open fun onLongClick() {}
+ /** Called when the grid scroll position has been updated. */
+ open fun onScrollPositionUpdated(firstVisibleItemIndex: Int, firstVisibleItemScroll: Int) {
+ currentScrollIndex = firstVisibleItemIndex
+ currentScrollOffset = firstVisibleItemScroll
+ }
+
+ /** Stores scroll values to interactor. */
+ protected fun persistScrollPosition() {
+ communalInteractor.setScrollPosition(currentScrollIndex, currentScrollOffset)
+ }
+
+ /** Invoked after scroll values are used to initialize grid position. */
+ open fun clearPersistedScrollPosition() {
+ communalInteractor.setScrollPosition(0, 0)
+ }
+
+ val savedFirstScrollIndex: Int
+ get() = communalInteractor.firstVisibleItemIndex
+
+ val savedFirstScrollOffset: Int
+ get() = communalInteractor.firstVisibleItemOffset
+
/** Set the key of the currently selected item */
fun setSelectedKey(key: String?) {
_selectedKey.value = key
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
index 18b343eb97c4..5346f74eaccf 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
@@ -216,6 +216,9 @@ constructor(
/** Called when exiting the edit mode, before transitioning back to the communal scene. */
fun cleanupEditModeState() {
communalSceneInteractor.setEditModeState(null)
+
+ // Set the scroll position of the glanceable hub to match where we are now.
+ persistScrollPosition()
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
index 780bf70f3f7b..02ecfe1b0cf9 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
@@ -233,7 +233,10 @@ constructor(
override fun onOpenWidgetEditor(
shouldOpenWidgetPickerOnStart: Boolean,
- ) = communalInteractor.showWidgetEditor(selectedKey.value, shouldOpenWidgetPickerOnStart)
+ ) {
+ persistScrollPosition()
+ communalInteractor.showWidgetEditor(selectedKey.value, shouldOpenWidgetPickerOnStart)
+ }
override fun onDismissCtaTile() {
scope.launch {