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

Commit fd97e9d9 authored by Siarhei Vishniakou's avatar Siarhei Vishniakou
Browse files

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
parent b8d28f82
Loading
Loading
Loading
Loading
+125 −2
Original line number Diff line number Diff line
@@ -2330,6 +2330,17 @@ protected:
        mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
    }

    void assertReceivedMotion(int32_t action, const std::vector<Point>& 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<UinputTouchScreen> 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);
+3 −4
Original line number Diff line number Diff line
@@ -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);
}

+1 −0
Original line number Diff line number Diff line
@@ -142,6 +142,7 @@ public:
    void sendPointerUp();
    void sendUp();
    void sendToolType(int32_t toolType);
    void sendSync();

    const Point getCenterPoint();