Loading services/inputflinger/dispatcher/TouchState.cpp +2 −4 Original line number Original line Diff line number Diff line Loading @@ -33,8 +33,7 @@ void TouchState::reset() { void TouchState::removeTouchedPointer(int32_t pointerId) { void TouchState::removeTouchedPointer(int32_t pointerId) { for (TouchedWindow& touchedWindow : windows) { for (TouchedWindow& touchedWindow : windows) { touchedWindow.pointerIds.reset(pointerId); touchedWindow.removeTouchingPointer(pointerId); touchedWindow.pilferedPointerIds.reset(pointerId); } } } } Loading @@ -42,8 +41,7 @@ void TouchState::removeTouchedPointerFromWindow( int32_t pointerId, const sp<android::gui::WindowInfoHandle>& windowHandle) { int32_t pointerId, const sp<android::gui::WindowInfoHandle>& windowHandle) { for (TouchedWindow& touchedWindow : windows) { for (TouchedWindow& touchedWindow : windows) { if (touchedWindow.windowHandle == windowHandle) { if (touchedWindow.windowHandle == windowHandle) { touchedWindow.pointerIds.reset(pointerId); touchedWindow.removeTouchingPointer(pointerId); touchedWindow.pilferedPointerIds.reset(pointerId); return; return; } } } } Loading services/inputflinger/dispatcher/TouchedWindow.cpp +8 −0 Original line number Original line Diff line number Diff line Loading @@ -50,6 +50,14 @@ void TouchedWindow::addHoveringPointer(int32_t deviceId, int32_t pointerId) { it->second.set(pointerId); it->second.set(pointerId); } } void TouchedWindow::removeTouchingPointer(int32_t pointerId) { pointerIds.reset(pointerId); pilferedPointerIds.reset(pointerId); if (pointerIds.none()) { firstDownTimeInTarget.reset(); } } void TouchedWindow::removeHoveringPointer(int32_t deviceId, int32_t pointerId) { void TouchedWindow::removeHoveringPointer(int32_t deviceId, int32_t pointerId) { const auto it = mHoveringPointerIdsByDevice.find(deviceId); const auto it = mHoveringPointerIdsByDevice.find(deviceId); if (it == mHoveringPointerIdsByDevice.end()) { if (it == mHoveringPointerIdsByDevice.end()) { Loading services/inputflinger/dispatcher/TouchedWindow.h +1 −0 Original line number Original line Diff line number Diff line Loading @@ -43,6 +43,7 @@ struct TouchedWindow { bool hasHoveringPointer(int32_t deviceId, int32_t pointerId) const; bool hasHoveringPointer(int32_t deviceId, int32_t pointerId) const; void addHoveringPointer(int32_t deviceId, int32_t pointerId); void addHoveringPointer(int32_t deviceId, int32_t pointerId); void removeHoveringPointer(int32_t deviceId, int32_t pointerId); void removeHoveringPointer(int32_t deviceId, int32_t pointerId); void removeTouchingPointer(int32_t pointerId); void clearHoveringPointers(); void clearHoveringPointers(); std::string dump() const; std::string dump() const; Loading services/inputflinger/tests/InputDispatcher_test.cpp +96 −0 Original line number Original line Diff line number Diff line Loading @@ -2171,6 +2171,102 @@ TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap) { rightWindow->assertNoEvents(); rightWindow->assertNoEvents(); } } /** * This test is similar to the test above, but the sequence of injected events is different. * * Two windows: a window on the left and a window on the right. * Mouse is hovered over the left window. * Next, we tap on the left window, where the cursor was last seen. * * After that, we inject one finger down onto the right window, and then a second finger down onto * the left window. * The touch is split, so this last gesture should cause 2 ACTION_DOWN events, one in the right * window (first), and then another on the left window (second). * This test reproduces a crash where there is a mismatch between the downTime and eventTime. * In the buggy implementation, second finger down on the left window would cause a crash. */ TEST_F(InputDispatcherTest, HoverTapAndSplitTouch) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); leftWindow->setFrame(Rect(0, 0, 200, 200)); sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); rightWindow->setFrame(Rect(200, 0, 400, 200)); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {leftWindow, rightWindow}}}); const int32_t mouseDeviceId = 6; const int32_t touchDeviceId = 4; // Hover over the left window. Keep the cursor there. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) .deviceId(mouseDeviceId) .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) .x(50) .y(50)) .build())); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); // Tap on left window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER) .x(100) .y(100)) .build())); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER) .x(100) .y(100)) .build())); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP)); // First finger down on right window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER) .x(300) .y(100)) .build())); rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); // Second finger down on the left window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER) .x(300) .y(100)) .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER) .x(100) .y(100)) .build())); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_MOVE)); // No more events leftWindow->assertNoEvents(); rightWindow->assertNoEvents(); } /** /** * On the display, have a single window, and also an area where there's no window. * 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. * First pointer touches the "no window" area of the screen. Second pointer touches the window. Loading Loading
services/inputflinger/dispatcher/TouchState.cpp +2 −4 Original line number Original line Diff line number Diff line Loading @@ -33,8 +33,7 @@ void TouchState::reset() { void TouchState::removeTouchedPointer(int32_t pointerId) { void TouchState::removeTouchedPointer(int32_t pointerId) { for (TouchedWindow& touchedWindow : windows) { for (TouchedWindow& touchedWindow : windows) { touchedWindow.pointerIds.reset(pointerId); touchedWindow.removeTouchingPointer(pointerId); touchedWindow.pilferedPointerIds.reset(pointerId); } } } } Loading @@ -42,8 +41,7 @@ void TouchState::removeTouchedPointerFromWindow( int32_t pointerId, const sp<android::gui::WindowInfoHandle>& windowHandle) { int32_t pointerId, const sp<android::gui::WindowInfoHandle>& windowHandle) { for (TouchedWindow& touchedWindow : windows) { for (TouchedWindow& touchedWindow : windows) { if (touchedWindow.windowHandle == windowHandle) { if (touchedWindow.windowHandle == windowHandle) { touchedWindow.pointerIds.reset(pointerId); touchedWindow.removeTouchingPointer(pointerId); touchedWindow.pilferedPointerIds.reset(pointerId); return; return; } } } } Loading
services/inputflinger/dispatcher/TouchedWindow.cpp +8 −0 Original line number Original line Diff line number Diff line Loading @@ -50,6 +50,14 @@ void TouchedWindow::addHoveringPointer(int32_t deviceId, int32_t pointerId) { it->second.set(pointerId); it->second.set(pointerId); } } void TouchedWindow::removeTouchingPointer(int32_t pointerId) { pointerIds.reset(pointerId); pilferedPointerIds.reset(pointerId); if (pointerIds.none()) { firstDownTimeInTarget.reset(); } } void TouchedWindow::removeHoveringPointer(int32_t deviceId, int32_t pointerId) { void TouchedWindow::removeHoveringPointer(int32_t deviceId, int32_t pointerId) { const auto it = mHoveringPointerIdsByDevice.find(deviceId); const auto it = mHoveringPointerIdsByDevice.find(deviceId); if (it == mHoveringPointerIdsByDevice.end()) { if (it == mHoveringPointerIdsByDevice.end()) { Loading
services/inputflinger/dispatcher/TouchedWindow.h +1 −0 Original line number Original line Diff line number Diff line Loading @@ -43,6 +43,7 @@ struct TouchedWindow { bool hasHoveringPointer(int32_t deviceId, int32_t pointerId) const; bool hasHoveringPointer(int32_t deviceId, int32_t pointerId) const; void addHoveringPointer(int32_t deviceId, int32_t pointerId); void addHoveringPointer(int32_t deviceId, int32_t pointerId); void removeHoveringPointer(int32_t deviceId, int32_t pointerId); void removeHoveringPointer(int32_t deviceId, int32_t pointerId); void removeTouchingPointer(int32_t pointerId); void clearHoveringPointers(); void clearHoveringPointers(); std::string dump() const; std::string dump() const; Loading
services/inputflinger/tests/InputDispatcher_test.cpp +96 −0 Original line number Original line Diff line number Diff line Loading @@ -2171,6 +2171,102 @@ TEST_F(InputDispatcherTest, HoverFromLeftToRightAndTap) { rightWindow->assertNoEvents(); rightWindow->assertNoEvents(); } } /** * This test is similar to the test above, but the sequence of injected events is different. * * Two windows: a window on the left and a window on the right. * Mouse is hovered over the left window. * Next, we tap on the left window, where the cursor was last seen. * * After that, we inject one finger down onto the right window, and then a second finger down onto * the left window. * The touch is split, so this last gesture should cause 2 ACTION_DOWN events, one in the right * window (first), and then another on the left window (second). * This test reproduces a crash where there is a mismatch between the downTime and eventTime. * In the buggy implementation, second finger down on the left window would cause a crash. */ TEST_F(InputDispatcherTest, HoverTapAndSplitTouch) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> leftWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT); leftWindow->setFrame(Rect(0, 0, 200, 200)); sp<FakeWindowHandle> rightWindow = sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT); rightWindow->setFrame(Rect(200, 0, 400, 200)); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {leftWindow, rightWindow}}}); const int32_t mouseDeviceId = 6; const int32_t touchDeviceId = 4; // Hover over the left window. Keep the cursor there. ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) .deviceId(mouseDeviceId) .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_MOUSE) .x(50) .y(50)) .build())); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); // Tap on left window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER) .x(100) .y(100)) .build())); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER) .x(100) .y(100)) .build())); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT)); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_UP)); // First finger down on right window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER) .x(300) .y(100)) .build())); rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); // Second finger down on the left window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .deviceId(touchDeviceId) .pointer(PointerBuilder(0, AMOTION_EVENT_TOOL_TYPE_FINGER) .x(300) .y(100)) .pointer(PointerBuilder(1, AMOTION_EVENT_TOOL_TYPE_FINGER) .x(100) .y(100)) .build())); leftWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_DOWN)); rightWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_MOVE)); // No more events leftWindow->assertNoEvents(); rightWindow->assertNoEvents(); } /** /** * On the display, have a single window, and also an area where there's no window. * 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. * First pointer touches the "no window" area of the screen. Second pointer touches the window. Loading