Add enough information to compatibility-transform getRaw()

Many apps are mis-using getRaw (assuming it means screen-coordinates).

This means, for now, we have to do a compatibility transform on the
API to prevent breaking said apps.

Fortunately, since the input window transform includes rotation,
the only extra information we need to calculate this compat-raw
is the display size.

This CL topic pipes the display size around so that it makes into the
MotionEvent and can be used to calculate getRaw()

Bug: 179274888
Test: atest inputflinger_tests:InputDispatcherTest
Change-Id: Iff893643312e8ec9f38eeb96d76a41fdb3a28350
diff --git a/include/input/Input.h b/include/input/Input.h
index bb5ca0e..7b522bb 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -318,6 +318,12 @@
  */
 constexpr float AMOTION_EVENT_INVALID_CURSOR_POSITION = std::numeric_limits<float>::quiet_NaN();
 
+/**
+ * Invalid value for display size. Used when display size isn't available for an event or doesn't
+ * matter. This is just a constant 0 so that it has no effect if unused.
+ */
+constexpr int32_t AMOTION_EVENT_INVALID_DISPLAY_SIZE = 0;
+
 /*
  * Pointer coordinate data.
  */
@@ -360,6 +366,8 @@
         return getAxisValue(AMOTION_EVENT_AXIS_Y);
     }
 
+    vec2 getXYValue() const { return vec2(getX(), getY()); }
+
 #ifdef __linux__
     status_t readFromParcel(Parcel* parcel);
     status_t writeToParcel(Parcel* parcel) const;
@@ -548,6 +556,8 @@
 
     void setCursorPosition(float x, float y);
 
+    int2 getDisplaySize() const { return {mDisplayWidth, mDisplayHeight}; }
+
     static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); }
 
     inline nsecs_t getDownTime() const { return mDownTime; }
@@ -570,8 +580,17 @@
 
     inline nsecs_t getEventTime() const { return mSampleEventTimes[getHistorySize()]; }
 
+    /**
+     * The actual raw pointer coords: whatever comes from the input device without any external
+     * transforms applied.
+     */
     const PointerCoords* getRawPointerCoords(size_t pointerIndex) const;
 
+    /**
+     * This is the raw axis value. However, for X/Y axes, this currently applies a "compat-raw"
+     * transform because many apps (incorrectly) assumed that raw == oriented-screen-space.
+     * "compat raw" is raw coordinates with screen rotation applied.
+     */
     float getRawAxisValue(int32_t axis, size_t pointerIndex) const;
 
     inline float getRawX(size_t pointerIndex) const {
@@ -634,9 +653,18 @@
         return mSampleEventTimes[historicalIndex];
     }
 
+    /**
+     * The actual raw pointer coords: whatever comes from the input device without any external
+     * transforms applied.
+     */
     const PointerCoords* getHistoricalRawPointerCoords(
             size_t pointerIndex, size_t historicalIndex) const;
 
+    /**
+     * This is the raw axis value. However, for X/Y axes, this currently applies a "compat-raw"
+     * transform because many apps (incorrectly) assumed that raw == oriented-screen-space.
+     * "compat raw" is raw coordinates with screen rotation applied.
+     */
     float getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
             size_t historicalIndex) const;
 
@@ -704,9 +732,9 @@
                     int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState,
                     MotionClassification classification, const ui::Transform& transform,
                     float xPrecision, float yPrecision, float rawXCursorPosition,
-                    float rawYCursorPosition, nsecs_t downTime, nsecs_t eventTime,
-                    size_t pointerCount, const PointerProperties* pointerProperties,
-                    const PointerCoords* pointerCoords);
+                    float rawYCursorPosition, int32_t displayWidth, int32_t displayHeight,
+                    nsecs_t downTime, nsecs_t eventTime, size_t pointerCount,
+                    const PointerProperties* pointerProperties, const PointerCoords* pointerCoords);
 
     void copyFrom(const MotionEvent* other, bool keepHistory);
 
@@ -759,6 +787,8 @@
     float mYPrecision;
     float mRawXCursorPosition;
     float mRawYCursorPosition;
