Modify pilferpointers API to selectively cancel pointers
Behavior changes:
- Pilfer pointers only cancels relevant pointers (If a pointer
is used by the window calling pilferPointers(), only then,
we need to send ACTION_CANCEL/POINTER_UP to other windows using
that particular pointer)
- Any pointers not used by the window calling pilferPointers()
will remain unaffected and the windows using them will keep
receiving the events
- Any future Pointer down events will go to other windows if and
only if the "the pilfering window" that called pilferPointers() do
not need that pointer for its gesture detection (the pointer down
occurs outside the touchable bounds of the pilfering window)
Bug: 220109830
Test: atest inputflinger_tests
Change-Id: Idc59ae06352560fefd7274bc043bd6e72d5e7710
diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp
index f46a8bc..047c628 100644
--- a/services/inputflinger/dispatcher/InputState.cpp
+++ b/services/inputflinger/dispatcher/InputState.cpp
@@ -286,19 +286,30 @@
for (const MotionMemento& memento : mMotionMementos) {
if (shouldCancelMotion(memento, options)) {
- const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT
- : AMOTION_EVENT_ACTION_CANCEL;
- events.push_back(
- std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime,
- memento.deviceId, memento.source,
- memento.displayId, memento.policyFlags, action,
- 0 /*actionButton*/, memento.flags, AMETA_NONE,
- 0 /*buttonState*/, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
- memento.yPrecision, memento.xCursorPosition,
- memento.yCursorPosition, memento.downTime,
- memento.pointerCount, memento.pointerProperties,
- memento.pointerCoords));
+ if (options.pointerIds == std::nullopt) {
+ const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT
+ : AMOTION_EVENT_ACTION_CANCEL;
+ events.push_back(
+ std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime,
+ memento.deviceId, memento.source,
+ memento.displayId, memento.policyFlags,
+ action, 0 /*actionButton*/, memento.flags,
+ AMETA_NONE, 0 /*buttonState*/,
+ MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE,
+ memento.xPrecision, memento.yPrecision,
+ memento.xCursorPosition,
+ memento.yCursorPosition, memento.downTime,
+ memento.pointerCount,
+ memento.pointerProperties,
+ memento.pointerCoords));
+ } else {
+ std::vector<std::unique_ptr<MotionEntry>> pointerCancelEvents =
+ synthesizeCancelationEventsForPointers(memento, options.pointerIds.value(),
+ currentTime);
+ events.insert(events.end(), std::make_move_iterator(pointerCancelEvents.begin()),
+ std::make_move_iterator(pointerCancelEvents.end()));
+ }
}
}
return events;
@@ -359,6 +370,73 @@
return events;
}
+std::vector<std::unique_ptr<MotionEntry>> InputState::synthesizeCancelationEventsForPointers(
+ const MotionMemento& memento, const BitSet32 pointerIds, nsecs_t currentTime) {
+ std::vector<std::unique_ptr<MotionEntry>> events;
+ std::vector<uint32_t> canceledPointerIndices;
+ std::vector<PointerProperties> pointerProperties(MAX_POINTERS);
+ std::vector<PointerCoords> pointerCoords(MAX_POINTERS);
+ for (uint32_t pointerIdx = 0; pointerIdx < memento.pointerCount; pointerIdx++) {
+ uint32_t pointerId = uint32_t(memento.pointerProperties[pointerIdx].id);
+ pointerProperties[pointerIdx].copyFrom(memento.pointerProperties[pointerIdx]);
+ pointerCoords[pointerIdx].copyFrom(memento.pointerCoords[pointerIdx]);
+ if (pointerIds.hasBit(pointerId)) {
+ canceledPointerIndices.push_back(pointerIdx);
+ }
+ }
+
+ if (canceledPointerIndices.size() == memento.pointerCount) {
+ const int32_t action =
+ memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL;
+ events.push_back(
+ std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime, memento.deviceId,
+ memento.source, memento.displayId,
+ memento.policyFlags, action, 0 /*actionButton*/,
+ memento.flags, AMETA_NONE, 0 /*buttonState*/,
+ MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
+ memento.yPrecision, memento.xCursorPosition,
+ memento.yCursorPosition, memento.downTime,
+ memento.pointerCount, memento.pointerProperties,
+ memento.pointerCoords));
+ } else {
+ // If we aren't canceling all pointers, we need to generated ACTION_POINTER_UP with
+ // FLAG_CANCELED for each of the canceled pointers. For each event, we must remove the
+ // previously canceled pointers from PointerProperties and PointerCoords, and update
+ // pointerCount appropriately. For convenience, sort the canceled pointer indices so that we
+ // can just slide the remaining pointers to the beginning of the array when a pointer is
+ // canceled.
+ std::sort(canceledPointerIndices.begin(), canceledPointerIndices.end(),
+ std::greater<uint32_t>());
+
+ uint32_t pointerCount = memento.pointerCount;
+ for (const uint32_t pointerIdx : canceledPointerIndices) {
+ const int32_t action = pointerCount == 1 ? AMOTION_EVENT_ACTION_CANCEL
+ : AMOTION_EVENT_ACTION_POINTER_UP |
+ (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+ events.push_back(
+ std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime,
+ memento.deviceId, memento.source,
+ memento.displayId, memento.policyFlags, action,
+ 0 /*actionButton*/,
+ memento.flags | AMOTION_EVENT_FLAG_CANCELED,
+ AMETA_NONE, 0 /*buttonState*/,
+ MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
+ memento.yPrecision, memento.xCursorPosition,
+ memento.yCursorPosition, memento.downTime,
+ pointerCount, pointerProperties.data(),
+ pointerCoords.data()));
+
+ // Cleanup pointer information
+ pointerProperties.erase(pointerProperties.begin() + pointerIdx);
+ pointerCoords.erase(pointerCoords.begin() + pointerIdx);
+ pointerCount--;
+ }
+ }
+ return events;
+}
+
void InputState::clear() {
mKeyMementos.clear();
mMotionMementos.clear();