Loading services/inputflinger/dispatcher/InputDispatcher.cpp +27 −30 Original line number Diff line number Diff line Loading @@ -3958,28 +3958,24 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( android_log_event_list(LOGTAG_INPUT_CANCEL) << connection->getInputChannelName().c_str() << reason << LOG_ID_EVENTS; sp<WindowInfoHandle> windowHandle; if (options.displayId) { windowHandle = getWindowHandleLocked(connection->inputChannel->getConnectionToken(), options.displayId.value()); } else { windowHandle = getWindowHandleLocked(connection->inputChannel->getConnectionToken()); } const bool wasEmpty = connection->outboundQueue.empty(); // The target to use if we don't find a window associated with the channel. const InputTarget fallbackTarget{.inputChannel = connection->inputChannel, .flags = InputTarget::Flags::DISPATCH_AS_IS}; const auto& token = connection->inputChannel->getConnectionToken(); for (size_t i = 0; i < cancelationEvents.size(); i++) { std::unique_ptr<EventEntry> cancelationEventEntry = std::move(cancelationEvents[i]); std::vector<InputTarget> targets{}; // The target to use if we don't find a window associated with the channel. const InputTarget fallbackTarget{.inputChannel = connection->inputChannel, .flags = InputTarget::Flags::DISPATCH_AS_IS}; switch (cancelationEventEntry->type) { case EventEntry::Type::KEY: { const auto& keyEntry = static_cast<const KeyEntry&>(*cancelationEventEntry); if (windowHandle != nullptr) { addWindowTargetLocked(windowHandle, InputTarget::Flags::DISPATCH_AS_IS, const std::optional<int32_t> targetDisplay = keyEntry.displayId != ADISPLAY_ID_NONE ? std::make_optional(keyEntry.displayId) : std::nullopt; if (const auto& window = getWindowHandleLocked(token, targetDisplay); window) { addWindowTargetLocked(window, InputTarget::Flags::DISPATCH_AS_IS, /*pointerIds=*/{}, keyEntry.downTime, targets); } else { targets.emplace_back(fallbackTarget); Loading @@ -3989,14 +3985,18 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( } case EventEntry::Type::MOTION: { const auto& motionEntry = static_cast<const MotionEntry&>(*cancelationEventEntry); if (windowHandle != nullptr) { const std::optional<int32_t> targetDisplay = motionEntry.displayId != ADISPLAY_ID_NONE ? std::make_optional(motionEntry.displayId) : std::nullopt; if (const auto& window = getWindowHandleLocked(token, targetDisplay); window) { std::bitset<MAX_POINTER_ID + 1> pointerIds; for (uint32_t pointerIndex = 0; pointerIndex < motionEntry.pointerCount; pointerIndex++) { pointerIds.set(motionEntry.pointerProperties[pointerIndex].id); } addWindowTargetLocked(windowHandle, InputTarget::Flags::DISPATCH_AS_IS, pointerIds, motionEntry.downTime, targets); addWindowTargetLocked(window, InputTarget::Flags::DISPATCH_AS_IS, pointerIds, motionEntry.downTime, targets); } else { targets.emplace_back(fallbackTarget); const auto it = mDisplayInfos.find(motionEntry.displayId); Loading Loading @@ -4905,11 +4905,13 @@ const std::vector<sp<WindowInfoHandle>>& InputDispatcher::getWindowHandlesLocked } sp<WindowInfoHandle> InputDispatcher::getWindowHandleLocked( const sp<IBinder>& windowHandleToken) const { const sp<IBinder>& windowHandleToken, std::optional<int32_t> displayId) const { if (windowHandleToken == nullptr) { return nullptr; } if (!displayId) { // Look through all displays. for (auto& it : mWindowHandlesByDisplay) { const std::vector<sp<WindowInfoHandle>>& windowHandles = it.second; for (const sp<WindowInfoHandle>& windowHandle : windowHandles) { Loading @@ -4921,13 +4923,8 @@ sp<WindowInfoHandle> InputDispatcher::getWindowHandleLocked( return nullptr; } sp<WindowInfoHandle> InputDispatcher::getWindowHandleLocked(const sp<IBinder>& windowHandleToken, int displayId) const { if (windowHandleToken == nullptr) { return nullptr; } for (const sp<WindowInfoHandle>& windowHandle : getWindowHandlesLocked(displayId)) { // Only look through the requested display. for (const sp<WindowInfoHandle>& windowHandle : getWindowHandlesLocked(*displayId)) { if (windowHandle->getToken() == windowHandleToken) { return windowHandle; } Loading services/inputflinger/dispatcher/InputDispatcher.h +3 −6 Original line number Diff line number Diff line Loading @@ -354,14 +354,11 @@ private: // Get a reference to window handles by display, return an empty vector if not found. const std::vector<sp<android::gui::WindowInfoHandle>>& getWindowHandlesLocked( int32_t displayId) const REQUIRES(mLock); sp<android::gui::WindowInfoHandle> getWindowHandleLocked( const sp<IBinder>& windowHandleToken) const REQUIRES(mLock); ui::Transform getTransformLocked(int32_t displayId) const REQUIRES(mLock); // Same function as above, but faster. Since displayId is provided, this avoids the need // to loop through all displays. sp<android::gui::WindowInfoHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken, int displayId) const REQUIRES(mLock); sp<android::gui::WindowInfoHandle> getWindowHandleLocked( const sp<IBinder>& windowHandleToken, std::optional<int32_t> displayId = {}) const REQUIRES(mLock); sp<android::gui::WindowInfoHandle> getWindowHandleLocked( const sp<android::gui::WindowInfoHandle>& windowHandle) const REQUIRES(mLock); std::shared_ptr<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const Loading services/inputflinger/tests/InputDispatcher_test.cpp +30 −0 Original line number Diff line number Diff line Loading @@ -4699,6 +4699,36 @@ TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverCancelationWithCorre firstWindow->assertNoEvents(); } TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverCancelationWithCorrectCoordinatesWhenMirrored) { auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0}; ui::Transform secondDisplayTransform; secondDisplayTransform.set(matrix); addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform); sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID); secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4); addWindow(secondWindowClone); // Send hover enter to second window mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT, {PointF{150, 220}})); secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithCoords(100, 80), WithRawCoords(300, 880), WithDisplayId(ADISPLAY_ID_DEFAULT))); mDispatcher->cancelCurrentTouch(); // Ensure the cancelation happens with the correct displayId and the correct coordinates. secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80), WithRawCoords(300, 880), WithDisplayId(ADISPLAY_ID_DEFAULT))); secondWindow->assertNoEvents(); firstWindow->assertNoEvents(); } /** Ensure consistent behavior of InputDispatcher in all orientations. */ class InputDispatcherDisplayOrientationFixture : public InputDispatcherDisplayProjectionTest, Loading Loading
services/inputflinger/dispatcher/InputDispatcher.cpp +27 −30 Original line number Diff line number Diff line Loading @@ -3958,28 +3958,24 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( android_log_event_list(LOGTAG_INPUT_CANCEL) << connection->getInputChannelName().c_str() << reason << LOG_ID_EVENTS; sp<WindowInfoHandle> windowHandle; if (options.displayId) { windowHandle = getWindowHandleLocked(connection->inputChannel->getConnectionToken(), options.displayId.value()); } else { windowHandle = getWindowHandleLocked(connection->inputChannel->getConnectionToken()); } const bool wasEmpty = connection->outboundQueue.empty(); // The target to use if we don't find a window associated with the channel. const InputTarget fallbackTarget{.inputChannel = connection->inputChannel, .flags = InputTarget::Flags::DISPATCH_AS_IS}; const auto& token = connection->inputChannel->getConnectionToken(); for (size_t i = 0; i < cancelationEvents.size(); i++) { std::unique_ptr<EventEntry> cancelationEventEntry = std::move(cancelationEvents[i]); std::vector<InputTarget> targets{}; // The target to use if we don't find a window associated with the channel. const InputTarget fallbackTarget{.inputChannel = connection->inputChannel, .flags = InputTarget::Flags::DISPATCH_AS_IS}; switch (cancelationEventEntry->type) { case EventEntry::Type::KEY: { const auto& keyEntry = static_cast<const KeyEntry&>(*cancelationEventEntry); if (windowHandle != nullptr) { addWindowTargetLocked(windowHandle, InputTarget::Flags::DISPATCH_AS_IS, const std::optional<int32_t> targetDisplay = keyEntry.displayId != ADISPLAY_ID_NONE ? std::make_optional(keyEntry.displayId) : std::nullopt; if (const auto& window = getWindowHandleLocked(token, targetDisplay); window) { addWindowTargetLocked(window, InputTarget::Flags::DISPATCH_AS_IS, /*pointerIds=*/{}, keyEntry.downTime, targets); } else { targets.emplace_back(fallbackTarget); Loading @@ -3989,14 +3985,18 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( } case EventEntry::Type::MOTION: { const auto& motionEntry = static_cast<const MotionEntry&>(*cancelationEventEntry); if (windowHandle != nullptr) { const std::optional<int32_t> targetDisplay = motionEntry.displayId != ADISPLAY_ID_NONE ? std::make_optional(motionEntry.displayId) : std::nullopt; if (const auto& window = getWindowHandleLocked(token, targetDisplay); window) { std::bitset<MAX_POINTER_ID + 1> pointerIds; for (uint32_t pointerIndex = 0; pointerIndex < motionEntry.pointerCount; pointerIndex++) { pointerIds.set(motionEntry.pointerProperties[pointerIndex].id); } addWindowTargetLocked(windowHandle, InputTarget::Flags::DISPATCH_AS_IS, pointerIds, motionEntry.downTime, targets); addWindowTargetLocked(window, InputTarget::Flags::DISPATCH_AS_IS, pointerIds, motionEntry.downTime, targets); } else { targets.emplace_back(fallbackTarget); const auto it = mDisplayInfos.find(motionEntry.displayId); Loading Loading @@ -4905,11 +4905,13 @@ const std::vector<sp<WindowInfoHandle>>& InputDispatcher::getWindowHandlesLocked } sp<WindowInfoHandle> InputDispatcher::getWindowHandleLocked( const sp<IBinder>& windowHandleToken) const { const sp<IBinder>& windowHandleToken, std::optional<int32_t> displayId) const { if (windowHandleToken == nullptr) { return nullptr; } if (!displayId) { // Look through all displays. for (auto& it : mWindowHandlesByDisplay) { const std::vector<sp<WindowInfoHandle>>& windowHandles = it.second; for (const sp<WindowInfoHandle>& windowHandle : windowHandles) { Loading @@ -4921,13 +4923,8 @@ sp<WindowInfoHandle> InputDispatcher::getWindowHandleLocked( return nullptr; } sp<WindowInfoHandle> InputDispatcher::getWindowHandleLocked(const sp<IBinder>& windowHandleToken, int displayId) const { if (windowHandleToken == nullptr) { return nullptr; } for (const sp<WindowInfoHandle>& windowHandle : getWindowHandlesLocked(displayId)) { // Only look through the requested display. for (const sp<WindowInfoHandle>& windowHandle : getWindowHandlesLocked(*displayId)) { if (windowHandle->getToken() == windowHandleToken) { return windowHandle; } Loading
services/inputflinger/dispatcher/InputDispatcher.h +3 −6 Original line number Diff line number Diff line Loading @@ -354,14 +354,11 @@ private: // Get a reference to window handles by display, return an empty vector if not found. const std::vector<sp<android::gui::WindowInfoHandle>>& getWindowHandlesLocked( int32_t displayId) const REQUIRES(mLock); sp<android::gui::WindowInfoHandle> getWindowHandleLocked( const sp<IBinder>& windowHandleToken) const REQUIRES(mLock); ui::Transform getTransformLocked(int32_t displayId) const REQUIRES(mLock); // Same function as above, but faster. Since displayId is provided, this avoids the need // to loop through all displays. sp<android::gui::WindowInfoHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken, int displayId) const REQUIRES(mLock); sp<android::gui::WindowInfoHandle> getWindowHandleLocked( const sp<IBinder>& windowHandleToken, std::optional<int32_t> displayId = {}) const REQUIRES(mLock); sp<android::gui::WindowInfoHandle> getWindowHandleLocked( const sp<android::gui::WindowInfoHandle>& windowHandle) const REQUIRES(mLock); std::shared_ptr<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const Loading
services/inputflinger/tests/InputDispatcher_test.cpp +30 −0 Original line number Diff line number Diff line Loading @@ -4699,6 +4699,36 @@ TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverCancelationWithCorre firstWindow->assertNoEvents(); } TEST_F(InputDispatcherDisplayProjectionTest, SynthesizeHoverCancelationWithCorrectCoordinatesWhenMirrored) { auto [firstWindow, secondWindow] = setupScaledDisplayScenario(); const std::array<float, 9> matrix = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 0.0, 0.0, 1.0}; ui::Transform secondDisplayTransform; secondDisplayTransform.set(matrix); addDisplayInfo(SECOND_DISPLAY_ID, secondDisplayTransform); sp<FakeWindowHandle> secondWindowClone = secondWindow->clone(SECOND_DISPLAY_ID); secondWindowClone->setWindowTransform(1.1, 2.2, 3.3, 4.4); addWindow(secondWindowClone); // Send hover enter to second window mDispatcher->notifyMotion(generateMotionArgs(ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS, ADISPLAY_ID_DEFAULT, {PointF{150, 220}})); secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_ENTER), WithCoords(100, 80), WithRawCoords(300, 880), WithDisplayId(ADISPLAY_ID_DEFAULT))); mDispatcher->cancelCurrentTouch(); // Ensure the cancelation happens with the correct displayId and the correct coordinates. secondWindow->consumeMotionEvent(AllOf(WithMotionAction(ACTION_HOVER_EXIT), WithCoords(100, 80), WithRawCoords(300, 880), WithDisplayId(ADISPLAY_ID_DEFAULT))); secondWindow->assertNoEvents(); firstWindow->assertNoEvents(); } /** Ensure consistent behavior of InputDispatcher in all orientations. */ class InputDispatcherDisplayOrientationFixture : public InputDispatcherDisplayProjectionTest, Loading