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

Commit 242261a5 authored by Alejandro Nijamkin's avatar Alejandro Nijamkin
Browse files

[flexiglass] Prevent swipe nav from LS when shade is not touchable.

There are two fixes here:
1. Takes the power state into account when calculating the outgoing
   desitnation scenes from the LockscreenScene (this CL)
2. Automatically switch to the Lockscreen scene when the device becomes
   non-interactive (next CL)

Bug: 330474509
Test: TDD - tests written first, then code change made until tests
passed
Test: manually verified that swiping up on the lockscreen scene in AOD
doesn't go to bouncer
Test: however, it's still possible to swipe up on the lockscreen scene
to go to the bouncer while AOD is transitioning on. The next CL will
address that
Flag: ACONFIG com.android.systemui.scene_container DEVELOPMENT

Change-Id: If9e66ed62eaaa066a2c61e12fed384644700fffb
parent 01ba9175
Loading
Loading
Loading
Loading
+75 −14
Original line number Original line 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.data.repository.fakeDeviceEntryRepository
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
import com.android.systemui.kosmos.testScope
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.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.data.repository.shadeRepository
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.testKosmos
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertThat
import kotlin.math.pow
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.runTest
import org.junit.BeforeClass
import org.junit.BeforeClass
@@ -57,14 +60,16 @@ import platform.test.runner.parameterized.Parameters
class LockscreenSceneViewModelTest : SysuiTestCase() {
class LockscreenSceneViewModelTest : SysuiTestCase() {


    companion object {
    companion object {
        private const val parameterCount = 6

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


    private val underTest by lazy { createLockscreenSceneViewModel() }
    private val underTest by lazy { createLockscreenSceneViewModel() }


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


            val destinationScenes by collectLastValue(underTest.destinationScenes)
            val destinationScenes by collectLastValue(underTest.destinationScenes)


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


            assertThat(destinationScenes?.get(Swipe(SwipeDirection.Up))?.toScene)
            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)
            assertThat(destinationScenes?.get(Swipe(SwipeDirection.Left))?.toScene)
                .isEqualTo(Scenes.Communal.takeIf { isCommunalAvailable })
                .isEqualTo(
                    expectedLeftDestination(
                        isCommunalAvailable = isCommunalAvailable,
                        isShadeTouchable = isShadeTouchable,
                    )
                )
        }
        }


    private fun createLockscreenSceneViewModel(): LockscreenSceneViewModel {
    private fun createLockscreenSceneViewModel(): LockscreenSceneViewModel {
+19 −10
Original line number Original line Diff line number Diff line
@@ -37,6 +37,8 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.stateIn


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