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

Commit db24d7e3 authored by Kenneth Albanowski's avatar Kenneth Albanowski Committed by Android (Google) Code Review
Browse files

Merge "InputReader: prevent merging pointer sub-devices" into main

parents 398819ea 3a96aed8
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -255,3 +255,12 @@ flag {
  bug: "277261245"
}

flag {
  name: "prevent_merging_input_pointer_devices"
  namespace: "desktop_input"
  description: "Prevent merging input sub-devices that provide pointer input streams"
  bug: "389689566"
  metadata {
    purpose: PURPOSE_BUGFIX
  }
}
+34 −7
Original line number Diff line number Diff line
@@ -62,6 +62,28 @@ bool isSubDevice(const InputDeviceIdentifier& identifier1,
            identifier1.location == identifier2.location);
}

/**
 * Determines if the device classes passed for two devices represent incompatible combinations
 * that should not be merged into into a single InputDevice.
 */

bool isCompatibleSubDevice(ftl::Flags<InputDeviceClass> classes1,
                           ftl::Flags<InputDeviceClass> classes2) {
    if (!com::android::input::flags::prevent_merging_input_pointer_devices()) {
        return true;
    }

    const ftl::Flags<InputDeviceClass> pointerFlags =
            ftl::Flags<InputDeviceClass>{InputDeviceClass::TOUCH, InputDeviceClass::TOUCH_MT,
                                         InputDeviceClass::CURSOR, InputDeviceClass::TOUCHPAD};

    // Do not merge devices that both have any type of pointer event.
    if (classes1.any(pointerFlags) && classes2.any(pointerFlags)) return false;

    // Safe to merge
    return true;
}

bool isStylusPointerGestureStart(const NotifyMotionArgs& motionArgs) {
    const auto actionMasked = MotionEvent::getActionMasked(motionArgs.action);
    if (actionMasked != AMOTION_EVENT_ACTION_HOVER_ENTER &&
@@ -271,7 +293,8 @@ void InputReader::addDeviceLocked(nsecs_t when, int32_t eventHubId) {
    }

    InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(eventHubId);
    std::shared_ptr<InputDevice> device = createDeviceLocked(when, eventHubId, identifier);
    ftl::Flags<InputDeviceClass> classes = mEventHub->getDeviceClasses(eventHubId);
    std::shared_ptr<InputDevice> device = createDeviceLocked(when, eventHubId, identifier, classes);

    mPendingArgs += device->configure(when, mConfig, /*changes=*/{});
    mPendingArgs += device->reset(when);
@@ -354,11 +377,15 @@ void InputReader::removeDeviceLocked(nsecs_t when, int32_t eventHubId) {
}

std::shared_ptr<InputDevice> InputReader::createDeviceLocked(
        nsecs_t when, int32_t eventHubId, const InputDeviceIdentifier& identifier) {
    auto deviceIt = std::find_if(mDevices.begin(), mDevices.end(), [identifier](auto& devicePair) {
        nsecs_t when, int32_t eventHubId, const InputDeviceIdentifier& identifier,
        ftl::Flags<InputDeviceClass> classes) {
    auto deviceIt =
            std::find_if(mDevices.begin(), mDevices.end(), [identifier, classes](auto& devicePair) {
                const InputDeviceIdentifier identifier2 =
                        devicePair.second->getDeviceInfo().getIdentifier();
        return isSubDevice(identifier, identifier2);
                const ftl::Flags<InputDeviceClass> classes2 = devicePair.second->getClasses();
                return isSubDevice(identifier, identifier2) &&
                        isCompatibleSubDevice(classes, classes2);
            });

    std::shared_ptr<InputDevice> device;
+3 −1
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <vector>

#include "EventHub.h"
#include "InputDevice.h"
#include "InputListener.h"
#include "InputReaderBase.h"
#include "InputReaderContext.h"
@@ -127,7 +128,8 @@ public:
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,
                                                            const InputDeviceIdentifier& identifier)
                                                            const InputDeviceIdentifier& identifier,
                                                            ftl::Flags<InputDeviceClass> classes)
            REQUIRES(mLock);

    // With each iteration of the loop, InputReader reads and processes one incoming message from
+62 −0
Original line number Diff line number Diff line
@@ -1405,6 +1405,68 @@ TEST_F(InputReaderTest, SetPowerWakeUp) {
    ASSERT_EQ(mFakeEventHub->fakeReadKernelWakeup(3), false);
}

TEST_F(InputReaderTest, MergeableInputDevices) {
    constexpr int32_t eventHubIds[2] = {END_RESERVED_ID, END_RESERVED_ID + 1};

    // By default, all of the default-created eventhub devices will have the same identifier
    // (implicitly vid 0, pid 0, etc.), which is why we expect them to be merged.
    ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[0], "1st", InputDeviceClass::KEYBOARD, nullptr));
    ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[1], "2nd", InputDeviceClass::JOYSTICK, nullptr));

    // The two devices will be merged to one input device as they have same identifier, and none are
    // pointer devices.
    ASSERT_EQ(1U, mFakePolicy->getInputDevices().size());
}

