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

Commit 2141d54f authored by Arthur Hung's avatar Arthur Hung
Browse files

Synthesize cancellation events when device is disabled

When disable a keyboard device, if some keys still stay in down, we
should synthesize the cancellation events for these keys to prevent the
states can't be reset when they're handled by policy or client side.

Bug: 239888702
Test: atest inputflinger_tests
Change-Id: I8d73d5b2b3df81d047799cb7e9403f170a094f97
parent 5b9a2716
Loading
Loading
Loading
Loading
+20 −8
Original line number Diff line number Diff line
@@ -127,7 +127,6 @@ void KeyboardInputMapper::dump(std::string& dump) {
    dump += StringPrintf(INDENT3 "Orientation: %d\n", getOrientation());
    dump += StringPrintf(INDENT3 "KeyDowns: %zu keys currently down\n", mKeyDowns.size());
    dump += StringPrintf(INDENT3 "MetaState: 0x%0x\n", mMetaState);
    dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime);
}

std::optional<DisplayViewport> KeyboardInputMapper::findViewport(
@@ -196,9 +195,7 @@ void KeyboardInputMapper::dumpParameters(std::string& dump) {
}

void KeyboardInputMapper::reset(nsecs_t when) {
    mMetaState = AMETA_NONE;
    mDownTime = 0;
    mKeyDowns.clear();
    cancelAllDownKeys(when);
    mCurrentHidUsage = 0;

    resetLedState();
@@ -281,6 +278,7 @@ void KeyboardInputMapper::processKey(nsecs_t when, nsecs_t readTime, bool down,
        policyFlags = 0;
    }

    nsecs_t downTime = when;
    if (down) {
        // Rotate key codes according to orientation if needed.
        if (mParameters.orientationAware) {
@@ -292,6 +290,7 @@ void KeyboardInputMapper::processKey(nsecs_t when, nsecs_t readTime, bool down,
        if (keyDownIndex >= 0) {
            // key repeat, be sure to use same keycode as before in case of rotation
            keyCode = mKeyDowns[keyDownIndex].keyCode;
            downTime = mKeyDowns[keyDownIndex].downTime;
        } else {
            // key down
            if ((policyFlags & POLICY_FLAG_VIRTUAL) &&
@@ -305,16 +304,16 @@ void KeyboardInputMapper::processKey(nsecs_t when, nsecs_t readTime, bool down,
            KeyDown keyDown;
            keyDown.keyCode = keyCode;
            keyDown.scanCode = scanCode;
            keyDown.downTime = when;
            mKeyDowns.push_back(keyDown);
        }

        mDownTime = when;
    } else {
        // Remove key down.
        ssize_t keyDownIndex = findKeyDown(scanCode);
        if (keyDownIndex >= 0) {
            // key up, be sure to use same keycode as before in case of rotation
            keyCode = mKeyDowns[keyDownIndex].keyCode;
            downTime = mKeyDowns[keyDownIndex].downTime;
            mKeyDowns.erase(mKeyDowns.begin() + (size_t)keyDownIndex);
        } else {
            // key was not actually down
@@ -333,8 +332,6 @@ void KeyboardInputMapper::processKey(nsecs_t when, nsecs_t readTime, bool down,
        keyMetaState = mMetaState;
    }

    nsecs_t downTime = mDownTime;

    // Key down on external an keyboard should wake the device.
    // We don't do this for internal keyboards to prevent them from waking up in your pocket.
    // For internal keyboards and devices for which the default wake behavior is explicitly
@@ -473,4 +470,19 @@ std::optional<int32_t> KeyboardInputMapper::getAssociatedDisplayId() {
    return std::nullopt;
}

void KeyboardInputMapper::cancelAllDownKeys(nsecs_t when) {
    size_t n = mKeyDowns.size();
    for (size_t i = 0; i < n; i++) {
        NotifyKeyArgs args(getContext()->getNextId(), when, systemTime(SYSTEM_TIME_MONOTONIC),
                           getDeviceId(), mSource, getDisplayId(), 0 /*policyFlags*/,
                           AKEY_EVENT_ACTION_UP,
                           AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_CANCELED,
                           mKeyDowns[i].keyCode, mKeyDowns[i].scanCode, AMETA_NONE,
                           mKeyDowns[i].downTime);
        getListener().notifyKey(&args);
    }
    mKeyDowns.clear();
    mMetaState = AMETA_NONE;
}

} // namespace android
+2 −1
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ private:
    std::optional<DisplayViewport> mViewport;

    struct KeyDown {
        nsecs_t downTime;
        int32_t keyCode;
        int32_t scanCode;
    };
@@ -59,7 +60,6 @@ private:

    std::vector<KeyDown> mKeyDowns; // keys that are down
    int32_t mMetaState;
    nsecs_t mDownTime; // time of most recent key down

    int32_t mCurrentHidUsage; // most recent HID usage seen this packet, or 0 if none

@@ -98,6 +98,7 @@ private:
    void updateLedStateForModifier(LedState& ledState, int32_t led, int32_t modifier, bool reset);
    std::optional<DisplayViewport> findViewport(nsecs_t when,
                                                const InputReaderConfiguration* config);
    void cancelAllDownKeys(nsecs_t when);
};

} // namespace android
+31 −0
Original line number Diff line number Diff line
@@ -4088,6 +4088,37 @@ TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleInMultiDevices) {
    ASSERT_EQ(AMETA_NONE, mapper2.getMetaState());
}

TEST_F(KeyboardInputMapperTest, Process_DisabledDevice) {
    const int32_t USAGE_A = 0x070004;
    mFakeEventHub->addKey(EVENTHUB_ID, KEY_HOME, 0, AKEYCODE_HOME, POLICY_FLAG_WAKE);
    mFakeEventHub->addKey(EVENTHUB_ID, 0, USAGE_A, AKEYCODE_A, POLICY_FLAG_WAKE);

    KeyboardInputMapper& mapper =
            addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
    // Key down by scan code.
    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_HOME, 1);
    NotifyKeyArgs args;
    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
    ASSERT_EQ(DEVICE_ID, args.deviceId);
    ASSERT_EQ(AINPUT_SOURCE_KEYBOARD, args.source);
    ASSERT_EQ(ARBITRARY_TIME, args.eventTime);
    ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
    ASSERT_EQ(AKEYCODE_HOME, args.keyCode);
    ASSERT_EQ(KEY_HOME, args.scanCode);
    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, args.flags);

    // Disable device, it should synthesize cancellation events for down events.
    mFakePolicy->addDisabledDevice(DEVICE_ID);
    configureDevice(InputReaderConfiguration::CHANGE_ENABLED_STATE);

    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
    ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
    ASSERT_EQ(AKEYCODE_HOME, args.keyCode);
    ASSERT_EQ(KEY_HOME, args.scanCode);
    ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_CANCELED, args.flags);
}

// --- KeyboardInputMapperTest_ExternalDevice ---

class KeyboardInputMapperTest_ExternalDevice : public InputMapperTest {