+    int32_t mDisplayWidth;
+    int32_t mDisplayHeight;
     nsecs_t mDownTime;
     Vector<PointerProperties> mPointerProperties;
     std::vector<nsecs_t> mSampleEventTimes;
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 898d1a9..ff33678 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -136,6 +136,8 @@
             float yPrecision;
             float xCursorPosition;
             float yCursorPosition;
+            int32_t displayWidth;
+            int32_t displayHeight;
             uint32_t pointerCount;
             uint32_t empty3;
             /**
@@ -353,8 +355,9 @@
                                 int32_t metaState, int32_t buttonState,
                                 MotionClassification classification, const ui::Transform& transform,
                                 float xPrecision, float yPrecision, float xCursorPosition,
-                                float yCursorPosition, nsecs_t downTime, nsecs_t eventTime,
-                                uint32_t pointerCount, const PointerProperties* pointerProperties,
+                                float yCursorPosition, int32_t displayWidth, int32_t displayHeight,
+                                nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount,
+                                const PointerProperties* pointerProperties,
                                 const PointerCoords* pointerCoords);
 
     /* Publishes a focus event to the input channel.
diff --git a/include/input/InputWindow.h b/include/input/InputWindow.h
index 36097d6..121be6d 100644
--- a/include/input/InputWindow.h
+++ b/include/input/InputWindow.h
@@ -168,6 +168,10 @@
     // Transform applied to individual windows.
     ui::Transform transform;
 
+    // Display size in its natural rotation. Used to rotate raw coordinates for compatibility.
+    int32_t displayWidth = AMOTION_EVENT_INVALID_DISPLAY_SIZE;
+    int32_t displayHeight = AMOTION_EVENT_INVALID_DISPLAY_SIZE;
+
     /*
      * This is filled in by the WM relative to the frame and then translated
      * to absolute coordinates by SurfaceFlinger once the frame is computed.
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 5600eb3..deb4679 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -340,7 +340,8 @@
                              int32_t flags, int32_t edgeFlags, int32_t metaState,
                              int32_t buttonState, MotionClassification classification,
                              const ui::Transform& transform, float xPrecision, float yPrecision,
-                             float rawXCursorPosition, float rawYCursorPosition, nsecs_t downTime,
+                             float rawXCursorPosition, float rawYCursorPosition,
+                             int32_t displayWidth, int32_t displayHeight, nsecs_t downTime,
                              nsecs_t eventTime, size_t pointerCount,
                              const PointerProperties* pointerProperties,
                              const PointerCoords* pointerCoords) {
@@ -357,6 +358,8 @@
     mYPrecision = yPrecision;
     mRawXCursorPosition = rawXCursorPosition;
     mRawYCursorPosition = rawYCursorPosition;
+    mDisplayWidth = displayWidth;
+    mDisplayHeight = displayHeight;
     mDownTime = downTime;
     mPointerProperties.clear();
     mPointerProperties.appendArray(pointerProperties, pointerCount);
@@ -380,6 +383,8 @@
     mYPrecision = other->mYPrecision;
     mRawXCursorPosition = other->mRawXCursorPosition;
     mRawYCursorPosition = other->mRawYCursorPosition;
+    mDisplayWidth = other->mDisplayWidth;
+    mDisplayHeight = other->mDisplayHeight;
     mDownTime = other->mDownTime;
     mPointerProperties = other->mPointerProperties;
 
@@ -426,7 +431,7 @@
 }
 
 float MotionEvent::getRawAxisValue(int32_t axis, size_t pointerIndex) const {
-    return getRawPointerCoords(pointerIndex)->getAxisValue(axis);
+    return getHistoricalRawAxisValue(axis, pointerIndex, getHistorySize());
 }
 
 float MotionEvent::getAxisValue(int32_t axis, size_t pointerIndex) const {
@@ -440,7 +445,32 @@
 
 float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex,
         size_t historicalIndex) const {
-    return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
+    if (axis != AMOTION_EVENT_AXIS_X && axis != AMOTION_EVENT_AXIS_Y) {
+        return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
+    }
+    // 0x7 encapsulates all 3 rotations (see ui::Transform::RotationFlags)
+    static const int ALL_ROTATIONS_MASK = 0x7;
+    uint32_t orientation = (mTransform.getOrientation() & ALL_ROTATIONS_MASK);
+    if (orientation == ui::Transform::ROT_0) {
+        return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
+    }
+
+    // For compatibility, convert raw coordinates into "oriented screen space". Once app developers
+    // are educated about getRaw, we can consider removing this.
+    vec2 xy = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getXYValue();
+    const float unrotatedX = xy.x;
+    if (orientation == ui::Transform::ROT_90) {
+        xy.x = mDisplayHeight - xy.y;
+        xy.y = unrotatedX;
+    } else if (orientation == ui::Transform::ROT_180) {
+        xy.x = mDisplayWidth - xy.x;
+        xy.y = mDisplayHeight - xy.y;
+    } else if (orientation == ui::Transform::ROT_270) {
+        xy.x = xy.y;
+        xy.y = mDisplayWidth - unrotatedX;
+    }
+    static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1);
+    return xy[axis];
 }
 
 float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex,
@@ -449,19 +479,10 @@
         return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
     }
 
-    float rawX = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getX();
-    float rawY = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getY();
-    vec2 vals = mTransform.transform(rawX, rawY);
-
-    switch (axis) {
-    case AMOTION_EVENT_AXIS_X:
-        return vals.x;
-    case AMOTION_EVENT_AXIS_Y:
-        return vals.y;
-    }
-
-    // This should never happen
-    return 0;
+    vec2 vals = mTransform.transform(
+            getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getXYValue());
+    static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1);
+    return vals[axis];
 }
 
 ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const {
@@ -606,6 +627,8 @@
     mYPrecision = parcel->readFloat();
     mRawXCursorPosition = parcel->readFloat();
     mRawYCursorPosition = parcel->readFloat();
+    mDisplayWidth = parcel->readInt32();
+    mDisplayHeight = parcel->readInt32();
     mDownTime = parcel->readInt64();
 
     mPointerProperties.clear();
@@ -665,6 +688,8 @@
     parcel->writeFloat(mYPrecision);
     parcel->writeFloat(mRawXCursorPosition);
     parcel->writeFloat(mRawYCursorPosition);
+    parcel->writeInt32(mDisplayWidth);
+    parcel->writeInt32(mDisplayHeight);
     parcel->writeInt64(mDownTime);
 
     for (size_t i = 0; i < pointerCount; i++) {
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 56a064b..de75691 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -228,6 +228,10 @@
             msg->body.motion.xCursorPosition = body.motion.xCursorPosition;
             // float yCursorPosition
             msg->body.motion.yCursorPosition = body.motion.yCursorPosition;
+            // int32_t displayW
+            msg->body.motion.displayWidth = body.motion.displayWidth;
+            // int32_t displayH
+            msg->body.motion.displayHeight = body.motion.displayHeight;
             // uint32_t pointerCount
             msg->body.motion.pointerCount = body.motion.pointerCount;
             //struct Pointer pointers[MAX_POINTERS]
@@ -517,9 +521,9 @@
         std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton, int32_t flags,
         int32_t edgeFlags, int32_t metaState, int32_t buttonState,
         MotionClassification classification, const ui::Transform& transform, float xPrecision,
-        float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime,
-        nsecs_t eventTime, uint32_t pointerCount, const PointerProperties* pointerProperties,
-        const PointerCoords* pointerCoords) {
+        float yPrecision, float xCursorPosition, float yCursorPosition, int32_t displayWidth,
+        int32_t displayHeight, 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 ")",
@@ -577,6 +581,8 @@
     msg.body.motion.yPrecision = yPrecision;
     msg.body.motion.xCursorPosition = xCursorPosition;
     msg.body.motion.yCursorPosition = yCursorPosition;
+    msg.body.motion.displayWidth = displayWidth;
+    msg.body.motion.displayHeight = displayHeight;
     msg.body.motion.downTime = downTime;
     msg.body.motion.eventTime = eventTime;
     msg.body.motion.pointerCount = pointerCount;
@@ -1343,6 +1349,7 @@
                       msg->body.motion.buttonState, msg->body.motion.classification, transform,
                       msg->body.motion.xPrecision, msg->body.motion.yPrecision,
                       msg->body.motion.xCursorPosition, msg->body.motion.yCursorPosition,
+                      msg->body.motion.displayWidth, msg->body.motion.displayHeight,
                       msg->body.motion.downTime, msg->body.motion.eventTime, pointerCount,
                       pointerProperties, pointerCoords);
 }
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index 601d8da..15ab428 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -271,6 +271,7 @@
                       AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
                       MotionClassification::NONE, mTransform, 2.0f, 2.1f,
                       AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                      AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
                       ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, 2, pointerProperties,
                       pointerCoords);
 
@@ -592,6 +593,7 @@
                      AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
                      MotionClassification::NONE, identityTransform, 0 /*xPrecision*/,
                      0 /*yPrecision*/, 3 + RADIUS /*xCursorPosition*/, 2 /*yCursorPosition*/,
