Use setting to control key event filtering
Rather than enabling key event filtering on debug builds, allow
filtering to be controlled by a car setting.
Test: confirm keyboard doesn't work on Seahawk until setting enabled
Test: atest android.hardware.input.cts.tests.UsbVoiceCommandTest#testMediaKeys
Test: atest android.view.cts.InputDeviceKeyLayoutMapTest#testLayoutKeyEvents
Bug: 187955894
Bug: 183053404
Bug: 194356647
Change-Id: Ic0e4321f4a770a85a61e14621d9de9cdc3a8baa1
(cherry picked from commit cf9cf8728a6e51c89f9ef6b86d691487ecc89bf7)
diff --git a/src/com/android/car/rotary/RotaryService.java b/src/com/android/car/rotary/RotaryService.java
index 87dae63..13d7368 100644
--- a/src/com/android/car/rotary/RotaryService.java
+++ b/src/com/android/car/rotary/RotaryService.java
@@ -16,6 +16,7 @@
package com.android.car.rotary;
import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS;
+import static android.car.settings.CarSettings.Secure.KEY_ROTARY_KEY_EVENT_FILTER;
import static android.provider.Settings.Secure.DEFAULT_INPUT_METHOD;
import static android.provider.Settings.Secure.DISABLED_SYSTEM_INPUT_METHODS;
import static android.provider.Settings.Secure.ENABLED_INPUT_METHODS;
@@ -313,6 +314,9 @@
/** Observer to update {@link #mTouchInputMethod} when the user switches IMEs. */
private ContentObserver mInputMethodObserver;
+ /** Observer to update service info when the developer toggles key event filtering. */
+ private ContentObserver mKeyEventFilterObserver;
+
private SharedPreferences mPrefs;
private UserManager mUserManager;
@@ -432,6 +436,11 @@
*/
@Nullable private Context mWindowContext;
+ /**
+ * Mapping from test keycodes to production keycodes. During development, you can use a USB
+ * keyboard as a stand-in for rotary hardware. To enable this: {@code adb shell settings put
+ * secure android.car.ROTARY_KEY_EVENT_FILTER 1}.
+ */
private static final Map<Integer, Integer> TEST_TO_REAL_KEYCODE_MAP;
private static final Map<Integer, Integer> DIRECTION_TO_KEYCODE_MAP;
@@ -681,12 +690,7 @@
}
});
- if (Build.IS_DEBUGGABLE) {
- AccessibilityServiceInfo serviceInfo = getServiceInfo();
- // Filter testing KeyEvents from a keyboard.
- serviceInfo.flags |= FLAG_REQUEST_FILTER_KEY_EVENTS;
- setServiceInfo(serviceInfo);
- }
+ updateServiceInfo();
mInputManager = getSystemService(InputManager.class);
@@ -695,6 +699,10 @@
// Register an observer to update mTouchInputMethod whenever the user switches IMEs.
registerInputMethodObserver();
+
+ // Register an observer to update the service info when the developer changes the filter
+ // setting.
+ registerFilterObserver();
}
@Override
@@ -708,6 +716,7 @@
getWindowContext().unregisterReceiver(mHomeButtonReceiver);
unregisterInputMethodObserver();
+ unregisterFilterObserver();
if (mCarInputManager != null) {
mCarInputManager.releaseInputEventCapture(CarInputManager.TARGET_DISPLAY_TYPE_MAIN);
}
@@ -898,6 +907,30 @@
}
/**
+ * Updates this accessibility service's info, enabling or disabling key event filtering
+ * depending on a setting.
+ */
+ private void updateServiceInfo() {
+ AccessibilityServiceInfo serviceInfo = getServiceInfo();
+ if (serviceInfo == null) {
+ L.w("Service info not available");
+ return;
+ }
+ int flags = serviceInfo.flags;
+ boolean filterKeyEvents = Settings.Secure.getInt(getContentResolver(),
+ KEY_ROTARY_KEY_EVENT_FILTER, /* def= */ 0) != 0;
+ if (filterKeyEvents) {
+ flags |= FLAG_REQUEST_FILTER_KEY_EVENTS;
+ } else {
+ flags &= ~FLAG_REQUEST_FILTER_KEY_EVENTS;
+ }
+ if (flags == serviceInfo.flags) return;
+ L.d((filterKeyEvents ? "Enabling" : "Disabling") + " key event filtering");
+ serviceInfo.flags = flags;
+ setServiceInfo(serviceInfo);
+ }
+
+ /**
* Registers an observer to updates {@link #mTouchInputMethod} whenever the user switches IMEs.
*/
private void registerInputMethodObserver() {
@@ -934,6 +967,35 @@
}
}
+ /**
+ * Registers an observer to update our accessibility service info whenever the developer changes
+ * the key event filter setting.
+ */
+ private void registerFilterObserver() {
+ if (mKeyEventFilterObserver != null) {
+ throw new IllegalStateException("Filter observer already registered");
+ }
+ mKeyEventFilterObserver = new ContentObserver(new Handler(Looper.myLooper())) {
+ @Override
+ public void onChange(boolean selfChange) {
+ updateServiceInfo();
+ }
+ };
+ getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(KEY_ROTARY_KEY_EVENT_FILTER),
+ /* notifyForDescendants= */ false,
+ mKeyEventFilterObserver);
+ }
+
+ /** Unregisters the observer registered by {@link #registerFilterObserver}. */
+ private void unregisterFilterObserver() {
+ if (mKeyEventFilterObserver != null) {
+ getContentResolver().unregisterContentObserver(mKeyEventFilterObserver);
+ mKeyEventFilterObserver = null;
+ }
+ }
+
+
private static boolean isValidDisplayId(int displayId) {
if (displayId == CarInputManager.TARGET_DISPLAY_TYPE_MAIN) {
return true;