Loading services/inputflinger/dispatcher/InputDispatcher.cpp +12 −8 Original line number Diff line number Diff line Loading @@ -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()) { Loading Loading @@ -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 " Loading Loading @@ -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); } } else { /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */ Loading Loading @@ -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; Loading services/inputflinger/tests/InputDispatcher_test.cpp +97 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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, Loading Loading
services/inputflinger/dispatcher/InputDispatcher.cpp +12 −8 Original line number Diff line number Diff line Loading @@ -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()) { Loading Loading @@ -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 " Loading Loading @@ -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); } } else { /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */ Loading Loading @@ -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; Loading
services/inputflinger/tests/InputDispatcher_test.cpp +97 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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, Loading