| /* |
| * Copyright 2023 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <CapturedTouchpadEventConverter.h> |
| |
| #include <list> |
| #include <memory> |
| |
| #include <EventHub.h> |
| #include <gtest/gtest.h> |
| #include <linux/input-event-codes.h> |
| #include <linux/input.h> |
| #include <utils/StrongPointer.h> |
| |
| #include "FakeEventHub.h" |
| #include "FakeInputReaderPolicy.h" |
| #include "InstrumentedInputReader.h" |
| #include "TestConstants.h" |
| #include "TestEventMatchers.h" |
| #include "TestInputListener.h" |
| |
| namespace android { |
| |
| using testing::AllOf; |
| |
| class CapturedTouchpadEventConverterTest : public testing::Test { |
| public: |
| CapturedTouchpadEventConverterTest() |
| : mFakeEventHub(std::make_unique<FakeEventHub>()), |
| mFakePolicy(sp<FakeInputReaderPolicy>::make()), |
| mReader(mFakeEventHub, mFakePolicy, mFakeListener), |
| mDevice(newDevice()), |
| mDeviceContext(*mDevice, EVENTHUB_ID) { |
| const size_t slotCount = 8; |
| mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_SLOT, 0, slotCount - 1, 0, 0, 0); |
| mAccumulator.configure(mDeviceContext, slotCount, /*usingSlotsProtocol=*/true); |
| } |
| |
| protected: |
| static constexpr int32_t DEVICE_ID = END_RESERVED_ID + 1000; |
| static constexpr int32_t EVENTHUB_ID = 1; |
| |
| std::shared_ptr<InputDevice> newDevice() { |
| InputDeviceIdentifier identifier; |
| identifier.name = "device"; |
| identifier.location = "USB1"; |
| identifier.bus = 0; |
| std::shared_ptr<InputDevice> device = |
| std::make_shared<InputDevice>(mReader.getContext(), DEVICE_ID, /*generation=*/2, |
| identifier); |
| mReader.pushNextDevice(device); |
| mFakeEventHub->addDevice(EVENTHUB_ID, identifier.name, InputDeviceClass::TOUCHPAD, |
| identifier.bus); |
| mReader.loopOnce(); |
| return device; |
| } |
| |
| void addBasicAxesToEventHub() { |
| 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_PRESSURE, 0, 256, 0, 0, 0); |
| mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MAJOR, 0, 1000, 0, 0, 0); |
| mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MINOR, 0, 1000, 0, 0, 0); |
| } |
| |
| CapturedTouchpadEventConverter createConverter() { |
| addBasicAxesToEventHub(); |
| return CapturedTouchpadEventConverter(*mReader.getContext(), mDeviceContext, mAccumulator, |
| DEVICE_ID); |
| } |
| |
| void processAxis(CapturedTouchpadEventConverter& conv, int32_t type, int32_t code, |
| int32_t value) { |
| RawEvent event; |
| event.when = ARBITRARY_TIME; |
| event.readTime = READ_TIME; |
| event.deviceId = EVENTHUB_ID; |
| event.type = type; |
| event.code = code; |
| event.value = value; |
| std::list<NotifyArgs> out = conv.process(event); |
| EXPECT_TRUE(out.empty()); |
| } |
| |
| std::list<NotifyArgs> processSync(CapturedTouchpadEventConverter& conv) { |
| RawEvent event; |
| event.when = ARBITRARY_TIME; |
| event.readTime = READ_TIME; |
| event.deviceId = EVENTHUB_ID; |
| event.type = EV_SYN; |
| event.code = SYN_REPORT; |
| event.value = 0; |
| return conv.process(event); |
| } |
| |
| NotifyMotionArgs processSyncAndExpectSingleMotionArg(CapturedTouchpadEventConverter& conv) { |
| std::list<NotifyArgs> args = processSync(conv); |
| EXPECT_EQ(1u, args.size()); |
| return std::get<NotifyMotionArgs>(args.front()); |
| } |
| |
| std::shared_ptr<FakeEventHub> mFakeEventHub; |
| sp<FakeInputReaderPolicy> mFakePolicy; |
| TestInputListener mFakeListener; |
| InstrumentedInputReader mReader; |
| std::shared_ptr<InputDevice> mDevice; |
| InputDeviceContext mDeviceContext; |
| MultiTouchMotionAccumulator mAccumulator; |
| }; |
| |
| 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_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); |
| mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MINOR, 0, 800, 0, 0, 20); |
| mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_ORIENTATION, -3, 4, 0, 0, 0); |
| mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_PRESSURE, 0, 256, 0, 0, 0); |
| CapturedTouchpadEventConverter conv(*mReader.getContext(), mDeviceContext, mAccumulator, |
| DEVICE_ID); |
| |
| InputDeviceInfo info; |
| conv.populateMotionRanges(info); |
| |
| // Most axes should have min, max, and resolution matching the evdev axes. |
| const InputDeviceInfo::MotionRange* posX = |
| info.getMotionRange(AMOTION_EVENT_AXIS_X, AINPUT_SOURCE_TOUCHPAD); |
| ASSERT_NE(nullptr, posX); |
| EXPECT_NEAR(0, posX->min, EPSILON); |
| EXPECT_NEAR(4000, posX->max, EPSILON); |
| EXPECT_NEAR(45, posX->resolution, EPSILON); |
| |
| 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(40, posY->resolution, EPSILON); |
| |
| const InputDeviceInfo::MotionRange* touchMajor = |
| info.getMotionRange(AMOTION_EVENT_AXIS_TOUCH_MAJOR, AINPUT_SOURCE_TOUCHPAD); |
| ASSERT_NE(nullptr, touchMajor); |
| EXPECT_NEAR(0, touchMajor->min, EPSILON); |
| EXPECT_NEAR(1100, touchMajor->max, EPSILON); |
| EXPECT_NEAR(35, touchMajor->resolution, EPSILON); |
| |
| const InputDeviceInfo::MotionRange* touchMinor = |
| info.getMotionRange(AMOTION_EVENT_AXIS_TOUCH_MINOR, AINPUT_SOURCE_TOUCHPAD); |
| ASSERT_NE(nullptr, touchMinor); |
| EXPECT_NEAR(0, touchMinor->min, EPSILON); |
| EXPECT_NEAR(1000, touchMinor->max, EPSILON); |
| EXPECT_NEAR(30, touchMinor->resolution, EPSILON); |
| |
| const InputDeviceInfo::MotionRange* toolMajor = |
| info.getMotionRange(AMOTION_EVENT_AXIS_TOOL_MAJOR, AINPUT_SOURCE_TOUCHPAD); |
| ASSERT_NE(nullptr, toolMajor); |
| EXPECT_NEAR(0, toolMajor->min, EPSILON); |
| EXPECT_NEAR(900, toolMajor->max, EPSILON); |
| EXPECT_NEAR(25, toolMajor->resolution, EPSILON); |
| |
| const InputDeviceInfo::MotionRange* toolMinor = |
| info.getMotionRange(AMOTION_EVENT_AXIS_TOOL_MINOR, AINPUT_SOURCE_TOUCHPAD); |
| ASSERT_NE(nullptr, toolMinor); |
| EXPECT_NEAR(0, toolMinor->min, EPSILON); |
| 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. |
| const InputDeviceInfo::MotionRange* orientation = |
| info.getMotionRange(AMOTION_EVENT_AXIS_ORIENTATION, AINPUT_SOURCE_TOUCHPAD); |
| ASSERT_NE(nullptr, orientation); |
| EXPECT_NEAR(-M_PI_2, orientation->min, EPSILON); |
| EXPECT_NEAR(M_PI_2, orientation->max, EPSILON); |
| EXPECT_NEAR(0, orientation->resolution, EPSILON); |
| |
| const InputDeviceInfo::MotionRange* pressure = |
| info.getMotionRange(AMOTION_EVENT_AXIS_PRESSURE, AINPUT_SOURCE_TOUCHPAD); |
| ASSERT_NE(nullptr, pressure); |
| EXPECT_NEAR(0, pressure->min, EPSILON); |
| EXPECT_NEAR(1, pressure->max, EPSILON); |
| EXPECT_NEAR(0, pressure->resolution, EPSILON); |
| |
| const InputDeviceInfo::MotionRange* size = |
| info.getMotionRange(AMOTION_EVENT_AXIS_SIZE, AINPUT_SOURCE_TOUCHPAD); |
| ASSERT_NE(nullptr, size); |
| EXPECT_NEAR(0, size->min, EPSILON); |
| EXPECT_NEAR(1, size->max, EPSILON); |
| EXPECT_NEAR(0, size->resolution, EPSILON); |
| } |
| |
| TEST_F(CapturedTouchpadEventConverterTest, MotionRanges_bareMinimumAxesPresent_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); |
| CapturedTouchpadEventConverter conv(*mReader.getContext(), mDeviceContext, mAccumulator, |
| DEVICE_ID); |
| |
| InputDeviceInfo info; |
| conv.populateMotionRanges(info); |
| |
| // Only the bare minimum motion ranges should be reported, and no others (e.g. size shouldn't be |
| // 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()); |
| } |
| |
| TEST_F(CapturedTouchpadEventConverterTest, OneFinger_motionReportedCorrectly) { |
| CapturedTouchpadEventConverter conv = createConverter(); |
| |
| 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), 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))); |
| |
| 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); |
| ASSERT_EQ(2u, args.size()); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u), |
| WithCoords(52, 99), WithToolType(ToolType::FINGER))); |
| args.pop_front(); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithPointerCount(1u), |
| WithCoords(52, 99), WithToolType(ToolType::FINGER))); |
| } |
| |
| TEST_F(CapturedTouchpadEventConverterTest, OneFinger_touchDimensionsPassedThrough) { |
| addBasicAxesToEventHub(); |
| mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MAJOR, 0, 1000, 0, 0, 0); |
| mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MINOR, 0, 1000, 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_TOUCH_MAJOR, 250); |
| processAxis(conv, EV_ABS, ABS_MT_TOUCH_MINOR, 120); |
| processAxis(conv, EV_ABS, ABS_MT_WIDTH_MAJOR, 400); |
| processAxis(conv, EV_ABS, ABS_MT_WIDTH_MINOR, 200); |
| |
| 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), |
| WithTouchDimensions(250, 120), WithToolDimensions(400, 200))); |
| } |
| |
| TEST_F(CapturedTouchpadEventConverterTest, OneFinger_orientationCalculatedCorrectly) { |
| addBasicAxesToEventHub(); |
| mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_ORIENTATION, -3, 4, 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_ORIENTATION, -3); |
| processAxis(conv, EV_KEY, BTN_TOUCH, 1); |
| processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1); |
| |
| EXPECT_NEAR(-3 * M_PI / 8, |
| processSyncAndExpectSingleMotionArg(conv).pointerCoords[0].getAxisValue( |
| AMOTION_EVENT_AXIS_ORIENTATION), |
| EPSILON); |
| |
| processAxis(conv, EV_ABS, ABS_MT_ORIENTATION, 0); |
| |
| EXPECT_NEAR(0, |
| processSyncAndExpectSingleMotionArg(conv).pointerCoords[0].getAxisValue( |
| AMOTION_EVENT_AXIS_ORIENTATION), |
| EPSILON); |
| |
| processAxis(conv, EV_ABS, ABS_MT_ORIENTATION, 4); |
| |
| EXPECT_NEAR(M_PI / 2, |
| processSyncAndExpectSingleMotionArg(conv).pointerCoords[0].getAxisValue( |
| AMOTION_EVENT_AXIS_ORIENTATION), |
| EPSILON); |
| } |
| |
| TEST_F(CapturedTouchpadEventConverterTest, OneFinger_pressureScaledCorrectly) { |
| 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_PRESSURE, 0, 256, 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_PRESSURE, 128); |
| processAxis(conv, EV_KEY, BTN_TOUCH, 1); |
| processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1); |
| |
| EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv), WithPressure(0.5)); |
| } |
| |
| TEST_F(CapturedTouchpadEventConverterTest, |
| OneFinger_withAllSizeAxes_sizeCalculatedFromTouchMajorMinorAverage) { |
| 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_TOUCH_MAJOR, 0, 256, 0, 0, 0); |
| mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MINOR, 0, 256, 0, 0, 0); |
| mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MAJOR, 0, 256, 0, 0, 0); |
| mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MINOR, 0, 256, 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_TOUCH_MAJOR, 138); |
| processAxis(conv, EV_ABS, ABS_MT_TOUCH_MINOR, 118); |
| processAxis(conv, EV_ABS, ABS_MT_WIDTH_MAJOR, 200); |
| processAxis(conv, EV_ABS, ABS_MT_WIDTH_MINOR, 210); |
| processAxis(conv, EV_KEY, BTN_TOUCH, 1); |
| processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1); |
| |
| EXPECT_NEAR(0.5, |
| processSyncAndExpectSingleMotionArg(conv).pointerCoords[0].getAxisValue( |
| AMOTION_EVENT_AXIS_SIZE), |
| EPSILON); |
| } |
| |
| TEST_F(CapturedTouchpadEventConverterTest, |
| OneFinger_withMajorDimensionsOnly_sizeCalculatedFromTouchMajor) { |
| 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_TOUCH_MAJOR, 0, 256, 0, 0, 0); |
| mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MAJOR, 0, 256, 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_TOUCH_MAJOR, 128); |
| processAxis(conv, EV_ABS, ABS_MT_WIDTH_MAJOR, 200); |
| processAxis(conv, EV_KEY, BTN_TOUCH, 1); |
| processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1); |
| |
| EXPECT_NEAR(0.5, |
| processSyncAndExpectSingleMotionArg(conv).pointerCoords[0].getAxisValue( |
| AMOTION_EVENT_AXIS_SIZE), |
| EPSILON); |
| } |
| |
| TEST_F(CapturedTouchpadEventConverterTest, |
| OneFinger_withToolDimensionsOnly_sizeCalculatedFromToolMajorMinorAverage) { |
| 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_WIDTH_MAJOR, 0, 256, 0, 0, 0); |
| mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MINOR, 0, 256, 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_WIDTH_MAJOR, 138); |
| processAxis(conv, EV_ABS, ABS_MT_WIDTH_MINOR, 118); |
| processAxis(conv, EV_KEY, BTN_TOUCH, 1); |
| processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1); |
| |
| EXPECT_NEAR(0.5, |
| processSyncAndExpectSingleMotionArg(conv).pointerCoords[0].getAxisValue( |
| AMOTION_EVENT_AXIS_SIZE), |
| EPSILON); |
| } |
| |
| TEST_F(CapturedTouchpadEventConverterTest, |
| OneFinger_withToolMajorOnly_sizeCalculatedFromTouchMajor) { |
| 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_WIDTH_MAJOR, 0, 256, 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_WIDTH_MAJOR, 128); |
| processAxis(conv, EV_KEY, BTN_TOUCH, 1); |
| processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1); |
| |
| EXPECT_NEAR(0.5, |
| processSyncAndExpectSingleMotionArg(conv).pointerCoords[0].getAxisValue( |
| AMOTION_EVENT_AXIS_SIZE), |
| 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(); |
| |
| 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), WithToolType(ToolType::FINGER))); |
| |
| 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, 99); |
| |
| 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_POSITION_Y, 200); |
| |
| processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0); |
| 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_MOVE), WithPointerCount(1u), |
| WithCoords(52, 99), 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), WithPointerCoords(0, 52, 99), |
| WithPointerCoords(1, 250, 200), WithPointerToolType(0, ToolType::FINGER), |
| WithPointerToolType(1, ToolType::FINGER))); |
| |
| processAxis(conv, EV_ABS, ABS_MT_SLOT, 0); |
| processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1); |
| processAxis(conv, EV_ABS, ABS_MT_SLOT, 1); |
| processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 255); |
| processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 202); |
| |
| processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1); |
| processAxis(conv, EV_KEY, BTN_TOOL_DOUBLETAP, 0); |
| |
| args = processSync(conv); |
| ASSERT_EQ(2u, args.size()); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(2u), |
| WithPointerCoords(0, 52, 99), WithPointerCoords(1, 255, 202), |
| WithPointerToolType(1, ToolType::FINGER), |
| WithPointerToolType(0, ToolType::FINGER))); |
| args.pop_front(); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | |
| 0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), |
| WithPointerCount(2u), WithPointerCoords(0, 52, 99), |
| WithPointerCoords(1, 255, 202), WithPointerToolType(0, ToolType::FINGER), |
| WithPointerToolType(1, ToolType::FINGER))); |
| |
| processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1); |
| processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0); |
| processAxis(conv, EV_KEY, BTN_TOUCH, 0); |
| |
| args = processSync(conv); |
| ASSERT_EQ(2u, args.size()); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(1u), |
| WithCoords(255, 202), WithToolType(ToolType::FINGER))); |
| args.pop_front(); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithPointerCount(1u), |
| WithCoords(255, 202), WithToolType(ToolType::FINGER))); |
| } |
| |
| // 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(); |
| |
| // Put down two fingers, which should get IDs 0 and 1. |
| 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, 10); |
| 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, 20); |
| |
| 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), |
| WithPointerId(/*index=*/0, /*id=*/0))); |
| 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), WithPointerId(/*index=*/0, /*id=*/0), |
| WithPointerId(/*index=*/1, /*id=*/1))); |
| |
| // Lift the finger in slot 0, freeing up pointer ID 0... |
| processAxis(conv, EV_ABS, ABS_MT_SLOT, 0); |
| processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1); |
| |
| // ...and simultaneously add a finger in slot 2. |
| processAxis(conv, EV_ABS, ABS_MT_SLOT, 2); |
| processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 3); |
| processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 30); |
| |
| args = processSync(conv); |
| ASSERT_EQ(3u, args.size()); |
| // Slot 1 being present will result in a MOVE event, even though it hasn't actually moved (see |
| // comments in CapturedTouchpadEventConverter::sync). |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithPointerCount(2u), |
| WithPointerId(/*index=*/0, /*id=*/0), WithPointerId(/*index=*/1, /*id=*/1))); |
| args.pop_front(); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_UP | |
| 0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), |
| WithPointerCount(2u), WithPointerId(/*index=*/0, /*id=*/0), |
| WithPointerId(/*index=*/1, /*id=*/1))); |
| args.pop_front(); |
| // Slot 0 being lifted causes the finger from slot 1 to move up to index 0, but keep its |
| // previous ID. The new finger in slot 2 should take ID 0, which was just freed up. |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| AllOf(WithMotionAction(AMOTION_EVENT_ACTION_POINTER_DOWN | |
| 1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT), |
| WithPointerCount(2u), WithPointerId(/*index=*/0, /*id=*/1), |
| WithPointerId(/*index=*/1, /*id=*/0))); |
| } |
| |
| // Motion events without any pointers are invalid, so when a button press is reported in the same |
| // frame as a touch down, the button press must be reported second. Similarly with a button release |
| // and a touch lift. |
| TEST_F(CapturedTouchpadEventConverterTest, |
| ButtonPressedAndReleasedInSameFrameAsTouch_ReportedWithPointers) { |
| CapturedTouchpadEventConverter conv = createConverter(); |
| |
| 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); |
| |
| processAxis(conv, EV_KEY, BTN_LEFT, 1); |
| |
| std::list<NotifyArgs> args = processSync(conv); |
| ASSERT_EQ(2u, args.size()); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); |
| args.pop_front(); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), WithPointerCount(1u), |
| WithCoords(50, 100), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), |
| WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY))); |
| |
| processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1); |
| processAxis(conv, EV_KEY, BTN_TOUCH, 0); |
| processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0); |
| |
| processAxis(conv, EV_KEY, BTN_LEFT, 0); |
| args = processSync(conv); |
| ASSERT_EQ(3u, args.size()); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| WithMotionAction(AMOTION_EVENT_ACTION_MOVE)); |
| args.pop_front(); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), WithPointerCount(1u), |
| WithCoords(50, 100), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), |
| WithButtonState(0))); |
| args.pop_front(); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| WithMotionAction(AMOTION_EVENT_ACTION_UP)); |
| } |
| |
| // Some touchpads sometimes report a button press before they report the finger touching the pad. In |
| // that case we need to wait until the touch comes to report the button press. |
| TEST_F(CapturedTouchpadEventConverterTest, ButtonPressedBeforeTouch_ReportedOnceTouchOccurs) { |
| CapturedTouchpadEventConverter conv = createConverter(); |
| |
| processAxis(conv, EV_KEY, BTN_LEFT, 1); |
| ASSERT_EQ(0u, processSync(conv).size()); |
| |
| 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); |
| |
| std::list<NotifyArgs> args = processSync(conv); |
| ASSERT_EQ(2u, args.size()); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); |
| args.pop_front(); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), WithPointerCount(1u), |
| WithCoords(50, 100), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), |
| WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY))); |
| } |
| |
| // When all fingers are lifted from a touchpad, we should release any buttons that are down, since |
| // we won't be able to report them being lifted later if no pointers are present. |
| TEST_F(CapturedTouchpadEventConverterTest, ButtonReleasedAfterTouchLifts_ReportedWithLift) { |
| CapturedTouchpadEventConverter conv = createConverter(); |
| |
| 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); |
| |
| processAxis(conv, EV_KEY, BTN_LEFT, 1); |
| |
| std::list<NotifyArgs> args = processSync(conv); |
| ASSERT_EQ(2u, args.size()); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); |
| args.pop_front(); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS)); |
| |
| processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1); |
| processAxis(conv, EV_KEY, BTN_TOUCH, 0); |
| processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0); |
| args = processSync(conv); |
| ASSERT_EQ(3u, args.size()); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| WithMotionAction(AMOTION_EVENT_ACTION_MOVE)); |
| args.pop_front(); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), WithPointerCount(1u), |
| WithCoords(50, 100), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), |
| WithButtonState(0))); |
| args.pop_front(); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| WithMotionAction(AMOTION_EVENT_ACTION_UP)); |
| |
| processAxis(conv, EV_KEY, BTN_LEFT, 0); |
| ASSERT_EQ(0u, processSync(conv).size()); |
| } |
| |
| TEST_F(CapturedTouchpadEventConverterTest, MultipleButtonsPressedDuringTouch_ReportedCorrectly) { |
| CapturedTouchpadEventConverter conv = createConverter(); |
| |
| 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), |
| WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); |
| |
| processAxis(conv, EV_KEY, BTN_LEFT, 1); |
| std::list<NotifyArgs> args = processSync(conv); |
| ASSERT_EQ(2u, args.size()); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| WithMotionAction(AMOTION_EVENT_ACTION_MOVE)); |
| args.pop_front(); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), |
| WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), |
| WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY))); |
| |
| processAxis(conv, EV_KEY, BTN_RIGHT, 1); |
| args = processSync(conv); |
| ASSERT_EQ(2u, args.size()); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| WithMotionAction(AMOTION_EVENT_ACTION_MOVE)); |
| args.pop_front(); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), |
| WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), |
| WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY | |
| AMOTION_EVENT_BUTTON_SECONDARY))); |
| |
| processAxis(conv, EV_KEY, BTN_LEFT, 0); |
| args = processSync(conv); |
| ASSERT_EQ(2u, args.size()); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| WithMotionAction(AMOTION_EVENT_ACTION_MOVE)); |
| args.pop_front(); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), |
| WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY), |
| WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY))); |
| |
| processAxis(conv, EV_KEY, BTN_RIGHT, 0); |
| args = processSync(conv); |
| ASSERT_EQ(2u, args.size()); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| WithMotionAction(AMOTION_EVENT_ACTION_MOVE)); |
| args.pop_front(); |
| EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()), |
| AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), |
| WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), WithButtonState(0))); |
| } |
| |
| } // namespace android |