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

Commit 892bce50 authored by Harry Cutts's avatar Harry Cutts
Browse files

CapturedTouchpadEventConverter: filter out palms

When a touchpad marks a touch as a palm, we don't want to pass it on to
apps that have captured the touchpad. In future, we could pass these
through if we wanted by removing @hide from MotionEvent.TOOL_TYPE_PALM
and using that to denote palm touches.

Bug: b/259547750
Test: atest inputflinger_tests
Test: on a suitable touchpad captured by a test app, move a palm around.
      Check it's not reported at all when the pad identifies it straight
      away, and that it's cancelled when identified after touching down.
      (`getevent -l | grep TOOL_TYPE` is useful to tell when the pad
      changes its classification of the touch)
Change-Id: Iefe84120321246f3661a4d2d06e0ec01ba9fe52b
parent bb24e27c
Loading
Loading
Loading
Loading
+16 −8
Original line number Diff line number Diff line
@@ -162,7 +162,6 @@ std::list<NotifyArgs> CapturedTouchpadEventConverter::process(const RawEvent& ra
}

std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t readTime) {
    // TODO(b/259547750): filter out touches marked as palms (using MT_TOOL_PALM).
    std::list<NotifyArgs> out;
    std::vector<PointerCoords> coords;
    std::vector<PointerProperties> properties;
@@ -187,7 +186,11 @@ std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t

    std::vector<size_t> upSlots, downSlots;
    for (size_t i = 0; i < mMotionAccumulator.getSlotCount(); i++) {
        const bool isInUse = mMotionAccumulator.getSlot(i).isInUse();
        const MultiTouchMotionAccumulator::Slot& slot = mMotionAccumulator.getSlot(i);
        // Some touchpads continue to report contacts even after they've identified them as palms.
        // We don't currently have a way to mark these as palms when reporting to apps, so don't
        // report them at all.
        const bool isInUse = slot.isInUse() && slot.getToolType() != ToolType::PALM;
        const bool wasInUse = mPointerIdForSlotNumber.find(i) != mPointerIdForSlotNumber.end();
        if (isInUse && !wasInUse) {
            downSlots.push_back(i);
@@ -199,10 +202,15 @@ std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t
    // For any touches that were lifted, send UP or POINTER_UP events.
    for (size_t slotNumber : upSlots) {
        const size_t indexToRemove = coordsIndexForSlotNumber.at(slotNumber);
        const int32_t action = coords.size() == 1
                ? AMOTION_EVENT_ACTION_UP
                : actionWithIndex(AMOTION_EVENT_ACTION_POINTER_UP, indexToRemove);
        out.push_back(makeMotionArgs(when, readTime, action, coords, properties));
        const bool cancel = mMotionAccumulator.getSlot(slotNumber).getToolType() == ToolType::PALM;
        int32_t action;
        if (coords.size() == 1) {
            action = cancel ? AMOTION_EVENT_ACTION_CANCEL : AMOTION_EVENT_ACTION_UP;
        } else {
            action = actionWithIndex(AMOTION_EVENT_ACTION_POINTER_UP, indexToRemove);
        }
        out.push_back(makeMotionArgs(when, readTime, action, coords, properties, /*actionButton=*/0,
                                     /*flags=*/cancel ? AMOTION_EVENT_FLAG_CANCELED : 0));

        freePointerIdForSlot(slotNumber);
        coords.erase(coords.begin() + indexToRemove);
@@ -249,12 +257,12 @@ std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t

NotifyMotionArgs CapturedTouchpadEventConverter::makeMotionArgs(
        nsecs_t when, nsecs_t readTime, int32_t action, const std::vector<PointerCoords>& coords,
        const std::vector<PointerProperties>& properties, int32_t actionButton) {
        const std::vector<PointerProperties>& properties, int32_t actionButton, int32_t flags) {
    LOG_ALWAYS_FATAL_IF(coords.size() != properties.size(),
                        "Mismatched coords and properties arrays.");
    return NotifyMotionArgs(mReaderContext.getNextId(), when, readTime, mDeviceId, SOURCE,
                            ADISPLAY_ID_NONE, /*policyFlags=*/POLICY_FLAG_WAKE, action,
                            /*actionButton=*/actionButton, /*flags=*/0,
                            /*actionButton=*/actionButton, flags,
                            mReaderContext.getGlobalMetaState(), mButtonState,
                            MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, coords.size(),
                            properties.data(), coords.data(), /*xPrecision=*/1.0f,
+1 −1
Original line number Diff line number Diff line
@@ -53,7 +53,7 @@ private:
    [[nodiscard]] NotifyMotionArgs makeMotionArgs(nsecs_t when, nsecs_t readTime, int32_t action,
                                                  const std::vector<PointerCoords>& coords,
                                                  const std::vector<PointerProperties>& properties,
                                                  int32_t actionButton = 0);
                                                  int32_t actionButton = 0, int32_t flags = 0);
    PointerCoords makePointerCoordsForSlot(const MultiTouchMotionAccumulator::Slot& slot) const;
    int32_t allocatePointerIdToSlot(size_t slotNumber);
    void freePointerIdForSlot(size_t slotNumber);
+228 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <EventHub.h>
#include <gtest/gtest.h>
#include <linux/input-event-codes.h>
#include <linux/input.h>
#include <utils/StrongPointer.h>

#include "FakeEventHub.h"
@@ -415,6 +416,233 @@ TEST_F(CapturedTouchpadEventConverterTest,
                EPSILON);
}

TEST_F(CapturedTouchpadEventConverterTest, OnePalm_neverReported) {
    addBasicAxesToEventHub();
    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOOL_TYPE, 0, MT_TOOL_PALM, 0, 0, 0);
    CapturedTouchpadEventConverter conv(*mReader.getContext(), mDeviceContext, mAccumulator,
                                        DEVICE_ID);

    processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
    processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 100);
    processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PALM);
    processAxis(conv, EV_KEY, BTN_TOUCH, 1);
    processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);

    EXPECT_EQ(0u, processSync(conv).size());

    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 51);

    EXPECT_EQ(0u, processSync(conv).size());

    processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1);
    processAxis(conv, EV_KEY, BTN_TOUCH, 0);
    processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0);

    EXPECT_EQ(0u, processSync(conv).size());
}