+                     AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
                      0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties,
                      pointerCoords);
     float originalRawX = 0 + 3;
@@ -634,6 +636,71 @@
     ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
 }
 
+TEST_F(MotionEventTest, RawCompatTransform) {
+    auto createTouchDownEvent = [](int x, int y, ui::Transform transform) {
+        std::vector<PointerProperties> pointerProperties;
+        pointerProperties.push_back(PointerProperties{/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER});
+        std::vector<PointerCoords> pointerCoords;
+        pointerCoords.emplace_back().clear();
+        pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_X, x);
+        pointerCoords.back().setAxisValue(AMOTION_EVENT_AXIS_Y, y);
+        nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC);
+        MotionEvent event;
+        event.initialize(InputEvent::nextId(), /* deviceId */ 1, AINPUT_SOURCE_TOUCHSCREEN,
+                         /* displayId */ 0, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN,
+                         /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE,
+                         /* buttonState */ 0, MotionClassification::NONE, transform,
+                         /* xPrecision */ 0, /* yPrecision */ 0,
+                         AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                         AMOTION_EVENT_INVALID_CURSOR_POSITION, /* displayWidth */ 400,
+                         /* displayHeight */ 800, eventTime, eventTime, pointerCoords.size(),
+                         pointerProperties.data(), pointerCoords.data());
+        return event;
+    };
+
+    {
+        // Make sure raw is raw regardless of transform translation.
+        ui::Transform xform;
+        xform.set(20, 40);
+        MotionEvent event = createTouchDownEvent(60, 100, xform);
+        ASSERT_EQ(60, event.getRawX(0));
+        ASSERT_EQ(100, event.getRawY(0));
+        ASSERT_NE(event.getRawX(0), event.getX(0));
+        ASSERT_NE(event.getRawY(0), event.getY(0));
+    }
+
+    // Next check that getRaw contains rotation (for compatibility) but otherwise is still
+    // "Screen-space". The following tests check all 3 rotations.
+    {
+        // Create a rotate-90 transform with an offset (like a window which isn't fullscreen).
+        ui::Transform xform(ui::Transform::ROT_90, 800, 400);
+        xform.set(xform.tx() + 20, xform.ty() + 40);
+        MotionEvent event = createTouchDownEvent(60, 100, xform);
+        ASSERT_EQ(700, event.getRawX(0));
+        ASSERT_EQ(60, event.getRawY(0));
+        ASSERT_NE(event.getRawX(0), event.getX(0));
+        ASSERT_NE(event.getRawY(0), event.getY(0));
+    }
+
+    {
+        // Same as above, but check rotate-180.
+        ui::Transform xform(ui::Transform::ROT_180, 400, 800);
+        xform.set(xform.tx() + 20, xform.ty() + 40);
+        MotionEvent event = createTouchDownEvent(60, 100, xform);
+        ASSERT_EQ(340, event.getRawX(0));
+        ASSERT_EQ(700, event.getRawY(0));
+    }
+
+    {
+        // Same as above, but check rotate-270.
+        ui::Transform xform(ui::Transform::ROT_270, 800, 400);
+        xform.set(xform.tx() + 20, xform.ty() + 40);
+        MotionEvent event = createTouchDownEvent(60, 100, xform);
+        ASSERT_EQ(100, event.getRawX(0));
+        ASSERT_EQ(340, event.getRawY(0));
+    }
+}
+
 TEST_F(MotionEventTest, Initialize_SetsClassification) {
     std::array<MotionClassification, 3> classifications = {
             MotionClassification::NONE,
@@ -657,7 +724,8 @@
                          DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
                          AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, classification,
                          identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                         AMOTION_EVENT_INVALID_CURSOR_POSITION, 0 /*downTime*/, 0 /*eventTime*/,
+                         AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+                         AMOTION_EVENT_INVALID_DISPLAY_SIZE, 0 /*downTime*/, 0 /*eventTime*/,
                          pointerCount, pointerProperties, pointerCoords);
         ASSERT_EQ(classification, event.getClassification());
     }
