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
diff --git a/include/input/Input.h b/include/input/Input.h
index 805957a..a976246 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -24,12 +24,14 @@
  */
 
 #include <android/input.h>
+#include <stdint.h>
 #include <utils/BitSet.h>
 #include <utils/KeyedVector.h>
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
 #include <utils/Vector.h>
-#include <stdint.h>
+
+#include <limits>
 
 /*
  * Additional private constants not defined in ndk/ui/input.h.
@@ -246,6 +248,13 @@
  */
 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.
  */
@@ -459,6 +468,14 @@
 
     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 void setDownTime(nsecs_t downTime) { mDownTime = downTime; }
@@ -600,26 +617,13 @@
 
     ssize_t findPointerIndex(int32_t pointerId) const;
 
-    void initialize(
-            int32_t deviceId,
-            int32_t source,
-            int32_t displayId,
-            int32_t action,
-            int32_t actionButton,
-            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);
+    void initialize(int32_t deviceId, int32_t source, int32_t displayId, int32_t action,
+                    int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState,
+                    int32_t buttonState, MotionClassification classification, float xOffset,
+                    float yOffset, float xPrecision, float yPrecision, float mXCursorPosition,
+                    float mYCursorPosition, nsecs_t downTime, nsecs_t eventTime,
+                    size_t pointerCount, const PointerProperties* pointerProperties,
+                    const PointerCoords* pointerCoords);
 
     void copyFrom(const MotionEvent* other, bool keepHistory);
 
@@ -669,6 +673,8 @@
     float mYOffset;
     float mXPrecision;
     float mYPrecision;
+    float mXCursorPosition;
+    float mYCursorPosition;
     nsecs_t mDownTime;
     Vector<PointerProperties> mPointerProperties;
     Vector<nsecs_t> mSampleEventTimes;
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 63606e5..df23f61 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -113,6 +113,8 @@
             float yOffset;
             float xPrecision;
             float yPrecision;
+            float xCursorPosition;
+            float yCursorPosition;
             uint32_t pointerCount;
             uint32_t empty3;
             // Note that PointerCoords requires 8 byte alignment.
@@ -261,27 +263,14 @@
      * 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.
      */
-    status_t publishMotionEvent(
-            uint32_t seq,
-            int32_t deviceId,
-            int32_t source,
-            int32_t displayId,
-            int32_t action,
-            int32_t actionButton,
-            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);
+    status_t publishMotionEvent(uint32_t seq, int32_t deviceId, int32_t source, int32_t displayId,
+                                int32_t action, int32_t actionButton, int32_t flags,
+                                int32_t edgeFlags, int32_t metaState, int32_t buttonState,
+                                MotionClassification classification, float xOffset, float yOffset,
+                                float xPrecision, float yPrecision, float xCursorPosition,
+                                float yCursorPosition, nsecs_t downTime, nsecs_t eventTime,
+                                uint32_t pointerCount, const PointerProperties* pointerProperties,
+                                const PointerCoords* pointerCoords);
 
     /* Receives the finished signal from the consumer in reply to the original dispatch signal.
      * If a signal was received, returns the message sequence number,
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 9fd25f9..3266b07 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -235,26 +235,14 @@
 
 // --- MotionEvent ---
 
-void MotionEvent::initialize(
-        int32_t deviceId,
-        int32_t source,
-        int32_t displayId,
-        int32_t action,
-        int32_t actionButton,
-        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) {
+void MotionEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId, int32_t action,
+                             int32_t actionButton, int32_t flags, int32_t edgeFlags,
+                             int32_t metaState, int32_t buttonState,
+                             MotionClassification classification, float xOffset, float yOffset,
+                             float xPrecision, float yPrecision, float xCursorPosition,
+                             float yCursorPosition, nsecs_t downTime, nsecs_t eventTime,
+                             size_t pointerCount, const PointerProperties* pointerProperties,
+                             const PointerCoords* pointerCoords) {
     InputEvent::initialize(deviceId, source, displayId);
     mAction = action;
     mActionButton = actionButton;
@@ -267,6 +255,8 @@
     mYOffset = yOffset;
     mXPrecision = xPrecision;
     mYPrecision = yPrecision;
+    mXCursorPosition = xCursorPosition;
+    mYCursorPosition = yCursorPosition;
     mDownTime = downTime;
     mPointerProperties.clear();
     mPointerProperties.appendArray(pointerProperties, pointerCount);
@@ -288,6 +278,8 @@
     mYOffset = other->mYOffset;
     mXPrecision = other->mXPrecision;
     mYPrecision = other->mYPrecision;
+    mXCursorPosition = other->mXCursorPosition;
+    mYCursorPosition = other->mYCursorPosition;
     mDownTime = other->mDownTime;
     mPointerProperties = other->mPointerProperties;
 
@@ -312,6 +304,16 @@
     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 {
     return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex];
 }
@@ -431,6 +433,15 @@
     float 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.
     size_t numSamples = mSamplePointerCoords.size();
     for (size_t i = 0; i < numSamples; i++) {
@@ -470,6 +481,8 @@
     mYOffset = parcel->readFloat();
     mXPrecision = parcel->readFloat();
     mYPrecision = parcel->readFloat();
+    mXCursorPosition = parcel->readFloat();
+    mYCursorPosition = parcel->readFloat();
     mDownTime = parcel->readInt64();
 
     mPointerProperties.clear();
@@ -521,6 +534,8 @@
     parcel->writeFloat(mYOffset);
     parcel->writeFloat(mXPrecision);
     parcel->writeFloat(mYPrecision);
+    parcel->writeFloat(mXCursorPosition);
+    parcel->writeFloat(mYCursorPosition);
     parcel->writeInt64(mDownTime);
 
     for (size_t i = 0; i < pointerCount; i++) {
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index d02cb8e..904a6fe 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -191,6 +191,10 @@
             msg->body.motion.xPrecision = body.motion.xPrecision;
             // float 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
             msg->body.motion.pointerCount = body.motion.pointerCount;
             //struct Pointer pointers[MAX_POINTERS]
@@ -465,26 +469,12 @@
 }
 
 status_t InputPublisher::publishMotionEvent(
-        uint32_t seq,
-        int32_t deviceId,
-        int32_t source,
-        int32_t displayId,
-        int32_t action,
-        int32_t actionButton,
-        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) {
+        uint32_t seq, int32_t deviceId, int32_t source, int32_t displayId, int32_t action,
+        int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState,
+        int32_t buttonState, MotionClassification classification, float xOffset, float yOffset,
+        float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition,
+        nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount,
+        const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) {
     if (ATRACE_ENABLED()) {
         std::string message = StringPrintf(
                 "publishMotionEvent(inputChannel=%s, action=%" PRId32 ")",
@@ -532,6 +522,8 @@
     msg.body.motion.yOffset = yOffset;
     msg.body.motion.xPrecision = xPrecision;
     msg.body.motion.yPrecision = yPrecision;
+    msg.body.motion.xCursorPosition = xCursorPosition;
+    msg.body.motion.yCursorPosition = yCursorPosition;
     msg.body.motion.downTime = downTime;
     msg.body.motion.eventTime = eventTime;
     msg.body.motion.pointerCount = pointerCount;
@@ -1135,26 +1127,16 @@
         pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
     }
 
-    event->initialize(
-            msg->body.motion.deviceId,
-            msg->body.motion.source,
-            msg->body.motion.displayId,
-            msg->body.motion.action,
-            msg->body.motion.actionButton,
-            msg->body.motion.flags,
-            msg->body.motion.edgeFlags,
-            msg->body.motion.metaState,
-            msg->body.motion.buttonState,
-            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);
+    event->initialize(msg->body.motion.deviceId, msg->body.motion.source,
+                      msg->body.motion.displayId, msg->body.motion.action,
+                      msg->body.motion.actionButton, msg->body.motion.flags,
+                      msg->body.motion.edgeFlags, msg->body.motion.metaState,
+                      msg->body.motion.buttonState, msg->body.motion.classification,
+                      msg->body.motion.xOffset, msg->body.motion.yOffset,
+                      msg->body.motion.xPrecision, msg->body.motion.yPrecision,
+                      msg->body.motion.xCursorPosition, msg->body.motion.yCursorPosition,
+                      msg->body.motion.downTime, msg->body.motion.eventTime, pointerCount,
+                      pointerProperties, pointerCoords);
 }
 
 void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) {
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index 2b75c82..ec34f3e 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -255,11 +255,11 @@
     pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27);
     pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28);
     event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE, 0,
-            AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
-            AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
-            MotionClassification::NONE, X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
-            ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME,
-            2, pointerProperties, pointerCoords);
+                      AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, AMOTION_EVENT_EDGE_FLAG_TOP,
+                      AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY, MotionClassification::NONE,
+                      X_OFFSET, Y_OFFSET, 2.0f, 2.1f, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                      AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_DOWN_TIME,
+                      ARBITRARY_EVENT_TIME, 2, pointerProperties, pointerCoords);
 
     pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110);
     pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111);
@@ -571,10 +571,11 @@
     }
     MotionEvent event;
     event.initialize(0 /*deviceId*/, AINPUT_SOURCE_UNKNOWN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE,
