Merge "Log system keys and shortcuts" into udc-qpr-dev

This commit is contained in:
Vaibhav Devmurari
2023-07-20 15:38:26 +00:00
committed by Android (Google) Code Review
7 changed files with 708 additions and 35 deletions

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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",

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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));
}
}