Loading services/inputflinger/dispatcher/InputDispatcher.cpp +10 −23 Original line number Diff line number Diff line Loading @@ -2398,7 +2398,7 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( // Copy current touch state into tempTouchState. // This state will be used to update saved touch state at the end of this function. // If no state for the specified display exists, then our initial state will be empty. const TouchState* oldState = getTouchStateForMotionEntry(entry, windowInfos); const TouchState* oldState = getTouchStateForMotionEntry(entry); TouchState tempTouchState; if (oldState != nullptr) { tempTouchState = *oldState; Loading Loading @@ -2787,9 +2787,9 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( if (maskedAction != AMOTION_EVENT_ACTION_SCROLL) { if (displayId >= ui::LogicalDisplayId::DEFAULT) { tempTouchState.clearWindowsWithoutPointers(); saveTouchStateForMotionEntry(entry, std::move(tempTouchState), windowInfos); saveTouchStateForMotionEntry(entry, std::move(tempTouchState)); } else { eraseTouchStateForMotionEntry(entry, windowInfos); eraseTouchStateForMotionEntry(entry); } } Loading Loading @@ -5182,14 +5182,6 @@ ui::Transform InputDispatcher::DispatcherWindowInfo::getRawTransform( : getDisplayTransform(windowInfo.displayId); } ui::LogicalDisplayId InputDispatcher::DispatcherWindowInfo::getPrimaryDisplayId( ui::LogicalDisplayId displayId) const { if (mTopology.graph.contains(displayId)) { return mTopology.primaryDisplayId; } return displayId; } std::string InputDispatcher::DispatcherWindowInfo::dumpDisplayAndWindowInfo() const { std::string dump; if (!mWindowHandlesByDisplay.empty()) { Loading Loading @@ -7483,37 +7475,32 @@ void InputDispatcher::DispatcherTouchState::clear() { void InputDispatcher::DispatcherTouchState::saveTouchStateForMotionEntry( const android::inputdispatcher::MotionEntry& entry, android::inputdispatcher::TouchState&& touchState, const DispatcherWindowInfo& windowInfos) { android::inputdispatcher::TouchState&& touchState) { if (touchState.windows.empty()) { eraseTouchStateForMotionEntry(entry, windowInfos); eraseTouchStateForMotionEntry(entry); return; } if (USE_TOPOLOGY && isMouseOrTouchpad(entry.source)) { mCursorStateByDisplay[windowInfos.getPrimaryDisplayId(entry.displayId)] = std::move(touchState); mCursorStateByDisplay[entry.displayId] = std::move(touchState); } else { mTouchStatesByDisplay[entry.displayId] = std::move(touchState); } } void InputDispatcher::DispatcherTouchState::eraseTouchStateForMotionEntry( const android::inputdispatcher::MotionEntry& entry, const DispatcherWindowInfo& windowInfos) { const android::inputdispatcher::MotionEntry& entry) { if (USE_TOPOLOGY && isMouseOrTouchpad(entry.source)) { mCursorStateByDisplay.erase(windowInfos.getPrimaryDisplayId(entry.displayId)); mCursorStateByDisplay.erase(entry.displayId); } else { mTouchStatesByDisplay.erase(entry.displayId); } } const TouchState* InputDispatcher::DispatcherTouchState::getTouchStateForMotionEntry( const android::inputdispatcher::MotionEntry& entry, const DispatcherWindowInfo& windowInfos) const { const android::inputdispatcher::MotionEntry& entry) const { if (USE_TOPOLOGY && isMouseOrTouchpad(entry.source)) { auto touchStateIt = mCursorStateByDisplay.find(windowInfos.getPrimaryDisplayId(entry.displayId)); auto touchStateIt = mCursorStateByDisplay.find(entry.displayId); if (touchStateIt != mCursorStateByDisplay.end()) { return &touchStateIt->second; } Loading services/inputflinger/dispatcher/InputDispatcher.h +3 −10 Original line number Diff line number Diff line Loading @@ -336,10 +336,6 @@ private: bool isTouchTrusted(const TouchOcclusionInfo& occlusionInfo) const; // Returns topology's primary display if the display belongs to it, otherwise the // same displayId. ui::LogicalDisplayId getPrimaryDisplayId(ui::LogicalDisplayId displayId) const; std::string dumpDisplayAndWindowInfo() const; private: Loading Loading @@ -470,15 +466,12 @@ private: ftl::Flags<InputTarget::Flags> newTargetFlags, const DispatcherWindowInfo& windowInfos, const ConnectionManager& connections); void saveTouchStateForMotionEntry(const MotionEntry& entry, TouchState&& touchState, const DispatcherWindowInfo& windowInfos); void saveTouchStateForMotionEntry(const MotionEntry& entry, TouchState&& touchState); void eraseTouchStateForMotionEntry(const MotionEntry& entry, const DispatcherWindowInfo& windowInfos); void eraseTouchStateForMotionEntry(const MotionEntry& entry); const TouchState* getTouchStateForMotionEntry( const android::inputdispatcher::MotionEntry& entry, const DispatcherWindowInfo& windowInfos) const; const android::inputdispatcher::MotionEntry& entry) const; bool canWindowReceiveMotion(const sp<gui::WindowInfoHandle>& window, const MotionEntry& motionEntry, Loading services/inputflinger/dispatcher/InputState.cpp +2 −21 Original line number Diff line number Diff line Loading @@ -24,19 +24,6 @@ namespace android::inputdispatcher { namespace { const bool USE_TOPOLOGY = com::android::input::flags::connected_displays_cursor(); bool isMouseOrTouchpad(uint32_t sources) { // Check if this is a mouse or touchpad, but not a drawing tablet. return isFromSource(sources, AINPUT_SOURCE_MOUSE_RELATIVE) || (isFromSource(sources, AINPUT_SOURCE_MOUSE) && !isFromSource(sources, AINPUT_SOURCE_STYLUS)); } } // namespace InputState::InputState(const IdGenerator& idGenerator) : mIdGenerator(idGenerator) {} InputState::~InputState() {} Loading Loading @@ -234,14 +221,10 @@ ssize_t InputState::findKeyMemento(const KeyEntry& entry) const { } ssize_t InputState::findMotionMemento(const MotionEntry& entry, bool hovering) const { // If we have connected displays a mouse can move between displays and displayId may change // while a gesture is in-progress. const bool skipDisplayCheck = USE_TOPOLOGY && isMouseOrTouchpad(entry.source); for (size_t i = 0; i < mMotionMementos.size(); i++) { const MotionMemento& memento = mMotionMementos[i]; if (memento.deviceId == entry.deviceId && memento.source == entry.source && memento.hovering == hovering && (skipDisplayCheck || memento.displayId == entry.displayId)) { memento.displayId == entry.displayId && memento.hovering == hovering) { return i; } } Loading Loading @@ -355,9 +338,7 @@ bool InputState::shouldCancelPreviousStream(const MotionEntry& motionEntry) cons // would receive different events from each display. Since the TouchStates are per-display, // it's unlikely that those two streams would be consistent with each other. Therefore, // cancel the previous gesture if the display id changes. // Except when we have connected-displays where a mouse may move across display boundaries. const bool skipDisplayCheck = (USE_TOPOLOGY && isMouseOrTouchpad(motionEntry.source)); if (!skipDisplayCheck && motionEntry.displayId != lastMemento.displayId) { if (motionEntry.displayId != lastMemento.displayId) { LOG(INFO) << "Canceling stream: last displayId was " << lastMemento.displayId << " and new event is " << motionEntry; return true; Loading services/inputflinger/tests/InputDispatcher_test.cpp +0 −87 Original line number Diff line number Diff line Loading @@ -15185,91 +15185,4 @@ TEST_P(TransferOrDontTransferFixture, MouseAndTouchTransferSimultaneousMultiDevi INSTANTIATE_TEST_SUITE_P(WithAndWithoutTransfer, TransferOrDontTransferFixture, testing::Bool()); class InputDispatcherConnectedDisplayTest : public InputDispatcherTest { constexpr static int DENSITY_MEDIUM = 160; const DisplayTopologyGraph mTopology{.primaryDisplayId = DISPLAY_ID, .graph = {{DISPLAY_ID, {{SECOND_DISPLAY_ID, DisplayTopologyPosition::TOP, 0.0f}}}, {SECOND_DISPLAY_ID, {{DISPLAY_ID, DisplayTopologyPosition::BOTTOM, 0.0f}}}}, .displaysDensity = {{DISPLAY_ID, DENSITY_MEDIUM}, {SECOND_DISPLAY_ID, DENSITY_MEDIUM}}}; protected: sp<FakeWindowHandle> mWindow; void SetUp() override { InputDispatcherTest::SetUp(); mDispatcher->setDisplayTopology(mTopology); mWindow = sp<FakeWindowHandle>::make(std::make_shared<FakeApplicationHandle>(), mDispatcher, "Window", DISPLAY_ID); mWindow->setFrame({0, 0, 100, 100}); mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); } }; TEST_F(InputDispatcherConnectedDisplayTest, MultiDisplayMouseGesture) { SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true); // pointer-down mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE) .displayId(DISPLAY_ID) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) .pointer(PointerBuilder(0, ToolType::MOUSE).x(60).y(60)) .build()); mWindow->consumeMotionEvent( AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(DISPLAY_ID), WithRawCoords(60, 60))); mDispatcher->notifyMotion( MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) .displayId(DISPLAY_ID) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) .pointer(PointerBuilder(0, ToolType::MOUSE).x(60).y(60)) .build()); mWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), WithDisplayId(DISPLAY_ID), WithRawCoords(60, 60))); // pointer-move mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE) .displayId(DISPLAY_ID) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) .pointer(PointerBuilder(0, ToolType::MOUSE).x(60).y(60)) .build()); mWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithDisplayId(DISPLAY_ID), WithRawCoords(60, 60))); // pointer-move with different display // TODO (b/383092013): by default windows will not be topology aware and receive events as it // was in the same display. This behaviour has not been implemented yet. mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE) .displayId(SECOND_DISPLAY_ID) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) .pointer(PointerBuilder(0, ToolType::MOUSE).x(70).y(70)) .build()); mWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithDisplayId(SECOND_DISPLAY_ID), WithRawCoords(70, 70))); // pointer-up mDispatcher->notifyMotion( MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE, AINPUT_SOURCE_MOUSE) .displayId(SECOND_DISPLAY_ID) .buttonState(0) .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) .pointer(PointerBuilder(0, ToolType::MOUSE).x(70).y(70)) .build()); mWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), WithDisplayId(SECOND_DISPLAY_ID), WithRawCoords(70, 70))); mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE) .displayId(SECOND_DISPLAY_ID) .buttonState(0) .pointer(PointerBuilder(0, ToolType::MOUSE).x(70).y(70)) .build()); mWindow->consumeMotionUp(SECOND_DISPLAY_ID); } } // namespace android::inputdispatcher Loading
services/inputflinger/dispatcher/InputDispatcher.cpp +10 −23 Original line number Diff line number Diff line Loading @@ -2398,7 +2398,7 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( // Copy current touch state into tempTouchState. // This state will be used to update saved touch state at the end of this function. // If no state for the specified display exists, then our initial state will be empty. const TouchState* oldState = getTouchStateForMotionEntry(entry, windowInfos); const TouchState* oldState = getTouchStateForMotionEntry(entry); TouchState tempTouchState; if (oldState != nullptr) { tempTouchState = *oldState; Loading Loading @@ -2787,9 +2787,9 @@ InputDispatcher::DispatcherTouchState::findTouchedWindowTargets( if (maskedAction != AMOTION_EVENT_ACTION_SCROLL) { if (displayId >= ui::LogicalDisplayId::DEFAULT) { tempTouchState.clearWindowsWithoutPointers(); saveTouchStateForMotionEntry(entry, std::move(tempTouchState), windowInfos); saveTouchStateForMotionEntry(entry, std::move(tempTouchState)); } else { eraseTouchStateForMotionEntry(entry, windowInfos); eraseTouchStateForMotionEntry(entry); } } Loading Loading @@ -5182,14 +5182,6 @@ ui::Transform InputDispatcher::DispatcherWindowInfo::getRawTransform( : getDisplayTransform(windowInfo.displayId); } ui::LogicalDisplayId InputDispatcher::DispatcherWindowInfo::getPrimaryDisplayId( ui::LogicalDisplayId displayId) const { if (mTopology.graph.contains(displayId)) { return mTopology.primaryDisplayId; } return displayId; } std::string InputDispatcher::DispatcherWindowInfo::dumpDisplayAndWindowInfo() const { std::string dump; if (!mWindowHandlesByDisplay.empty()) { Loading Loading @@ -7483,37 +7475,32 @@ void InputDispatcher::DispatcherTouchState::clear() { void InputDispatcher::DispatcherTouchState::saveTouchStateForMotionEntry( const android::inputdispatcher::MotionEntry& entry, android::inputdispatcher::TouchState&& touchState, const DispatcherWindowInfo& windowInfos) { android::inputdispatcher::TouchState&& touchState) { if (touchState.windows.empty()) { eraseTouchStateForMotionEntry(entry, windowInfos); eraseTouchStateForMotionEntry(entry); return; } if (USE_TOPOLOGY && isMouseOrTouchpad(entry.source)) { mCursorStateByDisplay[windowInfos.getPrimaryDisplayId(entry.displayId)] = std::move(touchState); mCursorStateByDisplay[entry.displayId] = std::move(touchState); } else { mTouchStatesByDisplay[entry.displayId] = std::move(touchState); } } void InputDispatcher::DispatcherTouchState::eraseTouchStateForMotionEntry( const android::inputdispatcher::MotionEntry& entry, const DispatcherWindowInfo& windowInfos) { const android::inputdispatcher::MotionEntry& entry) { if (USE_TOPOLOGY && isMouseOrTouchpad(entry.source)) { mCursorStateByDisplay.erase(windowInfos.getPrimaryDisplayId(entry.displayId)); mCursorStateByDisplay.erase(entry.displayId); } else { mTouchStatesByDisplay.erase(entry.displayId); } } const TouchState* InputDispatcher::DispatcherTouchState::getTouchStateForMotionEntry( const android::inputdispatcher::MotionEntry& entry, const DispatcherWindowInfo& windowInfos) const { const android::inputdispatcher::MotionEntry& entry) const { if (USE_TOPOLOGY && isMouseOrTouchpad(entry.source)) { auto touchStateIt = mCursorStateByDisplay.find(windowInfos.getPrimaryDisplayId(entry.displayId)); auto touchStateIt = mCursorStateByDisplay.find(entry.displayId); if (touchStateIt != mCursorStateByDisplay.end()) { return &touchStateIt->second; } Loading
services/inputflinger/dispatcher/InputDispatcher.h +3 −10 Original line number Diff line number Diff line Loading @@ -336,10 +336,6 @@ private: bool isTouchTrusted(const TouchOcclusionInfo& occlusionInfo) const; // Returns topology's primary display if the display belongs to it, otherwise the // same displayId. ui::LogicalDisplayId getPrimaryDisplayId(ui::LogicalDisplayId displayId) const; std::string dumpDisplayAndWindowInfo() const; private: Loading Loading @@ -470,15 +466,12 @@ private: ftl::Flags<InputTarget::Flags> newTargetFlags, const DispatcherWindowInfo& windowInfos, const ConnectionManager& connections); void saveTouchStateForMotionEntry(const MotionEntry& entry, TouchState&& touchState, const DispatcherWindowInfo& windowInfos); void saveTouchStateForMotionEntry(const MotionEntry& entry, TouchState&& touchState); void eraseTouchStateForMotionEntry(const MotionEntry& entry, const DispatcherWindowInfo& windowInfos); void eraseTouchStateForMotionEntry(const MotionEntry& entry); const TouchState* getTouchStateForMotionEntry( const android::inputdispatcher::MotionEntry& entry, const DispatcherWindowInfo& windowInfos) const; const android::inputdispatcher::MotionEntry& entry) const; bool canWindowReceiveMotion(const sp<gui::WindowInfoHandle>& window, const MotionEntry& motionEntry, Loading
services/inputflinger/dispatcher/InputState.cpp +2 −21 Original line number Diff line number Diff line Loading @@ -24,19 +24,6 @@ namespace android::inputdispatcher { namespace { const bool USE_TOPOLOGY = com::android::input::flags::connected_displays_cursor(); bool isMouseOrTouchpad(uint32_t sources) { // Check if this is a mouse or touchpad, but not a drawing tablet. return isFromSource(sources, AINPUT_SOURCE_MOUSE_RELATIVE) || (isFromSource(sources, AINPUT_SOURCE_MOUSE) && !isFromSource(sources, AINPUT_SOURCE_STYLUS)); } } // namespace InputState::InputState(const IdGenerator& idGenerator) : mIdGenerator(idGenerator) {} InputState::~InputState() {} Loading Loading @@ -234,14 +221,10 @@ ssize_t InputState::findKeyMemento(const KeyEntry& entry) const { } ssize_t InputState::findMotionMemento(const MotionEntry& entry, bool hovering) const { // If we have connected displays a mouse can move between displays and displayId may change // while a gesture is in-progress. const bool skipDisplayCheck = USE_TOPOLOGY && isMouseOrTouchpad(entry.source); for (size_t i = 0; i < mMotionMementos.size(); i++) { const MotionMemento& memento = mMotionMementos[i]; if (memento.deviceId == entry.deviceId && memento.source == entry.source && memento.hovering == hovering && (skipDisplayCheck || memento.displayId == entry.displayId)) { memento.displayId == entry.displayId && memento.hovering == hovering) { return i; } } Loading Loading @@ -355,9 +338,7 @@ bool InputState::shouldCancelPreviousStream(const MotionEntry& motionEntry) cons // would receive different events from each display. Since the TouchStates are per-display, // it's unlikely that those two streams would be consistent with each other. Therefore, // cancel the previous gesture if the display id changes. // Except when we have connected-displays where a mouse may move across display boundaries. const bool skipDisplayCheck = (USE_TOPOLOGY && isMouseOrTouchpad(motionEntry.source)); if (!skipDisplayCheck && motionEntry.displayId != lastMemento.displayId) { if (motionEntry.displayId != lastMemento.displayId) { LOG(INFO) << "Canceling stream: last displayId was " << lastMemento.displayId << " and new event is " << motionEntry; return true; Loading
services/inputflinger/tests/InputDispatcher_test.cpp +0 −87 Original line number Diff line number Diff line Loading @@ -15185,91 +15185,4 @@ TEST_P(TransferOrDontTransferFixture, MouseAndTouchTransferSimultaneousMultiDevi INSTANTIATE_TEST_SUITE_P(WithAndWithoutTransfer, TransferOrDontTransferFixture, testing::Bool()); class InputDispatcherConnectedDisplayTest : public InputDispatcherTest { constexpr static int DENSITY_MEDIUM = 160; const DisplayTopologyGraph mTopology{.primaryDisplayId = DISPLAY_ID, .graph = {{DISPLAY_ID, {{SECOND_DISPLAY_ID, DisplayTopologyPosition::TOP, 0.0f}}}, {SECOND_DISPLAY_ID, {{DISPLAY_ID, DisplayTopologyPosition::BOTTOM, 0.0f}}}}, .displaysDensity = {{DISPLAY_ID, DENSITY_MEDIUM}, {SECOND_DISPLAY_ID, DENSITY_MEDIUM}}}; protected: sp<FakeWindowHandle> mWindow; void SetUp() override { InputDispatcherTest::SetUp(); mDispatcher->setDisplayTopology(mTopology); mWindow = sp<FakeWindowHandle>::make(std::make_shared<FakeApplicationHandle>(), mDispatcher, "Window", DISPLAY_ID); mWindow->setFrame({0, 0, 100, 100}); mDispatcher->onWindowInfosChanged({{*mWindow->getInfo()}, {}, 0, 0}); } }; TEST_F(InputDispatcherConnectedDisplayTest, MultiDisplayMouseGesture) { SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true); // pointer-down mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE) .displayId(DISPLAY_ID) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) .pointer(PointerBuilder(0, ToolType::MOUSE).x(60).y(60)) .build()); mWindow->consumeMotionEvent( AllOf(WithMotionAction(ACTION_DOWN), WithDisplayId(DISPLAY_ID), WithRawCoords(60, 60))); mDispatcher->notifyMotion( MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS, AINPUT_SOURCE_MOUSE) .displayId(DISPLAY_ID) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) .pointer(PointerBuilder(0, ToolType::MOUSE).x(60).y(60)) .build()); mWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), WithDisplayId(DISPLAY_ID), WithRawCoords(60, 60))); // pointer-move mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE) .displayId(DISPLAY_ID) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) .pointer(PointerBuilder(0, ToolType::MOUSE).x(60).y(60)) .build()); mWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithDisplayId(DISPLAY_ID), WithRawCoords(60, 60))); // pointer-move with different display // TODO (b/383092013): by default windows will not be topology aware and receive events as it // was in the same display. This behaviour has not been implemented yet. mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE) .displayId(SECOND_DISPLAY_ID) .buttonState(AMOTION_EVENT_BUTTON_PRIMARY) .pointer(PointerBuilder(0, ToolType::MOUSE).x(70).y(70)) .build()); mWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithDisplayId(SECOND_DISPLAY_ID), WithRawCoords(70, 70))); // pointer-up mDispatcher->notifyMotion( MotionArgsBuilder(AMOTION_EVENT_ACTION_BUTTON_RELEASE, AINPUT_SOURCE_MOUSE) .displayId(SECOND_DISPLAY_ID) .buttonState(0) .actionButton(AMOTION_EVENT_BUTTON_PRIMARY) .pointer(PointerBuilder(0, ToolType::MOUSE).x(70).y(70)) .build()); mWindow->consumeMotionEvent(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), WithDisplayId(SECOND_DISPLAY_ID), WithRawCoords(70, 70))); mDispatcher->notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE) .displayId(SECOND_DISPLAY_ID) .buttonState(0) .pointer(PointerBuilder(0, ToolType::MOUSE).x(70).y(70)) .build()); mWindow->consumeMotionUp(SECOND_DISPLAY_ID); } } // namespace android::inputdispatcher