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

Commit 27fc9f1f authored by Siarhei Vishniakou's avatar Siarhei Vishniakou
Browse files

Handle non-split pointers for multi-device case

During multi-device event stream, tempTouchState will already contain
some pointers from another case. When the second device becomes active
and tries to add pointers to a non-splitting window, we should not be
marking that pointer as going to the second window unless it's already
receiving pointers for that device.

Fixes: 341869464
Flag: EXEMPT bugfix
Test: TEST=inputflinger_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:962044645a27baaaf9d7736f76c6c252aa82c419)
Merged-In: Ia295c1d9d941383792e90a3d6fd981473af8f015
Change-Id: Ia295c1d9d941383792e90a3d6fd981473af8f015
parent fc4d8c60
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -2705,6 +2705,9 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked(
                if (mDragState && mDragState->dragWindow == touchedWindow.windowHandle) {
                    continue;
                }
                if (!touchedWindow.hasTouchingPointers(entry.deviceId)) {
                    continue;
                }
                touchedWindow.addTouchingPointers(entry.deviceId, touchingPointers);
            }
        }
+7 −0
Original line number Diff line number Diff line
@@ -304,6 +304,13 @@ public:
                                          WithFlags(expectedFlags)));
    }

    inline void consumeMotionPointerDown(int32_t pointerIdx,
                                         const ::testing::Matcher<MotionEvent>& matcher) {
        const int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN |
                (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
        consumeMotionEvent(testing::AllOf(WithMotionAction(action), matcher));
    }

    inline void consumeMotionPointerUp(int32_t pointerIdx,
                                       const ::testing::Matcher<MotionEvent>& matcher) {
        const int32_t action = AMOTION_EVENT_ACTION_POINTER_UP |
+66 −0
Original line number Diff line number Diff line
@@ -5357,6 +5357,72 @@ TEST_F(InputDispatcherTest, SplittableAndNonSplittableWindows) {
    rightWindow->assertNoEvents();
}
/**
 * Two windows: left and right. The left window has PREVENT_SPLITTING input config. Device A sends a
 * down event to the right window. Device B sends a down event to the left window, and then a
 * POINTER_DOWN event to the right window. However, since the left window prevents splitting, the
 * POINTER_DOWN event should only go to the left window, and not to the right window.
 * This test attempts to reproduce a crash.
 */
TEST_F(InputDispatcherTest, MultiDeviceTwoWindowsPreventSplitting) {
    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
    sp<FakeWindowHandle> leftWindow =
            sp<FakeWindowHandle>::make(application, mDispatcher, "Left window (prevent splitting)",
                                       ui::LogicalDisplayId::DEFAULT);
    leftWindow->setFrame(Rect(0, 0, 100, 100));
    leftWindow->setPreventSplitting(true);
    sp<FakeWindowHandle> rightWindow =
            sp<FakeWindowHandle>::make(application, mDispatcher, "Right window",
                                       ui::LogicalDisplayId::DEFAULT);
    rightWindow->setFrame(Rect(100, 0, 200, 100));
    mDispatcher->onWindowInfosChanged(
            {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
    const DeviceId deviceA = 9;
    const DeviceId deviceB = 3;
    // Touch the right window with device A
    mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
                                      .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
                                      .deviceId(deviceA)
                                      .build());
    rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
    // Touch the left window with device B
    mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
                                      .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
                                      .deviceId(deviceB)
                                      .build());
    leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
    // Send a second pointer from device B to the right window. It shouldn't go to the right window
    // because the left window prevents splitting.
    mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
                                      .deviceId(deviceB)
                                      .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
                                      .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
                                      .build());
    leftWindow->consumeMotionPointerDown(1, WithDeviceId(deviceB));
    // Finish the gesture for both devices
    mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
                                      .deviceId(deviceB)
                                      .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
                                      .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
                                      .build());
    leftWindow->consumeMotionPointerUp(1, WithDeviceId(deviceB));
    mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
                                      .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
                                      .deviceId(deviceB)
                                      .build());
    leftWindow->consumeMotionEvent(
            AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceB), WithPointerId(0, 0)));
    mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
                                      .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
                                      .deviceId(deviceA)
                                      .build());
    rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceA)));
}
TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) {
    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
    sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Window",
+27 −4
Original line number Diff line number Diff line
@@ -609,10 +609,33 @@ MATCHER_P(WithRepeatCount, repeatCount, "KeyEvent with specified repeat count")
    return arg.getRepeatCount() == repeatCount;
}

MATCHER_P2(WithPointerId, index, id, "MotionEvent with specified pointer ID for pointer index") {
    const auto argPointerId = arg.pointerProperties[index].id;
    *result_listener << "expected pointer with index " << index << " to have ID " << argPointerId;
    return argPointerId == id;
class WithPointerIdMatcher {
public:
    using is_gtest_matcher = void;
    explicit WithPointerIdMatcher(size_t index, int32_t pointerId)
          : mIndex(index), mPointerId(pointerId) {}

    bool MatchAndExplain(const NotifyMotionArgs& args, std::ostream*) const {
        return args.pointerProperties[mIndex].id == mPointerId;
    }

    bool MatchAndExplain(const MotionEvent& event, std::ostream*) const {
        return event.getPointerId(mIndex) == mPointerId;
    }

    void DescribeTo(std::ostream* os) const {
        *os << "with pointer[" << mIndex << "] id = " << mPointerId;
    }

    void DescribeNegationTo(std::ostream* os) const { *os << "wrong pointerId"; }

private:
    const size_t mIndex;
    const int32_t mPointerId;
};

inline WithPointerIdMatcher WithPointerId(size_t index, int32_t pointerId) {
    return WithPointerIdMatcher(index, pointerId);
}

MATCHER_P2(WithCursorPosition, x, y, "InputEvent with specified cursor position") {