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

Commit ca1fefc3 authored by Harry Cutts's avatar Harry Cutts Committed by Android (Google) Code Review
Browse files

Merge changes I57d23909,If6828f95 into main

* changes:
  TestEventMatchers: bounds check pointer indexes
  CapturedTouchpadEventConverter: report relative axes
parents 45833f21 ccd9d51b
Loading
Loading
Loading
Loading
+63 −9
Original line number Diff line number Diff line
@@ -20,14 +20,19 @@
#include <sstream>

#include <android-base/stringprintf.h>
#include <com_android_input_flags.h>
#include <input/PrintTools.h>
#include <linux/input-event-codes.h>
#include <log/log_main.h>

namespace input_flags = com::android::input::flags;

namespace android {

namespace {

static constexpr uint32_t SOURCE = AINPUT_SOURCE_TOUCHPAD;

int32_t actionWithIndex(int32_t action, int32_t index) {
    return action | (index << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
}
@@ -43,6 +48,12 @@ size_t firstUnmarkedBit(T set) {
    return i;
}

void addRawMotionRange(InputDeviceInfo& deviceInfo, int32_t androidAxis,
                       RawAbsoluteAxisInfo& evdevAxis) {
    deviceInfo.addMotionRange(androidAxis, SOURCE, evdevAxis.minValue, evdevAxis.maxValue,
                              evdevAxis.flat, evdevAxis.fuzz, evdevAxis.resolution);
}

} // namespace

CapturedTouchpadEventConverter::CapturedTouchpadEventConverter(
@@ -108,8 +119,15 @@ std::string CapturedTouchpadEventConverter::dump() const {
}

void CapturedTouchpadEventConverter::populateMotionRanges(InputDeviceInfo& info) const {
    if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
        tryAddRawMotionRangeWithRelative(/*byref*/ info, AMOTION_EVENT_AXIS_X,
                                         AMOTION_EVENT_AXIS_RELATIVE_X, ABS_MT_POSITION_X);
        tryAddRawMotionRangeWithRelative(/*byref*/ info, AMOTION_EVENT_AXIS_Y,
                                         AMOTION_EVENT_AXIS_RELATIVE_Y, ABS_MT_POSITION_Y);
    } else {
        tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_X, ABS_MT_POSITION_X);
        tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_Y, ABS_MT_POSITION_Y);
    }
    tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOUCH_MAJOR, ABS_MT_TOUCH_MAJOR);
    tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOUCH_MINOR, ABS_MT_TOUCH_MINOR);
    tryAddRawMotionRange(/*byref*/ info, AMOTION_EVENT_AXIS_TOOL_MAJOR, ABS_MT_WIDTH_MAJOR);
@@ -135,8 +153,23 @@ void CapturedTouchpadEventConverter::tryAddRawMotionRange(InputDeviceInfo& devic
                                                          int32_t evdevAxis) const {
    std::optional<RawAbsoluteAxisInfo> info = mDeviceContext.getAbsoluteAxisInfo(evdevAxis);
    if (info) {
        deviceInfo.addMotionRange(androidAxis, SOURCE, info->minValue, info->maxValue, info->flat,
                                  info->fuzz, info->resolution);
        addRawMotionRange(/*byref*/ deviceInfo, androidAxis, *info);
    }
}

void CapturedTouchpadEventConverter::tryAddRawMotionRangeWithRelative(InputDeviceInfo& deviceInfo,
                                                                      int32_t androidAxis,
                                                                      int32_t androidRelativeAxis,
                                                                      int32_t evdevAxis) const {
    std::optional<RawAbsoluteAxisInfo> axisInfo = mDeviceContext.getAbsoluteAxisInfo(evdevAxis);
    if (axisInfo) {
        addRawMotionRange(/*byref*/ deviceInfo, androidAxis, *axisInfo);

        // The largest movement we could possibly report on a relative axis is from the minimum to
        // the maximum (or vice versa) of the absolute axis.
        float range = axisInfo->maxValue - axisInfo->minValue;
        deviceInfo.addMotionRange(androidRelativeAxis, SOURCE, -range, range, axisInfo->flat,
                                  axisInfo->fuzz, axisInfo->resolution);
    }
}

