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

Commit 64a70881 authored by Arpit Singh's avatar Arpit Singh
Browse files

Check if cursor has moved out of viewport bounds in CursorController

This CL updates CursorController to check if and which boundary the
cursor has crossed. This will be used to enable cursor moving between
different connected displays.

Test: atest inputflinger_tests
Test: verify cursor can move between displays as expected
Bug: 367660694
Flag: com.android.input.flags.connected_displays_cursor
Change-Id: Ida11e897d4e6767549dcc40da5c83e4c6be178c9
parent c60efe59
Loading
Loading
Loading
Loading
+23 −11
Original line number Original line Diff line number Diff line
@@ -28,12 +28,14 @@
#define INDENT "  "
#define INDENT "  "
#define INDENT2 "    "
#define INDENT2 "    "


namespace android {

namespace {
namespace {

// Time to spend fading out the pointer completely.
// Time to spend fading out the pointer completely.
const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms
const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms
} // namespace


namespace android {
} // namespace


// --- MouseCursorController ---
// --- MouseCursorController ---


@@ -64,17 +66,23 @@ MouseCursorController::~MouseCursorController() {
    mLocked.pointerSprite.clear();
    mLocked.pointerSprite.clear();
}
}


void MouseCursorController::move(float deltaX, float deltaY) {
FloatPoint MouseCursorController::move(float deltaX, float deltaY) {
#if DEBUG_MOUSE_CURSOR_UPDATES
#if DEBUG_MOUSE_CURSOR_UPDATES
    ALOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY);
    ALOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY);
#endif
#endif
    if (deltaX == 0.0f && deltaY == 0.0f) {
    if (deltaX == 0.0f && deltaY == 0.0f) {
        return;
        return {0, 0};
    }
    }


    // When transition occurs, the MouseCursorController object may or may not be deleted, depending
    // if there's another display on the other side of the transition. At this point we still need
    // to move the cursor to the boundary.
    std::scoped_lock lock(mLock);
    std::scoped_lock lock(mLock);

    const FloatPoint position{mLocked.pointerX + deltaX, mLocked.pointerY + deltaY};
    setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY);
    setPositionLocked(position.x, position.y);
    // The amount of the delta that was not consumed as a result of the cursor
    // hitting the edge of the display.
    return {position.x - mLocked.pointerX, position.y - mLocked.pointerY};
}
}


void MouseCursorController::setPosition(float x, float y) {
void MouseCursorController::setPosition(float x, float y) {
@@ -85,19 +93,23 @@ void MouseCursorController::setPosition(float x, float y) {
    setPositionLocked(x, y);
    setPositionLocked(x, y);
}
}


void MouseCursorController::setPositionLocked(float x, float y) REQUIRES(mLock) {
FloatRect MouseCursorController::getBoundsLocked() REQUIRES(mLock) {
    const auto& v = mLocked.viewport;
    if (!v.isValid()) return;

    // The valid bounds for a mouse cursor. Since the right and bottom edges are considered outside
    // The valid bounds for a mouse cursor. Since the right and bottom edges are considered outside
    // the display, clip the bounds by one pixel instead of letting the cursor get arbitrarily
    // the display, clip the bounds by one pixel instead of letting the cursor get arbitrarily
    // close to the outside edge.
    // close to the outside edge.
    const FloatRect bounds{
    return FloatRect{
            static_cast<float>(mLocked.viewport.logicalLeft),
            static_cast<float>(mLocked.viewport.logicalLeft),
            static_cast<float>(mLocked.viewport.logicalTop),
            static_cast<float>(mLocked.viewport.logicalTop),
            static_cast<float>(mLocked.viewport.logicalRight - 1),
            static_cast<float>(mLocked.viewport.logicalRight - 1),
            static_cast<float>(mLocked.viewport.logicalBottom - 1),
            static_cast<float>(mLocked.viewport.logicalBottom - 1),
    };
    };
}

void MouseCursorController::setPositionLocked(float x, float y) REQUIRES(mLock) {
    const auto& v = mLocked.viewport;
    if (!v.isValid()) return;

    const FloatRect bounds = getBoundsLocked();
    mLocked.pointerX = std::max(bounds.left, std::min(bounds.right, x));
    mLocked.pointerX = std::max(bounds.left, std::min(bounds.right, x));
    mLocked.pointerY = std::max(bounds.top, std::min(bounds.bottom, y));
    mLocked.pointerY = std::max(bounds.top, std::min(bounds.bottom, y));


+3 −4
Original line number Original line Diff line number Diff line
@@ -20,9 +20,6 @@
#include <gui/DisplayEventReceiver.h>
#include <gui/DisplayEventReceiver.h>
#include <input/DisplayViewport.h>
#include <input/DisplayViewport.h>
#include <input/Input.h>
#include <input/Input.h>
#include <utils/BitSet.h>
#include <utils/Looper.h>
#include <utils/RefBase.h>


#include <functional>
#include <functional>
#include <map>
#include <map>
@@ -43,7 +40,8 @@ public:
    MouseCursorController(PointerControllerContext& context);
    MouseCursorController(PointerControllerContext& context);
    ~MouseCursorController();
    ~MouseCursorController();


    void move(float deltaX, float deltaY);
    // Move the pointer and return unconsumed delta
    FloatPoint move(float deltaX, float deltaY);
    void setPosition(float x, float y);
    void setPosition(float x, float y);
    FloatPoint getPosition() const;
    FloatPoint getPosition() const;
    ui::LogicalDisplayId getDisplayId() const;
    ui::LogicalDisplayId getDisplayId() const;
@@ -113,6 +111,7 @@ private:
    bool doFadingAnimationLocked(nsecs_t timestamp);
    bool doFadingAnimationLocked(nsecs_t timestamp);


    void startAnimationLocked();
    void startAnimationLocked();
    FloatRect getBoundsLocked();
};
};


} // namespace android
} // namespace android
+9 −5
Original line number Original line Diff line number Diff line
@@ -138,15 +138,19 @@ std::mutex& PointerController::getLock() const {
    return mDisplayInfoListener->mLock;
    return mDisplayInfoListener->mLock;
}
}