@@ -678,8 +746,10 @@
     event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_MOUSE, DISPLAY_ID,
                      INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE,
                      AMETA_NONE, 0, MotionClassification::NONE, identityTransform, 0, 0,
-                     280 /*xCursorPosition*/, 540 /*yCursorPosition*/, 0 /*downTime*/,
-                     0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords);
+                     280 /*xCursorPosition*/, 540 /*yCursorPosition*/,
+                     AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+                     0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties,
+                     pointerCoords);
     event.offsetLocation(20, 60);
     ASSERT_EQ(280, event.getRawXCursorPosition());
     ASSERT_EQ(540, event.getRawYCursorPosition());
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 088e00b..a2cfaa1 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -162,6 +162,8 @@
     constexpr float yPrecision = 0.5;
     constexpr float xCursorPosition = 1.3;
     constexpr float yCursorPosition = 50.6;
+    constexpr int32_t displayWidth = 1000;
+    constexpr int32_t displayHeight = 2000;
     constexpr nsecs_t downTime = 3;
     constexpr size_t pointerCount = 3;
     constexpr nsecs_t eventTime = 4;
@@ -190,8 +192,9 @@
     status = mPublisher->publishMotionEvent(seq, eventId, deviceId, source, displayId, hmac, action,
                                             actionButton, flags, edgeFlags, metaState, buttonState,
                                             classification, transform, xPrecision, yPrecision,
-                                            xCursorPosition, yCursorPosition, downTime, eventTime,
-                                            pointerCount, pointerProperties, pointerCoords);
+                                            xCursorPosition, yCursorPosition, displayWidth,
+                                            displayHeight, downTime, eventTime, pointerCount,
+                                            pointerProperties, pointerCoords);
     ASSERT_EQ(OK, status)
             << "publisher publishMotionEvent should return OK";
 
