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

Commit 00f511d3 authored by Garfield Tan's avatar Garfield Tan
Browse files

Dispatch mouse events to window under the cursor.

This CL adds cursor positions to NotifyMotionArgs, MotionEntry,
InputMessage motion body and MotionEvent.

Bug: 134788085
Test: The window under the cursor always responds to the gesture.
Test: atest inputflinger_tests
Test: atest libinput_tests
Change-Id: I8ea460ed8738ffc3a5e997215685889cc1e1f2fe
parent eb6ab629
Loading
Loading
Loading
Loading
+27 −21
Original line number Original line Diff line number Diff line
@@ -24,12 +24,14 @@
 */
 */


#include <android/input.h>
#include <android/input.h>
#include <stdint.h>
#include <utils/BitSet.h>
#include <utils/BitSet.h>
#include <utils/KeyedVector.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
#include <utils/Timers.h>
#include <utils/Vector.h>
#include <utils/Vector.h>
#include <stdint.h>

#include <limits>


/*
/*
 * Additional private constants not defined in ndk/ui/input.h.
 * Additional private constants not defined in ndk/ui/input.h.
@@ -246,6 +248,13 @@ enum class MotionClassification : uint8_t {
 */
 */
const char* motionClassificationToString(MotionClassification classification);
const char* motionClassificationToString(MotionClassification classification);


/**
 * Invalid value for cursor position. Used for non-mouse events, tests and injected events. Don't
 * use it for direct comparison with any other value, because NaN isn't equal to itself according to
 * IEEE 754. Use isnan() instead to check if a cursor position is valid.
 */
constexpr float AMOTION_EVENT_INVALID_CURSOR_POSITION = std::numeric_limits<float>::quiet_NaN();

/*
/*
 * Pointer coordinate data.
 * Pointer coordinate data.
 */
 */
@@ -459,6 +468,14 @@ public:


    inline float getYPrecision() const { return mYPrecision; }
    inline float getYPrecision() const { return mYPrecision; }


    inline float getRawXCursorPosition() const { return mXCursorPosition; }

    float getXCursorPosition() const;

    inline float getRawYCursorPosition() const { return mYCursorPosition; }

    float getYCursorPosition() const;

    inline nsecs_t getDownTime() const { return mDownTime; }
    inline nsecs_t getDownTime() const { return mDownTime; }


    inline void setDownTime(nsecs_t downTime) { mDownTime = downTime; }
    inline void setDownTime(nsecs_t downTime) { mDownTime = downTime; }
@@ -600,25 +617,12 @@ public:


    ssize_t findPointerIndex(int32_t pointerId) const;
    ssize_t findPointerIndex(int32_t pointerId) const;


    void initialize(
    void initialize(int32_t deviceId, int32_t source, int32_t displayId, int32_t action,
            int32_t deviceId,
                    int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState,
            int32_t source,
                    int32_t buttonState, MotionClassification classification, float xOffset,
            int32_t displayId,
                    float yOffset, float xPrecision, float yPrecision, float mXCursorPosition,
            int32_t action,
                    float mYCursorPosition, nsecs_t downTime, nsecs_t eventTime,
            int32_t actionButton,
                    size_t pointerCount, const PointerProperties* pointerProperties,
            int32_t flags,
            int32_t edgeFlags,
            int32_t metaState,
            int32_t buttonState,
            MotionClassification classification,
            float xOffset,
            float yOffset,
            float xPrecision,
            float yPrecision,
            nsecs_t downTime,
            nsecs_t eventTime,
            size_t pointerCount,
            const PointerProperties* pointerProperties,
                    const PointerCoords* pointerCoords);
                    const PointerCoords* pointerCoords);


    void copyFrom(const MotionEvent* other, bool keepHistory);
    void copyFrom(const MotionEvent* other, bool keepHistory);
@@ -669,6 +673,8 @@ protected:
    float mYOffset;
    float mYOffset;
    float mXPrecision;
    float mXPrecision;
    float mYPrecision;
    float mYPrecision;
    float mXCursorPosition;
    float mYCursorPosition;
    nsecs_t mDownTime;
    nsecs_t mDownTime;
    Vector<PointerProperties> mPointerProperties;
    Vector<PointerProperties> mPointerProperties;
    Vector<nsecs_t> mSampleEventTimes;
    Vector<nsecs_t> mSampleEventTimes;
