Repository: robolectric/robolectric (Java)

Issue:
Track MotionEvent's offsetLocation behaivor change from Android 12L
> Looks like the MotionEvent#offsetLocation only works for TOUCHSCREEN source on new Android version, see https://cs.android.com/android/_/android/platform/cts/+/94b12501181957920053a23d92a46b74d65a16cd:tests/tests/view/src/android/view/cts/MotionEventTest.java;l=325;bpv=1;bpt=0;drc=d1cce47035b827bfa05746ab6d0c7cfed2812d67;dlc=3d620013b0faf66c65caa3c604d14ad7f1b4c308. It's better if we can enhance current MotionEventTest for Robolectric too.

See https://github.com/robolectric/robolectric/pull/7170 for detail.



Discussion: @hoisie I copied missed test from `MotionEventTest` in master branch at https://github.com/robolectric/robolectric/pull/7216, and it failed on Robolectric and Emulator. We need to wait response from Android Product Team about this restriction before doing more for this issue.



Fix (patch):
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/NativeInput.java b/shadows/framework/src/main/java/org/robolectric/shadows/NativeInput.java
index cbda248650a..408f94aeacc 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/NativeInput.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/NativeInput.java
@@ -2,7 +2,10 @@
 
 import static com.google.common.base.Preconditions.checkState;
 import static org.robolectric.shadows.NativeAndroidInput.AINPUT_EVENT_TYPE_MOTION;
+import static org.robolectric.shadows.NativeAndroidInput.AINPUT_SOURCE_CLASS_JOYSTICK;
 import static org.robolectric.shadows.NativeAndroidInput.AINPUT_SOURCE_CLASS_POINTER;
+import static org.robolectric.shadows.NativeAndroidInput.AINPUT_SOURCE_CLASS_POSITION;
+import static org.robolectric.shadows.NativeAndroidInput.AINPUT_SOURCE_MOUSE_RELATIVE;
 import static org.robolectric.shadows.NativeAndroidInput.AKEY_EVENT_FLAG_CANCELED;
 import static org.robolectric.shadows.NativeAndroidInput.AMOTION_EVENT_ACTION_CANCEL;
 import static org.robolectric.shadows.NativeAndroidInput.AMOTION_EVENT_ACTION_DOWN;
@@ -30,7 +33,9 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Optional;
+import org.robolectric.RuntimeEnvironment;
 import org.robolectric.res.android.Ref;
+import org.robolectric.versioning.AndroidVersions;
 
 /**
  * Java representation of framework native input Transliterated from oreo-mr1 (SDK 27)
@@ -436,6 +441,9 @@ public float getRawY(int pointerIndex) {
 
     public float getAxisValue(int axis, int pointerIndex) {
       float value = getRawPointerCoords(pointerIndex).getAxisValue(axis);
+      if (shouldDisregardTransformation(mSource)) {
+        return value;
+      }
       switch (axis) {
         case AMOTION_EVENT_AXIS_X:
           return value + mXOffset;
@@ -507,6 +515,9 @@ public float getHistoricalRawY(int pointerIndex, int historicalIndex) {
 
     public float getHistoricalAxisValue(int axis, int pointerIndex, int historicalIndex) {
       float value = getHistoricalRawPointerCoords(pointerIndex, historicalIndex).getAxisValue(axis);
+      if (shouldDisregardTransformation(mSource)) {
+        return value;
+      }
       switch (axis) {
         case AMOTION_EVENT_AXIS_X:
           return value + mXOffset;
@@ -954,5 +965,26 @@ List<Long> getSampleEventTimes() {
     List<NativeInput.PointerCoords> getSamplePointerCoords() {
       return mSamplePointerCoords;
     }
+
+    // frameworks/native/libs/input/Input.cpp#isFromSource
+    private static boolean isFromSource(int source, int test) {
+      return (source & test) == test;
+    }
+
+    // frameworks/native/libs/input/Input.cpp#shouldDisregardTransformation
+    private static boolean shouldDisregardTransformation(int source) {
+      // From the ctesque test result, the offsetLocation is not supported by non pointer source
+      // sources from Android 12L. So this method expects itself can work from Android 12L.
+      if (RuntimeEnvironment.getApiLevel() >= AndroidVersions.Sv2.SDK_INT) {
+        // See
+        // https://cs.android.com/android/_/android/platform/frameworks/native/+/7e1ee565b3fe4738e6771bceb2e9679562232992.
+        // Do not apply any transformations to axes from joysticks, touchpads, or relative mice.
+        return isFromSource(source, AINPUT_SOURCE_CLASS_JOYSTICK)
+            || isFromSource(source, AINPUT_SOURCE_CLASS_POSITION)
+            || isFromSource(source, AINPUT_SOURCE_MOUSE_RELATIVE);
+      } else {
+        return false;
+      }
+    }
   }
 }