diff options
-rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.cpp | 3 | ||||
-rw-r--r-- | services/inputflinger/tests/InputDispatcher_test.cpp | 80 | ||||
-rw-r--r-- | services/inputflinger/tests/TestEventMatchers.h | 31 |
3 files changed, 110 insertions, 4 deletions
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index c91ba38101..2fd1763b40 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -2624,6 +2624,9 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked( if (mDragState && mDragState->dragWindow == touchedWindow.windowHandle) { continue; } + if (!touchedWindow.hasTouchingPointers(entry.deviceId)) { + continue; + } touchedWindow.addTouchingPointers(entry.deviceId, touchingPointers); } } diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index 168e74ca83..dc13fed569 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -1340,6 +1340,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)); + } + void consumeMotionPointerUp(int32_t pointerIdx, int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, int32_t expectedFlags = 0) { const int32_t action = AMOTION_EVENT_ACTION_POINTER_UP | @@ -1348,6 +1355,13 @@ public: WithFlags(expectedFlags))); } + 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), matcher)); + } + void consumeMotionUp(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, int32_t expectedFlags = 0) { consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDisplayId(expectedDisplayId), @@ -4771,6 +4785,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)", + ADISPLAY_ID_DEFAULT); + leftWindow->setFrame(Rect(0, 0, 100, 100)); + leftWindow->setPreventSplitting(true); + + sp<FakeWindowHandle> rightWindow = + sp<FakeWindowHandle>::make(application, mDispatcher, "Right window", + ADISPLAY_ID_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 = diff --git a/services/inputflinger/tests/TestEventMatchers.h b/services/inputflinger/tests/TestEventMatchers.h index a3e8eafea3..76170eb93c 100644 --- a/services/inputflinger/tests/TestEventMatchers.h +++ b/services/inputflinger/tests/TestEventMatchers.h @@ -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") { |