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

Commit c8a43465 authored by Yeabkal Wubshit's avatar Yeabkal Wubshit
Browse files

Cancel multipress gesture if a press is too slow

If a user starts a multipress gesture (i.e. starts a second/third press)
of a button, but that second/third press is long, cancel the multipress
gesture. We require the first and second (and third) down events to
happen quickly after one another, so it is more organic that we expect
the consecutive presses to be within the same duration.

Bug: 370095426
Test: atest SingleKeyGestureTests
Flag: com.android.hardware.input.abort_slow_multi_press

Change-Id: Id17c13e7d7863e3f7949da7b53ee7f4dfc0c1236
parent 8fcd566a
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -225,3 +225,13 @@ flag {
    description: "Removes modifiers from the original key event that activated the fallback, ensuring that only the intended fallback event is sent."
    bug: "382545048"
}

flag {
    name: "abort_slow_multi_press"
    namespace: "wear_frameworks"
    description: "If a press that's a part of a multipress takes too long, the multipress gesture will be cancelled."
    bug: "370095426"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}
+15 −0
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@ import android.util.Log;
import android.view.KeyEvent;
import android.view.ViewConfiguration;

import com.android.hardware.input.Flags;

import java.io.PrintWriter;
import java.util.ArrayList;

@@ -355,6 +357,19 @@ public final class SingleKeyGestureDetector {
        }

        if (event.getKeyCode() == mActiveRule.mKeyCode) {
            if (Flags.abortSlowMultiPress()
                    && (event.getEventTime() - mLastDownTime
                            >= mActiveRule.getLongPressTimeoutMs())) {
                // In this case, we are either on a first long press (but long press behavior is not
                // supported for this rule), or, on a non-first press that is at least as long as
                // the long-press duration. Thus, we will cancel the multipress gesture.
                if (DEBUG) {
                    Log.d(TAG, "The duration of the press is too slow. Resetting.");
                }
                reset();
                return false;
            }

            // key-up action should always be triggered if not processed by long press.
            MessageObject object = new MessageObject(mActiveRule, mActiveRule.mKeyCode,
                    mKeyPressCounter, event);
+46 −0
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@ import static android.view.KeyEvent.KEYCODE_POWER;

import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;

import static com.android.hardware.input.Flags.FLAG_ABORT_SLOW_MULTI_PRESS;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -35,9 +37,13 @@ import android.os.HandlerThread;
import android.os.Looper;
import android.os.Process;
import android.os.SystemClock;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.view.KeyEvent;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;

import java.util.concurrent.BlockingQueue;
@@ -52,6 +58,8 @@ import java.util.concurrent.TimeUnit;
 *  atest WmTests:SingleKeyGestureTests
 */
public class SingleKeyGestureTests {
    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();

    private SingleKeyGestureDetector mDetector;

    private int mMaxMultiPressCount = 3;
@@ -259,6 +267,44 @@ public class SingleKeyGestureTests {
        assertTrue(mVeryLongPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
    }

    @Test
    @EnableFlags(FLAG_ABORT_SLOW_MULTI_PRESS)
    public void testMultipress_noLongPressBehavior_longPressCancelsMultiPress()
            throws InterruptedException {
        mLongPressOnPowerBehavior = false;

        pressKey(KEYCODE_POWER, 0 /* pressTime */);
        pressKey(KEYCODE_POWER, mLongPressTime /* pressTime */);

        assertFalse(mMultiPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
    }

    @Test
    @EnableFlags(FLAG_ABORT_SLOW_MULTI_PRESS)
    public void testMultipress_noVeryLongPressBehavior_veryLongPressCancelsMultiPress()
            throws InterruptedException {
        mLongPressOnPowerBehavior = false;
        mVeryLongPressOnPowerBehavior = false;

        pressKey(KEYCODE_POWER, 0 /* pressTime */);
        pressKey(KEYCODE_POWER, mVeryLongPressTime /* pressTime */);

        assertFalse(mMultiPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
    }

    @Test
    @DisableFlags(FLAG_ABORT_SLOW_MULTI_PRESS)
    public void testMultipress_flagDisabled_noLongPressBehavior_longPressDoesNotCancelMultiPress()
            throws InterruptedException {
        mLongPressOnPowerBehavior = false;
        mExpectedMultiPressCount = 2;

        pressKey(KEYCODE_POWER, 0 /* pressTime */);
        pressKey(KEYCODE_POWER, mLongPressTime /* pressTime */);

        assertTrue(mMultiPressed.await(mWaitTimeout, TimeUnit.MILLISECONDS));
    }

    @Test
    public void testMultiPress() throws InterruptedException {
        // Double presses.