Merge "Update TouchInputMapper to support new VirtualNavigationTouchpad."
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index b8a6dad..3e4db43 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -191,6 +191,9 @@
         // The set of disabled input devices (disabledDevices) has changed.
         CHANGE_ENABLED_STATE = 1 << 9,
 
+        // The device type has been updated.
+        CHANGE_DEVICE_TYPE = 1 << 10,
+
         // All devices must be reopened.
         CHANGE_MUST_REOPEN = 1 << 31,
     };
@@ -212,6 +215,10 @@
     // Used to determine which DisplayViewport should be tied to which InputDevice.
     std::unordered_map<std::string, std::string> uniqueIdAssociations;
 
+    // The associations between input device ports device types.
+    // This is used to determine which device type and source should be tied to which InputDevice.
+    std::unordered_map<std::string, std::string> deviceTypeAssociations;
+
     // The suggested display ID to show the cursor.
     int32_t defaultPointerDisplayId;
 
@@ -326,7 +333,6 @@
     std::optional<DisplayViewport> getDisplayViewportById(int32_t displayId) const;
     void setDisplayViewports(const std::vector<DisplayViewport>& viewports);
 
-
     void dump(std::string& dump) const;
     void dumpViewport(std::string& dump, const DisplayViewport& viewport) const;
 
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 11b5209..6dfe5f5 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -56,6 +56,16 @@
 
 InputDevice::~InputDevice() {}
 
+template <typename K, typename V>
+std::optional<V> getValueByKey(const std::unordered_map<K, V>& map, K key) {
+    auto it = map.find(key);
+    std::optional<V> value = std::nullopt;
+    if (it != map.end()) {
+        value = it->second;
+    }
+    return value;
+}
+
 bool InputDevice::isEnabled() {
     if (!hasEventHubDevices()) {
         return false;
@@ -291,6 +301,9 @@
                 context.getConfiguration(&configuration);
                 mConfiguration.addAll(&configuration);
             });
+
+            mAssociatedDeviceType =
+                    getValueByKey(config->deviceTypeAssociations, mIdentifier.location);
         }
 
         if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) {
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 6fa21e5..af59fe2 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -65,6 +65,9 @@
     inline std::optional<std::string> getAssociatedDisplayUniqueId() const {
         return mAssociatedDisplayUniqueId;
     }
+    inline std::optional<std::string> getDeviceTypeAssociation() const {
+        return mAssociatedDeviceType;
+    }
     inline std::optional<DisplayViewport> getAssociatedViewport() const {
         return mAssociatedViewport;
     }
@@ -180,6 +183,7 @@
     bool mIsExternal;
     std::optional<uint8_t> mAssociatedDisplayPort;
     std::optional<std::string> mAssociatedDisplayUniqueId;
+    std::optional<std::string> mAssociatedDeviceType;
     std::optional<DisplayViewport> mAssociatedViewport;
     bool mHasMic;
     bool mDropUntilNextSync;
@@ -408,6 +412,9 @@
     inline std::optional<std::string> getAssociatedDisplayUniqueId() const {
         return mDevice.getAssociatedDisplayUniqueId();
     }
+    inline std::optional<std::string> getDeviceTypeAssociation() const {
+        return mDevice.getDeviceTypeAssociation();
+    }
     inline std::optional<DisplayViewport> getAssociatedViewport() const {
         return mDevice.getAssociatedViewport();
     }
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index cefc44e..160f9eb 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -392,33 +392,10 @@
         }
     }
 
-    if (getDeviceContext().hasInputProperty(INPUT_PROP_DIRECT)) {
-        // The device is a touch screen.
-        mParameters.deviceType = Parameters::DeviceType::TOUCH_SCREEN;
-    } else if (getDeviceContext().hasInputProperty(INPUT_PROP_POINTER)) {
-        // The device is a pointing device like a track pad.
-        mParameters.deviceType = Parameters::DeviceType::POINTER;
-    } else {
-        // The device is a touch pad of unknown purpose.
-        mParameters.deviceType = Parameters::DeviceType::POINTER;
-    }
+    configureDeviceType();
 
     mParameters.hasButtonUnderPad = getDeviceContext().hasInputProperty(INPUT_PROP_BUTTONPAD);
 
-    std::string deviceTypeString;
-    if (getDeviceContext().getConfiguration().tryGetProperty("touch.deviceType",
-                                                             deviceTypeString)) {
-        if (deviceTypeString == "touchScreen") {
-            mParameters.deviceType = Parameters::DeviceType::TOUCH_SCREEN;
-        } else if (deviceTypeString == "touchNavigation") {
-            mParameters.deviceType = Parameters::DeviceType::TOUCH_NAVIGATION;
-        } else if (deviceTypeString == "pointer") {
-            mParameters.deviceType = Parameters::DeviceType::POINTER;
-        } else if (deviceTypeString != "default") {
-            ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.c_str());
-        }
-    }
-
     mParameters.orientationAware = mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN;
     getDeviceContext().getConfiguration().tryGetProperty("touch.orientationAware",
                                                          mParameters.orientationAware);
