Merge "Listen to rotary input events and report them to FocusEventDebugView." into main
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index bf6e1c4..50ebab7 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5627,7 +5627,7 @@
public static final String SHOW_TOUCHES = "show_touches";
/**
- * Show key presses and other events dispatched to focused windows on the screen.
+ * Show key presses dispatched to focused windows on the screen.
* 0 = no
* 1 = yes
* @hide
@@ -5635,6 +5635,14 @@
public static final String SHOW_KEY_PRESSES = "show_key_presses";
/**
+ * Show rotary input dispatched to focused windows on the screen.
+ * 0 = no
+ * 1 = yes
+ * @hide
+ */
+ public static final String SHOW_ROTARY_INPUT = "show_rotary_input";
+
+ /**
* Log raw orientation data from
* {@link com.android.server.policy.WindowOrientationListener} for use with the
* orientationplot.py tool.
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 0dd8569..80cf6c3 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -184,6 +184,7 @@
VALIDATORS.put(System.POINTER_LOCATION, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.SHOW_TOUCHES, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.SHOW_KEY_PRESSES, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(System.SHOW_ROTARY_INPUT, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.WINDOW_ORIENTATION_LISTENER_LOG, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.LOCKSCREEN_SOUNDS_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.LOCKSCREEN_DISABLED, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 4678559..c697c1f 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -79,6 +79,7 @@
Settings.System.SHOW_GTALK_SERVICE_STATUS, // candidate for backup?
Settings.System.SHOW_TOUCHES,
Settings.System.SHOW_KEY_PRESSES,
+ Settings.System.SHOW_ROTARY_INPUT,
Settings.System.SIP_ADDRESS_ONLY, // value, not a setting
Settings.System.SIP_ALWAYS, // value, not a setting
Settings.System.SYSTEM_LOCALES, // bug?
diff --git a/services/core/java/com/android/server/input/FocusEventDebugGlobalMonitor.java b/services/core/java/com/android/server/input/FocusEventDebugGlobalMonitor.java
new file mode 100644
index 0000000..67c221f
--- /dev/null
+++ b/services/core/java/com/android/server/input/FocusEventDebugGlobalMonitor.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.input;
+
+import android.view.Display;
+import android.view.InputEvent;
+import android.view.InputEventReceiver;
+import android.view.MotionEvent;
+
+import com.android.server.UiThread;
+
+/**
+ * Receives input events before they are dispatched and reports them to FocusEventDebugView.
+ */
+class FocusEventDebugGlobalMonitor extends InputEventReceiver {
+ private final FocusEventDebugView mDebugView;
+
+ FocusEventDebugGlobalMonitor(FocusEventDebugView debugView, InputManagerService service) {
+ super(service.monitorInput("FocusEventDebugGlobalMonitor", Display.DEFAULT_DISPLAY),
+ UiThread.getHandler().getLooper());
+ mDebugView = debugView;
+ }
+
+ @Override
+ public void onInputEvent(InputEvent event) {
+ try {
+ if (event instanceof MotionEvent) {
+ mDebugView.reportMotionEvent((MotionEvent) event);
+ }
+ } finally {
+ finishInputEvent(event, false);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/input/FocusEventDebugView.java b/services/core/java/com/android/server/input/FocusEventDebugView.java
index fba2aa6..02e0eb0 100644
--- a/services/core/java/com/android/server/input/FocusEventDebugView.java
+++ b/services/core/java/com/android/server/input/FocusEventDebugView.java
@@ -22,17 +22,20 @@
import android.animation.LayoutTransition;
import android.annotation.AnyThread;
+import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Typeface;
+import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.TypedValue;
import android.view.Gravity;
-import android.view.InputEvent;
+import android.view.InputDevice;
import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.view.RoundedCorner;
import android.view.View;
import android.view.WindowInsets;
@@ -64,42 +67,31 @@
private static final int KEY_VIEW_MIN_WIDTH_DP = 32;
private static final int KEY_VIEW_TEXT_SIZE_SP = 12;
+ private final InputManagerService mService;
private final int mOuterPadding;
// Tracks all keys that are currently pressed/down.
private final Map<Pair<Integer /*deviceId*/, Integer /*scanCode*/>, PressedKeyView>
mPressedKeys = new HashMap<>();
- private final PressedKeyContainer mPressedKeyContainer;
- private final PressedKeyContainer mPressedModifierContainer;
+ @Nullable
+ private FocusEventDebugGlobalMonitor mFocusEventDebugGlobalMonitor;
+ @Nullable
+ private PressedKeyContainer mPressedKeyContainer;
+ @Nullable
+ private PressedKeyContainer mPressedModifierContainer;
- FocusEventDebugView(Context c) {
+ FocusEventDebugView(Context c, InputManagerService service) {
super(c);
setFocusableInTouchMode(true);
+ mService = service;
final var dm = mContext.getResources().getDisplayMetrics();
mOuterPadding = (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, OUTER_PADDING_DP, dm);
setOrientation(HORIZONTAL);
setLayoutDirection(LAYOUT_DIRECTION_RTL);
setGravity(Gravity.START | Gravity.BOTTOM);
-
- mPressedKeyContainer = new PressedKeyContainer(mContext);
- mPressedKeyContainer.setOrientation(HORIZONTAL);
- mPressedKeyContainer.setGravity(Gravity.RIGHT | Gravity.BOTTOM);
- mPressedKeyContainer.setLayoutDirection(LAYOUT_DIRECTION_LTR);
- final var scroller = new HorizontalScrollView(mContext);
- scroller.addView(mPressedKeyContainer);
- scroller.setHorizontalScrollBarEnabled(false);
- scroller.addOnLayoutChangeListener(
- (view, l, t, r, b, ol, ot, or, ob) -> scroller.fullScroll(View.FOCUS_RIGHT));
- scroller.setHorizontalFadingEdgeEnabled(true);
- addView(scroller, new LayoutParams(0, WRAP_CONTENT, 1));
-
- mPressedModifierContainer = new PressedKeyContainer(mContext);
- mPressedModifierContainer.setOrientation(VERTICAL);
- mPressedModifierContainer.setGravity(Gravity.LEFT | Gravity.BOTTOM);
- addView(mPressedModifierContainer, new LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
}
@Override
@@ -135,17 +127,82 @@
return super.dispatchKeyEvent(event);
}
- /** Report an input event to the debug view. */
@AnyThread
- public void reportEvent(InputEvent event) {
- if (!(event instanceof KeyEvent)) {
- // TODO: Support non-pointer MotionEvents.
+ public void updateShowKeyPresses(boolean enabled) {
+ post(() -> handleUpdateShowKeyPresses(enabled));
+ }
+
+ @AnyThread
+ public void updateShowRotaryInput(boolean enabled) {
+ post(() -> handleUpdateShowRotaryInput(enabled));
+ }
+
+ private void handleUpdateShowKeyPresses(boolean enabled) {
+ if (enabled == showKeyPresses()) {
return;
}
+
+ if (!enabled) {
+ removeView(mPressedKeyContainer);
+ mPressedKeyContainer = null;
+ removeView(mPressedModifierContainer);
+ mPressedModifierContainer = null;
+ return;
+ }
+
+ mPressedKeyContainer = new PressedKeyContainer(mContext);
+ mPressedKeyContainer.setOrientation(HORIZONTAL);
+ mPressedKeyContainer.setGravity(Gravity.RIGHT | Gravity.BOTTOM);
+ mPressedKeyContainer.setLayoutDirection(LAYOUT_DIRECTION_LTR);
+ final var scroller = new HorizontalScrollView(mContext);
+ scroller.addView(mPressedKeyContainer);
+ scroller.setHorizontalScrollBarEnabled(false);
+ scroller.addOnLayoutChangeListener(
+ (view, l, t, r, b, ol, ot, or, ob) -> scroller.fullScroll(View.FOCUS_RIGHT));
+ scroller.setHorizontalFadingEdgeEnabled(true);
+ addView(scroller, new LayoutParams(0, WRAP_CONTENT, 1));
+
+ mPressedModifierContainer = new PressedKeyContainer(mContext);
+ mPressedModifierContainer.setOrientation(VERTICAL);
+ mPressedModifierContainer.setGravity(Gravity.LEFT | Gravity.BOTTOM);
+ addView(mPressedModifierContainer, new LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
+ }
+
+ private void handleUpdateShowRotaryInput(boolean enabled) {
+ if (enabled == showRotaryInput()) {
+ return;
+ }
+
+ if (!enabled) {
+ mFocusEventDebugGlobalMonitor.dispose();
+ mFocusEventDebugGlobalMonitor = null;
+ return;
+ }
+
+ mFocusEventDebugGlobalMonitor = new FocusEventDebugGlobalMonitor(this, mService);
+ }
+
+ /** Report a key event to the debug view. */
+ @AnyThread
+ public void reportKeyEvent(KeyEvent event) {
post(() -> handleKeyEvent(KeyEvent.obtain((KeyEvent) event)));
}
+ /** Report a motion event to the debug view. */
+ @AnyThread
+ public void reportMotionEvent(MotionEvent event) {
+ if (event.getSource() != InputDevice.SOURCE_ROTARY_ENCODER) {
+ return;
+ }
+
+ post(() -> handleRotaryInput(MotionEvent.obtain((MotionEvent) event)));
+ }
+
private void handleKeyEvent(KeyEvent keyEvent) {
+ if (!showKeyPresses()) {
+ return;
+ }
+
final var identifier = new Pair<>(keyEvent.getDeviceId(), keyEvent.getScanCode());
final var container = KeyEvent.isModifierKey(keyEvent.getKeyCode())
? mPressedModifierContainer
@@ -185,6 +242,18 @@
keyEvent.recycle();
}
+ private void handleRotaryInput(MotionEvent motionEvent) {
+ if (!showRotaryInput()) {
+ return;
+ }
+
+ float scrollAxisValue = motionEvent.getAxisValue(MotionEvent.AXIS_SCROLL);
+ // TODO(b/286086154): replace log with visualization.
+ Log.d(TAG, "ROTARY INPUT: " + String.valueOf(scrollAxisValue));
+
+ motionEvent.recycle();
+ }
+
private static String getLabel(KeyEvent event) {
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_SPACE:
@@ -232,6 +301,16 @@
return label;
}
+ /** Determine whether to show key presses by checking one of the key-related objects. */
+ private boolean showKeyPresses() {
+ return mPressedKeyContainer != null;
+ }
+
+ /** Determine whether to show rotary input by checking one of the rotary-related objects. */
+ private boolean showRotaryInput() {
+ return mFocusEventDebugGlobalMonitor != null;
+ }
+
private static class PressedKeyView extends TextView {
private static final ColorFilter sInvertColors = new ColorMatrixColorFilter(new float[]{
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 6241ebb..b8e9d5d 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -390,6 +390,8 @@
@GuardedBy("mFocusEventDebugViewLock")
@Nullable
private FocusEventDebugView mFocusEventDebugView;
+ private boolean mShowKeyPresses = false;
+ private boolean mShowRotaryInput = false;
/** Point of injection for test dependencies. */
@VisibleForTesting
@@ -2476,7 +2478,7 @@
private int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
synchronized (mFocusEventDebugViewLock) {
if (mFocusEventDebugView != null) {
- mFocusEventDebugView.reportEvent(event);
+ mFocusEventDebugView.reportKeyEvent(event);
}
}
return mWindowManagerCallbacks.interceptKeyBeforeQueueing(event, policyFlags);
@@ -3396,14 +3398,45 @@
mWindowManagerCallbacks.notifyPointerLocationChanged(enabled);
}
- void updateFocusEventDebugViewEnabled(boolean enabled) {
+ void updateShowKeyPresses(boolean enabled) {
+ if (mShowKeyPresses == enabled) {
+ return;
+ }
+
+ mShowKeyPresses = enabled;
+ updateFocusEventDebugViewEnabled();
+
+ synchronized (mFocusEventDebugViewLock) {
+ if (mFocusEventDebugView != null) {
+ mFocusEventDebugView.updateShowKeyPresses(enabled);
+ }
+ }
+ }
+
+ void updateShowRotaryInput(boolean enabled) {
+ if (mShowRotaryInput == enabled) {
+ return;
+ }
+
+ mShowRotaryInput = enabled;
+ updateFocusEventDebugViewEnabled();
+
+ synchronized (mFocusEventDebugViewLock) {
+ if (mFocusEventDebugView != null) {
+ mFocusEventDebugView.updateShowRotaryInput(enabled);
+ }
+ }
+ }
+
+ private void updateFocusEventDebugViewEnabled() {
+ boolean enabled = mShowKeyPresses || mShowRotaryInput;
FocusEventDebugView view;
synchronized (mFocusEventDebugViewLock) {
if (enabled == (mFocusEventDebugView != null)) {
return;
}
if (enabled) {
- mFocusEventDebugView = new FocusEventDebugView(mContext);
+ mFocusEventDebugView = new FocusEventDebugView(mContext, this);
view = mFocusEventDebugView;
} else {
view = mFocusEventDebugView;
diff --git a/services/core/java/com/android/server/input/InputSettingsObserver.java b/services/core/java/com/android/server/input/InputSettingsObserver.java
index cf7c692..aab491e 100644
--- a/services/core/java/com/android/server/input/InputSettingsObserver.java
+++ b/services/core/java/com/android/server/input/InputSettingsObserver.java
@@ -86,7 +86,9 @@
Map.entry(Settings.Secure.getUriFor(Settings.Secure.KEY_REPEAT_TIMEOUT_MS),
(reason) -> updateKeyRepeatInfo(getLatestLongPressTimeoutValue())),
Map.entry(Settings.Secure.getUriFor(Settings.Secure.KEY_REPEAT_DELAY_MS),
- (reason) -> updateKeyRepeatInfo(getLatestLongPressTimeoutValue())));
+ (reason) -> updateKeyRepeatInfo(getLatestLongPressTimeoutValue())),
+ Map.entry(Settings.System.getUriFor(Settings.System.SHOW_ROTARY_INPUT),
+ (reason) -> updateShowRotaryInput()));
}
/**
@@ -164,8 +166,11 @@
}
private void updateShowKeyPresses() {
- mService.updateFocusEventDebugViewEnabled(
- getBoolean(Settings.System.SHOW_KEY_PRESSES, false));
+ mService.updateShowKeyPresses(getBoolean(Settings.System.SHOW_KEY_PRESSES, false));
+ }
+
+ private void updateShowRotaryInput() {
+ mService.updateShowRotaryInput(getBoolean(Settings.System.SHOW_ROTARY_INPUT, false));
}
private void updateAccessibilityLargePointer() {