Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b8fbc229 authored by Alejandro Nijamkin's avatar Alejandro Nijamkin
Browse files

[flexiglass] BouncerViewModel is now SysUiViewModel

Also converts the following child view-models:
- BouncerMessageViewModel
- PinBoncerViewModel
- PatternBouncerViewModel
- PasswordBouncerViewModel

For more info, please see go/sysui-arch:summer-24

Bug: 354270224
Flag: com.android.systemui.scene_container
Test: all existing unit tests currently working
Test: manually verified each authentication method including correct
auth, wrong auth, timeout, and correct auth after wrong auth and after
timeour

Change-Id: Id0cdf01bcdd2a17a1ff92f416c8f489a9876dcd4
parent c1b875b5
Loading
Loading
Loading
Loading
+14 −14
Original line number Diff line number Diff line
@@ -95,7 +95,7 @@ import com.android.systemui.bouncer.ui.BouncerDialogFactory
import com.android.systemui.bouncer.ui.helper.BouncerSceneLayout
import com.android.systemui.bouncer.ui.viewmodel.AuthMethodBouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.BouncerMessageViewModel
import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.BouncerSceneContentViewModel
import com.android.systemui.bouncer.ui.viewmodel.MessageViewModel
import com.android.systemui.bouncer.ui.viewmodel.PasswordBouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.PatternBouncerViewModel
@@ -114,7 +114,7 @@ import platform.test.motion.compose.values.motionTestValues

