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

Commit 2bcd0830 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Ensure notification shade keyboard shortcut opens on focused display" into main

parents fa145ff4 9fa42923
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.shade.display.StatusBarTouchShadeDisplayPolicy
import com.android.systemui.statusbar.CommandQueue
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -47,6 +48,7 @@ class SysUIKeyGestureEventInitializerTest : SysuiTestCase() {
    @JvmField @Rule var mockitoRule = MockitoJUnit.rule()
    @Mock private lateinit var inputManager: InputManager
    @Mock private lateinit var commandQueue: CommandQueue
    @Mock private lateinit var shadeDisplayPolicy: StatusBarTouchShadeDisplayPolicy
    @Captor private lateinit var keyGestureEventsCaptor: ArgumentCaptor<List<Int>>
    @Captor
    private lateinit var keyGestureEventHandlerCaptor: ArgumentCaptor<KeyGestureEventHandler>
@@ -55,7 +57,7 @@ class SysUIKeyGestureEventInitializerTest : SysuiTestCase() {

    @Before
    fun setup() {
        underTest = SysUIKeyGestureEventInitializer(inputManager, commandQueue)
        underTest = SysUIKeyGestureEventInitializer(inputManager, commandQueue, shadeDisplayPolicy)
    }

    @Test
@@ -101,6 +103,7 @@ class SysUIKeyGestureEventInitializerTest : SysuiTestCase() {
            /* focusedToken= */ null,
        )

        verify(shadeDisplayPolicy).onNotificationPanelKeyboardShortcut()
        verify(commandQueue).toggleNotificationsPanel()
    }

@@ -118,6 +121,7 @@ class SysUIKeyGestureEventInitializerTest : SysuiTestCase() {
            /* focusedToken= */ null,
        )

        verify(shadeDisplayPolicy).onQSPanelKeyboardShortcut()
        verify(commandQueue).toggleQuickSettingsPanel()
    }