@@ -228,6 +231,8 @@
     EXPECT_EQ(yCursorPosition, motionEvent->getRawYCursorPosition());
     EXPECT_EQ(xCursorPosition * xScale + xOffset, motionEvent->getXCursorPosition());
     EXPECT_EQ(yCursorPosition * yScale + yOffset, motionEvent->getYCursorPosition());
+    EXPECT_EQ(displayWidth, motionEvent->getDisplaySize().x);
+    EXPECT_EQ(displayHeight, motionEvent->getDisplaySize().y);
     EXPECT_EQ(downTime, motionEvent->getDownTime());
     EXPECT_EQ(eventTime, motionEvent->getEventTime());
     EXPECT_EQ(pointerCount, motionEvent->getPointerCount());
@@ -455,7 +460,7 @@
     status = mPublisher->publishMotionEvent(0, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0,
                                             0, 0, 0, MotionClassification::NONE, identityTransform,
                                             0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                                            AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0,
+                                            AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, 0, 0,
                                             pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
@@ -471,7 +476,7 @@
     status = mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0,
                                             0, 0, 0, MotionClassification::NONE, identityTransform,
                                             0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                                            AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0,
+                                            AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, 0, 0,
                                             pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
@@ -492,7 +497,7 @@
     status = mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0,
                                             0, 0, 0, MotionClassification::NONE, identityTransform,
                                             0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                                            AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0,
+                                            AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0, 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 585779e..5861d55 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -74,9 +74,11 @@
   CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 124);
   CHECK_OFFSET(InputMessage::Body::Motion, xCursorPosition, 128);
   CHECK_OFFSET(InputMessage::Body::Motion, yCursorPosition, 132);
