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

Commit ac779d45 authored by Ale Nijamkin's avatar Ale Nijamkin Committed by Android (Google) Code Review
Browse files

Merge changes I53ea810d,If9e66ed6,Ieb4a85bb,I3ad46557 into main

* changes:
  [flexiglass] Changes to the bouncer scene when becomes non-interactive.
  [flexiglass] Prevent swipe nav from LS when shade is not touchable.
  [flexiglass] Stops change to Shade scene when AOD starts.
  [flexiglass] Fixes back navigation.
parents b829674a 96cb7e01
Loading
Loading
Loading
Loading
+10 −9
Original line number Diff line number Diff line
@@ -204,15 +204,16 @@ internal class SceneTransitionLayoutImpl(
                    }

                // Handle back events.
                // TODO(b/290184746): Make sure that this works with SystemUI once we use
                // SceneTransitionLayout in Flexiglass.
                scene(state.transitionState.currentScene).userActions[Back]?.let { result ->
                val targetSceneForBackOrNull =
                    scene(state.transitionState.currentScene).userActions[Back]?.toScene
                BackHandler(
                    enabled = targetSceneForBackOrNull != null,
                ) {
                    targetSceneForBackOrNull?.let { targetSceneForBack ->
                        // TODO(b/290184746): Handle predictive back and use result.distance if
                        // specified.
                    BackHandler {
                        val targetScene = result.toScene
                        if (state.canChangeScene(targetScene)) {
                            with(state) { coroutineScope.onChangeScene(targetScene) }
                        if (state.canChangeScene(targetSceneForBack)) {
                            with(state) { coroutineScope.onChangeScene(targetSceneForBack) }
                        }
                    }
                }
+75 −14
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@ 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.kosmos.testScope
import com.android.systemui.power.data.repository.fakePowerRepository
import com.android.systemui.power.shared.model.WakefulnessState
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.data.repository.shadeRepository
@@ -43,6 +45,7 @@ import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificati
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import kotlin.math.pow
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.junit.BeforeClass
@@ -57,14 +60,16 @@ import platform.test.runner.parameterized.Parameters
class LockscreenSceneViewModelTest : SysuiTestCase() {

    companion object {
        private const val parameterCount = 6

        @Parameters(
            name =
                "canSwipeToEnter={0}, downWithTwoPointers={1}, downFromEdge={2}," +
                    " isSingleShade={3}, isCommunalAvailable={4}"
                    " isSingleShade={3}, isCommunalAvailable={4}, isShadeTouchable={5}"
        )
        @JvmStatic
        fun combinations() = buildList {
            repeat(32) { combination ->
            repeat(2f.pow(parameterCount).toInt()) { combination ->
                add(
                    arrayOf(
                            /* canSwipeToEnter= */ combination and 1 != 0,
@@ -72,7 +77,9 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
                            /* downFromEdge= */ combination and 4 != 0,
                            /* isSingleShade= */ combination and 8 != 0,
                            /* isCommunalAvailable= */ combination and 16 != 0,
                            /* isShadeTouchable= */ combination and 32 != 0,
                        )
                        .also { check(it.size == parameterCount) }
                )
            }
        }
@@ -82,8 +89,15 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
        fun setUp() {
            val combinationStrings =
                combinations().map { array ->
                    check(array.size == 5)
                    "${array[4]},${array[3]},${array[2]},${array[1]},${array[0]}"
                    check(array.size == parameterCount)
                    buildString {
                        ((parameterCount - 1) downTo 0).forEach { index ->
                            append("${array[index]}")
                            if (index > 0) {
                                append(",")
                            }
                        }
                    }
                }
            val uniqueCombinations = combinationStrings.toSet()
            assertThat(combinationStrings).hasSize(uniqueCombinations.size)
@@ -92,8 +106,35 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
        private fun expectedDownDestination(
            downFromEdge: Boolean,
            isSingleShade: Boolean,
        ): SceneKey {
            return if (downFromEdge && isSingleShade) Scenes.QuickSettings else Scenes.Shade
            isShadeTouchable: Boolean,
        ): SceneKey? {
            return when {
                !isShadeTouchable -> null
                downFromEdge && isSingleShade -> Scenes.QuickSettings
                else -> Scenes.Shade
            }
        }

        private fun expectedUpDestination(
            canSwipeToEnter: Boolean,
            isShadeTouchable: Boolean,
        ): SceneKey? {
            return when {
                !isShadeTouchable -> null
                canSwipeToEnter -> Scenes.Gone
                else -> Scenes.Bouncer
            }
        }

        private fun expectedLeftDestination(
            isCommunalAvailable: Boolean,
            isShadeTouchable: Boolean,
        ): SceneKey? {
            return when {
                !isShadeTouchable -> null
                isCommunalAvailable -> Scenes.Communal
                else -> null
            }
        }
    }

@@ -106,6 +147,7 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
    @JvmField @Parameter(2) var downFromEdge: Boolean = false
    @JvmField @Parameter(3) var isSingleShade: Boolean = true
    @JvmField @Parameter(4) var isCommunalAvailable: Boolean = false
    @JvmField @Parameter(5) var isShadeTouchable: Boolean = false

    private val underTest by lazy { createLockscreenSceneViewModel() }

@@ -130,6 +172,14 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
                }
            )
            kosmos.setCommunalAvailable(isCommunalAvailable)
            kosmos.fakePowerRepository.updateWakefulness(
                rawState =
                    if (isShadeTouchable) {
                        WakefulnessState.AWAKE
                    } else {
                        WakefulnessState.ASLEEP
                    },
            )

            val destinationScenes by collectLastValue(underTest.destinationScenes)

@@ -148,14 +198,25 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
                    expectedDownDestination(
                        downFromEdge = downFromEdge,
                        isSingleShade = isSingleShade,
                        isShadeTouchable = isShadeTouchable,
                    )
                )

            assertThat(destinationScenes?.get(Swipe(SwipeDirection.Up))?.toScene)
                .isEqualTo(if (canSwipeToEnter) Scenes.Gone else Scenes.Bouncer)
                .isEqualTo(
                    expectedUpDestination(
                        canSwipeToEnter = canSwipeToEnter,
                        isShadeTouchable = isShadeTouchable,
                    )
                )

            assertThat(destinationScenes?.get(Swipe(SwipeDirection.Left))?.toScene)
                .isEqualTo(Scenes.Communal.takeIf { isCommunalAvailable })
                .isEqualTo(
                    expectedLeftDestination(
                        isCommunalAvailable = isCommunalAvailable,
                        isShadeTouchable = isShadeTouchable,
                    )
                )
        }

    private fun createLockscreenSceneViewModel(): LockscreenSceneViewModel {
+1 −0
Original line number Diff line number Diff line
@@ -293,6 +293,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
                occlusionInteractor = kosmos.sceneContainerOcclusionInteractor,
                faceUnlockInteractor = kosmos.deviceEntryFaceAuthInteractor,
                deviceUnlockedInteractor = kosmos.deviceUnlockedInteractor,
                shadeInteractor = kosmos.shadeInteractor,
            )
        startable.start()

+33 −0
Original line number Diff line number Diff line
@@ -48,14 +48,17 @@ import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
import com.android.systemui.kosmos.testScope
import com.android.systemui.model.sysUiState
import com.android.systemui.power.data.repository.fakePowerRepository
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest
import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest
import com.android.systemui.power.domain.interactor.PowerInteractorFactory
import com.android.systemui.power.shared.model.WakefulnessState
import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
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.shade.domain.interactor.shadeInteractor
import com.android.systemui.shared.system.QuickStepContract
import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor
@@ -140,6 +143,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
                occlusionInteractor = kosmos.sceneContainerOcclusionInteractor,
                faceUnlockInteractor = kosmos.deviceEntryFaceAuthInteractor,
                deviceUnlockedInteractor = kosmos.deviceUnlockedInteractor,
                shadeInteractor = kosmos.shadeInteractor,
            )
    }