-            0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE,
-            AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE,
-            0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/,
-            0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords);
+                     0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE,
+                     0 /*buttonState*/, MotionClassification::NONE, 0 /*xOffset*/, 0 /*yOffset*/,
+                     0 /*xPrecision*/, 0 /*yPrecision*/, 3 + RADIUS /*xCursorPosition*/,
+                     2 /*yCursorPosition*/, 0 /*downTime*/, 0 /*eventTime*/, pointerCount,
+                     pointerProperties, pointerCoords);
     float originalRawX = 0 + 3;
     float originalRawY = -RADIUS + 2;
 
@@ -602,6 +603,10 @@
         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.
     ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001);
     ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
@@ -626,11 +631,34 @@
 
     for (MotionClassification classification : classifications) {
         event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
-                AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0,
-                classification, 0, 0, 0, 0, 0 /*downTime*/, 0 /*eventTime*/,
-                pointerCount, pointerProperties, pointerCoords);
+                         AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE,
+                         0, classification, 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                         AMOTION_EVENT_INVALID_CURSOR_POSITION, 0 /*downTime*/, 0 /*eventTime*/,
+                         pointerCount, pointerProperties, pointerCoords);
         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
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index f2cd1be..a362f32 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -146,6 +146,8 @@
     constexpr float yOffset = -20;
     constexpr float xPrecision = 0.25;
     constexpr float yPrecision = 0.5;
+    constexpr float xCursorPosition = 1.3;
+    constexpr float yCursorPosition = 50.6;
     constexpr nsecs_t downTime = 3;
     constexpr size_t pointerCount = 3;
     constexpr nsecs_t eventTime = 4;
@@ -168,10 +170,12 @@
         pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i);
     }
 
-    status = mPublisher->publishMotionEvent(seq, deviceId, source, displayId, action, actionButton,
-            flags, edgeFlags, metaState, buttonState, classification,
-            xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount,
-            pointerProperties, pointerCoords);
+    status =
+            mPublisher->publishMotionEvent(seq, deviceId, source, displayId, action, actionButton,
+                                           flags, edgeFlags, metaState, buttonState, classification,
+                                           xOffset, yOffset, xPrecision, yPrecision,
+                                           xCursorPosition, yCursorPosition, downTime, eventTime,
+                                           pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(OK, status)
             << "publisher publishMotionEvent should return OK";
 
@@ -199,6 +203,10 @@
     EXPECT_EQ(classification, motionEvent->getClassification());
     EXPECT_EQ(xPrecision, motionEvent->getXPrecision());
     EXPECT_EQ(yPrecision, motionEvent->getYPrecision());
+    EXPECT_EQ(xCursorPosition, motionEvent->getRawXCursorPosition());
+    EXPECT_EQ(yCursorPosition, motionEvent->getRawYCursorPosition());
+    EXPECT_EQ(xCursorPosition + xOffset, motionEvent->getXCursorPosition());
+    EXPECT_EQ(yCursorPosition + yOffset, motionEvent->getYCursorPosition());
     EXPECT_EQ(downTime, motionEvent->getDownTime());
     EXPECT_EQ(eventTime, motionEvent->getEventTime());
     EXPECT_EQ(pointerCount, motionEvent->getPointerCount());
@@ -266,9 +274,11 @@
         pointerCoords[i].clear();
     }
 
-    status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            MotionClassification::NONE, 0, 0, 0, 0, 0, 0,
-            pointerCount, pointerProperties, pointerCoords);
+    status =
+            mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, MotionClassification::NONE,
+                                           0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                                           AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0,
+                                           pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
 }
@@ -279,9 +289,11 @@
     PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
 
-    status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            MotionClassification::NONE, 0, 0, 0, 0, 0, 0,
-            pointerCount, pointerProperties, pointerCoords);
+    status =
+            mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, MotionClassification::NONE,
+                                           0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                                           AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0,
+                                           pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
 }
@@ -297,9 +309,11 @@
         pointerCoords[i].clear();
     }
 
-    status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            MotionClassification::NONE, 0, 0, 0, 0, 0, 0,
-            pointerCount, pointerProperties, pointerCoords);
+    status =
+            mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, MotionClassification::NONE,
+                                           0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                                           AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0,
+                                           pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
 }
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 62023fb..8d8cf06 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -64,8 +64,10 @@
   CHECK_OFFSET(InputMessage::Body::Motion, yOffset, 68);
   CHECK_OFFSET(InputMessage::Body::Motion, xPrecision, 72);
   CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 76);
-  CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 80);
-  CHECK_OFFSET(InputMessage::Body::Motion, pointers, 88);
+  CHECK_OFFSET(InputMessage::Body::Motion, xCursorPosition, 80);
+  CHECK_OFFSET(InputMessage::Body::Motion, yCursorPosition, 84);
+  CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 88);
+  CHECK_OFFSET(InputMessage::Body::Motion, pointers, 96);
 
   CHECK_OFFSET(InputMessage::Body::Finished, seq, 0);
   CHECK_OFFSET(InputMessage::Body::Finished, handled, 4);
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index 368446f..968e2fa 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -176,12 +176,13 @@
         EXPECT_EQ(pointerIndex, pointerCount);
 
         MotionEvent event;
-        event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
-                action, 0 /*actionButton*/, 0 /*flags*/,
-                AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
-                MotionClassification::NONE,
-                0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/,
-                0 /*downTime*/, entry.eventTime.count(), pointerCount, properties, coords);
+        event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, action,
+                         0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE,
+                         0 /*buttonState*/, MotionClassification::NONE, 0 /*xOffset*/,
+                         0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/,
+                         AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                         AMOTION_EVENT_INVALID_CURSOR_POSITION, 0 /*downTime*/,
+                         entry.eventTime.count(), pointerCount, properties, coords);
 
         events.emplace_back(event);
     }
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index c2ff4c9..b323099 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -262,14 +262,18 @@
 
 // --- InputDispatcher ---
 
-InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
-    mPolicy(policy),
-    mPendingEvent(nullptr), mLastDropReason(DROP_REASON_NOT_DROPPED),
-    mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
-    mNextUnblockedEvent(nullptr),
-    mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
-    mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
-    mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
+InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
+      : mPolicy(policy),
+        mPendingEvent(nullptr),
+        mLastDropReason(DROP_REASON_NOT_DROPPED),
+        mAppSwitchSawKeyDown(false),
+        mAppSwitchDueTime(LONG_LONG_MAX),
+        mNextUnblockedEvent(nullptr),
+        mDispatchEnabled(false),
+        mDispatchFrozen(false),
+        mInputFilterEnabled(false),
+        mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
+        mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
     mLooper = new Looper(false);
     mReporter = createInputReporter();
 
@@ -1326,6 +1330,7 @@
     bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN
             || maskedAction == AMOTION_EVENT_ACTION_SCROLL
             || isHoverAction);