-  CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 136);
-  CHECK_OFFSET(InputMessage::Body::Motion, empty3, 140);
-  CHECK_OFFSET(InputMessage::Body::Motion, pointers, 144);
+  CHECK_OFFSET(InputMessage::Body::Motion, displayWidth, 136);
+  CHECK_OFFSET(InputMessage::Body::Motion, displayHeight, 140);
+  CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 144);
+  CHECK_OFFSET(InputMessage::Body::Motion, empty3, 148);
+  CHECK_OFFSET(InputMessage::Body::Motion, pointers, 152);
 
   CHECK_OFFSET(InputMessage::Body::Focus, eventId, 0);
   CHECK_OFFSET(InputMessage::Body::Focus, hasFocus, 4);
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index d049d05..aefc2ec 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -183,7 +183,8 @@
                          AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
                          MotionClassification::NONE, identityTransform, 0 /*xPrecision*/,
                          0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                         AMOTION_EVENT_INVALID_CURSOR_POSITION, 0 /*downTime*/,
+                         AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+                         AMOTION_EVENT_INVALID_DISPLAY_SIZE, 0 /*downTime*/,
                          entry.eventTime.count(), pointerCount, properties, coords);
 
         events.emplace_back(event);
diff --git a/libs/input/tests/VerifiedInputEvent_test.cpp b/libs/input/tests/VerifiedInputEvent_test.cpp
index 36f87b8..f79098c 100644
--- a/libs/input/tests/VerifiedInputEvent_test.cpp
+++ b/libs/input/tests/VerifiedInputEvent_test.cpp
@@ -46,8 +46,10 @@
                      INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, flags,
                      AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
                      MotionClassification::NONE, transform, 0.1 /*xPrecision*/, 0.2 /*yPrecision*/,
-                     280 /*xCursorPosition*/, 540 /*yCursorPosition*/, 100 /*downTime*/,
-                     200 /*eventTime*/, pointerCount, pointerProperties, pointerCoords);
+                     280 /*xCursorPosition*/, 540 /*yCursorPosition*/,
+                     AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+                     100 /*downTime*/, 200 /*eventTime*/, pointerCount, pointerProperties,
+                     pointerCoords);
     return event;
 }
 
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 7bd0c6b..1b5f1ab 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -232,7 +232,8 @@
                      /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
                      identityTransform, /* xPrecision */ 0,
                      /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, currentTime,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+                     AMOTION_EVENT_INVALID_DISPLAY_SIZE, currentTime, currentTime,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     return event;
 }
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index 5270b8a..6ed9593 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -296,12 +296,13 @@
 volatile int32_t DispatchEntry::sNextSeqAtomic;
 
 DispatchEntry::DispatchEntry(std::shared_ptr<EventEntry> eventEntry, int32_t targetFlags,
-                             ui::Transform transform, float globalScaleFactor)
+                             ui::Transform transform, float globalScaleFactor, vec2 displaySize)
       : seq(nextSeq()),
         eventEntry(std::move(eventEntry)),
         targetFlags(targetFlags),
         transform(transform),
         globalScaleFactor(globalScaleFactor),
+        displaySize(displaySize),
         deliveryTime(0),
         resolvedAction(0),
         resolvedFlags(0) {}
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index f3ef64b..45c5e24 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -215,6 +215,7 @@
     int32_t targetFlags;
     ui::Transform transform;
     float globalScaleFactor;
