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

Commit 43b8f8a8 authored by Prabir Pradhan's avatar Prabir Pradhan Committed by Android (Google) Code Review
Browse files

Merge "Move stylus tail button gesture detection to PhoneWindowManager" into main

parents 715986ac c98777a7
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -22,8 +22,6 @@ import android.annotation.Nullable;
import android.view.Display;
import android.view.KeyCharacterMap;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.AnnotationValidations;
import com.android.internal.util.FrameworkStatsLog;

import java.lang.annotation.Retention;
@@ -170,6 +168,14 @@ public final class KeyGestureEvent {
        this.mKeyGestureEvent = keyGestureEvent;
    }

    /**
     * Tests whether this keyboard shortcut event has the given modifiers (i.e. all of the given
     * modifiers were pressed when this shortcut was triggered).
     */
    public boolean hasModifiers(int modifiers) {
        return (getModifierState() & modifiers) == modifiers;
    }

    /**
     * Key gesture event builder used to create a KeyGestureEvent for tests in Java.
     *
+24 −5
Original line number Diff line number Diff line
@@ -75,8 +75,10 @@ constructor(
     * [NoteTaskController], ensure custom actions can be triggered (i.e., keyboard shortcut).
     */
    private fun initializeHandleSystemKey() {
        if (!useKeyGestureEventHandler()) {
            commandQueue.addCallback(callbacks)
        }
    }

    /**
     * Initializes a [InputManager.KeyGestureEventHandler] which will handle shortcuts for opening
@@ -130,6 +132,11 @@ constructor(
            InputManager.KeyGestureEventHandler {

            override fun handleSystemKey(key: KeyEvent) {
                if (useKeyGestureEventHandler()) {
                    throw IllegalStateException(
                        "handleSystemKey must not be used when KeyGestureEventHandler is used"
                    )
                }
                key.toNoteTaskEntryPointOrNull()?.let(controller::showNoteTask)
            }

@@ -151,13 +158,13 @@ constructor(

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

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

@@ -209,9 +216,21 @@ constructor(
            "handleKeyGestureEvent: Received OPEN_NOTES gesture event from keycodes: " +
                event.keycodes.contentToString()
        }
        if (
            event.keycodes.contains(KEYCODE_N) &&
                event.hasModifiers(KeyEvent.META_CTRL_ON or KeyEvent.META_META_ON)
        ) {
            debugLog { "Note task triggered by keyboard shortcut" }
            backgroundExecutor.execute { controller.showNoteTask(KEYBOARD_SHORTCUT) }
            return true
        }
        if (event.keycodes.size == 1 && event.keycodes[0] == KEYCODE_STYLUS_BUTTON_TAIL) {
            debugLog { "Note task triggered by stylus tail button" }
            backgroundExecutor.execute { controller.showNoteTask(TAIL_BUTTON) }
            return true
        }
        return false
    }

    private fun isKeyGestureSupported(gestureType: Int): Boolean {
        return gestureType == KeyGestureEvent.KEY_GESTURE_TYPE_OPEN_NOTES
+65 −20
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.hardware.input.InputManager
import android.hardware.input.KeyGestureEvent
import android.os.UserHandle
import android.os.UserManager
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.SetFlagsRule
import android.view.KeyEvent
@@ -32,6 +33,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.SysuiTestCase
import com.android.systemui.notetask.NoteTaskEntryPoint.KEYBOARD_SHORTCUT
import com.android.systemui.notetask.NoteTaskEntryPoint.TAIL_BUTTON
import com.android.systemui.settings.FakeUserTracker
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.util.concurrency.FakeExecutor
@@ -62,8 +65,7 @@ import org.mockito.MockitoAnnotations.initMocks
@RunWith(AndroidJUnit4::class)
internal class NoteTaskInitializerTest : SysuiTestCase() {

    @get:Rule
    val setFlagsRule = SetFlagsRule()
    @get:Rule val setFlagsRule = SetFlagsRule()

    @Mock lateinit var commandQueue: CommandQueue
    @Mock lateinit var inputManager: InputManager
@@ -83,10 +85,7 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {
        whenever(keyguardMonitor.isUserUnlocked(userTracker.userId)).thenReturn(true)
    }

    private fun createUnderTest(
        isEnabled: Boolean,
        bubbles: Bubbles?,
    ): NoteTaskInitializer =
    private fun createUnderTest(isEnabled: Boolean, bubbles: Bubbles?): NoteTaskInitializer =
        NoteTaskInitializer(
            controller = controller,
            commandQueue = commandQueue,
@@ -104,7 +103,7 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {
        code: Int,
        downTime: Long = 0L,
        eventTime: Long = 0L,
        metaState: Int = 0
        metaState: Int = 0,
    ): KeyEvent = KeyEvent(downTime, eventTime, action, code, 0 /*repeat*/, metaState)

    @Test
