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

Commit 08fae357 authored by Prabir Pradhan's avatar Prabir Pradhan Committed by Automerger Merge Worker
Browse files

Merge changes Ic879c4c2,Ib8776101 am: 69e22e9e

parents 264a82f0 69e22e9e
Loading
Loading
Loading
Loading
+27 −6
Original line number Diff line number Diff line
@@ -107,6 +107,8 @@ constexpr int LOGTAG_INPUT_INTERACTION = 62000;
constexpr int LOGTAG_INPUT_FOCUS = 62001;
constexpr int LOGTAG_INPUT_CANCEL = 62003;

const ui::Transform kIdentityTransform;

inline nsecs_t now() {
    return systemTime(SYSTEM_TIME_MONOTONIC);
}
@@ -460,7 +462,7 @@ 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, int32_t displayId, float x, float y,
                          bool isStylus) {
                          bool isStylus, const ui::Transform& displayTransform) {
    const auto inputConfig = windowInfo.inputConfig;
    if (windowInfo.displayId != displayId ||
        inputConfig.test(WindowInfo::InputConfig::NOT_VISIBLE)) {
@@ -470,7 +472,17 @@ bool windowAcceptsTouchAt(const WindowInfo& windowInfo, int32_t displayId, float
    if (inputConfig.test(WindowInfo::InputConfig::NOT_TOUCHABLE) && !windowCanInterceptTouch) {
        return false;
    }
    if (!windowInfo.touchableRegionContainsPoint(x, y)) {

    // 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;
@@ -1072,7 +1084,8 @@ sp<WindowInfoHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayI
        }

        const WindowInfo& info = *windowHandle->getInfo();
        if (!info.isSpy() && windowAcceptsTouchAt(info, displayId, x, y, isStylus)) {
        if (!info.isSpy() &&
            windowAcceptsTouchAt(info, displayId, x, y, isStylus, getTransformLocked(displayId))) {
            return windowHandle;
        }

@@ -1093,7 +1106,7 @@ std::vector<sp<WindowInfoHandle>> InputDispatcher::findTouchedSpyWindowsAtLocked
    for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
        const WindowInfo& info = *windowHandle->getInfo();

        if (!windowAcceptsTouchAt(info, displayId, x, y, isStylus)) {
        if (!windowAcceptsTouchAt(info, displayId, x, y, isStylus, getTransformLocked(displayId))) {
            continue;
        }
        if (!info.isSpy()) {
@@ -2120,7 +2133,8 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
        }

        if (newTouchedWindows.empty()) {
            ALOGI("Dropping event because there is no touchable window at (%d, %d) on display %d.",
            ALOGI("Dropping event because there is no touchable window at (%.1f, %.1f) on display "
                  "%d.",
                  x, y, displayId);
            injectionResult = InputEventInjectionResult::FAILED;
            goto Failed;
@@ -2154,7 +2168,8 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked(
                        computeTouchOcclusionInfoLocked(windowHandle, x, y);
                if (!isTouchTrustedLocked(occlusionInfo)) {
                    if (DEBUG_TOUCH_OCCLUSION) {
                        ALOGD("Stack of obscuring windows during untrusted touch (%d, %d):", x, y);
                        ALOGD("Stack of obscuring windows during untrusted touch (%.1f, %.1f):", x,
                              y);
                        for (const auto& log : occlusionInfo.debugInfo) {
                            ALOGD("%s", log.c_str());
                        }
@@ -4579,6 +4594,12 @@ sp<WindowInfoHandle> InputDispatcher::getFocusedWindowHandleLocked(int displayId
    return getWindowHandleLocked(focusedToken, displayId);
}

ui::Transform InputDispatcher::getTransformLocked(int32_t displayId) const {
    auto displayInfoIt = mDisplayInfos.find(displayId);
    return displayInfoIt != mDisplayInfos.end() ? displayInfoIt->second.transform
                                                : kIdentityTransform;
}

bool InputDispatcher::hasResponsiveConnectionLocked(WindowInfoHandle& windowHandle) const {
    sp<Connection> connection = getConnectionLocked(windowHandle.getToken());
    const bool noInputChannel =
+1 −0
Original line number Diff line number Diff line
@@ -370,6 +370,7 @@ private:
            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.
+81 −5
Original line number Diff line number Diff line
@@ -2481,8 +2481,7 @@ class InputDispatcherDisplayProjectionTest : public InputDispatcherTest {
public:
    void SetUp() override {
        InputDispatcherTest::SetUp();
        mDisplayInfos.clear();
        mWindowInfos.clear();
        removeAllWindowsAndDisplays();
    }

    void addDisplayInfo(int displayId, const ui::Transform& transform) {
@@ -2498,6 +2497,11 @@ public:
        mDispatcher->onWindowInfosChanged(mWindowInfos, mDisplayInfos);
    }

    void removeAllWindowsAndDisplays() {
        mDisplayInfos.clear();
        mWindowInfos.clear();
    }

    // Set up a test scenario where the display has a scaled projection and there are two windows
    // on the display.
    std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupScaledDisplayScenario() {
@@ -2529,11 +2533,11 @@ private:
    std::vector<gui::WindowInfo> mWindowInfos;
};

TEST_F(InputDispatcherDisplayProjectionTest, HitTestsInDisplaySpace) {
TEST_F(InputDispatcherDisplayProjectionTest, HitTestCoordinateSpaceConsistency) {
    auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
    // Send down to the first window. The point is represented in the display space. The point is
    // selected so that if the hit test was done with the transform applied to it, then it would
    // end up in the incorrect window.
    // selected so that if the hit test was performed with the point and the bounds being in
    // different coordinate spaces, the event would end up in the incorrect window.
    NotifyMotionArgs downMotionArgs =
            generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
                               ADISPLAY_ID_DEFAULT, {PointF{75, 55}});
@@ -2608,6 +2612,78 @@ TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinate
    EXPECT_EQ(80, event->getY(0));
}

/** Ensure consistent behavior of InputDispatcher in all orientations. */
class InputDispatcherDisplayOrientationFixture
      : public InputDispatcherDisplayProjectionTest,
        public ::testing::WithParamInterface<ui::Rotation> {};

// This test verifies the touchable region of a window for all rotations of the display by tapping
// in different locations on the display, specifically points close to the four corners of a
// window.
TEST_P(InputDispatcherDisplayOrientationFixture, HitTestInDifferentOrientations) {
    constexpr static int32_t displayWidth = 400;
    constexpr static int32_t displayHeight = 800;

    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();

    const auto rotation = GetParam();

    // Set up the display with the specified rotation.
    const bool isRotated = rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270;
    const int32_t logicalDisplayWidth = isRotated ? displayHeight : displayWidth;
    const int32_t logicalDisplayHeight = isRotated ? displayWidth : displayHeight;
    const ui::Transform displayTransform(ui::Transform::toRotationFlags(rotation),
                                         logicalDisplayWidth, logicalDisplayHeight);
    addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);

    // Create a window with its bounds determined in the logical display.
    const Rect frameInLogicalDisplay(100, 100, 200, 300);
    const Rect frameInDisplay = displayTransform.inverse().transform(frameInLogicalDisplay);
    sp<FakeWindowHandle> window =
            sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
    window->setFrame(frameInDisplay, displayTransform);
    addWindow(window);

    // The following points in logical display space should be inside the window.
    static const std::array<vec2, 4> insidePoints{
            {{100, 100}, {199.99, 100}, {100, 299.99}, {199.99, 299.99}}};
    for (const auto pointInsideWindow : insidePoints) {
        const vec2 p = displayTransform.inverse().transform(pointInsideWindow);
        const PointF pointInDisplaySpace{p.x, p.y};
        const auto down = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
                                             ADISPLAY_ID_DEFAULT, {pointInDisplaySpace});
        mDispatcher->notifyMotion(&down);
        window->consumeMotionDown();

        const auto up = generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
                                           ADISPLAY_ID_DEFAULT, {pointInDisplaySpace});
        mDispatcher->notifyMotion(&up);
        window->consumeMotionUp();
    }

    // The following points in logical display space should be outside the window.
    static const std::array<vec2, 5> outsidePoints{
            {{200, 100}, {100, 300}, {200, 300}, {100, 99.99}, {99.99, 100}}};
    for (const auto pointOutsideWindow : outsidePoints) {
        const vec2 p = displayTransform.inverse().transform(pointOutsideWindow);
        const PointF pointInDisplaySpace{p.x, p.y};
        const auto down = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
                                             ADISPLAY_ID_DEFAULT, {pointInDisplaySpace});
        mDispatcher->notifyMotion(&down);

        const auto up = generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
                                           ADISPLAY_ID_DEFAULT, {pointInDisplaySpace});
        mDispatcher->notifyMotion(&up);
    }
    window->assertNoEvents();
}

// Run the precision tests for all rotations.
INSTANTIATE_TEST_SUITE_P(InputDispatcherDisplayOrientationTests,
                         InputDispatcherDisplayOrientationFixture,
                         ::testing::Values(ui::ROTATION_0, ui::ROTATION_90, ui::ROTATION_180,
                                           ui::ROTATION_270));

using TransferFunction = std::function<bool(const std::unique_ptr<InputDispatcher>& dispatcher,
                                            sp<IBinder>, sp<IBinder>)>;