+    vec2 displaySize;
     // Both deliveryTime and timeoutTime are only populated when the entry is sent to the app,
     // and will be undefined before that.
     nsecs_t deliveryTime; // time when the event was actually delivered
@@ -227,7 +228,7 @@
     int32_t resolvedFlags;
 
     DispatchEntry(std::shared_ptr<EventEntry> eventEntry, int32_t targetFlags,
-                  ui::Transform transform, float globalScaleFactor);
+                  ui::Transform transform, float globalScaleFactor, vec2 displaySize);
 
     inline bool hasForegroundTarget() const { return targetFlags & InputTarget::FLAG_FOREGROUND; }
 
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 27443b0..16cb7d7 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -339,14 +339,16 @@
             // values do not represent on-screen coordinates, so they should not have any window
             // transformations applied to them.
             return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, identityTransform,
-                                                   1.0f /*globalScaleFactor*/);
+                                                   1.0f /*globalScaleFactor*/,
+                                                   inputTarget.displaySize);
         }
     }
 
     if (inputTarget.useDefaultPointerTransform()) {
         const ui::Transform& transform = inputTarget.getDefaultPointerTransform();
         return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, transform,
-                                               inputTarget.globalScaleFactor);
+                                               inputTarget.globalScaleFactor,
+                                               inputTarget.displaySize);
     }
 
     ALOG_ASSERT(eventEntry->type == EventEntry::Type::MOTION);
@@ -397,7 +399,8 @@
 
     std::unique_ptr<DispatchEntry> dispatchEntry =
             std::make_unique<DispatchEntry>(std::move(combinedMotionEntry), inputTargetFlags,
-                                            firstPointerTransform, inputTarget.globalScaleFactor);
+                                            firstPointerTransform, inputTarget.globalScaleFactor,
+                                            inputTarget.displaySize);
     return dispatchEntry;
 }
 
@@ -2402,6 +2405,8 @@
         inputTarget.inputChannel = inputChannel;
         inputTarget.flags = targetFlags;
         inputTarget.globalScaleFactor = windowInfo->globalScaleFactor;
+        inputTarget.displaySize =
+                vec2(windowHandle->getInfo()->displayWidth, windowHandle->getInfo()->displayHeight);
         inputTargets.push_back(inputTarget);
         it = inputTargets.end() - 1;
     }
@@ -3107,6 +3112,8 @@
                                                      motionEntry.xPrecision, motionEntry.yPrecision,
                                                      motionEntry.xCursorPosition,
                                                      motionEntry.yCursorPosition,
+                                                     dispatchEntry->displaySize.x,
+                                                     dispatchEntry->displaySize.y,
                                                      motionEntry.downTime, motionEntry.eventTime,
                                                      motionEntry.pointerCount,
                                                      motionEntry.pointerProperties, usingCoords);
@@ -3819,7 +3826,8 @@
                              args->action, args->actionButton, args->flags, args->edgeFlags,
                              args->metaState, args->buttonState, args->classification, transform,
                              args->xPrecision, args->yPrecision, args->xCursorPosition,
-                             args->yCursorPosition, args->downTime, args->eventTime,
+                             args->yCursorPosition, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+                             AMOTION_EVENT_INVALID_DISPLAY_SIZE, args->downTime, args->eventTime,
                              args->pointerCount, args->pointerProperties, args->pointerCoords);
 
             policyFlags |= POLICY_FLAG_FILTERED;
diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h
index debf805..2543852 100644
--- a/services/inputflinger/dispatcher/InputTarget.h
+++ b/services/inputflinger/dispatcher/InputTarget.h
@@ -100,6 +100,9 @@
     // (ignored for KeyEvents)
     float globalScaleFactor = 1.0f;
 