@@ -163,7 +196,7 @@ std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t
    std::list<NotifyArgs> out;
    std::vector<PointerCoords> coords;
    std::vector<PointerProperties> properties;
    std::map<size_t, size_t> coordsIndexForSlotNumber;
    std::map<size_t /*slotNumber*/, size_t /*coordsIndex*/> coordsIndexForSlotNumber;

    // For all the touches that were already down, send a MOVE event with their updated coordinates.
    // A convention of the MotionEvent API is that pointer coordinates in UP events match the
@@ -175,11 +208,19 @@ std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t
            // to stay perfectly still between frames, and if it does the worst that can happen is
            // an extra MOVE event, so it's not worth the overhead of checking for changes.
            coordsIndexForSlotNumber[slotNumber] = coords.size();
            coords.push_back(makePointerCoordsForSlot(mMotionAccumulator.getSlot(slotNumber)));
            coords.push_back(makePointerCoordsForSlot(slotNumber));
            properties.push_back({.id = pointerId, .toolType = ToolType::FINGER});
        }
        out.push_back(
                makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_MOVE, coords, properties));
        if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
            // For any further events we send from this sync, the pointers won't have moved relative
            // to the positions we just reported in this MOVE event, so zero out the relative axes.
            for (PointerCoords& pointer : coords) {
                pointer.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0);
                pointer.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0);
            }
        }
    }

    std::vector<size_t> upSlots, downSlots;
@@ -234,6 +275,9 @@ std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t
                                     /*flags=*/cancel ? AMOTION_EVENT_FLAG_CANCELED : 0));

        freePointerIdForSlot(slotNumber);
        if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
            mPreviousCoordsForSlotNumber.erase(slotNumber);
        }
        coords.erase(coords.begin() + indexToRemove);
        properties.erase(properties.begin() + indexToRemove);
        // Now that we've removed some coords and properties, we might have to update the slot
@@ -254,7 +298,7 @@ std::list<NotifyArgs> CapturedTouchpadEventConverter::sync(nsecs_t when, nsecs_t
                : actionWithIndex(AMOTION_EVENT_ACTION_POINTER_DOWN, coordsIndex);

        coordsIndexForSlotNumber[slotNumber] = coordsIndex;
        coords.push_back(makePointerCoordsForSlot(mMotionAccumulator.getSlot(slotNumber)));
        coords.push_back(makePointerCoordsForSlot(slotNumber));
        properties.push_back(
                {.id = allocatePointerIdToSlot(slotNumber), .toolType = ToolType::FINGER});

@@ -286,12 +330,22 @@ NotifyMotionArgs CapturedTouchpadEventConverter::makeMotionArgs(
                            AMOTION_EVENT_INVALID_CURSOR_POSITION, mDownTime, /*videoFrames=*/{});
}

PointerCoords CapturedTouchpadEventConverter::makePointerCoordsForSlot(
        const MultiTouchMotionAccumulator::Slot& slot) const {
PointerCoords CapturedTouchpadEventConverter::makePointerCoordsForSlot(size_t slotNumber) {
    const MultiTouchMotionAccumulator::Slot& slot = mMotionAccumulator.getSlot(slotNumber);
    PointerCoords coords;
    coords.clear();
    coords.setAxisValue(AMOTION_EVENT_AXIS_X, slot.getX());
    coords.setAxisValue(AMOTION_EVENT_AXIS_Y, slot.getY());
    if (input_flags::include_relative_axis_values_for_captured_touchpads()) {
        if (auto it = mPreviousCoordsForSlotNumber.find(slotNumber);
            it != mPreviousCoordsForSlotNumber.end()) {
            auto [oldX, oldY] = it->second;
            coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, slot.getX() - oldX);
            coords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, slot.getY() - oldY);
        }
        mPreviousCoordsForSlotNumber[slotNumber] = std::make_pair(slot.getX(), slot.getY());
    }

    coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, slot.getTouchMajor());
    coords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, slot.getTouchMinor());
    coords.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, slot.getToolMajor());
+5 −3
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <map>
#include <set>
#include <string>
#include <utility>
#include <vector>

