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

Commit 33cfc6d2 authored by Prabir Pradhan's avatar Prabir Pradhan
Browse files

InputDispatcher: Fix pointer count when canceling a subset of pointers

There was a bug in the logic for calculating the pointer coords and
properties for canceling a subset of pointers. It was introduced when we
refactored storing the coords in a vector rather than using a
fixed-length array with a pointerCount variable in the following change:
I91b4a88ec5df3f017ade8a6e55be3d3c1281de75

Bug: 346342507
Test: atest inputflinger_tests
Flag: NONE bug fix

Change-Id: Ie9a5fbd5ba1fd75c53b7289a93573ec2d0d1947b
parent de36292b
Loading
Loading
Loading
Loading
+30 −44
Original line number Diff line number Diff line
@@ -499,48 +499,36 @@ std::vector<std::unique_ptr<MotionEntry>> InputState::synthesizeCancelationEvent
        nsecs_t currentTime) {
    std::vector<std::unique_ptr<MotionEntry>> events;
    std::vector<uint32_t> canceledPointerIndices;
    std::vector<PointerProperties> pointerProperties(MAX_POINTERS);
    std::vector<PointerCoords> pointerCoords(MAX_POINTERS);

    for (uint32_t pointerIdx = 0; pointerIdx < memento.getPointerCount(); pointerIdx++) {
        uint32_t pointerId = uint32_t(memento.pointerProperties[pointerIdx].id);
        pointerProperties[pointerIdx] = memento.pointerProperties[pointerIdx];
        pointerCoords[pointerIdx] = memento.pointerCoords[pointerIdx];
        if (pointerIds.test(pointerId)) {
            canceledPointerIndices.push_back(pointerIdx);
        }
    }

    if (canceledPointerIndices.size() == memento.getPointerCount()) {
        const int32_t action =
                memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL;
        int32_t flags = memento.flags;
        if (action == AMOTION_EVENT_ACTION_CANCEL) {
            flags |= AMOTION_EVENT_FLAG_CANCELED;
        // We are cancelling all pointers.
        events.emplace_back(createCancelEntryForMemento(memento, currentTime));
        return events;
    }
        events.push_back(
                std::make_unique<MotionEntry>(mIdGenerator.nextId(), /*injectionState=*/nullptr,
                                              currentTime, memento.deviceId, memento.source,
                                              memento.displayId, memento.policyFlags, action,
                                              /*actionButton=*/0, flags, AMETA_NONE,
                                              /*buttonState=*/0, MotionClassification::NONE,
                                              AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
                                              memento.yPrecision, memento.xCursorPosition,
                                              memento.yCursorPosition, memento.downTime,
                                              memento.pointerProperties, memento.pointerCoords));
    } else {

    // If we aren't canceling all pointers, we need to generate ACTION_POINTER_UP with
    // FLAG_CANCELED for each of the canceled pointers. For each event, we must remove the
    // previously canceled pointers from PointerProperties and PointerCoords, and update
        // pointerCount appropriately. For convenience, sort the canceled pointer indices so that we
        // can just slide the remaining pointers to the beginning of the array when a pointer is
        // canceled.
    // pointerCount appropriately. For convenience, sort the canceled pointer indices in
    // descending order so that we can just slide the remaining pointers to the beginning of
    // the array when a pointer is canceled.
    std::sort(canceledPointerIndices.begin(), canceledPointerIndices.end(),
              std::greater<uint32_t>());

        uint32_t pointerCount = memento.getPointerCount();
    std::vector<PointerProperties> pointerProperties = memento.pointerProperties;
    std::vector<PointerCoords> pointerCoords = memento.pointerCoords;
    for (const uint32_t pointerIdx : canceledPointerIndices) {
            const int32_t action = pointerCount == 1 ? AMOTION_EVENT_ACTION_CANCEL
                                                     : AMOTION_EVENT_ACTION_POINTER_UP |
        if (pointerProperties.size() <= 1) {
            LOG(FATAL) << "Unexpected code path for canceling all pointers!";
        }
        const int32_t action = AMOTION_EVENT_ACTION_POINTER_UP |
                (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
        events.push_back(
                std::make_unique<MotionEntry>(mIdGenerator.nextId(), /*injectionState=*/nullptr,
@@ -558,8 +546,6 @@ std::vector<std::unique_ptr<MotionEntry>> InputState::synthesizeCancelationEvent
        // Cleanup pointer information
        pointerProperties.erase(pointerProperties.begin() + pointerIdx);
        pointerCoords.erase(pointerCoords.begin() + pointerIdx);
            pointerCount--;
        }
    }
    return events;
}
+3 −7
Original line number Diff line number Diff line
@@ -304,15 +304,11 @@ public:
                                          WithFlags(expectedFlags)));
    }

    inline void consumeMotionPointerUp(
            int32_t pointerIdx,
            ui::LogicalDisplayId expectedDisplayId = ui::LogicalDisplayId::DEFAULT,
            int32_t expectedFlags = 0) {
    inline void consumeMotionPointerUp(int32_t pointerIdx,
                                       const ::testing::Matcher<MotionEvent>& matcher) {
        const int32_t action = AMOTION_EVENT_ACTION_POINTER_UP |
                (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
        consumeMotionEvent(testing::AllOf(WithMotionAction(action),
                                          WithDisplayId(expectedDisplayId),
                                          WithFlags(expectedFlags)));
        consumeMotionEvent(testing::AllOf(WithMotionAction(action), matcher));
    }

    inline void consumeMotionUp(
+21 −11
Original line number Diff line number Diff line
@@ -1282,9 +1282,11 @@ TEST_P(ShouldSplitTouchFixture, WallpaperWindowReceivesMultiTouch) {
              injectMotionEvent(*mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT,
                                InputEventInjectionSync::WAIT_FOR_RESULT))
            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
    foregroundWindow->consumeMotionPointerUp(0);
    wallpaperWindow->consumeMotionPointerUp(0, ui::LogicalDisplayId::DEFAULT,
                                            EXPECTED_WALLPAPER_FLAGS);
    foregroundWindow->consumeMotionPointerUp(/*pointerIdx=*/0,
                                             WithDisplayId(ui::LogicalDisplayId::DEFAULT));
    wallpaperWindow->consumeMotionPointerUp(/*pointerIdx=*/0,
                                            AllOf(WithDisplayId(ui::LogicalDisplayId::DEFAULT),
                                                  WithFlags(EXPECTED_WALLPAPER_FLAGS)));
    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
              injectMotionEvent(*mDispatcher,
@@ -6220,8 +6222,10 @@ TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) {
                                                 {touchPoint, touchPoint}));
    // The first window gets nothing and the second gets pointer up
    firstWindow->assertNoEvents();
    secondWindow->consumeMotionPointerUp(1, ui::LogicalDisplayId::DEFAULT,
                                         AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
    secondWindow->consumeMotionPointerUp(/*pointerIdx=*/1,
                                         AllOf(WithDisplayId(ui::LogicalDisplayId::DEFAULT),
                                               WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE),
                                               WithPointerCount(2)));
    // Send up event to the second window
    mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
@@ -6363,8 +6367,10 @@ TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) {
                                                 {pointInFirst, pointInSecond}));
    // The first window gets nothing and the second gets pointer up
    firstWindow->assertNoEvents();
    secondWindow->consumeMotionPointerUp(1, ui::LogicalDisplayId::DEFAULT,
                                         AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
    secondWindow->consumeMotionPointerUp(/*pointerIdx=*/1,
                                         AllOf(WithDisplayId(ui::LogicalDisplayId::DEFAULT),
                                               WithFlags(AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE),
                                               WithPointerCount(2)));
    // Send up event to the second window
    mDispatcher->notifyMotion(generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
@@ -12878,10 +12884,14 @@ TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) {
    // Spy window pilfers the pointers.
    EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken()));
    window->consumeMotionPointerUp(/*idx=*/2, ui::LogicalDisplayId::DEFAULT,
                                   AMOTION_EVENT_FLAG_CANCELED);
    window->consumeMotionPointerUp(/*idx=*/1, ui::LogicalDisplayId::DEFAULT,
                                   AMOTION_EVENT_FLAG_CANCELED);
    window->consumeMotionPointerUp(/*pointerIdx=*/2,
                                   AllOf(WithDisplayId(ui::LogicalDisplayId::DEFAULT),
                                         WithFlags(AMOTION_EVENT_FLAG_CANCELED),
                                         WithPointerCount(3)));
    window->consumeMotionPointerUp(/*pointerIdx=*/1,
                                   AllOf(WithDisplayId(ui::LogicalDisplayId::DEFAULT),
                                         WithFlags(AMOTION_EVENT_FLAG_CANCELED),
                                         WithPointerCount(2)));
    spy->assertNoEvents();
    window->assertNoEvents();