+    // Display-size in its natural rotation. Used for compatibility transform of raw coordinates.
+    vec2 displaySize = {AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE};
+
     // The subset of pointer ids to include in motion events dispatched to this input target
     // if FLAG_SPLIT is set.
     BitSet32 pointerIds;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 31d6900..9687c83 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -526,7 +526,8 @@
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
                      /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification,
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+                     AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -539,6 +540,7 @@
                              (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                      0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                     AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
                      ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties,
                      pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
@@ -551,6 +553,7 @@
                              (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                      0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                     AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
                      ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties,
                      pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
@@ -564,6 +567,7 @@
                              (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                      0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                     AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
                      ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties,
                      pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
@@ -576,6 +580,7 @@
                              (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                      0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                     AMOTION_EVENT_INVALID_DISPLAY_SIZE, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
                      ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties,
                      pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
@@ -587,7 +592,8 @@
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
                      AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+                     AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 0, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -597,7 +603,8 @@
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
                      AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+                     AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -609,7 +616,8 @@
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
                      AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+                     AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -620,7 +628,8 @@
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
                      AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+                     AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -633,7 +642,8 @@
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
                      AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_TIME, ARBITRARY_TIME,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_DISPLAY_SIZE,
+                     AMOTION_EVENT_INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 2, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -1237,8 +1247,8 @@
                          mAction, mActionButton, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE,
                          mButtonState, MotionClassification::NONE, identityTransform,
                          /* xPrecision */ 0, /* yPrecision */ 0, mRawXCursorPosition,
-                         mRawYCursorPosition, mEventTime, mEventTime, mPointers.size(),
-                         pointerProperties.data(), pointerCoords.data());
+                         mRawYCursorPosition, mDisplayWidth, mDisplayHeight, mEventTime, mEventTime,
+                         mPointers.size(), pointerProperties.data(), pointerCoords.data());
 
         return event;
     }
@@ -1252,6 +1262,8 @@
     int32_t mButtonState{0};
     float mRawXCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION};
     float mRawYCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION};
+    int32_t mDisplayWidth{AMOTION_EVENT_INVALID_DISPLAY_SIZE};
+    int32_t mDisplayHeight{AMOTION_EVENT_INVALID_DISPLAY_SIZE};
 
     std::vector<PointerBuilder> mPointers;
 };
@@ -2029,6 +2041,19 @@
                                      expectedDisplayId, expectedFlags);
     }
 
+    MotionEvent* consumeMotion() {
+        InputEvent* event = mInputReceiver->consume();
+        if (!event) {
+            ADD_FAILURE() << "No event was produced";
+            return nullptr;
+        }
+        if (event->getType() != AINPUT_EVENT_TYPE_MOTION) {
+            ADD_FAILURE() << "Received event of type " << event->getType() << " instead of motion";
+            return nullptr;
+        }
+        return static_cast<MotionEvent*>(event);
+    }
+
     void assertNoEvents() { mInputReceiver->assertNoEvents(); }
 
 private:
@@ -2115,6 +2140,27 @@
     mFakePolicy->assertNotifyMonitorResponsiveWasCalled();
 }
 
+// Tests for gesture monitors
+TEST_F(InputDispatcherTest, GestureMonitor_NoWindowTransform) {
+    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+    sp<FakeWindowHandle> window =
+            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+    window->setWindowOffset(20, 40);
+    window->setWindowTransform(0, 1, -1, 0);
+
+    FakeMonitorReceiver monitor = FakeMonitorReceiver(mDispatcher, "GM_1", ADISPLAY_ID_DEFAULT,
+                                                      true /*isGestureMonitor*/);
+
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+    MotionEvent* event = monitor.consumeMotion();
+    // Even though window has transform, gesture monitor must not.
+    ASSERT_EQ(ui::Transform(), event->getTransform());
+}
+
 TEST_F(InputDispatcherTest, TestMoveEvent) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> window =
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 7707aaf..0d673ea 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2449,6 +2449,8 @@
     ui::Transform toPhysicalDisplay;
     if (display) {
         toPhysicalDisplay = display->getTransform();
+        info.displayWidth = display->getWidth();
+        info.displayHeight = display->getHeight();
     }
     fillInputFrameInfo(info, toPhysicalDisplay);