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

Commit 983e76b2 authored by Vaibhav Devmurari's avatar Vaibhav Devmurari
Browse files

Support bounce and slow keys for internal Alphabetic keyboards

Test: atest --host libinputflinger_rs_test
Bug: 294546335
Flag: EXEMPT bugfix
Change-Id: I590e9494f1bab562ac2b3c085781f05f2c250314
parent faff77d5
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -24,7 +24,8 @@ mod keyboard_classifier;

pub use data_store::{DataStore, DefaultFileReaderWriter};
pub use input::{
    DeviceClass, DeviceId, InputDevice, ModifierState, MotionAction, MotionFlags, Source,
    DeviceClass, DeviceId, InputDevice, KeyboardType, ModifierState, MotionAction, MotionFlags,
    Source,
};
pub use input_verifier::InputVerifier;
pub use keyboard_classifier::KeyboardClassifier;
+1 −0
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ void InputFilter::notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs&
        AidlDeviceInfo& aidlInfo = mDeviceInfos.emplace_back();
        aidlInfo.deviceId = info.getId();
        aidlInfo.external = info.isExternal();
        aidlInfo.keyboardType = info.getKeyboardType();
    }
    if (isFilterEnabled()) {
        LOG_ALWAYS_FATAL_IF(!mInputFilterRust->notifyInputDevicesChanged(mDeviceInfos).isOk());
+1 −0
Original line number Diff line number Diff line
@@ -23,4 +23,5 @@ package com.android.server.inputflinger;
parcelable DeviceInfo {
    int deviceId;
    boolean external;
    int keyboardType;
}
 No newline at end of file
+138 −13
Original line number Diff line number Diff line
@@ -17,12 +17,13 @@
//! Bounce keys input filter implementation.
//! Bounce keys is an accessibility feature to aid users who have physical disabilities, that
//! allows the user to configure the device to ignore rapid, repeated key presses of the same key.
use crate::input_filter::Filter;
use crate::input_filter::{Filter, VIRTUAL_KEYBOARD_DEVICE_ID};

use android_hardware_input_common::aidl::android::hardware::input::common::Source::Source;
use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{
    DeviceInfo::DeviceInfo, KeyEvent::KeyEvent, KeyEventAction::KeyEventAction,
};
use input::KeyboardType;
use log::debug;
use std::collections::{HashMap, HashSet};

@@ -42,7 +43,7 @@ pub struct BounceKeysFilter {
    next: Box<dyn Filter + Send + Sync>,
    key_event_map: HashMap<i32, LastUpKeyEvent>,
    blocked_events: Vec<BlockedEvent>,
    external_devices: HashSet<i32>,
    supported_devices: HashSet<i32>,
    bounce_key_threshold_ns: i64,
}

@@ -56,7 +57,7 @@ impl BounceKeysFilter {
            next,
            key_event_map: HashMap::new(),
            blocked_events: Vec::new(),
            external_devices: HashSet::new(),
            supported_devices: HashSet::new(),
            bounce_key_threshold_ns,
        }
    }
