Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 204b3bc7 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "[CD Cursor] Enable gesture transfer across connected displays" into main

parents da713fe6 105a3fca
Loading
Loading
Loading
Loading
+40 −3
Original line number Diff line number Diff line
@@ -5067,8 +5067,19 @@ sp<WindowInfoHandle> InputDispatcher::DispatcherWindowInfo::findWindowHandle(
    }

    // Only look through the requested display.
    for (const sp<WindowInfoHandle>& windowHandle : getWindowHandlesForDisplay(*displayId)) {
        if (windowHandle->getToken() == windowHandleToken) {
    return findWindowHandleOnDisplay(windowHandleToken, *displayId);
}

sp<WindowInfoHandle> InputDispatcher::DispatcherWindowInfo::findWindowHandleOnConnectedDisplays(
        const sp<IBinder>& windowHandleToken, ui::LogicalDisplayId displayId) const {
    if (windowHandleToken == nullptr) {
        return nullptr;
    }

    sp<WindowInfoHandle> windowHandle;
    for (ui::LogicalDisplayId connectedDisplayId : getConnectedDisplays(displayId)) {
        windowHandle = findWindowHandleOnDisplay(windowHandleToken, connectedDisplayId);
        if (windowHandle != nullptr) {
            return windowHandle;
        }
    }
@@ -5214,6 +5225,29 @@ std::string InputDispatcher::DispatcherWindowInfo::dumpDisplayAndWindowInfo() co
    return dump;
}

std::vector<ui::LogicalDisplayId> InputDispatcher::DispatcherWindowInfo::getConnectedDisplays(
        ui::LogicalDisplayId displayId) const {
    if (!mTopology.graph.contains(displayId)) {
        return {displayId};
    }

    std::vector<ui::LogicalDisplayId> connectedDisplays;
    for (auto it : mTopology.graph) {
        connectedDisplays.push_back(it.first);
    }
    return connectedDisplays;
}

sp<WindowInfoHandle> InputDispatcher::DispatcherWindowInfo::findWindowHandleOnDisplay(
        const sp<IBinder>& windowHandleToken, ui::LogicalDisplayId displayId) const {
    for (const sp<WindowInfoHandle>& windowHandle : getWindowHandlesForDisplay(displayId)) {
        if (windowHandle->getToken() == windowHandleToken) {
            return windowHandle;
        }
    }
    return nullptr;
}

bool InputDispatcher::DispatcherTouchState::canWindowReceiveMotion(
        const sp<android::gui::WindowInfoHandle>& window,
        const android::inputdispatcher::MotionEntry& motionEntry) const {
@@ -5806,7 +5840,10 @@ InputDispatcher::DispatcherTouchState::transferTouchGesture(const sp<android::IB
    const DeviceId deviceId = *deviceIds.begin();

    const sp<WindowInfoHandle> fromWindowHandle = touchedWindow.windowHandle;
    const sp<WindowInfoHandle> toWindowHandle = mWindowInfos.findWindowHandle(toToken, displayId);
    // TouchState displayId may not be same as window displayId, we need to lookup for toToken on
    // all connected displays.
    const sp<WindowInfoHandle> toWindowHandle =
            mWindowInfos.findWindowHandleOnConnectedDisplays(toToken, displayId);
    if (!toWindowHandle) {
        ALOGW("Cannot transfer touch because the transfer target window was not found.");
        return std::nullopt;
+11 −0
Original line number Diff line number Diff line
@@ -319,6 +319,11 @@ private:
                const sp<IBinder>& windowHandleToken,
                std::optional<ui::LogicalDisplayId> displayId = {}) const;

        // Lookup for WindowInfoHandle from token and a display-id. Lookup is done for all connected
        // displays in the topology of the queried display.
        sp<android::gui::WindowInfoHandle> findWindowHandleOnConnectedDisplays(
                const sp<IBinder>& windowHandleToken, ui::LogicalDisplayId displayId) const;

        bool isWindowPresent(const sp<android::gui::WindowInfoHandle>& windowHandle) const;

        // Returns the touched window at the given location, excluding the ignoreWindow if provided.
@@ -349,6 +354,12 @@ private:
        std::string dumpDisplayAndWindowInfo() const;

    private:
        std::vector<ui::LogicalDisplayId> getConnectedDisplays(
                ui::LogicalDisplayId displayId) const;

        sp<android::gui::WindowInfoHandle> findWindowHandleOnDisplay(
                const sp<IBinder>& windowHandleToken, ui::LogicalDisplayId displayId) const;

        std::unordered_map<ui::LogicalDisplayId /*displayId*/,
                           std::vector<sp<android::gui::WindowInfoHandle>>>
                mWindowHandlesByDisplay;
+77 −20
Original line number Diff line number Diff line
@@ -12414,18 +12414,22 @@ protected:
                 0});
    }
    void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
    void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN,
                    ui::LogicalDisplayId displayId = ui::LogicalDisplayId::DEFAULT) {
        bool consumeButtonPress = false;
        const PointF location =
                displayId == ui::LogicalDisplayId::DEFAULT ? PointF(50, 50) : PointF(50, 450);
        switch (fromSource) {
            case AINPUT_SOURCE_TOUCHSCREEN: {
                ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
                          injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
                                           ui::LogicalDisplayId::DEFAULT, {50, 50}))
                          injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, displayId,
                                           location))
                        << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
                break;
            }
            case AINPUT_SOURCE_STYLUS: {
                PointerBuilder pointer = PointerBuilder(0, ToolType::STYLUS).x(50).y(50);
                PointerBuilder pointer =
                        PointerBuilder(0, ToolType::STYLUS).x(location.x).y(location.y);
                ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
                          injectMotionEvent(*mDispatcher,
                                            MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
@@ -12448,12 +12452,14 @@ protected:
                break;
            }
            case AINPUT_SOURCE_MOUSE: {
                PointerBuilder pointer =
                        PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE).x(50).y(50);
                PointerBuilder pointer = PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
                                                 .x(location.x)
                                                 .y(location.y);
                ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
                          injectMotionEvent(*mDispatcher,
                                            MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
                                                               AINPUT_SOURCE_MOUSE)
                                                    .displayId(displayId)
                                                    .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
                                                    .pointer(pointer)
                                                    .build()));