#include <android/input.h>
@@ -49,12 +50,14 @@ public:
private:
    void tryAddRawMotionRange(InputDeviceInfo& deviceInfo, int32_t androidAxis,
                              int32_t evdevAxis) const;
    void tryAddRawMotionRangeWithRelative(InputDeviceInfo& deviceInfo, int32_t androidAxis,
                                          int32_t androidRelativeAxis, int32_t evdevAxis) const;
    [[nodiscard]] std::list<NotifyArgs> sync(nsecs_t when, nsecs_t readTime);
    [[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 flags = 0);
    PointerCoords makePointerCoordsForSlot(const MultiTouchMotionAccumulator::Slot& slot) const;
    PointerCoords makePointerCoordsForSlot(size_t slotNumber);
    int32_t allocatePointerIdToSlot(size_t slotNumber);
    void freePointerIdForSlot(size_t slotNumber);

@@ -76,8 +79,7 @@ private:

    std::bitset<MAX_POINTER_ID + 1> mPointerIdsInUse;
    std::map<size_t, int32_t> mPointerIdForSlotNumber;

    static constexpr uint32_t SOURCE = AINPUT_SOURCE_TOUCHPAD;
    std::map<size_t, std::pair<float, float>> mPreviousCoordsForSlotNumber;
};

} // namespace android
+111 −19
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <memory>

#include <EventHub.h>
#include <com_android_input_flags.h>
#include <gtest/gtest.h>
#include <linux/input-event-codes.h>
#include <linux/input.h>
@@ -32,6 +33,8 @@
#include "TestEventMatchers.h"
#include "TestInputListener.h"

namespace input_flags = com::android::input::flags;

namespace android {

using testing::AllOf;
@@ -47,6 +50,8 @@ public:
            mReader(mFakeEventHub, mFakePolicy, mFakeListener),
            mDevice(newDevice()),
            mDeviceContext(*mDevice, EVENTHUB_ID) {
        input_flags::include_relative_axis_values_for_captured_touchpads(true);

        const size_t slotCount = 8;
        mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_SLOT, 0, slotCount - 1, 0, 0, 0);
        mAccumulator.configure(mDeviceContext, slotCount, /*usingSlotsProtocol=*/true);
@@ -126,7 +131,7 @@ protected:

TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_allAxesPresent_populatedCorrectly) {
    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, 0, 4000, 0, 0, 45);
    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, 0, 2500, 0, 0, 40);
    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, -500, 2000, 0, 0, 40);
    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MAJOR, 0, 1100, 0, 0, 35);
    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MINOR, 0, 1000, 0, 0, 30);
    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MAJOR, 0, 900, 0, 0, 25);
@@ -150,8 +155,8 @@ TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_allAxesPresent_populated
    const InputDeviceInfo::MotionRange* posY =
            info.getMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TOUCHPAD);
    ASSERT_NE(nullptr, posY);
    EXPECT_NEAR(0, posY->min, EPSILON);
    EXPECT_NEAR(2500, posY->max, EPSILON);
    EXPECT_NEAR(-500, posY->min, EPSILON);
    EXPECT_NEAR(2000, posY->max, EPSILON);
    EXPECT_NEAR(40, posY->resolution, EPSILON);

    const InputDeviceInfo::MotionRange* touchMajor =
@@ -182,8 +187,22 @@ TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_allAxesPresent_populated
    EXPECT_NEAR(800, toolMinor->max, EPSILON);
    EXPECT_NEAR(20, toolMinor->resolution, EPSILON);

    // ...except orientation and pressure, which get scaled, and size, which is generated from other
    // values.
    // ...except for the relative motion axes, derived from the corresponding absolute ones:
    const InputDeviceInfo::MotionRange* relX =
            info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, AINPUT_SOURCE_TOUCHPAD);
    ASSERT_NE(nullptr, relX);
    EXPECT_NEAR(-4000, relX->min, EPSILON);
    EXPECT_NEAR(4000, relX->max, EPSILON);
    EXPECT_NEAR(45, relX->resolution, EPSILON);

    const InputDeviceInfo::MotionRange* relY =
            info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, AINPUT_SOURCE_TOUCHPAD);
    ASSERT_NE(nullptr, relY);
    EXPECT_NEAR(-2500, relY->min, EPSILON);
    EXPECT_NEAR(2500, relY->max, EPSILON);
    EXPECT_NEAR(40, relY->resolution, EPSILON);

    // ...orientation and pressure, which get scaled:
    const InputDeviceInfo::MotionRange* orientation =
            info.getMotionRange(AMOTION_EVENT_AXIS_ORIENTATION, AINPUT_SOURCE_TOUCHPAD);
    ASSERT_NE(nullptr, orientation);