@@ -1127,6 +1131,33 @@ class SceneContainerStartableTest : SysuiTestCase() {
            assertThat(kosmos.fakeDeviceEntryFaceAuthRepository.isAuthRunning.value).isTrue()
        }

    @Test
    fun switchToLockscreen_whenShadeBecomesNotTouchable() =
        testScope.runTest {
            val currentScene by collectLastValue(sceneInteractor.currentScene)
            val isShadeTouchable by collectLastValue(kosmos.shadeInteractor.isShadeTouchable)
            val transitionStateFlow = prepareState()
            underTest.start()
            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
            // Flung to bouncer, 90% of the way there:
            transitionStateFlow.value =
                ObservableTransitionState.Transition(
                    fromScene = Scenes.Lockscreen,
                    toScene = Scenes.Bouncer,
                    progress = flowOf(0.9f),
                    isInitiatedByUserInput = true,
                    isUserInputOngoing = flowOf(false),
                )
            runCurrent()
            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)

            kosmos.fakePowerRepository.updateWakefulness(WakefulnessState.ASLEEP)
            runCurrent()
            assertThat(isShadeTouchable).isFalse()

            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
        }

    private fun TestScope.emulateSceneTransition(
        transitionStateFlow: MutableStateFlow<ObservableTransitionState>,
        toScene: SceneKey,
@@ -1166,6 +1197,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
        isLockscreenEnabled: Boolean = true,
        startsAwake: Boolean = true,
        isDeviceProvisioned: Boolean = true,
        isInteractive: Boolean = true,
    ): MutableStateFlow<ObservableTransitionState> {
        if (authenticationMethod?.isSecure == true) {
            assert(isLockscreenEnabled) {
@@ -1205,6 +1237,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
        } else {
            powerInteractor.setAsleepForTest()
        }
        kosmos.fakePowerRepository.setInteractive(isInteractive)

        kosmos.fakeDeviceProvisioningRepository.setDeviceProvisioned(isDeviceProvisioned)

+19 −10
Original line number Diff line number Diff line
@@ -37,6 +37,8 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.stateIn

/** Models UI state and handles user input for the lockscreen scene. */
@@ -52,6 +54,11 @@ constructor(
    val notifications: NotificationsPlaceholderViewModel,
) {
    val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> =
        shadeInteractor.isShadeTouchable
            .flatMapLatest { isShadeTouchable ->
                if (!isShadeTouchable) {
                    flowOf(emptyMap())
                } else {
                    combine(
                        deviceEntryInteractor.isUnlocked,
                        communalInteractor.isCommunalAvailable,
@@ -63,6 +70,8 @@ constructor(
                            shadeMode = shadeMode,
                        )
                    }
                }
            }
            .stateIn(
                scope = applicationScope,
                started = SharingStarted.WhileSubscribed(),
Loading