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

Commit d014c14c authored by Vaibhav Devmurari's avatar Vaibhav Devmurari Committed by Android (Google) Code Review
Browse files

Merge "Shift Open notes key gesture handling to SystemUI" into main

parents ccf9aa3e c20cc5d2
Loading
Loading
Loading
Loading
+47 −1
Original line number Diff line number Diff line
@@ -19,11 +19,15 @@ import android.app.role.OnRoleHoldersChangedListener
import android.app.role.RoleManager
import android.content.Context
import android.content.pm.UserInfo
import android.hardware.input.InputManager
import android.hardware.input.KeyGestureEvent
import android.os.IBinder
import android.os.UserHandle
import android.view.KeyEvent
import android.view.KeyEvent.KEYCODE_N
import android.view.KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL
import android.view.ViewConfiguration
import com.android.hardware.input.Flags.useKeyGestureEventHandler
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.dagger.qualifiers.Background
@@ -47,6 +51,7 @@ constructor(
    private val optionalBubbles: Optional<Bubbles>,
    private val userTracker: UserTracker,
    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
    private val inputManager: InputManager,
    @Background private val backgroundExecutor: Executor,
    @NoteTaskEnabledKey private val isEnabled: Boolean,
) {
@@ -59,6 +64,7 @@ constructor(
        if (!isEnabled || optionalBubbles.isEmpty) return

        initializeHandleSystemKey()
        initializeKeyGestureEventHandler()
        initializeOnRoleHoldersChanged()
        initializeOnUserUnlocked()
        initializeUserTracker()
@@ -72,6 +78,16 @@ constructor(
        commandQueue.addCallback(callbacks)
    }

    /**
     * Initializes a [InputManager.KeyGestureEventHandler] which will handle shortcuts for opening
     * the notes role via [NoteTaskController].
     */
    private fun initializeKeyGestureEventHandler() {
        if (useKeyGestureEventHandler()) {
            inputManager.registerKeyGestureEventHandler(callbacks)
        }
    }

    /**
     * Initializes the [RoleManager] role holder changed listener to ensure [NoteTaskController]
     * will always update whenever the role holder app changes. Keep in mind that a role may change
@@ -110,7 +126,8 @@ constructor(
            KeyguardUpdateMonitorCallback(),
            CommandQueue.Callbacks,
            UserTracker.Callback,
            OnRoleHoldersChangedListener {
            OnRoleHoldersChangedListener,
            InputManager.KeyGestureEventHandler {

            override fun handleSystemKey(key: KeyEvent) {
                key.toNoteTaskEntryPointOrNull()?.let(controller::showNoteTask)
@@ -131,6 +148,17 @@ constructor(
            override fun onProfilesChanged(profiles: List<UserInfo>) {
                controller.updateNoteTaskForCurrentUserAndManagedProfiles()
            }

            override fun handleKeyGestureEvent(
                event: KeyGestureEvent,
                focusedToken: IBinder?
            ): Boolean {
                return this@NoteTaskInitializer.handleKeyGestureEvent(event)
            }

            override fun isKeyGestureSupported(gestureType: Int): Boolean {
                return this@NoteTaskInitializer.isKeyGestureSupported(gestureType);
            }
        }

    /**
@@ -171,6 +199,24 @@ constructor(
        return !isMultiPress && !isLongPress
    }

    private fun handleKeyGestureEvent(event: KeyGestureEvent): Boolean {
        // This method is on input hot path and should be kept lightweight. Shift all complex
        // processing onto background executor wherever possible.
        if (event.keyGestureType != KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES) {
            return false
        }
        debugLog {
            "handleKeyGestureEvent: Received OPEN_NOTES gesture event from keycodes: " +
                event.keycodes.contentToString()
        }
        backgroundExecutor.execute { controller.showNoteTask(KEYBOARD_SHORTCUT) }
        return true
    }

    private fun isKeyGestureSupported(gestureType: Int): Boolean {
        return gestureType == KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES
    }

    companion object {
        val MULTI_PRESS_TIMEOUT = ViewConfiguration.getMultiPressTimeout().toLong()
        val LONG_PRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout().toLong()
+30 −0
Original line number Diff line number Diff line
@@ -17,8 +17,12 @@ package com.android.systemui.notetask

import android.app.role.RoleManager
import android.app.role.RoleManager.ROLE_NOTES
import android.hardware.input.InputManager
import android.hardware.input.KeyGestureEvent
import android.os.UserHandle
import android.os.UserManager
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.SetFlagsRule
import android.view.KeyEvent
import android.view.KeyEvent.ACTION_DOWN
import android.view.KeyEvent.ACTION_UP
@@ -42,6 +46,7 @@ import com.google.common.truth.Truth.assertThat
import java.util.Optional
import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
@@ -57,7 +62,11 @@ import org.mockito.MockitoAnnotations.initMocks
@RunWith(AndroidJUnit4::class)
internal class NoteTaskInitializerTest : SysuiTestCase() {

    @get:Rule
    val setFlagsRule = SetFlagsRule()

    @Mock lateinit var commandQueue: CommandQueue
    @Mock lateinit var inputManager: InputManager
    @Mock lateinit var bubbles: Bubbles
    @Mock lateinit var controller: NoteTaskController
    @Mock lateinit var roleManager: RoleManager
@@ -86,6 +95,7 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {
            roleManager = roleManager,
            userTracker = userTracker,
            keyguardUpdateMonitor = keyguardMonitor,
            inputManager = inputManager,
            backgroundExecutor = executor,
        )

@@ -171,6 +181,26 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {
        verify(controller).showNoteTask(any())
    }

    @Test
    @EnableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
    fun initialize_handleKeyGestureEvent() {
        val gestureEvent = KeyGestureEvent.Builder()
            .setKeycodes(intArrayOf(KeyEvent.KEYCODE_N))
            .setModifierState(KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON)
            .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES)
            .setAction(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
            .build()
        val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
        underTest.initialize()
        val callback =
            withArgCaptor { verify(inputManager).registerKeyGestureEventHandler(capture()) }

        assertThat(callback.handleKeyGestureEvent(gestureEvent, null)).isTrue()

        executor.runAllReady()
        verify(controller).showNoteTask(any())
    }

    @Test
    fun initialize_userUnlocked_shouldUpdateNoteTask() {
        whenever(keyguardMonitor.isUserUnlocked(userTracker.userId)).thenReturn(false)
+5 −1
Original line number Diff line number Diff line
@@ -259,7 +259,11 @@ final class KeyGestureController {
            case KeyEvent.KEYCODE_N:
                if (firstDown && event.isMetaPressed()) {
                    if (event.isCtrlPressed()) {
                        // TODO(b/358569822): Move open notes handling in System UI instead of PWM
                        return handleKeyGesture(deviceId, new int[]{keyCode},
                                KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON,
                                KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES,
                                KeyGestureEvent.ACTION_GESTURE_COMPLETE, displayId,
                                focusedToken, /* flags = */0);
                    } else {
                        return handleKeyGesture(deviceId, new int[]{keyCode},
                                KeyEvent.META_META_ON,
+12 −0
Original line number Diff line number Diff line
@@ -285,6 +285,18 @@ class KeyGestureControllerTests {
                KeyEvent.META_META_ON,
                intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
            ),
            TestData(
                "META + CTRL + N -> Open Notes",
                intArrayOf(
                    KeyEvent.KEYCODE_META_LEFT,
                    KeyEvent.KEYCODE_CTRL_LEFT,
                    KeyEvent.KEYCODE_N
                ),
                KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES,
                intArrayOf(KeyEvent.KEYCODE_N),
                KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON,
                intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
            ),
            TestData(
                "META + CTRL + S -> Take Screenshot",
                intArrayOf(