Add POLICY_FLAG_PASS_TO_USER to complete the gesture
Before an input event is processed by the dispatcher, the policy has the
chance to intercept it. The policy sets POLICY_FLAG_PASS_TO_USER if it
wants the event to be processed by the dispatcher, and does not set this
flag if it wants the event to get dropped.
If the device becomes non-interactive, the policy would stop sending
this flag. This could happen in the middle of the gesture.
To account for this, check whether there's an active stream inside the
dispatcher, and finish the gesture if so.
This allows the policy implementation to remain simple. If we wanted the
policy to be consistent (either the whole gesture is sent to the app, or
the whole gesture isn't), it would complicate the policy implementation
and require it to keep state.
Dispatcher already keeps the state, so we fix this in the dispatcher.
Bug: 267614813
Test: atest inputflinger_tests:InputDispatcherTest#TwoPointerCancel
Change-Id: I8d162c658f4f53a76d32d5e5a1de8ac3722e277d
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 079b80d..d14a781 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -4185,6 +4185,17 @@
bool needWake = false;
{ // acquire lock
mLock.lock();
+ if (!(policyFlags & POLICY_FLAG_PASS_TO_USER)) {
+ // Set the flag anyway if we already have an ongoing gesture. That would allow us to
+ // complete the processing of the current stroke.
+ const auto touchStateIt = mTouchStatesByDisplay.find(args->displayId);
+ if (touchStateIt != mTouchStatesByDisplay.end()) {
+ const TouchState& touchState = touchStateIt->second;
+ if (touchState.deviceId == args->deviceId && touchState.isDown()) {
+ policyFlags |= POLICY_FLAG_PASS_TO_USER;
+ }
+ }
+ }
if (shouldSendMotionToInputFilterLocked(args)) {
ui::Transform displayTransform;