Skip to content

Commit e535b6d

Browse files
committed
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. Merge conflict resolutiion: added a bunch of helper functions for matching the properties of motionevent that are present internally, but missing in the aosp code. 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
1 parent a42f727 commit e535b6d

3 files changed

Lines changed: 110 additions & 4 deletions

File tree

services/inputflinger/dispatcher/InputDispatcher.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2624,6 +2624,9 @@ std::vector<InputTarget> InputDispatcher::findTouchedWindowTargetsLocked(
26242624
if (mDragState && mDragState->dragWindow == touchedWindow.windowHandle) {
26252625
continue;
26262626
}
2627+
if (!touchedWindow.hasTouchingPointers(entry.deviceId)) {
2628+
continue;
2629+
}
26272630
touchedWindow.addTouchingPointers(entry.deviceId, touchingPointers);
26282631
}
26292632
}

services/inputflinger/tests/InputDispatcher_test.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
47744854
TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) {
47754855
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
47764856
sp<FakeWindowHandle> window =

services/inputflinger/tests/TestEventMatchers.h

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -609,10 +609,33 @@ MATCHER_P(WithRepeatCount, repeatCount, "KeyEvent with specified repeat count")
609609
return arg.getRepeatCount() == repeatCount;
610610
}
611611

612-
MATCHER_P2(WithPointerId, index, id, "MotionEvent with specified pointer ID for pointer index") {
613-
const auto argPointerId = arg.pointerProperties[index].id;
614-
*result_listener << "expected pointer with index " << index << " to have ID " << argPointerId;
615-
return argPointerId == id;
612+
class WithPointerIdMatcher {
613+
public:
614+
using is_gtest_matcher = void;
615+
explicit WithPointerIdMatcher(size_t index, int32_t pointerId)
616+
: mIndex(index), mPointerId(pointerId) {}
617+
618+
bool MatchAndExplain(const NotifyMotionArgs& args, std::ostream*) const {
619+
return args.pointerProperties[mIndex].id == mPointerId;
620+
}
621+
622+
bool MatchAndExplain(const MotionEvent& event, std::ostream*) const {
623+
return event.getPointerId(mIndex) == mPointerId;
624+
}
625+
626+
void DescribeTo(std::ostream* os) const {
627+
*os << "with pointer[" << mIndex << "] id = " << mPointerId;
628+
}
629+
630+
void DescribeNegationTo(std::ostream* os) const { *os << "wrong pointerId"; }
631+
632+
private:
633+
const size_t mIndex;
634+
const int32_t mPointerId;
635+
};
636+
637+
inline WithPointerIdMatcher WithPointerId(size_t index, int32_t pointerId) {
638+
return WithPointerIdMatcher(index, pointerId);
616639
}
617640

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

0 commit comments

Comments
 (0)