@@ -12461,6 +12467,7 @@ protected:
                          injectMotionEvent(*mDispatcher,
                                            MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS,
                                                               AINPUT_SOURCE_MOUSE)
                                                    .displayId(displayId)
                                                    .actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
                                                    .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
                                                    .pointer(pointer)
@@ -12474,25 +12481,30 @@ protected:
        }
        // Window should receive motion event.
        mWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
        sp<FakeWindowHandle>& targetWindow =
                displayId == ui::LogicalDisplayId::DEFAULT ? mWindow : mWindowOnSecondDisplay;
        targetWindow->consumeMotionDown(displayId);
        if (consumeButtonPress) {
            mWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
            targetWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
        }
        // Spy window should also receive motion event
        // Spy window should also receive motion event if event is on the same display.
        if (displayId == ui::LogicalDisplayId::DEFAULT) {
            mSpyWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
        }
    }
    // Start performing drag, we will create a drag window and transfer touch to it.
    // @param sendDown : if true, send a motion down on first window before perform drag and drop.
    // Returns true on success.
    bool startDrag(bool sendDown = true, int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
    bool startDrag(bool sendDown = true, int fromSource = AINPUT_SOURCE_TOUCHSCREEN,
                   ui::LogicalDisplayId dragStartDisplay = ui::LogicalDisplayId::DEFAULT) {
        if (sendDown) {
            injectDown(fromSource);
            injectDown(fromSource, dragStartDisplay);
        }
        // The drag window covers the entire display
        mDragWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "DragWindow",
                                                 ui::LogicalDisplayId::DEFAULT);
        mDragWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "DragWindow", dragStartDisplay);
        mDragWindow->setTouchableRegion(Region{{0, 0, 0, 0}});
        mDispatcher->onWindowInfosChanged(
                {{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(),
@@ -12501,14 +12513,17 @@ protected:
                 0,
                 0});
        sp<FakeWindowHandle>& targetWindow = dragStartDisplay == ui::LogicalDisplayId::DEFAULT
                ? mWindow
                : mWindowOnSecondDisplay;
        // Transfer touch focus to the drag window
        bool transferred =
                mDispatcher->transferTouchGesture(mWindow->getToken(), mDragWindow->getToken(),
                mDispatcher->transferTouchGesture(targetWindow->getToken(), mDragWindow->getToken(),
                                                  /*isDragDrop=*/true);
        if (transferred) {
            mWindow->consumeMotionCancel();
            mDragWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT,
                                           AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
            targetWindow->consumeMotionCancel(dragStartDisplay);
            mDragWindow->consumeMotionDown(dragStartDisplay, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
        }
        return transferred;
    }
@@ -15292,10 +15307,10 @@ TEST_F(InputDispatcherConnectedDisplayTest, MultiDisplayMouseGesture) {
    mWindow->consumeMotionUp(SECOND_DISPLAY_ID);
}
TEST_F(InputDispatcherConnectedDisplayTest, MultiDisplayMouseDragAndDrop) {
TEST_F(InputDispatcherConnectedDisplayTest, MultiDisplayMouseDragAndDropFromPrimaryDisplay) {
    SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
    startDrag(true, AINPUT_SOURCE_MOUSE);
    EXPECT_TRUE(startDrag(true, AINPUT_SOURCE_MOUSE));
    // Move on window.
    mDispatcher->notifyMotion(
            MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
@@ -15346,4 +15361,46 @@ TEST_F(InputDispatcherConnectedDisplayTest, MultiDisplayMouseDragAndDrop) {
    mWindowOnSecondDisplay->assertNoEvents();
}
TEST_F(InputDispatcherConnectedDisplayTest, MultiDisplayMouseDragAndDropFromNonPrimaryDisplay) {
    SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
    EXPECT_TRUE(startDrag(true, AINPUT_SOURCE_MOUSE, SECOND_DISPLAY_ID));
    // Move on window.
    mDispatcher->notifyMotion(
            MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
                    .displayId(SECOND_DISPLAY_ID)
                    .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
                    .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE).x(50).y(50))
                    .build());
    mDragWindow->consumeMotionMove(SECOND_DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
    mWindow->assertNoEvents();
    mSecondWindow->assertNoEvents();
    mWindowOnSecondDisplay->consumeDragEvent(false, 50, 50);
    // Move to window on the primary display
    mDispatcher->notifyMotion(
            MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
                    .displayId(DISPLAY_ID)
                    .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
                    .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE).x(50).y(50))
                    .build());
    mDragWindow->consumeMotionMove(DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
    mWindow->consumeDragEvent(false, 50, 50);
    mSecondWindow->assertNoEvents();
    mWindowOnSecondDisplay->consumeDragEvent(true, 50, 50);
    // drop on the primary display
    mDispatcher->notifyMotion(
            MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
                    .displayId(DISPLAY_ID)
                    .buttonState(0)
                    .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE).x(50).y(50))
                    .build());
    mDragWindow->consumeMotionUp(DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
    mFakePolicy->assertDropTargetEquals(*mDispatcher, mWindow->getToken());
    mWindow->assertNoEvents();
    mSecondWindow->assertNoEvents();
    mWindowOnSecondDisplay->assertNoEvents();
}
} // namespace android::inputdispatcher