Merge changes Ia03f7e3d,Ief31910b into main
* changes:
FTL: Add Optional<T>::ok_or and FTL_TRY
FTL: Touch up Concat
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index c62fc7d..6cf5a7e 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -394,6 +394,12 @@
/* Sysfs node change reported. Recreate device if required to incorporate the new sysfs nodes */
virtual void sysfsNodeChanged(const std::string& sysfsNodePath) = 0;
+
+ /* Get the ID of the InputDevice that was used most recently.
+ *
+ * Returns ReservedInputDeviceId::INVALID_INPUT_DEVICE_ID if no device has been used since boot.
+ */
+ virtual DeviceId getLastUsedInputDeviceId() = 0;
};
// --- TouchAffineTransformation ---
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 12f52b8..69555f8 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -38,6 +38,8 @@
namespace android {
+namespace {
+
/**
* Determines if the identifiers passed are a sub-devices. Sub-devices are physical devices
* that expose multiple input device paths such a keyboard that also has a touchpad input.
@@ -49,8 +51,8 @@
* inputs versus the same device plugged into multiple ports.
*/
-static bool isSubDevice(const InputDeviceIdentifier& identifier1,
- const InputDeviceIdentifier& identifier2) {
+bool isSubDevice(const InputDeviceIdentifier& identifier1,
+ const InputDeviceIdentifier& identifier2) {
return (identifier1.vendor == identifier2.vendor &&
identifier1.product == identifier2.product && identifier1.bus == identifier2.bus &&
identifier1.version == identifier2.version &&
@@ -58,7 +60,7 @@
identifier1.location == identifier2.location);
}
-static bool isStylusPointerGestureStart(const NotifyMotionArgs& motionArgs) {
+bool isStylusPointerGestureStart(const NotifyMotionArgs& motionArgs) {
const auto actionMasked = MotionEvent::getActionMasked(motionArgs.action);
if (actionMasked != AMOTION_EVENT_ACTION_HOVER_ENTER &&
actionMasked != AMOTION_EVENT_ACTION_DOWN &&
@@ -69,6 +71,28 @@
return isStylusToolType(motionArgs.pointerProperties[actionIndex].toolType);
}
+bool isNewGestureStart(const NotifyMotionArgs& motion) {
+ return motion.action == AMOTION_EVENT_ACTION_DOWN ||
+ motion.action == AMOTION_EVENT_ACTION_HOVER_ENTER;
+}
+
+bool isNewGestureStart(const NotifyKeyArgs& key) {
+ return key.action == AKEY_EVENT_ACTION_DOWN;
+}
+
+// Return the event's device ID if it marks the start of a new gesture.
+std::optional<DeviceId> getDeviceIdOfNewGesture(const NotifyArgs& args) {
+ if (const auto* motion = std::get_if<NotifyMotionArgs>(&args); motion != nullptr) {
+ return isNewGestureStart(*motion) ? std::make_optional(motion->deviceId) : std::nullopt;
+ }
+ if (const auto* key = std::get_if<NotifyKeyArgs>(&args); key != nullptr) {
+ return isNewGestureStart(*key) ? std::make_optional(key->deviceId) : std::nullopt;
+ }
+ return std::nullopt;
+}
+
+} // namespace
+
// --- InputReader ---
InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,
@@ -162,6 +186,11 @@
}
std::swap(notifyArgs, mPendingArgs);
+
+ // Keep track of the last used device
+ for (const NotifyArgs& args : notifyArgs) {
+ mLastUsedDeviceId = getDeviceIdOfNewGesture(args).value_or(mLastUsedDeviceId);
+ }
} // release lock
// Flush queued events out to the listener.
@@ -883,6 +912,11 @@
mEventHub->sysfsNodeChanged(sysfsNodePath);
}
+DeviceId InputReader::getLastUsedInputDeviceId() {
+ std::scoped_lock _l(mLock);
+ return mLastUsedDeviceId;
+}
+
void InputReader::dump(std::string& dump) {
std::scoped_lock _l(mLock);
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index d9ac917..92a778a 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -118,6 +118,8 @@
void sysfsNodeChanged(const std::string& sysfsNodePath) override;
+ DeviceId getLastUsedInputDeviceId() override;
+
protected:
// These members are protected so they can be instrumented by test cases.
virtual std::shared_ptr<InputDevice> createDeviceLocked(nsecs_t when, int32_t deviceId,
@@ -200,6 +202,9 @@
// records timestamp of the last key press on the physical keyboard
nsecs_t mLastKeyDownTimestamp GUARDED_BY(mLock){0};
+ // The input device that produced a new gesture most recently.
+ DeviceId mLastUsedDeviceId GUARDED_BY(mLock){ReservedInputDeviceId::INVALID_INPUT_DEVICE_ID};
+
// low-level input event decoding and device management
[[nodiscard]] std::list<NotifyArgs> processEventsLocked(const RawEvent* rawEvents, size_t count)
REQUIRES(mLock);
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index a0abb61..8536ff0 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -27,6 +27,7 @@
#include <JoystickInputMapper.h>
#include <KeyboardInputMapper.h>
#include <MultiTouchInputMapper.h>
+#include <NotifyArgsBuilders.h>
#include <PeripheralController.h>
#include <SensorInputMapper.h>
#include <SingleTouchInputMapper.h>
@@ -1183,6 +1184,82 @@
mFakeListener->assertNotifyCaptureWasNotCalled();
}
+TEST_F(InputReaderTest, GetLastUsedInputDeviceId) {
+ constexpr int32_t FIRST_DEVICE_ID = END_RESERVED_ID + 1000;
+ constexpr int32_t SECOND_DEVICE_ID = FIRST_DEVICE_ID + 1;
+ FakeInputMapper& firstMapper =
+ addDeviceWithFakeInputMapper(FIRST_DEVICE_ID, FIRST_DEVICE_ID, "first",
+ InputDeviceClass::KEYBOARD, AINPUT_SOURCE_KEYBOARD,
+ /*configuration=*/nullptr);
+ FakeInputMapper& secondMapper =
+ addDeviceWithFakeInputMapper(SECOND_DEVICE_ID, SECOND_DEVICE_ID, "second",
+ InputDeviceClass::TOUCH_MT, AINPUT_SOURCE_STYLUS,
+ /*configuration=*/nullptr);
+
+ ASSERT_EQ(ReservedInputDeviceId::INVALID_INPUT_DEVICE_ID, mReader->getLastUsedInputDeviceId());
+
+ // Start a new key gesture from the first device
+ firstMapper.setProcessResult({KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
+ .deviceId(FIRST_DEVICE_ID)
+ .build()});
+ mFakeEventHub->enqueueEvent(ARBITRARY_TIME, ARBITRARY_TIME, FIRST_DEVICE_ID, 0, 0, 0);
+ mReader->loopOnce();
+ ASSERT_EQ(firstMapper.getDeviceId(), mReader->getLastUsedInputDeviceId());
+
+ // Start a new touch gesture from the second device
+ secondMapper.setProcessResult(
+ {MotionArgsBuilder(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_STYLUS)
+ .deviceId(SECOND_DEVICE_ID)
+ .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER))
+ .build()});
+ mFakeEventHub->enqueueEvent(ARBITRARY_TIME, ARBITRARY_TIME, SECOND_DEVICE_ID, 0, 0, 0);
+ mReader->loopOnce();
+ ASSERT_EQ(SECOND_DEVICE_ID, mReader->getLastUsedInputDeviceId());
+
+ // Releasing the key is not a new gesture, so it does not update the last used device
+ firstMapper.setProcessResult({KeyArgsBuilder(AKEY_EVENT_ACTION_UP, AINPUT_SOURCE_KEYBOARD)
+ .deviceId(FIRST_DEVICE_ID)
+ .build()});
+ mFakeEventHub->enqueueEvent(ARBITRARY_TIME, ARBITRARY_TIME, FIRST_DEVICE_ID, 0, 0, 0);
+ mReader->loopOnce();
+ ASSERT_EQ(SECOND_DEVICE_ID, mReader->getLastUsedInputDeviceId());
+
+ // But pressing a new key does start a new gesture
+ firstMapper.setProcessResult({KeyArgsBuilder(AKEY_EVENT_ACTION_DOWN, AINPUT_SOURCE_KEYBOARD)
+ .deviceId(FIRST_DEVICE_ID)
+ .build()});
+ mFakeEventHub->enqueueEvent(ARBITRARY_TIME, ARBITRARY_TIME, FIRST_DEVICE_ID, 0, 0, 0);
+ mReader->loopOnce();
+ ASSERT_EQ(FIRST_DEVICE_ID, mReader->getLastUsedInputDeviceId());
+
+ // Moving or ending a touch gesture does not update the last used device
+ secondMapper.setProcessResult(
+ {MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_STYLUS)
+ .deviceId(SECOND_DEVICE_ID)
+ .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS))
+ .build()});
+ mFakeEventHub->enqueueEvent(ARBITRARY_TIME, ARBITRARY_TIME, SECOND_DEVICE_ID, 0, 0, 0);
+ mReader->loopOnce();
+ ASSERT_EQ(FIRST_DEVICE_ID, mReader->getLastUsedInputDeviceId());
+ secondMapper.setProcessResult({MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_STYLUS)
+ .deviceId(SECOND_DEVICE_ID)
+ .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS))
+ .build()});
+ mFakeEventHub->enqueueEvent(ARBITRARY_TIME, ARBITRARY_TIME, SECOND_DEVICE_ID, 0, 0, 0);
+ mReader->loopOnce();
+ ASSERT_EQ(FIRST_DEVICE_ID, mReader->getLastUsedInputDeviceId());
+
+ // Starting a new hover gesture updates the last used device
+ secondMapper.setProcessResult(
+ {MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
+ .deviceId(SECOND_DEVICE_ID)
+ .pointer(PointerBuilder(/*id=*/0, ToolType::STYLUS))
+ .build()});
+ mFakeEventHub->enqueueEvent(ARBITRARY_TIME, ARBITRARY_TIME, SECOND_DEVICE_ID, 0, 0, 0);
+ mReader->loopOnce();
+ ASSERT_EQ(SECOND_DEVICE_ID, mReader->getLastUsedInputDeviceId());
+}
+
class FakeVibratorInputMapper : public FakeInputMapper {
public:
FakeVibratorInputMapper(InputDeviceContext& deviceContext,
diff --git a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
index 34ea54c..a19726a 100644
--- a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
@@ -169,6 +169,8 @@
reader->sysfsNodeChanged(sysfsNodePath);
}
+ DeviceId getLastUsedInputDeviceId() override { return reader->getLastUsedInputDeviceId(); }
+
private:
std::unique_ptr<InputReaderInterface> reader;
};