+    const bool isFromMouse = entry->source == AINPUT_SOURCE_MOUSE;
     bool wrongDevice = false;
     if (newGesture) {
         bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN;
@@ -1361,11 +1366,17 @@
     if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
         /* Case 1: New splittable pointer going down, or need target for hover or scroll. */
 
+        int32_t x;
+        int32_t y;
         int32_t pointerIndex = getMotionEventActionPointerIndex(action);
-        int32_t x = int32_t(entry->pointerCoords[pointerIndex].
-                getAxisValue(AMOTION_EVENT_AXIS_X));
-        int32_t y = int32_t(entry->pointerCoords[pointerIndex].
-                getAxisValue(AMOTION_EVENT_AXIS_Y));
+        // Always dispatch mouse events to cursor position.
+        if (isFromMouse) {
+            x = int32_t(entry->xCursorPosition);
+            y = int32_t(entry->yCursorPosition);
+        } else {
+            x = int32_t(entry->pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X));
+            y = int32_t(entry->pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y));
+        }
         bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN;
         sp<InputWindowHandle> newTouchedWindowHandle = findTouchedWindowAtLocked(
                 displayId, x, y, isDown /*addOutsideTargets*/, true /*addPortalWindows*/);
@@ -2256,15 +2267,21 @@
             }
 
             // Publish the motion event.
-            status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
-                    motionEntry->deviceId, motionEntry->source, motionEntry->displayId,
-                    dispatchEntry->resolvedAction, motionEntry->actionButton,
-                    dispatchEntry->resolvedFlags, motionEntry->edgeFlags,
-                    motionEntry->metaState, motionEntry->buttonState, motionEntry->classification,
-                    xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision,
-                    motionEntry->downTime, motionEntry->eventTime,
-                    motionEntry->pointerCount, motionEntry->pointerProperties,
-                    usingCoords);
+            status =
+                    connection->inputPublisher
+                            .publishMotionEvent(dispatchEntry->seq, motionEntry->deviceId,
+                                                motionEntry->source, motionEntry->displayId,
+                                                dispatchEntry->resolvedAction,
+                                                motionEntry->actionButton,
+                                                dispatchEntry->resolvedFlags,
+                                                motionEntry->edgeFlags, motionEntry->metaState,
+                                                motionEntry->buttonState,
+                                                motionEntry->classification, xOffset, yOffset,
+                                                motionEntry->xPrecision, motionEntry->yPrecision,
+                                                motionEntry->xCursorPosition,
+                                                motionEntry->yCursorPosition, motionEntry->downTime,
+                                                motionEntry->eventTime, motionEntry->pointerCount,
+                                                motionEntry->pointerProperties, usingCoords);
             break;
         }
 
@@ -2590,24 +2607,17 @@
         }
     }
 
-    MotionEntry* splitMotionEntry = new MotionEntry(
-            originalMotionEntry->sequenceNum,
-            originalMotionEntry->eventTime,
-            originalMotionEntry->deviceId,
-            originalMotionEntry->source,
-            originalMotionEntry->displayId,
-            originalMotionEntry->policyFlags,
-            action,
-            originalMotionEntry->actionButton,
-            originalMotionEntry->flags,
-            originalMotionEntry->metaState,
-            originalMotionEntry->buttonState,
-            originalMotionEntry->classification,
-            originalMotionEntry->edgeFlags,
-            originalMotionEntry->xPrecision,
-            originalMotionEntry->yPrecision,
-            originalMotionEntry->downTime,
-            splitPointerCount, splitPointerProperties, splitPointerCoords, 0, 0);
+    MotionEntry* splitMotionEntry =
+            new MotionEntry(originalMotionEntry->sequenceNum, originalMotionEntry->eventTime,
+                            originalMotionEntry->deviceId, originalMotionEntry->source,
+                            originalMotionEntry->displayId, originalMotionEntry->policyFlags,
+                            action, originalMotionEntry->actionButton, originalMotionEntry->flags,
+                            originalMotionEntry->metaState, originalMotionEntry->buttonState,
+                            originalMotionEntry->classification, originalMotionEntry->edgeFlags,
+                            originalMotionEntry->xPrecision, originalMotionEntry->yPrecision,
+                            originalMotionEntry->xCursorPosition,
+                            originalMotionEntry->yCursorPosition, originalMotionEntry->downTime,
+                            splitPointerCount, splitPointerProperties, splitPointerCoords, 0, 0);
 
     if (originalMotionEntry->injectionState) {
         splitMotionEntry->injectionState = originalMotionEntry->injectionState;
@@ -2753,12 +2763,14 @@
 void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
 #if DEBUG_INBOUND_EVENT_DETAILS
     ALOGD("notifyMotion - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32
-            ", policyFlags=0x%x, "
-            "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x,"
-            "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64,
-            args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags,
-            args->action, args->actionButton, args->flags, args->metaState, args->buttonState,
-            args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime);
+          ", policyFlags=0x%x, "
+          "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, "
+          "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, xCursorPosition=%f, "
+          "mYCursorPosition=%f, downTime=%" PRId64,
+          args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags,
+          args->action, args->actionButton, args->flags, args->metaState, args->buttonState,
+          args->edgeFlags, args->xPrecision, args->yPrecision, arg->xCursorPosition,
+          args->yCursorPosition, args->downTime);
     for (uint32_t i = 0; i < args->pointerCount; i++) {
         ALOGD("  Pointer %d: id=%d, toolType=%d, "
                 "x=%f, y=%f, pressure=%f, size=%f, "
@@ -2800,12 +2812,12 @@
             mLock.unlock();
 
             MotionEvent event;
-            event.initialize(args->deviceId, args->source, args->displayId,
-                    args->action, args->actionButton,
-                    args->flags, args->edgeFlags, args->metaState, args->buttonState,
-                    args->classification, 0, 0, args->xPrecision, args->yPrecision,
-                    args->downTime, args->eventTime,
-                    args->pointerCount, args->pointerProperties, args->pointerCoords);
+            event.initialize(args->deviceId, args->source, args->displayId, args->action,
+                             args->actionButton, args->flags, args->edgeFlags, args->metaState,
+                             args->buttonState, args->classification, 0, 0, args->xPrecision,
+                             args->yPrecision, args->xCursorPosition, args->yCursorPosition,
+                             args->downTime, args->eventTime, args->pointerCount,
+                             args->pointerProperties, args->pointerCoords);
 
             policyFlags |= POLICY_FLAG_FILTERED;
             if (!mPolicy->filterInputEvent(&event, policyFlags)) {
@@ -2816,12 +2828,14 @@
         }
 
         // Just enqueue a new motion event.
-        MotionEntry* newEntry = new MotionEntry(args->sequenceNum, args->eventTime,
-                args->deviceId, args->source, args->displayId, policyFlags,
-                args->action, args->actionButton, args->flags,
-                args->metaState, args->buttonState, args->classification,
-                args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
-                args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0);
+        MotionEntry* newEntry =
+                new MotionEntry(args->sequenceNum, args->eventTime, args->deviceId, args->source,
+                                args->displayId, policyFlags, args->action, args->actionButton,
+                                args->flags, args->metaState, args->buttonState,
+                                args->classification, args->edgeFlags, args->xPrecision,
+                                args->yPrecision, args->xCursorPosition, args->yCursorPosition,
+                                args->downTime, args->pointerCount, args->pointerProperties,
+                                args->pointerCoords, 0, 0);
 
         needWake = enqueueInboundEventLocked(newEntry);
         mLock.unlock();
@@ -2952,31 +2966,34 @@
         mLock.lock();
         const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
         const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
-        firstInjectedEntry = new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes,
-                motionEvent->getDeviceId(), motionEvent->getSource(), motionEvent->getDisplayId(),
-                policyFlags,
-                action, actionButton, motionEvent->getFlags(),
-                motionEvent->getMetaState(), motionEvent->getButtonState(),
-                motionEvent->getClassification(), motionEvent->getEdgeFlags(),
-                motionEvent->getXPrecision(), motionEvent->getYPrecision(),
-                motionEvent->getDownTime(),
-                uint32_t(pointerCount), pointerProperties, samplePointerCoords,
-                motionEvent->getXOffset(), motionEvent->getYOffset());
+        firstInjectedEntry =
+                new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes,
+                                motionEvent->getDeviceId(), motionEvent->getSource(),
+                                motionEvent->getDisplayId(), policyFlags, action, actionButton,
+                                motionEvent->getFlags(), motionEvent->getMetaState(),
+                                motionEvent->getButtonState(), motionEvent->getClassification(),
+                                motionEvent->getEdgeFlags(), motionEvent->getXPrecision(),
+                                motionEvent->getYPrecision(), motionEvent->getRawXCursorPosition(),
+                                motionEvent->getRawYCursorPosition(), motionEvent->getDownTime(),
+                                uint32_t(pointerCount), pointerProperties, samplePointerCoords,
+                                motionEvent->getXOffset(), motionEvent->getYOffset());
         lastInjectedEntry = firstInjectedEntry;
         for (size_t i = motionEvent->getHistorySize(); i > 0; i--) {
             sampleEventTimes += 1;
             samplePointerCoords += pointerCount;
-            MotionEntry* nextInjectedEntry = new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM,
-                    *sampleEventTimes,
-                    motionEvent->getDeviceId(), motionEvent->getSource(),
-                    motionEvent->getDisplayId(), policyFlags,
-                    action, actionButton, motionEvent->getFlags(),
-                    motionEvent->getMetaState(), motionEvent->getButtonState(),
-                    motionEvent->getClassification(), motionEvent->getEdgeFlags(),
-                    motionEvent->getXPrecision(), motionEvent->getYPrecision(),
-                    motionEvent->getDownTime(),
-                    uint32_t(pointerCount), pointerProperties, samplePointerCoords,
-                    motionEvent->getXOffset(), motionEvent->getYOffset());
+            MotionEntry* nextInjectedEntry =
+                    new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes,
+                                    motionEvent->getDeviceId(), motionEvent->getSource(),
+                                    motionEvent->getDisplayId(), policyFlags, action, actionButton,
+                                    motionEvent->getFlags(), motionEvent->getMetaState(),
+                                    motionEvent->getButtonState(), motionEvent->getClassification(),
+                                    motionEvent->getEdgeFlags(), motionEvent->getXPrecision(),
+                                    motionEvent->getYPrecision(),
+                                    motionEvent->getRawXCursorPosition(),
+                                    motionEvent->getRawYCursorPosition(),
+                                    motionEvent->getDownTime(), uint32_t(pointerCount),
+                                    pointerProperties, samplePointerCoords,
+                                    motionEvent->getXOffset(), motionEvent->getYOffset());
             lastInjectedEntry->next = nextInjectedEntry;
             lastInjectedEntry = nextInjectedEntry;
         }