void PointerController::move(float deltaX, float deltaY) {
FloatPoint PointerController::move(float deltaX, float deltaY) {
    const ui::LogicalDisplayId displayId = mCursorController.getDisplayId();
    const ui::LogicalDisplayId displayId = mCursorController.getDisplayId();
    vec2 transformed;
    ui::Transform transform;
    {
    {
        std::scoped_lock lock(getLock());
        std::scoped_lock lock(getLock());
        const auto& transform = getTransformForDisplayLocked(displayId);
        transform = getTransformForDisplayLocked(displayId);
        transformed = transformWithoutTranslation(transform, {deltaX, deltaY});
    }
    }
    mCursorController.move(transformed.x, transformed.y);

    const vec2 transformed = transformWithoutTranslation(transform, {deltaX, deltaY});

    const FloatPoint unconsumedDelta = mCursorController.move(transformed.x, transformed.y);
    return FloatPoint(transformWithoutTranslation(transform.inverse(),
                                                  {unconsumedDelta.x, unconsumedDelta.y}));
}
}


void PointerController::setPosition(float x, float y) {
void PointerController::setPosition(float x, float y) {
+2 −2
Original line number Original line Diff line number Diff line
@@ -51,7 +51,7 @@ public:


    ~PointerController() override;
    ~PointerController() override;


    void move(float deltaX, float deltaY) override;
    FloatPoint move(float deltaX, float deltaY) override;
    void setPosition(float x, float y) override;
    void setPosition(float x, float y) override;
    FloatPoint getPosition() const override;
    FloatPoint getPosition() const override;
    ui::LogicalDisplayId getDisplayId() const override;
    ui::LogicalDisplayId getDisplayId() const override;
@@ -165,7 +165,7 @@ public:


    ~TouchPointerController() override;
    ~TouchPointerController() override;


    void move(float, float) override {
    FloatPoint move(float, float) override {
        LOG_ALWAYS_FATAL("Should not be called");
        LOG_ALWAYS_FATAL("Should not be called");
    }
    }
    void setPosition(float, float) override {
    void setPosition(float, float) override {
+131 −0
Original line number Original line Diff line number Diff line
@@ -40,6 +40,8 @@ enum TestCursorType {
    CURSOR_TYPE_CUSTOM = -1,
    CURSOR_TYPE_CUSTOM = -1,
};
};


static constexpr float EPSILON = MotionEvent::ROUNDING_PRECISION;

using ::testing::AllOf;
using ::testing::AllOf;
using ::testing::Field;
using ::testing::Field;
using ::testing::NiceMock;
using ::testing::NiceMock;
@@ -399,6 +401,135 @@ INSTANTIATE_TEST_SUITE_P(PointerControllerSkipScreenshotFlagTest,
                         testing::Values(PointerControllerInterface::ControllerType::MOUSE,
                         testing::Values(PointerControllerInterface::ControllerType::MOUSE,
                                         PointerControllerInterface::ControllerType::STYLUS));
                                         PointerControllerInterface::ControllerType::STYLUS));


class MousePointerControllerTest : public PointerControllerTest {
protected:
    MousePointerControllerTest() {
        sp<MockSprite> testPointerSprite(new NiceMock<MockSprite>);
        EXPECT_CALL(*mSpriteController, createSprite).WillOnce(Return(testPointerSprite));

        // create a mouse pointer controller
        mPointerController =
                PointerController::create(mPolicy, mLooper, *mSpriteController,
                                          PointerControllerInterface::ControllerType::MOUSE);

        // set display viewport
        DisplayViewport viewport;
        viewport.displayId = ui::LogicalDisplayId::DEFAULT;
        viewport.logicalRight = 5;
        viewport.logicalBottom = 5;
        viewport.physicalRight = 5;
        viewport.physicalBottom = 5;
        viewport.deviceWidth = 5;
        viewport.deviceHeight = 5;
        mPointerController->setDisplayViewport(viewport);
    }
};

struct MousePointerControllerTestParam {
    vec2 startPosition;
    vec2 delta;
    vec2 endPosition;
    vec2 unconsumedDelta;
};

class PointerControllerViewportTransitionTest
      : public MousePointerControllerTest,
        public testing::WithParamInterface<MousePointerControllerTestParam> {};

TEST_P(PointerControllerViewportTransitionTest, testPointerViewportTransition) {
    const auto& params = GetParam();

    mPointerController->setPosition(params.startPosition.x, params.startPosition.y);
    auto unconsumedDelta = mPointerController->move(params.delta.x, params.delta.y);

    auto position = mPointerController->getPosition();
    EXPECT_NEAR(position.x, params.endPosition.x, EPSILON);
    EXPECT_NEAR(position.y, params.endPosition.y, EPSILON);
    EXPECT_NEAR(unconsumedDelta.x, params.unconsumedDelta.x, EPSILON);
    EXPECT_NEAR(unconsumedDelta.y, params.unconsumedDelta.y, EPSILON);
}

INSTANTIATE_TEST_SUITE_P(PointerControllerViewportTransitionTest,
                         PointerControllerViewportTransitionTest,
                         testing::Values(
                                 // no transition
                                 MousePointerControllerTestParam{{2.0f, 2.0f},
                                                                 {2.0f, 2.0f},
                                                                 {4.0f, 4.0f},
                                                                 {0.0f, 0.0f}},
                                 // right boundary
                                 MousePointerControllerTestParam{{2.0f, 2.0f},
                                                                 {3.0f, 0.0f},
                                                                 {4.0f, 2.0f},
                                                                 {1.0f, 0.0f}},
                                 MousePointerControllerTestParam{{2.0f, 2.0f},
                                                                 {3.0f, -1.0f},
                                                                 {4.0f, 1.0f},
                                                                 {1.0f, 0.0f}},
                                 MousePointerControllerTestParam{{2.0f, 2.0f},
                                                                 {3.0f, 1.0f},
                                                                 {4.0f, 3.0f},
                                                                 {1.0f, 0.0f}},
                                 // left boundary
                                 MousePointerControllerTestParam{{2.0f, 2.0f},
                                                                 {-3.0f, 0.0f},
                                                                 {0.0f, 2.0f},
                                                                 {-1.0f, 0.0f}},
                                 MousePointerControllerTestParam{{2.0f, 2.0f},
                                                                 {-3.0f, -1.0f},
                                                                 {0.0f, 1.0f},
                                                                 {-1.0f, 0.0f}},
                                 MousePointerControllerTestParam{{2.0f, 2.0f},
                                                                 {-3.0f, 1.0f},
                                                                 {0.0f, 3.0f},
                                                                 {-1.0f, 0.0f}},
                                 // bottom boundary
                                 MousePointerControllerTestParam{{2.0f, 2.0f},
                                                                 {0.0f, 3.0f},
                                                                 {2.0f, 4.0f},
                                                                 {0.0f, 1.0f}},
                                 MousePointerControllerTestParam{{2.0f, 2.0f},
                                                                 {-1.0f, 3.0f},
                                                                 {1.0f, 4.0f},
                                                                 {0.0f, 1.0f}},
                                 MousePointerControllerTestParam{{2.0f, 2.0f},
                                                                 {1.0f, 3.0f},
                                                                 {3.0f, 4.0f},
                                                                 {0.0f, 1.0f}},
                                 // top boundary
                                 MousePointerControllerTestParam{{2.0f, 2.0f},
                                                                 {0.0f, -3.0f},
                                                                 {2.0f, 0.0f},
                                                                 {0.0f, -1.0f}},
                                 MousePointerControllerTestParam{{2.0f, 2.0f},
                                                                 {-1.0f, -3.0f},
                                                                 {1.0f, 0.0f},
                                                                 {0.0f, -1.0f}},
                                 MousePointerControllerTestParam{{2.0f, 2.0f},
                                                                 {1.0f, -3.0f},
                                                                 {3.0f, 0.0f},
                                                                 {0.0f, -1.0f}},
                                 // top-left corner
                                 MousePointerControllerTestParam{{2.0f, 2.0f},
                                                                 {-3.0f, -3.0f},
                                                                 {0.0f, 0.0f},
                                                                 {-1.0f, -1.0f}},
                                 // top-right corner
                                 MousePointerControllerTestParam{{2.0f, 2.0f},
                                                                 {3.0f, -3.0f},
                                                                 {4.0f, 0.0f},
                                                                 {1.0f, -1.0f}},
                                 // bottom-right corner
                                 MousePointerControllerTestParam{{2.0f, 2.0f},
                                                                 {3.0f, 3.0f},
                                                                 {4.0f, 4.0f},
                                                                 {1.0f, 1.0f}},
                                 // bottom-left corner
                                 MousePointerControllerTestParam{{2.0f, 2.0f},
                                                                 {-3.0f, 3.0f},
                                                                 {0.0f, 4.0f},
                                                                 {-1.0f, 1.0f}}));

class PointerControllerWindowInfoListenerTest : public Test {};
class PointerControllerWindowInfoListenerTest : public Test {};


TEST_F(PointerControllerWindowInfoListenerTest,
TEST_F(PointerControllerWindowInfoListenerTest,