TEST_F(CapturedTouchpadEventConverterTest, FingerTurningIntoPalm_cancelled) {
    addBasicAxesToEventHub();
    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOOL_TYPE, 0, MT_TOOL_PALM, 0, 0, 0);
    CapturedTouchpadEventConverter conv(*mReader.getContext(), mDeviceContext, mAccumulator,
                                        DEVICE_ID);

    processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
    processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 100);
    processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);
    processAxis(conv, EV_KEY, BTN_TOUCH, 1);
    processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);

    EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithToolType(ToolType::FINGER),
                      WithPointerCount(1u)));

    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 51);
    processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PALM);

    std::list<NotifyArgs> args = processSync(conv);
    ASSERT_EQ(2u, args.size());
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u)));
    args.pop_front();
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL), WithPointerCount(1u)));

    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52);

    EXPECT_EQ(0u, processSync(conv).size());

    processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1);
    processAxis(conv, EV_KEY, BTN_TOUCH, 0);
    processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0);

    EXPECT_EQ(0u, processSync(conv).size());
}

TEST_F(CapturedTouchpadEventConverterTest, PalmTurningIntoFinger_reported) {
    addBasicAxesToEventHub();
    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOOL_TYPE, 0, MT_TOOL_PALM, 0, 0, 0);
    CapturedTouchpadEventConverter conv(*mReader.getContext(), mDeviceContext, mAccumulator,
                                        DEVICE_ID);

    processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
    processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 100);
    processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PALM);
    processAxis(conv, EV_KEY, BTN_TOUCH, 1);
    processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);

    EXPECT_EQ(0u, processSync(conv).size());

    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 51);
    processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);

    EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
                      WithCoords(51, 100)));

    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52);

    EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u),
                      WithCoords(52, 100)));
}