@@ -4633,21 +4650,32 @@
 
 // --- InputDispatcher::MotionEntry ---
 
-InputDispatcher::MotionEntry::MotionEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId,
-        uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action,
-        int32_t actionButton,
+InputDispatcher::MotionEntry::MotionEntry(
+        uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
+        int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton,
         int32_t flags, int32_t metaState, int32_t buttonState, MotionClassification classification,
-        int32_t edgeFlags, float xPrecision, float yPrecision, nsecs_t downTime,
-        uint32_t pointerCount,
+        int32_t edgeFlags, float xPrecision, float yPrecision, float xCursorPosition,
+        float yCursorPosition, nsecs_t downTime, uint32_t pointerCount,
         const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
-        float xOffset, float yOffset) :
-        EventEntry(sequenceNum, TYPE_MOTION, eventTime, policyFlags),
+        float xOffset, float yOffset)
+      : EventEntry(sequenceNum, TYPE_MOTION, eventTime, policyFlags),
         eventTime(eventTime),
-        deviceId(deviceId), source(source), displayId(displayId), action(action),
-        actionButton(actionButton), flags(flags), metaState(metaState), buttonState(buttonState),
-        classification(classification), edgeFlags(edgeFlags),
-        xPrecision(xPrecision), yPrecision(yPrecision),
-        downTime(downTime), pointerCount(pointerCount) {
+        deviceId(deviceId),
+        source(source),
+        displayId(displayId),
+        action(action),
+        actionButton(actionButton),
+        flags(flags),
+        metaState(metaState),
+        buttonState(buttonState),
+        classification(classification),
+        edgeFlags(edgeFlags),
+        xPrecision(xPrecision),
+        yPrecision(yPrecision),
+        xCursorPosition(xCursorPosition),
+        yCursorPosition(yCursorPosition),
+        downTime(downTime),
+        pointerCount(pointerCount) {
     for (uint32_t i = 0; i < pointerCount; i++) {
         this->pointerProperties[i].copyFrom(pointerProperties[i]);
         this->pointerCoords[i].copyFrom(pointerCoords[i]);
@@ -4662,11 +4690,14 @@
 
 void InputDispatcher::MotionEntry::appendDescription(std::string& msg) const {
     msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32
-            ", action=%s, actionButton=0x%08x, flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, "
-            "classification=%s, edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, pointers=[",
-            deviceId, source, displayId, motionActionToString(action).c_str(), actionButton, flags,
-            metaState, buttonState, motionClassificationToString(classification), edgeFlags,
-            xPrecision, yPrecision);
+                        ", action=%s, actionButton=0x%08x, flags=0x%08x, metaState=0x%08x, "
+                        "buttonState=0x%08x, "
+                        "classification=%s, edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, "
+                        "xCursorPosition=%0.1f, yCursorPosition=%0.1f, pointers=[",
+                        deviceId, source, displayId, motionActionToString(action).c_str(),
+                        actionButton, flags, metaState, buttonState,
+                        motionClassificationToString(classification), edgeFlags, xPrecision,
+                        yPrecision, xCursorPosition, yCursorPosition);
 
     for (uint32_t i = 0; i < pointerCount; i++) {
         if (i) {
@@ -4936,6 +4967,8 @@
     memento.flags = flags;
     memento.xPrecision = entry->xPrecision;
     memento.yPrecision = entry->yPrecision;
+    memento.xCursorPosition = entry->xCursorPosition;
+    memento.yCursorPosition = entry->yCursorPosition;
     memento.downTime = entry->downTime;
     memento.setPointers(entry);
     memento.hovering = hovering;
@@ -4966,13 +4999,16 @@
         if (shouldCancelMotion(memento, options)) {
             const int32_t action = memento.hovering ?
                     AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL;
-            outEvents.push_back(new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime,
-                    memento.deviceId, memento.source, memento.displayId, memento.policyFlags,
-                    action, 0 /*actionButton*/, memento.flags, AMETA_NONE, 0 /*buttonState*/,
-                    MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
-                    memento.xPrecision, memento.yPrecision, memento.downTime,
-                    memento.pointerCount, memento.pointerProperties, memento.pointerCoords,
-                    0 /*xOffset*/, 0 /*yOffset*/));
+            outEvents.push_back(
+                    new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, currentTime, memento.deviceId,
+                                    memento.source, memento.displayId, memento.policyFlags, action,
+                                    0 /*actionButton*/, memento.flags, AMETA_NONE,
+                                    0 /*buttonState*/, MotionClassification::NONE,
+                                    AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
+                                    memento.yPrecision, memento.xCursorPosition,
+                                    memento.yCursorPosition, memento.downTime, memento.pointerCount,
+                                    memento.pointerProperties, memento.pointerCoords, 0 /*xOffset*/,
+                                    0 /*yOffset*/));
         }
     }
 }
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 753b748..46dd9bd 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -570,19 +570,21 @@
         int32_t edgeFlags;
         float xPrecision;
         float yPrecision;
+        float xCursorPosition;
+        float yCursorPosition;
         nsecs_t downTime;
         uint32_t pointerCount;
         PointerProperties pointerProperties[MAX_POINTERS];
         PointerCoords pointerCoords[MAX_POINTERS];
 
