Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 58558d18 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "InputReader: Add API to get the last used input device" into main

parents 08f13b72 018faea1
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -394,6 +394,12 @@ public:

    /* 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 ---
+37 −3
Original line number Diff line number Diff line
@@ -38,6 +38,8 @@ using android::base::StringPrintf;

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,7 +51,7 @@ namespace android {
 *    inputs versus the same device plugged into multiple ports.
 */

static bool isSubDevice(const InputDeviceIdentifier& identifier1,
bool isSubDevice(const InputDeviceIdentifier& identifier1,
                 const InputDeviceIdentifier& identifier2) {
    return (identifier1.vendor == identifier2.vendor &&
            identifier1.product == identifier2.product && identifier1.bus == identifier2.bus &&
@@ -58,7 +60,7 @@ static bool isSubDevice(const InputDeviceIdentifier& identifier1,
            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 @@ static bool isStylusPointerGestureStart(const NotifyMotionArgs& motionArgs) {
    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 @@ void InputReader::loopOnce() {
        }

        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 @@ void InputReader::sysfsNodeChanged(const std::string& sysfsNodePath) {
    mEventHub->sysfsNodeChanged(sysfsNodePath);
}

DeviceId InputReader::getLastUsedInputDeviceId() {
    std::scoped_lock _l(mLock);
    return mLastUsedDeviceId;
}

void InputReader::dump(std::string& dump) {
    std::scoped_lock _l(mLock);

+5 −0
Original line number Diff line number Diff line
@@ -118,6 +118,8 @@ public:

    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 @@ private:
    // 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);
+77 −0
Original line number Diff line number Diff line
@@ -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 @@ TEST_F(InputReaderTest, ChangingPointerCaptureNotifiesInputListener) {
    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,
+2 −0
Original line number Diff line number Diff line
@@ -169,6 +169,8 @@ public:
        reader->sysfsNodeChanged(sysfsNodePath);
    }

    DeviceId getLastUsedInputDeviceId() override { return reader->getLastUsedInputDeviceId(); }

private:
    std::unique_ptr<InputReaderInterface> reader;
};