MotionEvent: Round coordinates to a precision of 0.001

When tests inject input events at a location on the screen, the
dispatched event is expected to have the same coordinates. However, on
scaled devices, this may not always be the case due to precision losses
incurred through floating point arithmetics. For example, it was
possible for an injected event with a coordinate of 1.0 to end up with
a value of 0.9997.

To combat this issue, we will round transformed axis values that are
leaving a MotionEvent to a precision of 0.001. After this CL, even if
the injection process results in precision losses, they should be
overcome by rounding, assuming injection does not require greater
precision.

This will solve the issue where input injected to an inclusive edge of
the View bounds was not getting dispatched to the View due to precision
losses.

Bug: 264978231
Bug: 260965930
Test: atest libinput_tests
Test: atest inputflinger_tests
Test: atest HoverTest (with screen size override)
Change-Id: I81062597058361a1218e6873d34b9b0d2fbfad96
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 133b260..53b22cb 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -151,10 +151,23 @@
 
 // --- InputEvent ---
 
+// Due to precision limitations when working with floating points, transforming - namely
+// scaling - floating points can lead to minute errors. We round transformed values to approximately
+// three decimal places so that values like 0.99997 show up as 1.0.
+inline float roundTransformedCoords(float val) {
+    // Use a power to two to approximate three decimal places to potentially reduce some cycles.
+    // This should be at least as precise as MotionEvent::ROUNDING_PRECISION.
+    return std::round(val * 1024.f) / 1024.f;
+}
+
+inline vec2 roundTransformedCoords(vec2 p) {
+    return {roundTransformedCoords(p.x), roundTransformedCoords(p.y)};
+}
+
 vec2 transformWithoutTranslation(const ui::Transform& transform, const vec2& xy) {
     const vec2 transformedXy = transform.transform(xy);
     const vec2 transformedOrigin = transform.transform(0, 0);
-    return transformedXy - transformedOrigin;
+    return roundTransformedCoords(transformedXy - transformedOrigin);
 }
 
 float transformAngle(const ui::Transform& transform, float angleRadians) {
@@ -606,12 +619,12 @@
 
 float MotionEvent::getXCursorPosition() const {
     vec2 vals = mTransform.transform(getRawXCursorPosition(), getRawYCursorPosition());
-    return vals.x;
+    return roundTransformedCoords(vals.x);
 }
 
 float MotionEvent::getYCursorPosition() const {
     vec2 vals = mTransform.transform(getRawXCursorPosition(), getRawYCursorPosition());
-    return vals.y;
+    return roundTransformedCoords(vals.y);
 }
 
 void MotionEvent::setCursorPosition(float x, float y) {
@@ -933,7 +946,7 @@
 static inline vec2 calculateTransformedXYUnchecked(uint32_t source, const ui::Transform& transform,
                                                    const vec2& xy) {
     return shouldDisregardOffset(source) ? transformWithoutTranslation(transform, xy)
-                                         : transform.transform(xy);
+                                         : roundTransformedCoords(transform.transform(xy));
 }
 
 vec2 MotionEvent::calculateTransformedXY(uint32_t source, const ui::Transform& transform,