-        MotionEntry(uint32_t sequenceNum, nsecs_t eventTime,
-                int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags,
-                int32_t action, int32_t actionButton, int32_t flags,
-                int32_t metaState, int32_t buttonState, MotionClassification classification,
-                int32_t edgeFlags, float xPrecision, float yPrecision,
-                nsecs_t downTime, uint32_t pointerCount,
-                const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
-                float xOffset, float yOffset);
+        MotionEntry(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
+                    int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton,
+                    int32_t flags, int32_t metaState, int32_t buttonState,
+                    MotionClassification classification, int32_t edgeFlags, float xPrecision,
+                    float yPrecision, float xCursorPosition, float yCursorPosition,
+                    nsecs_t downTime, uint32_t pointerCount,
+                    const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
+                    float xOffset, float yOffset);
         virtual void appendDescription(std::string& msg) const;
 
     protected:
@@ -830,6 +832,8 @@
             int32_t flags;
             float xPrecision;
             float yPrecision;
+            float xCursorPosition;
+            float yCursorPosition;
             nsecs_t downTime;
             uint32_t pointerCount;
             PointerProperties pointerProperties[MAX_POINTERS];
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 423b69c..0498e87 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -21,6 +21,7 @@
 #include "InputListener.h"
 
 #include <android/log.h>
+#include <math.h>
 
 namespace android {
 
@@ -87,21 +88,33 @@
 
 // --- NotifyMotionArgs ---
 
-NotifyMotionArgs::NotifyMotionArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId,
-        uint32_t source, int32_t displayId, uint32_t policyFlags,
-        int32_t action, int32_t actionButton, int32_t flags, int32_t metaState,
-        int32_t buttonState, MotionClassification classification,
+NotifyMotionArgs::NotifyMotionArgs(
+        uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
+        int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton,
+        int32_t flags, int32_t metaState, int32_t buttonState, MotionClassification classification,
         int32_t edgeFlags, uint32_t deviceTimestamp, uint32_t pointerCount,
         const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
-        float xPrecision, float yPrecision, nsecs_t downTime,
-        const std::vector<TouchVideoFrame>& videoFrames) :
-        NotifyArgs(sequenceNum, eventTime), deviceId(deviceId), source(source),
-        displayId(displayId), policyFlags(policyFlags),
-        action(action), actionButton(actionButton),
-        flags(flags), metaState(metaState), buttonState(buttonState),
-        classification(classification), edgeFlags(edgeFlags), deviceTimestamp(deviceTimestamp),
+        float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition,
+        nsecs_t downTime, const std::vector<TouchVideoFrame>& videoFrames)
+      : NotifyArgs(sequenceNum, eventTime),
+        deviceId(deviceId),
+        source(source),
+        displayId(displayId),
+        policyFlags(policyFlags),
+        action(action),
+        actionButton(actionButton),
+        flags(flags),
+        metaState(metaState),
+        buttonState(buttonState),
+        classification(classification),
+        edgeFlags(edgeFlags),
+        deviceTimestamp(deviceTimestamp),
         pointerCount(pointerCount),
-        xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime),
+        xPrecision(xPrecision),
+        yPrecision(yPrecision),
+        xCursorPosition(xCursorPosition),
+        yCursorPosition(yCursorPosition),
+        downTime(downTime),
         videoFrames(videoFrames) {
     for (uint32_t i = 0; i < pointerCount; i++) {
         this->pointerProperties[i].copyFrom(pointerProperties[i]);
@@ -109,14 +122,26 @@
     }
 }
 
-NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) :
-        NotifyArgs(other.sequenceNum, other.eventTime), deviceId(other.deviceId),
-        source(other.source), displayId(other.displayId), policyFlags(other.policyFlags),
-        action(other.action), actionButton(other.actionButton), flags(other.flags),
-        metaState(other.metaState), buttonState(other.buttonState),
-        classification(other.classification), edgeFlags(other.edgeFlags),
-        deviceTimestamp(other.deviceTimestamp), pointerCount(other.pointerCount),
-        xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime),
+NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other)
+      : NotifyArgs(other.sequenceNum, other.eventTime),
+        deviceId(other.deviceId),
+        source(other.source),
+        displayId(other.displayId),
+        policyFlags(other.policyFlags),
+        action(other.action),
+        actionButton(other.actionButton),
+        flags(other.flags),
+        metaState(other.metaState),
+        buttonState(other.buttonState),
+        classification(other.classification),
+        edgeFlags(other.edgeFlags),
+        deviceTimestamp(other.deviceTimestamp),
+        pointerCount(other.pointerCount),
+        xPrecision(other.xPrecision),
+        yPrecision(other.yPrecision),
+        xCursorPosition(other.xCursorPosition),
+        yCursorPosition(other.yCursorPosition),
+        downTime(other.downTime),
         videoFrames(other.videoFrames) {
     for (uint32_t i = 0; i < pointerCount; i++) {
         pointerProperties[i].copyFrom(other.pointerProperties[i]);
@@ -124,28 +149,23 @@
     }
 }
 
+static inline bool isCursorPositionEqual(float lhs, float rhs) {
+    return (isnan(lhs) && isnan(rhs)) || lhs == rhs;
+}
+
 bool NotifyMotionArgs::operator==(const NotifyMotionArgs& rhs) const {
-    bool equal =
-            sequenceNum == rhs.sequenceNum
-            && eventTime == rhs.eventTime
-            && deviceId == rhs.deviceId
-            && source == rhs.source
-            && displayId == rhs.displayId
-            && policyFlags == rhs.policyFlags
-            && action == rhs.action
-            && actionButton == rhs.actionButton
-            && flags == rhs.flags
-            && metaState == rhs.metaState
-            && buttonState == rhs.buttonState
-            && classification == rhs.classification
-            && edgeFlags == rhs.edgeFlags
-            && deviceTimestamp == rhs.deviceTimestamp
-            && pointerCount == rhs.pointerCount
+    bool equal = sequenceNum == rhs.sequenceNum && eventTime == rhs.eventTime &&
+            deviceId == rhs.deviceId && source == rhs.source && displayId == rhs.displayId &&
+            policyFlags == rhs.policyFlags && action == rhs.action &&
+            actionButton == rhs.actionButton && flags == rhs.flags && metaState == rhs.metaState &&
+            buttonState == rhs.buttonState && classification == rhs.classification &&
+            edgeFlags == rhs.edgeFlags && deviceTimestamp == rhs.deviceTimestamp &&
+            pointerCount == rhs.pointerCount
             // PointerProperties and PointerCoords are compared separately below
-            && xPrecision == rhs.xPrecision
-            && yPrecision == rhs.yPrecision
-            && downTime == rhs.downTime
-            && videoFrames == rhs.videoFrames;
+            && xPrecision == rhs.xPrecision && yPrecision == rhs.yPrecision &&
+            isCursorPositionEqual(xCursorPosition, rhs.xCursorPosition) &&
+            isCursorPositionEqual(yCursorPosition, rhs.yCursorPosition) &&
+            downTime == rhs.downTime && videoFrames == rhs.videoFrames;
     if (!equal) {
         return false;
     }
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index a45b8a5..9e59909 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -2782,6 +2782,8 @@
     mPointerVelocityControl.move(when, &deltaX, &deltaY);
 
     int32_t displayId;
+    float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
+    float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
     if (mSource == AINPUT_SOURCE_MOUSE) {
         if (moved || scrolled || buttonsChanged) {
             mPointerController->setPresentation(
@@ -2798,10 +2800,9 @@
             mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
         }
 
-        float x, y;
-        mPointerController->getPosition(&x, &y);
-        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
-        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
+        mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
+        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition);
+        pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
         displayId = mPointerController->getDisplayId();
@@ -2845,21 +2846,25 @@
                 int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit());
                 buttonState &= ~actionButton;
                 NotifyMotionArgs releaseArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
-                        mSource, displayId, policyFlags,
-                        AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
-                        metaState, buttonState,
-                        MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
-                        /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
-                        mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
+                                             mSource, displayId, policyFlags,
+                                             AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
+                                             metaState, buttonState, MotionClassification::NONE,
+                                             AMOTION_EVENT_EDGE_FLAG_NONE,
+                                             /* deviceTimestamp */ 0, 1, &pointerProperties,
+                                             &pointerCoords, mXPrecision, mYPrecision,
+                                             xCursorPosition, yCursorPosition, downTime,
+                                             /* videoFrames */ {});
                 getListener()->notifyMotion(&releaseArgs);
             }
         }
 
         NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
