Merge "Add TouchIntegrationTest tests" into rvc-dev
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 3ae8b56..618aefc 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -1748,7 +1748,7 @@
virtual void SetUp() override {
mFakePolicy = new FakeInputReaderPolicy();
- mTestListener = new TestInputListener();
+ mTestListener = new TestInputListener(50ms);
mReader = new InputReader(std::make_shared<EventHub>(), mFakePolicy, mTestListener);
ASSERT_EQ(mReader->start(), OK);
@@ -1847,6 +1847,135 @@
ASSERT_LE(prevTimestamp, keyArgs.eventTime);
}
+// --- TouchProcessTest ---
+class TouchIntegrationTest : public InputReaderIntegrationTest {
+protected:
+ static const int32_t FIRST_SLOT = 0;
+ static const int32_t SECOND_SLOT = 1;
+ static const int32_t FIRST_TRACKING_ID = 0;
+ static const int32_t SECOND_TRACKING_ID = 1;
+ const std::string UNIQUE_ID = "local:0";
+
+ virtual void SetUp() override {
+ InputReaderIntegrationTest::SetUp();
+ // At least add an internal display.
+ setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ DISPLAY_ORIENTATION_0, UNIQUE_ID, NO_PORT,
+ ViewportType::VIEWPORT_INTERNAL);
+
+ mDevice = createUinputDevice<UinputTouchScreen>(Rect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT));
+ ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled());
+ }
+
+ void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height,
+ int32_t orientation, const std::string& uniqueId,
+ std::optional<uint8_t> physicalPort,
+ ViewportType viewportType) {
+ mFakePolicy->addDisplayViewport(displayId, width, height, orientation, uniqueId,
+ physicalPort, viewportType);
+ mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ }
+
+ std::unique_ptr<UinputTouchScreen> mDevice;
+};
+
+TEST_F(TouchIntegrationTest, InputEvent_ProcessSingleTouch) {
+ NotifyMotionArgs args;
+ const Point centerPoint = mDevice->getCenterPoint();
+
+ // ACTION_DOWN
+ mDevice->sendDown(centerPoint);
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
+
+ // ACTION_MOVE
+ mDevice->sendMove(centerPoint + Point(1, 1));
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
+
+ // ACTION_UP
+ mDevice->sendUp();
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action);
+}
+
+TEST_F(TouchIntegrationTest, InputEvent_ProcessMultiTouch) {
+ NotifyMotionArgs args;
+ const Point centerPoint = mDevice->getCenterPoint();
+
+ // ACTION_DOWN
+ mDevice->sendDown(centerPoint);
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
+
+ // ACTION_POINTER_DOWN (Second slot)
+ const Point secondPoint = centerPoint + Point(100, 100);
+ mDevice->sendSlot(SECOND_SLOT);
+ mDevice->sendTrackingId(SECOND_TRACKING_ID);
+ mDevice->sendDown(secondPoint + Point(1, 1));
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ args.action);
+
+ // ACTION_MOVE (Second slot)
+ mDevice->sendMove(secondPoint);
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
+
+ // ACTION_POINTER_UP (Second slot)
+ mDevice->sendUp();
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ args.action);
+
+ // ACTION_UP
+ mDevice->sendSlot(FIRST_SLOT);
+ mDevice->sendUp();
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action);
+}
+
+TEST_F(TouchIntegrationTest, InputEvent_ProcessPalm) {
+ NotifyMotionArgs args;
+ const Point centerPoint = mDevice->getCenterPoint();
+
+ // ACTION_DOWN
+ mDevice->sendDown(centerPoint);
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action);
+
+ // ACTION_POINTER_DOWN (Second slot)
+ const Point secondPoint = centerPoint + Point(100, 100);
+ mDevice->sendSlot(SECOND_SLOT);
+ mDevice->sendTrackingId(SECOND_TRACKING_ID);
+ mDevice->sendDown(secondPoint);
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ args.action);
+
+ // ACTION_MOVE (Second slot)
+ mDevice->sendMove(secondPoint + Point(1, 1));
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
+
+ // Send MT_TOOL_PALM, which indicates that the touch IC has determined this to be a grip event.
+ // Expect to receive ACTION_CANCEL, to abort the entire gesture.
+ mDevice->sendToolType(MT_TOOL_PALM);
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, args.action);
+
+ // ACTION_POINTER_UP (Second slot)
+ mDevice->sendUp();
+
+ // ACTION_UP
+ mDevice->sendSlot(FIRST_SLOT);
+ mDevice->sendUp();
+
+ // Expect no event received after abort the entire gesture.
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasNotCalled());
+}
+
// --- InputDeviceTest ---
class InputDeviceTest : public testing::Test {
protected:
@@ -7032,5 +7161,4 @@
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
ASSERT_EQ(SECONDARY_DISPLAY_ID, motionArgs.displayId);
}
-
} // namespace android
diff --git a/services/inputflinger/tests/TestInputListener.cpp b/services/inputflinger/tests/TestInputListener.cpp
index 06b05ac..86ff3b1 100644
--- a/services/inputflinger/tests/TestInputListener.cpp
+++ b/services/inputflinger/tests/TestInputListener.cpp
@@ -19,20 +19,11 @@
#include "TestInputListener.h"
-namespace {
-
-using std::chrono_literals::operator""ms;
-
-// Timeout for waiting for an expected event
-static constexpr std::chrono::duration WAIT_TIMEOUT = 5ms;
-
-} // namespace
-
namespace android {
// --- TestInputListener ---
-TestInputListener::TestInputListener() { }
+TestInputListener::TestInputListener(const std::chrono::milliseconds timeout) : mTimeout(timeout) {}
TestInputListener::~TestInputListener() { }
@@ -95,9 +86,9 @@
std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues);
if (queue.empty()) {
- const bool eventReceived =
- mCondition.wait_for(lock, WAIT_TIMEOUT,
- [&queue]() REQUIRES(mLock) { return !queue.empty(); });
+ const bool eventReceived = mCondition.wait_for(lock, mTimeout, [&queue]() REQUIRES(mLock) {
+ return !queue.empty();
+ });
if (!eventReceived) {
FAIL() << "Timed out waiting for event: " << message.c_str();
}
@@ -114,7 +105,7 @@
base::ScopedLockAssertion assumeLocked(mLock);
std::vector<NotifyArgsType>& queue = std::get<std::vector<NotifyArgsType>>(mQueues);
- const bool eventReceived = mCondition.wait_for(lock, WAIT_TIMEOUT, [&queue]() REQUIRES(mLock) {
+ const bool eventReceived = mCondition.wait_for(lock, mTimeout, [&queue]() REQUIRES(mLock) {
return !queue.empty();
});
if (eventReceived) {
diff --git a/services/inputflinger/tests/TestInputListener.h b/services/inputflinger/tests/TestInputListener.h
index 945e2ea..4262f5a 100644
--- a/services/inputflinger/tests/TestInputListener.h
+++ b/services/inputflinger/tests/TestInputListener.h
@@ -21,6 +21,8 @@
#include <gtest/gtest.h>
#include "InputListener.h"
+using std::chrono_literals::operator""ms;
+
namespace android {
// --- TestInputListener ---
@@ -30,7 +32,7 @@
virtual ~TestInputListener();
public:
- TestInputListener();
+ TestInputListener(const std::chrono::milliseconds timeout = 5ms);
void assertNotifyConfigurationChangedWasCalled(
NotifyConfigurationChangedArgs* outEventArgs = nullptr);
@@ -73,6 +75,7 @@
std::mutex mLock;
std::condition_variable mCondition;
+ const std::chrono::milliseconds mTimeout;
std::tuple<std::vector<NotifyConfigurationChangedArgs>, //
std::vector<NotifyDeviceResetArgs>, //
diff --git a/services/inputflinger/tests/UinputDevice.cpp b/services/inputflinger/tests/UinputDevice.cpp
index 2775d21..99480b7 100644
--- a/services/inputflinger/tests/UinputDevice.cpp
+++ b/services/inputflinger/tests/UinputDevice.cpp
@@ -119,7 +119,7 @@
EXPECT_NO_FATAL_FAILURE(releaseKey(key));
}
-// --- UinputHomeKey---
+// --- UinputHomeKey ---
UinputHomeKey::UinputHomeKey() : UinputKeyboard({KEY_HOME}) {}
@@ -127,4 +127,71 @@
EXPECT_NO_FATAL_FAILURE(pressAndReleaseKey(KEY_HOME));
}
+// --- UinputTouchScreen ---
+UinputTouchScreen::UinputTouchScreen(const Rect* size)
+ : UinputDevice(UinputTouchScreen::DEVICE_NAME), mSize(*size) {}
+
+void UinputTouchScreen::configureDevice(int fd, uinput_user_dev* device) {
+ // Setup the touch screen device
+ ioctl(fd, UI_SET_EVBIT, EV_KEY);
+ ioctl(fd, UI_SET_EVBIT, EV_REL);
+ ioctl(fd, UI_SET_EVBIT, EV_ABS);
+ ioctl(fd, UI_SET_ABSBIT, ABS_MT_SLOT);
+ ioctl(fd, UI_SET_ABSBIT, ABS_MT_TOUCH_MAJOR);
+ ioctl(fd, UI_SET_ABSBIT, ABS_MT_POSITION_X);
+ ioctl(fd, UI_SET_ABSBIT, ABS_MT_POSITION_Y);
+ ioctl(fd, UI_SET_ABSBIT, ABS_MT_TRACKING_ID);
+ ioctl(fd, UI_SET_ABSBIT, ABS_MT_TOOL_TYPE);
+ ioctl(fd, UI_SET_PROPBIT, INPUT_PROP_DIRECT);
+ ioctl(fd, UI_SET_KEYBIT, BTN_TOUCH);
+
+ device->absmin[ABS_MT_SLOT] = RAW_SLOT_MIN;
+ device->absmax[ABS_MT_SLOT] = RAW_SLOT_MAX;
+ device->absmin[ABS_MT_TOUCH_MAJOR] = RAW_TOUCH_MIN;
+ device->absmax[ABS_MT_TOUCH_MAJOR] = RAW_TOUCH_MAX;
+ device->absmin[ABS_MT_POSITION_X] = mSize.left;
+ device->absmax[ABS_MT_POSITION_X] = mSize.right - 1;
+ device->absmin[ABS_MT_POSITION_Y] = mSize.top;
+ device->absmax[ABS_MT_POSITION_Y] = mSize.bottom - 1;
+ device->absmin[ABS_MT_TRACKING_ID] = RAW_ID_MIN;
+ device->absmax[ABS_MT_TRACKING_ID] = RAW_ID_MAX;
+}
+
+void UinputTouchScreen::sendSlot(int32_t slot) {
+ EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_SLOT, slot));
+}
+
+void UinputTouchScreen::sendTrackingId(int32_t trackingId) {
+ EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_TRACKING_ID, trackingId));
+}
+
+void UinputTouchScreen::sendDown(const Point& point) {
+ EXPECT_NO_FATAL_FAILURE(injectEvent(EV_KEY, BTN_TOUCH, 1));
+ EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_POSITION_X, point.x));
+ EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_POSITION_Y, point.y));
+ EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0));
+}
+
+void UinputTouchScreen::sendMove(const Point& point) {
+ EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_POSITION_X, point.x));
+ EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_POSITION_Y, point.y));
+ EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0));
+}
+
+void UinputTouchScreen::sendUp() {
+ sendTrackingId(0xffffffff);
+ EXPECT_NO_FATAL_FAILURE(injectEvent(EV_KEY, BTN_TOUCH, 0));
+ EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0));
+}
+
+void UinputTouchScreen::sendToolType(int32_t toolType) {
+ EXPECT_NO_FATAL_FAILURE(injectEvent(EV_ABS, ABS_MT_TOOL_TYPE, toolType));
+ EXPECT_NO_FATAL_FAILURE(injectEvent(EV_SYN, SYN_REPORT, 0));
+}
+
+// Get the center x, y base on the range definition.
+const Point UinputTouchScreen::getCenterPoint() {
+ return Point(mSize.left + mSize.width() / 2, mSize.top + mSize.height() / 2);
+}
+
} // namespace android
diff --git a/services/inputflinger/tests/UinputDevice.h b/services/inputflinger/tests/UinputDevice.h
index 57d9011..ec3cd9f 100644
--- a/services/inputflinger/tests/UinputDevice.h
+++ b/services/inputflinger/tests/UinputDevice.h
@@ -22,6 +22,8 @@
#include <inttypes.h>
#include <linux/uinput.h>
#include <log/log.h>
+#include <ui/Point.h>
+#include <ui/Rect.h>
#include <memory>
@@ -106,6 +108,40 @@
UinputHomeKey();
};
+// --- UinputTouchScreen ---
+// A touch screen device with specific size.
+class UinputTouchScreen : public UinputDevice {
+public:
+ static constexpr const char* DEVICE_NAME = "Test Touch Screen";
+ static const int32_t RAW_TOUCH_MIN = 0;
+ static const int32_t RAW_TOUCH_MAX = 31;
+ static const int32_t RAW_ID_MIN = 0;
+ static const int32_t RAW_ID_MAX = 9;
+ static const int32_t RAW_SLOT_MIN = 0;
+ static const int32_t RAW_SLOT_MAX = 9;
+ static const int32_t RAW_PRESSURE_MIN = 0;
+ static const int32_t RAW_PRESSURE_MAX = 255;
+
+ template <class D, class... Ts>
+ friend std::unique_ptr<D> createUinputDevice(Ts... args);
+
+ void sendSlot(int32_t slot);
+ void sendTrackingId(int32_t trackingId);
+ void sendDown(const Point& point);
+ void sendMove(const Point& point);
+ void sendUp();
+ void sendToolType(int32_t toolType);
+
+ const Point getCenterPoint();
+
+protected:
+ UinputTouchScreen(const Rect* size);
+
+private:
+ void configureDevice(int fd, uinput_user_dev* device) override;
+ const Rect mSize;
+};
+
} // namespace android
#endif // _UI_TEST_INPUT_UINPUT_INJECTOR_H