+10 −21
Original line number Original line Diff line number Diff line
@@ -113,6 +113,8 @@ struct InputMessage {
            float yOffset;
            float yOffset;
            float xPrecision;
            float xPrecision;
            float yPrecision;
            float yPrecision;
            float xCursorPosition;
            float yCursorPosition;
            uint32_t pointerCount;
            uint32_t pointerCount;
            uint32_t empty3;
            uint32_t empty3;
            // Note that PointerCoords requires 8 byte alignment.
            // Note that PointerCoords requires 8 byte alignment.
@@ -261,26 +263,13 @@ public:
     * Returns BAD_VALUE if seq is 0 or if pointerCount is less than 1 or greater than MAX_POINTERS.
     * Returns BAD_VALUE if seq is 0 or if pointerCount is less than 1 or greater than MAX_POINTERS.
     * Other errors probably indicate that the channel is broken.
     * Other errors probably indicate that the channel is broken.
     */
     */
    status_t publishMotionEvent(
    status_t publishMotionEvent(uint32_t seq, int32_t deviceId, int32_t source, int32_t displayId,
            uint32_t seq,
                                int32_t action, int32_t actionButton, int32_t flags,
            int32_t deviceId,
                                int32_t edgeFlags, int32_t metaState, int32_t buttonState,
            int32_t source,
                                MotionClassification classification, float xOffset, float yOffset,
            int32_t displayId,
                                float xPrecision, float yPrecision, float xCursorPosition,
            int32_t action,
                                float yCursorPosition, nsecs_t downTime, nsecs_t eventTime,
            int32_t actionButton,
                                uint32_t pointerCount, const PointerProperties* pointerProperties,
            int32_t flags,
            int32_t edgeFlags,
            int32_t metaState,
            int32_t buttonState,
            MotionClassification classification,
            float xOffset,
            float yOffset,
            float xPrecision,
            float yPrecision,
            nsecs_t downTime,
            nsecs_t eventTime,
            uint32_t pointerCount,
            const PointerProperties* pointerProperties,
                                const PointerCoords* pointerCoords);
                                const PointerCoords* pointerCoords);


    /* Receives the finished signal from the consumer in reply to the original dispatch signal.
    /* Receives the finished signal from the consumer in reply to the original dispatch signal.
+35 −20
Original line number Original line Diff line number Diff line
@@ -235,25 +235,13 @@ void PointerProperties::copyFrom(const PointerProperties& other) {


// --- MotionEvent ---
// --- MotionEvent ---


void MotionEvent::initialize(
void MotionEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId, int32_t action,
        int32_t deviceId,
                             int32_t actionButton, int32_t flags, int32_t edgeFlags,
        int32_t source,
                             int32_t metaState, int32_t buttonState,
        int32_t displayId,
                             MotionClassification classification, float xOffset, float yOffset,
        int32_t action,
                             float xPrecision, float yPrecision, float xCursorPosition,
        int32_t actionButton,
                             float yCursorPosition, nsecs_t downTime, nsecs_t eventTime,
        int32_t flags,
                             size_t pointerCount, const PointerProperties* pointerProperties,
        int32_t edgeFlags,
        int32_t metaState,
        int32_t buttonState,
        MotionClassification classification,
        float xOffset,
        float yOffset,
        float xPrecision,
        float yPrecision,
        nsecs_t downTime,
        nsecs_t eventTime,
        size_t pointerCount,
        const PointerProperties* pointerProperties,
                             const PointerCoords* pointerCoords) {
                             const PointerCoords* pointerCoords) {
    InputEvent::initialize(deviceId, source, displayId);
    InputEvent::initialize(deviceId, source, displayId);
    mAction = action;
    mAction = action;
@@ -267,6 +255,8 @@ void MotionEvent::initialize(
    mYOffset = yOffset;
    mYOffset = yOffset;
    mXPrecision = xPrecision;
    mXPrecision = xPrecision;
    mYPrecision = yPrecision;
    mYPrecision = yPrecision;
    mXCursorPosition = xCursorPosition;
    mYCursorPosition = yCursorPosition;
    mDownTime = downTime;
    mDownTime = downTime;
    mPointerProperties.clear();
    mPointerProperties.clear();
    mPointerProperties.appendArray(pointerProperties, pointerCount);
    mPointerProperties.appendArray(pointerProperties, pointerCount);
@@ -288,6 +278,8 @@ void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) {
    mYOffset = other->mYOffset;
    mYOffset = other->mYOffset;
    mXPrecision = other->mXPrecision;
    mXPrecision = other->mXPrecision;
    mYPrecision = other->mYPrecision;
    mYPrecision = other->mYPrecision;
    mXCursorPosition = other->mXCursorPosition;
    mYCursorPosition = other->mYCursorPosition;
    mDownTime = other->mDownTime;
    mDownTime = other->mDownTime;
    mPointerProperties = other->mPointerProperties;
    mPointerProperties = other->mPointerProperties;


@@ -312,6 +304,16 @@ void MotionEvent::addSample(
    mSamplePointerCoords.appendArray(pointerCoords, getPointerCount());
    mSamplePointerCoords.appendArray(pointerCoords, getPointerCount());
}
}


float MotionEvent::getXCursorPosition() const {
    const float rawX = getRawXCursorPosition();
    return rawX + mXOffset;
}

float MotionEvent::getYCursorPosition() const {
    const float rawY = getRawYCursorPosition();
    return rawY + mYOffset;
}

const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const {
const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const {
    return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex];
    return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex];
}
}
@@ -431,6 +433,15 @@ void MotionEvent::transform(const float matrix[9]) {
    float originX, originY;
    float originX, originY;
    transformPoint(matrix, 0, 0, &originX, &originY);
    transformPoint(matrix, 0, 0, &originX, &originY);


    // Apply the transformation to cursor position.
    if (!isnan(mXCursorPosition) && !isnan(mYCursorPosition)) {
        float x = mXCursorPosition + oldXOffset;
        float y = mYCursorPosition + oldYOffset;
        transformPoint(matrix, x, y, &x, &y);
        mXCursorPosition = x - mXOffset;
        mYCursorPosition = y - mYOffset;
    }

    // Apply the transformation to all samples.
    // Apply the transformation to all samples.
    size_t numSamples = mSamplePointerCoords.size();
    size_t numSamples = mSamplePointerCoords.size();
    for (size_t i = 0; i < numSamples; i++) {
    for (size_t i = 0; i < numSamples; i++) {
@@ -470,6 +481,8 @@ status_t MotionEvent::readFromParcel(Parcel* parcel) {
    mYOffset = parcel->readFloat();
    mYOffset = parcel->readFloat();
    mXPrecision = parcel->readFloat();
    mXPrecision = parcel->readFloat();
    mYPrecision = parcel->readFloat();
    mYPrecision = parcel->readFloat();
    mXCursorPosition = parcel->readFloat();
    mYCursorPosition = parcel->readFloat();
    mDownTime = parcel->readInt64();
    mDownTime = parcel->readInt64();


    mPointerProperties.clear();
    mPointerProperties.clear();
@@ -521,6 +534,8 @@ status_t MotionEvent::writeToParcel(Parcel* parcel) const {
    parcel->writeFloat(mYOffset);
    parcel->writeFloat(mYOffset);
    parcel->writeFloat(mXPrecision);
    parcel->writeFloat(mXPrecision);
    parcel->writeFloat(mYPrecision);
    parcel->writeFloat(mYPrecision);
    parcel->writeFloat(mXCursorPosition);
    parcel->writeFloat(mYCursorPosition);
    parcel->writeInt64(mDownTime);
    parcel->writeInt64(mDownTime);


    for (size_t i = 0; i < pointerCount; i++) {
    for (size_t i = 0; i < pointerCount; i++) {
+22 −40
Original line number Original line Diff line number Diff line
@@ -191,6 +191,10 @@ void InputMessage::getSanitizedCopy(InputMessage* msg) const {
            msg->body.motion.xPrecision = body.motion.xPrecision;
            msg->body.motion.xPrecision = body.motion.xPrecision;
            // float yPrecision
            // float yPrecision
            msg->body.motion.yPrecision = body.motion.yPrecision;
            msg->body.motion.yPrecision = body.motion.yPrecision;
            // float xCursorPosition
            msg->body.motion.xCursorPosition = body.motion.xCursorPosition;
            // float yCursorPosition
            msg->body.motion.yCursorPosition = body.motion.yCursorPosition;
            // uint32_t pointerCount
            // uint32_t pointerCount
            msg->body.motion.pointerCount = body.motion.pointerCount;
            msg->body.motion.pointerCount = body.motion.pointerCount;
            //struct Pointer pointers[MAX_POINTERS]
            //struct Pointer pointers[MAX_POINTERS]
@@ -465,26 +469,12 @@ status_t InputPublisher::publishKeyEvent(
}
}


status_t InputPublisher::publishMotionEvent(
status_t InputPublisher::publishMotionEvent(
        uint32_t seq,
        uint32_t seq, int32_t deviceId, int32_t source, int32_t displayId, int32_t action,
        int32_t deviceId,
        int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState,
        int32_t source,
        int32_t buttonState, MotionClassification classification, float xOffset, float yOffset,
        int32_t displayId,
        float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition,
        int32_t action,
        nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount,
        int32_t actionButton,
        const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) {
        int32_t flags,
        int32_t edgeFlags,
        int32_t metaState,
        int32_t buttonState,
        MotionClassification classification,
        float xOffset,
        float yOffset,
        float xPrecision,
        float yPrecision,
        nsecs_t downTime,
        nsecs_t eventTime,
        uint32_t pointerCount,
        const PointerProperties* pointerProperties,
        const PointerCoords* pointerCoords) {
    if (ATRACE_ENABLED()) {
    if (ATRACE_ENABLED()) {
        std::string message = StringPrintf(
        std::string message = StringPrintf(
                "publishMotionEvent(inputChannel=%s, action=%" PRId32 ")",
                "publishMotionEvent(inputChannel=%s, action=%" PRId32 ")",
@@ -532,6 +522,8 @@ status_t InputPublisher::publishMotionEvent(
    msg.body.motion.yOffset = yOffset;
    msg.body.motion.yOffset = yOffset;
    msg.body.motion.xPrecision = xPrecision;
    msg.body.motion.xPrecision = xPrecision;
    msg.body.motion.yPrecision = yPrecision;
    msg.body.motion.yPrecision = yPrecision;
    msg.body.motion.xCursorPosition = xCursorPosition;
    msg.body.motion.yCursorPosition = yCursorPosition;
    msg.body.motion.downTime = downTime;
    msg.body.motion.downTime = downTime;
    msg.body.motion.eventTime = eventTime;
    msg.body.motion.eventTime = eventTime;
    msg.body.motion.pointerCount = pointerCount;
    msg.body.motion.pointerCount = pointerCount;
@@ -1135,26 +1127,16 @@ void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage
        pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
        pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
    }
    }


    event->initialize(
    event->initialize(msg->body.motion.deviceId, msg->body.motion.source,
            msg->body.motion.deviceId,
                      msg->body.motion.displayId, msg->body.motion.action,
            msg->body.motion.source,
                      msg->body.motion.actionButton, msg->body.motion.flags,
            msg->body.motion.displayId,
                      msg->body.motion.edgeFlags, msg->body.motion.metaState,
            msg->body.motion.action,
                      msg->body.motion.buttonState, msg->body.motion.classification,
            msg->body.motion.actionButton,
                      msg->body.motion.xOffset, msg->body.motion.yOffset,
            msg->body.motion.flags,
                      msg->body.motion.xPrecision, msg->body.motion.yPrecision,
            msg->body.motion.edgeFlags,
                      msg->body.motion.xCursorPosition, msg->body.motion.yCursorPosition,
            msg->body.motion.metaState,
                      msg->body.motion.downTime, msg->body.motion.eventTime, pointerCount,
            msg->body.motion.buttonState,
                      pointerProperties, pointerCoords);
            msg->body.motion.classification,
            msg->body.motion.xOffset,
            msg->body.motion.yOffset,
            msg->body.motion.xPrecision,
            msg->body.motion.yPrecision,
            msg->body.motion.downTime,
            msg->body.motion.eventTime,
            pointerCount,
            pointerProperties,
            pointerCoords);
}
}


void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) {
void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) {
+40 −12
Original line number Original line Diff line number Diff line
@@ -255,11 +255,11 @@ void MotionEventTest::initializeEventWithHistory(MotionEvent* event) {
    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27);
    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27);
    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28);
    pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28);
    event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE, 0,
    event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE, 0,
            AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
                      AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, AMOTION_EVENT_EDGE_FLAG_TOP,
            AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
                      AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY, MotionClassification::NONE,
            MotionClassification::NONE, X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
                      X_OFFSET, Y_OFFSET, 2.0f, 2.1f, AMOTION_EVENT_INVALID_CURSOR_POSITION,
            ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_DOWN_TIME,
            2, pointerProperties, pointerCoords);
                      ARBITRARY_EVENT_TIME, 2, pointerProperties, pointerCoords);


    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110);
    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110);
    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111);
    pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111);
@@ -571,10 +571,11 @@ TEST_F(MotionEventTest, Transform) {
    }
    }
    MotionEvent event;
    MotionEvent event;
    event.initialize(0 /*deviceId*/, AINPUT_SOURCE_UNKNOWN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE,
    event.initialize(0 /*deviceId*/, AINPUT_SOURCE_UNKNOWN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE,
            0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE,
                     0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE,
            AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE,
                     0 /*buttonState*/, MotionClassification::NONE, 0 /*xOffset*/, 0 /*yOffset*/,
            0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/,
                     0 /*xPrecision*/, 0 /*yPrecision*/, 3 + RADIUS /*xCursorPosition*/,
            0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords);
                     2 /*yCursorPosition*/, 0 /*downTime*/, 0 /*eventTime*/, pointerCount,
                     pointerProperties, pointerCoords);
    float originalRawX = 0 + 3;
    float originalRawX = 0 + 3;
    float originalRawY = -RADIUS + 2;
    float originalRawY = -RADIUS + 2;