TEST_F(CapturedTouchpadEventConverterTest, FingerArrivingAfterPalm_onlyFingerReported) {
    addBasicAxesToEventHub();
    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOOL_TYPE, 0, MT_TOOL_PALM, 0, 0, 0);
    CapturedTouchpadEventConverter conv(*mReader.getContext(), mDeviceContext, mAccumulator,
                                        DEVICE_ID);

    processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
    processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 100);
    processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PALM);
    processAxis(conv, EV_KEY, BTN_TOUCH, 1);
    processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);

    EXPECT_EQ(0u, processSync(conv).size());

    processAxis(conv, EV_ABS, ABS_MT_SLOT, 1);
    processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 2);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 100);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 150);
    processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);
    processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0);
    processAxis(conv, EV_KEY, BTN_TOOL_DOUBLETAP, 1);

    EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
                      WithCoords(100, 150)));

    processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 102);
    processAxis(conv, EV_ABS, ABS_MT_SLOT, 1);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 98);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 148);

    EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u),
                      WithCoords(98, 148)));
}

TEST_F(CapturedTouchpadEventConverterTest, FingerAndFingerTurningIntoPalm_partiallyCancelled) {
    addBasicAxesToEventHub();
    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOOL_TYPE, 0, MT_TOOL_PALM, 0, 0, 0);
    CapturedTouchpadEventConverter conv(*mReader.getContext(), mDeviceContext, mAccumulator,
                                        DEVICE_ID);

    processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
    processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50);
    processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);

    processAxis(conv, EV_ABS, ABS_MT_SLOT, 1);
    processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 2);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 250);
    processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);

    processAxis(conv, EV_KEY, BTN_TOUCH, 1);
    processAxis(conv, EV_KEY, BTN_TOOL_DOUBLETAP, 1);

    std::list<NotifyArgs> args = processSync(conv);
    ASSERT_EQ(2u, args.size());
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
                      WithToolType(ToolType::FINGER)));
    args.pop_front();
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN |
                                       1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                      WithPointerCount(2u), WithPointerToolType(0, ToolType::FINGER),
                      WithPointerToolType(1, ToolType::FINGER)));

    processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 51);

    processAxis(conv, EV_ABS, ABS_MT_SLOT, 1);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 251);
    processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PALM);

    args = processSync(conv);
    ASSERT_EQ(2u, args.size());
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(2u)));
    args.pop_front();
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP |
                                       1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                      WithFlags(AMOTION_EVENT_FLAG_CANCELED), WithPointerCount(2u)));
}

TEST_F(CapturedTouchpadEventConverterTest, FingerAndPalmTurningIntoFinger_reported) {
    addBasicAxesToEventHub();
    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOOL_TYPE, 0, MT_TOOL_PALM, 0, 0, 0);
    CapturedTouchpadEventConverter conv(*mReader.getContext(), mDeviceContext, mAccumulator,
                                        DEVICE_ID);

    processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
    processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50);
    processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);

    processAxis(conv, EV_ABS, ABS_MT_SLOT, 1);
    processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 2);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 250);
    processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PALM);

    processAxis(conv, EV_KEY, BTN_TOUCH, 1);
    processAxis(conv, EV_KEY, BTN_TOOL_DOUBLETAP, 1);

    EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
                      WithToolType(ToolType::FINGER)));

    processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 51);

    processAxis(conv, EV_ABS, ABS_MT_SLOT, 1);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 251);
    processAxis(conv, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);

    std::list<NotifyArgs> args = processSync(conv);
    ASSERT_EQ(2u, args.size());
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u)));
    args.pop_front();
    EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN |
                                       1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                      WithPointerCount(2u)));
}

TEST_F(CapturedTouchpadEventConverterTest, TwoFingers_motionReportedCorrectly) {
    CapturedTouchpadEventConverter conv = createConverter();