Merge "Set touch and tool resolution in TouchInputMapper"
diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h
index f1c0e5a..d83d74d 100644
--- a/services/inputflinger/reader/mapper/InputMapper.h
+++ b/services/inputflinger/reader/mapper/InputMapper.h
@@ -45,7 +45,7 @@
 
     inline int32_t getDeviceId() { return mDeviceContext.getId(); }
     inline InputDeviceContext& getDeviceContext() { return mDeviceContext; }
-    inline const std::string getDeviceName() { return mDeviceContext.getName(); }
+    inline const std::string getDeviceName() const { return mDeviceContext.getName(); }
     inline InputReaderContext* getContext() { return mDeviceContext.getContext(); }
     inline InputReaderPolicyInterface* getPolicy() { return getContext()->getPolicy(); }
     inline InputListenerInterface& getListener() { return getContext()->getListener(); }
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
index 6bdb121..ad11b05 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
@@ -32,8 +32,7 @@
 void JoystickInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
     InputMapper::populateDeviceInfo(info);
 
-    for (std::pair<const int32_t, Axis>& pair : mAxes) {
-        const Axis& axis = pair.second;
+    for (const auto& [_, axis] : mAxes) {
         addMotionRange(axis.axisInfo.axis, axis, info);
 
         if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 046323d..0a5de27 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -609,6 +609,15 @@
     return std::make_optional(newViewport);
 }
 
+int32_t TouchInputMapper::clampResolution(const char* axisName, int32_t resolution) const {
+    if (resolution < 0) {
+        ALOGE("Invalid %s resolution %" PRId32 " for device %s", axisName, resolution,
+              getDeviceName().c_str());
+        return 0;
+    }
+    return resolution;
+}
+
 void TouchInputMapper::initializeSizeRanges() {
     if (mCalibration.sizeCalibration == Calibration::SizeCalibration::NONE) {
         mSizeScale = 0.0f;
@@ -638,9 +647,19 @@
     mOrientedRanges.touchMajor.flat = 0;
     mOrientedRanges.touchMajor.fuzz = 0;
     mOrientedRanges.touchMajor.resolution = 0;
+    if (mRawPointerAxes.touchMajor.valid) {
+        mRawPointerAxes.touchMajor.resolution =
+                clampResolution("touchMajor", mRawPointerAxes.touchMajor.resolution);
+        mOrientedRanges.touchMajor.resolution = mRawPointerAxes.touchMajor.resolution;
+    }
 
     mOrientedRanges.touchMinor = mOrientedRanges.touchMajor;
     mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR;
+    if (mRawPointerAxes.touchMinor.valid) {
+        mRawPointerAxes.touchMinor.resolution =
+                clampResolution("touchMinor", mRawPointerAxes.touchMinor.resolution);
+        mOrientedRanges.touchMinor.resolution = mRawPointerAxes.touchMinor.resolution;
+    }
 
     mOrientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR;
     mOrientedRanges.toolMajor.source = mSource;
@@ -649,9 +668,31 @@
     mOrientedRanges.toolMajor.flat = 0;
     mOrientedRanges.toolMajor.fuzz = 0;
     mOrientedRanges.toolMajor.resolution = 0;
+    if (mRawPointerAxes.toolMajor.valid) {
+        mRawPointerAxes.toolMajor.resolution =
+                clampResolution("toolMajor", mRawPointerAxes.toolMajor.resolution);
+        mOrientedRanges.toolMajor.resolution = mRawPointerAxes.toolMajor.resolution;
+    }
 
     mOrientedRanges.toolMinor = mOrientedRanges.toolMajor;
     mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR;
+    if (mRawPointerAxes.toolMinor.valid) {
+        mRawPointerAxes.toolMinor.resolution =
+                clampResolution("toolMinor", mRawPointerAxes.toolMinor.resolution);
+        mOrientedRanges.toolMinor.resolution = mRawPointerAxes.toolMinor.resolution;
+    }
+
+    if (mCalibration.sizeCalibration == Calibration::SizeCalibration::GEOMETRIC) {
+        mOrientedRanges.touchMajor.resolution *= mGeometricScale;
+        mOrientedRanges.touchMinor.resolution *= mGeometricScale;
+        mOrientedRanges.toolMajor.resolution *= mGeometricScale;
+        mOrientedRanges.toolMinor.resolution *= mGeometricScale;
+    } else {
+        // Support for other calibrations can be added here.
+        ALOGW("%s calibration is not supported for size ranges at the moment. "
+              "Using raw resolution instead",
+              ftl::enum_string(mCalibration.sizeCalibration).c_str());
+    }
 
     mOrientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE;
     mOrientedRanges.size.source = mSource;
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 6f15b90..9fd30e4 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -733,6 +733,7 @@
     void resetExternalStylus();
     void clearStylusDataPendingFlags();
 
+    int32_t clampResolution(const char* axisName, int32_t resolution) const;
     void initializeOrientedRanges();
     void initializeSizeRanges();
 
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 336afc6..41ce116 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -106,6 +106,24 @@
     }
 }
 
+static void assertAxisResolution(MultiTouchInputMapper& mapper, int axis, float resolution) {
+    InputDeviceInfo info;
+    mapper.populateDeviceInfo(&info);
+
+    const InputDeviceInfo::MotionRange* motionRange =
+            info.getMotionRange(axis, AINPUT_SOURCE_TOUCHSCREEN);
+    ASSERT_NEAR(motionRange->resolution, resolution, EPSILON);
+}
+
+static void assertAxisNotPresent(MultiTouchInputMapper& mapper, int axis) {
+    InputDeviceInfo info;
+    mapper.populateDeviceInfo(&info);
+
+    const InputDeviceInfo::MotionRange* motionRange =
+            info.getMotionRange(axis, AINPUT_SOURCE_TOUCHSCREEN);
+    ASSERT_EQ(nullptr, motionRange);
+}
+
 // --- FakePointerController ---
 
 class FakePointerController : public PointerControllerInterface {
@@ -6488,7 +6506,7 @@
         mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MAJOR, RAW_TOOL_MIN, RAW_TOOL_MAX,
                                        0, 0);
         if (axes & MINOR) {
-            mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MINOR, RAW_TOOL_MAX,
+            mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MINOR, RAW_TOOL_MIN,
                                            RAW_TOOL_MAX, 0, 0);
         }
     }
