From c1f1d85f0461173752ce6a21464fd4ab16001d2b Mon Sep 17 00:00:00 2001 From: Prabir Pradhan Date: Fri, 1 Sep 2023 22:52:30 +0000 Subject: Support key gesture detection for stylus tail button in SysUI Here, we add gesture detection logic for the stylus tail button in SysUI. The notes task will only be shown immediately on the UP event of the first key press of a key gesture. A long press will not do anything for now. If there is a multi-press (e.g. double-press, triple-press), only the first press will react to the event. Bug: 298056902 Test: manual with stylus Test: atest NoteTaskInitializerTest (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:515a1625d4948f2fdb1ef6e966fe4469b0ed4d9f) Merged-In: I90391f411d84ec5c749bb4d8cdefd7e610539e6e Change-Id: I90391f411d84ec5c749bb4d8cdefd7e610539e6e --- .../systemui/notetask/NoteTaskInitializer.kt | 45 +++++++++++++++++----- .../systemui/notetask/NoteTaskInitializerTest.kt | 38 ++++++++++++++++++ 2 files changed, 73 insertions(+), 10 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt index 3f609a25c3fc..338d3ed42f95 100644 --- a/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt +++ b/packages/SystemUI/src/com/android/systemui/notetask/NoteTaskInitializer.kt @@ -23,6 +23,7 @@ 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.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.dagger.qualifiers.Background @@ -128,15 +129,39 @@ constructor( controller.updateNoteTaskForCurrentUserAndManagedProfiles() } } -} -/** - * Maps a [KeyEvent] to a [NoteTaskEntryPoint]. If the [KeyEvent] does not represent a - * [NoteTaskEntryPoint], returns null. - */ -private fun KeyEvent.toNoteTaskEntryPointOrNull(): NoteTaskEntryPoint? = - when { - keyCode == KEYCODE_STYLUS_BUTTON_TAIL && action == KeyEvent.ACTION_UP -> TAIL_BUTTON - keyCode == KEYCODE_N && isMetaPressed && isCtrlPressed -> KEYBOARD_SHORTCUT - else -> null + /** + * Tracks a [KeyEvent], and determines if it should trigger an action to show the note task. + * Returns a [NoteTaskEntryPoint] if an action should be taken, and null otherwise. + */ + private fun KeyEvent.toNoteTaskEntryPointOrNull(): NoteTaskEntryPoint? = + when { + keyCode == KEYCODE_STYLUS_BUTTON_TAIL && isTailButtonNotesGesture() -> TAIL_BUTTON + keyCode == KEYCODE_N && isMetaPressed && isCtrlPressed -> KEYBOARD_SHORTCUT + else -> null + } + + private var lastStylusButtonTailUpEventTime: Long = -MULTI_PRESS_TIMEOUT + + /** + * Perform gesture detection for the stylus tail button to make sure we only show the note task + * when there is a single press. Long presses and multi-presses are ignored for now. + */ + private fun KeyEvent.isTailButtonNotesGesture(): Boolean { + if (keyCode != KEYCODE_STYLUS_BUTTON_TAIL || action != KeyEvent.ACTION_UP) { + return false + } + + val isMultiPress = (downTime - lastStylusButtonTailUpEventTime) < MULTI_PRESS_TIMEOUT + val isLongPress = (eventTime - downTime) >= LONG_PRESS_TIMEOUT + lastStylusButtonTailUpEventTime = eventTime + // For now, trigger action immediately on UP of a single press, without waiting for + // the multi-press timeout to expire. + return !isMultiPress && !isLongPress } + + companion object { + val MULTI_PRESS_TIMEOUT = ViewConfiguration.getMultiPressTimeout().toLong() + val LONG_PRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout().toLong() + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt index 162b7b3d41db..78330078076c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/notetask/NoteTaskInitializerTest.kt @@ -235,4 +235,42 @@ internal class NoteTaskInitializerTest : SysuiTestCase() { verify(controller).showNoteTask(any()) } + + @Test + fun tailButtonGestureDetection_doublePress_shouldNotShowNoteTaskTwice() { + val underTest = createUnderTest(isEnabled = true, bubbles = bubbles) + underTest.initialize() + val callback = withArgCaptor { verify(commandQueue).addCallback(capture()) } + + callback.handleSystemKey( + createKeyEvent(ACTION_DOWN, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 0, eventTime = 0) + ) + callback.handleSystemKey( + createKeyEvent(ACTION_UP, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 0, eventTime = 50) + ) + callback.handleSystemKey( + createKeyEvent(ACTION_DOWN, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 99, eventTime = 99) + ) + callback.handleSystemKey( + createKeyEvent(ACTION_UP, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 99, eventTime = 150) + ) + + verify(controller, times(1)).showNoteTask(any()) + } + + @Test + fun tailButtonGestureDetection_longPress_shouldNotShowNoteTask() { + val underTest = createUnderTest(isEnabled = true, bubbles = bubbles) + underTest.initialize() + val callback = withArgCaptor { verify(commandQueue).addCallback(capture()) } + + callback.handleSystemKey( + createKeyEvent(ACTION_DOWN, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 0, eventTime = 0) + ) + callback.handleSystemKey( + createKeyEvent(ACTION_UP, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 0, eventTime = 1000) + ) + + verify(controller, never()).showNoteTask(any()) + } } -- cgit v1.2.3-59-g8ed1b