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

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

[flexiglass] Factor device provisioning for visibility

As a followup for ag/26072345, we're adding collection of device
provisioning state to the visibility evaluation.

The reason is that it's not enough to just look at whether FRP is
active, the system UI shade shouldn't be visible during the Setup Wizard
flow.

Fix: 322197941
Test: manually verified that sys UI is invisible in the setup wizard
Test: added a unit test for the startable
Test: expanded the integration test for Flexiglass
Flag: ACONFIG com.android.systemui.scene_container DEVELOPMENT
Change-Id: Ie74697253b36d6c64e424229b0628f7796b1b0d0
parent 35588a29
Loading
Loading
Loading
Loading
+8 −4
Original line number Diff line number Diff line
@@ -522,14 +522,18 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
        }

    @Test
    fun factoryResetProtectionActive_isNotVisible() =
    fun deviceProvisioningAndFactoryResetProtection() =
        testScope.runTest {
            val isVisible by collectLastValue(sceneContainerViewModel.isVisible)
            assertThat(isVisible).isTrue()

            kosmos.fakeDeviceProvisioningRepository.setFactoryResetProtectionActive(isActive = true)
            kosmos.fakeDeviceProvisioningRepository.setDeviceProvisioned(false)
            kosmos.fakeDeviceProvisioningRepository.setFactoryResetProtectionActive(true)
            assertThat(isVisible).isFalse()

            kosmos.fakeDeviceProvisioningRepository.setFactoryResetProtectionActive(false)
            assertThat(isVisible).isFalse()

            kosmos.fakeDeviceProvisioningRepository.setDeviceProvisioned(true)
            assertThat(isVisible).isTrue()
        }

    /**
+31 −0
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository
import com.android.systemui.statusbar.policy.data.repository.fakeDeviceProvisioningRepository
import com.android.systemui.statusbar.policy.domain.interactor.deviceProvisioningInteractor
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.mock
@@ -163,6 +164,30 @@ class SceneContainerStartableTest : SysuiTestCase() {
            assertThat(isVisible).isFalse()
        }

    @Test
    fun hydrateVisibility_basedOnDeviceProvisioningAndFactoryResetProtection() =
        testScope.runTest {
            val isVisible by collectLastValue(sceneInteractor.isVisible)
            prepareState(
                isDeviceUnlocked = true,
                initialSceneKey = SceneKey.Lockscreen,
                isDeviceProvisioned = false,
                isFrpActive = true,
            )

            underTest.start()
            assertThat(isVisible).isFalse()

            kosmos.fakeDeviceProvisioningRepository.setFactoryResetProtectionActive(false)
            assertThat(isVisible).isFalse()

            kosmos.fakeDeviceProvisioningRepository.setDeviceProvisioned(true)
            assertThat(isVisible).isTrue()

            kosmos.fakeDeviceProvisioningRepository.setFactoryResetProtectionActive(true)
            assertThat(isVisible).isFalse()
        }

    @Test
    fun startsInLockscreenScene() =
        testScope.runTest {
@@ -745,6 +770,8 @@ class SceneContainerStartableTest : SysuiTestCase() {
        authenticationMethod: AuthenticationMethodModel? = null,
        isLockscreenEnabled: Boolean = true,
        startsAwake: Boolean = true,
        isDeviceProvisioned: Boolean = true,
        isFrpActive: Boolean = false,
    ): MutableStateFlow<ObservableTransitionState> {
        if (authenticationMethod?.isSecure == true) {
            assert(isLockscreenEnabled) {
@@ -781,6 +808,10 @@ class SceneContainerStartableTest : SysuiTestCase() {
        } else {
            powerInteractor.setAsleepForTest()
        }

        kosmos.fakeDeviceProvisioningRepository.setDeviceProvisioned(isDeviceProvisioned)
        kosmos.fakeDeviceProvisioningRepository.setFactoryResetProtectionActive(isFrpActive)

        runCurrent()

        return transitionStateFlow
+12 −5
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.flow.emptyFlow
@@ -115,11 +116,15 @@ constructor(
    private fun hydrateVisibility() {
        applicationScope.launch {
            // TODO(b/296114544): Combine with some global hun state to make it visible!
            deviceProvisioningInteractor.isFactoryResetProtectionActive
                .flatMapLatest { isFrpActive ->
                    if (isFrpActive) {
                        flowOf(false to "Factory Reset Protection is active")
                    } else {
            combine(
                    deviceProvisioningInteractor.isDeviceProvisioned,
                    deviceProvisioningInteractor.isFactoryResetProtectionActive,
                ) { isDeviceProvisioned, isFrpActive ->
                    isDeviceProvisioned && !isFrpActive
                }
                .distinctUntilChanged()
                .flatMapLatest { isAllowedToBeVisible ->
                    if (isAllowedToBeVisible) {
                        sceneInteractor.transitionState
                            .mapNotNull { state ->
                                when (state) {
@@ -140,6 +145,8 @@ constructor(
                                }
                            }
                            .distinctUntilChanged()
                    } else {
                        flowOf(false to "Device not provisioned or Factory Reset Protection active")
                    }
                }
                .collect { (isVisible, loggingReason) ->
+9 −1
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.view.MotionEvent
import com.android.systemui.assist.AssistManager
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.log.LogBuffer
import com.android.systemui.log.dagger.ShadeTouchLog
@@ -34,11 +35,13 @@ import com.android.systemui.statusbar.notification.stack.NotificationStackScroll
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import dagger.Lazy
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

/**
 * Implementation of ShadeController backed by scenes instead of NPVC.
@@ -50,6 +53,7 @@ import kotlinx.coroutines.launch
class ShadeControllerSceneImpl
@Inject
constructor(
    @Main private val mainDispatcher: CoroutineDispatcher,
    @Background private val scope: CoroutineScope,
    private val shadeInteractor: ShadeInteractor,
    private val sceneInteractor: SceneInteractor,
@@ -193,7 +197,11 @@ constructor(
    }

    override fun setVisibilityListener(listener: ShadeVisibilityListener) {
        scope.launch { sceneInteractor.isVisible.collect { listener.expandedVisibleChanged(it) } }
        scope.launch {
            sceneInteractor.isVisible.collect { isVisible ->
                withContext(mainDispatcher) { listener.expandedVisibleChanged(isVisible) }
            }
        }
    }

    @ExperimentalCoroutinesApi
+2 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import com.android.systemui.concurrency.fakeExecutor
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.log.LogBuffer
import com.android.systemui.plugins.statusbar.statusBarStateController
import com.android.systemui.scene.domain.interactor.sceneInteractor
@@ -44,6 +45,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
val Kosmos.shadeControllerSceneImpl by
    Kosmos.Fixture {
        ShadeControllerSceneImpl(
            mainDispatcher = testDispatcher,
            scope = applicationCoroutineScope,
            shadeInteractor = shadeInteractor,
            sceneInteractor = sceneInteractor,
Loading