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

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

Merge "[CD Cursor] Remove displayId check from windowAcceptsTouchAt" into main

parents 9fb2ee50 52c5ed25
Loading
Loading
Loading
Loading
+37 −35
Original line number Diff line number Diff line
@@ -578,34 +578,6 @@ bool isUserActivityEvent(const EventEntry& eventEntry) {
    }
}

// Returns true if the given window can accept pointer events at the given display location.
bool windowAcceptsTouchAt(const WindowInfo& windowInfo, ui::LogicalDisplayId displayId, float x,
                          float y, bool isStylus, const ui::Transform& displayTransform) {
    const auto inputConfig = windowInfo.inputConfig;
    if (windowInfo.displayId != displayId ||
        inputConfig.test(WindowInfo::InputConfig::NOT_VISIBLE)) {
        return false;
    }
    const bool windowCanInterceptTouch = isStylus && windowInfo.interceptsStylus();
    if (inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) && !windowCanInterceptTouch) {
        return false;
    }

    // Window Manager works in the logical display coordinate space. When it specifies bounds for a
    // window as (l, t, r, b), the range of x in [l, r) and y in [t, b) are considered to be inside
    // the window. Points on the right and bottom edges should not be inside the window, so we need
    // to be careful about performing a hit test when the display is rotated, since the "right" and
    // "bottom" of the window will be different in the display (un-rotated) space compared to in the
    // logical display in which WM determined the bounds. Perform the hit test in the logical
    // display space to ensure these edges are considered correctly in all orientations.
    const auto touchableRegion = displayTransform.transform(windowInfo.touchableRegion);
    const auto p = displayTransform.transform(x, y);
    if (!touchableRegion.contains(std::floor(p.x), std::floor(p.y))) {
        return false;
    }
    return true;
}

