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

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

Merge changes from topic "cherrypicker-L35800000963116081:N91200001406548621" into udc-qpr-dev

* changes:
  Support key gesture detection for stylus tail button in SysUI
  Launch notes task when the stylus tail button goes UP
parents e8ae7b22 c1f1d85f
Loading
Loading
Loading
Loading
+35 −16
Original line number Diff line number Diff line
@@ -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
@@ -65,12 +66,6 @@ constructor(
     * [NoteTaskController], ensure custom actions can be triggered (i.e., keyboard shortcut).
     */
    private fun initializeHandleSystemKey() {
        val callbacks =
            object : CommandQueue.Callbacks {
                override fun handleSystemKey(key: KeyEvent) {
                    key.toNoteTaskEntryPointOrNull()?.let(controller::showNoteTask)
                }
            }
        commandQueue.addCallback(callbacks)
    }

@@ -134,15 +129,39 @@ constructor(
                controller.updateNoteTaskForCurrentUserAndManagedProfiles()
            }
        }
}

    /**
 * Maps a [KeyEvent] to a [NoteTaskEntryPoint]. If the [KeyEvent] does not represent a
 * [NoteTaskEntryPoint], returns 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 -> TAIL_BUTTON
            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()
    }
}
+98 −28
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import android.os.UserManager
import android.testing.AndroidTestingRunner
import android.view.KeyEvent
import android.view.KeyEvent.ACTION_DOWN
import android.view.KeyEvent.ACTION_UP
import android.view.KeyEvent.KEYCODE_N
import android.view.KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardUpdateMonitor
@@ -30,7 +32,6 @@ import com.android.systemui.settings.FakeUserTracker
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
@@ -43,7 +44,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.times
@@ -66,6 +66,7 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {

    private val executor = FakeExecutor(FakeSystemClock())
    private val userTracker = FakeUserTracker()
    private val handlerCallbacks = mutableListOf<Runnable>()

    @Before
    fun setUp() {
@@ -88,6 +89,14 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {
            backgroundExecutor = executor,
        )

    private fun createKeyEvent(
        action: Int,
        code: Int,
        downTime: Long = 0L,
        eventTime: Long = 0L,
        metaState: Int = 0
    ): KeyEvent = KeyEvent(downTime, eventTime, action, code, 0 /*repeat*/, metaState)

    @Test
    fun initialize_withUserUnlocked() {
        whenever(keyguardMonitor.isUserUnlocked(userTracker.userId)).thenReturn(true)
@@ -147,7 +156,12 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {

    @Test
    fun initialize_handleSystemKey() {
        val expectedKeyEvent = KeyEvent(ACTION_DOWN, KEYCODE_STYLUS_BUTTON_TAIL)
        val expectedKeyEvent =
            createKeyEvent(
                ACTION_DOWN,
                KEYCODE_N,
                metaState = KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON
            )
        val underTest = createUnderTest(isEnabled = true, bubbles = bubbles)
        underTest.initialize()
        val callback = withArgCaptor { verify(commandQueue).addCallback(capture()) }
@@ -203,4 +217,60 @@ internal class NoteTaskInitializerTest : SysuiTestCase() {

        verify(controller, times(2)).updateNoteTaskForCurrentUserAndManagedProfiles()
    }

    @Test
    fun tailButtonGestureDetection_singlePress_shouldShowNoteTaskOnUp() {
        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)
        )
        verify(controller, never()).showNoteTask(any())

        callback.handleSystemKey(
            createKeyEvent(ACTION_UP, KEYCODE_STYLUS_BUTTON_TAIL, downTime = 0, eventTime = 50)
        )

        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())
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -4559,7 +4559,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            case KeyEvent.KEYCODE_STYLUS_BUTTON_SECONDARY:
            case KeyEvent.KEYCODE_STYLUS_BUTTON_TERTIARY:
            case KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL: {
                if (down && mStylusButtonsEnabled) {
                if (mStylusButtonsEnabled) {
                    sendSystemKeyToStatusBarAsync(event);
                }
                result &= ~ACTION_PASS_TO_USER;