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

Commit ea3f4fc7 authored by arthurhung's avatar arthurhung
Browse files

Prevent accidentally click on window with split touch

Currently, inputflinger would send an ACTION_POINTER_UP event with
AKEY_EVENT_FLAG_CANCELED when we have at least 2 pointers down and
one becomes the accidental touch.

An input window could have FLAG_SPLIT that could split a multi touch
event into some single touch events, so we should check the cancel flag
in order to prevent it trigger an accidental click on the target window.

Bug: 161655782
Test: inputflinger_tests
Test: enable twoshay, test accidental touch on slipt window.
Change-Id: I95eae0c9aef1f888f352b31affcece893d557754
parent 57563a10
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -3414,6 +3414,8 @@ std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent(
                // The first/last pointer went down/up.
                action = maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN
                        ? AMOTION_EVENT_ACTION_DOWN
                        : (originalMotionEntry.flags & AMOTION_EVENT_FLAG_CANCELED) != 0
                                ? AMOTION_EVENT_ACTION_CANCEL
                                : AMOTION_EVENT_ACTION_UP;
            } else {
                // A secondary pointer went down/up.
+65 −0
Original line number Diff line number Diff line
@@ -1785,6 +1785,71 @@ TEST_F(InputDispatcherTest, UnfocusedWindow_ReceivesMotionsButNotKeys) {
    window->assertNoEvents(); // Key event or focus event will not be received
}

TEST_F(InputDispatcherTest, PointerCancel_SendCancelWhenSplitTouch) {
    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();

    // Create first non touch modal window that supports split touch
    sp<FakeWindowHandle> firstWindow =
            new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
    firstWindow->setFrame(Rect(0, 0, 600, 400));
    firstWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
                          InputWindowInfo::Flag::SPLIT_TOUCH);

    // Create second non touch modal window that supports split touch
    sp<FakeWindowHandle> secondWindow =
            new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
    secondWindow->setFrame(Rect(0, 400, 600, 800));
    secondWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
                           InputWindowInfo::Flag::SPLIT_TOUCH);

    // Add the windows to the dispatcher
    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});

    PointF pointInFirst = {300, 200};
    PointF pointInSecond = {300, 600};

    // Send down to the first window
    NotifyMotionArgs firstDownMotionArgs =
            generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
                               ADISPLAY_ID_DEFAULT, {pointInFirst});
    mDispatcher->notifyMotion(&firstDownMotionArgs);
    // Only the first window should get the down event
    firstWindow->consumeMotionDown();
    secondWindow->assertNoEvents();

    // Send down to the second window
    NotifyMotionArgs secondDownMotionArgs =
            generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN |
                                       (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                               AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
                               {pointInFirst, pointInSecond});
    mDispatcher->notifyMotion(&secondDownMotionArgs);
    // The first window gets a move and the second a down
    firstWindow->consumeMotionMove();
    secondWindow->consumeMotionDown();

    // Send pointer cancel to the second window
    NotifyMotionArgs pointerUpMotionArgs =
            generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP |
                                       (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                               AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
                               {pointInFirst, pointInSecond});
    pointerUpMotionArgs.flags |= AMOTION_EVENT_FLAG_CANCELED;
    mDispatcher->notifyMotion(&pointerUpMotionArgs);
    // The first window gets move and the second gets cancel.
    firstWindow->consumeMotionMove(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);
    secondWindow->consumeMotionCancel(ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED);

    // Send up event.
    NotifyMotionArgs upMotionArgs =
            generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
                               ADISPLAY_ID_DEFAULT);
    mDispatcher->notifyMotion(&upMotionArgs);
    // The first window gets up and the second gets nothing.
    firstWindow->consumeMotionUp();
    secondWindow->assertNoEvents();
}

class FakeMonitorReceiver {
public:
    FakeMonitorReceiver(const sp<InputDispatcher>& dispatcher, const std::string name,