Loading packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt +61 −3 Original line number Original line Diff line number Diff line Loading @@ -19,13 +19,20 @@ package com.android.systemui.qs.ui.viewmodel import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest import com.android.compose.animation.scene.Back import com.android.compose.animation.scene.Back import com.android.compose.animation.scene.Edge import com.android.compose.animation.scene.Swipe import com.android.compose.animation.scene.Swipe import com.android.compose.animation.scene.SwipeDirection import com.android.compose.animation.scene.SwipeDirection import com.android.compose.animation.scene.UserActionResult import com.android.compose.animation.scene.UserActionResult import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository import com.android.systemui.authentication.shared.model.AuthenticationMethodModel import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectLastValue import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor import com.android.systemui.flags.Flags import com.android.systemui.flags.Flags import com.android.systemui.flags.fakeFeatureFlagsClassic import com.android.systemui.flags.fakeFeatureFlagsClassic import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.testScope import com.android.systemui.qs.FooterActionsController import com.android.systemui.qs.FooterActionsController import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel Loading @@ -41,6 +48,7 @@ import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Before import org.junit.Test import org.junit.Test Loading @@ -66,12 +74,15 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { private lateinit var underTest: QuickSettingsSceneViewModel private lateinit var underTest: QuickSettingsSceneViewModel @OptIn(ExperimentalCoroutinesApi::class) @Before @Before fun setUp() { fun setUp() { kosmos.fakeFeatureFlagsClassic.set(Flags.NEW_NETWORK_SLICE_UI, false) kosmos.fakeFeatureFlagsClassic.set(Flags.NEW_NETWORK_SLICE_UI, false) underTest = underTest = QuickSettingsSceneViewModel( QuickSettingsSceneViewModel( applicationScope = testScope.backgroundScope, deviceEntryInteractor = kosmos.deviceEntryInteractor, brightnessMirrorViewModel = kosmos.brightnessMirrorViewModel, brightnessMirrorViewModel = kosmos.brightnessMirrorViewModel, shadeHeaderViewModel = kosmos.shadeHeaderViewModel, shadeHeaderViewModel = kosmos.shadeHeaderViewModel, qsSceneAdapter = qsFlexiglassAdapter, qsSceneAdapter = qsFlexiglassAdapter, Loading @@ -83,17 +94,27 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { } } @Test @Test fun destinations_whenNotCustomizing() = fun destinations_whenNotCustomizing_unlocked() = testScope.runTest { testScope.runTest { overrideResource(R.bool.config_use_split_notification_shade, false) overrideResource(R.bool.config_use_split_notification_shade, false) val destinations by collectLastValue(underTest.destinationScenes) val destinations by collectLastValue(underTest.destinationScenes) qsFlexiglassAdapter.setCustomizing(false) qsFlexiglassAdapter.setCustomizing(false) kosmos.fakeAuthenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.Pin ) kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus( SuccessFingerprintAuthenticationStatus(0, true) ) assertThat(destinations) assertThat(destinations) .isEqualTo( .isEqualTo( mapOf( mapOf( Back to UserActionResult(Scenes.Shade), Back to UserActionResult(Scenes.Shade), Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Shade), Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Shade), Swipe( fromSource = Edge.Bottom, direction = SwipeDirection.Up, ) to UserActionResult(Scenes.Gone) ) ) ) ) } } Loading @@ -111,12 +132,39 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { sceneInteractor.changeScene(Scenes.QuickSettings, "reason") sceneInteractor.changeScene(Scenes.QuickSettings, "reason") assertThat(currentScene).isEqualTo(Scenes.QuickSettings) assertThat(currentScene).isEqualTo(Scenes.QuickSettings) assertThat(previousScene).isEqualTo(Scenes.Lockscreen) assertThat(previousScene).isEqualTo(Scenes.Lockscreen) assertThat(destinations) assertThat(destinations) .isEqualTo( .isEqualTo( mapOf( mapOf( Back to UserActionResult(Scenes.Lockscreen), Back to UserActionResult(Scenes.Lockscreen), Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Lockscreen), Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Lockscreen), Swipe( fromSource = Edge.Bottom, direction = SwipeDirection.Up, ) to UserActionResult(Scenes.Lockscreen) ) ) } @Test fun destinations_whenNotCustomizing_authMethodSwipe_lockscreenNotDismissed() = testScope.runTest { overrideResource(R.bool.config_use_split_notification_shade, false) val destinations by collectLastValue(underTest.destinationScenes) qsFlexiglassAdapter.setCustomizing(false) kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(true) kosmos.fakeAuthenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.None ) assertThat(destinations) .isEqualTo( mapOf( Back to UserActionResult(Scenes.Shade), Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Shade), Swipe( fromSource = Edge.Bottom, direction = SwipeDirection.Up, ) to UserActionResult(Scenes.Lockscreen) ) ) ) ) } } Loading @@ -132,17 +180,27 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { } } @Test @Test fun destinations_whenNotCustomizing_inSplitShade() = fun destinations_whenNotCustomizing_inSplitShade_unlocked() = testScope.runTest { testScope.runTest { overrideResource(R.bool.config_use_split_notification_shade, true) overrideResource(R.bool.config_use_split_notification_shade, true) val destinations by collectLastValue(underTest.destinationScenes) val destinations by collectLastValue(underTest.destinationScenes) qsFlexiglassAdapter.setCustomizing(false) qsFlexiglassAdapter.setCustomizing(false) kosmos.fakeAuthenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.Pin ) kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus( SuccessFingerprintAuthenticationStatus(0, true) ) assertThat(destinations) assertThat(destinations) .isEqualTo( .isEqualTo( mapOf( mapOf( Back to UserActionResult(Scenes.Shade), Back to UserActionResult(Scenes.Shade), Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Shade), Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Shade), Swipe( fromSource = Edge.Bottom, direction = SwipeDirection.Up, ) to UserActionResult(Scenes.Gone), ) ) ) ) } } Loading packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt +68 −14 Original line number Original line Diff line number Diff line Loading @@ -18,10 +18,15 @@ package com.android.systemui.qs.ui.viewmodel import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner import com.android.compose.animation.scene.Back import com.android.compose.animation.scene.Back import com.android.compose.animation.scene.Edge import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.Swipe import com.android.compose.animation.scene.Swipe import com.android.compose.animation.scene.SwipeDirection import com.android.compose.animation.scene.SwipeDirection import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult import com.android.compose.animation.scene.UserActionResult import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor import com.android.systemui.qs.FooterActionsController import com.android.systemui.qs.FooterActionsController import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel import com.android.systemui.qs.ui.adapter.QSSceneAdapter import com.android.systemui.qs.ui.adapter.QSSceneAdapter Loading @@ -32,35 +37,84 @@ import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject import javax.inject.Inject import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn /** Models UI state and handles user input for the quick settings scene. */ /** Models UI state and handles user input for the quick settings scene. */ @SysUISingleton @SysUISingleton class QuickSettingsSceneViewModel class QuickSettingsSceneViewModel @Inject @Inject constructor( constructor( @Application private val applicationScope: CoroutineScope, deviceEntryInteractor: DeviceEntryInteractor, val brightnessMirrorViewModel: BrightnessMirrorViewModel, val brightnessMirrorViewModel: BrightnessMirrorViewModel, val shadeHeaderViewModel: ShadeHeaderViewModel, val shadeHeaderViewModel: ShadeHeaderViewModel, val qsSceneAdapter: QSSceneAdapter, val qsSceneAdapter: QSSceneAdapter, val notifications: NotificationsPlaceholderViewModel, val notifications: NotificationsPlaceholderViewModel, private val footerActionsViewModelFactory: FooterActionsViewModel.Factory, private val footerActionsViewModelFactory: FooterActionsViewModel.Factory, private val footerActionsController: FooterActionsController, private val footerActionsController: FooterActionsController, private val sceneInteractor: SceneInteractor, sceneInteractor: SceneInteractor, ) { ) { val destinationScenes = @OptIn(ExperimentalCoroutinesApi::class) qsSceneAdapter.isCustomizing.flatMapLatest { customizing -> val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> = if (customizing) { combine( flowOf(emptyMap()) deviceEntryInteractor.isUnlocked, deviceEntryInteractor.canSwipeToEnter, qsSceneAdapter.isCustomizing, sceneInteractor.previousScene(ignored = Scenes.QuickSettings), ) { isUnlocked, canSwipeToDismiss, isCustomizing, previousScene -> destinationScenes( isUnlocked, canSwipeToDismiss, isCustomizing, previousScene, ) } .stateIn( scope = applicationScope, started = SharingStarted.WhileSubscribed(), initialValue = destinationScenes( isUnlocked = deviceEntryInteractor.isUnlocked.value, canSwipeToDismiss = deviceEntryInteractor.canSwipeToEnter.value, isCustomizing = qsSceneAdapter.isCustomizing.value, previousScene = sceneInteractor .previousScene(ignored = Scenes.QuickSettings).value, ), ) private fun destinationScenes( isUnlocked: Boolean, canSwipeToDismiss: Boolean?, isCustomizing: Boolean, previousScene: SceneKey? ): Map<UserAction, UserActionResult> { val upBottomEdge = when { canSwipeToDismiss == true -> Scenes.Lockscreen isUnlocked -> Scenes.Gone else -> Scenes.Lockscreen } return buildMap { if (isCustomizing) { // TODO(b/332749288) Empty map so there are no back handlers and back can close // customizer // TODO(b/330200163) Add an Up from Bottom to be able to collapse the shade // TODO(b/330200163) Add an Up from Bottom to be able to collapse the shade // while customizing // while customizing } else { } else { sceneInteractor.previousScene(ignored = Scenes.QuickSettings).map { previousScene -> this[Back] = UserActionResult(previousScene ?: Scenes.Shade) mapOf( this[Swipe(SwipeDirection.Up)] = UserActionResult(previousScene ?: Scenes.Shade) Back to UserActionResult(previousScene ?: Scenes.Shade), this[ Swipe(SwipeDirection.Up) to UserActionResult(previousScene ?: Scenes.Shade), Swipe( ) fromSource = Edge.Bottom, direction = SwipeDirection.Up, )] = UserActionResult(upBottomEdge) } } } } } } Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt +61 −3 Original line number Original line Diff line number Diff line Loading @@ -19,13 +19,20 @@ package com.android.systemui.qs.ui.viewmodel import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest import com.android.compose.animation.scene.Back import com.android.compose.animation.scene.Back import com.android.compose.animation.scene.Edge import com.android.compose.animation.scene.Swipe import com.android.compose.animation.scene.Swipe import com.android.compose.animation.scene.SwipeDirection import com.android.compose.animation.scene.SwipeDirection import com.android.compose.animation.scene.UserActionResult import com.android.compose.animation.scene.UserActionResult import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository import com.android.systemui.authentication.shared.model.AuthenticationMethodModel import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectLastValue import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor import com.android.systemui.flags.Flags import com.android.systemui.flags.Flags import com.android.systemui.flags.fakeFeatureFlagsClassic import com.android.systemui.flags.fakeFeatureFlagsClassic import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus import com.android.systemui.kosmos.testScope import com.android.systemui.kosmos.testScope import com.android.systemui.qs.FooterActionsController import com.android.systemui.qs.FooterActionsController import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel Loading @@ -41,6 +48,7 @@ import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Before import org.junit.Test import org.junit.Test Loading @@ -66,12 +74,15 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { private lateinit var underTest: QuickSettingsSceneViewModel private lateinit var underTest: QuickSettingsSceneViewModel @OptIn(ExperimentalCoroutinesApi::class) @Before @Before fun setUp() { fun setUp() { kosmos.fakeFeatureFlagsClassic.set(Flags.NEW_NETWORK_SLICE_UI, false) kosmos.fakeFeatureFlagsClassic.set(Flags.NEW_NETWORK_SLICE_UI, false) underTest = underTest = QuickSettingsSceneViewModel( QuickSettingsSceneViewModel( applicationScope = testScope.backgroundScope, deviceEntryInteractor = kosmos.deviceEntryInteractor, brightnessMirrorViewModel = kosmos.brightnessMirrorViewModel, brightnessMirrorViewModel = kosmos.brightnessMirrorViewModel, shadeHeaderViewModel = kosmos.shadeHeaderViewModel, shadeHeaderViewModel = kosmos.shadeHeaderViewModel, qsSceneAdapter = qsFlexiglassAdapter, qsSceneAdapter = qsFlexiglassAdapter, Loading @@ -83,17 +94,27 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { } } @Test @Test fun destinations_whenNotCustomizing() = fun destinations_whenNotCustomizing_unlocked() = testScope.runTest { testScope.runTest { overrideResource(R.bool.config_use_split_notification_shade, false) overrideResource(R.bool.config_use_split_notification_shade, false) val destinations by collectLastValue(underTest.destinationScenes) val destinations by collectLastValue(underTest.destinationScenes) qsFlexiglassAdapter.setCustomizing(false) qsFlexiglassAdapter.setCustomizing(false) kosmos.fakeAuthenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.Pin ) kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus( SuccessFingerprintAuthenticationStatus(0, true) ) assertThat(destinations) assertThat(destinations) .isEqualTo( .isEqualTo( mapOf( mapOf( Back to UserActionResult(Scenes.Shade), Back to UserActionResult(Scenes.Shade), Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Shade), Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Shade), Swipe( fromSource = Edge.Bottom, direction = SwipeDirection.Up, ) to UserActionResult(Scenes.Gone) ) ) ) ) } } Loading @@ -111,12 +132,39 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { sceneInteractor.changeScene(Scenes.QuickSettings, "reason") sceneInteractor.changeScene(Scenes.QuickSettings, "reason") assertThat(currentScene).isEqualTo(Scenes.QuickSettings) assertThat(currentScene).isEqualTo(Scenes.QuickSettings) assertThat(previousScene).isEqualTo(Scenes.Lockscreen) assertThat(previousScene).isEqualTo(Scenes.Lockscreen) assertThat(destinations) assertThat(destinations) .isEqualTo( .isEqualTo( mapOf( mapOf( Back to UserActionResult(Scenes.Lockscreen), Back to UserActionResult(Scenes.Lockscreen), Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Lockscreen), Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Lockscreen), Swipe( fromSource = Edge.Bottom, direction = SwipeDirection.Up, ) to UserActionResult(Scenes.Lockscreen) ) ) } @Test fun destinations_whenNotCustomizing_authMethodSwipe_lockscreenNotDismissed() = testScope.runTest { overrideResource(R.bool.config_use_split_notification_shade, false) val destinations by collectLastValue(underTest.destinationScenes) qsFlexiglassAdapter.setCustomizing(false) kosmos.fakeDeviceEntryRepository.setLockscreenEnabled(true) kosmos.fakeAuthenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.None ) assertThat(destinations) .isEqualTo( mapOf( Back to UserActionResult(Scenes.Shade), Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Shade), Swipe( fromSource = Edge.Bottom, direction = SwipeDirection.Up, ) to UserActionResult(Scenes.Lockscreen) ) ) ) ) } } Loading @@ -132,17 +180,27 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { } } @Test @Test fun destinations_whenNotCustomizing_inSplitShade() = fun destinations_whenNotCustomizing_inSplitShade_unlocked() = testScope.runTest { testScope.runTest { overrideResource(R.bool.config_use_split_notification_shade, true) overrideResource(R.bool.config_use_split_notification_shade, true) val destinations by collectLastValue(underTest.destinationScenes) val destinations by collectLastValue(underTest.destinationScenes) qsFlexiglassAdapter.setCustomizing(false) qsFlexiglassAdapter.setCustomizing(false) kosmos.fakeAuthenticationRepository.setAuthenticationMethod( AuthenticationMethodModel.Pin ) kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus( SuccessFingerprintAuthenticationStatus(0, true) ) assertThat(destinations) assertThat(destinations) .isEqualTo( .isEqualTo( mapOf( mapOf( Back to UserActionResult(Scenes.Shade), Back to UserActionResult(Scenes.Shade), Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Shade), Swipe(SwipeDirection.Up) to UserActionResult(Scenes.Shade), Swipe( fromSource = Edge.Bottom, direction = SwipeDirection.Up, ) to UserActionResult(Scenes.Gone), ) ) ) ) } } Loading
packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt +68 −14 Original line number Original line Diff line number Diff line Loading @@ -18,10 +18,15 @@ package com.android.systemui.qs.ui.viewmodel import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner import com.android.compose.animation.scene.Back import com.android.compose.animation.scene.Back import com.android.compose.animation.scene.Edge import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.Swipe import com.android.compose.animation.scene.Swipe import com.android.compose.animation.scene.SwipeDirection import com.android.compose.animation.scene.SwipeDirection import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult import com.android.compose.animation.scene.UserActionResult import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor import com.android.systemui.qs.FooterActionsController import com.android.systemui.qs.FooterActionsController import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel import com.android.systemui.qs.ui.adapter.QSSceneAdapter import com.android.systemui.qs.ui.adapter.QSSceneAdapter Loading @@ -32,35 +37,84 @@ import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject import javax.inject.Inject import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn /** Models UI state and handles user input for the quick settings scene. */ /** Models UI state and handles user input for the quick settings scene. */ @SysUISingleton @SysUISingleton class QuickSettingsSceneViewModel class QuickSettingsSceneViewModel @Inject @Inject constructor( constructor( @Application private val applicationScope: CoroutineScope, deviceEntryInteractor: DeviceEntryInteractor, val brightnessMirrorViewModel: BrightnessMirrorViewModel, val brightnessMirrorViewModel: BrightnessMirrorViewModel, val shadeHeaderViewModel: ShadeHeaderViewModel, val shadeHeaderViewModel: ShadeHeaderViewModel, val qsSceneAdapter: QSSceneAdapter, val qsSceneAdapter: QSSceneAdapter, val notifications: NotificationsPlaceholderViewModel, val notifications: NotificationsPlaceholderViewModel, private val footerActionsViewModelFactory: FooterActionsViewModel.Factory, private val footerActionsViewModelFactory: FooterActionsViewModel.Factory, private val footerActionsController: FooterActionsController, private val footerActionsController: FooterActionsController, private val sceneInteractor: SceneInteractor, sceneInteractor: SceneInteractor, ) { ) { val destinationScenes = @OptIn(ExperimentalCoroutinesApi::class) qsSceneAdapter.isCustomizing.flatMapLatest { customizing -> val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> = if (customizing) { combine( flowOf(emptyMap()) deviceEntryInteractor.isUnlocked, deviceEntryInteractor.canSwipeToEnter, qsSceneAdapter.isCustomizing, sceneInteractor.previousScene(ignored = Scenes.QuickSettings), ) { isUnlocked, canSwipeToDismiss, isCustomizing, previousScene -> destinationScenes( isUnlocked, canSwipeToDismiss, isCustomizing, previousScene, ) } .stateIn( scope = applicationScope, started = SharingStarted.WhileSubscribed(), initialValue = destinationScenes( isUnlocked = deviceEntryInteractor.isUnlocked.value, canSwipeToDismiss = deviceEntryInteractor.canSwipeToEnter.value, isCustomizing = qsSceneAdapter.isCustomizing.value, previousScene = sceneInteractor .previousScene(ignored = Scenes.QuickSettings).value, ), ) private fun destinationScenes( isUnlocked: Boolean, canSwipeToDismiss: Boolean?, isCustomizing: Boolean, previousScene: SceneKey? ): Map<UserAction, UserActionResult> { val upBottomEdge = when { canSwipeToDismiss == true -> Scenes.Lockscreen isUnlocked -> Scenes.Gone else -> Scenes.Lockscreen } return buildMap { if (isCustomizing) { // TODO(b/332749288) Empty map so there are no back handlers and back can close // customizer // TODO(b/330200163) Add an Up from Bottom to be able to collapse the shade // TODO(b/330200163) Add an Up from Bottom to be able to collapse the shade // while customizing // while customizing } else { } else { sceneInteractor.previousScene(ignored = Scenes.QuickSettings).map { previousScene -> this[Back] = UserActionResult(previousScene ?: Scenes.Shade) mapOf( this[Swipe(SwipeDirection.Up)] = UserActionResult(previousScene ?: Scenes.Shade) Back to UserActionResult(previousScene ?: Scenes.Shade), this[ Swipe(SwipeDirection.Up) to UserActionResult(previousScene ?: Scenes.Shade), Swipe( ) fromSource = Edge.Bottom, direction = SwipeDirection.Up, )] = UserActionResult(upBottomEdge) } } } } } } Loading