Loading services/inputflinger/dispatcher/InputDispatcher.cpp +17 −12 Original line number Diff line number Diff line Loading @@ -2276,6 +2276,20 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); } } // Update the pointerIds for non-splittable when it received pointer down. if (!isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN) { // If no split, we suppose all touched windows should receive pointer down. const int32_t pointerIndex = getMotionEventActionPointerIndex(action); for (size_t i = 0; i < tempTouchState.windows.size(); i++) { TouchedWindow& touchedWindow = tempTouchState.windows[i]; // Ignore drag window for it should just track one pointer. if (mDragState && mDragState->dragWindow == touchedWindow.windowHandle) { continue; } touchedWindow.pointerIds.markBit(entry.pointerProperties[pointerIndex].id); } } } // Update dispatching for hover enter and exit. Loading Loading @@ -2384,13 +2398,15 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( if (info->displayId == displayId && windowHandle->getInfo()->inputConfig.test( WindowInfo::InputConfig::IS_WALLPAPER)) { BitSet32 pointerIds; pointerIds.markBit(entry.pointerProperties[0].id); tempTouchState .addOrUpdateWindow(windowHandle, InputTarget::FLAG_WINDOW_IS_OBSCURED | InputTarget:: FLAG_WINDOW_IS_PARTIALLY_OBSCURED | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0)); pointerIds); } } } Loading Loading @@ -2460,17 +2476,6 @@ Failed: } i += 1; } } else if (!isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN) { // If no split, we suppose all touched windows should receive pointer down. const int32_t pointerIndex = getMotionEventActionPointerIndex(action); for (size_t i = 0; i < tempTouchState.windows.size(); i++) { TouchedWindow& touchedWindow = tempTouchState.windows[i]; // Ignore drag window for it should just track one pointer. if (mDragState && mDragState->dragWindow == touchedWindow.windowHandle) { continue; } touchedWindow.pointerIds.markBit(entry.pointerProperties[pointerIndex].id); } } // Save changes unless the action was scroll in which case the temporary touch Loading services/inputflinger/tests/InputDispatcher_test.cpp +95 −0 Original line number Diff line number Diff line Loading @@ -1887,6 +1887,64 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { wallpaperWindow->assertNoEvents(); } TEST_F(InputDispatcherTest, WallpaperWindowReceivesMultiTouch) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); window->setDupTouchToWallpaper(true); sp<FakeWindowHandle> wallpaperWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); wallpaperWindow->setIsWallpaper(true); constexpr int expectedWallpaperFlags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; wallpaperWindow->setPreventSplitting(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, wallpaperWindow}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(ADISPLAY_ID_DEFAULT); wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); const MotionEvent secondFingerDownEvent = MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionPointerDown(1); wallpaperWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); const MotionEvent secondFingerUpEvent = MotionEventBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN) .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionPointerUp(1); wallpaperWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionUp(ADISPLAY_ID_DEFAULT); wallpaperWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); } /** * On the display, have a single window, and also an area where there's no window. * First pointer touches the "no window" area of the screen. Second pointer touches the window. Loading Loading @@ -2375,6 +2433,43 @@ TEST_F(InputDispatcherTest, OnWindowInfosChanged_RemoveAllWindowsOnDisplay) { window->assertNoEvents(); } TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); // Ensure window is non-split and have some transform. window->setPreventSplitting(true); window->setWindowOffset(20, 40); mDispatcher->onWindowInfosChanged({*window->getInfo()}, {}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(ADISPLAY_ID_DEFAULT); const MotionEvent secondFingerDownEvent = MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER) .x(-30) .y(-50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; const MotionEvent* event = window->consumeMotion(); EXPECT_EQ(POINTER_1_DOWN, event->getAction()); EXPECT_EQ(70, event->getX(0)); // 50 + 20 EXPECT_EQ(90, event->getY(0)); // 50 + 40 EXPECT_EQ(-10, event->getX(1)); // -30 + 20 EXPECT_EQ(-10, event->getY(1)); // -50 + 40 } /** * Ensure the correct coordinate spaces are used by InputDispatcher. * Loading Loading
services/inputflinger/dispatcher/InputDispatcher.cpp +17 −12 Original line number Diff line number Diff line Loading @@ -2276,6 +2276,20 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); } } // Update the pointerIds for non-splittable when it received pointer down. if (!isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN) { // If no split, we suppose all touched windows should receive pointer down. const int32_t pointerIndex = getMotionEventActionPointerIndex(action); for (size_t i = 0; i < tempTouchState.windows.size(); i++) { TouchedWindow& touchedWindow = tempTouchState.windows[i]; // Ignore drag window for it should just track one pointer. if (mDragState && mDragState->dragWindow == touchedWindow.windowHandle) { continue; } touchedWindow.pointerIds.markBit(entry.pointerProperties[pointerIndex].id); } } } // Update dispatching for hover enter and exit. Loading Loading @@ -2384,13 +2398,15 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( if (info->displayId == displayId && windowHandle->getInfo()->inputConfig.test( WindowInfo::InputConfig::IS_WALLPAPER)) { BitSet32 pointerIds; pointerIds.markBit(entry.pointerProperties[0].id); tempTouchState .addOrUpdateWindow(windowHandle, InputTarget::FLAG_WINDOW_IS_OBSCURED | InputTarget:: FLAG_WINDOW_IS_PARTIALLY_OBSCURED | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0)); pointerIds); } } } Loading Loading @@ -2460,17 +2476,6 @@ Failed: } i += 1; } } else if (!isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN) { // If no split, we suppose all touched windows should receive pointer down. const int32_t pointerIndex = getMotionEventActionPointerIndex(action); for (size_t i = 0; i < tempTouchState.windows.size(); i++) { TouchedWindow& touchedWindow = tempTouchState.windows[i]; // Ignore drag window for it should just track one pointer. if (mDragState && mDragState->dragWindow == touchedWindow.windowHandle) { continue; } touchedWindow.pointerIds.markBit(entry.pointerProperties[pointerIndex].id); } } // Save changes unless the action was scroll in which case the temporary touch Loading
services/inputflinger/tests/InputDispatcher_test.cpp +95 −0 Original line number Diff line number Diff line Loading @@ -1887,6 +1887,64 @@ TEST_F(InputDispatcherTest, TwoWindows_SplitWallpaperTouch) { wallpaperWindow->assertNoEvents(); } TEST_F(InputDispatcherTest, WallpaperWindowReceivesMultiTouch) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT); window->setDupTouchToWallpaper(true); sp<FakeWindowHandle> wallpaperWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Wallpaper", ADISPLAY_ID_DEFAULT); wallpaperWindow->setIsWallpaper(true); constexpr int expectedWallpaperFlags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED | AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED; wallpaperWindow->setPreventSplitting(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window, wallpaperWindow}}}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(ADISPLAY_ID_DEFAULT); wallpaperWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); const MotionEvent secondFingerDownEvent = MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionPointerDown(1); wallpaperWindow->consumeMotionPointerDown(1, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); const MotionEvent secondFingerUpEvent = MotionEventBuilder(POINTER_1_UP, AINPUT_SOURCE_TOUCHSCREEN) .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerUpEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionPointerUp(1); wallpaperWindow->consumeMotionPointerUp(1, ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionUp(ADISPLAY_ID_DEFAULT); wallpaperWindow->consumeMotionUp(ADISPLAY_ID_DEFAULT, expectedWallpaperFlags); } /** * On the display, have a single window, and also an area where there's no window. * First pointer touches the "no window" area of the screen. Second pointer touches the window. Loading Loading @@ -2375,6 +2433,43 @@ TEST_F(InputDispatcherTest, OnWindowInfosChanged_RemoveAllWindowsOnDisplay) { window->assertNoEvents(); } TEST_F(InputDispatcherTest, NonSplitTouchableWindowReceivesMultiTouch) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT); // Ensure window is non-split and have some transform. window->setPreventSplitting(true); window->setWindowOffset(20, 40); mDispatcher->onWindowInfosChanged({*window->getInfo()}, {}); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(ADISPLAY_ID_DEFAULT); const MotionEvent secondFingerDownEvent = MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER) .x(-30) .y(-50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; const MotionEvent* event = window->consumeMotion(); EXPECT_EQ(POINTER_1_DOWN, event->getAction()); EXPECT_EQ(70, event->getX(0)); // 50 + 20 EXPECT_EQ(90, event->getY(0)); // 50 + 40 EXPECT_EQ(-10, event->getX(1)); // -30 + 20 EXPECT_EQ(-10, event->getY(1)); // -50 + 40 } /** * Ensure the correct coordinate spaces are used by InputDispatcher. * Loading