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;
 };