-                displayId, policyFlags, motionEventAction, 0, 0, metaState, currentButtonState,
-                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
-                /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
-                mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
+                              displayId, policyFlags, motionEventAction, 0, 0, metaState,
+                              currentButtonState, MotionClassification::NONE,
+                              AMOTION_EVENT_EDGE_FLAG_NONE,
+                              /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
+                              mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime,
+                              /* videoFrames */ {});
         getListener()->notifyMotion(&args);
 
         if (buttonsPressed) {
@@ -2868,11 +2873,14 @@
                 int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit());
                 buttonState |= actionButton;
                 NotifyMotionArgs pressArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
-                        mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_BUTTON_PRESS,
-                        actionButton, 0, metaState, buttonState,
-                        MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
-                        /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
-                        mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
+                                           mSource, displayId, policyFlags,
+                                           AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
+                                           metaState, buttonState, MotionClassification::NONE,
+                                           AMOTION_EVENT_EDGE_FLAG_NONE,
+                                           /* deviceTimestamp */ 0, 1, &pointerProperties,
+                                           &pointerCoords, mXPrecision, mYPrecision,
+                                           xCursorPosition, yCursorPosition, downTime,
+                                           /* videoFrames */ {});
                 getListener()->notifyMotion(&pressArgs);
             }
         }
@@ -2882,12 +2890,14 @@
         // Send hover move after UP to tell the application that the mouse is hovering now.
         if (motionEventAction == AMOTION_EVENT_ACTION_UP
                 && (mSource == AINPUT_SOURCE_MOUSE)) {
-            NotifyMotionArgs hoverArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
-                    mSource, displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
-                    metaState, currentButtonState,
-                    MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
-                    /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
-                    mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
+            NotifyMotionArgs hoverArgs(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
+                                       displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
+                                       0, metaState, currentButtonState, MotionClassification::NONE,
+                                       AMOTION_EVENT_EDGE_FLAG_NONE,
+                                       /* deviceTimestamp */ 0, 1, &pointerProperties,
+                                       &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
+                                       yCursorPosition, downTime,
+                                       /* videoFrames */ {});
             getListener()->notifyMotion(&hoverArgs);
         }
 
@@ -2897,11 +2907,14 @@
             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
 
             NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
-                    mSource, displayId, policyFlags,
-                    AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState,
-                    MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
-                    /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
-                    mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
+                                        mSource, displayId, policyFlags,
+                                        AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
+                                        currentButtonState, MotionClassification::NONE,
+                                        AMOTION_EVENT_EDGE_FLAG_NONE,
+                                        /* deviceTimestamp */ 0, 1, &pointerProperties,
+                                        &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
+                                        yCursorPosition, downTime,
+                                        /* videoFrames */ {});
             getListener()->notifyMotion(&scrollArgs);
         }
     }
@@ -3041,12 +3054,13 @@
         int32_t metaState = mContext->getGlobalMetaState();
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SCROLL, scroll * mScalingFactor);
 
-        NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(),
-                mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, /* buttonState */ 0,
-                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
-                /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
-                0, 0, 0, /* videoFrames */ {});
+        NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
+                                    displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0,
+                                    metaState, /* buttonState */ 0, MotionClassification::NONE,
+                                    AMOTION_EVENT_EDGE_FLAG_NONE,
+                                    /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
+                                    0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                                    AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
         getListener()->notifyMotion(&scrollArgs);
     }
 
@@ -5450,12 +5464,12 @@
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
 
         const int32_t displayId = mPointerController->getDisplayId();
-        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
-                mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
-                metaState, buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
-                /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
-                0, 0, mPointerGesture.downTime, /* videoFrames */ {});
+        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
+                              displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
+                              metaState, buttonState, MotionClassification::NONE,
+                              AMOTION_EVENT_EDGE_FLAG_NONE,
+                              /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, 0, 0,
+                              x, y, mPointerGesture.downTime, /* videoFrames */ {});
         getListener()->notifyMotion(&args);
     }
 
@@ -6360,29 +6374,31 @@
     int32_t metaState = getContext()->getGlobalMetaState();
     int32_t displayId = mViewport.displayId;
 
-    if (mPointerController != nullptr) {
-        if (down || hovering) {
-            mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
-            mPointerController->clearSpots();
-            mPointerController->setButtonState(mCurrentRawState.buttonState);
-            mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
-        } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) {
-            mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
-        }
-        displayId = mPointerController->getDisplayId();
+    if (down || hovering) {
+        mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
+        mPointerController->clearSpots();
+        mPointerController->setButtonState(mCurrentRawState.buttonState);
+        mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
+    } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) {
+        mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
     }
+    displayId = mPointerController->getDisplayId();
+
+    float xCursorPosition;
+    float yCursorPosition;
+    mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
 
     if (mPointerSimple.down && !down) {
         mPointerSimple.down = false;
 
         // Send up.
-        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
-                mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState,
-                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
-                1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
-                mOrientedXPrecision, mOrientedYPrecision,
-                mPointerSimple.downTime, /* videoFrames */ {});
+        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
+                              displayId, policyFlags, AMOTION_EVENT_ACTION_UP, 0, 0, metaState,
+                              mLastRawState.buttonState, MotionClassification::NONE,
+                              AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1,
+                              &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
+                              mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
+                              yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
         getListener()->notifyMotion(&args);
     }
 
@@ -6390,13 +6406,13 @@
         mPointerSimple.hovering = false;
 
         // Send hover exit.
-        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
-                mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState,
-                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
-                1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
-                mOrientedXPrecision, mOrientedYPrecision,
-                mPointerSimple.downTime, /* videoFrames */ {});
+        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
+                              displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0,
+                              metaState, mLastRawState.buttonState, MotionClassification::NONE,
+                              AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1,
+                              &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
+                              mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
+                              yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
         getListener()->notifyMotion(&args);
     }
 
@@ -6406,25 +6422,25 @@
             mPointerSimple.downTime = when;
 
             // Send down.
-            NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
-                    mSource, displayId, policyFlags,
-                    AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState,
-                    MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
-                    /* deviceTimestamp */ 0,
-                    1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
-                    mOrientedXPrecision, mOrientedYPrecision,
-                    mPointerSimple.downTime, /* videoFrames */ {});
+            NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
+                                  displayId, policyFlags, AMOTION_EVENT_ACTION_DOWN, 0, 0,
+                                  metaState, mCurrentRawState.buttonState,
+                                  MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
+                                  /* deviceTimestamp */ 0, 1, &mPointerSimple.currentProperties,
+                                  &mPointerSimple.currentCoords, mOrientedXPrecision,
+                                  mOrientedYPrecision, xCursorPosition, yCursorPosition,
+                                  mPointerSimple.downTime, /* videoFrames */ {});
             getListener()->notifyMotion(&args);
         }
 
         // Send move.
-        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
-                mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState,
-                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
-                1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
-                mOrientedXPrecision, mOrientedYPrecision,
-                mPointerSimple.downTime, /* videoFrames */ {});
+        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
+                              displayId, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
+                              mCurrentRawState.buttonState, MotionClassification::NONE,
+                              AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1,
+                              &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
+                              mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
+                              yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
         getListener()->notifyMotion(&args);
     }
 
@@ -6433,26 +6449,25 @@
             mPointerSimple.hovering = true;
 
             // Send hover enter.