@@ -113,7 +112,6 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {

        createUnderTest(isEnabled = true, bubbles = bubbles).initialize()

        verify(commandQueue).addCallback(any())
        verify(roleManager).addOnRoleHoldersChangedListenerAsUser(any(), any(), any())
        verify(controller).updateNoteTaskForCurrentUserAndManagedProfiles()
        verify(keyguardMonitor).registerCallback(any())
@@ -125,7 +123,6 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {

        createUnderTest(isEnabled = true, bubbles = bubbles).initialize()

        verify(commandQueue).addCallback(any())
        verify(roleManager).addOnRoleHoldersChangedListenerAsUser(any(), any(), any())
        verify(controller, never()).setNoteTaskShortcutEnabled(any(), any())
        verify(keyguardMonitor).registerCallback(any())
@@ -165,12 +162,13 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {
    }

    @Test
    @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
    fun initialize_handleSystemKey() {
        val expectedKeyEvent =
            createKeyEvent(
                ACTION_DOWN,
                KEYCODE_N,
                metaState = KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON
                metaState = KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON,
            )
        val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
        underTest.initialize()
@@ -183,8 +181,9 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {

    @Test
    @EnableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
    fun initialize_handleKeyGestureEvent() {
        val gestureEvent = KeyGestureEvent.Builder()
    fun handlesShortcut_metaCtrlN() {
        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)
@@ -192,13 +191,56 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {
                .build()
        val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
        underTest.initialize()
        val callback =
            withArgCaptor { verify(inputManager).registerKeyGestureEventHandler(capture()) }
        val callback = withArgCaptor {
            verify(inputManager).registerKeyGestureEventHandler(capture())
        }

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

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

    @Test
    @EnableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
    fun handlesShortcut_stylusTailButton() {
        val gestureEvent =
            KeyGestureEvent.Builder()
                .setKeycodes(intArrayOf(KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL))
                .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(eq(TAIL_BUTTON))
    }

    @Test
    @EnableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
    fun ignoresUnrelatedShortcuts() {
        val gestureEvent =
            KeyGestureEvent.Builder()
                .setKeycodes(intArrayOf(KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL))
                .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_HOME)
                .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)).isFalse()

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

    @Test
@@ -249,6 +291,7 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {
    }

    @Test
    @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
    fun tailButtonGestureDetection_singlePress_shouldShowNoteTaskOnUp() {
        val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
        underTest.initialize()
@@ -267,6 +310,7 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {
    }

    @Test
    @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
    fun tailButtonGestureDetection_doublePress_shouldNotShowNoteTaskTwice() {
        val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
        underTest.initialize()
@@ -289,6 +333,7 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {
    }

    @Test
    @DisableFlags(com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER)
    fun tailButtonGestureDetection_longPress_shouldNotShowNoteTask() {
        val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
        underTest.initialize()
+19 −0
Original line number Diff line number Diff line
@@ -232,6 +232,9 @@ public abstract class InputManagerInternal {
    /**
     * Notify key gesture was completed by the user.
     *
     * NOTE: This is a temporary API added to assist in a long-term refactor, and is not meant for
     * general use by system services.
     *
     * @param deviceId the device ID of the keyboard using which the event was completed
     * @param keycodes the keys pressed for the event
     * @param modifierState the modifier state
@@ -240,4 +243,20 @@ public abstract class InputManagerInternal {
     */
    public abstract void notifyKeyGestureCompleted(int deviceId, int[] keycodes, int modifierState,
            @KeyGestureEvent.KeyGestureType int event);

    /**
     * Notify that a key gesture was detected by another system component, and it should be handled
     * appropriately by KeyGestureController.
     *
     * NOTE: This is a temporary API added to assist in a long-term refactor, and is not meant for
     * general use by system services.
     *
     * @param deviceId the device ID of the keyboard using which the event was completed
     * @param keycodes the keys pressed for the event
     * @param modifierState the modifier state
     * @param event the gesture event that was completed
     *
     */
    public abstract void handleKeyGestureInKeyGestureController(int deviceId, int[] keycodes,
            int modifierState, @KeyGestureEvent.KeyGestureType int event);
}
+6 −0
Original line number Diff line number Diff line
@@ -3408,6 +3408,12 @@ public class InputManagerService extends IInputManager.Stub
            mKeyGestureController.notifyKeyGestureCompleted(deviceId, keycodes, modifierState,
                    gestureType);
        }

        @Override
        public void handleKeyGestureInKeyGestureController(int deviceId, int[] keycodes,
                int modifierState, @KeyGestureEvent.KeyGestureType int gestureType) {
            mKeyGestureController.handleKeyGesture(deviceId, keycodes, modifierState, gestureType);
        }
    }

    @Override
Loading