Keep track of pilfered pointer explicitly
The pointers that are getting pilfered were not being tracked explicitly
before. The behaviour relied on the window going away in order to reset
the "isPilfering" value to "false".
Now, however, some windows are getting persisted longer, because they
might receive a hover gesture that doesn't end (like a mouse that
someone stops using).
Therefore, we need to explicitly keep track of which pointers are being
pilfered. This is also in line with our eventual goal of explicit
per-window pointer management.
In the failing case, the windows was considered to be "pilfering". Since
the gesture monitors were receiving all of the pointers, the pointers
would no longer get dispatched to any windows underneath.
With this CL, we maintain the existing intended behaviours of pilfering,
while also expanding the support for multiple pilfered pointers.
In the added test case, there is a mouse interaction first, which
persists the gesture monitor window. Next, we pilfer a touch event,
which sets the "isPilfering" flag to ON. And finally, we inject the new
touch gesture. This gesture was (incorrectly) getting only sent to the
gesture monitor, because it kept maintaining the "isPilfering" status.
Bug: 266705421
Test: m inputflinger_tests && $ANDROID_HOST_OUT/nativetest64/inputflinger_tests/inputflinger_tests --gtest_filter="*MouseAndTouchWithSpyWindows*"
Change-Id: I6b72dc3e4de0e0ef09ccc469df0f703762c76fa6
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 5d9ee5f..0f3dc5c 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2333,14 +2333,22 @@
}
}
- // If any existing window is pilfering pointers from newly added window, remove it
- BitSet32 canceledPointers = BitSet32(0);
- for (const TouchedWindow& window : tempTouchState.windows) {
- if (window.isPilferingPointers) {
- canceledPointers |= window.pointerIds;
+ // If a window is already pilfering some pointers, give it this new pointer as well and
+ // make it pilfering. This will prevent other non-spy windows from getting this pointer,
+ // which is a specific behaviour that we want.
+ const int32_t pointerId = entry.pointerProperties[pointerIndex].id;
+ for (TouchedWindow& touchedWindow : tempTouchState.windows) {
+ if (touchedWindow.pointerIds.hasBit(pointerId) &&
+ touchedWindow.pilferedPointerIds.count() > 0) {
+ // This window is already pilfering some pointers, and this new pointer is also
+ // going to it. Therefore, take over this pointer and don't give it to anyone
+ // else.
+ touchedWindow.pilferedPointerIds.set(pointerId);
}
}
- tempTouchState.cancelPointersForNonPilferingWindows(canceledPointers);
+
+ // Restrict all pilfered pointers to the pilfering windows.
+ tempTouchState.cancelPointersForNonPilferingWindows();
} else {
/* Case 2: Pointer move, up, cancel or non-splittable pointer down. */
@@ -3942,8 +3950,8 @@
if (action == AMOTION_EVENT_ACTION_DOWN) {
LOG_ALWAYS_FATAL_IF(splitDownTime != originalMotionEntry.eventTime,
"Split motion event has mismatching downTime and eventTime for "
- "ACTION_DOWN, motionEntry=%s, splitDownTime=%" PRId64 "ms",
- originalMotionEntry.getDescription().c_str(), ns2ms(splitDownTime));
+ "ACTION_DOWN, motionEntry=%s, splitDownTime=%" PRId64,
+ originalMotionEntry.getDescription().c_str(), splitDownTime);
}
int32_t newId = mIdGenerator.nextId();
@@ -5778,7 +5786,10 @@
// Prevent the gesture from being sent to any other windows.
// This only blocks relevant pointers to be sent to other windows
- window.isPilferingPointers = true;
+ for (BitSet32 idBits(window.pointerIds); !idBits.isEmpty();) {
+ uint32_t id = idBits.clearFirstMarkedBit();
+ window.pilferedPointerIds.set(id);
+ }
state.cancelPointersForWindowsExcept(window.pointerIds, token);
return OK;