diff options
| -rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.cpp | 20 | ||||
| -rw-r--r-- | services/inputflinger/tests/InputDispatcher_test.cpp | 97 |
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, |