Log system keys and shortcuts
Test: atest ShortcutLoggingTests Bug: 280423320 Change-Id: I22ca8cca9f3ea42625b1c406eec51ebeebc17cec
This commit is contained in:
@@ -21,12 +21,16 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
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 com.android.internal.util.FrameworkStatsLog;
|
||||
|
||||
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 @@ public final class KeyboardMetricsCollector {
|
||||
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 @@ public final class KeyboardMetricsCollector {
|
||||
@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 @@ public final class KeyboardMetricsCollector {
|
||||
* {@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 @@ public final class KeyboardMetricsCollector {
|
||||
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 @@ public final class KeyboardMetricsCollector {
|
||||
|| layoutSelectionCriteria == LAYOUT_SELECTION_CRITERIA_DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.Intent;
|
||||
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.Log;
|
||||
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 @@ class ModifierShortcutManager {
|
||||
}
|
||||
|
||||
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 @@ class ModifierShortcutManager {
|
||||
* 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 @@ class ModifierShortcutManager {
|
||||
+ "keyCode=" + KeyEvent.keyCodeToString(keyCode) + ","
|
||||
+ " category=" + category);
|
||||
}
|
||||
logKeyboardShortcut(keyEvent, KeyboardLogEvent.getLogEventFromIntent(intent));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -323,11 +334,24 @@ class ModifierShortcutManager {
|
||||
+ "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 @@ class ModifierShortcutManager {
|
||||
}
|
||||
|
||||
final KeyCharacterMap kcm = event.getKeyCharacterMap();
|
||||
if (handleIntentShortcut(kcm, keyCode, metaState)) {
|
||||
if (handleIntentShortcut(kcm, event, metaState)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -219,6 +219,7 @@ import com.android.server.UiThread;
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
ActivityManagerInternal mActivityManagerInternal;
|
||||
ActivityTaskManagerInternal mActivityTaskManagerInternal;
|
||||
AutofillManagerInternal mAutofillManagerInternal;
|
||||
InputManager mInputManager;
|
||||
InputManagerInternal mInputManagerInternal;
|
||||
DreamManagerInternal mDreamManagerInternal;
|
||||
PowerManagerInternal mPowerManagerInternal;
|
||||
@@ -762,7 +764,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
}
|
||||
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
// 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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
* 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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
preloadRecentApps();
|
||||
} else if (!down) {
|
||||
toggleRecentApps();
|
||||
logKeyboardSystemsEvent(event, KeyboardLogEvent.APP_SWITCH);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -3080,6 +3099,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
|
||||
if (statusbar != null) {
|
||||
statusbar.goToFullscreenFromSplit();
|
||||
logKeyboardSystemsEvent(event, KeyboardLogEvent.SPLIT_SCREEN_NAVIGATION);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -3135,18 +3162,21 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
shiftlessModifiers, KeyEvent.META_ALT_ON)) {
|
||||
mRecentAppsHeldModifiers = shiftlessModifiers;
|
||||
showRecentApps(true);
|
||||
logKeyboardSystemsEvent(event, KeyboardLogEvent.RECENT_APPS);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -3273,11 +3311,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
switch (mSearchKeyBehavior) {
|
||||
case SEARCH_BEHAVIOR_TARGET_ACTIVITY: {
|
||||
launchTargetSearchActivity();
|
||||
logKeyboardSystemsEvent(event, KeyboardLogEvent.LAUNCH_SEARCH);
|
||||
return true;
|
||||
}
|
||||
case SEARCH_BEHAVIOR_DEFAULT_SEARCH:
|
||||
@@ -3297,6 +3338,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
// Handle special keys.
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_BACK: {
|
||||
logKeyboardSystemsEventOnActionUp(event, KeyboardLogEvent.BACK);
|
||||
if (down) {
|
||||
mBackKeyHandled = false;
|
||||
} else {
|
||||
@@ -4217,6 +4269,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
}
|
||||
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
}
|
||||
|
||||
case KeyEvent.KEYCODE_POWER: {
|
||||
logKeyboardSystemsEventOnActionUp(event, KeyboardLogEvent.TOGGLE_POWER);
|
||||
EventLogTags.writeInterceptPower(
|
||||
KeyEvent.actionToString(event.getAction()),
|
||||
mPowerKeyHandled ? 1 : 0,
|
||||
@@ -4348,12 +4404,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
}
|
||||
|
||||
case KeyEvent.KEYCODE_SOFT_SLEEP: {
|
||||
logKeyboardSystemsEventOnActionUp(event, KeyboardLogEvent.SLEEP);
|
||||
result &= ~ACTION_PASS_TO_USER;
|
||||
isWakeKey = false;
|
||||
if (!down) {
|
||||
@@ -4377,6 +4436,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
}
|
||||
|
||||
case KeyEvent.KEYCODE_WAKEUP: {
|
||||
logKeyboardSystemsEventOnActionUp(event, KeyboardLogEvent.WAKEUP);
|
||||
result &= ~ACTION_PASS_TO_USER;
|
||||
isWakeKey = true;
|
||||
break;
|
||||
@@ -4385,6 +4445,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
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 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
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;
|
||||
|
||||
@@ -51,6 +51,7 @@ android_test {
|
||||
"services.core",
|
||||
"androidx.test.runner",
|
||||
"androidx.test.rules",
|
||||
"junit-params",
|
||||
"mockito-target-extended-minus-junit4",
|
||||
"platform-test-annotations",
|
||||
"servicestests-utils",
|
||||
|
||||
@@ -63,7 +63,7 @@ class ShortcutKeyTestBase {
|
||||
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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
|
||||
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.never;
|
||||
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.after;
|
||||
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.app.SearchManager;
|
||||
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.service.dreams.DreamManagerInternal;
|
||||
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.Mock;
|
||||
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 @@ class TestPhoneWindowManager {
|
||||
@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 @@ class TestPhoneWindowManager {
|
||||
// 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 @@ class TestPhoneWindowManager {
|
||||
|
||||
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 @@ class TestPhoneWindowManager {
|
||||
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 @@ class TestPhoneWindowManager {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user