Loading services/core/java/com/android/server/policy/ShortcutManager.java→services/core/java/com/android/server/policy/ModifierShortcutManager.java +192 −10 Original line number Diff line number Diff line /* * Copyright (C) 2007 The Android Open Source Project * Copyright (C) 2021 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. Loading @@ -16,18 +16,24 @@ package com.android.server.policy; import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.res.XmlResourceParser; import android.os.RemoteException; import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; import android.util.LongSparseArray; import android.util.Slog; import android.util.SparseArray; import android.view.KeyCharacterMap; import android.view.KeyEvent; import com.android.internal.policy.IShortcutService; import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParser; Loading @@ -39,8 +45,9 @@ import java.io.IOException; * Manages quick launch shortcuts by: * <li> Keeping the local copy in sync with the database (this is an observer) * <li> Returning a shortcut-matching intent to clients * <li> Returning particular kind of application intent by special key. */ class ShortcutManager { class ModifierShortcutManager { private static final String TAG = "ShortcutManager"; private static final String TAG_BOOKMARKS = "bookmarks"; Loading @@ -52,12 +59,39 @@ class ShortcutManager { private static final String ATTRIBUTE_CATEGORY = "category"; private static final String ATTRIBUTE_SHIFT = "shift"; private final SparseArray<ShortcutInfo> mShortcuts = new SparseArray<>(); private final SparseArray<ShortcutInfo> mIntentShortcuts = new SparseArray<>(); private final SparseArray<ShortcutInfo> mShiftShortcuts = new SparseArray<>(); private LongSparseArray<IShortcutService> mShortcutKeyServices = new LongSparseArray<>(); /* Table of Application Launch keys. Maps from key codes to intent categories. * * These are special keys that are used to launch particular kinds of applications, * such as a web browser. HID defines nearly a hundred of them in the Consumer (0x0C) * usage page. We don't support quite that many yet... */ static SparseArray<String> sApplicationLaunchKeyCategories; static { sApplicationLaunchKeyCategories = new SparseArray<String>(); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_EXPLORER, Intent.CATEGORY_APP_BROWSER); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_ENVELOPE, Intent.CATEGORY_APP_EMAIL); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_CONTACTS, Intent.CATEGORY_APP_CONTACTS); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_CALENDAR, Intent.CATEGORY_APP_CALENDAR); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_MUSIC, Intent.CATEGORY_APP_MUSIC); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_CALCULATOR, Intent.CATEGORY_APP_CALCULATOR); } private final Context mContext; private boolean mSearchKeyShortcutPending = false; private boolean mConsumeSearchKeyUp = true; public ShortcutManager(Context context) { ModifierShortcutManager(Context context) { mContext = context; loadShortcuts(); } Loading @@ -77,12 +111,12 @@ class ShortcutManager { * to invoke the shortcut. * @return The intent that matches the shortcut, or null if not found. */ public Intent getIntent(KeyCharacterMap kcm, int keyCode, int metaState) { private Intent getIntent(KeyCharacterMap kcm, int keyCode, int metaState) { ShortcutInfo shortcut = null; // If the Shift key is pressed, then search for the shift shortcuts. boolean isShiftOn = (metaState & KeyEvent.META_SHIFT_ON) == KeyEvent.META_SHIFT_ON; SparseArray<ShortcutInfo> shortcutMap = isShiftOn ? mShiftShortcuts : mShortcuts; SparseArray<ShortcutInfo> shortcutMap = isShiftOn ? mShiftShortcuts : mIntentShortcuts; // First try the exact keycode (with modifiers). int shortcutChar = kcm.get(keyCode, metaState); Loading Loading @@ -176,7 +210,7 @@ class ShortcutManager { if (isShiftShortcut) { mShiftShortcuts.put(shortcutChar, shortcut); } else { mShortcuts.put(shortcutChar, shortcut); mIntentShortcuts.put(shortcutChar, shortcut); } } } catch (XmlPullParserException e) { Loading @@ -186,11 +220,159 @@ class ShortcutManager { } } void registerShortcutKey(long shortcutCode, IShortcutService shortcutService) throws RemoteException { IShortcutService service = mShortcutKeyServices.get(shortcutCode); if (service != null && service.asBinder().pingBinder()) { throw new RemoteException("Key already exists."); } mShortcutKeyServices.put(shortcutCode, shortcutService); } /** * Handle the shortcut to {@link IShortcutService} * @param keyCode The key code of the event. * @param metaState The meta key modifier state. * @return True if invoked the shortcut, otherwise false. */ private boolean handleShortcutService(int keyCode, int metaState) { long shortcutCode = keyCode; if ((metaState & KeyEvent.META_CTRL_ON) != 0) { shortcutCode |= ((long) KeyEvent.META_CTRL_ON) << Integer.SIZE; } if ((metaState & KeyEvent.META_ALT_ON) != 0) { shortcutCode |= ((long) KeyEvent.META_ALT_ON) << Integer.SIZE; } if ((metaState & KeyEvent.META_SHIFT_ON) != 0) { shortcutCode |= ((long) KeyEvent.META_SHIFT_ON) << Integer.SIZE; } if ((metaState & KeyEvent.META_META_ON) != 0) { shortcutCode |= ((long) KeyEvent.META_META_ON) << Integer.SIZE; } IShortcutService shortcutService = mShortcutKeyServices.get(shortcutCode); if (shortcutService != null) { try { shortcutService.notifyShortcutKeyPressed(shortcutCode); } catch (RemoteException e) { mShortcutKeyServices.delete(shortcutCode); } return true; } return false; } /** * 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 metaState The meta key modifier state. * @return True if invoked the shortcut, otherwise false. */ private boolean handleIntentShortcut(KeyCharacterMap kcm, int keyCode, int metaState) { // 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 // inadvertently inserted when using a keyboard that has built-in macro // shortcut keys (that emit Search+x) and some of them are not registered. if (mSearchKeyShortcutPending) { if (kcm.isPrintingKey(keyCode)) { mConsumeSearchKeyUp = true; mSearchKeyShortcutPending = false; } else { return false; } } else if ((metaState & KeyEvent.META_META_MASK) != 0) { // Invoke shortcuts using Meta. metaState &= ~KeyEvent.META_META_MASK; } else { // Handle application launch keys. String category = sApplicationLaunchKeyCategories.get(keyCode); if (category != null) { Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { mContext.startActivityAsUser(intent, UserHandle.CURRENT); } catch (ActivityNotFoundException ex) { Slog.w(TAG, "Dropping application launch key because " + "the activity to which it is registered was not found: " + "keyCode=" + KeyEvent.keyCodeToString(keyCode) + "," + " category=" + category, ex); } return true; } else { return false; } } final Intent shortcutIntent = getIntent(kcm, keyCode, metaState); if (shortcutIntent != null) { shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { mContext.startActivityAsUser(shortcutIntent, UserHandle.CURRENT); } catch (ActivityNotFoundException ex) { Slog.w(TAG, "Dropping shortcut key combination because " + "the activity to which it is registered was not found: " + "META+ or SEARCH" + KeyEvent.keyCodeToString(keyCode), ex); } return true; } return false; } /** * Handle the shortcut from {@link KeyEvent} * * @param event Description of the key event. * @return True if invoked the shortcut, otherwise false. */ boolean interceptKey(KeyEvent event) { if (event.getRepeatCount() != 0) { return false; } final int metaState = event.getModifiers(); final int keyCode = event.getKeyCode(); if (keyCode == KeyEvent.KEYCODE_SEARCH) { if (event.getAction() == KeyEvent.ACTION_DOWN) { mSearchKeyShortcutPending = true; mConsumeSearchKeyUp = false; } else { mSearchKeyShortcutPending = false; if (mConsumeSearchKeyUp) { mConsumeSearchKeyUp = false; return true; } } return false; } if (event.getAction() != KeyEvent.ACTION_DOWN) { return false; } final KeyCharacterMap kcm = event.getKeyCharacterMap(); if (handleIntentShortcut(kcm, keyCode, metaState)) { return true; } if (handleShortcutService(keyCode, metaState)) { return true; } return false; } private static final class ShortcutInfo { public final String title; public final Intent intent; public ShortcutInfo(String title, Intent intent) { ShortcutInfo(String title, Intent intent) { this.title = title; this.intent = intent; } Loading services/core/java/com/android/server/policy/PhoneWindowManager.java +12 −153 Original line number Diff line number Diff line Loading @@ -163,7 +163,6 @@ import android.service.vr.IPersistentVrStateCallbacks; import android.speech.RecognizerIntent; import android.telecom.TelecomManager; import android.util.Log; import android.util.LongSparseArray; import android.util.MutableBoolean; import android.util.PrintWriterPrinter; import android.util.Slog; Loading Loading @@ -318,29 +317,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { */ private boolean mKeyguardDrawnOnce; /* Table of Application Launch keys. Maps from key codes to intent categories. * * These are special keys that are used to launch particular kinds of applications, * such as a web browser. HID defines nearly a hundred of them in the Consumer (0x0C) * usage page. We don't support quite that many yet... */ static SparseArray<String> sApplicationLaunchKeyCategories; static { sApplicationLaunchKeyCategories = new SparseArray<String>(); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_EXPLORER, Intent.CATEGORY_APP_BROWSER); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_ENVELOPE, Intent.CATEGORY_APP_EMAIL); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_CONTACTS, Intent.CATEGORY_APP_CONTACTS); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_CALENDAR, Intent.CATEGORY_APP_CALENDAR); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_MUSIC, Intent.CATEGORY_APP_MUSIC); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_CALCULATOR, Intent.CATEGORY_APP_CALCULATOR); } /** Amount of time (in milliseconds) to wait for windows drawn before powering on. */ static final int WAITING_FOR_DRAWN_TIMEOUT = 1000; Loading Loading @@ -419,8 +395,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mSafeMode; private WindowState mKeyguardCandidate = null; private LongSparseArray<IShortcutService> mShortcutKeyServices = new LongSparseArray<>(); // Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key. // This is for car dock and this is updated from resource. private boolean mEnableCarDockHomeCapture = true; Loading Loading @@ -516,8 +490,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { Intent mCarDockIntent; Intent mDeskDockIntent; Intent mVrHeadsetHomeIntent; boolean mSearchKeyShortcutPending; boolean mConsumeSearchKeyUp; boolean mPendingMetaAction; boolean mPendingCapsLockToggle; Loading Loading @@ -578,7 +550,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { private static final int BRIGHTNESS_STEPS = 10; SettingsObserver mSettingsObserver; ShortcutManager mShortcutManager; ModifierShortcutManager mModifierShortcutManager; PowerManager.WakeLock mBroadcastWakeLock; PowerManager.WakeLock mPowerKeyWakeLock; boolean mHavePendingMediaKeyRepeatWithWakeLock; Loading Loading @@ -1772,7 +1744,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler); mSettingsObserver = new SettingsObserver(mHandler); mSettingsObserver.observe(); mShortcutManager = new ShortcutManager(context); mModifierShortcutManager = new ModifierShortcutManager(context); mUiMode = context.getResources().getInteger( com.android.internal.R.integer.config_defaultUiModeType); mHomeIntent = new Intent(Intent.ACTION_MAIN, null); Loading Loading @@ -2574,6 +2546,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { mPendingCapsLockToggle = false; } if (isUserSetupComplete() && !keyguardOn) { if (mModifierShortcutManager.interceptKey(event)) { dismissKeyboardShortcutsMenu(); mPendingMetaAction = false; mPendingCapsLockToggle = false; return key_consumed; } } switch(keyCode) { case KeyEvent.KEYCODE_HOME: // First we always handle the home key here, so applications Loading @@ -2599,20 +2580,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } break; case KeyEvent.KEYCODE_SEARCH: if (down) { if (repeatCount == 0) { mSearchKeyShortcutPending = true; mConsumeSearchKeyUp = false; } } else { mSearchKeyShortcutPending = false; if (mConsumeSearchKeyUp) { mConsumeSearchKeyUp = false; return key_consumed; } } return 0; case KeyEvent.KEYCODE_APP_SWITCH: if (!keyguardOn) { if (down && repeatCount == 0) { Loading Loading @@ -2820,114 +2787,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { break; } // 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 // inadvertently inserted when using a keyboard that has built-in macro // shortcut keys (that emit Search+x) and some of them are not registered. if (mSearchKeyShortcutPending) { final KeyCharacterMap kcm = event.getKeyCharacterMap(); if (kcm.isPrintingKey(keyCode)) { mConsumeSearchKeyUp = true; mSearchKeyShortcutPending = false; if (down && repeatCount == 0 && !keyguardOn) { Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode, metaState); if (shortcutIntent != null) { shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { startActivityAsUser(shortcutIntent, UserHandle.CURRENT); dismissKeyboardShortcutsMenu(); } catch (ActivityNotFoundException ex) { Slog.w(TAG, "Dropping shortcut key combination because " + "the activity to which it is registered was not found: " + "SEARCH+" + KeyEvent.keyCodeToString(keyCode), ex); } } else { Slog.i(TAG, "Dropping unregistered shortcut key combination: " + "SEARCH+" + KeyEvent.keyCodeToString(keyCode)); } } return key_consumed; } } // Invoke shortcuts using Meta. if (down && repeatCount == 0 && !keyguardOn && (metaState & KeyEvent.META_META_ON) != 0) { final KeyCharacterMap kcm = event.getKeyCharacterMap(); if (kcm.isPrintingKey(keyCode)) { Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode, metaState & ~(KeyEvent.META_META_ON | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON)); if (shortcutIntent != null) { shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { startActivityAsUser(shortcutIntent, UserHandle.CURRENT); dismissKeyboardShortcutsMenu(); } catch (ActivityNotFoundException ex) { Slog.w(TAG, "Dropping shortcut key combination because " + "the activity to which it is registered was not found: " + "META+" + KeyEvent.keyCodeToString(keyCode), ex); } return key_consumed; } } } // Handle application launch keys. if (down && repeatCount == 0 && !keyguardOn) { String category = sApplicationLaunchKeyCategories.get(keyCode); if (category != null) { Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { startActivityAsUser(intent, UserHandle.CURRENT); dismissKeyboardShortcutsMenu(); } catch (ActivityNotFoundException ex) { Slog.w(TAG, "Dropping application launch key because " + "the activity to which it is registered was not found: " + "keyCode=" + keyCode + ", category=" + category, ex); } return key_consumed; } } if (isValidGlobalKey(keyCode) && mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) { return key_consumed; } if (down) { long shortcutCode = keyCode; if (event.isCtrlPressed()) { shortcutCode |= ((long) KeyEvent.META_CTRL_ON) << Integer.SIZE; } if (event.isAltPressed()) { shortcutCode |= ((long) KeyEvent.META_ALT_ON) << Integer.SIZE; } if (event.isShiftPressed()) { shortcutCode |= ((long) KeyEvent.META_SHIFT_ON) << Integer.SIZE; } if (event.isMetaPressed()) { shortcutCode |= ((long) KeyEvent.META_META_ON) << Integer.SIZE; } IShortcutService shortcutService = mShortcutKeyServices.get(shortcutCode); if (shortcutService != null) { try { if (isUserSetupComplete()) { shortcutService.notifyShortcutKeyPressed(shortcutCode); } } catch (RemoteException e) { mShortcutKeyServices.delete(shortcutCode); } return key_consumed; } } // Reserve all the META modifier combos for system behavior if ((metaState & KeyEvent.META_META_ON) != 0) { return key_consumed; Loading Loading @@ -3113,12 +2977,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void registerShortcutKey(long shortcutCode, IShortcutService shortcutService) throws RemoteException { synchronized (mLock) { IShortcutService service = mShortcutKeyServices.get(shortcutCode); if (service != null && service.asBinder().pingBinder()) { throw new RemoteException("Key already exists."); } mShortcutKeyServices.put(shortcutCode, shortcutService); mModifierShortcutManager.registerShortcutKey(shortcutCode, shortcutService); } } Loading Loading
services/core/java/com/android/server/policy/ShortcutManager.java→services/core/java/com/android/server/policy/ModifierShortcutManager.java +192 −10 Original line number Diff line number Diff line /* * Copyright (C) 2007 The Android Open Source Project * Copyright (C) 2021 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. Loading @@ -16,18 +16,24 @@ package com.android.server.policy; import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.res.XmlResourceParser; import android.os.RemoteException; import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; import android.util.LongSparseArray; import android.util.Slog; import android.util.SparseArray; import android.view.KeyCharacterMap; import android.view.KeyEvent; import com.android.internal.policy.IShortcutService; import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParser; Loading @@ -39,8 +45,9 @@ import java.io.IOException; * Manages quick launch shortcuts by: * <li> Keeping the local copy in sync with the database (this is an observer) * <li> Returning a shortcut-matching intent to clients * <li> Returning particular kind of application intent by special key. */ class ShortcutManager { class ModifierShortcutManager { private static final String TAG = "ShortcutManager"; private static final String TAG_BOOKMARKS = "bookmarks"; Loading @@ -52,12 +59,39 @@ class ShortcutManager { private static final String ATTRIBUTE_CATEGORY = "category"; private static final String ATTRIBUTE_SHIFT = "shift"; private final SparseArray<ShortcutInfo> mShortcuts = new SparseArray<>(); private final SparseArray<ShortcutInfo> mIntentShortcuts = new SparseArray<>(); private final SparseArray<ShortcutInfo> mShiftShortcuts = new SparseArray<>(); private LongSparseArray<IShortcutService> mShortcutKeyServices = new LongSparseArray<>(); /* Table of Application Launch keys. Maps from key codes to intent categories. * * These are special keys that are used to launch particular kinds of applications, * such as a web browser. HID defines nearly a hundred of them in the Consumer (0x0C) * usage page. We don't support quite that many yet... */ static SparseArray<String> sApplicationLaunchKeyCategories; static { sApplicationLaunchKeyCategories = new SparseArray<String>(); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_EXPLORER, Intent.CATEGORY_APP_BROWSER); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_ENVELOPE, Intent.CATEGORY_APP_EMAIL); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_CONTACTS, Intent.CATEGORY_APP_CONTACTS); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_CALENDAR, Intent.CATEGORY_APP_CALENDAR); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_MUSIC, Intent.CATEGORY_APP_MUSIC); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_CALCULATOR, Intent.CATEGORY_APP_CALCULATOR); } private final Context mContext; private boolean mSearchKeyShortcutPending = false; private boolean mConsumeSearchKeyUp = true; public ShortcutManager(Context context) { ModifierShortcutManager(Context context) { mContext = context; loadShortcuts(); } Loading @@ -77,12 +111,12 @@ class ShortcutManager { * to invoke the shortcut. * @return The intent that matches the shortcut, or null if not found. */ public Intent getIntent(KeyCharacterMap kcm, int keyCode, int metaState) { private Intent getIntent(KeyCharacterMap kcm, int keyCode, int metaState) { ShortcutInfo shortcut = null; // If the Shift key is pressed, then search for the shift shortcuts. boolean isShiftOn = (metaState & KeyEvent.META_SHIFT_ON) == KeyEvent.META_SHIFT_ON; SparseArray<ShortcutInfo> shortcutMap = isShiftOn ? mShiftShortcuts : mShortcuts; SparseArray<ShortcutInfo> shortcutMap = isShiftOn ? mShiftShortcuts : mIntentShortcuts; // First try the exact keycode (with modifiers). int shortcutChar = kcm.get(keyCode, metaState); Loading Loading @@ -176,7 +210,7 @@ class ShortcutManager { if (isShiftShortcut) { mShiftShortcuts.put(shortcutChar, shortcut); } else { mShortcuts.put(shortcutChar, shortcut); mIntentShortcuts.put(shortcutChar, shortcut); } } } catch (XmlPullParserException e) { Loading @@ -186,11 +220,159 @@ class ShortcutManager { } } void registerShortcutKey(long shortcutCode, IShortcutService shortcutService) throws RemoteException { IShortcutService service = mShortcutKeyServices.get(shortcutCode); if (service != null && service.asBinder().pingBinder()) { throw new RemoteException("Key already exists."); } mShortcutKeyServices.put(shortcutCode, shortcutService); } /** * Handle the shortcut to {@link IShortcutService} * @param keyCode The key code of the event. * @param metaState The meta key modifier state. * @return True if invoked the shortcut, otherwise false. */ private boolean handleShortcutService(int keyCode, int metaState) { long shortcutCode = keyCode; if ((metaState & KeyEvent.META_CTRL_ON) != 0) { shortcutCode |= ((long) KeyEvent.META_CTRL_ON) << Integer.SIZE; } if ((metaState & KeyEvent.META_ALT_ON) != 0) { shortcutCode |= ((long) KeyEvent.META_ALT_ON) << Integer.SIZE; } if ((metaState & KeyEvent.META_SHIFT_ON) != 0) { shortcutCode |= ((long) KeyEvent.META_SHIFT_ON) << Integer.SIZE; } if ((metaState & KeyEvent.META_META_ON) != 0) { shortcutCode |= ((long) KeyEvent.META_META_ON) << Integer.SIZE; } IShortcutService shortcutService = mShortcutKeyServices.get(shortcutCode); if (shortcutService != null) { try { shortcutService.notifyShortcutKeyPressed(shortcutCode); } catch (RemoteException e) { mShortcutKeyServices.delete(shortcutCode); } return true; } return false; } /** * 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 metaState The meta key modifier state. * @return True if invoked the shortcut, otherwise false. */ private boolean handleIntentShortcut(KeyCharacterMap kcm, int keyCode, int metaState) { // 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 // inadvertently inserted when using a keyboard that has built-in macro // shortcut keys (that emit Search+x) and some of them are not registered. if (mSearchKeyShortcutPending) { if (kcm.isPrintingKey(keyCode)) { mConsumeSearchKeyUp = true; mSearchKeyShortcutPending = false; } else { return false; } } else if ((metaState & KeyEvent.META_META_MASK) != 0) { // Invoke shortcuts using Meta. metaState &= ~KeyEvent.META_META_MASK; } else { // Handle application launch keys. String category = sApplicationLaunchKeyCategories.get(keyCode); if (category != null) { Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { mContext.startActivityAsUser(intent, UserHandle.CURRENT); } catch (ActivityNotFoundException ex) { Slog.w(TAG, "Dropping application launch key because " + "the activity to which it is registered was not found: " + "keyCode=" + KeyEvent.keyCodeToString(keyCode) + "," + " category=" + category, ex); } return true; } else { return false; } } final Intent shortcutIntent = getIntent(kcm, keyCode, metaState); if (shortcutIntent != null) { shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { mContext.startActivityAsUser(shortcutIntent, UserHandle.CURRENT); } catch (ActivityNotFoundException ex) { Slog.w(TAG, "Dropping shortcut key combination because " + "the activity to which it is registered was not found: " + "META+ or SEARCH" + KeyEvent.keyCodeToString(keyCode), ex); } return true; } return false; } /** * Handle the shortcut from {@link KeyEvent} * * @param event Description of the key event. * @return True if invoked the shortcut, otherwise false. */ boolean interceptKey(KeyEvent event) { if (event.getRepeatCount() != 0) { return false; } final int metaState = event.getModifiers(); final int keyCode = event.getKeyCode(); if (keyCode == KeyEvent.KEYCODE_SEARCH) { if (event.getAction() == KeyEvent.ACTION_DOWN) { mSearchKeyShortcutPending = true; mConsumeSearchKeyUp = false; } else { mSearchKeyShortcutPending = false; if (mConsumeSearchKeyUp) { mConsumeSearchKeyUp = false; return true; } } return false; } if (event.getAction() != KeyEvent.ACTION_DOWN) { return false; } final KeyCharacterMap kcm = event.getKeyCharacterMap(); if (handleIntentShortcut(kcm, keyCode, metaState)) { return true; } if (handleShortcutService(keyCode, metaState)) { return true; } return false; } private static final class ShortcutInfo { public final String title; public final Intent intent; public ShortcutInfo(String title, Intent intent) { ShortcutInfo(String title, Intent intent) { this.title = title; this.intent = intent; } Loading
services/core/java/com/android/server/policy/PhoneWindowManager.java +12 −153 Original line number Diff line number Diff line Loading @@ -163,7 +163,6 @@ import android.service.vr.IPersistentVrStateCallbacks; import android.speech.RecognizerIntent; import android.telecom.TelecomManager; import android.util.Log; import android.util.LongSparseArray; import android.util.MutableBoolean; import android.util.PrintWriterPrinter; import android.util.Slog; Loading Loading @@ -318,29 +317,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { */ private boolean mKeyguardDrawnOnce; /* Table of Application Launch keys. Maps from key codes to intent categories. * * These are special keys that are used to launch particular kinds of applications, * such as a web browser. HID defines nearly a hundred of them in the Consumer (0x0C) * usage page. We don't support quite that many yet... */ static SparseArray<String> sApplicationLaunchKeyCategories; static { sApplicationLaunchKeyCategories = new SparseArray<String>(); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_EXPLORER, Intent.CATEGORY_APP_BROWSER); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_ENVELOPE, Intent.CATEGORY_APP_EMAIL); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_CONTACTS, Intent.CATEGORY_APP_CONTACTS); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_CALENDAR, Intent.CATEGORY_APP_CALENDAR); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_MUSIC, Intent.CATEGORY_APP_MUSIC); sApplicationLaunchKeyCategories.append( KeyEvent.KEYCODE_CALCULATOR, Intent.CATEGORY_APP_CALCULATOR); } /** Amount of time (in milliseconds) to wait for windows drawn before powering on. */ static final int WAITING_FOR_DRAWN_TIMEOUT = 1000; Loading Loading @@ -419,8 +395,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mSafeMode; private WindowState mKeyguardCandidate = null; private LongSparseArray<IShortcutService> mShortcutKeyServices = new LongSparseArray<>(); // Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key. // This is for car dock and this is updated from resource. private boolean mEnableCarDockHomeCapture = true; Loading Loading @@ -516,8 +490,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { Intent mCarDockIntent; Intent mDeskDockIntent; Intent mVrHeadsetHomeIntent; boolean mSearchKeyShortcutPending; boolean mConsumeSearchKeyUp; boolean mPendingMetaAction; boolean mPendingCapsLockToggle; Loading Loading @@ -578,7 +550,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { private static final int BRIGHTNESS_STEPS = 10; SettingsObserver mSettingsObserver; ShortcutManager mShortcutManager; ModifierShortcutManager mModifierShortcutManager; PowerManager.WakeLock mBroadcastWakeLock; PowerManager.WakeLock mPowerKeyWakeLock; boolean mHavePendingMediaKeyRepeatWithWakeLock; Loading Loading @@ -1772,7 +1744,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mWakeGestureListener = new MyWakeGestureListener(mContext, mHandler); mSettingsObserver = new SettingsObserver(mHandler); mSettingsObserver.observe(); mShortcutManager = new ShortcutManager(context); mModifierShortcutManager = new ModifierShortcutManager(context); mUiMode = context.getResources().getInteger( com.android.internal.R.integer.config_defaultUiModeType); mHomeIntent = new Intent(Intent.ACTION_MAIN, null); Loading Loading @@ -2574,6 +2546,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { mPendingCapsLockToggle = false; } if (isUserSetupComplete() && !keyguardOn) { if (mModifierShortcutManager.interceptKey(event)) { dismissKeyboardShortcutsMenu(); mPendingMetaAction = false; mPendingCapsLockToggle = false; return key_consumed; } } switch(keyCode) { case KeyEvent.KEYCODE_HOME: // First we always handle the home key here, so applications Loading @@ -2599,20 +2580,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } break; case KeyEvent.KEYCODE_SEARCH: if (down) { if (repeatCount == 0) { mSearchKeyShortcutPending = true; mConsumeSearchKeyUp = false; } } else { mSearchKeyShortcutPending = false; if (mConsumeSearchKeyUp) { mConsumeSearchKeyUp = false; return key_consumed; } } return 0; case KeyEvent.KEYCODE_APP_SWITCH: if (!keyguardOn) { if (down && repeatCount == 0) { Loading Loading @@ -2820,114 +2787,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { break; } // 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 // inadvertently inserted when using a keyboard that has built-in macro // shortcut keys (that emit Search+x) and some of them are not registered. if (mSearchKeyShortcutPending) { final KeyCharacterMap kcm = event.getKeyCharacterMap(); if (kcm.isPrintingKey(keyCode)) { mConsumeSearchKeyUp = true; mSearchKeyShortcutPending = false; if (down && repeatCount == 0 && !keyguardOn) { Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode, metaState); if (shortcutIntent != null) { shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { startActivityAsUser(shortcutIntent, UserHandle.CURRENT); dismissKeyboardShortcutsMenu(); } catch (ActivityNotFoundException ex) { Slog.w(TAG, "Dropping shortcut key combination because " + "the activity to which it is registered was not found: " + "SEARCH+" + KeyEvent.keyCodeToString(keyCode), ex); } } else { Slog.i(TAG, "Dropping unregistered shortcut key combination: " + "SEARCH+" + KeyEvent.keyCodeToString(keyCode)); } } return key_consumed; } } // Invoke shortcuts using Meta. if (down && repeatCount == 0 && !keyguardOn && (metaState & KeyEvent.META_META_ON) != 0) { final KeyCharacterMap kcm = event.getKeyCharacterMap(); if (kcm.isPrintingKey(keyCode)) { Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode, metaState & ~(KeyEvent.META_META_ON | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON)); if (shortcutIntent != null) { shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { startActivityAsUser(shortcutIntent, UserHandle.CURRENT); dismissKeyboardShortcutsMenu(); } catch (ActivityNotFoundException ex) { Slog.w(TAG, "Dropping shortcut key combination because " + "the activity to which it is registered was not found: " + "META+" + KeyEvent.keyCodeToString(keyCode), ex); } return key_consumed; } } } // Handle application launch keys. if (down && repeatCount == 0 && !keyguardOn) { String category = sApplicationLaunchKeyCategories.get(keyCode); if (category != null) { Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { startActivityAsUser(intent, UserHandle.CURRENT); dismissKeyboardShortcutsMenu(); } catch (ActivityNotFoundException ex) { Slog.w(TAG, "Dropping application launch key because " + "the activity to which it is registered was not found: " + "keyCode=" + keyCode + ", category=" + category, ex); } return key_consumed; } } if (isValidGlobalKey(keyCode) && mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) { return key_consumed; } if (down) { long shortcutCode = keyCode; if (event.isCtrlPressed()) { shortcutCode |= ((long) KeyEvent.META_CTRL_ON) << Integer.SIZE; } if (event.isAltPressed()) { shortcutCode |= ((long) KeyEvent.META_ALT_ON) << Integer.SIZE; } if (event.isShiftPressed()) { shortcutCode |= ((long) KeyEvent.META_SHIFT_ON) << Integer.SIZE; } if (event.isMetaPressed()) { shortcutCode |= ((long) KeyEvent.META_META_ON) << Integer.SIZE; } IShortcutService shortcutService = mShortcutKeyServices.get(shortcutCode); if (shortcutService != null) { try { if (isUserSetupComplete()) { shortcutService.notifyShortcutKeyPressed(shortcutCode); } } catch (RemoteException e) { mShortcutKeyServices.delete(shortcutCode); } return key_consumed; } } // Reserve all the META modifier combos for system behavior if ((metaState & KeyEvent.META_META_ON) != 0) { return key_consumed; Loading Loading @@ -3113,12 +2977,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { public void registerShortcutKey(long shortcutCode, IShortcutService shortcutService) throws RemoteException { synchronized (mLock) { IShortcutService service = mShortcutKeyServices.get(shortcutCode); if (service != null && service.asBinder().pingBinder()) { throw new RemoteException("Key already exists."); } mShortcutKeyServices.put(shortcutCode, shortcutService); mModifierShortcutManager.registerShortcutKey(shortcutCode, shortcutService); } } Loading