@@ -444,7 +421,9 @@
     mParameters.associatedDisplayIsExternal = false;
     if (mParameters.orientationAware ||
         mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN ||
-        mParameters.deviceType == Parameters::DeviceType::POINTER) {
+        mParameters.deviceType == Parameters::DeviceType::POINTER ||
+        (mParameters.deviceType == Parameters::DeviceType::TOUCH_NAVIGATION &&
+         getDeviceContext().getAssociatedViewport())) {
         mParameters.hasAssociatedDisplay = true;
         if (mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN) {
             mParameters.associatedDisplayIsExternal = getDeviceContext().isExternal();
@@ -473,6 +452,34 @@
                                                          mParameters.enableForInactiveViewport);
 }
 
+void TouchInputMapper::configureDeviceType() {
+    if (getDeviceContext().hasInputProperty(INPUT_PROP_DIRECT)) {
+        // The device is a touch screen.
+        mParameters.deviceType = Parameters::DeviceType::TOUCH_SCREEN;
+    } else if (getDeviceContext().hasInputProperty(INPUT_PROP_POINTER)) {
+        // The device is a pointing device like a track pad.
+        mParameters.deviceType = Parameters::DeviceType::POINTER;
+    } else {
+        // The device is a touch pad of unknown purpose.
+        mParameters.deviceType = Parameters::DeviceType::POINTER;
+    }
+
+    // Type association takes precedence over the device type found in the idc file.
+    std::string deviceTypeString = getDeviceContext().getDeviceTypeAssociation().value_or("");
+    if (deviceTypeString.empty()) {
+        getDeviceContext().getConfiguration().tryGetProperty("touch.deviceType", deviceTypeString);
+    }
+    if (deviceTypeString == "touchScreen") {
+        mParameters.deviceType = Parameters::DeviceType::TOUCH_SCREEN;
+    } else if (deviceTypeString == "touchNavigation") {
+        mParameters.deviceType = Parameters::DeviceType::TOUCH_NAVIGATION;
+    } else if (deviceTypeString == "pointer") {
+        mParameters.deviceType = Parameters::DeviceType::POINTER;
+    } else if (deviceTypeString != "default" && deviceTypeString != "") {
+        ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.c_str());
+    }
+}
+
 void TouchInputMapper::dumpParameters(std::string& dump) {
     dump += INDENT3 "Parameters:\n";
 
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 34ba625..50a7ea3 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -814,6 +814,8 @@
     static void assignPointerIds(const RawState& last, RawState& current);
 
     void rotateAndScale(float& x, float& y) const;
+
+    void configureDeviceType();
 };
 
 } // namespace android
diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.cpp b/services/inputflinger/tests/FakeInputReaderPolicy.cpp
index 3af4298..dc7e581 100644
--- a/services/inputflinger/tests/FakeInputReaderPolicy.cpp
+++ b/services/inputflinger/tests/FakeInputReaderPolicy.cpp
@@ -126,6 +126,11 @@
     mConfig.portAssociations.insert({inputPort, displayPort});
 }
 
+void FakeInputReaderPolicy::addDeviceTypeAssociation(const std::string& inputPort,
+                                                     const std::string& type) {
+    mConfig.deviceTypeAssociations.insert({inputPort, type});
+}
+
 void FakeInputReaderPolicy::addInputUniqueIdAssociation(const std::string& inputUniqueId,
                                                         const std::string& displayUniqueId) {
     mConfig.uniqueIdAssociations.insert({inputUniqueId, displayUniqueId});
diff --git a/services/inputflinger/tests/FakeInputReaderPolicy.h b/services/inputflinger/tests/FakeInputReaderPolicy.h
index c16cda4..faa9c01 100644
--- a/services/inputflinger/tests/FakeInputReaderPolicy.h
+++ b/services/inputflinger/tests/FakeInputReaderPolicy.h
@@ -55,6 +55,7 @@
     bool updateViewport(const DisplayViewport& viewport);
     void addExcludedDeviceName(const std::string& deviceName);
     void addInputPortAssociation(const std::string& inputPort, uint8_t displayPort);
+    void addDeviceTypeAssociation(const std::string& inputPort, const std::string& type);
     void addInputUniqueIdAssociation(const std::string& inputUniqueId,
                                      const std::string& displayUniqueId);
     void addDisabledDevice(int32_t deviceId);
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 4cc48f6..3516092 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -6505,6 +6505,17 @@
                   WithCoords(toDisplayX(100), toDisplayY(200)), WithButtonState(0))));
 }
 
+TEST_F(SingleTouchInputMapperTest, WhenDeviceTypeIsSetToTouchNavigation_setsCorrectType) {
+    mFakePolicy->addDeviceTypeAssociation(DEVICE_LOCATION, "touchNavigation");
+    prepareDisplay(ui::ROTATION_0);
+    prepareButtons();
+    prepareAxes(POSITION);
+    SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled());
+
+    ASSERT_EQ(AINPUT_SOURCE_TOUCH_NAVIGATION, mapper.getSources());
+}
+
 // --- TouchDisplayProjectionTest ---
 
 class TouchDisplayProjectionTest : public SingleTouchInputMapperTest {