MotionEvent: Ensure addBatch works in the current coordinate space

The PointerCoords added via addBatch() are expected to be in the
"current" coordinate space of the event. If the event was transformed
before the batch was added, it should not affect the coordinate space of
the current batch.

To ensure coordinate consistency, we need to transfom the newly added
PointerCoords by the event's inverse transform so that we get the same
values out of the event.

Bug: 342349872
Test: atest MotionEventTest
Change-Id: I1a25fd6bf0f600b77b3c35cf2ef6d567f996b5dc
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index cb5af91..90f37c0 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -204,48 +204,57 @@
 }
 
 static void pointerCoordsToNative(JNIEnv* env, jobject pointerCoordsObj,
-        float xOffset, float yOffset, PointerCoords* outRawPointerCoords) {
-    outRawPointerCoords->clear();
-    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_X,
-            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.x) - xOffset);
-    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_Y,
-            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.y) - yOffset);
-    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
-            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.pressure));
-    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_SIZE,
-            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.size));
-    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR,
-            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.touchMajor));
-    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR,
-            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.touchMinor));
-    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR,
-            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.toolMajor));
-    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR,
-            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.toolMinor));
-    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION,
-            env->GetFloatField(pointerCoordsObj, gPointerCoordsClassInfo.orientation));
-    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X,
-                                      env->GetFloatField(pointerCoordsObj,
-                                                         gPointerCoordsClassInfo.relativeX));
-    outRawPointerCoords->setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y,
-                                      env->GetFloatField(pointerCoordsObj,
-                                                         gPointerCoordsClassInfo.relativeY));
-    outRawPointerCoords->isResampled =
+                                  PointerCoords& outRawPointerCoords) {
+    outRawPointerCoords.clear();
+    outRawPointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X,
+                                     env->GetFloatField(pointerCoordsObj,
+                                                        gPointerCoordsClassInfo.x));
+    outRawPointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y,
+                                     env->GetFloatField(pointerCoordsObj,
+                                                        gPointerCoordsClassInfo.y));
+    outRawPointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE,
+                                     env->GetFloatField(pointerCoordsObj,
+                                                        gPointerCoordsClassInfo.pressure));
+    outRawPointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SIZE,
+                                     env->GetFloatField(pointerCoordsObj,
+                                                        gPointerCoordsClassInfo.size));
+    outRawPointerCoords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR,
+                                     env->GetFloatField(pointerCoordsObj,
+                                                        gPointerCoordsClassInfo.touchMajor));
+    outRawPointerCoords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR,
+                                     env->GetFloatField(pointerCoordsObj,
+                                                        gPointerCoordsClassInfo.touchMinor));
+    outRawPointerCoords.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR,
+                                     env->GetFloatField(pointerCoordsObj,
+                                                        gPointerCoordsClassInfo.toolMajor));
+    outRawPointerCoords.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR,
+                                     env->GetFloatField(pointerCoordsObj,
+                                                        gPointerCoordsClassInfo.toolMinor));
+    outRawPointerCoords.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION,
+                                     env->GetFloatField(pointerCoordsObj,
+                                                        gPointerCoordsClassInfo.orientation));
+    outRawPointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X,
+                                     env->GetFloatField(pointerCoordsObj,
+                                                        gPointerCoordsClassInfo.relativeX));
+    outRawPointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y,
+                                     env->GetFloatField(pointerCoordsObj,
+                                                        gPointerCoordsClassInfo.relativeY));
+    outRawPointerCoords.isResampled =
             env->GetBooleanField(pointerCoordsObj, gPointerCoordsClassInfo.isResampled);
 
     BitSet64 bits =
             BitSet64(env->GetLongField(pointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisBits));
     if (!bits.isEmpty()) {
-        jfloatArray valuesArray = jfloatArray(env->GetObjectField(pointerCoordsObj,
-                gPointerCoordsClassInfo.mPackedAxisValues));
+        jfloatArray valuesArray = jfloatArray(
+                env->GetObjectField(pointerCoordsObj, gPointerCoordsClassInfo.mPackedAxisValues));
         if (valuesArray) {
-            jfloat* values = static_cast<jfloat*>(
-                    env->GetPrimitiveArrayCritical(valuesArray, NULL));
+            jfloat* values =
+                    static_cast<jfloat*>(env->GetPrimitiveArrayCritical(valuesArray, NULL));
 
             uint32_t index = 0;
             do {
                 uint32_t axis = bits.clearFirstMarkedBit();
-                outRawPointerCoords->setAxisValue(axis, values[index++]);
+                outRawPointerCoords.setAxisValue(axis, values[index++]);
             } while (!bits.isEmpty());
 
             env->ReleasePrimitiveArrayCritical(valuesArray, values, JNI_ABORT);
@@ -343,6 +352,10 @@
         event = std::make_unique<MotionEvent>();
     }
 
+    ui::Transform transform;
+    transform.set(xOffset, yOffset);
+    const ui::Transform inverseTransform = transform.inverse();
+
     PointerProperties pointerProperties[pointerCount];
     PointerCoords rawPointerCoords[pointerCount];
 
@@ -359,22 +372,22 @@
             jniThrowNullPointerException(env, "pointerCoords");
             return 0;
         }
-        pointerCoordsToNative(env, pointerCoordsObj, xOffset, yOffset, &rawPointerCoords[i]);
+        pointerCoordsToNative(env, pointerCoordsObj, rawPointerCoords[i]);
         if (rawPointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION) != 0.f) {
             flags |= AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_ORIENTATION |
                     AMOTION_EVENT_PRIVATE_FLAG_SUPPORTS_DIRECTIONAL_ORIENTATION;
         }
+        MotionEvent::calculateTransformedCoordsInPlace(rawPointerCoords[i], source, flags,
+                                                       inverseTransform);
         env->DeleteLocalRef(pointerCoordsObj);
     }
 
-    ui::Transform transform;
-    transform.set(xOffset, yOffset);
-    ui::Transform identityTransform;
+    static const ui::Transform kIdentityTransform;
     event->initialize(InputEvent::nextId(), deviceId, source, ui::LogicalDisplayId{displayId},
                       INVALID_HMAC, action, 0, flags, edgeFlags, metaState, buttonState,
                       static_cast<MotionClassification>(classification), transform, xPrecision,
                       yPrecision, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                      AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, downTimeNanos,
+                      AMOTION_EVENT_INVALID_CURSOR_POSITION, kIdentityTransform, downTimeNanos,
                       eventTimeNanos, pointerCount, pointerProperties, rawPointerCoords);
 
     return reinterpret_cast<jlong>(event.release());
@@ -395,6 +408,8 @@
         return;
     }
 
+    const ui::Transform inverseTransform = event->getTransform().inverse();
+
     PointerCoords rawPointerCoords[pointerCount];
 
     for (size_t i = 0; i < pointerCount; i++) {
@@ -403,8 +418,9 @@
             jniThrowNullPointerException(env, "pointerCoords");
             return;
         }
-        pointerCoordsToNative(env, pointerCoordsObj, event->getRawXOffset(), event->getRawYOffset(),
-                              &rawPointerCoords[i]);
+        pointerCoordsToNative(env, pointerCoordsObj, rawPointerCoords[i]);
+        MotionEvent::calculateTransformedCoordsInPlace(rawPointerCoords[i], event->getSource(),
+                                                       event->getFlags(), inverseTransform);
         env->DeleteLocalRef(pointerCoordsObj);
     }