-            NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
-                    mSource, displayId, policyFlags,
-                    AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
-                    mCurrentRawState.buttonState, MotionClassification::NONE,
-                    AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
-                    1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
-                    mOrientedXPrecision, mOrientedYPrecision,
-                    mPointerSimple.downTime, /* videoFrames */ {});
+            NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
+                                  displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0,
+                                  metaState, mCurrentRawState.buttonState,
+                                  MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
+                                  /* deviceTimestamp */ 0, 1, &mPointerSimple.currentProperties,
+                                  &mPointerSimple.currentCoords, mOrientedXPrecision,
+                                  mOrientedYPrecision, xCursorPosition, yCursorPosition,
+                                  mPointerSimple.downTime, /* videoFrames */ {});
             getListener()->notifyMotion(&args);
         }
 
         // Send hover move.
-        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
-                mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
-                mCurrentRawState.buttonState, MotionClassification::NONE,
-                AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
-                1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
-                mOrientedXPrecision, mOrientedYPrecision,
-                mPointerSimple.downTime, /* videoFrames */ {});
+        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
+                              displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
+                              metaState, mCurrentRawState.buttonState, MotionClassification::NONE,
+                              AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1,
+                              &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
+                              mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
+                              yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
         getListener()->notifyMotion(&args);
     }
 
@@ -6468,13 +6483,13 @@
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
 
-        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
-                mSource, displayId, policyFlags,
-                AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState,
-                MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
-                1, &mPointerSimple.currentProperties, &pointerCoords,
-                mOrientedXPrecision, mOrientedYPrecision,
-                mPointerSimple.downTime, /* videoFrames */ {});
+        NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
+                              displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
+                              mCurrentRawState.buttonState, MotionClassification::NONE,
+                              AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1,
+                              &mPointerSimple.currentProperties, &pointerCoords,
+                              mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
+                              yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
         getListener()->notifyMotion(&args);
     }
 
@@ -6531,16 +6546,21 @@
             ALOG_ASSERT(false);
         }
     }
+    float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
+    float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
+    if (mDeviceMode == DEVICE_MODE_POINTER) {
+        mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
+    }
     const int32_t displayId = getAssociatedDisplay().value_or(ADISPLAY_ID_NONE);
     const int32_t deviceId = getDeviceId();
     std::vector<TouchVideoFrame> frames = mDevice->getEventHub()->getVideoFrames(deviceId);
     std::for_each(frames.begin(), frames.end(),
             [this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); });
-    NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId,
-            source, displayId, policyFlags,
-            action, actionButton, flags, metaState, buttonState, MotionClassification::NONE,
-            edgeFlags, deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
-            xPrecision, yPrecision, downTime, std::move(frames));
+    NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId, source, displayId,
+                          policyFlags, action, actionButton, flags, metaState, buttonState,
+                          MotionClassification::NONE, edgeFlags, deviceTimestamp, pointerCount,
+                          pointerProperties, pointerCoords, xPrecision, yPrecision, xCursorPosition,
+                          yCursorPosition, downTime, std::move(frames));
     getListener()->notifyMotion(&args);
 }
 
@@ -7462,10 +7482,12 @@
     uint32_t policyFlags = 0;
 
     NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
-            AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE, policyFlags,
-            AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, MotionClassification::NONE,
-            AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1,
-            &pointerProperties, &pointerCoords, 0, 0, 0, /* videoFrames */ {});
+                          AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE, policyFlags,
+                          AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
+                          MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
+                          /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, 0, 0,
+                          AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                          AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
     getListener()->notifyMotion(&args);
 }
 
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index b51dcb6..57c894b 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -119,19 +119,27 @@
     PointerCoords pointerCoords[MAX_POINTERS];
     float xPrecision;
     float yPrecision;
+    /**
+     * Mouse cursor position when this event is reported relative to the origin of the specified
+     * display. Only valid if this is a mouse event (originates from a mouse or from a trackpad in
+     * gestures enabled mode.
+     */
+    float xCursorPosition;
+    float yCursorPosition;
     nsecs_t downTime;
     std::vector<TouchVideoFrame> videoFrames;
 
     inline NotifyMotionArgs() { }
 
     NotifyMotionArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
-            int32_t displayId, uint32_t policyFlags,
-            int32_t action, int32_t actionButton, int32_t flags,
-            int32_t metaState, int32_t buttonState, MotionClassification classification,
-            int32_t edgeFlags, uint32_t deviceTimestamp, uint32_t pointerCount,
-            const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
-            float xPrecision, float yPrecision, nsecs_t downTime,
-            const std::vector<TouchVideoFrame>& videoFrames);
+                     int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton,
+                     int32_t flags, int32_t metaState, int32_t buttonState,
+                     MotionClassification classification, int32_t edgeFlags,
+                     uint32_t deviceTimestamp, uint32_t pointerCount,
+                     const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
+                     float xPrecision, float yPrecision, float xCursorPosition,
+                     float yCursorPosition, nsecs_t downTime,
+                     const std::vector<TouchVideoFrame>& videoFrames);
 
     NotifyMotionArgs(const NotifyMotionArgs& other);
 
diff --git a/services/inputflinger/tests/InputClassifierConverter_test.cpp b/services/inputflinger/tests/InputClassifierConverter_test.cpp
index 813b69e..ba1c7c9 100644
--- a/services/inputflinger/tests/InputClassifierConverter_test.cpp
+++ b/services/inputflinger/tests/InputClassifierConverter_test.cpp
@@ -38,12 +38,15 @@
     coords.setAxisValue(AMOTION_EVENT_AXIS_Y, 2);
     coords.setAxisValue(AMOTION_EVENT_AXIS_SIZE, 0.5);
     static constexpr nsecs_t downTime = 2;
-    NotifyMotionArgs motionArgs(1/*sequenceNum*/, downTime/*eventTime*/, 3/*deviceId*/,
-            AINPUT_SOURCE_ANY, ADISPLAY_ID_DEFAULT, 4/*policyFlags*/, AMOTION_EVENT_ACTION_DOWN,
-            0/*actionButton*/, 0/*flags*/, AMETA_NONE, 0/*buttonState*/, MotionClassification::NONE,
-            AMOTION_EVENT_EDGE_FLAG_NONE, 5/*deviceTimestamp*/,
-            1/*pointerCount*/, &properties, &coords, 0/*xPrecision*/, 0/*yPrecision*/,
-            downTime, {}/*videoFrames*/);
+    NotifyMotionArgs motionArgs(1 /*sequenceNum*/, downTime /*eventTime*/, 3 /*deviceId*/,
+                                AINPUT_SOURCE_ANY, ADISPLAY_ID_DEFAULT, 4 /*policyFlags*/,
+                                AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, 0 /*flags*/,
+                                AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE,
+                                AMOTION_EVENT_EDGE_FLAG_NONE, 5 /*deviceTimestamp*/,
+                                1 /*pointerCount*/, &properties, &coords, 0 /*xPrecision*/,
+                                0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                                AMOTION_EVENT_INVALID_CURSOR_POSITION, downTime,
+                                {} /*videoFrames*/);
     return motionArgs;
 }
 
diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputClassifier_test.cpp
index 7cc17a2..9bc4282 100644
--- a/services/inputflinger/tests/InputClassifier_test.cpp
+++ b/services/inputflinger/tests/InputClassifier_test.cpp
@@ -38,12 +38,15 @@
     coords.setAxisValue(AMOTION_EVENT_AXIS_X, 1);
     coords.setAxisValue(AMOTION_EVENT_AXIS_Y, 1);
     static constexpr nsecs_t downTime = 2;
