From fd97e9d9ceadcbd129f67b984dd84556c0588c04 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 4 Jan 2022 16:59:04 -0800 Subject: Add integration test that clarifies behaviour of ACTION_POINTER_UP This test shows what will happen when a pointer goes up. For example, if a pointer goes up at the same time as another pointer moves, which will happen first, MOVE or POINTER_UP? This integration test explores these behaviours. We need to know this behaviour because later, if we want to suppress a pointer, we need to be able to cancel pointers without losing information about motions of other pointers. Bug: 198472780 Test: atest inputflinger_tests Change-Id: Ie56cca1324ffdd777eecbd0c6a2fe413d59f241a --- services/inputflinger/tests/InputReader_test.cpp | 127 ++++++++++++++++++++++- services/inputflinger/tests/UinputDevice.cpp | 7 +- services/inputflinger/tests/UinputDevice.h | 1 + 3 files changed, 129 insertions(+), 6 deletions(-) diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 068e03c4fd..2c5b32140d 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -2330,6 +2330,17 @@ protected: mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO); } + void assertReceivedMotion(int32_t action, const std::vector& points) { + NotifyMotionArgs args; + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); + EXPECT_EQ(action, args.action); + ASSERT_EQ(points.size(), args.pointerCount); + for (size_t i = 0; i < args.pointerCount; i++) { + EXPECT_EQ(points[i].x, args.pointerCoords[i].getX()); + EXPECT_EQ(points[i].y, args.pointerCoords[i].getY()); + } + } + std::unique_ptr mDevice; }; @@ -2340,16 +2351,19 @@ TEST_F(TouchIntegrationTest, InputEvent_ProcessSingleTouch) { // ACTION_DOWN mDevice->sendTrackingId(FIRST_TRACKING_ID); mDevice->sendDown(centerPoint); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); // ACTION_MOVE mDevice->sendMove(centerPoint + Point(1, 1)); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); // ACTION_UP mDevice->sendUp(); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); } @@ -2362,6 +2376,7 @@ TEST_F(TouchIntegrationTest, InputEvent_ProcessMultiTouch) { mDevice->sendSlot(FIRST_SLOT); mDevice->sendTrackingId(FIRST_TRACKING_ID); mDevice->sendDown(centerPoint); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); @@ -2369,27 +2384,129 @@ TEST_F(TouchIntegrationTest, InputEvent_ProcessMultiTouch) { const Point secondPoint = centerPoint + Point(100, 100); mDevice->sendSlot(SECOND_SLOT); mDevice->sendTrackingId(SECOND_TRACKING_ID); - mDevice->sendDown(secondPoint + Point(1, 1)); + mDevice->sendDown(secondPoint); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(ACTION_POINTER_1_DOWN, args.action); // ACTION_MOVE (Second slot) - mDevice->sendMove(secondPoint); + mDevice->sendMove(secondPoint + Point(1, 1)); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); // ACTION_POINTER_UP (Second slot) mDevice->sendPointerUp(); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(ACTION_POINTER_1_UP, args.action); // ACTION_UP mDevice->sendSlot(FIRST_SLOT); mDevice->sendUp(); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); } +/** + * What happens when a pointer goes up while another pointer moves in the same frame? Are POINTER_UP + * events guaranteed to contain the same data as a preceding MOVE, or can they contain different + * data? + * In this test, we try to send a change in coordinates in Pointer 0 in the same frame as the + * liftoff of Pointer 1. We check that POINTER_UP event is generated first, and the MOVE event + * for Pointer 0 only is generated after. + * Suppose we are only interested in learning the movement of Pointer 0. If we only observe MOVE + * events, we will not miss any information. + * Even though the Pointer 1 up event contains updated Pointer 0 coordinates, there is another MOVE + * event generated afterwards that contains the newest movement of pointer 0. + * This is important for palm rejection. If there is a subsequent InputListener stage that detects + * palms, and wants to cancel Pointer 1, then it is safe to simply drop POINTER_1_UP event without + * losing information about non-palm pointers. + */ +TEST_F(TouchIntegrationTest, MultiTouch_PointerMoveAndSecondPointerUp) { + NotifyMotionArgs args; + const Point centerPoint = mDevice->getCenterPoint(); + + // ACTION_DOWN + mDevice->sendSlot(FIRST_SLOT); + mDevice->sendTrackingId(FIRST_TRACKING_ID); + mDevice->sendDown(centerPoint); + mDevice->sendSync(); + assertReceivedMotion(AMOTION_EVENT_ACTION_DOWN, {centerPoint}); + + // ACTION_POINTER_DOWN (Second slot) + const Point secondPoint = centerPoint + Point(100, 100); + mDevice->sendSlot(SECOND_SLOT); + mDevice->sendTrackingId(SECOND_TRACKING_ID); + mDevice->sendDown(secondPoint); + mDevice->sendSync(); + assertReceivedMotion(ACTION_POINTER_1_DOWN, {centerPoint, secondPoint}); + + // ACTION_MOVE (First slot) + mDevice->sendSlot(FIRST_SLOT); + mDevice->sendMove(centerPoint + Point(5, 5)); + // ACTION_POINTER_UP (Second slot) + mDevice->sendSlot(SECOND_SLOT); + mDevice->sendPointerUp(); + // Send a single sync for the above 2 pointer updates + mDevice->sendSync(); + + // First, we should get POINTER_UP for the second pointer + assertReceivedMotion(ACTION_POINTER_1_UP, + {/*first pointer */ centerPoint + Point(5, 5), + /*second pointer*/ secondPoint}); + + // Next, the MOVE event for the first pointer + assertReceivedMotion(AMOTION_EVENT_ACTION_MOVE, {centerPoint + Point(5, 5)}); +} + +/** + * Similar scenario as above. The difference is that when the second pointer goes up, it will first + * move, and then it will go up, all in the same frame. + * In this scenario, the movement of the second pointer just prior to liftoff is ignored, and never + * gets sent to the listener. + */ +TEST_F(TouchIntegrationTest, MultiTouch_PointerMoveAndSecondPointerMoveAndUp) { + NotifyMotionArgs args; + const Point centerPoint = mDevice->getCenterPoint(); + + // ACTION_DOWN + mDevice->sendSlot(FIRST_SLOT); + mDevice->sendTrackingId(FIRST_TRACKING_ID); + mDevice->sendDown(centerPoint); + mDevice->sendSync(); + assertReceivedMotion(AMOTION_EVENT_ACTION_DOWN, {centerPoint}); + + // ACTION_POINTER_DOWN (Second slot) + const Point secondPoint = centerPoint + Point(100, 100); + mDevice->sendSlot(SECOND_SLOT); + mDevice->sendTrackingId(SECOND_TRACKING_ID); + mDevice->sendDown(secondPoint); + mDevice->sendSync(); + assertReceivedMotion(ACTION_POINTER_1_DOWN, {centerPoint, secondPoint}); + + // ACTION_MOVE (First slot) + mDevice->sendSlot(FIRST_SLOT); + mDevice->sendMove(centerPoint + Point(5, 5)); + // ACTION_POINTER_UP (Second slot) + mDevice->sendSlot(SECOND_SLOT); + mDevice->sendMove(secondPoint + Point(6, 6)); + mDevice->sendPointerUp(); + // Send a single sync for the above 2 pointer updates + mDevice->sendSync(); + + // First, we should get POINTER_UP for the second pointer + // The movement of the second pointer during the liftoff frame is ignored. + // The coordinates 'secondPoint + Point(6, 6)' are never sent to the listener. + assertReceivedMotion(ACTION_POINTER_1_UP, + {/*first pointer */ centerPoint + Point(5, 5), + /*second pointer*/ secondPoint}); + + // Next, the MOVE event for the first pointer + assertReceivedMotion(AMOTION_EVENT_ACTION_MOVE, {centerPoint + Point(5, 5)}); +} + TEST_F(TouchIntegrationTest, InputEvent_ProcessPalm) { NotifyMotionArgs args; const Point centerPoint = mDevice->getCenterPoint(); @@ -2398,6 +2515,7 @@ TEST_F(TouchIntegrationTest, InputEvent_ProcessPalm) { mDevice->sendSlot(FIRST_SLOT); mDevice->sendTrackingId(FIRST_TRACKING_ID); mDevice->sendDown(centerPoint); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, args.action); @@ -2406,11 +2524,13 @@ TEST_F(TouchIntegrationTest, InputEvent_ProcessPalm) { mDevice->sendSlot(SECOND_SLOT); mDevice->sendTrackingId(SECOND_TRACKING_ID); mDevice->sendDown(secondPoint); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(ACTION_POINTER_1_DOWN, args.action); // ACTION_MOVE (second slot) mDevice->sendMove(secondPoint + Point(1, 1)); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); @@ -2418,18 +2538,21 @@ TEST_F(TouchIntegrationTest, InputEvent_ProcessPalm) { // a palm event. // Expect to receive the ACTION_POINTER_UP with cancel flag. mDevice->sendToolType(MT_TOOL_PALM); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(ACTION_POINTER_1_UP, args.action); ASSERT_EQ(AMOTION_EVENT_FLAG_CANCELED, args.flags); // Send up to second slot, expect first slot send moving. mDevice->sendPointerUp(); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action); // Send ACTION_UP (first slot) mDevice->sendSlot(FIRST_SLOT); mDevice->sendUp(); + mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); diff --git a/services/inputflinger/tests/UinputDevice.cpp b/services/inputflinger/tests/UinputDevice.cpp index 7fec2c8b4b..132b877bb9 100644 --- a/services/inputflinger/tests/UinputDevice.cpp +++ b/services/inputflinger/tests/UinputDevice.cpp @@ -170,28 +170,27 @@ void UinputTouchScreen::sendDown(const Point& point) { injectEvent(EV_KEY, BTN_TOUCH, 1); injectEvent(EV_ABS, ABS_MT_POSITION_X, point.x); injectEvent(EV_ABS, ABS_MT_POSITION_Y, point.y); - injectEvent(EV_SYN, SYN_REPORT, 0); } void UinputTouchScreen::sendMove(const Point& point) { injectEvent(EV_ABS, ABS_MT_POSITION_X, point.x); injectEvent(EV_ABS, ABS_MT_POSITION_Y, point.y); - injectEvent(EV_SYN, SYN_REPORT, 0); } void UinputTouchScreen::sendPointerUp() { sendTrackingId(0xffffffff); - injectEvent(EV_SYN, SYN_REPORT, 0); } void UinputTouchScreen::sendUp() { sendTrackingId(0xffffffff); injectEvent(EV_KEY, BTN_TOUCH, 0); - injectEvent(EV_SYN, SYN_REPORT, 0); } void UinputTouchScreen::sendToolType(int32_t toolType) { injectEvent(EV_ABS, ABS_MT_TOOL_TYPE, toolType); +} + +void UinputTouchScreen::sendSync() { injectEvent(EV_SYN, SYN_REPORT, 0); } diff --git a/services/inputflinger/tests/UinputDevice.h b/services/inputflinger/tests/UinputDevice.h index 01a557cc70..a37fc2b790 100644 --- a/services/inputflinger/tests/UinputDevice.h +++ b/services/inputflinger/tests/UinputDevice.h @@ -142,6 +142,7 @@ public: void sendPointerUp(); void sendUp(); void sendToolType(int32_t toolType); + void sendSync(); const Point getCenterPoint(); -- cgit v1.2.3-59-g8ed1b