Loading packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt +1 −12 Original line number Diff line number Diff line Loading @@ -22,11 +22,8 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import com.android.compose.animation.scene.Back import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.SceneScope import com.android.compose.animation.scene.Swipe import com.android.compose.animation.scene.SwipeDirection import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult import com.android.systemui.bouncer.ui.BouncerDialogFactory Loading @@ -35,9 +32,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.ui.composable.ComposableScene import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow object Bouncer { object Elements { Loading @@ -57,13 +52,7 @@ constructor( override val key = Scenes.Bouncer override val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> = MutableStateFlow( mapOf( Back to UserActionResult(Scenes.Lockscreen), Swipe(SwipeDirection.Down) to UserActionResult(Scenes.Lockscreen), ) ) .asStateFlow() viewModel.destinationScenes @Composable override fun SceneScope.Content( Loading packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt +24 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,10 @@ package com.android.systemui.bouncer.ui.viewmodel import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.compose.animation.scene.Back import com.android.compose.animation.scene.Swipe import com.android.compose.animation.scene.SwipeDirection import com.android.compose.animation.scene.UserActionResult import com.android.systemui.SysuiTestCase import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository Loading @@ -34,7 +38,10 @@ import com.android.systemui.flags.Flags import com.android.systemui.flags.fakeFeatureFlagsClassic import com.android.systemui.kosmos.testScope import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.shared.model.fakeSceneDataSource import com.android.systemui.testKosmos import com.android.systemui.truth.containsEntriesExactly import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertWithMessage import kotlinx.coroutines.ExperimentalCoroutinesApi Loading Loading @@ -193,6 +200,23 @@ class BouncerViewModelTest : SysuiTestCase() { assertThat(isFoldSplitRequired).isTrue() } @Test fun destinationScenes() = testScope.runTest { val destinationScenes by collectLastValue(underTest.destinationScenes) kosmos.fakeSceneDataSource.changeScene(Scenes.QuickSettings) runCurrent() kosmos.fakeSceneDataSource.changeScene(Scenes.Bouncer) runCurrent() assertThat(destinationScenes) .containsEntriesExactly( Back to UserActionResult(Scenes.QuickSettings), Swipe(SwipeDirection.Down) to UserActionResult(Scenes.QuickSettings), ) } private fun authMethodsToTest(): List<AuthenticationMethodModel> { return listOf(None, Pin, Password, Pattern, Sim) } Loading packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt +32 −0 Original line number Diff line number Diff line Loading @@ -289,6 +289,38 @@ class SceneContainerStartableTest : SysuiTestCase() { assertThat(currentSceneKey).isEqualTo(Scenes.Gone) } @Test fun switchFromBouncerToQuickSettingsWhenDeviceUnlocked() = testScope.runTest { val currentSceneKey by collectLastValue(sceneInteractor.currentScene) val transitionState = prepareState( authenticationMethod = AuthenticationMethodModel.Pin, isDeviceUnlocked = false, initialSceneKey = Scenes.Lockscreen, ) assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen) underTest.start() runCurrent() sceneInteractor.changeScene(Scenes.QuickSettings, "switching to qs for test") transitionState.value = ObservableTransitionState.Idle(Scenes.QuickSettings) runCurrent() assertThat(currentSceneKey).isEqualTo(Scenes.QuickSettings) sceneInteractor.changeScene(Scenes.Bouncer, "switching to bouncer for test") transitionState.value = ObservableTransitionState.Idle(Scenes.Bouncer) runCurrent() assertThat(currentSceneKey).isEqualTo(Scenes.Bouncer) kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus( SuccessFingerprintAuthenticationStatus(0, true) ) assertThat(currentSceneKey).isEqualTo(Scenes.QuickSettings) } @Test fun switchFromLockscreenToGoneWhenDeviceUnlocksWithBypassOn() = testScope.runTest { Loading packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt +8 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.bouncer.domain.interactor import com.android.compose.animation.scene.SceneKey import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor import com.android.systemui.authentication.domain.interactor.AuthenticationResult import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.Sim Loading @@ -26,6 +27,8 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.model.Scenes import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.async Loading @@ -47,6 +50,7 @@ constructor( private val deviceEntryFaceAuthInteractor: DeviceEntryFaceAuthInteractor, private val falsingInteractor: FalsingInteractor, private val powerInteractor: PowerInteractor, sceneInteractor: SceneInteractor, ) { private val _onIncorrectBouncerInput = MutableSharedFlow<Unit>() val onIncorrectBouncerInput: SharedFlow<Unit> = _onIncorrectBouncerInput Loading Loading @@ -80,6 +84,10 @@ constructor( } .map {} /** The scene to show when bouncer is dismissed. */ val dismissDestination: Flow<SceneKey> = sceneInteractor.previousScene.map { it ?: Scenes.Lockscreen } /** Notifies that the user has places down a pointer, not necessarily dragging just yet. */ fun onDown() { falsingInteractor.avoidGesture() Loading packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt +26 −6 Original line number Diff line number Diff line Loading @@ -21,6 +21,12 @@ import android.app.admin.DevicePolicyResources import android.content.Context import android.graphics.Bitmap import androidx.core.graphics.drawable.toBitmap import com.android.compose.animation.scene.Back import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.Swipe import com.android.compose.animation.scene.SwipeDirection import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor import com.android.systemui.authentication.shared.model.AuthenticationMethodModel import com.android.systemui.authentication.shared.model.AuthenticationWipeModel Loading @@ -35,6 +41,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.inputmethod.domain.interactor.InputMethodInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.systemui.user.ui.viewmodel.UserActionViewModel import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel Loading Loading @@ -82,6 +89,15 @@ class BouncerViewModel( initialValue = null, ) val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> = bouncerInteractor.dismissDestination .map(::destinationSceneMap) .stateIn( applicationScope, SharingStarted.WhileSubscribed(), initialValue = destinationSceneMap(Scenes.Lockscreen), ) val message: BouncerMessageViewModel = bouncerMessageViewModel val userSwitcherDropdown: StateFlow<List<UserSwitcherDropdownItemViewModel>> = Loading Loading @@ -310,8 +326,7 @@ class BouncerViewModel( { message }, failedAttempts, remainingAttempts, ) ?: message ) ?: message } else { message } Loading @@ -328,8 +343,7 @@ class BouncerViewModel( .KEYGUARD_DIALOG_FAILED_ATTEMPTS_ERASING_PROFILE, { message }, failedAttempts, ) ?: message ) ?: message } else { message } Loading Loading @@ -357,6 +371,12 @@ class BouncerViewModel( } } private fun destinationSceneMap(prevScene: SceneKey) = mapOf( Back to UserActionResult(prevScene), Swipe(SwipeDirection.Down) to UserActionResult(prevScene), ) data class DialogViewModel( val text: String, Loading Loading @@ -400,13 +420,13 @@ object BouncerViewModelModule { simBouncerInteractor = simBouncerInteractor, authenticationInteractor = authenticationInteractor, selectedUserInteractor = selectedUserInteractor, devicePolicyManager = devicePolicyManager, bouncerMessageViewModel = bouncerMessageViewModel, flags = flags, selectedUser = userSwitcherViewModel.selectedUser, users = userSwitcherViewModel.users, userSwitcherMenu = userSwitcherViewModel.menu, actionButton = actionButtonInteractor.actionButton, devicePolicyManager = devicePolicyManager, bouncerMessageViewModel = bouncerMessageViewModel, ) } } Loading
packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt +1 −12 Original line number Diff line number Diff line Loading @@ -22,11 +22,8 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import com.android.compose.animation.scene.Back import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.SceneScope import com.android.compose.animation.scene.Swipe import com.android.compose.animation.scene.SwipeDirection import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult import com.android.systemui.bouncer.ui.BouncerDialogFactory Loading @@ -35,9 +32,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.ui.composable.ComposableScene import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow object Bouncer { object Elements { Loading @@ -57,13 +52,7 @@ constructor( override val key = Scenes.Bouncer override val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> = MutableStateFlow( mapOf( Back to UserActionResult(Scenes.Lockscreen), Swipe(SwipeDirection.Down) to UserActionResult(Scenes.Lockscreen), ) ) .asStateFlow() viewModel.destinationScenes @Composable override fun SceneScope.Content( Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModelTest.kt +24 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,10 @@ package com.android.systemui.bouncer.ui.viewmodel import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.compose.animation.scene.Back import com.android.compose.animation.scene.Swipe import com.android.compose.animation.scene.SwipeDirection import com.android.compose.animation.scene.UserActionResult import com.android.systemui.SysuiTestCase import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository Loading @@ -34,7 +38,10 @@ import com.android.systemui.flags.Flags import com.android.systemui.flags.fakeFeatureFlagsClassic import com.android.systemui.kosmos.testScope import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.shared.model.fakeSceneDataSource import com.android.systemui.testKosmos import com.android.systemui.truth.containsEntriesExactly import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertWithMessage import kotlinx.coroutines.ExperimentalCoroutinesApi Loading Loading @@ -193,6 +200,23 @@ class BouncerViewModelTest : SysuiTestCase() { assertThat(isFoldSplitRequired).isTrue() } @Test fun destinationScenes() = testScope.runTest { val destinationScenes by collectLastValue(underTest.destinationScenes) kosmos.fakeSceneDataSource.changeScene(Scenes.QuickSettings) runCurrent() kosmos.fakeSceneDataSource.changeScene(Scenes.Bouncer) runCurrent() assertThat(destinationScenes) .containsEntriesExactly( Back to UserActionResult(Scenes.QuickSettings), Swipe(SwipeDirection.Down) to UserActionResult(Scenes.QuickSettings), ) } private fun authMethodsToTest(): List<AuthenticationMethodModel> { return listOf(None, Pin, Password, Pattern, Sim) } Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt +32 −0 Original line number Diff line number Diff line Loading @@ -289,6 +289,38 @@ class SceneContainerStartableTest : SysuiTestCase() { assertThat(currentSceneKey).isEqualTo(Scenes.Gone) } @Test fun switchFromBouncerToQuickSettingsWhenDeviceUnlocked() = testScope.runTest { val currentSceneKey by collectLastValue(sceneInteractor.currentScene) val transitionState = prepareState( authenticationMethod = AuthenticationMethodModel.Pin, isDeviceUnlocked = false, initialSceneKey = Scenes.Lockscreen, ) assertThat(currentSceneKey).isEqualTo(Scenes.Lockscreen) underTest.start() runCurrent() sceneInteractor.changeScene(Scenes.QuickSettings, "switching to qs for test") transitionState.value = ObservableTransitionState.Idle(Scenes.QuickSettings) runCurrent() assertThat(currentSceneKey).isEqualTo(Scenes.QuickSettings) sceneInteractor.changeScene(Scenes.Bouncer, "switching to bouncer for test") transitionState.value = ObservableTransitionState.Idle(Scenes.Bouncer) runCurrent() assertThat(currentSceneKey).isEqualTo(Scenes.Bouncer) kosmos.fakeDeviceEntryFingerprintAuthRepository.setAuthenticationStatus( SuccessFingerprintAuthenticationStatus(0, true) ) assertThat(currentSceneKey).isEqualTo(Scenes.QuickSettings) } @Test fun switchFromLockscreenToGoneWhenDeviceUnlocksWithBypassOn() = testScope.runTest { Loading
packages/SystemUI/src/com/android/systemui/bouncer/domain/interactor/BouncerInteractor.kt +8 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.systemui.bouncer.domain.interactor import com.android.compose.animation.scene.SceneKey import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor import com.android.systemui.authentication.domain.interactor.AuthenticationResult import com.android.systemui.authentication.shared.model.AuthenticationMethodModel.Sim Loading @@ -26,6 +27,8 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.model.Scenes import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.async Loading @@ -47,6 +50,7 @@ constructor( private val deviceEntryFaceAuthInteractor: DeviceEntryFaceAuthInteractor, private val falsingInteractor: FalsingInteractor, private val powerInteractor: PowerInteractor, sceneInteractor: SceneInteractor, ) { private val _onIncorrectBouncerInput = MutableSharedFlow<Unit>() val onIncorrectBouncerInput: SharedFlow<Unit> = _onIncorrectBouncerInput Loading Loading @@ -80,6 +84,10 @@ constructor( } .map {} /** The scene to show when bouncer is dismissed. */ val dismissDestination: Flow<SceneKey> = sceneInteractor.previousScene.map { it ?: Scenes.Lockscreen } /** Notifies that the user has places down a pointer, not necessarily dragging just yet. */ fun onDown() { falsingInteractor.avoidGesture() Loading
packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt +26 −6 Original line number Diff line number Diff line Loading @@ -21,6 +21,12 @@ import android.app.admin.DevicePolicyResources import android.content.Context import android.graphics.Bitmap import androidx.core.graphics.drawable.toBitmap import com.android.compose.animation.scene.Back import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.Swipe import com.android.compose.animation.scene.SwipeDirection import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult import com.android.systemui.authentication.domain.interactor.AuthenticationInteractor import com.android.systemui.authentication.shared.model.AuthenticationMethodModel import com.android.systemui.authentication.shared.model.AuthenticationWipeModel Loading @@ -35,6 +41,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.inputmethod.domain.interactor.InputMethodInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.systemui.user.ui.viewmodel.UserActionViewModel import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel Loading Loading @@ -82,6 +89,15 @@ class BouncerViewModel( initialValue = null, ) val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> = bouncerInteractor.dismissDestination .map(::destinationSceneMap) .stateIn( applicationScope, SharingStarted.WhileSubscribed(), initialValue = destinationSceneMap(Scenes.Lockscreen), ) val message: BouncerMessageViewModel = bouncerMessageViewModel val userSwitcherDropdown: StateFlow<List<UserSwitcherDropdownItemViewModel>> = Loading Loading @@ -310,8 +326,7 @@ class BouncerViewModel( { message }, failedAttempts, remainingAttempts, ) ?: message ) ?: message } else { message } Loading @@ -328,8 +343,7 @@ class BouncerViewModel( .KEYGUARD_DIALOG_FAILED_ATTEMPTS_ERASING_PROFILE, { message }, failedAttempts, ) ?: message ) ?: message } else { message } Loading Loading @@ -357,6 +371,12 @@ class BouncerViewModel( } } private fun destinationSceneMap(prevScene: SceneKey) = mapOf( Back to UserActionResult(prevScene), Swipe(SwipeDirection.Down) to UserActionResult(prevScene), ) data class DialogViewModel( val text: String, Loading Loading @@ -400,13 +420,13 @@ object BouncerViewModelModule { simBouncerInteractor = simBouncerInteractor, authenticationInteractor = authenticationInteractor, selectedUserInteractor = selectedUserInteractor, devicePolicyManager = devicePolicyManager, bouncerMessageViewModel = bouncerMessageViewModel, flags = flags, selectedUser = userSwitcherViewModel.selectedUser, users = userSwitcherViewModel.users, userSwitcherMenu = userSwitcherViewModel.menu, actionButton = actionButtonInteractor.actionButton, devicePolicyManager = devicePolicyManager, bouncerMessageViewModel = bouncerMessageViewModel, ) } }