@@ -6855,6 +6873,57 @@
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
 }
 
+TEST_F(MultiTouchInputMapperTest, AxisResolution_IsPopulated) {
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+
+    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, /*flat*/ 0,
+                                   /*fuzz*/ 0, /*resolution*/ 10);
+    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX, /*flat*/ 0,
+                                   /*fuzz*/ 0, /*resolution*/ 11);
+    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MAJOR, RAW_TOUCH_MIN, RAW_TOUCH_MAX,
+                                   /*flat*/ 0, /*fuzz*/ 0, /*resolution*/ 12);
+    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_TOUCH_MINOR, RAW_TOUCH_MIN, RAW_TOUCH_MAX,
+                                   /*flat*/ 0, /*fuzz*/ 0, /*resolution*/ 13);
+    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MAJOR, RAW_TOOL_MIN, RAW_TOOL_MAX,
+                                   /*flat*/ 0, /*flat*/ 0, /*resolution*/ 14);
+    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_WIDTH_MINOR, RAW_TOOL_MIN, RAW_TOOL_MAX,
+                                   /*flat*/ 0, /*flat*/ 0, /*resolution*/ 15);
+
+    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+    // X and Y axes
+    assertAxisResolution(mapper, AMOTION_EVENT_AXIS_X, 10 / X_PRECISION);
+    assertAxisResolution(mapper, AMOTION_EVENT_AXIS_Y, 11 / Y_PRECISION);
+    // Touch major and minor
+    assertAxisResolution(mapper, AMOTION_EVENT_AXIS_TOUCH_MAJOR, 12 * GEOMETRIC_SCALE);
+    assertAxisResolution(mapper, AMOTION_EVENT_AXIS_TOUCH_MINOR, 13 * GEOMETRIC_SCALE);
+    // Tool major and minor
+    assertAxisResolution(mapper, AMOTION_EVENT_AXIS_TOOL_MAJOR, 14 * GEOMETRIC_SCALE);
+    assertAxisResolution(mapper, AMOTION_EVENT_AXIS_TOOL_MINOR, 15 * GEOMETRIC_SCALE);
+}
+
+TEST_F(MultiTouchInputMapperTest, TouchMajorAndMinorAxes_DoNotAppearIfNotSupported) {
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+
+    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, /*flat*/ 0,
+                                   /*fuzz*/ 0, /*resolution*/ 10);
+    mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX, /*flat*/ 0,
+                                   /*fuzz*/ 0, /*resolution*/ 11);
+
+    // We do not add ABS_MT_TOUCH_MAJOR / MINOR or ABS_MT_WIDTH_MAJOR / MINOR axes
+
+    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+    // Touch major and minor
+    assertAxisNotPresent(mapper, AMOTION_EVENT_AXIS_TOUCH_MAJOR);
+    assertAxisNotPresent(mapper, AMOTION_EVENT_AXIS_TOUCH_MINOR);
+    // Tool major and minor
+    assertAxisNotPresent(mapper, AMOTION_EVENT_AXIS_TOOL_MAJOR);
+    assertAxisNotPresent(mapper, AMOTION_EVENT_AXIS_TOOL_MINOR);
+}
+
 TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingIds) {
     addConfigurationProperty("touch.deviceType", "touchScreen");
     prepareDisplay(DISPLAY_ORIENTATION_0);