Update TouchInputMapper to support new VirtualNavigationTouchpad.
This change propagates type associations to InputDevice.cpp. The type associations are used there to define the device type for touch input mapper to use. This is required because of the virtual nature of the navigation touchpad the implementation can't rely on idc files.
Design doc: http://go/virtual-touchpad
Test: atest cts/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualNavigationTouchpadTest
Test: atest frameworks/native/services/inputflinger/tests/InputReader_test.cpp
Bug: 252767726
Change-Id: Ia4252460c16deb093d61b059e5030d902a4c9a2c
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 {