@@ -198,6 +217,7 @@ TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_allAxesPresent_populated
    EXPECT_NEAR(1, pressure->max, EPSILON);
    EXPECT_NEAR(0, pressure->resolution, EPSILON);

    // ... and size, which is generated from other values.
    const InputDeviceInfo::MotionRange* size =
            info.getMotionRange(AMOTION_EVENT_AXIS_SIZE, AINPUT_SOURCE_TOUCHPAD);
    ASSERT_NE(nullptr, size);
@@ -219,7 +239,9 @@ TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_bareMinimumAxesPresent_p
    // present, since it's generated from axes that aren't provided by this device).
    EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_X, AINPUT_SOURCE_TOUCHPAD));
    EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_Y, AINPUT_SOURCE_TOUCHPAD));
    EXPECT_EQ(2u, info.getMotionRanges().size());
    EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, AINPUT_SOURCE_TOUCHPAD));
    EXPECT_NE(nullptr, info.getMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, AINPUT_SOURCE_TOUCHPAD));
    EXPECT_EQ(4u, info.getMotionRanges().size());
}

TEST_F(CapturedTouchpadEventConverterTest, OneFinger_motionReportedCorrectly) {
@@ -235,14 +257,16 @@ TEST_F(CapturedTouchpadEventConverterTest, OneFinger_motionReportedCorrectly) {

    EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
                      WithCoords(50, 100), WithToolType(ToolType::FINGER)));
                      WithCoords(50, 100), WithRelativeMotion(0, 0),
                      WithToolType(ToolType::FINGER)));

    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 99);

    EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u),
                      WithCoords(52, 99), WithToolType(ToolType::FINGER)));
                      WithCoords(52, 99), WithRelativeMotion(2, -1),
                      WithToolType(ToolType::FINGER)));

    processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1);
    processAxis(conv, EV_KEY, BTN_TOUCH, 0);
@@ -255,7 +279,8 @@ TEST_F(CapturedTouchpadEventConverterTest, OneFinger_motionReportedCorrectly) {
                            VariantWith<NotifyMotionArgs>(
                                    WithMotionAction(AMOTION_EVENT_ACTION_UP))));
    EXPECT_THAT(args,
                Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(52, 99), WithPointerCount(1u),
                Each(VariantWith<NotifyMotionArgs>(
                        AllOf(WithCoords(52, 99), WithRelativeMotion(0, 0), WithPointerCount(1u),
                              WithToolType(ToolType::FINGER)))));
}

@@ -507,13 +532,13 @@ TEST_F(CapturedTouchpadEventConverterTest, PalmTurningIntoFinger_reported) {

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

    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52);

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

TEST_F(CapturedTouchpadEventConverterTest, FingerArrivingAfterPalm_onlyFingerReported) {
@@ -553,7 +578,7 @@ TEST_F(CapturedTouchpadEventConverterTest, FingerArrivingAfterPalm_onlyFingerRep

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

TEST_F(CapturedTouchpadEventConverterTest, FingerAndFingerTurningIntoPalm_partiallyCancelled) {
@@ -660,7 +685,8 @@ TEST_F(CapturedTouchpadEventConverterTest, TwoFingers_motionReportedCorrectly) {

    EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
                      WithCoords(50, 100), WithToolType(ToolType::FINGER)));
                      WithCoords(50, 100), WithRelativeMotion(0, 0),
                      WithToolType(ToolType::FINGER)));

    processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 52);
@@ -678,13 +704,16 @@ TEST_F(CapturedTouchpadEventConverterTest, TwoFingers_motionReportedCorrectly) {
                ElementsAre(VariantWith<NotifyMotionArgs>(
                                    AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
                                          WithPointerCount(1u), WithCoords(52, 99),
                                          WithRelativeMotion(2, -1),
                                          WithToolType(ToolType::FINGER))),
                            VariantWith<NotifyMotionArgs>(
                                    AllOf(WithMotionAction(
                                                  AMOTION_EVENT_ACTION_POINTER_DOWN |
                                                  1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                                          WithPointerCount(2u), WithPointerCoords(0, 52, 99),
                                          WithPointerRelativeMotion(0, 0, 0),
                                          WithPointerCoords(1, 250, 200),
                                          WithPointerRelativeMotion(1, 0, 0),
                                          WithPointerToolType(0, ToolType::FINGER),
                                          WithPointerToolType(1, ToolType::FINGER)))));