@Composable
fun BouncerContent(
    viewModel: BouncerViewModel,
    viewModel: BouncerSceneContentViewModel,
    dialogFactory: BouncerDialogFactory,
    modifier: Modifier = Modifier,
) {
@@ -128,7 +128,7 @@ fun BouncerContent(
@VisibleForTesting
fun BouncerContent(
    layout: BouncerSceneLayout,
    viewModel: BouncerViewModel,
    viewModel: BouncerSceneContentViewModel,
    dialogFactory: BouncerDialogFactory,
    modifier: Modifier
) {
@@ -173,7 +173,7 @@ fun BouncerContent(
 */
@Composable
private fun StandardLayout(
    viewModel: BouncerViewModel,
    viewModel: BouncerSceneContentViewModel,
    modifier: Modifier = Modifier,
) {
    val isHeightExpanded =
@@ -235,7 +235,7 @@ private fun StandardLayout(
 */
@Composable
private fun SplitLayout(
    viewModel: BouncerViewModel,
    viewModel: BouncerSceneContentViewModel,
    modifier: Modifier = Modifier,
) {
    val authMethod by viewModel.authMethodViewModel.collectAsStateWithLifecycle()
@@ -326,7 +326,7 @@ private fun SplitLayout(
 */
@Composable
private fun BesideUserSwitcherLayout(
    viewModel: BouncerViewModel,
    viewModel: BouncerSceneContentViewModel,
    modifier: Modifier = Modifier,
) {
    val layoutDirection = LocalLayoutDirection.current
@@ -461,7 +461,7 @@ private fun BesideUserSwitcherLayout(
/** Arranges the bouncer contents and user switcher contents one on top of the other, vertically. */
@Composable
private fun BelowUserSwitcherLayout(
    viewModel: BouncerViewModel,
    viewModel: BouncerSceneContentViewModel,
    modifier: Modifier = Modifier,
) {
    Column(
@@ -506,7 +506,7 @@ private fun BelowUserSwitcherLayout(

@Composable
private fun FoldAware(
    viewModel: BouncerViewModel,
    viewModel: BouncerSceneContentViewModel,
    aboveFold: @Composable BoxScope.() -> Unit,
    belowFold: @Composable BoxScope.() -> Unit,
    modifier: Modifier = Modifier,
@@ -649,7 +649,7 @@ private fun StatusMessage(
 */
@Composable
private fun OutputArea(
    viewModel: BouncerViewModel,
    viewModel: BouncerSceneContentViewModel,
    modifier: Modifier = Modifier,
) {
    val authMethodViewModel: AuthMethodBouncerViewModel? by
@@ -677,7 +677,7 @@ private fun OutputArea(
 */
@Composable
private fun InputArea(
    viewModel: BouncerViewModel,
    viewModel: BouncerSceneContentViewModel,
    pinButtonRowVerticalSpacing: Dp,
    centerPatternDotsVertically: Boolean,
    modifier: Modifier = Modifier,
@@ -706,7 +706,7 @@ private fun InputArea(

@Composable
private fun ActionArea(
    viewModel: BouncerViewModel,
    viewModel: BouncerSceneContentViewModel,
    modifier: Modifier = Modifier,
) {
    val actionButton: BouncerActionButtonModel? by
@@ -774,7 +774,7 @@ private fun ActionArea(

@Composable
private fun Dialog(
    bouncerViewModel: BouncerViewModel,
    bouncerViewModel: BouncerSceneContentViewModel,
    dialogFactory: BouncerDialogFactory,
) {
    val dialogViewModel by bouncerViewModel.dialogViewModel.collectAsStateWithLifecycle()
@@ -803,7 +803,7 @@ private fun Dialog(
/** Renders the UI of the user switcher that's displayed on large screens next to the bouncer UI. */
@Composable
private fun UserSwitcher(
    viewModel: BouncerViewModel,
    viewModel: BouncerSceneContentViewModel,
    modifier: Modifier = Modifier,
) {
    if (!viewModel.isUserSwitcherVisible) {
@@ -884,7 +884,7 @@ private fun UserSwitcher(
@Composable
private fun UserSwitcherDropdownMenu(
    isExpanded: Boolean,
    items: List<BouncerViewModel.UserSwitcherDropdownItemViewModel>,
    items: List<BouncerSceneContentViewModel.UserSwitcherDropdownItemViewModel>,
    onDismissed: () -> Unit,
) {
    val context = LocalContext.current
+21 −5
Original line number Diff line number Diff line
@@ -27,9 +27,11 @@ import com.android.compose.animation.scene.SceneScope
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.systemui.bouncer.ui.BouncerDialogFactory
import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
import com.android.systemui.bouncer.ui.viewmodel.BouncerSceneActionsViewModel
import com.android.systemui.bouncer.ui.viewmodel.BouncerSceneContentViewModel
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.lifecycle.rememberViewModel
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.ui.composable.ComposableScene
import javax.inject.Inject
@@ -51,23 +53,37 @@ object Bouncer {
class BouncerScene
@Inject
constructor(
    private val viewModel: BouncerViewModel,
    private val actionsViewModelFactory: BouncerSceneActionsViewModel.Factory,
    private val contentViewModelFactory: BouncerSceneContentViewModel.Factory,
    private val dialogFactory: BouncerDialogFactory,
) : ComposableScene {
    override val key = Scenes.Bouncer

    private val actionsViewModel: BouncerSceneActionsViewModel by lazy {
        actionsViewModelFactory.create()
    }

    override val destinationScenes: Flow<Map<UserAction, UserActionResult>> =
        viewModel.destinationScenes
        actionsViewModel.actions

    override suspend fun activate() {
        actionsViewModel.activate()
    }

    @Composable
    override fun SceneScope.Content(
        modifier: Modifier,
    ) = BouncerScene(viewModel, dialogFactory, modifier)
    ) =
        BouncerScene(
            viewModel = rememberViewModel { contentViewModelFactory.create() },
            dialogFactory = dialogFactory,
            modifier = modifier,
        )
}

@Composable
private fun SceneScope.BouncerScene(
    viewModel: BouncerViewModel,
    viewModel: BouncerSceneContentViewModel,
    dialogFactory: BouncerDialogFactory,
    modifier: Modifier = Modifier,
) {
+9 −10
Original line number Diff line number Diff line
@@ -22,14 +22,14 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.authentication.data.repository.FakeAuthenticationRepository
import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.bouncer.domain.interactor.bouncerInteractor
import com.android.systemui.bouncer.domain.interactor.simBouncerInteractor
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.lifecycle.activateIn
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@@ -39,17 +39,16 @@ class AuthMethodBouncerViewModelTest : SysuiTestCase() {

    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope
    private val bouncerInteractor by lazy { kosmos.bouncerInteractor }
    private val underTest by lazy {
        PinBouncerViewModel(
            applicationContext = context,
            viewModelScope = testScope.backgroundScope,
            interactor = bouncerInteractor,
    private val underTest =
        kosmos.pinBouncerViewModelFactory.create(
            isInputEnabled = MutableStateFlow(true),
            simBouncerInteractor = kosmos.simBouncerInteractor,
            authenticationMethod = AuthenticationMethodModel.Pin,
            onIntentionalUserInput = {},
            authenticationMethod = AuthenticationMethodModel.Pin,
        )

    @Before
    fun setUp() {
        underTest.activateIn(testScope)
    }

    @Test
+2 −0
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ import com.android.systemui.keyguard.shared.model.ErrorFingerprintAuthentication
import com.android.systemui.keyguard.shared.model.FailFingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.HelpFingerprintAuthenticationStatus
import com.android.systemui.kosmos.testScope
import com.android.systemui.lifecycle.activateIn
import com.android.systemui.res.R
import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.fakeUserRepository
@@ -87,6 +88,7 @@ class BouncerMessageViewModelTest : SysuiTestCase() {
            intArrayOf(ignoreHelpMessageId)
        )
        underTest = kosmos.bouncerMessageViewModel
        underTest.activateIn(testScope)
        overrideResource(R.string.kg_trust_agent_disabled, "Trust agent is unavailable")
        kosmos.fakeSystemPropertiesHelper.set(
            DeviceUnlockedInteractor.SYS_BOOT_REASON_PROP,
+77 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

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.coroutines.collectLastValue
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.kosmos.testScope
import com.android.systemui.lifecycle.activateIn
import com.android.systemui.scene.domain.startable.sceneContainerStartable
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 kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(AndroidJUnit4::class)
@EnableSceneContainer
class BouncerSceneActionsViewModelTest : SysuiTestCase() {

    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope

    private lateinit var underTest: BouncerSceneActionsViewModel

    @Before
    fun setUp() {
        kosmos.sceneContainerStartable.start()
        underTest = kosmos.bouncerSceneActionsViewModel
        underTest.activateIn(testScope)
    }

    @Test
    fun actions() =
        testScope.runTest {
            val actions by collectLastValue(underTest.actions)
            kosmos.fakeSceneDataSource.changeScene(Scenes.QuickSettings)
            runCurrent()

            kosmos.fakeSceneDataSource.changeScene(Scenes.Bouncer)
            runCurrent()

            assertThat(actions)
                .containsEntriesExactly(
                    Back to UserActionResult(Scenes.QuickSettings),
                    Swipe(SwipeDirection.Down) to UserActionResult(Scenes.QuickSettings),
                )
        }
}
Loading