+150 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import com.android.systemui.display.data.repository.display
import com.android.systemui.display.data.repository.displayRepository
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.shade.data.repository.fakeFocusedDisplayRepository
import com.android.systemui.shade.data.repository.statusBarTouchShadeDisplayPolicy
import com.android.systemui.shade.domain.interactor.notificationElement
import com.android.systemui.shade.domain.interactor.qsElement
@@ -48,6 +49,7 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() {
    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
    private val testScope = kosmos.testScope
    private val displayRepository = kosmos.displayRepository
    private val focusedDisplayRepository = kosmos.fakeFocusedDisplayRepository

    private val underTest = kosmos.statusBarTouchShadeDisplayPolicy

@@ -135,6 +137,154 @@ class StatusBarTouchShadeDisplayPolicyTest : SysuiTestCase() {
            assertThat(underTest.consumeExpansionIntent()).isNull()
        }

    @Test
    fun onNotificationPanelKeyboardShortcut_called_updatesDisplayId() =
        testScope.runTest {
            val displayId by collectLastValue(underTest.displayId)

            displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL))
            focusedDisplayRepository.setDisplayId(2)
            underTest.onNotificationPanelKeyboardShortcut()

            assertThat(displayId).isEqualTo(2)
        }

    @Test
    fun onNotificationPanelKeyboardShortcut_notExistentDisplay_displayIdNotUpdated() =
        testScope.runTest {
            val displayIds by collectValues(underTest.displayId)
            assertThat(displayIds).isEqualTo(listOf(Display.DEFAULT_DISPLAY))

            underTest.onNotificationPanelKeyboardShortcut()

            // Never set, as 2 was not a display according to the repository.
            assertThat(displayIds).isEqualTo(listOf(Display.DEFAULT_DISPLAY))
        }

    @Test
    fun onNotificationPanelKeyboardShortcut_afterDisplayRemoved_goesBackToDefaultDisplay() =
        testScope.runTest {
            val displayId by collectLastValue(underTest.displayId)

            displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL))
            focusedDisplayRepository.setDisplayId(2)
            underTest.onNotificationPanelKeyboardShortcut()

            assertThat(displayId).isEqualTo(2)

            displayRepository.removeDisplay(2)

            assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY)
        }

    @Test
    fun onNotificationPanelKeyboardShortcut_called_intentSetToNotifications() =
        testScope.runTest {
            underTest.onNotificationPanelKeyboardShortcut()

            assertThat(underTest.consumeExpansionIntent()).isEqualTo(kosmos.notificationElement)
        }

    @Test
    fun onNotificationPanelKeyboardShortcut_nullAfterConsumed() =
        testScope.runTest {
            underTest.onNotificationPanelKeyboardShortcut()

            assertThat(underTest.consumeExpansionIntent()).isEqualTo(kosmos.notificationElement)
            assertThat(underTest.consumeExpansionIntent()).isNull()
        }

    @Test
    fun onNotificationPanelKeyboardShortcut_afterOnStatusBarOrLauncherTouched_movesShadeToFocusedDisplay() =
        testScope.runTest {
            val displayId by collectLastValue(underTest.displayId)

            displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL))
            displayRepository.addDisplays(display(id = 3, type = TYPE_EXTERNAL))
            underTest.onStatusBarOrLauncherTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH)

            assertThat(displayId).isEqualTo(2)

            focusedDisplayRepository.setDisplayId(3)
            underTest.onNotificationPanelKeyboardShortcut()

            assertThat(displayId).isEqualTo(3)
        }

    @Test
    fun onQSPanelKeyboardShortcut_called_updatesDisplayId() =
        testScope.runTest {
            val displayId by collectLastValue(underTest.displayId)

            displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL))
            focusedDisplayRepository.setDisplayId(2)
            underTest.onQSPanelKeyboardShortcut()

            assertThat(displayId).isEqualTo(2)
        }

    @Test
    fun onQSPanelKeyboardShortcut_notExistentDisplay_displayIdNotUpdated() =
        testScope.runTest {
            val displayIds by collectValues(underTest.displayId)
            assertThat(displayIds).isEqualTo(listOf(Display.DEFAULT_DISPLAY))

            underTest.onQSPanelKeyboardShortcut()

            // Never set, as 2 was not a display according to the repository.
            assertThat(displayIds).isEqualTo(listOf(Display.DEFAULT_DISPLAY))
        }

    @Test
    fun onQSPanelKeyboardShortcut_afterDisplayRemoved_goesBackToDefaultDisplay() =
        testScope.runTest {
            val displayId by collectLastValue(underTest.displayId)

            displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL))
            focusedDisplayRepository.setDisplayId(2)
            underTest.onQSPanelKeyboardShortcut()

            assertThat(displayId).isEqualTo(2)

            displayRepository.removeDisplay(2)

            assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY)
        }

    @Test
    fun onQSPanelKeyboardShortcut_called_intentSetToNotifications() =
        testScope.runTest {
            underTest.onQSPanelKeyboardShortcut()

            assertThat(underTest.consumeExpansionIntent()).isEqualTo(kosmos.qsElement)
        }

    @Test
    fun onQSPanelKeyboardShortcut_nullAfterConsumed() =
        testScope.runTest {
            underTest.onQSPanelKeyboardShortcut()

            assertThat(underTest.consumeExpansionIntent()).isEqualTo(kosmos.qsElement)
            assertThat(underTest.consumeExpansionIntent()).isNull()
        }

    @Test
    fun onQSPanelKeyboardShortcut_afterOnStatusBarOrLauncherTouched_movesShadeToFocusedDisplay() =
        testScope.runTest {
            val displayId by collectLastValue(underTest.displayId)

            displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL))
            displayRepository.addDisplays(display(id = 3, type = TYPE_EXTERNAL))
            underTest.onStatusBarOrLauncherTouched(createMotionEventForDisplay(2), STATUS_BAR_WIDTH)

            assertThat(displayId).isEqualTo(2)

            focusedDisplayRepository.setDisplayId(3)
            underTest.onQSPanelKeyboardShortcut()

            assertThat(displayId).isEqualTo(3)
        }

    companion object {
        private const val STATUS_BAR_WIDTH = 100
    }