@@ -700,14 +729,17 @@ TEST_F(CapturedTouchpadEventConverterTest, TwoFingers_motionReportedCorrectly) {
    std::list<NotifyArgs> args = processSync(conv);
    EXPECT_THAT(args,
                ElementsAre(VariantWith<NotifyMotionArgs>(
                                    WithMotionAction(AMOTION_EVENT_ACTION_MOVE)),
                            VariantWith<NotifyMotionArgs>(WithMotionAction(
                                    AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE),
                                          WithPointerRelativeMotion(1, 5, 2))),
                            VariantWith<NotifyMotionArgs>(
                                    AllOf(WithMotionAction(
                                                  AMOTION_EVENT_ACTION_POINTER_UP |
                                    0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT))));
                                                  0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                                          WithPointerRelativeMotion(1, 0, 0)))));
    EXPECT_THAT(args,
                Each(VariantWith<NotifyMotionArgs>(
                        AllOf(WithPointerCount(2u), WithPointerCoords(0, 52, 99),
                              WithPointerCoords(1, 255, 202),
                              WithPointerRelativeMotion(0, 0, 0), WithPointerCoords(1, 255, 202),
                              WithPointerToolType(1, ToolType::FINGER),
                              WithPointerToolType(0, ToolType::FINGER)))));

@@ -723,9 +755,69 @@ TEST_F(CapturedTouchpadEventConverterTest, TwoFingers_motionReportedCorrectly) {
                                    WithMotionAction(AMOTION_EVENT_ACTION_UP))));
    EXPECT_THAT(args,
                Each(VariantWith<NotifyMotionArgs>(AllOf(WithPointerCount(1u), WithCoords(255, 202),
                                                         WithRelativeMotion(0, 0),
                                                         WithToolType(ToolType::FINGER)))));
}

TEST_F(CapturedTouchpadEventConverterTest, RelativeMotionAxesClearedForNewFingerInSlot) {
    CapturedTouchpadEventConverter conv = createConverter();
    // Put down one finger.
    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_KEY, BTN_TOUCH, 1);
    processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);

    EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithPointerCount(1u),
                      WithCoords(50, 100), WithRelativeMotion(0, 0)));

    // Move it in negative X and Y directions.
    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 47);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 97);

    EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithCoords(47, 97),
                      WithRelativeMotion(-3, -3)));

    // Lift it.
    processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1);
    processAxis(conv, EV_KEY, BTN_TOUCH, 0);
    processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0);

    std::list<NotifyArgs> args = processSync(conv);
    EXPECT_THAT(args,
                ElementsAre(VariantWith<NotifyMotionArgs>(
                                    WithMotionAction(AMOTION_EVENT_ACTION_MOVE)),
                            VariantWith<NotifyMotionArgs>(
                                    WithMotionAction(AMOTION_EVENT_ACTION_UP))));
    EXPECT_THAT(args,
                Each(VariantWith<NotifyMotionArgs>(AllOf(WithCoords(47, 97),
                                                         WithRelativeMotion(0, 0),
                                                         WithPointerCount(1u)))));

    // Put down another finger using the same slot. Relative axis values should be cleared.
    processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 2);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 60);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 60);

    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), WithPointerCount(1u),
                      WithCoords(60, 60), WithRelativeMotion(0, 0)));

    processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 64);
    processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 58);

    EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
                AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u),
                      WithCoords(64, 58), WithRelativeMotion(4, -2)));
}

// Pointer IDs max out at 31, and so must be reused once a touch is lifted to avoid running out.
TEST_F(CapturedTouchpadEventConverterTest, PointerIdsReusedAfterLift) {
    CapturedTouchpadEventConverter conv = createConverter();
+58 −10

File changed.

Preview size limit exceeded, changes collapsed.