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

Commit 92ddbc49 authored by Vaibhav Devmurari's avatar Vaibhav Devmurari Committed by Android (Google) Code Review
Browse files

Merge "Support bounce and slow keys for internal Alphabetic keyboards" into main

parents 9b5ad421 983e76b2
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