-    NotifyMotionArgs motionArgs(1/*sequenceNum*/, downTime/*eventTime*/, 3/*deviceId*/,
-            AINPUT_SOURCE_ANY, ADISPLAY_ID_DEFAULT, 4/*policyFlags*/, AMOTION_EVENT_ACTION_DOWN,
-            0/*actionButton*/, 0/*flags*/, AMETA_NONE, 0/*buttonState*/, MotionClassification::NONE,
-            AMOTION_EVENT_EDGE_FLAG_NONE, 5/*deviceTimestamp*/,
-            1/*pointerCount*/, &properties, &coords, 0/*xPrecision*/, 0/*yPrecision*/,
-            downTime, {}/*videoFrames*/);
+    NotifyMotionArgs motionArgs(1 /*sequenceNum*/, downTime /*eventTime*/, 3 /*deviceId*/,
+                                AINPUT_SOURCE_ANY, ADISPLAY_ID_DEFAULT, 4 /*policyFlags*/,
+                                AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, 0 /*flags*/,
+                                AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE,
+                                AMOTION_EVENT_EDGE_FLAG_NONE, 5 /*deviceTimestamp*/,
+                                1 /*pointerCount*/, &properties, &coords, 0 /*xPrecision*/,
+                                0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                                AMOTION_EVENT_INVALID_CURSOR_POSITION, downTime,
+                                {} /*videoFrames*/);
     return motionArgs;
 }
 
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 9fe6481..c28a621 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -249,8 +249,10 @@
 
     // Rejects undefined motion actions.
     event.initialize(DEVICE_ID, source, DISPLAY_ID,
-            /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
+                     /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                     ARBITRARY_TIME, ARBITRARY_TIME,
+                     /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
@@ -258,18 +260,24 @@
 
     // Rejects pointer down with invalid index.
     event.initialize(DEVICE_ID, source, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
+                     AMOTION_EVENT_ACTION_POINTER_DOWN |
+                             (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+                     0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                     ARBITRARY_TIME, ARBITRARY_TIME,
+                     /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer down index too large.";
 
     event.initialize(DEVICE_ID, source, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_POINTER_DOWN | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
+                     AMOTION_EVENT_ACTION_POINTER_DOWN |
+                             (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+                     0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                     ARBITRARY_TIME, ARBITRARY_TIME,
+                     /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
@@ -277,36 +285,45 @@
 
     // Rejects pointer up with invalid index.
     event.initialize(DEVICE_ID, source, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
+                     AMOTION_EVENT_ACTION_POINTER_UP |
+                             (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+                     0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                     ARBITRARY_TIME, ARBITRARY_TIME,
+                     /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer up index too large.";
 
     event.initialize(DEVICE_ID, source, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_POINTER_UP | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
+                     AMOTION_EVENT_ACTION_POINTER_UP |
+                             (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+                     0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                     ARBITRARY_TIME, ARBITRARY_TIME,
+                     /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer up index too small.";
 
     // Rejects motion events with invalid number of pointers.
-    event.initialize(DEVICE_ID, source, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 0, pointerProperties, pointerCoords);
+    event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags,
+                     metaState, 0, classification, 0, 0, 0, 0,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                     ARBITRARY_TIME, ARBITRARY_TIME,
+                     /*pointerCount*/ 0, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with 0 pointers.";
 
-    event.initialize(DEVICE_ID, source, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME,
-            /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
+    event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags,
+                     metaState, 0, classification, 0, 0, 0, 0,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                     ARBITRARY_TIME, ARBITRARY_TIME,
+                     /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
@@ -314,18 +331,22 @@
 
     // Rejects motion events with invalid pointer ids.
     pointerProperties[0].id = -1;
-    event.initialize(DEVICE_ID, source, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
+    event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags,
+                     metaState, 0, classification, 0, 0, 0, 0,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                     ARBITRARY_TIME, ARBITRARY_TIME,
+                     /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer ids less than 0.";
 
     pointerProperties[0].id = MAX_POINTER_ID + 1;
-    event.initialize(DEVICE_ID, source, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
+    event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags,
+                     metaState, 0, classification, 0, 0, 0, 0,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                     ARBITRARY_TIME, ARBITRARY_TIME,
+                     /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
@@ -334,9 +355,11 @@
     // Rejects motion events with duplicate pointer ids.
     pointerProperties[0].id = 1;
     pointerProperties[1].id = 1;
-    event.initialize(DEVICE_ID, source, DISPLAY_ID,
-            AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
-            ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 2, pointerProperties, pointerCoords);
+    event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags,
+                     metaState, 0, classification, 0, 0, 0, 0,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                     ARBITRARY_TIME, ARBITRARY_TIME,
+                     /*pointerCount*/ 2, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
             &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
@@ -463,6 +486,7 @@
         mInfo.frameRight = mFrame.right;
         mInfo.frameBottom = mFrame.bottom;
         mInfo.globalScaleFactor = 1.0;
+        mInfo.touchableRegion.clear();
         mInfo.addTouchableRegion(mFrame);
         mInfo.visible = true;
         mInfo.canReceiveKeys = true;
@@ -521,8 +545,10 @@
             INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
 }
 
-static int32_t injectMotionDown(const sp<InputDispatcher>& dispatcher, int32_t source,
-        int32_t displayId, int32_t x = 100, int32_t y = 200) {
+static int32_t injectMotionEvent(const sp<InputDispatcher>& dispatcher, int32_t action,
+                                 int32_t source, int32_t displayId, int32_t x, int32_t y,
+                                 int32_t xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                                 int32_t yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION) {
     MotionEvent event;
     PointerProperties pointerProperties[1];
     PointerCoords pointerCoords[1];
@@ -537,12 +563,11 @@
 
     nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
     // Define a valid motion down event.
-    event.initialize(DEVICE_ID, source, displayId,
-            AMOTION_EVENT_ACTION_DOWN, /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0,
-            AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
-            /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0,
-            /* yPrecision */ 0, currentTime, currentTime, /*pointerCount*/ 1, pointerProperties,
-            pointerCoords);
+    event.initialize(DEVICE_ID, source, displayId, action, /* actionButton */ 0, /* flags */ 0,
+                     /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
+                     /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0,
+                     /* yPrecision */ 0, xCursorPosition, yCursorPosition, currentTime, currentTime,
+                     /*pointerCount*/ 1, pointerProperties, pointerCoords);
 
     // Inject event until dispatch out.
     return dispatcher->injectInputEvent(
@@ -551,6 +576,11 @@
             INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
 }
 
+static int32_t injectMotionDown(const sp<InputDispatcher>& dispatcher, int32_t source,
+                                int32_t displayId, int32_t x = 100, int32_t y = 200) {
+    return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_DOWN, source, displayId, x, y);
+}
+
 static NotifyKeyArgs generateKeyArgs(int32_t action, int32_t displayId = ADISPLAY_ID_NONE) {
     nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
     // Define a valid key event.
@@ -576,11 +606,12 @@
     nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
     // Define a valid motion event.
     NotifyMotionArgs args(/* sequenceNum */ 0, currentTime, DEVICE_ID, source, displayId,
-            POLICY_FLAG_PASS_TO_USER, action, /* actionButton */ 0, /* flags */ 0,
-            AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
-            AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, pointerProperties,
-            pointerCoords, /* xPrecision */ 0, /* yPrecision */ 0, currentTime,
-            /* videoFrames */ {});
+                          POLICY_FLAG_PASS_TO_USER, action, /* actionButton */ 0, /* flags */ 0,
+                          AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
+                          AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1,
+                          pointerProperties, pointerCoords, /* xPrecision */ 0, /* yPrecision */ 0,
+                          AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                          AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, /* videoFrames */ {});
 
     return args;
 }
@@ -704,6 +735,32 @@
     windowSecond->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
 }
 
+TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) {
+    sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+
+    sp<FakeWindowHandle> windowLeft =
+            new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
+    windowLeft->setFrame(Rect(0, 0, 600, 800));
+    windowLeft->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);
+    sp<FakeWindowHandle> windowRight =
+            new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
+    windowRight->setFrame(Rect(600, 0, 1200, 800));
+    windowRight->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);
+
+    mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+
+    std::vector<sp<InputWindowHandle>> inputWindowHandles{windowLeft, windowRight};
+    mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+
+    // Inject an event with coordinate in the area of right window, with mouse cursor in the area of
+    // left window. This event should be dispatched to the left window.
+    ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED,
+              injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE,
+                                ADISPLAY_ID_DEFAULT, 610, 400, 599, 400));
+    windowLeft->consumeEvent(AINPUT_EVENT_TYPE_MOTION, ADISPLAY_ID_DEFAULT);
+    windowRight->assertNoEvents();
+}
+
 /* Test InputDispatcher for MultiDisplay */
 class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
 public: