Loading services/core/java/com/android/server/input/KeyboardMetricsCollector.java +301 −9 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 Loading @@ -56,7 +64,8 @@ public final class KeyboardMetricsCollector { 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; Loading @@ -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); } } /** Loading Loading @@ -328,4 +621,3 @@ public final class KeyboardMetricsCollector { || layoutSelectionCriteria == LAYOUT_SELECTION_CRITERIA_DEFAULT; } } services/core/java/com/android/server/policy/ModifierShortcutManager.java +28 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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(); } Loading Loading @@ -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 Loading Loading @@ -307,6 +317,7 @@ class ModifierShortcutManager { + "keyCode=" + KeyEvent.keyCodeToString(keyCode) + "," + " category=" + category); } logKeyboardShortcut(keyEvent, KeyboardLogEvent.getLogEventFromIntent(intent)); return true; } else { return false; Loading @@ -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} * Loading Loading @@ -360,7 +384,7 @@ class ModifierShortcutManager { } final KeyCharacterMap kcm = event.getKeyCharacterMap(); if (handleIntentShortcut(kcm, keyCode, metaState)) { if (handleIntentShortcut(kcm, event, metaState)) { return true; } Loading services/core/java/com/android/server/policy/PhoneWindowManager.java +83 −19 File changed.Preview size limit exceeded, changes collapsed. Show changes services/tests/wmtests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -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", Loading services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java +1 −1 Original line number Diff line number Diff line Loading @@ -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); Loading Loading
services/core/java/com/android/server/input/KeyboardMetricsCollector.java +301 −9 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 Loading @@ -56,7 +64,8 @@ public final class KeyboardMetricsCollector { 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; Loading @@ -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); } } /** Loading Loading @@ -328,4 +621,3 @@ public final class KeyboardMetricsCollector { || layoutSelectionCriteria == LAYOUT_SELECTION_CRITERIA_DEFAULT; } }
services/core/java/com/android/server/policy/ModifierShortcutManager.java +28 −4 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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(); } Loading Loading @@ -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 Loading Loading @@ -307,6 +317,7 @@ class ModifierShortcutManager { + "keyCode=" + KeyEvent.keyCodeToString(keyCode) + "," + " category=" + category); } logKeyboardShortcut(keyEvent, KeyboardLogEvent.getLogEventFromIntent(intent)); return true; } else { return false; Loading @@ -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} * Loading Loading @@ -360,7 +384,7 @@ class ModifierShortcutManager { } final KeyCharacterMap kcm = event.getKeyCharacterMap(); if (handleIntentShortcut(kcm, keyCode, metaState)) { if (handleIntentShortcut(kcm, event, metaState)) { return true; } Loading
services/core/java/com/android/server/policy/PhoneWindowManager.java +83 −19 File changed.Preview size limit exceeded, changes collapsed. Show changes
services/tests/wmtests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -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", Loading
services/tests/wmtests/src/com/android/server/policy/ShortcutKeyTestBase.java +1 −1 Original line number Diff line number Diff line Loading @@ -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); Loading