@@ -1340,6 +1340,13 @@ class FakeWindowHandle : public WindowInfoHandle {
13401340 WithFlags(expectedFlags)));
13411341 }
13421342
1343+ inline void consumeMotionPointerDown(int32_t pointerIdx,
1344+ const ::testing::Matcher<MotionEvent>& matcher) {
1345+ const int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN |
1346+ (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
1347+ consumeMotionEvent(testing::AllOf(WithMotionAction(action), matcher));
1348+ }
1349+
13431350 void consumeMotionPointerUp(int32_t pointerIdx, int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
13441351 int32_t expectedFlags = 0) {
13451352 const int32_t action = AMOTION_EVENT_ACTION_POINTER_UP |
@@ -1348,6 +1355,13 @@ class FakeWindowHandle : public WindowInfoHandle {
13481355 WithFlags(expectedFlags)));
13491356 }
13501357
1358+ inline void consumeMotionPointerUp(int32_t pointerIdx,
1359+ const ::testing::Matcher<MotionEvent>& matcher) {
1360+ const int32_t action = AMOTION_EVENT_ACTION_POINTER_UP |
1361+ (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
1362+ consumeMotionEvent(testing::AllOf(WithMotionAction(action), matcher));
1363+ }
1364+
13511365 void consumeMotionUp(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
13521366 int32_t expectedFlags = 0) {
13531367 consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDisplayId(expectedDisplayId),
@@ -4771,6 +4785,72 @@ TEST_F(InputDispatcherTest, SplittableAndNonSplittableWindows) {
47714785 rightWindow->assertNoEvents();
47724786}
47734787
4788+ /**
4789+ * Two windows: left and right. The left window has PREVENT_SPLITTING input config. Device A sends a
4790+ * down event to the right window. Device B sends a down event to the left window, and then a
4791+ * POINTER_DOWN event to the right window. However, since the left window prevents splitting, the
4792+ * POINTER_DOWN event should only go to the left window, and not to the right window.
4793+ * This test attempts to reproduce a crash.
4794+ */
4795+ TEST_F(InputDispatcherTest, MultiDeviceTwoWindowsPreventSplitting) {
4796+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
4797+ sp<FakeWindowHandle> leftWindow =
4798+ sp<FakeWindowHandle>::make(application, mDispatcher, "Left window (prevent splitting)",
4799+ ADISPLAY_ID_DEFAULT);
4800+ leftWindow->setFrame(Rect(0, 0, 100, 100));
4801+ leftWindow->setPreventSplitting(true);
4802+
4803+ sp<FakeWindowHandle> rightWindow =
4804+ sp<FakeWindowHandle>::make(application, mDispatcher, "Right window",
4805+ ADISPLAY_ID_DEFAULT);
4806+ rightWindow->setFrame(Rect(100, 0, 200, 100));
4807+
4808+ mDispatcher->onWindowInfosChanged(
4809+ {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
4810+
4811+ const DeviceId deviceA = 9;
4812+ const DeviceId deviceB = 3;
4813+ // Touch the right window with device A
4814+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4815+ .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
4816+ .deviceId(deviceA)
4817+ .build());
4818+ rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceA)));
4819+ // Touch the left window with device B
4820+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4821+ .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4822+ .deviceId(deviceB)
4823+ .build());
4824+ leftWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_DOWN), WithDeviceId(deviceB)));
4825+ // Send a second pointer from device B to the right window. It shouldn't go to the right window
4826+ // because the left window prevents splitting.
4827+ mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
4828+ .deviceId(deviceB)
4829+ .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4830+ .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
4831+ .build());
4832+ leftWindow->consumeMotionPointerDown(1, WithDeviceId(deviceB));
4833+
4834+ // Finish the gesture for both devices
4835+ mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN)
4836+ .deviceId(deviceB)
4837+ .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4838+ .pointer(PointerBuilder(1, ToolType::FINGER).x(120).y(120))
4839+ .build());
4840+ leftWindow->consumeMotionPointerUp(1, WithDeviceId(deviceB));
4841+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4842+ .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
4843+ .deviceId(deviceB)
4844+ .build());
4845+ leftWindow->consumeMotionEvent(
4846+ AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceB), WithPointerId(0, 0)));
4847+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
4848+ .pointer(PointerBuilder(0, ToolType::FINGER).x(150).y(50))
4849+ .deviceId(deviceA)
4850+ .build());
4851+ rightWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_UP), WithDeviceId(deviceA)));
4852+ }
4853+
47744854TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) {
47754855 std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
47764856 sp<FakeWindowHandle> window =
0 commit comments