@@ -64,7 +65,7 @@ impl BounceKeysFilter {

impl Filter for BounceKeysFilter {
    fn notify_key(&mut self, event: &KeyEvent) {
        if !(self.external_devices.contains(&event.deviceId) && event.source == Source::KEYBOARD) {
        if !(self.supported_devices.contains(&event.deviceId) && event.source == Source::KEYBOARD) {
            self.next.notify_key(event);
            return;
        }
@@ -110,10 +111,17 @@ impl Filter for BounceKeysFilter {
        self.blocked_events.retain(|blocked_event| {
            device_infos.iter().any(|x| blocked_event.device_id == x.deviceId)
        });
        self.external_devices.clear();
        self.supported_devices.clear();
        for device_info in device_infos {
            if device_info.external {
                self.external_devices.insert(device_info.deviceId);
            if device_info.deviceId == VIRTUAL_KEYBOARD_DEVICE_ID {
                continue;
            }
            if device_info.keyboardType == KeyboardType::None as i32 {
                continue;
            }
            // Support Alphabetic keyboards and Non-alphabetic external keyboards
            if device_info.external || device_info.keyboardType == KeyboardType::Alphabetic as i32 {
                self.supported_devices.insert(device_info.deviceId);
            }
        }
        self.next.notify_devices_changed(device_infos);
@@ -127,11 +135,12 @@ impl Filter for BounceKeysFilter {
#[cfg(test)]
mod tests {
    use crate::bounce_keys_filter::BounceKeysFilter;
    use crate::input_filter::{test_filter::TestFilter, Filter};
    use crate::input_filter::{test_filter::TestFilter, Filter, VIRTUAL_KEYBOARD_DEVICE_ID};
    use android_hardware_input_common::aidl::android::hardware::input::common::Source::Source;
    use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{
        DeviceInfo::DeviceInfo, KeyEvent::KeyEvent, KeyEventAction::KeyEventAction,
    };
    use input::KeyboardType;

    static BASE_KEY_EVENT: KeyEvent = KeyEvent {
        id: 1,
@@ -156,6 +165,7 @@ mod tests {
            Box::new(next.clone()),
            1,   /* device_id */
            100, /* threshold */
            KeyboardType::Alphabetic,
        );

        let event = KeyEvent { action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
@@ -181,12 +191,68 @@ mod tests {
    }

    #[test]
    fn test_is_notify_key_doesnt_block_for_internal_keyboard() {
    fn test_is_notify_key_blocks_for_internal_keyboard() {
        let mut next = TestFilter::new();
        let mut filter = setup_filter_with_internal_device(
            Box::new(next.clone()),
            1,   /* device_id */
            100, /* threshold */
            KeyboardType::Alphabetic,
        );

        let event = KeyEvent { action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
        filter.notify_key(&event);
        assert_eq!(next.last_event().unwrap(), event);

        let event = KeyEvent { action: KeyEventAction::UP, ..BASE_KEY_EVENT };
        filter.notify_key(&event);
        assert_eq!(next.last_event().unwrap(), event);

        next.clear();
        let event = KeyEvent { action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
        filter.notify_key(&event);
        assert!(next.last_event().is_none());

        let event = KeyEvent { eventTime: 100, action: KeyEventAction::UP, ..BASE_KEY_EVENT };
        filter.notify_key(&event);
        assert!(next.last_event().is_none());

        let event = KeyEvent { eventTime: 200, action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
        filter.notify_key(&event);
        assert_eq!(next.last_event().unwrap(), event);
    }

    #[test]
    fn test_is_notify_key_doesnt_block_for_internal_non_alphabetic_keyboard() {
        let next = TestFilter::new();
        let mut filter = setup_filter_with_internal_device(
            Box::new(next.clone()),
            1,   /* device_id */
            100, /* threshold */
            KeyboardType::NonAlphabetic,
        );

        let event = KeyEvent { action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
        filter.notify_key(&event);
        assert_eq!(next.last_event().unwrap(), event);

        let event = KeyEvent { action: KeyEventAction::UP, ..BASE_KEY_EVENT };
        filter.notify_key(&event);
        assert_eq!(next.last_event().unwrap(), event);

        let event = KeyEvent { action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
        filter.notify_key(&event);
        assert_eq!(next.last_event().unwrap(), event);
    }

    #[test]
    fn test_is_notify_key_doesnt_block_for_virtual_keyboard() {
        let next = TestFilter::new();
        let mut filter = setup_filter_with_internal_device(
            Box::new(next.clone()),
            VIRTUAL_KEYBOARD_DEVICE_ID, /* device_id */
            100,                        /* threshold */
            KeyboardType::Alphabetic,
        );

        let event = KeyEvent { action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
@@ -209,6 +275,7 @@ mod tests {
            Box::new(next.clone()),
            1,   /* device_id */
            100, /* threshold */
            KeyboardType::NonAlphabetic,
        );

        let event =
@@ -233,12 +300,60 @@ mod tests {
        let mut filter = setup_filter_with_devices(
            Box::new(next.clone()),
            &[
                DeviceInfo { deviceId: 1, external: true },
                DeviceInfo { deviceId: 2, external: true },
                DeviceInfo {
                    deviceId: 1,
                    external: true,
                    keyboardType: KeyboardType::Alphabetic as i32,
                },
                DeviceInfo {
                    deviceId: 2,
                    external: true,
                    keyboardType: KeyboardType::Alphabetic as i32,
                },
            ],
            100, /* threshold */
        );

        // Bounce key scenario on the external keyboard
        let event = KeyEvent { deviceId: 1, action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
        filter.notify_key(&event);
        assert_eq!(next.last_event().unwrap(), event);

        let event = KeyEvent { deviceId: 1, action: KeyEventAction::UP, ..BASE_KEY_EVENT };
        filter.notify_key(&event);
        assert_eq!(next.last_event().unwrap(), event);

        next.clear();
        let event = KeyEvent { deviceId: 1, action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
        filter.notify_key(&event);
        assert!(next.last_event().is_none());

        let event = KeyEvent { deviceId: 2, action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
        filter.notify_key(&event);
        assert_eq!(next.last_event().unwrap(), event);
    }

    #[test]
    fn test_is_notify_key_for_external_and_internal_alphabetic_keyboards() {
        let mut next = TestFilter::new();
        let mut filter = setup_filter_with_devices(
            Box::new(next.clone()),
            &[
                DeviceInfo {
                    deviceId: 1,
                    external: false,
                    keyboardType: KeyboardType::Alphabetic as i32,
                },
                DeviceInfo {
                    deviceId: 2,
                    external: true,
                    keyboardType: KeyboardType::Alphabetic as i32,
                },
            ],
            100, /* threshold */
        );

        // Bounce key scenario on the internal keyboard
        let event = KeyEvent { deviceId: 1, action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
        filter.notify_key(&event);
        assert_eq!(next.last_event().unwrap(), event);
@@ -261,10 +376,15 @@ mod tests {
        next: Box<dyn Filter + Send + Sync>,
        device_id: i32,
        threshold: i64,
        keyboard_type: KeyboardType,
    ) -> BounceKeysFilter {
        setup_filter_with_devices(
            next,
            &[DeviceInfo { deviceId: device_id, external: true }],
            &[DeviceInfo {
                deviceId: device_id,
                external: true,
                keyboardType: keyboard_type as i32,
            }],
            threshold,
        )
    }
@@ -273,10 +393,15 @@ mod tests {
        next: Box<dyn Filter + Send + Sync>,
        device_id: i32,
        threshold: i64,
        keyboard_type: KeyboardType,
    ) -> BounceKeysFilter {
        setup_filter_with_devices(
            next,
            &[DeviceInfo { deviceId: device_id, external: false }],
            &[DeviceInfo {
                deviceId: device_id,
                external: false,
                keyboardType: keyboard_type as i32,
            }],
            threshold,
        )
    }
+9 −1
Original line number Diff line number Diff line
@@ -35,6 +35,9 @@ use input::ModifierState;
use log::{error, info};
use std::sync::{Arc, Mutex, RwLock};

/// Virtual keyboard device ID
pub const VIRTUAL_KEYBOARD_DEVICE_ID: i32 = -1;

/// Interface for all the sub input filters
pub trait Filter {
    fn notify_key(&mut self, event: &KeyEvent);
@@ -214,6 +217,7 @@ mod tests {
        InputFilterConfiguration::InputFilterConfiguration, KeyEvent::KeyEvent,
        KeyEventAction::KeyEventAction,
    };
    use input::KeyboardType;
    use std::sync::{Arc, RwLock};

    #[test]
@@ -256,7 +260,11 @@ mod tests {
            Arc::new(RwLock::new(Strong::new(Box::new(test_callbacks)))),
        );
        assert!(input_filter
            .notifyInputDevicesChanged(&[DeviceInfo { deviceId: 0, external: true }])
            .notifyInputDevicesChanged(&[DeviceInfo {
                deviceId: 0,
                external: true,
                keyboardType: KeyboardType::None as i32
            }])
            .is_ok());
        assert!(test_filter.is_device_changed_called());
    }
Loading