@@ -602,6 +603,10 @@ TEST_F(MotionEventTest, Transform) {
        ASSERT_NEAR(tanf(angle), tanf(event.getOrientation(i)), 0.1);
        ASSERT_NEAR(tanf(angle), tanf(event.getOrientation(i)), 0.1);
    }
    }


    // Check cursor positions.
    ASSERT_NEAR(sinf(PI_180 * (90 + ROTATION)) * RADIUS, event.getXCursorPosition(), 0.001);
    ASSERT_NEAR(-cosf(PI_180 * (90 + ROTATION)) * RADIUS, event.getYCursorPosition(), 0.001);

    // Applying the transformation should preserve the raw X and Y of the first point.
    // Applying the transformation should preserve the raw X and Y of the first point.
    ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001);
    ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001);
    ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
    ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
@@ -626,11 +631,34 @@ TEST_F(MotionEventTest, Initialize_SetsClassification) {


    for (MotionClassification classification : classifications) {
    for (MotionClassification classification : classifications) {
        event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
        event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
                AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0,
                         AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE,
                classification, 0, 0, 0, 0, 0 /*downTime*/, 0 /*eventTime*/,
                         0, classification, 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
                         AMOTION_EVENT_INVALID_CURSOR_POSITION, 0 /*downTime*/, 0 /*eventTime*/,
                         pointerCount, pointerProperties, pointerCoords);
                         pointerCount, pointerProperties, pointerCoords);
        ASSERT_EQ(classification, event.getClassification());
        ASSERT_EQ(classification, event.getClassification());
    }
    }
}
}


TEST_F(MotionEventTest, Initialize_SetsCursorPosition) {
    MotionEvent event;
    constexpr size_t pointerCount = 1;
    PointerProperties pointerProperties[pointerCount];
    PointerCoords pointerCoords[pointerCount];
    for (size_t i = 0; i < pointerCount; i++) {
        pointerProperties[i].clear();
        pointerProperties[i].id = i;
        pointerCoords[i].clear();
    }

    event.initialize(0 /*deviceId*/, AINPUT_SOURCE_MOUSE, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0,
                     0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE, 0,
                     0, 0, 0, 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, 0 /*downTime*/,
                     0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords);
    event.offsetLocation(20, 60);
    ASSERT_EQ(280, event.getRawXCursorPosition());
    ASSERT_EQ(540, event.getRawYCursorPosition());
    ASSERT_EQ(300, event.getXCursorPosition());
    ASSERT_EQ(600, event.getYCursorPosition());
}

} // namespace android
} // namespace android
Loading