Log system keys and shortcuts
Test: atest ShortcutLoggingTests
Bug: 280423320
Change-Id: I22ca8cca9f3ea42625b1c406eec51ebeebc17cec
diff --git a/services/core/java/com/android/server/input/KeyboardMetricsCollector.java b/services/core/java/com/android/server/input/KeyboardMetricsCollector.java
index eb2da34..4b30ae5 100644
--- a/services/core/java/com/android/server/input/KeyboardMetricsCollector.java
+++ b/services/core/java/com/android/server/input/KeyboardMetricsCollector.java
@@ -21,12 +21,16 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Intent;
import android.hardware.input.KeyboardLayout;
import android.icu.util.ULocale;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.InputDevice;
+import android.view.KeyEvent;
import android.view.inputmethod.InputMethodSubtype;
import com.android.internal.annotations.VisibleForTesting;
@@ -36,8 +40,12 @@
import java.lang.annotation.Retention;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
+import java.util.Set;
/**
* Collect Keyboard metrics
@@ -50,13 +58,14 @@
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@Retention(SOURCE)
- @IntDef(prefix = { "LAYOUT_SELECTION_CRITERIA_" }, value = {
+ @IntDef(prefix = {"LAYOUT_SELECTION_CRITERIA_"}, value = {
LAYOUT_SELECTION_CRITERIA_USER,
LAYOUT_SELECTION_CRITERIA_DEVICE,
LAYOUT_SELECTION_CRITERIA_VIRTUAL_KEYBOARD,
LAYOUT_SELECTION_CRITERIA_DEFAULT
})
- public @interface LayoutSelectionCriteria {}
+ public @interface LayoutSelectionCriteria {
+ }
/** Manual selection by user */
public static final int LAYOUT_SELECTION_CRITERIA_USER = 0;
@@ -76,17 +85,301 @@
@VisibleForTesting
static final String DEFAULT_LANGUAGE_TAG = "None";
+ public enum KeyboardLogEvent {
+ UNSPECIFIED(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__UNSPECIFIED,
+ "INVALID_KEYBOARD_EVENT"),
+ HOME(FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__HOME,
+ "HOME"),
+ RECENT_APPS(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__RECENT_APPS,
+ "RECENT_APPS"),
+ BACK(FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BACK,
+ "BACK"),
+ APP_SWITCH(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__APP_SWITCH,
+ "APP_SWITCH"),
+ LAUNCH_ASSISTANT(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_ASSISTANT,
+ "LAUNCH_ASSISTANT"),
+ LAUNCH_VOICE_ASSISTANT(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_VOICE_ASSISTANT,
+ "LAUNCH_VOICE_ASSISTANT"),
+ LAUNCH_SYSTEM_SETTINGS(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_SYSTEM_SETTINGS,
+ "LAUNCH_SYSTEM_SETTINGS"),
+ TOGGLE_NOTIFICATION_PANEL(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_NOTIFICATION_PANEL,
+ "TOGGLE_NOTIFICATION_PANEL"),
+ TOGGLE_TASKBAR(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_TASKBAR,
+ "TOGGLE_TASKBAR"),
+ TAKE_SCREENSHOT(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TAKE_SCREENSHOT,
+ "TAKE_SCREENSHOT"),
+ OPEN_SHORTCUT_HELPER(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__OPEN_SHORTCUT_HELPER,
+ "OPEN_SHORTCUT_HELPER"),
+ BRIGHTNESS_UP(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BRIGHTNESS_UP,
+ "BRIGHTNESS_UP"),
+ BRIGHTNESS_DOWN(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__BRIGHTNESS_DOWN,
+ "BRIGHTNESS_DOWN"),
+ KEYBOARD_BACKLIGHT_UP(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__KEYBOARD_BACKLIGHT_UP,
+ "KEYBOARD_BACKLIGHT_UP"),
+ KEYBOARD_BACKLIGHT_DOWN(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__KEYBOARD_BACKLIGHT_DOWN,
+ "KEYBOARD_BACKLIGHT_DOWN"),
+ KEYBOARD_BACKLIGHT_TOGGLE(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__KEYBOARD_BACKLIGHT_TOGGLE,
+ "KEYBOARD_BACKLIGHT_TOGGLE"),
+ VOLUME_UP(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_UP,
+ "VOLUME_UP"),
+ VOLUME_DOWN(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_DOWN,
+ "VOLUME_DOWN"),
+ VOLUME_MUTE(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__VOLUME_MUTE,
+ "VOLUME_MUTE"),
+ ALL_APPS(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__ALL_APPS,
+ "ALL_APPS"),
+ LAUNCH_SEARCH(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_SEARCH,
+ "LAUNCH_SEARCH"),
+ LANGUAGE_SWITCH(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LANGUAGE_SWITCH,
+ "LANGUAGE_SWITCH"),
+ ACCESSIBILITY_ALL_APPS(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__ACCESSIBILITY_ALL_APPS,
+ "ACCESSIBILITY_ALL_APPS"),
+ TOGGLE_CAPS_LOCK(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_CAPS_LOCK,
+ "TOGGLE_CAPS_LOCK"),
+ SYSTEM_MUTE(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SYSTEM_MUTE,
+ "SYSTEM_MUTE"),
+ SPLIT_SCREEN_NAVIGATION(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SPLIT_SCREEN_NAVIGATION,
+ "SPLIT_SCREEN_NAVIGATION"),
+ TRIGGER_BUG_REPORT(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TRIGGER_BUG_REPORT,
+ "TRIGGER_BUG_REPORT"),
+ LOCK_SCREEN(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LOCK_SCREEN,
+ "LOCK_SCREEN"),
+ OPEN_NOTES(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__OPEN_NOTES,
+ "OPEN_NOTES"),
+ TOGGLE_POWER(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__TOGGLE_POWER,
+ "TOGGLE_POWER"),
+ SYSTEM_NAVIGATION(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SYSTEM_NAVIGATION,
+ "SYSTEM_NAVIGATION"),
+ SLEEP(FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SLEEP,
+ "SLEEP"),
+ WAKEUP(FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__WAKEUP,
+ "WAKEUP"),
+ MEDIA_KEY(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MEDIA_KEY,
+ "MEDIA_KEY"),
+ LAUNCH_DEFAULT_BROWSER(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_BROWSER,
+ "LAUNCH_DEFAULT_BROWSER"),
+ LAUNCH_DEFAULT_EMAIL(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_EMAIL,
+ "LAUNCH_DEFAULT_EMAIL"),
+ LAUNCH_DEFAULT_CONTACTS(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_CONTACTS,
+ "LAUNCH_DEFAULT_CONTACTS"),
+ LAUNCH_DEFAULT_CALENDAR(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_CALENDAR,
+ "LAUNCH_DEFAULT_CALENDAR"),
+ LAUNCH_DEFAULT_CALCULATOR(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_CALCULATOR,
+ "LAUNCH_DEFAULT_CALCULATOR"),
+ LAUNCH_DEFAULT_MUSIC(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_MUSIC,
+ "LAUNCH_DEFAULT_MUSIC"),
+ LAUNCH_DEFAULT_MAPS(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_MAPS,
+ "LAUNCH_DEFAULT_MAPS"),
+ LAUNCH_DEFAULT_MESSAGING(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_MESSAGING,
+ "LAUNCH_DEFAULT_MESSAGING"),
+ LAUNCH_DEFAULT_GALLERY(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_GALLERY,
+ "LAUNCH_DEFAULT_GALLERY"),
+ LAUNCH_DEFAULT_FILES(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_FILES,
+ "LAUNCH_DEFAULT_FILES"),
+ LAUNCH_DEFAULT_WEATHER(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_WEATHER,
+ "LAUNCH_DEFAULT_WEATHER"),
+ LAUNCH_DEFAULT_FITNESS(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_DEFAULT_FITNESS,
+ "LAUNCH_DEFAULT_FITNESS"),
+ LAUNCH_APPLICATION_BY_PACKAGE_NAME(
+ FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__LAUNCH_APPLICATION_BY_PACKAGE_NAME,
+ "LAUNCH_APPLICATION_BY_PACKAGE_NAME");
+
+ private final int mValue;
+ private final String mName;
+
+ private static final SparseArray<KeyboardLogEvent> VALUE_TO_ENUM_MAP = new SparseArray<>();
+
+ static {
+ for (KeyboardLogEvent type : KeyboardLogEvent.values()) {
+ VALUE_TO_ENUM_MAP.put(type.mValue, type);
+ }
+ }
+
+ KeyboardLogEvent(int enumValue, String enumName) {
+ mValue = enumValue;
+ mName = enumName;
+ }
+
+ public int getIntValue() {
+ return mValue;
+ }
+
+ /**
+ * Convert int value to corresponding KeyboardLogEvent enum. If can't find any matching
+ * value will return {@code null}
+ */
+ @Nullable
+ public static KeyboardLogEvent from(int value) {
+ return VALUE_TO_ENUM_MAP.get(value);
+ }
+
+ /**
+ * Find KeyboardLogEvent corresponding to volume up/down/mute key events.
+ */
+ @Nullable
+ public static KeyboardLogEvent getVolumeEvent(int keycode) {
+ switch (keycode) {
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ return VOLUME_DOWN;
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ return VOLUME_UP;
+ case KeyEvent.KEYCODE_VOLUME_MUTE:
+ return VOLUME_MUTE;
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Find KeyboardLogEvent corresponding to brightness up/down key events.
+ */
+ @Nullable
+ public static KeyboardLogEvent getBrightnessEvent(int keycode) {
+ switch (keycode) {
+ case KeyEvent.KEYCODE_BRIGHTNESS_DOWN:
+ return BRIGHTNESS_DOWN;
+ case KeyEvent.KEYCODE_BRIGHTNESS_UP:
+ return BRIGHTNESS_UP;
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Find KeyboardLogEvent corresponding to intent filter category. Returns
+ * {@code null if no matching event found}
+ */
+ @Nullable
+ public static KeyboardLogEvent getLogEventFromIntent(Intent intent) {
+ Intent selectorIntent = intent.getSelector();
+ if (selectorIntent != null) {
+ Set<String> selectorCategories = selectorIntent.getCategories();
+ if (selectorCategories != null && !selectorCategories.isEmpty()) {
+ for (String intentCategory : selectorCategories) {
+ KeyboardLogEvent logEvent = getEventFromSelectorCategory(intentCategory);
+ if (logEvent == null) {
+ continue;
+ }
+ return logEvent;
+ }
+ }
+ }
+
+ Set<String> intentCategories = intent.getCategories();
+ if (intentCategories == null || intentCategories.isEmpty()
+ || !intentCategories.contains(Intent.CATEGORY_LAUNCHER)) {
+ return null;
+ }
+ if (intent.getComponent() == null) {
+ return null;
+ }
+
+ // TODO(b/280423320): Add new field package name associated in the
+ // KeyboardShortcutEvent atom and log it accordingly.
+ return LAUNCH_APPLICATION_BY_PACKAGE_NAME;
+ }
+
+ @Nullable
+ private static KeyboardLogEvent getEventFromSelectorCategory(String category) {
+ switch (category) {
+ case Intent.CATEGORY_APP_BROWSER:
+ return LAUNCH_DEFAULT_BROWSER;
+ case Intent.CATEGORY_APP_EMAIL:
+ return LAUNCH_DEFAULT_EMAIL;
+ case Intent.CATEGORY_APP_CONTACTS:
+ return LAUNCH_DEFAULT_CONTACTS;
+ case Intent.CATEGORY_APP_CALENDAR:
+ return LAUNCH_DEFAULT_CALENDAR;
+ case Intent.CATEGORY_APP_CALCULATOR:
+ return LAUNCH_DEFAULT_CALCULATOR;
+ case Intent.CATEGORY_APP_MUSIC:
+ return LAUNCH_DEFAULT_MUSIC;
+ case Intent.CATEGORY_APP_MAPS:
+ return LAUNCH_DEFAULT_MAPS;
+ case Intent.CATEGORY_APP_MESSAGING:
+ return LAUNCH_DEFAULT_MESSAGING;
+ case Intent.CATEGORY_APP_GALLERY:
+ return LAUNCH_DEFAULT_GALLERY;
+ case Intent.CATEGORY_APP_FILES:
+ return LAUNCH_DEFAULT_FILES;
+ case Intent.CATEGORY_APP_WEATHER:
+ return LAUNCH_DEFAULT_WEATHER;
+ case Intent.CATEGORY_APP_FITNESS:
+ return LAUNCH_DEFAULT_FITNESS;
+ default:
+ return null;
+ }
+ }
+ }
+
/**
* Log keyboard system shortcuts for the proto
* {@link com.android.os.input.KeyboardSystemsEventReported}
* defined in "stats/atoms/input/input_extension_atoms.proto"
*/
- public static void logKeyboardSystemsEventReportedAtom(InputDevice inputDevice,
- int keyboardSystemEvent, int[] keyCode, int modifierState) {
+ public static void logKeyboardSystemsEventReportedAtom(@Nullable InputDevice inputDevice,
+ @Nullable KeyboardLogEvent keyboardSystemEvent, int modifierState, int... keyCodes) {
+ // Logging Keyboard system event only for an external HW keyboard. We should not log events
+ // for virtual keyboards or internal Key events.
+ if (inputDevice == null || inputDevice.isVirtual() || !inputDevice.isFullKeyboard()) {
+ return;
+ }
int vendorId = inputDevice.getVendorId();
int productId = inputDevice.getProductId();
+ if (keyboardSystemEvent == null) {
+ Slog.w(TAG, "Invalid keyboard event logging, keycode = " + Arrays.toString(keyCodes)
+ + ", modifier state = " + modifierState);
+ return;
+ }
FrameworkStatsLog.write(FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED,
- vendorId, productId, keyboardSystemEvent, keyCode, modifierState);
+ vendorId, productId, keyboardSystemEvent.getIntValue(), keyCodes, modifierState);
+
+ if (DEBUG) {
+ Slog.d(TAG, "Logging Keyboard system event: " + keyboardSystemEvent.mName);
+ }
}
/**
@@ -94,8 +387,8 @@
* {@link com.android.os.input.KeyboardConfigured} atom
*
* @param event {@link KeyboardConfigurationEvent} contains information about keyboard
- * configuration. Use {@link KeyboardConfigurationEvent.Builder} to create the
- * configuration event to log.
+ * configuration. Use {@link KeyboardConfigurationEvent.Builder} to create the
+ * configuration event to log.
*/
public static void logKeyboardConfiguredAtom(KeyboardConfigurationEvent event) {
// Creating proto to log nested field KeyboardLayoutConfig in atom
@@ -241,7 +534,7 @@
KeyboardLayout selectedLayout = mSelectedLayoutList.get(i);
@LayoutSelectionCriteria int layoutSelectionCriteria =
mLayoutSelectionCriteriaList.get(i);
- InputMethodSubtype imeSubtype = mImeSubtypeList.get(i);
+ InputMethodSubtype imeSubtype = mImeSubtypeList.get(i);
String keyboardLanguageTag = mInputDevice.getKeyboardLanguageTag();
keyboardLanguageTag = keyboardLanguageTag == null ? DEFAULT_LANGUAGE_TAG
: keyboardLanguageTag;
@@ -328,4 +621,3 @@
|| layoutSelectionCriteria == LAYOUT_SELECTION_CRITERIA_DEFAULT;
}
}
-
diff --git a/services/core/java/com/android/server/policy/ModifierShortcutManager.java b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
index 784e177..69cc125 100644
--- a/services/core/java/com/android/server/policy/ModifierShortcutManager.java
+++ b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
@@ -16,6 +16,7 @@
package com.android.server.policy;
+import android.annotation.SuppressLint;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
@@ -23,6 +24,8 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.XmlResourceParser;
+import android.hardware.input.InputManager;
+import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -30,11 +33,14 @@
import android.util.LongSparseArray;
import android.util.Slog;
import android.util.SparseArray;
+import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import com.android.internal.policy.IShortcutService;
import com.android.internal.util.XmlUtils;
+import com.android.server.input.KeyboardMetricsCollector;
+import com.android.server.input.KeyboardMetricsCollector.KeyboardLogEvent;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -88,11 +94,13 @@
}
private final Context mContext;
+ private final Handler mHandler;
private boolean mSearchKeyShortcutPending = false;
private boolean mConsumeSearchKeyUp = true;
- ModifierShortcutManager(Context context) {
+ ModifierShortcutManager(Context context, Handler handler) {
mContext = context;
+ mHandler = handler;
loadShortcuts();
}
@@ -273,11 +281,13 @@
* Handle the shortcut to {@link Intent}
*
* @param kcm the {@link KeyCharacterMap} associated with the keyboard device.
- * @param keyCode The key code of the event.
+ * @param keyEvent The key event.
* @param metaState The meta key modifier state.
* @return True if invoked the shortcut, otherwise false.
*/
- private boolean handleIntentShortcut(KeyCharacterMap kcm, int keyCode, int metaState) {
+ @SuppressLint("MissingPermission")
+ private boolean handleIntentShortcut(KeyCharacterMap kcm, KeyEvent keyEvent, int metaState) {
+ final int keyCode = keyEvent.getKeyCode();
// Shortcuts are invoked through Search+key, so intercept those here
// Any printing key that is chorded with Search should be consumed
// even if no shortcut was invoked. This prevents text from being
@@ -307,6 +317,7 @@
+ "keyCode=" + KeyEvent.keyCodeToString(keyCode) + ","
+ " category=" + category);
}
+ logKeyboardShortcut(keyEvent, KeyboardLogEvent.getLogEventFromIntent(intent));
return true;
} else {
return false;
@@ -323,11 +334,24 @@
+ "the activity to which it is registered was not found: "
+ "META+ or SEARCH" + KeyEvent.keyCodeToString(keyCode));
}
+ logKeyboardShortcut(keyEvent, KeyboardLogEvent.getLogEventFromIntent(shortcutIntent));
return true;
}
return false;
}
+ private void logKeyboardShortcut(KeyEvent event, KeyboardLogEvent logEvent) {
+ mHandler.post(() -> handleKeyboardLogging(event, logEvent));
+ }
+
+ private void handleKeyboardLogging(KeyEvent event, KeyboardLogEvent logEvent) {
+ final InputManager inputManager = mContext.getSystemService(InputManager.class);
+ final InputDevice inputDevice = inputManager != null
+ ? inputManager.getInputDevice(event.getDeviceId()) : null;
+ KeyboardMetricsCollector.logKeyboardSystemsEventReportedAtom(inputDevice,
+ logEvent, event.getMetaState(), event.getKeyCode());
+ }
+
/**
* Handle the shortcut from {@link KeyEvent}
*
@@ -360,7 +384,7 @@
}
final KeyCharacterMap kcm = event.getKeyCharacterMap();
- if (handleIntentShortcut(kcm, keyCode, metaState)) {
+ if (handleIntentShortcut(kcm, event, metaState)) {
return true;
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 5cfbcaa..ca64792 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -219,6 +219,7 @@
import com.android.server.display.BrightnessUtils;
import com.android.server.input.InputManagerInternal;
import com.android.server.input.KeyboardMetricsCollector;
+import com.android.server.input.KeyboardMetricsCollector.KeyboardLogEvent;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.pm.UserManagerInternal;
import com.android.server.policy.KeyCombinationManager.TwoKeysCombinationRule;
@@ -409,6 +410,7 @@
ActivityManagerInternal mActivityManagerInternal;
ActivityTaskManagerInternal mActivityTaskManagerInternal;
AutofillManagerInternal mAutofillManagerInternal;
+ InputManager mInputManager;
InputManagerInternal mInputManagerInternal;
DreamManagerInternal mDreamManagerInternal;
PowerManagerInternal mPowerManagerInternal;
@@ -762,7 +764,7 @@
handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
break;
case MSG_LOG_KEYBOARD_SYSTEM_EVENT:
- handleKeyboardSystemEvent(msg.arg2, (KeyEvent) msg.obj);
+ handleKeyboardSystemEvent(KeyboardLogEvent.from(msg.arg1), (KeyEvent) msg.obj);
break;
}
}
@@ -1762,8 +1764,11 @@
}
private void launchAllAppsViaA11y() {
- getAccessibilityManagerInternal().performSystemAction(
- AccessibilityService.GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
+ AccessibilityManagerInternal accessibilityManager = getAccessibilityManagerInternal();
+ if (accessibilityManager != null) {
+ accessibilityManager.performSystemAction(
+ AccessibilityService.GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
+ }
}
private void toggleNotificationPanel() {
@@ -1834,6 +1839,7 @@
// If we have released the home key, and didn't do anything else
// while it was pressed, then it is time to go home!
if (!down) {
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.HOME);
if (mDisplayId == DEFAULT_DISPLAY) {
cancelPreloadRecentApps();
}
@@ -2035,6 +2041,7 @@
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
+ mInputManager = mContext.getSystemService(InputManager.class);
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
@@ -2104,7 +2111,7 @@
mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler);
mSettingsObserver = new SettingsObserver(mHandler);
mSettingsObserver.observe();
- mModifierShortcutManager = new ModifierShortcutManager(mContext);
+ mModifierShortcutManager = new ModifierShortcutManager(mContext, mHandler);
mUiMode = mContext.getResources().getInteger(
com.android.internal.R.integer.config_defaultUiModeType);
mHomeIntent = new Intent(Intent.ACTION_MAIN, null);
@@ -2930,20 +2937,33 @@
* We won't log keyboard events when the input device is null
* or when it is virtual.
*/
- private void handleKeyboardSystemEvent(int keyboardSystemEvent, KeyEvent event) {
- final InputManager inputManager = mContext.getSystemService(InputManager.class);
- final InputDevice inputDevice = inputManager != null
- ? inputManager.getInputDevice(event.getDeviceId()) : null;
- if (inputDevice != null && !inputDevice.isVirtual()) {
- KeyboardMetricsCollector.logKeyboardSystemsEventReportedAtom(
- inputDevice, keyboardSystemEvent,
- new int[]{event.getKeyCode()}, event.getMetaState());
- }
+ private void handleKeyboardSystemEvent(KeyboardLogEvent keyboardLogEvent, KeyEvent event) {
+ final InputDevice inputDevice = mInputManager.getInputDevice(event.getDeviceId());
+ KeyboardMetricsCollector.logKeyboardSystemsEventReportedAtom(inputDevice,
+ keyboardLogEvent, event.getMetaState(), event.getKeyCode());
+ event.recycle();
}
- private void logKeyboardSystemsEvent(KeyEvent event, int keyboardSystemEvent) {
- mHandler.obtainMessage(MSG_LOG_KEYBOARD_SYSTEM_EVENT, 0, keyboardSystemEvent, event)
- .sendToTarget();
+ private void logKeyboardSystemsEventOnActionUp(KeyEvent event,
+ KeyboardLogEvent keyboardSystemEvent) {
+ if (event.getAction() != KeyEvent.ACTION_UP) {
+ return;
+ }
+ logKeyboardSystemsEvent(event, keyboardSystemEvent);
+ }
+
+ private void logKeyboardSystemsEventOnActionDown(KeyEvent event,
+ KeyboardLogEvent keyboardSystemEvent) {
+ if (event.getAction() != KeyEvent.ACTION_DOWN) {
+ return;
+ }
+ logKeyboardSystemsEvent(event, keyboardSystemEvent);
+ }
+
+ private void logKeyboardSystemsEvent(KeyEvent event, KeyboardLogEvent keyboardSystemEvent) {
+ KeyEvent eventToLog = KeyEvent.obtain(event);
+ mHandler.obtainMessage(MSG_LOG_KEYBOARD_SYSTEM_EVENT, keyboardSystemEvent.getIntValue(), 0,
+ eventToLog).sendToTarget();
}
// TODO(b/117479243): handle it in InputPolicy
@@ -3044,8 +3064,6 @@
switch (keyCode) {
case KeyEvent.KEYCODE_HOME:
- logKeyboardSystemsEvent(event,
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__HOME);
return handleHomeShortcuts(displayId, focusedToken, event);
case KeyEvent.KEYCODE_MENU:
// Hijack modified menu keys for debugging features
@@ -3056,14 +3074,14 @@
Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT,
null, null, null, 0, null, null);
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.TRIGGER_BUG_REPORT);
return true;
}
break;
case KeyEvent.KEYCODE_RECENT_APPS:
if (firstDown) {
showRecentApps(false /* triggeredFromAltTab */);
- logKeyboardSystemsEvent(event,
- FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__RECENT_APPS);
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.RECENT_APPS);
}
return true;
case KeyEvent.KEYCODE_APP_SWITCH:
@@ -3072,6 +3090,7 @@
preloadRecentApps();
} else if (!down) {
toggleRecentApps();
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.APP_SWITCH);
}
}
return true;
@@ -3080,6 +3099,7 @@
launchAssistAction(Intent.EXTRA_ASSIST_INPUT_HINT_KEYBOARD,
deviceId, event.getEventTime(),
AssistUtils.INVOCATION_TYPE_UNKNOWN);
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.LAUNCH_ASSISTANT);
return true;
}
break;
@@ -3092,12 +3112,14 @@
case KeyEvent.KEYCODE_I:
if (firstDown && event.isMetaPressed()) {
showSystemSettings();
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.LAUNCH_SYSTEM_SETTINGS);
return true;
}
break;
case KeyEvent.KEYCODE_L:
if (firstDown && event.isMetaPressed()) {
lockNow(null /* options */);
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.LOCK_SCREEN);
return true;
}
break;
@@ -3105,8 +3127,10 @@
if (firstDown && event.isMetaPressed()) {
if (event.isCtrlPressed()) {
sendSystemKeyToStatusBarAsync(event);
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.OPEN_NOTES);
} else {
toggleNotificationPanel();
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.TOGGLE_NOTIFICATION_PANEL);
}
return true;
}
@@ -3114,12 +3138,14 @@
case KeyEvent.KEYCODE_S:
if (firstDown && event.isMetaPressed() && event.isCtrlPressed()) {
interceptScreenshotChord(SCREENSHOT_KEY_OTHER, 0 /*pressDelay*/);
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.TAKE_SCREENSHOT);
return true;
}
break;
case KeyEvent.KEYCODE_T:
if (firstDown && event.isMetaPressed()) {
toggleTaskbar();
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.TOGGLE_TASKBAR);
return true;
}
break;
@@ -3128,6 +3154,7 @@
StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
if (statusbar != null) {
statusbar.goToFullscreenFromSplit();
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.SPLIT_SCREEN_NAVIGATION);
return true;
}
}
@@ -3135,18 +3162,21 @@
case KeyEvent.KEYCODE_DPAD_LEFT:
if (firstDown && event.isMetaPressed() && event.isCtrlPressed()) {
enterStageSplitFromRunningApp(true /* leftOrTop */);
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.SPLIT_SCREEN_NAVIGATION);
return true;
}
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
if (firstDown && event.isMetaPressed() && event.isCtrlPressed()) {
enterStageSplitFromRunningApp(false /* leftOrTop */);
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.SPLIT_SCREEN_NAVIGATION);
return true;
}
break;
case KeyEvent.KEYCODE_SLASH:
if (firstDown && event.isMetaPressed() && !keyguardOn) {
toggleKeyboardShortcutsMenu(event.getDeviceId());
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.OPEN_SHORTCUT_HELPER);
return true;
}
break;
@@ -3215,20 +3245,26 @@
intent.addFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION);
intent.putExtra(EXTRA_FROM_BRIGHTNESS_KEY, true);
startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.getBrightnessEvent(keyCode));
}
return true;
case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_DOWN:
if (down) {
mInputManagerInternal.decrementKeyboardBacklight(event.getDeviceId());
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.KEYBOARD_BACKLIGHT_DOWN);
}
return true;
case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_UP:
if (down) {
mInputManagerInternal.incrementKeyboardBacklight(event.getDeviceId());
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.KEYBOARD_BACKLIGHT_UP);
}
return true;
case KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_TOGGLE:
// TODO: Add logic
+ if (!down) {
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.KEYBOARD_BACKLIGHT_TOGGLE);
+ }
return true;
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
@@ -3254,6 +3290,7 @@
if (firstDown && !keyguardOn && isUserSetupComplete()) {
if (event.isMetaPressed()) {
showRecentApps(false);
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.RECENT_APPS);
return true;
} else if (mRecentAppsHeldModifiers == 0) {
final int shiftlessModifiers =
@@ -3262,6 +3299,7 @@
shiftlessModifiers, KeyEvent.META_ALT_ON)) {
mRecentAppsHeldModifiers = shiftlessModifiers;
showRecentApps(true);
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.RECENT_APPS);
return true;
}
}
@@ -3273,11 +3311,13 @@
Message msg = mHandler.obtainMessage(MSG_HANDLE_ALL_APPS);
msg.setAsynchronous(true);
msg.sendToTarget();
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.ALL_APPS);
}
return true;
case KeyEvent.KEYCODE_NOTIFICATION:
if (!down) {
toggleNotificationPanel();
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.TOGGLE_NOTIFICATION_PANEL);
}
return true;
case KeyEvent.KEYCODE_SEARCH:
@@ -3285,6 +3325,7 @@
switch (mSearchKeyBehavior) {
case SEARCH_BEHAVIOR_TARGET_ACTIVITY: {
launchTargetSearchActivity();
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.LAUNCH_SEARCH);
return true;
}
case SEARCH_BEHAVIOR_DEFAULT_SEARCH:
@@ -3297,6 +3338,7 @@
if (firstDown) {
int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
sendSwitchKeyboardLayout(event, direction);
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.LANGUAGE_SWITCH);
return true;
}
break;
@@ -3305,6 +3347,7 @@
if (firstDown && event.isMetaPressed()) {
int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
sendSwitchKeyboardLayout(event, direction);
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.LANGUAGE_SWITCH);
return true;
}
break;
@@ -3323,9 +3366,11 @@
if (mPendingCapsLockToggle) {
mInputManagerInternal.toggleCapsLock(event.getDeviceId());
mPendingCapsLockToggle = false;
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.TOGGLE_CAPS_LOCK);
} else if (mPendingMetaAction) {
if (!canceled) {
launchAllAppsViaA11y();
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.ACCESSIBILITY_ALL_APPS);
}
mPendingMetaAction = false;
}
@@ -3353,10 +3398,16 @@
if (mPendingCapsLockToggle) {
mInputManagerInternal.toggleCapsLock(event.getDeviceId());
mPendingCapsLockToggle = false;
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.TOGGLE_CAPS_LOCK);
return true;
}
}
break;
+ case KeyEvent.KEYCODE_CAPS_LOCK:
+ if (!down) {
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.TOGGLE_CAPS_LOCK);
+ }
+ break;
case KeyEvent.KEYCODE_STYLUS_BUTTON_PRIMARY:
case KeyEvent.KEYCODE_STYLUS_BUTTON_SECONDARY:
case KeyEvent.KEYCODE_STYLUS_BUTTON_TERTIARY:
@@ -4200,6 +4251,7 @@
// Handle special keys.
switch (keyCode) {
case KeyEvent.KEYCODE_BACK: {
+ logKeyboardSystemsEventOnActionUp(event, KeyboardLogEvent.BACK);
if (down) {
mBackKeyHandled = false;
} else {
@@ -4217,6 +4269,8 @@
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
+ logKeyboardSystemsEventOnActionDown(event,
+ KeyboardLogEvent.getVolumeEvent(keyCode));
if (down) {
sendSystemKeyToStatusBarAsync(event);
@@ -4317,6 +4371,7 @@
}
case KeyEvent.KEYCODE_TV_POWER: {
+ logKeyboardSystemsEventOnActionUp(event, KeyboardLogEvent.TOGGLE_POWER);
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
if (down && hdmiControlManager != null) {
@@ -4326,6 +4381,7 @@
}
case KeyEvent.KEYCODE_POWER: {
+ logKeyboardSystemsEventOnActionUp(event, KeyboardLogEvent.TOGGLE_POWER);
EventLogTags.writeInterceptPower(
KeyEvent.actionToString(event.getAction()),
mPowerKeyHandled ? 1 : 0,
@@ -4348,12 +4404,14 @@
case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_LEFT:
// fall through
case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_RIGHT: {
+ logKeyboardSystemsEventOnActionUp(event, KeyboardLogEvent.SYSTEM_NAVIGATION);
result &= ~ACTION_PASS_TO_USER;
interceptSystemNavigationKey(event);
break;
}
case KeyEvent.KEYCODE_SLEEP: {
+ logKeyboardSystemsEventOnActionUp(event, KeyboardLogEvent.SLEEP);
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false;
if (!mPowerManager.isInteractive()) {
@@ -4368,6 +4426,7 @@
}
case KeyEvent.KEYCODE_SOFT_SLEEP: {
+ logKeyboardSystemsEventOnActionUp(event, KeyboardLogEvent.SLEEP);
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false;
if (!down) {
@@ -4377,6 +4436,7 @@
}
case KeyEvent.KEYCODE_WAKEUP: {
+ logKeyboardSystemsEventOnActionUp(event, KeyboardLogEvent.WAKEUP);
result &= ~ACTION_PASS_TO_USER;
isWakeKey = true;
break;
@@ -4385,6 +4445,7 @@
case KeyEvent.KEYCODE_MUTE:
result &= ~ACTION_PASS_TO_USER;
if (down && event.getRepeatCount() == 0) {
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.SYSTEM_MUTE);
toggleMicrophoneMuteFromKey();
}
break;
@@ -4399,6 +4460,7 @@
case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: {
+ logKeyboardSystemsEventOnActionUp(event, KeyboardLogEvent.MEDIA_KEY);
if (MediaSessionLegacyHelper.getHelper(mContext).isGlobalPriorityActive()) {
// If the global session is active pass all media keys to it
// instead of the active window.
@@ -4443,6 +4505,7 @@
0 /* unused */, event.getEventTime() /* eventTime */);
msg.setAsynchronous(true);
msg.sendToTarget();
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.LAUNCH_ASSISTANT);
}
result &= ~ACTION_PASS_TO_USER;
break;
@@ -4453,6 +4516,7 @@
Message msg = mHandler.obtainMessage(MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK);
msg.setAsynchronous(true);
msg.sendToTarget();
+ logKeyboardSystemsEvent(event, KeyboardLogEvent.LAUNCH_VOICE_ASSISTANT);
}
result &= ~ACTION_PASS_TO_USER;
break;
diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp
index 5f48f3c..6aa5989 100644
--- a/services/tests/wmtests/Android.bp
+++ b/services/tests/wmtests/Android.bp
@@ -51,6 +51,7 @@
"services.core",
"androidx.test.runner",
"androidx.test.rules",
+ "junit-params",
"mockito-target-extended-minus-junit4",
"platform-test-annotations",
"servicestests-utils",
diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
index 2015ae9..bf88ce4 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java
@@ -63,7 +63,7 @@
final Context mContext = spy(getInstrumentation().getTargetContext());
/** Modifier key to meta state */
- private static final Map<Integer, Integer> MODIFIER;
+ protected static final Map<Integer, Integer> MODIFIER;
static {
final Map<Integer, Integer> map = new ArrayMap<>();
map.put(KEYCODE_CTRL_LEFT, META_CTRL_LEFT_ON | META_CTRL_ON);
diff --git a/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java b/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java
new file mode 100644
index 0000000..feca326
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/policy/ShortcutLoggingTests.java
@@ -0,0 +1,245 @@
+/*
+ * 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.policy;
+
+import android.platform.test.annotations.Presubmit;
+import android.view.KeyEvent;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.annotations.Keep;
+import com.android.server.input.KeyboardMetricsCollector.KeyboardLogEvent;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
+
+@Presubmit
+@SmallTest
+@RunWith(JUnitParamsRunner.class)
+public class ShortcutLoggingTests extends ShortcutKeyTestBase {
+
+ private static final int VENDOR_ID = 0x123;
+ private static final int PRODUCT_ID = 0x456;
+ private static final int META_KEY = KeyEvent.KEYCODE_META_LEFT;
+ private static final int META_ON = MODIFIER.get(KeyEvent.KEYCODE_META_LEFT);
+ private static final int ALT_KEY = KeyEvent.KEYCODE_ALT_LEFT;
+ private static final int ALT_ON = MODIFIER.get(KeyEvent.KEYCODE_ALT_LEFT);
+ private static final int CTRL_KEY = KeyEvent.KEYCODE_CTRL_LEFT;
+ private static final int CTRL_ON = MODIFIER.get(KeyEvent.KEYCODE_CTRL_LEFT);
+ private static final int SHIFT_KEY = KeyEvent.KEYCODE_SHIFT_LEFT;
+ private static final int SHIFT_ON = MODIFIER.get(KeyEvent.KEYCODE_SHIFT_LEFT);
+
+ @Keep
+ private static Object[][] shortcutTestArguments() {
+ // testName, testKeys, expectedLogEvent, expectedKey, expectedModifierState
+ return new Object[][]{
+ {"Meta + H -> Open Home", new int[]{META_KEY, KeyEvent.KEYCODE_H},
+ KeyboardLogEvent.HOME, KeyEvent.KEYCODE_H, META_ON},
+ {"Meta + Enter -> Open Home", new int[]{META_KEY, KeyEvent.KEYCODE_ENTER},
+ KeyboardLogEvent.HOME, KeyEvent.KEYCODE_ENTER, META_ON},
+ {"HOME key -> Open Home", new int[]{KeyEvent.KEYCODE_HOME}, KeyboardLogEvent.HOME,
+ KeyEvent.KEYCODE_HOME, 0},
+ {"RECENT_APPS key -> Open Overview", new int[]{KeyEvent.KEYCODE_RECENT_APPS},
+ KeyboardLogEvent.RECENT_APPS, KeyEvent.KEYCODE_RECENT_APPS, 0},
+ {"Meta + Tab -> Open OVerview", new int[]{META_KEY, KeyEvent.KEYCODE_TAB},
+ KeyboardLogEvent.RECENT_APPS, KeyEvent.KEYCODE_TAB, META_ON},
+ {"Alt + Tab -> Open Overview", new int[]{ALT_KEY, KeyEvent.KEYCODE_TAB},
+ KeyboardLogEvent.RECENT_APPS, KeyEvent.KEYCODE_TAB, ALT_ON},
+ {"BACK key -> Go back", new int[]{KeyEvent.KEYCODE_BACK}, KeyboardLogEvent.BACK,
+ KeyEvent.KEYCODE_BACK, 0},
+ {"APP_SWITCH key -> Open App switcher", new int[]{KeyEvent.KEYCODE_APP_SWITCH},
+ KeyboardLogEvent.APP_SWITCH, KeyEvent.KEYCODE_APP_SWITCH, 0},
+ {"ASSIST key -> Launch assistant", new int[]{KeyEvent.KEYCODE_ASSIST},
+ KeyboardLogEvent.LAUNCH_ASSISTANT, KeyEvent.KEYCODE_ASSIST, 0},
+ {"Meta + A -> Launch assistant", new int[]{META_KEY, KeyEvent.KEYCODE_A},
+ KeyboardLogEvent.LAUNCH_ASSISTANT, KeyEvent.KEYCODE_A, META_ON},
+ {"VOICE_ASSIST key -> Launch Voice Assistant",
+ new int[]{KeyEvent.KEYCODE_VOICE_ASSIST},
+ KeyboardLogEvent.LAUNCH_VOICE_ASSISTANT, KeyEvent.KEYCODE_VOICE_ASSIST, 0},
+ {"Meta + I -> Launch System Settings", new int[]{META_KEY, KeyEvent.KEYCODE_I},
+ KeyboardLogEvent.LAUNCH_SYSTEM_SETTINGS, KeyEvent.KEYCODE_I, META_ON},
+ {"Meta + N -> Toggle Notification panel", new int[]{META_KEY, KeyEvent.KEYCODE_N},
+ KeyboardLogEvent.TOGGLE_NOTIFICATION_PANEL, KeyEvent.KEYCODE_N, META_ON},
+ {"NOTIFICATION key -> Toggle Notification Panel",
+ new int[]{KeyEvent.KEYCODE_NOTIFICATION},
+ KeyboardLogEvent.TOGGLE_NOTIFICATION_PANEL, KeyEvent.KEYCODE_NOTIFICATION,
+ 0},
+ {"Meta + T -> Toggle Taskbar", new int[]{META_KEY, KeyEvent.KEYCODE_T},
+ KeyboardLogEvent.TOGGLE_TASKBAR, KeyEvent.KEYCODE_T, META_ON},
+ {"Meta + Ctrl + S -> Take Screenshot",
+ new int[]{META_KEY, CTRL_KEY, KeyEvent.KEYCODE_S},
+ KeyboardLogEvent.TAKE_SCREENSHOT, KeyEvent.KEYCODE_S, META_ON | CTRL_ON},
+ {"Meta + / -> Open Shortcut Helper", new int[]{META_KEY, KeyEvent.KEYCODE_SLASH},
+ KeyboardLogEvent.OPEN_SHORTCUT_HELPER, KeyEvent.KEYCODE_SLASH, META_ON},
+ {"BRIGHTNESS_UP key -> Increase Brightness",
+ new int[]{KeyEvent.KEYCODE_BRIGHTNESS_UP}, KeyboardLogEvent.BRIGHTNESS_UP,
+ KeyEvent.KEYCODE_BRIGHTNESS_UP, 0},
+ {"BRIGHTNESS_DOWN key -> Decrease Brightness",
+ new int[]{KeyEvent.KEYCODE_BRIGHTNESS_DOWN},
+ KeyboardLogEvent.BRIGHTNESS_DOWN, KeyEvent.KEYCODE_BRIGHTNESS_DOWN, 0},
+ {"KEYBOARD_BACKLIGHT_UP key -> Increase Keyboard Backlight",
+ new int[]{KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_UP},
+ KeyboardLogEvent.KEYBOARD_BACKLIGHT_UP,
+ KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_UP, 0},
+ {"KEYBOARD_BACKLIGHT_DOWN key -> Decrease Keyboard Backlight",
+ new int[]{KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_DOWN},
+ KeyboardLogEvent.KEYBOARD_BACKLIGHT_DOWN,
+ KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_DOWN, 0},
+ {"KEYBOARD_BACKLIGHT_TOGGLE key -> Toggle Keyboard Backlight",
+ new int[]{KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_TOGGLE},
+ KeyboardLogEvent.KEYBOARD_BACKLIGHT_TOGGLE,
+ KeyEvent.KEYCODE_KEYBOARD_BACKLIGHT_TOGGLE, 0},
+ {"VOLUME_UP key -> Increase Volume", new int[]{KeyEvent.KEYCODE_VOLUME_UP},
+ KeyboardLogEvent.VOLUME_UP, KeyEvent.KEYCODE_VOLUME_UP, 0},
+ {"VOLUME_DOWN key -> Decrease Volume", new int[]{KeyEvent.KEYCODE_VOLUME_DOWN},
+ KeyboardLogEvent.VOLUME_DOWN, KeyEvent.KEYCODE_VOLUME_DOWN, 0},
+ {"VOLUME_MUTE key -> Mute Volume", new int[]{KeyEvent.KEYCODE_VOLUME_MUTE},
+ KeyboardLogEvent.VOLUME_MUTE, KeyEvent.KEYCODE_VOLUME_MUTE, 0},
+ {"ALL_APPS key -> Open App Drawer", new int[]{KeyEvent.KEYCODE_ALL_APPS},
+ KeyboardLogEvent.ALL_APPS, KeyEvent.KEYCODE_ALL_APPS, 0},
+ {"SEARCH key -> Launch Search Activity", new int[]{KeyEvent.KEYCODE_SEARCH},
+ KeyboardLogEvent.LAUNCH_SEARCH, KeyEvent.KEYCODE_SEARCH, 0},
+ {"LANGUAGE_SWITCH key -> Switch Keyboard Language",
+ new int[]{KeyEvent.KEYCODE_LANGUAGE_SWITCH},
+ KeyboardLogEvent.LANGUAGE_SWITCH, KeyEvent.KEYCODE_LANGUAGE_SWITCH, 0},
+ {"Meta + Space -> Switch Keyboard Language",
+ new int[]{META_KEY, KeyEvent.KEYCODE_SPACE},
+ KeyboardLogEvent.LANGUAGE_SWITCH, KeyEvent.KEYCODE_SPACE, META_ON},
+ {"Meta + Shift + Space -> Switch Keyboard Language",
+ new int[]{META_KEY, SHIFT_KEY, KeyEvent.KEYCODE_SPACE},
+ KeyboardLogEvent.LANGUAGE_SWITCH, KeyEvent.KEYCODE_SPACE,
+ META_ON | SHIFT_ON},
+ {"META key -> Open App Drawer in Accessibility mode", new int[]{META_KEY},
+ KeyboardLogEvent.ACCESSIBILITY_ALL_APPS, META_KEY, META_ON},
+ {"Meta + Alt -> Toggle CapsLock", new int[]{META_KEY, ALT_KEY},
+ KeyboardLogEvent.TOGGLE_CAPS_LOCK, ALT_KEY, META_ON | ALT_ON},
+ {"Alt + Meta -> Toggle CapsLock", new int[]{ALT_KEY, META_KEY},
+ KeyboardLogEvent.TOGGLE_CAPS_LOCK, META_KEY, META_ON | ALT_ON},
+ {"CAPS_LOCK key -> Toggle CapsLock", new int[]{KeyEvent.KEYCODE_CAPS_LOCK},
+ KeyboardLogEvent.TOGGLE_CAPS_LOCK, KeyEvent.KEYCODE_CAPS_LOCK, 0},
+ {"MUTE key -> Mute System Microphone", new int[]{KeyEvent.KEYCODE_MUTE},
+ KeyboardLogEvent.SYSTEM_MUTE, KeyEvent.KEYCODE_MUTE, 0},
+ {"Meta + Ctrl + DPAD_UP -> Split screen navigation",
+ new int[]{META_KEY, CTRL_KEY, KeyEvent.KEYCODE_DPAD_UP},
+ KeyboardLogEvent.SPLIT_SCREEN_NAVIGATION, KeyEvent.KEYCODE_DPAD_UP,
+ META_ON | CTRL_ON},
+ {"Meta + Ctrl + DPAD_LEFT -> Split screen navigation",
+ new int[]{META_KEY, CTRL_KEY, KeyEvent.KEYCODE_DPAD_LEFT},
+ KeyboardLogEvent.SPLIT_SCREEN_NAVIGATION, KeyEvent.KEYCODE_DPAD_LEFT,
+ META_ON | CTRL_ON},
+ {"Meta + Ctrl + DPAD_RIGHT -> Split screen navigation",
+ new int[]{META_KEY, CTRL_KEY, KeyEvent.KEYCODE_DPAD_RIGHT},
+ KeyboardLogEvent.SPLIT_SCREEN_NAVIGATION, KeyEvent.KEYCODE_DPAD_RIGHT,
+ META_ON | CTRL_ON},
+ {"Shift + Menu -> Trigger Bug Report", new int[]{SHIFT_KEY, KeyEvent.KEYCODE_MENU},
+ KeyboardLogEvent.TRIGGER_BUG_REPORT, KeyEvent.KEYCODE_MENU, SHIFT_ON},
+ {"Meta + L -> Lock Homescreen", new int[]{META_KEY, KeyEvent.KEYCODE_L},
+ KeyboardLogEvent.LOCK_SCREEN, KeyEvent.KEYCODE_L, META_ON},
+ {"Meta + Ctrl + N -> Open Notes", new int[]{META_KEY, CTRL_KEY, KeyEvent.KEYCODE_N},
+ KeyboardLogEvent.OPEN_NOTES, KeyEvent.KEYCODE_N, META_ON | CTRL_ON},
+ {"POWER key -> Toggle Power", new int[]{KeyEvent.KEYCODE_POWER},
+ KeyboardLogEvent.TOGGLE_POWER, KeyEvent.KEYCODE_POWER, 0},
+ {"TV_POWER key -> Toggle Power", new int[]{KeyEvent.KEYCODE_TV_POWER},
+ KeyboardLogEvent.TOGGLE_POWER, KeyEvent.KEYCODE_TV_POWER, 0},
+ {"SYSTEM_NAVIGATION_DOWN key -> System Navigation",
+ new int[]{KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN},
+ KeyboardLogEvent.SYSTEM_NAVIGATION, KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN,
+ 0},
+ {"SYSTEM_NAVIGATION_UP key -> System Navigation",
+ new int[]{KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP},
+ KeyboardLogEvent.SYSTEM_NAVIGATION, KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP,
+ 0},
+ {"SYSTEM_NAVIGATION_LEFT key -> System Navigation",
+ new int[]{KeyEvent.KEYCODE_SYSTEM_NAVIGATION_LEFT},
+ KeyboardLogEvent.SYSTEM_NAVIGATION, KeyEvent.KEYCODE_SYSTEM_NAVIGATION_LEFT,
+ 0},
+ {"SYSTEM_NAVIGATION_RIGHT key -> System Navigation",
+ new int[]{KeyEvent.KEYCODE_SYSTEM_NAVIGATION_RIGHT},
+ KeyboardLogEvent.SYSTEM_NAVIGATION,
+ KeyEvent.KEYCODE_SYSTEM_NAVIGATION_RIGHT, 0},
+ {"SLEEP key -> System Sleep", new int[]{KeyEvent.KEYCODE_SLEEP},
+ KeyboardLogEvent.SLEEP, KeyEvent.KEYCODE_SLEEP, 0},
+ {"SOFT_SLEEP key -> System Sleep", new int[]{KeyEvent.KEYCODE_SOFT_SLEEP},
+ KeyboardLogEvent.SLEEP, KeyEvent.KEYCODE_SOFT_SLEEP, 0},
+ {"WAKEUP key -> System Wakeup", new int[]{KeyEvent.KEYCODE_WAKEUP},
+ KeyboardLogEvent.WAKEUP, KeyEvent.KEYCODE_WAKEUP, 0},
+ {"MEDIA_PLAY key -> Media Control", new int[]{KeyEvent.KEYCODE_MEDIA_PLAY},
+ KeyboardLogEvent.MEDIA_KEY, KeyEvent.KEYCODE_MEDIA_PLAY, 0},
+ {"MEDIA_PAUSE key -> Media Control", new int[]{KeyEvent.KEYCODE_MEDIA_PAUSE},
+ KeyboardLogEvent.MEDIA_KEY, KeyEvent.KEYCODE_MEDIA_PAUSE, 0},
+ {"MEDIA_PLAY_PAUSE key -> Media Control",
+ new int[]{KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE}, KeyboardLogEvent.MEDIA_KEY,
+ KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, 0},
+ {"Meta + B -> Launch Default Browser", new int[]{META_KEY, KeyEvent.KEYCODE_B},
+ KeyboardLogEvent.LAUNCH_DEFAULT_BROWSER, KeyEvent.KEYCODE_B, META_ON},
+ {"EXPLORER key -> Launch Default Browser", new int[]{KeyEvent.KEYCODE_EXPLORER},
+ KeyboardLogEvent.LAUNCH_DEFAULT_BROWSER, KeyEvent.KEYCODE_EXPLORER, 0},
+ {"Meta + C -> Launch Default Contacts", new int[]{META_KEY, KeyEvent.KEYCODE_C},
+ KeyboardLogEvent.LAUNCH_DEFAULT_CONTACTS, KeyEvent.KEYCODE_C, META_ON},
+ {"CONTACTS key -> Launch Default Contacts", new int[]{KeyEvent.KEYCODE_CONTACTS},
+ KeyboardLogEvent.LAUNCH_DEFAULT_CONTACTS, KeyEvent.KEYCODE_CONTACTS, 0},
+ {"Meta + E -> Launch Default Email", new int[]{META_KEY, KeyEvent.KEYCODE_E},
+ KeyboardLogEvent.LAUNCH_DEFAULT_EMAIL, KeyEvent.KEYCODE_E, META_ON},
+ {"ENVELOPE key -> Launch Default Email", new int[]{KeyEvent.KEYCODE_ENVELOPE},
+ KeyboardLogEvent.LAUNCH_DEFAULT_EMAIL, KeyEvent.KEYCODE_ENVELOPE, 0},
+ {"Meta + K -> Launch Default Calendar", new int[]{META_KEY, KeyEvent.KEYCODE_K},
+ KeyboardLogEvent.LAUNCH_DEFAULT_CALENDAR, KeyEvent.KEYCODE_K, META_ON},
+ {"CALENDAR key -> Launch Default Calendar", new int[]{KeyEvent.KEYCODE_CALENDAR},
+ KeyboardLogEvent.LAUNCH_DEFAULT_CALENDAR, KeyEvent.KEYCODE_CALENDAR, 0},
+ {"Meta + P -> Launch Default Music", new int[]{META_KEY, KeyEvent.KEYCODE_P},
+ KeyboardLogEvent.LAUNCH_DEFAULT_MUSIC, KeyEvent.KEYCODE_P, META_ON},
+ {"MUSIC key -> Launch Default Music", new int[]{KeyEvent.KEYCODE_MUSIC},
+ KeyboardLogEvent.LAUNCH_DEFAULT_MUSIC, KeyEvent.KEYCODE_MUSIC, 0},
+ {"Meta + U -> Launch Default Calculator", new int[]{META_KEY, KeyEvent.KEYCODE_U},
+ KeyboardLogEvent.LAUNCH_DEFAULT_CALCULATOR, KeyEvent.KEYCODE_U, META_ON},
+ {"CALCULATOR key -> Launch Default Calculator",
+ new int[]{KeyEvent.KEYCODE_CALCULATOR},
+ KeyboardLogEvent.LAUNCH_DEFAULT_CALCULATOR, KeyEvent.KEYCODE_CALCULATOR, 0},
+ {"Meta + M -> Launch Default Maps", new int[]{META_KEY, KeyEvent.KEYCODE_M},
+ KeyboardLogEvent.LAUNCH_DEFAULT_MAPS, KeyEvent.KEYCODE_M, META_ON},
+ {"Meta + S -> Launch Default Messaging App",
+ new int[]{META_KEY, KeyEvent.KEYCODE_S},
+ KeyboardLogEvent.LAUNCH_DEFAULT_MESSAGING, KeyEvent.KEYCODE_S, META_ON}};
+ }
+
+ @Before
+ @Override
+ public void setUp() {
+ super.setUp();
+ mPhoneWindowManager.overrideKeyEventSource(VENDOR_ID, PRODUCT_ID);
+ mPhoneWindowManager.overrideLaunchHome();
+ mPhoneWindowManager.overrideSearchKeyBehavior(
+ PhoneWindowManager.SEARCH_BEHAVIOR_TARGET_ACTIVITY);
+ mPhoneWindowManager.overrideEnableBugReportTrigger(true);
+ mPhoneWindowManager.overrideStatusBarManagerInternal();
+ mPhoneWindowManager.overrideStartActivity();
+ mPhoneWindowManager.overrideUserSetupComplete();
+ }
+
+ @Test
+ @Parameters(method = "shortcutTestArguments")
+ public void testShortcuts(String testName, int[] testKeys, KeyboardLogEvent expectedLogEvent,
+ int expectedKey, int expectedModifierState) {
+ sendKeyCombination(testKeys, 0);
+ mPhoneWindowManager.assertShortcutLogged(VENDOR_ID, PRODUCT_ID, expectedLogEvent,
+ expectedKey, expectedModifierState, "Failed while executing " + testName);
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
index 766a88f..1866767 100644
--- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
+++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java
@@ -26,6 +26,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyLong;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.description;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
@@ -35,6 +36,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_POWER_ASSISTANT;
import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_POWER_GLOBAL_ACTIONS;
import static com.android.server.policy.PhoneWindowManager.LONG_PRESS_POWER_GO_TO_VOICE_ASSIST;
@@ -50,7 +52,6 @@
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mockingDetails;
import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.withSettings;
import android.app.ActivityManagerInternal;
@@ -60,8 +61,10 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.hardware.SensorPrivacyManager;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerInternal;
+import android.hardware.input.InputManager;
import android.media.AudioManagerInternal;
import android.os.Handler;
import android.os.HandlerThread;
@@ -75,14 +78,17 @@
import android.telecom.TelecomManager;
import android.util.FeatureFlagUtils;
import android.view.Display;
+import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.autofill.AutofillManagerInternal;
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
import com.android.internal.accessibility.AccessibilityShortcutController;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.server.GestureLauncherService;
import com.android.server.LocalServices;
import com.android.server.input.InputManagerInternal;
+import com.android.server.input.KeyboardMetricsCollector.KeyboardLogEvent;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.pm.UserManagerInternal;
import com.android.server.policy.keyguard.KeyguardServiceDelegate;
@@ -102,6 +108,7 @@
import org.mockito.MockSettings;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import org.mockito.quality.Strictness;
import java.util.function.Supplier;
@@ -117,6 +124,8 @@
@Mock private ActivityManagerInternal mActivityManagerInternal;
@Mock private ActivityTaskManagerInternal mActivityTaskManagerInternal;
@Mock private InputManagerInternal mInputManagerInternal;
+ @Mock private InputManager mInputManager;
+ @Mock private SensorPrivacyManager mSensorPrivacyManager;
@Mock private DreamManagerInternal mDreamManagerInternal;
@Mock private PowerManagerInternal mPowerManagerInternal;
@Mock private DisplayManagerInternal mDisplayManagerInternal;
@@ -186,6 +195,8 @@
// Return mocked services: LocalServices.getService
mMockitoSession = mockitoSession()
.mockStatic(LocalServices.class, spyStubOnly)
+ .mockStatic(FrameworkStatsLog.class)
+ .strictness(Strictness.LENIENT)
.startMocking();
doReturn(mWindowManagerInternal).when(
@@ -213,7 +224,10 @@
doReturn(mAppOpsManager).when(mContext).getSystemService(eq(AppOpsManager.class));
doReturn(mDisplayManager).when(mContext).getSystemService(eq(DisplayManager.class));
+ doReturn(mInputManager).when(mContext).getSystemService(eq(InputManager.class));
doReturn(mPackageManager).when(mContext).getPackageManager();
+ doReturn(mSensorPrivacyManager).when(mContext).getSystemService(
+ eq(SensorPrivacyManager.class));
doReturn(false).when(mPackageManager).hasSystemFeature(any());
try {
doThrow(new PackageManager.NameNotFoundException("test")).when(mPackageManager)
@@ -409,6 +423,31 @@
doReturn(isShowing).when(mKeyguardServiceDelegate).isShowing();
}
+ void overrideKeyEventSource(int vendorId, int productId) {
+ InputDevice device = new InputDevice.Builder().setId(1).setVendorId(vendorId).setProductId(
+ productId).setSources(InputDevice.SOURCE_KEYBOARD).setKeyboardType(
+ InputDevice.KEYBOARD_TYPE_ALPHABETIC).build();
+ doReturn(mInputManager).when(mContext).getSystemService(eq(InputManager.class));
+ doReturn(device).when(mInputManager).getInputDevice(anyInt());
+ }
+
+ void overrideSearchKeyBehavior(int behavior) {
+ mPhoneWindowManager.mSearchKeyBehavior = behavior;
+ }
+
+ void overrideEnableBugReportTrigger(boolean enable) {
+ mPhoneWindowManager.mEnableShiftMenuBugReports = enable;
+ }
+
+ void overrideStartActivity() {
+ doNothing().when(mContext).startActivityAsUser(any(), any());
+ doNothing().when(mContext).startActivityAsUser(any(), any(), any());
+ }
+
+ void overrideUserSetupComplete() {
+ doReturn(true).when(mPhoneWindowManager).isUserSetupComplete();
+ }
+
/**
* Below functions will check the policy behavior could be invoked.
*/
@@ -563,4 +602,12 @@
verify(mContext, after(TEST_SINGLE_KEY_DELAY_MILLIS).never())
.startActivityAsUser(any(Intent.class), any(), any(UserHandle.class));
}
+
+ void assertShortcutLogged(int vendorId, int productId, KeyboardLogEvent logEvent,
+ int expectedKey, int expectedModifierState, String errorMsg) {
+ waitForIdle();
+ verify(() -> FrameworkStatsLog.write(FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED,
+ vendorId, productId, logEvent.getIntValue(), new int[]{expectedKey},
+ expectedModifierState), description(errorMsg));
+ }
}