From e631e32a1a771a36267af3f8af8b64e9365bc19e Mon Sep 17 00:00:00 2001 From: Peeyush Agarwal Date: Wed, 19 Oct 2016 11:41:42 +0100 Subject: [PATCH] Extend MenuItem to allow modifier keys for shortcut Before this, CTRL was the default modifier for MenuItem shortcuts. Now, It's possible to specify the modifier in XML or via MenuItem methods. The modifier list includes META, CTRL, ALT, SHIFT, SYM and FUNCTION. WIP on support library implementation Bug: 32165848 Test: Run the tests using following commands: > cts-tradefed run cts-dev -m CtsViewTestCases -t > android.view.cts.MenuTest#testPerformShortcut > cts-tradefed run cts-dev -m CtsViewTestCases -t > android.view.cts.MenuInflaterTest#testInflateShortcutModifiersFromXml Change-Id: I7db4607d4657451934761914efe4c250de109653 --- api/current.txt | 8 ++ api/system-current.txt | 8 ++ api/test-current.txt | 8 ++ core/java/android/app/Activity.java | 3 +- core/java/android/view/Menu.java | 7 + core/java/android/view/MenuInflater.java | 12 +- core/java/android/view/MenuItem.java | 130 ++++++++++++++++-- core/java/android/view/ViewRootImpl.java | 4 +- .../internal/view/menu/ActionMenu.java | 12 +- .../internal/view/menu/ActionMenuItem.java | 34 ++++- .../internal/view/menu/MenuBuilder.java | 12 +- .../internal/view/menu/MenuItemImpl.java | 58 +++++++- core/res/res/values/attrs.xml | 22 +++ core/res/res/values/public.xml | 2 + 14 files changed, 292 insertions(+), 28 deletions(-) diff --git a/api/current.txt b/api/current.txt index d7721819e404d..93aa23c413cac 100644 --- a/api/current.txt +++ b/api/current.txt @@ -268,6 +268,7 @@ package android { field public static final int allowTaskReparenting = 16843268; // 0x1010204 field public static final int allowUndo = 16843999; // 0x10104df field public static final int alpha = 16843551; // 0x101031f + field public static final int alphabeticModifiers = 16844112; // 0x1010550 field public static final int alphabeticShortcut = 16843235; // 0x10101e3 field public static final int alwaysDrawnWithCache = 16842991; // 0x10100ef field public static final int alwaysRetainTaskState = 16843267; // 0x1010203 @@ -922,6 +923,7 @@ package android { field public static final int numbersSelectorColor = 16843939; // 0x10104a3 field public static final int numbersTextColor = 16843937; // 0x10104a1 field public static final deprecated int numeric = 16843109; // 0x1010165 + field public static final int numericModifiers = 16844113; // 0x1010551 field public static final int numericShortcut = 16843236; // 0x10101e4 field public static final int offset = 16844052; // 0x1010514 field public static final int onClick = 16843375; // 0x101026f @@ -43832,6 +43834,7 @@ package android.view { field public static final int FLAG_APPEND_TO_GROUP = 1; // 0x1 field public static final int FLAG_PERFORM_NO_CLOSE = 1; // 0x1 field public static final int NONE = 0; // 0x0 + field public static final int SUPPORTED_MODIFIERS_MASK = 69647; // 0x1100f } public class MenuInflater { @@ -43844,6 +43847,7 @@ package android.view { method public abstract boolean expandActionView(); method public abstract android.view.ActionProvider getActionProvider(); method public abstract android.view.View getActionView(); + method public default int getAlphabeticModifiers(); method public abstract char getAlphabeticShortcut(); method public default java.lang.CharSequence getContentDescription(); method public abstract int getGroupId(); @@ -43851,6 +43855,7 @@ package android.view { method public abstract android.content.Intent getIntent(); method public abstract int getItemId(); method public abstract android.view.ContextMenu.ContextMenuInfo getMenuInfo(); + method public default int getNumericModifiers(); method public abstract char getNumericShortcut(); method public abstract int getOrder(); method public abstract android.view.SubMenu getSubMenu(); @@ -43867,6 +43872,7 @@ package android.view { method public abstract android.view.MenuItem setActionView(android.view.View); method public abstract android.view.MenuItem setActionView(int); method public abstract android.view.MenuItem setAlphabeticShortcut(char); + method public default android.view.MenuItem setAlphabeticShortcut(char, int); method public abstract android.view.MenuItem setCheckable(boolean); method public abstract android.view.MenuItem setChecked(boolean); method public default android.view.MenuItem setContentDescription(java.lang.CharSequence); @@ -43875,9 +43881,11 @@ package android.view { method public abstract android.view.MenuItem setIcon(int); method public abstract android.view.MenuItem setIntent(android.content.Intent); method public abstract android.view.MenuItem setNumericShortcut(char); + method public default android.view.MenuItem setNumericShortcut(char, int); method public abstract android.view.MenuItem setOnActionExpandListener(android.view.MenuItem.OnActionExpandListener); method public abstract android.view.MenuItem setOnMenuItemClickListener(android.view.MenuItem.OnMenuItemClickListener); method public abstract android.view.MenuItem setShortcut(char, char); + method public default android.view.MenuItem setShortcut(char, char, int, int); method public abstract void setShowAsAction(int); method public abstract android.view.MenuItem setShowAsActionFlags(int); method public abstract android.view.MenuItem setTitle(java.lang.CharSequence); diff --git a/api/system-current.txt b/api/system-current.txt index 6affa7fea40f5..56c227e4fa9be 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -380,6 +380,7 @@ package android { field public static final int allowTaskReparenting = 16843268; // 0x1010204 field public static final int allowUndo = 16843999; // 0x10104df field public static final int alpha = 16843551; // 0x101031f + field public static final int alphabeticModifiers = 16844112; // 0x1010550 field public static final int alphabeticShortcut = 16843235; // 0x10101e3 field public static final int alwaysDrawnWithCache = 16842991; // 0x10100ef field public static final int alwaysRetainTaskState = 16843267; // 0x1010203 @@ -1034,6 +1035,7 @@ package android { field public static final int numbersSelectorColor = 16843939; // 0x10104a3 field public static final int numbersTextColor = 16843937; // 0x10104a1 field public static final deprecated int numeric = 16843109; // 0x1010165 + field public static final int numericModifiers = 16844113; // 0x1010551 field public static final int numericShortcut = 16843236; // 0x10101e4 field public static final int offset = 16844052; // 0x1010514 field public static final int onClick = 16843375; // 0x101026f @@ -47239,6 +47241,7 @@ package android.view { field public static final int FLAG_APPEND_TO_GROUP = 1; // 0x1 field public static final int FLAG_PERFORM_NO_CLOSE = 1; // 0x1 field public static final int NONE = 0; // 0x0 + field public static final int SUPPORTED_MODIFIERS_MASK = 69647; // 0x1100f } public class MenuInflater { @@ -47251,6 +47254,7 @@ package android.view { method public abstract boolean expandActionView(); method public abstract android.view.ActionProvider getActionProvider(); method public abstract android.view.View getActionView(); + method public default int getAlphabeticModifiers(); method public abstract char getAlphabeticShortcut(); method public default java.lang.CharSequence getContentDescription(); method public abstract int getGroupId(); @@ -47258,6 +47262,7 @@ package android.view { method public abstract android.content.Intent getIntent(); method public abstract int getItemId(); method public abstract android.view.ContextMenu.ContextMenuInfo getMenuInfo(); + method public default int getNumericModifiers(); method public abstract char getNumericShortcut(); method public abstract int getOrder(); method public abstract android.view.SubMenu getSubMenu(); @@ -47274,6 +47279,7 @@ package android.view { method public abstract android.view.MenuItem setActionView(android.view.View); method public abstract android.view.MenuItem setActionView(int); method public abstract android.view.MenuItem setAlphabeticShortcut(char); + method public default android.view.MenuItem setAlphabeticShortcut(char, int); method public abstract android.view.MenuItem setCheckable(boolean); method public abstract android.view.MenuItem setChecked(boolean); method public default android.view.MenuItem setContentDescription(java.lang.CharSequence); @@ -47282,9 +47288,11 @@ package android.view { method public abstract android.view.MenuItem setIcon(int); method public abstract android.view.MenuItem setIntent(android.content.Intent); method public abstract android.view.MenuItem setNumericShortcut(char); + method public default android.view.MenuItem setNumericShortcut(char, int); method public abstract android.view.MenuItem setOnActionExpandListener(android.view.MenuItem.OnActionExpandListener); method public abstract android.view.MenuItem setOnMenuItemClickListener(android.view.MenuItem.OnMenuItemClickListener); method public abstract android.view.MenuItem setShortcut(char, char); + method public default android.view.MenuItem setShortcut(char, char, int, int); method public abstract void setShowAsAction(int); method public abstract android.view.MenuItem setShowAsActionFlags(int); method public abstract android.view.MenuItem setTitle(java.lang.CharSequence); diff --git a/api/test-current.txt b/api/test-current.txt index bbb7f898d201a..a41ab92028722 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -268,6 +268,7 @@ package android { field public static final int allowTaskReparenting = 16843268; // 0x1010204 field public static final int allowUndo = 16843999; // 0x10104df field public static final int alpha = 16843551; // 0x101031f + field public static final int alphabeticModifiers = 16844112; // 0x1010550 field public static final int alphabeticShortcut = 16843235; // 0x10101e3 field public static final int alwaysDrawnWithCache = 16842991; // 0x10100ef field public static final int alwaysRetainTaskState = 16843267; // 0x1010203 @@ -922,6 +923,7 @@ package android { field public static final int numbersSelectorColor = 16843939; // 0x10104a3 field public static final int numbersTextColor = 16843937; // 0x10104a1 field public static final deprecated int numeric = 16843109; // 0x1010165 + field public static final int numericModifiers = 16844113; // 0x1010551 field public static final int numericShortcut = 16843236; // 0x10101e4 field public static final int offset = 16844052; // 0x1010514 field public static final int onClick = 16843375; // 0x101026f @@ -44136,6 +44138,7 @@ package android.view { field public static final int FLAG_APPEND_TO_GROUP = 1; // 0x1 field public static final int FLAG_PERFORM_NO_CLOSE = 1; // 0x1 field public static final int NONE = 0; // 0x0 + field public static final int SUPPORTED_MODIFIERS_MASK = 69647; // 0x1100f } public class MenuInflater { @@ -44148,6 +44151,7 @@ package android.view { method public abstract boolean expandActionView(); method public abstract android.view.ActionProvider getActionProvider(); method public abstract android.view.View getActionView(); + method public default int getAlphabeticModifiers(); method public abstract char getAlphabeticShortcut(); method public default java.lang.CharSequence getContentDescription(); method public abstract int getGroupId(); @@ -44155,6 +44159,7 @@ package android.view { method public abstract android.content.Intent getIntent(); method public abstract int getItemId(); method public abstract android.view.ContextMenu.ContextMenuInfo getMenuInfo(); + method public default int getNumericModifiers(); method public abstract char getNumericShortcut(); method public abstract int getOrder(); method public abstract android.view.SubMenu getSubMenu(); @@ -44171,6 +44176,7 @@ package android.view { method public abstract android.view.MenuItem setActionView(android.view.View); method public abstract android.view.MenuItem setActionView(int); method public abstract android.view.MenuItem setAlphabeticShortcut(char); + method public default android.view.MenuItem setAlphabeticShortcut(char, int); method public abstract android.view.MenuItem setCheckable(boolean); method public abstract android.view.MenuItem setChecked(boolean); method public default android.view.MenuItem setContentDescription(java.lang.CharSequence); @@ -44179,9 +44185,11 @@ package android.view { method public abstract android.view.MenuItem setIcon(int); method public abstract android.view.MenuItem setIntent(android.content.Intent); method public abstract android.view.MenuItem setNumericShortcut(char); + method public default android.view.MenuItem setNumericShortcut(char, int); method public abstract android.view.MenuItem setOnActionExpandListener(android.view.MenuItem.OnActionExpandListener); method public abstract android.view.MenuItem setOnMenuItemClickListener(android.view.MenuItem.OnMenuItemClickListener); method public abstract android.view.MenuItem setShortcut(char, char); + method public default android.view.MenuItem setShortcut(char, char, int, int); method public abstract void setShowAsAction(int); method public abstract android.view.MenuItem setShowAsActionFlags(int); method public abstract android.view.MenuItem setTitle(java.lang.CharSequence); diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 6f9530901d821..abf8d32d5b085 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -1744,13 +1744,14 @@ public class Activity extends ContextThemeWrapper final MenuItem item = menu.getItem(i); final CharSequence title = item.getTitle(); final char alphaShortcut = item.getAlphabeticShortcut(); + final int alphaModifiers = item.getAlphabeticModifiers(); if (title != null && alphaShortcut != MIN_VALUE) { if (group == null) { final int resource = mApplication.getApplicationInfo().labelRes; group = new KeyboardShortcutGroup(resource != 0 ? getString(resource) : null); } group.addItem(new KeyboardShortcutInfo( - title, alphaShortcut, KeyEvent.META_CTRL_ON)); + title, alphaShortcut, alphaModifiers)); } } if (group != null) { diff --git a/core/java/android/view/Menu.java b/core/java/android/view/Menu.java index 0c2e9cff81baa..a8ea4dc1b8a0d 100644 --- a/core/java/android/view/Menu.java +++ b/core/java/android/view/Menu.java @@ -74,6 +74,13 @@ public interface Menu { */ static final int CATEGORY_SHIFT = 16; + /** + * A mask of all supported modifiers for MenuItem's keyboard shortcuts + */ + static final int SUPPORTED_MODIFIERS_MASK = KeyEvent.META_META_ON | KeyEvent.META_CTRL_ON + | KeyEvent.META_ALT_ON | KeyEvent.META_SHIFT_ON | KeyEvent.META_SYM_ON + | KeyEvent.META_FUNCTION_ON; + /** * Value to use for group and item identifier integers when you don't care * about them. diff --git a/core/java/android/view/MenuInflater.java b/core/java/android/view/MenuInflater.java index 7a5c65f6a87ef..6574bc0a1db82 100644 --- a/core/java/android/view/MenuInflater.java +++ b/core/java/android/view/MenuInflater.java @@ -305,7 +305,9 @@ public class MenuInflater { private CharSequence itemTitleCondensed; private int itemIconResId; private char itemAlphabeticShortcut; + private int itemAlphabeticModifiers; private char itemNumericShortcut; + private int itemNumericModifiers; /** * Sync to attrs.xml enum: * - 0: none @@ -395,8 +397,14 @@ public class MenuInflater { itemIconResId = a.getResourceId(com.android.internal.R.styleable.MenuItem_icon, 0); itemAlphabeticShortcut = getShortcut(a.getString(com.android.internal.R.styleable.MenuItem_alphabeticShortcut)); + itemAlphabeticModifiers = + a.getInt(com.android.internal.R.styleable.MenuItem_alphabeticModifiers, + KeyEvent.META_CTRL_ON); itemNumericShortcut = getShortcut(a.getString(com.android.internal.R.styleable.MenuItem_numericShortcut)); + itemNumericModifiers = + a.getInt(com.android.internal.R.styleable.MenuItem_numericModifiers, + KeyEvent.META_CTRL_ON); if (a.hasValue(com.android.internal.R.styleable.MenuItem_checkable)) { // Item has attribute checkable, use it itemCheckable = a.getBoolean(com.android.internal.R.styleable.MenuItem_checkable, false) ? 1 : 0; @@ -451,8 +459,8 @@ public class MenuInflater { .setCheckable(itemCheckable >= 1) .setTitleCondensed(itemTitleCondensed) .setIcon(itemIconResId) - .setAlphabeticShortcut(itemAlphabeticShortcut) - .setNumericShortcut(itemNumericShortcut); + .setAlphabeticShortcut(itemAlphabeticShortcut, itemAlphabeticModifiers) + .setNumericShortcut(itemNumericShortcut, itemNumericModifiers); if (itemShowAsAction >= 0) { item.setShowAsAction(itemShowAsAction); diff --git a/core/java/android/view/MenuItem.java b/core/java/android/view/MenuItem.java index 3f8d08937a777..6aaaedbeb1af5 100644 --- a/core/java/android/view/MenuItem.java +++ b/core/java/android/view/MenuItem.java @@ -261,12 +261,13 @@ public interface MenuItem { /** * Change both the numeric and alphabetic shortcut associated with this * item. Note that the shortcut will be triggered when the key that - * generates the given character is pressed along with the ctrl key. - * Also note that case is not significant and that alphabetic shortcut - * characters will be displayed in lower case. + * generates the given character is pressed along with the corresponding + * modifier key. The default modifier is {@link KeyEvent#META_CTRL_ON} in + * case nothing is specified. Also note that case is not significant and + * that alphabetic shortcut characters will be handled in lower case. *

* See {@link Menu} for the menu types that support shortcuts. - * + * * @param numericChar The numeric shortcut key. This is the shortcut when * using a numeric (e.g., 12-key) keyboard. * @param alphaChar The alphabetic shortcut key. This is the shortcut when @@ -275,6 +276,39 @@ public interface MenuItem { */ public MenuItem setShortcut(char numericChar, char alphaChar); + /** + * Change both the numeric and alphabetic shortcut associated with this + * item. Note that the shortcut will be triggered when the key that + * generates the given character is pressed along with the corresponding + * modifier key. Also note that case is not significant and that alphabetic + * shortcut characters will be handled in lower case. + *

+ * See {@link Menu} for the menu types that support shortcuts. + * + * @param numericChar The numeric shortcut key. This is the shortcut when + * using a numeric (e.g., 12-key) keyboard. + * @param numericModifiers The numeric modifier associated with the shortcut. It should + * be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON}, + * {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON}, + * {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}. + * @param alphaChar The alphabetic shortcut key. This is the shortcut when + * using a keyboard with alphabetic keys. + * @param alphaModifiers The alphabetic modifier associated with the shortcut. It should + * be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON}, + * {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON}, + * {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}. + * @return This Item so additional setters can be called. + */ + default public MenuItem setShortcut(char numericChar, char alphaChar, int numericModifiers, + int alphaModifiers) { + if ((alphaModifiers & Menu.SUPPORTED_MODIFIERS_MASK) == KeyEvent.META_CTRL_ON + && (numericModifiers & Menu.SUPPORTED_MODIFIERS_MASK) == KeyEvent.META_CTRL_ON) { + return setShortcut(numericChar, alphaChar); + } else { + return this; + } + } + /** * Change the numeric shortcut associated with this item. *

@@ -286,6 +320,27 @@ public interface MenuItem { */ public MenuItem setNumericShortcut(char numericChar); + /** + * Change the numeric shortcut and modifiers associated with this item. + *

+ * See {@link Menu} for the menu types that support shortcuts. + * + * @param numericChar The numeric shortcut key. This is the shortcut when + * using a 12-key (numeric) keyboard. + * @param numericModifiers The modifier associated with the shortcut. It should + * be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON}, + * {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON}, + * {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}. + * @return This Item so additional setters can be called. + */ + default public MenuItem setNumericShortcut(char numericChar, int numericModifiers) { + if ((numericModifiers & Menu.SUPPORTED_MODIFIERS_MASK) == KeyEvent.META_CTRL_ON) { + return setNumericShortcut(numericChar); + } else { + return this; + } + } + /** * Return the char for this menu item's numeric (12-key) shortcut. * @@ -293,22 +348,63 @@ public interface MenuItem { */ public char getNumericShortcut(); + /** + * Return the modifiers for this menu item's numeric (12-key) shortcut. + * The modifier is a combination of {@link KeyEvent#META_META_ON}, + * {@link KeyEvent#META_CTRL_ON}, {@link KeyEvent#META_ALT_ON}, + * {@link KeyEvent#META_SHIFT_ON}, {@link KeyEvent#META_SYM_ON}, + * {@link KeyEvent#META_FUNCTION_ON}. + * For example, {@link KeyEvent#META_FUNCTION_ON}|{@link KeyEvent#META_CTRL_ON} + * + * @return Modifier associated with the numeric shortcut. + */ + default public int getNumericModifiers() { + return KeyEvent.META_CTRL_ON; + } + /** * Change the alphabetic shortcut associated with this item. The shortcut * will be triggered when the key that generates the given character is - * pressed along with the ctrl key. Case is not significant and shortcut - * characters will be displayed in lower case. Note that menu items with - * the characters '\b' or '\n' as shortcuts will get triggered by the - * Delete key or Carriage Return key, respectively. + * pressed along with the corresponding modifier key. The default modifier + * is {@link KeyEvent#META_CTRL_ON} in case nothing is specified. Case is + * not significant and shortcut characters will be displayed in lower case. + * Note that menu items with the characters '\b' or '\n' as shortcuts will + * get triggered by the Delete key or Carriage Return key, respectively. *

* See {@link Menu} for the menu types that support shortcuts. - * + * * @param alphaChar The alphabetic shortcut key. This is the shortcut when * using a keyboard with alphabetic keys. * @return This Item so additional setters can be called. */ public MenuItem setAlphabeticShortcut(char alphaChar); + /** + * Change the alphabetic shortcut associated with this item. The shortcut + * will be triggered when the key that generates the given character is + * pressed along with the modifier keys. Case is not significant and shortcut + * characters will be displayed in lower case. Note that menu items with + * the characters '\b' or '\n' as shortcuts will get triggered by the + * Delete key or Carriage Return key, respectively. + *

+ * See {@link Menu} for the menu types that support shortcuts. + * + * @param alphaChar The alphabetic shortcut key. This is the shortcut when + * using a keyboard with alphabetic keys. + * @param alphaModifiers The modifier associated with the shortcut. It should + * be a combination of {@link KeyEvent#META_META_ON}, {@link KeyEvent#META_CTRL_ON}, + * {@link KeyEvent#META_ALT_ON}, {@link KeyEvent#META_SHIFT_ON}, + * {@link KeyEvent#META_SYM_ON}, {@link KeyEvent#META_FUNCTION_ON}. + * @return This Item so additional setters can be called. + */ + default public MenuItem setAlphabeticShortcut(char alphaChar, int alphaModifiers) { + if ((alphaModifiers & Menu.SUPPORTED_MODIFIERS_MASK) == KeyEvent.META_CTRL_ON) { + return setAlphabeticShortcut(alphaChar); + } else { + return this; + } + } + /** * Return the char for this menu item's alphabetic shortcut. * @@ -316,6 +412,20 @@ public interface MenuItem { */ public char getAlphabeticShortcut(); + /** + * Return the modifier for this menu item's alphabetic shortcut. + * The modifier is a combination of {@link KeyEvent#META_META_ON}, + * {@link KeyEvent#META_CTRL_ON}, {@link KeyEvent#META_ALT_ON}, + * {@link KeyEvent#META_SHIFT_ON}, {@link KeyEvent#META_SYM_ON}, + * {@link KeyEvent#META_FUNCTION_ON}. + * For example, {@link KeyEvent#META_FUNCTION_ON}|{@link KeyEvent#META_CTRL_ON} + * + * @return Modifier associated with the keyboard shortcut. + */ + default public int getAlphabeticModifiers() { + return KeyEvent.META_CTRL_ON; + } + /** * Control whether this item can display a check mark. Setting this does * not actually display a check mark (see {@link #setChecked} for that); @@ -323,7 +433,7 @@ public interface MenuItem { * check mark. *

* See {@link Menu} for the menu types that support check marks. - * + * * @param checkable Set to true to allow a check mark, false to * disallow. The default is false. * @see #setChecked diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 9bfc2600d0e19..03266a27d30ce 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -4472,9 +4472,9 @@ public final class ViewRootImpl implements ViewParent, } } - // If the Control modifier is held, try to interpret the key as a shortcut. + // If a modifier is held, try to interpret the key as a shortcut. if (event.getAction() == KeyEvent.ACTION_DOWN - && event.isCtrlPressed() + && !KeyEvent.metaStateHasNoModifiers(event.getMetaState()) && event.getRepeatCount() == 0 && !KeyEvent.isModifierKey(event.getKeyCode()) && groupNavigationDirection == 0) { diff --git a/core/java/com/android/internal/view/menu/ActionMenu.java b/core/java/com/android/internal/view/menu/ActionMenu.java index 3d44ebc24d749..c657b872e71e3 100644 --- a/core/java/com/android/internal/view/menu/ActionMenu.java +++ b/core/java/com/android/internal/view/menu/ActionMenu.java @@ -38,7 +38,7 @@ public class ActionMenu implements Menu { private boolean mIsQwerty; private ArrayList mItems; - + public ActionMenu(Context context) { mContext = context; mItems = new ArrayList(); @@ -157,18 +157,22 @@ public class ActionMenu implements Menu { return false; } - + private ActionMenuItem findItemWithShortcut(int keyCode, KeyEvent event) { // TODO Make this smarter. final boolean qwerty = mIsQwerty; final ArrayList items = mItems; final int itemCount = items.size(); - + final int modifierState = event.getModifiers(); for (int i = 0; i < itemCount; i++) { ActionMenuItem item = items.get(i); final char shortcut = qwerty ? item.getAlphabeticShortcut() : item.getNumericShortcut(); - if (keyCode == shortcut) { + final int shortcutModifiers = + qwerty ? item.getAlphabeticModifiers() : item.getNumericModifiers(); + final boolean is_modifiers_exact_match = (modifierState & SUPPORTED_MODIFIERS_MASK) + == (shortcutModifiers & SUPPORTED_MODIFIERS_MASK); + if ((keyCode == shortcut) && is_modifiers_exact_match) { return item; } } diff --git a/core/java/com/android/internal/view/menu/ActionMenuItem.java b/core/java/com/android/internal/view/menu/ActionMenuItem.java index 1fce0b78db507..ace0cce10473e 100644 --- a/core/java/com/android/internal/view/menu/ActionMenuItem.java +++ b/core/java/com/android/internal/view/menu/ActionMenuItem.java @@ -21,6 +21,7 @@ import android.content.Intent; import android.graphics.drawable.Drawable; import android.view.ActionProvider; import android.view.ContextMenu.ContextMenuInfo; +import android.view.KeyEvent; import android.view.MenuItem; import android.view.SubMenu; import android.view.View; @@ -33,12 +34,14 @@ public class ActionMenuItem implements MenuItem { private final int mGroup; private final int mCategoryOrder; private final int mOrdering; - + private CharSequence mTitle; private CharSequence mTitleCondensed; private Intent mIntent; private char mShortcutNumericChar; + private int mShortcutNumericModifiers = KeyEvent.META_CTRL_ON; private char mShortcutAlphabeticChar; + private int mShortcutAlphabeticModifiers = KeyEvent.META_CTRL_ON; private Drawable mIconDrawable; private int mIconResId = NO_ICON; @@ -73,6 +76,10 @@ public class ActionMenuItem implements MenuItem { return mShortcutAlphabeticChar; } + public int getAlphabeticModifiers() { + return mShortcutAlphabeticModifiers; + } + public int getGroupId() { return mGroup; } @@ -97,6 +104,10 @@ public class ActionMenuItem implements MenuItem { return mShortcutNumericChar; } + public int getNumericModifiers() { + return mShortcutNumericModifiers; + } + public int getOrder() { return mOrdering; } @@ -138,6 +149,12 @@ public class ActionMenuItem implements MenuItem { return this; } + public MenuItem setAlphabeticShortcut(char alphachar, int alphaModifiers) { + mShortcutAlphabeticChar = alphachar; + mShortcutAlphabeticModifiers = KeyEvent.normalizeMetaState(alphaModifiers); + return this; + } + public MenuItem setCheckable(boolean checkable) { mFlags = (mFlags & ~CHECKABLE) | (checkable ? CHECKABLE : 0); return this; @@ -180,6 +197,12 @@ public class ActionMenuItem implements MenuItem { return this; } + public MenuItem setNumericShortcut(char numericChar, int numericModifiers) { + mShortcutNumericChar = numericChar; + mShortcutNumericModifiers = KeyEvent.normalizeMetaState(numericModifiers); + return this; + } + public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) { mClickListener = menuItemClickListener; return this; @@ -191,6 +214,15 @@ public class ActionMenuItem implements MenuItem { return this; } + public MenuItem setShortcut(char numericChar, char alphaChar, int numericModifiers, + int alphaModifiers) { + mShortcutNumericChar = numericChar; + mShortcutNumericModifiers = KeyEvent.normalizeMetaState(numericModifiers); + mShortcutAlphabeticChar = alphaChar; + mShortcutAlphabeticModifiers = KeyEvent.normalizeMetaState(alphaModifiers); + return this; + } + public MenuItem setTitle(CharSequence title) { mTitle = title; return this; diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java index df57639a819e3..7eb0f4dbddc7a 100644 --- a/core/java/com/android/internal/view/menu/MenuBuilder.java +++ b/core/java/com/android/internal/view/menu/MenuBuilder.java @@ -805,7 +805,7 @@ public class MenuBuilder implements Menu { */ void findItemsWithShortcutForKey(List items, int keyCode, KeyEvent event) { final boolean qwerty = isQwertyMode(); - final int metaState = event.getMetaState(); + final int modifierState = event.getModifiers(); final KeyCharacterMap.KeyData possibleChars = new KeyCharacterMap.KeyData(); // Get the chars associated with the keyCode (i.e using any chording combo) final boolean isKeyCodeMapped = event.getKeyData(possibleChars); @@ -821,9 +821,13 @@ public class MenuBuilder implements Menu { if (item.hasSubMenu()) { ((MenuBuilder)item.getSubMenu()).findItemsWithShortcutForKey(items, keyCode, event); } - final char shortcutChar = qwerty ? item.getAlphabeticShortcut() : item.getNumericShortcut(); - if (((metaState & (KeyEvent.META_SHIFT_ON | KeyEvent.META_SYM_ON)) == 0) && - (shortcutChar != 0) && + final char shortcutChar = + qwerty ? item.getAlphabeticShortcut() : item.getNumericShortcut(); + final int shortcutModifiers = + qwerty ? item.getAlphabeticModifiers() : item.getNumericModifiers(); + final boolean isModifiersExactMatch = (modifierState & SUPPORTED_MODIFIERS_MASK) + == (shortcutModifiers & SUPPORTED_MODIFIERS_MASK); + if (isModifiersExactMatch && (shortcutChar != 0) && (shortcutChar == possibleChars.meta[0] || shortcutChar == possibleChars.meta[2] || (qwerty && shortcutChar == '\b' && diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java index 342943f814ba7..4c3118d4f072b 100644 --- a/core/java/com/android/internal/view/menu/MenuItemImpl.java +++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java @@ -25,6 +25,7 @@ import android.graphics.drawable.Drawable; import android.util.Log; import android.view.ActionProvider; import android.view.ContextMenu.ContextMenuInfo; +import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.SubMenu; @@ -50,7 +51,9 @@ public final class MenuItemImpl implements MenuItem { private CharSequence mTitleCondensed; private Intent mIntent; private char mShortcutNumericChar; + private int mShortcutNumericModifiers = KeyEvent.META_CTRL_ON; private char mShortcutAlphabeticChar; + private int mShortcutAlphabeticModifiers = KeyEvent.META_CTRL_ON; /** The icon's drawable which is only created as needed */ private Drawable mIconDrawable; @@ -227,18 +230,36 @@ public final class MenuItemImpl implements MenuItem { mItemCallback = callback; return this; } - + public char getAlphabeticShortcut() { return mShortcutAlphabeticChar; } + public int getAlphabeticModifiers() { + return mShortcutAlphabeticModifiers; + } + public MenuItem setAlphabeticShortcut(char alphaChar) { if (mShortcutAlphabeticChar == alphaChar) return this; - + mShortcutAlphabeticChar = Character.toLowerCase(alphaChar); - + mMenu.onItemsChanged(false); - + + return this; + } + + public MenuItem setAlphabeticShortcut(char alphaChar, int alphaModifiers){ + if (mShortcutAlphabeticChar == alphaChar && + mShortcutAlphabeticModifiers == alphaModifiers) { + return this; + } + + mShortcutAlphabeticChar = alphaChar; + mShortcutAlphabeticModifiers = KeyEvent.normalizeMetaState(alphaModifiers); + + mMenu.onItemsChanged(false); + return this; } @@ -246,6 +267,10 @@ public final class MenuItemImpl implements MenuItem { return mShortcutNumericChar; } + public int getNumericModifiers() { + return mShortcutNumericModifiers; + } + public MenuItem setNumericShortcut(char numericChar) { if (mShortcutNumericChar == numericChar) return this; @@ -256,6 +281,19 @@ public final class MenuItemImpl implements MenuItem { return this; } + public MenuItem setNumericShortcut(char numericChar, int numericModifiers){ + if (mShortcutNumericChar == numericChar && mShortcutNumericModifiers == numericModifiers) { + return this; + } + + mShortcutNumericChar = numericChar; + mShortcutNumericModifiers = KeyEvent.normalizeMetaState(numericModifiers); + + mMenu.onItemsChanged(false); + + return this; + } + public MenuItem setShortcut(char numericChar, char alphaChar) { mShortcutNumericChar = numericChar; mShortcutAlphabeticChar = Character.toLowerCase(alphaChar); @@ -265,6 +303,18 @@ public final class MenuItemImpl implements MenuItem { return this; } + public MenuItem setShortcut(char numericChar, int numericModifiers, char alphaChar, + int alphaModifiers) { + mShortcutNumericChar = numericChar; + mShortcutNumericModifiers = KeyEvent.normalizeMetaState(numericModifiers); + mShortcutAlphabeticChar = alphaChar; + mShortcutAlphabeticModifiers = KeyEvent.normalizeMetaState(alphaModifiers); + + mMenu.onItemsChanged(false); + + return this; + } + /** * @return The active shortcut (based on QWERTY-mode of the menu). */ diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 7f49f056d3bfa..aeba589766378 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -6975,10 +6975,32 @@ with alphabetic keys. --> + + + + + + + + + + + + + + + + + + + + diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 1b48469b100e9..1dbd567db453e 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2792,6 +2792,8 @@ + +