summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArthur Hung <arthurhung@google.com>2021-11-16 02:45:54 +0000
committerArthur Hung <arthurhung@google.com>2021-11-26 07:34:41 +0000
commit71625474845866aaa2fc2bb5994eeb0eb47f4a83 (patch)
tree348c3af1501a5f613c372cd65272a758577efe39
parent3316c9775acab304c5f790b6fa48a576563b7bcc (diff)
downloadnative-71625474845866aaa2fc2bb5994eeb0eb47f4a83.tar.gz
Allow touch split enabled when no window touched
If no window can be touched by first touch down, it would still deliver the event to the gesture monitor. So before gesture monitor pilfer the touch, if a new window supports split touch, it can't recevied the new point down event cause device looks unresponsive. Test: atest inputflinger_test Bug: 201647070 Change-Id: Ib0734ef7082bf673afb11eef9ec7bdb0b3f103ec (cherry picked from commit fbfa572245e430392f779edbb01b3b18e1b2ed82) Merged-In: Ib0734ef7082bf673afb11eef9ec7bdb0b3f103ec
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.cpp20
-rw-r--r--services/inputflinger/tests/InputDispatcher_test.cpp97
2 files changed, 109 insertions, 8 deletions
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 550572603f..464236dfb3 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2021,10 +2021,6 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
findTouchedWindowAtLocked(displayId, x, y, &tempTouchState,
isDown /*addOutsideTargets*/, true /*addPortalWindows*/);
- std::vector<TouchedMonitor> newGestureMonitors = isDown
- ? findTouchedGestureMonitorsLocked(displayId, tempTouchState.portalWindows)
- : std::vector<TouchedMonitor>{};
-
// Figure out whether splitting will be allowed for this window.
if (newTouchedWindowHandle != nullptr &&
newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
@@ -2084,8 +2080,10 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
newTouchedWindowHandle = nullptr;
}
- // Also don't send the new touch event to unresponsive gesture monitors
- newGestureMonitors = selectResponsiveMonitorsLocked(newGestureMonitors);
+ const std::vector<TouchedMonitor> newGestureMonitors = isDown
+ ? selectResponsiveMonitorsLocked(
+ findTouchedGestureMonitorsLocked(displayId, tempTouchState.portalWindows))
+ : tempTouchState.gestureMonitors;
if (newTouchedWindowHandle == nullptr && newGestureMonitors.empty()) {
ALOGI("Dropping event because there is no touchable window or gesture monitor at "
@@ -2121,9 +2119,14 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
pointerIds.markBit(pointerId);
}
tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
+ } else if (tempTouchState.windows.empty()) {
+ // If no window is touched, set split to true. This will allow the next pointer down to
+ // be delivered to a new window which supports split touch.
+ tempTouchState.split = true;
+ }
+ if (isDown) {
+ tempTouchState.addGestureMonitors(newGestureMonitors);
}
-
- tempTouchState.addGestureMonitors(newGestureMonitors);
} else {
/* Case 2: Pointer move, up, cancel or non-splittable pointer down. */
@@ -5414,6 +5417,7 @@ status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) {
canceledWindows.c_str());
// Then clear the current touch state so we stop dispatching to them as well.
+ state.split = false;
state.filterNonMonitors();
}
return OK;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 83e74bad39..00b00e3719 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -2301,6 +2301,18 @@ public:
expectedDisplayId, expectedFlags);
}
+ void consumeMotionCancel(int32_t expectedDisplayId, int32_t expectedFlags = 0) {
+ mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL,
+ expectedDisplayId, expectedFlags);
+ }
+
+ void consumeMotionPointerDown(int32_t pointerIdx) {
+ int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN |
+ (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+ mInputReceiver->consumeEvent(AINPUT_EVENT_TYPE_MOTION, action, ADISPLAY_ID_DEFAULT,
+ 0 /*expectedFlags*/);
+ }
+
MotionEvent* consumeMotion() {
InputEvent* event = mInputReceiver->consume();
if (!event) {
@@ -2447,6 +2459,91 @@ TEST_F(InputDispatcherTest, TestMoveEvent) {
0 /*expectedFlags*/);
}
+TEST_F(InputDispatcherTest, GestureMonitor_SplitIfNoWindowTouched) {
+ FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
+ true /*isGestureMonitor*/);
+
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ // Create a non touch modal window that supports split touch
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ window->setFrame(Rect(0, 0, 100, 100));
+ window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+
+ // First finger down, no window touched.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {100, 200}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ window->assertNoEvents();
+
+ // Second finger down on window, the window should receive touch down.
+ const MotionEvent secondFingerDownEvent =
+ MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
+ (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ AINPUT_SOURCE_TOUCHSCREEN)
+ .displayId(ADISPLAY_ID_DEFAULT)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
+ .x(100)
+ .y(200))
+ .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ monitor.consumeMotionPointerDown(1 /* pointerIndex */);
+}
+
+TEST_F(InputDispatcherTest, GestureMonitor_NoSplitAfterPilfer) {
+ FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
+ true /*isGestureMonitor*/);
+
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ // Create a non touch modal window that supports split touch
+ sp<FakeWindowHandle> window =
+ new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+ window->setFrame(Rect(0, 0, 100, 100));
+ window->setFlags(WindowInfo::Flag::NOT_TOUCH_MODAL | WindowInfo::Flag::SPLIT_TOUCH);
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+
+ // First finger down, no window touched.
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+ {100, 200}))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+ monitor.consumeMotionDown(ADISPLAY_ID_DEFAULT);
+ window->assertNoEvents();
+
+ // Gesture monitor pilfer the pointers.
+ mDispatcher->pilferPointers(monitor.getToken());
+
+ // Second finger down on window, the window should not receive touch down.
+ const MotionEvent secondFingerDownEvent =
+ MotionEventBuilder(AMOTION_EVENT_ACTION_POINTER_DOWN |
+ (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ AINPUT_SOURCE_TOUCHSCREEN)
+ .displayId(ADISPLAY_ID_DEFAULT)
+ .eventTime(systemTime(SYSTEM_TIME_MONOTONIC))
+ .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER)
+ .x(100)
+ .y(200))
+ .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50))
+ .build();
+ ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+ injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+ InputEventInjectionSync::WAIT_FOR_RESULT))
+ << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+ window->assertNoEvents();
+ monitor.consumeMotionPointerDown(1 /* pointerIndex */);
+}
+
/**
* Dispatcher has touch mode enabled by default. Typically, the policy overrides that value to
* the device default right away. In the test scenario, we check both the default value,