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

Commit 3430be78 authored by helen cheuk's avatar helen cheuk
Browse files

[Action Corner] Not subscribe to cursor position when no action is

configured for corners

It is to avoid adding any input monitor when users are not using action
corner (i.e. all actions are None)

Bug: 426536832
Test: ActionCornerSettingRepositoryTest
Test: ActionCornerRepositoryTest
Flag: com.android.systemui.shared.cursor_hot_corner
Change-Id: I3f995d40c3d5c5e5e49362fa9b7d4caea73f4e38
parent c746b257
Loading
Loading
Loading
Loading
+130 −125
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
package com.android.systemui.actioncorner.data.repository

import android.graphics.Rect
import android.provider.Settings.Secure.ACTION_CORNER_ACTION_HOME
import android.provider.Settings.Secure.ACTION_CORNER_TOP_LEFT_ACTION
import android.view.Display.DEFAULT_DISPLAY
import android.view.WindowInsets
import android.view.WindowManager
@@ -41,8 +43,11 @@ import com.android.systemui.kosmos.backgroundScope
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.collectValues
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.testKosmos
import com.android.systemui.util.settings.data.repository.userAwareSecureSettingsRepository
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
import kotlin.time.Duration.Companion.milliseconds
@@ -63,11 +68,18 @@ class ActionCornerRepositoryTest : SysuiTestCase() {
    @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
    private val Kosmos.fakePointerRepository by Fixture { FakePointerDeviceRepository() }
    private val settingsRepository = kosmos.userAwareSecureSettingsRepository

    private val Kosmos.underTest by Fixture {
        ActionCornerRepositoryImpl(
            cursorPositionRepository,
            kosmos.fakeDisplayWindowPropertiesRepository,
            kosmos.fakePointerRepository,
            ActionCornerSettingRepository(
                settingsRepository,
                testScope.backgroundScope,
                testDispatcher,
            ),
            kosmos.backgroundScope,
        )
    }
@@ -84,22 +96,17 @@ class ActionCornerRepositoryTest : SysuiTestCase() {
    }

    @Test
    fun topLeftCursor_topLeftActionCornerEmitted() =
        kosmos.runTest {
    fun topLeftCursor_topLeftActionCornerEmitted() = setUpAndRunTest {
        val model by collectLastValue(underTest.actionCornerState)
        addCursorPosition(display.topLeftCursorPos)
        assertThat(model)
            .isEqualTo(
                    ActiveActionCorner(
                        ActionCornerRegion.TOP_LEFT,
                        display.topLeftCursorPos.displayId,
                    )
                ActiveActionCorner(ActionCornerRegion.TOP_LEFT, display.topLeftCursorPos.displayId)
            )
    }

    @Test
    fun outOfBoundTopLeftCursor_noActionCornerEmitted() =
        kosmos.runTest {
    fun outOfBoundTopLeftCursor_noActionCornerEmitted() = setUpAndRunTest {
        val model by collectLastValue(underTest.actionCornerState)
        val actionCornerPos = display.topLeftCursorPos
        // Update x and y to make it just out of bound of action corner
@@ -114,20 +121,16 @@ class ActionCornerRepositoryTest : SysuiTestCase() {
    }

    @Test
    fun topRightCursor_topRightActionCornerEmitted() =
        kosmos.runTest {
    fun topRightCursor_topRightActionCornerEmitted() = setUpAndRunTest {
        val model by collectLastValue(underTest.actionCornerState)
        val actionCornerPos = display.topRightCursorPos
        addCursorPosition(actionCornerPos)
        assertThat(model)
                .isEqualTo(
                    ActiveActionCorner(ActionCornerRegion.TOP_RIGHT, actionCornerPos.displayId)
                )
            .isEqualTo(ActiveActionCorner(ActionCornerRegion.TOP_RIGHT, actionCornerPos.displayId))
    }

    @Test
    fun outOfBoundTopRightCursor_noActionCornerEmitted() =
        kosmos.runTest {
    fun outOfBoundTopRightCursor_noActionCornerEmitted() = setUpAndRunTest {
        val model by collectLastValue(underTest.actionCornerState)
        val actionCornerPos = display.topRightCursorPos
        addCursorPosition(
@@ -141,8 +144,7 @@ class ActionCornerRepositoryTest : SysuiTestCase() {
    }

    @Test
    fun bottomLeftCursor_bottomLeftActionCornerEmitted() =
        kosmos.runTest {
    fun bottomLeftCursor_bottomLeftActionCornerEmitted() = setUpAndRunTest {
        val model by collectLastValue(underTest.actionCornerState)
        val actionCornerPos = display.bottomLeftCursorPos
        addCursorPosition(actionCornerPos)
@@ -153,8 +155,7 @@ class ActionCornerRepositoryTest : SysuiTestCase() {
    }

    @Test
    fun outOfBoundBottomLeftCursor_noActionCornerEmitted() =
        kosmos.runTest {
    fun outOfBoundBottomLeftCursor_noActionCornerEmitted() = setUpAndRunTest {
        val model by collectLastValue(underTest.actionCornerState)
        val actionCornerPos = display.bottomLeftCursorPos
        addCursorPosition(
@@ -168,8 +169,7 @@ class ActionCornerRepositoryTest : SysuiTestCase() {
    }

    @Test
    fun bottomRightCursor_bottomRightActionCornerEmitted() =
        kosmos.runTest {
    fun bottomRightCursor_bottomRightActionCornerEmitted() = setUpAndRunTest {
        val model by collectLastValue(underTest.actionCornerState)
        val actionCornerPos = display.bottomRightCursorPos
        addCursorPosition(actionCornerPos)
@@ -180,8 +180,7 @@ class ActionCornerRepositoryTest : SysuiTestCase() {
    }

    @Test
    fun outOfBoundBottomRightCursor_noActionCornerEmitted() =
        kosmos.runTest {
    fun outOfBoundBottomRightCursor_noActionCornerEmitted() = setUpAndRunTest {
        val model by collectLastValue(underTest.actionCornerState)
        val actionCornerPos = display.bottomRightCursorPos
        addCursorPosition(
@@ -196,12 +195,10 @@ class ActionCornerRepositoryTest : SysuiTestCase() {

    @Test
    fun actionCornerCursor_moveOutOfBound_reEnterActionCorner_secondActiveActionCornerEmitted() =
        kosmos.runTest {
        setUpAndRunTest {
            // Filter out InactiveActionCorner for test readability
            val models by
                kosmos.collectValues(
                    underTest.actionCornerState.filter { it != InactiveActionCorner }
                )
                collectValues(underTest.actionCornerState.filter { it != InactiveActionCorner })
            val actionCornerPos = display.bottomRightCursorPos
            addCursorPosition(actionCornerPos)
            addCursorPosition(CursorPosition(x = 1000f, y = 1000f, actionCornerPos.displayId))
@@ -213,33 +210,23 @@ class ActionCornerRepositoryTest : SysuiTestCase() {
        }

    @Test
    fun actionCornerCursor_moveInsideSameCorner_OneActionCornerEmitted() =
        kosmos.runTest {
            val models by kosmos.collectValues(underTest.actionCornerState.drop(1))
    fun actionCornerCursor_moveInsideSameCorner_OneActionCornerEmitted() = setUpAndRunTest {
        val models by collectValues(underTest.actionCornerState.drop(1))
        val actionCornerPos = display.bottomRightCursorPos
        addCursorPosition(actionCornerPos)
        // Move within the same corner
        addCursorPosition(
                CursorPosition(
                    actionCornerPos.x + 1,
                    actionCornerPos.y + 1,
                    actionCornerPos.displayId,
                )
            CursorPosition(actionCornerPos.x + 1, actionCornerPos.y + 1, actionCornerPos.displayId)
        )
        addCursorPosition(
                CursorPosition(
                    actionCornerPos.x + 2,
                    actionCornerPos.y + 2,
                    actionCornerPos.displayId,
                )
            CursorPosition(actionCornerPos.x + 2, actionCornerPos.y + 2, actionCornerPos.displayId)
        )

        assertThat(models.size).isEqualTo(1)
    }

    @Test
    fun activeActionCorner_pointerDeviceDisconnected_inactiveActionCorner() =
        kosmos.runTest {
    fun activeActionCorner_pointerDeviceDisconnected_inactiveActionCorner() = setUpAndRunTest {
        val model by collectLastValue(underTest.actionCornerState)

        val actionCornerPos = display.bottomRightCursorPos
@@ -252,7 +239,7 @@ class ActionCornerRepositoryTest : SysuiTestCase() {

    @Test
    fun actionCornerState_remainsInactive_whenCursorMovesIntoActiveArea_butDebounceNotMet() =
        kosmos.runTest {
        setUpAndRunTest {
            val model by collectLastValue(underTest.actionCornerState)

            val actionCornerPos = display.bottomRightCursorPos
@@ -262,11 +249,29 @@ class ActionCornerRepositoryTest : SysuiTestCase() {
            assertThat(model).isEqualTo(InactiveActionCorner)
        }

    @Test
    fun noActionConfigured_cursorMovesIntoActiveArea_remainInactiveActionCorner() =
        kosmos.runTest {
            // No action configured to corners by default
            val model by collectLastValue(underTest.actionCornerState)

            val actionCornerPos = display.bottomRightCursorPos
            addCursorPosition(actionCornerPos)

            assertThat(model).isEqualTo(InactiveActionCorner)
        }

    private fun Kosmos.addCursorPosition(cursorPosition: CursorPosition) {
        cursorPositionRepository.addCursorPosition(cursorPosition)
        advanceTimeBy(DEBOUNCE_DELAY + 1.milliseconds)
    }

    private fun setUpAndRunTest(testBody: suspend Kosmos.() -> Unit) =
        kosmos.runTest {
            settingsRepository.setInt(ACTION_CORNER_TOP_LEFT_ACTION, ACTION_CORNER_ACTION_HOME)
            testBody()
        }

    private fun createDisplayWindowProperties() =
        DisplayWindowProperties(
            DEFAULT_DISPLAY,
+10 −5
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
@@ -60,17 +61,21 @@ constructor(
    cursorRepository: MultiDisplayCursorPositionRepository,
    private val displayWindowPropertiesRepository: DisplayWindowPropertiesRepository,
    pointerDeviceRepository: PointerDeviceRepository,
    actionCornerSettingRepository: ActionCornerSettingRepository,
    @Background private val backgroundScope: CoroutineScope,
) : ActionCornerRepository {

    override val actionCornerState: StateFlow<ActionCornerState> =
        pointerDeviceRepository.isAnyPointerDeviceConnected
            .flatMapLatest { isConnected ->
                if (isConnected) {
        combine(
                pointerDeviceRepository.isAnyPointerDeviceConnected,
                actionCornerSettingRepository.isAnyActionConfigured,
            ) { isConnected, isAnyActionConfigured ->
                isConnected && isAnyActionConfigured
            }
            .flatMapLatest { shouldMonitorCursorPosition ->
                if (shouldMonitorCursorPosition) {
                    cursorRepository.cursorPositions.map(::mapToActionCornerState)
                } else {
                    // When not connected, emit an InactiveActionCorner state and then complete this
                    // inner flow.
                    flowOf(InactiveActionCorner)
                }
            }
+14 −0
Original line number Diff line number Diff line
@@ -36,8 +36,11 @@ import com.android.systemui.util.settings.repository.UserAwareSecureSettingsRepo
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
@@ -65,6 +68,17 @@ constructor(
    val bottomRightCornerAction: StateFlow<ActionType> =
        getCornerActionFlow(ACTION_CORNER_BOTTOM_RIGHT_ACTION)

    val isAnyActionConfigured: Flow<Boolean> =
        combine(
                topLeftCornerAction,
                topRightCornerAction,
                bottomLeftCornerAction,
                bottomRightCornerAction,
            ) { topLeft, topRight, bottomLeft, bottomRight ->
                listOf(topLeft, topRight, bottomLeft, bottomRight).any { action -> action != NONE }
            }
            .distinctUntilChanged()

    private fun getCornerActionFlow(settingName: String): StateFlow<ActionType> {
        return settingsRepository
            .intSetting(name = settingName)