TEST_F(InputReaderTest, MergeableDevicesWithTouch) {
    constexpr int32_t eventHubIds[3] = {END_RESERVED_ID, END_RESERVED_ID + 1, END_RESERVED_ID + 2};

    // By default, all of the default-created eventhub devices will have the same identifier
    // (implicitly vid 0, pid 0, etc.), which is why we expect them to be merged.
    ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[0], "1st", InputDeviceClass::TOUCH_MT, nullptr));
    ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[1], "2nd", InputDeviceClass::KEYBOARD, nullptr));
    ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[2], "3rd", InputDeviceClass::GAMEPAD, nullptr));

    // The three devices will be merged to one input device as they have same identifier, and only
    // one is a pointer device.
    ASSERT_EQ(1U, mFakePolicy->getInputDevices().size());
}

TEST_F(InputReaderTest, UnmergeableTouchDevices) {
    SCOPED_FLAG_OVERRIDE(prevent_merging_input_pointer_devices, true);

    constexpr int32_t eventHubIds[3] = {END_RESERVED_ID, END_RESERVED_ID + 1, END_RESERVED_ID + 2};

    // By default, all of the default-created eventhub devices will have the same identifier
    // (implicitly vid 0, pid 0, etc.), which is why they can potentially be merged.
    ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[0], "1st", InputDeviceClass::TOUCH, nullptr));
    ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[1], "2nd", InputDeviceClass::TOUCH_MT, nullptr));
    ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[2], "2nd", InputDeviceClass::CURSOR, nullptr));

    // The three devices will not be merged, as they have same identifier, but are all pointer
    // devices.
    ASSERT_EQ(3U, mFakePolicy->getInputDevices().size());
}

TEST_F(InputReaderTest, MergeableMixedDevices) {
    SCOPED_FLAG_OVERRIDE(prevent_merging_input_pointer_devices, true);

    constexpr int32_t eventHubIds[4] = {END_RESERVED_ID, END_RESERVED_ID + 1, END_RESERVED_ID + 2,
                                        END_RESERVED_ID + 3};

    // By default, all of the default-created eventhub devices will have the same identifier
    // (implicitly vid 0, pid 0, etc.), which is why they can potentially be merged.
    ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[0], "1st", InputDeviceClass::TOUCH, nullptr));
    ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[1], "2nd", InputDeviceClass::TOUCH_MT, nullptr));
    ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[2], "3rd", InputDeviceClass::DPAD, nullptr));
    ASSERT_NO_FATAL_FAILURE(addDevice(eventHubIds[3], "4th", InputDeviceClass::JOYSTICK, nullptr));

    // Non-touch devices can be merged with one of the touch devices, as they have same identifier,
    // but the two touch devices will not combine with each other. It is not specified which touch
    // device the non-touch devices merge with.
    ASSERT_EQ(2U, mFakePolicy->getInputDevices().size());
}

// --- InputReaderIntegrationTest ---

// These tests create and interact with the InputReader only through its interface.
+3 −2
Original line number Diff line number Diff line
@@ -38,13 +38,14 @@ std::shared_ptr<InputDevice> InstrumentedInputReader::newDevice(int32_t deviceId
}

std::shared_ptr<InputDevice> InstrumentedInputReader::createDeviceLocked(
        nsecs_t when, int32_t eventHubId, const InputDeviceIdentifier& identifier) REQUIRES(mLock) {
        nsecs_t when, int32_t eventHubId, const InputDeviceIdentifier& identifier,
        ftl::Flags<InputDeviceClass> classes) REQUIRES(mLock) {
    if (!mNextDevices.empty()) {
        std::shared_ptr<InputDevice> device(std::move(mNextDevices.front()));
        mNextDevices.pop();
        return device;
    }
    return InputReader::createDeviceLocked(when, eventHubId, identifier);
    return InputReader::createDeviceLocked(when, eventHubId, identifier, classes);
}

} // namespace android
Loading