+12 −4
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.util.Slog
import com.android.hardware.input.Flags.enableQuickSettingsPanelShortcut
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.shade.display.StatusBarTouchShadeDisplayPolicy
import com.android.systemui.statusbar.CommandQueue
import com.android.window.flags.Flags.enableKeyGestureHandlerForSysui
import javax.inject.Inject
@@ -34,8 +35,11 @@ import javax.inject.Inject
@SysUISingleton
class SysUIKeyGestureEventInitializer
@Inject
constructor(private val inputManager: InputManager, private val commandQueue: CommandQueue) :
    CoreStartable {
constructor(
    private val inputManager: InputManager,
    private val commandQueue: CommandQueue,
    private val shadeDisplayPolicy: StatusBarTouchShadeDisplayPolicy,
) : CoreStartable {
    override fun start() {
        val supportedGestures = mutableListOf<Int>()
        if (enableKeyGestureHandlerForSysui()) {
@@ -49,10 +53,14 @@ constructor(private val inputManager: InputManager, private val commandQueue: Co
        }
        inputManager.registerKeyGestureEventHandler(supportedGestures) { event, _ ->
            when (event.keyGestureType) {
                KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL ->
                KEY_GESTURE_TYPE_TOGGLE_NOTIFICATION_PANEL -> {
                    shadeDisplayPolicy.onNotificationPanelKeyboardShortcut()
                    commandQueue.toggleNotificationsPanel()
                KEY_GESTURE_TYPE_TOGGLE_QUICK_SETTINGS_PANEL ->
                }
                KEY_GESTURE_TYPE_TOGGLE_QUICK_SETTINGS_PANEL -> {
                    shadeDisplayPolicy.onQSPanelKeyboardShortcut()
                    commandQueue.toggleQuickSettingsPanel()
                }

                else -> Slog.w(TAG, "Unsupported key gesture event: ${event.keyGestureType}")
            }
+22 −9
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import com.android.app.tracing.coroutines.launchTraced
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.display.data.repository.DisplayRepository
import com.android.systemui.display.data.repository.FocusedDisplayRepository
import com.android.systemui.shade.domain.interactor.NotificationShadeElement
import com.android.systemui.shade.domain.interactor.QSShadeElement
import com.android.systemui.shade.domain.interactor.ShadeExpandedStateInteractor.ShadeElement
@@ -51,6 +52,7 @@ class StatusBarTouchShadeDisplayPolicy
@Inject
constructor(
    displayRepository: DisplayRepository,
    private val focusedDisplayRepository: FocusedDisplayRepository,
    @Background private val backgroundScope: CoroutineScope,
    private val qsShadeElement: Lazy<QSShadeElement>,
    private val notificationElement: Lazy<NotificationShadeElement>,
@@ -70,16 +72,28 @@ constructor(
    /** Called when the status bar or launcher homescreen on the given display is touched. */
    fun onStatusBarOrLauncherTouched(event: MotionEvent, statusBarWidth: Int) {
        ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()
        updateShadeDisplayIfNeeded(event)
        updateExpansionIntent(event, statusBarWidth)
        updateShadeDisplayIfNeeded(event.displayId)
        val element = classifyStatusBarEvent(event, statusBarWidth)
        updateExpansionIntent(element)
    }

    private fun onKeyboardShortcut(element: ShadeElement) {
        ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()
        updateShadeDisplayIfNeeded(focusedDisplayRepository.focusedDisplayId.value)
        updateExpansionIntent(element)
    }

    /** Called when notification panel keyboard shortcut is pressed. */
    fun onNotificationPanelKeyboardShortcut() = onKeyboardShortcut(notificationElement.get())

    /** Called when quick settings panel keyboard shortcut is pressed. */
    fun onQSPanelKeyboardShortcut() = onKeyboardShortcut(qsShadeElement.get())

    override fun consumeExpansionIntent(): ShadeElement? {
        return latestIntent.getAndSet(null)
    }

    private fun updateExpansionIntent(event: MotionEvent, statusBarWidth: Int) {
        val element = classifyStatusBarEvent(event, statusBarWidth)
    private fun updateExpansionIntent(element: ShadeElement) {
        latestIntent.set(element)
        timeoutJob?.cancel()
        timeoutJob =
@@ -89,13 +103,12 @@ constructor(
            }
    }

    private fun updateShadeDisplayIfNeeded(event: MotionEvent) {
        val statusBarDisplayId = event.displayId
        if (statusBarDisplayId !in availableDisplayIds.value) {
            Log.e(TAG, "Got touch on unknown display $statusBarDisplayId")
    private fun updateShadeDisplayIfNeeded(newDisplayId: Int) {
        if (newDisplayId !in availableDisplayIds.value) {
            Log.e(TAG, "Cannot update display id to unknown display $newDisplayId")
            return
        }
        currentDisplayId.value = statusBarDisplayId
        currentDisplayId.value = newDisplayId
        if (removalListener == null) {
            // Lazy start this at the first invocation. it's fine to let it run also when the policy
            // is not selected anymore, as the job doesn't do anything until someone subscribes to
+1 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ val Kosmos.anyExternalShadeDisplayPolicy: AnyExternalShadeDisplayPolicy by
val Kosmos.statusBarTouchShadeDisplayPolicy: StatusBarTouchShadeDisplayPolicy by
    Kosmos.Fixture {
        StatusBarTouchShadeDisplayPolicy(
            focusedDisplayRepository = fakeFocusedDisplayRepository,
            displayRepository = displayRepository,
            backgroundScope = testScope.backgroundScope,
            qsShadeElement = { qsElement },