// Returns true if the given window's frame can occlude pointer events at the given display
// location.
bool windowOccludesTouchAt(const WindowInfo& windowInfo, ui::LogicalDisplayId displayId, float x,
@@ -1461,8 +1433,7 @@ sp<WindowInfoHandle> InputDispatcher::DispatcherWindowInfo::findTouchedWindowAt(
        }

        const WindowInfo& info = *windowHandle->getInfo();
        if (!info.isSpy() &&
            windowAcceptsTouchAt(info, displayId, x, y, isStylus, getDisplayTransform(displayId))) {
        if (!info.isSpy() && windowAcceptsTouchAt(info, displayId, x, y, isStylus)) {
            return windowHandle;
        }
    }
@@ -1503,11 +1474,10 @@ std::vector<sp<WindowInfoHandle>> InputDispatcher::findTouchedSpyWindowsAt(
        const DispatcherWindowInfo& windowInfos) {
    // Traverse windows from front to back and gather the touched spy windows.
    std::vector<sp<WindowInfoHandle>> spyWindows;
    const ui::Transform displayTransform = windowInfos.getDisplayTransform(displayId);
    const auto& windowHandles = windowInfos.getWindowHandlesForDisplay(displayId);
    for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
        const WindowInfo& info = *windowHandle->getInfo();
        if (!windowAcceptsTouchAt(info, displayId, x, y, isStylus, displayTransform)) {
        if (!windowInfos.windowAcceptsTouchAt(info, displayId, x, y, isStylus)) {
            // Skip if the pointer is outside of the window.
            continue;
        }
@@ -5269,6 +5239,36 @@ ui::Transform InputDispatcher::DispatcherWindowInfo::getRawTransform(
    return getDisplayTransform(windowInfo.displayId);
}

bool InputDispatcher::DispatcherWindowInfo::windowAcceptsTouchAt(const gui::WindowInfo& windowInfo,
                                                                 ui::LogicalDisplayId displayId,
                                                                 float x, float y,
                                                                 bool isStylus) const {
    const auto inputConfig = windowInfo.inputConfig;
    if (windowInfo.displayId != displayId ||
        inputConfig.test(WindowInfo::InputConfig::NOT_VISIBLE)) {
        return false;
    }
    const bool windowCanInterceptTouch = isStylus && windowInfo.interceptsStylus();
    if (inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) && !windowCanInterceptTouch) {
        return false;
    }

    // Window Manager works in the logical display coordinate space. When it specifies bounds for a
    // window as (l, t, r, b), the range of x in [l, r) and y in [t, b) are considered to be inside
    // the window. Points on the right and bottom edges should not be inside the window, so we need
    // to be careful about performing a hit test when the display is rotated, since the "right" and
    // "bottom" of the window will be different in the display (un-rotated) space compared to in the
    // logical display in which WM determined the bounds. Perform the hit test in the logical
    // display space to ensure these edges are considered correctly in all orientations.
    const ui::Transform& displayTransform = getDisplayTransform(windowInfo.displayId);
    const auto touchableRegion = displayTransform.transform(windowInfo.touchableRegion);
    const auto p = displayTransform.transform(x, y);
    if (!touchableRegion.contains(std::floor(p.x), std::floor(p.y))) {
        return false;
    }
    return true;
}

ui::LogicalDisplayId InputDispatcher::DispatcherWindowInfo::getPrimaryDisplayId(
        ui::LogicalDisplayId displayId) const {
    if (mTopology.graph.contains(displayId)) {
@@ -5616,14 +5616,16 @@ InputDispatcher::DispatcherTouchState::updateHoveringStateFromWindowInfo(
    std::list<CancellationArgs> cancellations;
    // Check if the hovering should stop because the window is no longer eligible to receive it
    // (for example, if the touchable region changed)
    ui::Transform displayTransform = mWindowInfos.getDisplayTransform(displayId);
    for (TouchedWindow& touchedWindow : state.windows) {
        const gui::WindowInfo& windowInfo = *touchedWindow.windowHandle->getInfo();
        std::vector<DeviceId> erasedDevices = touchedWindow.eraseHoveringPointersIf(
                [&](const PointerProperties& properties, float x, float y) {
                    const bool isStylus = properties.toolType == ToolType::STYLUS;
                    // The touchstate's displayId may be different from window's display on the
                    // connected-displays, for this reason we use use window's displayId here.
                    const bool stillAcceptsTouch =
                            windowAcceptsTouchAt(*touchedWindow.windowHandle->getInfo(), displayId,
                                                 x, y, isStylus, displayTransform);
                            mWindowInfos.windowAcceptsTouchAt(windowInfo, windowInfo.displayId, x,
                                                              y, isStylus);
                    return !stillAcceptsTouch;
                });

+4 −0
Original line number Diff line number Diff line
@@ -342,6 +342,10 @@ private:
        sp<android::gui::WindowInfoHandle> findWallpaperWindowBelow(
                const sp<android::gui::WindowInfoHandle>& windowHandle) const;

        // Returns true if the given window can accept pointer events at the given display location.
        bool windowAcceptsTouchAt(const gui::WindowInfo& windowInfo, ui::LogicalDisplayId displayId,
                                  float x, float y, bool isStylus) const;

        bool isTouchTrusted(const TouchOcclusionInfo& occlusionInfo) const;

        // Returns topology's primary display if the display belongs to it, otherwise the
+45 −1
Original line number Diff line number Diff line
@@ -15488,6 +15488,7 @@ TEST_P(TransferOrDontTransferFixture, MouseAndTouchTransferSimultaneousMultiDevi
INSTANTIATE_TEST_SUITE_P(WithAndWithoutTransfer, TransferOrDontTransferFixture, testing::Bool());
class InputDispatcherConnectedDisplayTest : public InputDispatcherDragTests {
protected:
    constexpr static int DENSITY_MEDIUM = 160;
    const DisplayTopologyGraph mTopology =
@@ -15503,7 +15504,6 @@ class InputDispatcherConnectedDisplayTest : public InputDispatcherDragTests {
                                          {SECOND_DISPLAY_ID, DENSITY_MEDIUM}})
                    .value();
protected:
    void SetUp() override {
        addDisplay(DISPLAY_ID, ui::Transform());
        addDisplay(SECOND_DISPLAY_ID,
@@ -15674,6 +15674,50 @@ TEST_F(InputDispatcherConnectedDisplayTest, MultiDisplayMouseDragAndDropFromNonP
    mWindowOnSecondDisplay->assertNoEvents();
}
/**
 * Test that touch state is maintained across windowInfo updates on the non-primary display.
 *
 * Create two windows, one on the primary display and another on the secondary display.
 * Start hovering on the window on the secondary display.
 *
 * Update the window info, and verify that the hover state is maintained, and no events are
 * generated.
 *
 * Remove the window on the secondary display, and verify that the window receives a HOVER_EXIT
 * event.
 */
TEST_F(InputDispatcherConnectedDisplayTest,
       NonPrimaryDisplayTouchStateIsMaintainedOnWindowInfoUpdate) {
    SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
    sp<FakeWindowHandle> window0 =
            sp<FakeWindowHandle>::make(std::make_shared<FakeApplicationHandle>(), mDispatcher,
                                       "TestWindowOnPrimaryDisplay", mTopology.primaryDisplayId);
    window0->setFrame(Rect(0, 0, 500, 500));
    sp<FakeWindowHandle> window1 =
            sp<FakeWindowHandle>::make(std::make_shared<FakeApplicationHandle>(), mDispatcher,
                                       "TestWindowOnNonPrimaryDisplay", SECOND_DISPLAY_ID);
    window1->setFrame(Rect(0, 0, 500, 500));
    mDispatcher->onWindowInfosChanged({{*window0->getInfo(), *window1->getInfo()}, {}, 0, 0});
    // Add hover state to window on display 1.
    mDispatcher->notifyMotion(
            MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
                    .displayId(SECOND_DISPLAY_ID)
                    .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE).x(100).y(100))
                    .build());
    window1->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
    // Sending same window info should not generate any events.
    mDispatcher->onWindowInfosChanged({{*window0->getInfo(), *window1->getInfo()}, {}, 0, 0});
    window1->assertNoEvents();
    // Remove the window now, it should receive hover_exit as usual.
    mDispatcher->onWindowInfosChanged({{}, {}, 0, 0});
    window1->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_EXIT));
    window0->assertNoEvents();
}
using InputDispatcherConnectedDisplayPointerInWindowTest = InputDispatcherConnectedDisplayTest;
TEST_F(InputDispatcherConnectedDisplayPointerInWindowTest, MouseOnWindowOnPrimaryDisplay) {