Loading core/java/android/content/Intent.java +8 −0 Original line number Diff line number Diff line Loading @@ -2578,6 +2578,14 @@ public class Intent implements Parcelable, Cloneable { public static final String ACTION_SHOW_BRIGHTNESS_DIALOG = "android.intent.action.SHOW_BRIGHTNESS_DIALOG"; /** * Broadcast Action: A global button was pressed. Includes a single * extra field, {@link #EXTRA_KEY_EVENT}, containing the key event that * caused the broadcast. * @hide */ public static final String ACTION_GLOBAL_BUTTON = "android.intent.action.GLOBAL_BUTTON"; // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Standard intent categories (see addCategory()). Loading core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -1142,6 +1142,7 @@ <java-symbol type="xml" name="time_zones_by_country" /> <java-symbol type="xml" name="sms_short_codes" /> <java-symbol type="xml" name="audio_assets" /> <java-symbol type="xml" name="global_keys" /> <java-symbol type="raw" name="accessibility_gestures" /> <java-symbol type="raw" name="incognito_mode_start_page" /> Loading core/res/res/xml/global_keys.xml 0 → 100644 +31 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- /* ** Copyright 2013, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ --> <!-- Mapping of keycodes to components which will be handled globally. Modify this file to add global keys. A global key will NOT go to the foreground application and instead only ever be sent via targeted broadcast to the specified component. The action of the intent will be android.intent.action.GLOBAL_BUTTON and the KeyEvent will be included in the intent as android.intent.extra.KEY_EVENT. --> <global_keys version="1"> <!-- Example format: keyCode = keycode to handle globally. component = component which will handle this key. --> <!-- <key keyCode="KEYCODE_VOLUME_UP" component="com.android.example.keys/.VolumeKeyHandler" /> --> </global_keys> policy/src/com/android/internal/policy/impl/GlobalKeyManager.java 0 → 100644 +126 −0 Original line number Diff line number Diff line /* * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.policy.impl; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.os.UserHandle; import android.util.Log; import android.util.SparseArray; import android.view.KeyEvent; import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; /** * Stores a mapping of global keys. * <p> * A global key will NOT go to the foreground application and instead only ever be sent via targeted * broadcast to the specified component. The action of the intent will be * {@link Intent#ACTION_GLOBAL_BUTTON} and the KeyEvent will be included in the intent with * {@link Intent#EXTRA_KEY_EVENT}. */ final class GlobalKeyManager { private static final String TAG = "GlobalKeyManager"; private static final String TAG_GLOBAL_KEYS = "global_keys"; private static final String ATTR_VERSION = "version"; private static final String TAG_KEY = "key"; private static final String ATTR_KEY_CODE = "keyCode"; private static final String ATTR_COMPONENT = "component"; private static final int GLOBAL_KEY_FILE_VERSION = 1; private SparseArray<ComponentName> mKeyMapping; public GlobalKeyManager(Context context) { mKeyMapping = new SparseArray<ComponentName>(); loadGlobalKeys(context); } /** * Broadcasts an intent if the keycode is part of the global key mapping. * * @param context context used to broadcast the event * @param keyCode keyCode which triggered this function * @param event keyEvent which trigged this function * @return {@code true} if this was handled */ boolean handleGlobalKey(Context context, int keyCode, KeyEvent event) { if (mKeyMapping.size() > 0) { ComponentName component = mKeyMapping.get(keyCode); if (component != null) { Intent intent = new Intent(Intent.ACTION_GLOBAL_BUTTON) .setComponent(component) .putExtra(Intent.EXTRA_KEY_EVENT, event); context.sendBroadcastAsUser(intent, UserHandle.CURRENT, null); return true; } } return false; } /** * Returns {@code true} if the key will be handled globally. */ boolean shouldHandleGlobalKey(int keyCode, KeyEvent event) { return mKeyMapping.get(keyCode) != null; } private void loadGlobalKeys(Context context) { XmlResourceParser parser = null; try { parser = context.getResources().getXml(com.android.internal.R.xml.global_keys); XmlUtils.beginDocument(parser, TAG_GLOBAL_KEYS); int version = parser.getAttributeIntValue(null, ATTR_VERSION, 0); if (GLOBAL_KEY_FILE_VERSION == version) { while (true) { XmlUtils.nextElement(parser); String element = parser.getName(); if (element == null) { break; } if (TAG_KEY.equals(element)) { String keyCodeName = parser.getAttributeValue(null, ATTR_KEY_CODE); String componentName = parser.getAttributeValue(null, ATTR_COMPONENT); int keyCode = KeyEvent.keyCodeFromString(keyCodeName); if (keyCode != KeyEvent.KEYCODE_UNKNOWN) { mKeyMapping.put(keyCode, ComponentName.unflattenFromString( componentName)); } } } } } catch (Resources.NotFoundException e) { Log.w(TAG, "global keys file not found", e); } catch (XmlPullParserException e) { Log.w(TAG, "XML parser exception reading global keys file", e); } catch (IOException e) { Log.w(TAG, "I/O exception reading global keys file", e); } finally { if (parser != null) { parser.close(); } } } } policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +15 −0 Original line number Diff line number Diff line Loading @@ -441,6 +441,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { PowerManager.WakeLock mBroadcastWakeLock; boolean mHavePendingMediaKeyRepeatWithWakeLock; // Maps global key codes to the components that will handle them. private GlobalKeyManager mGlobalKeyManager; // Fallback actions by key code. private final SparseArray<KeyCharacterMap.FallbackAction> mFallbackActions = new SparseArray<KeyCharacterMap.FallbackAction>(); Loading Loading @@ -898,6 +901,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { mScreenshotChordEnabled = mContext.getResources().getBoolean( com.android.internal.R.bool.config_enableScreenshotChord); mGlobalKeyManager = new GlobalKeyManager(mContext); // Controls rotation and the like. initializeHdmiState(); Loading Loading @@ -2140,6 +2145,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { return -1; } if (mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) { return -1; } // Let the application handle the key. return 0; } Loading Loading @@ -3585,6 +3594,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } // If the key would be handled globally, just return the result, don't worry about special // key processing. if (mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) { return result; } // Handle special keys. switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_DOWN: Loading Loading
core/java/android/content/Intent.java +8 −0 Original line number Diff line number Diff line Loading @@ -2578,6 +2578,14 @@ public class Intent implements Parcelable, Cloneable { public static final String ACTION_SHOW_BRIGHTNESS_DIALOG = "android.intent.action.SHOW_BRIGHTNESS_DIALOG"; /** * Broadcast Action: A global button was pressed. Includes a single * extra field, {@link #EXTRA_KEY_EVENT}, containing the key event that * caused the broadcast. * @hide */ public static final String ACTION_GLOBAL_BUTTON = "android.intent.action.GLOBAL_BUTTON"; // --------------------------------------------------------------------- // --------------------------------------------------------------------- // Standard intent categories (see addCategory()). Loading
core/res/res/values/symbols.xml +1 −0 Original line number Diff line number Diff line Loading @@ -1142,6 +1142,7 @@ <java-symbol type="xml" name="time_zones_by_country" /> <java-symbol type="xml" name="sms_short_codes" /> <java-symbol type="xml" name="audio_assets" /> <java-symbol type="xml" name="global_keys" /> <java-symbol type="raw" name="accessibility_gestures" /> <java-symbol type="raw" name="incognito_mode_start_page" /> Loading
core/res/res/xml/global_keys.xml 0 → 100644 +31 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- /* ** Copyright 2013, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ --> <!-- Mapping of keycodes to components which will be handled globally. Modify this file to add global keys. A global key will NOT go to the foreground application and instead only ever be sent via targeted broadcast to the specified component. The action of the intent will be android.intent.action.GLOBAL_BUTTON and the KeyEvent will be included in the intent as android.intent.extra.KEY_EVENT. --> <global_keys version="1"> <!-- Example format: keyCode = keycode to handle globally. component = component which will handle this key. --> <!-- <key keyCode="KEYCODE_VOLUME_UP" component="com.android.example.keys/.VolumeKeyHandler" /> --> </global_keys>
policy/src/com/android/internal/policy/impl/GlobalKeyManager.java 0 → 100644 +126 −0 Original line number Diff line number Diff line /* * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.policy.impl; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.os.UserHandle; import android.util.Log; import android.util.SparseArray; import android.view.KeyEvent; import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; /** * Stores a mapping of global keys. * <p> * A global key will NOT go to the foreground application and instead only ever be sent via targeted * broadcast to the specified component. The action of the intent will be * {@link Intent#ACTION_GLOBAL_BUTTON} and the KeyEvent will be included in the intent with * {@link Intent#EXTRA_KEY_EVENT}. */ final class GlobalKeyManager { private static final String TAG = "GlobalKeyManager"; private static final String TAG_GLOBAL_KEYS = "global_keys"; private static final String ATTR_VERSION = "version"; private static final String TAG_KEY = "key"; private static final String ATTR_KEY_CODE = "keyCode"; private static final String ATTR_COMPONENT = "component"; private static final int GLOBAL_KEY_FILE_VERSION = 1; private SparseArray<ComponentName> mKeyMapping; public GlobalKeyManager(Context context) { mKeyMapping = new SparseArray<ComponentName>(); loadGlobalKeys(context); } /** * Broadcasts an intent if the keycode is part of the global key mapping. * * @param context context used to broadcast the event * @param keyCode keyCode which triggered this function * @param event keyEvent which trigged this function * @return {@code true} if this was handled */ boolean handleGlobalKey(Context context, int keyCode, KeyEvent event) { if (mKeyMapping.size() > 0) { ComponentName component = mKeyMapping.get(keyCode); if (component != null) { Intent intent = new Intent(Intent.ACTION_GLOBAL_BUTTON) .setComponent(component) .putExtra(Intent.EXTRA_KEY_EVENT, event); context.sendBroadcastAsUser(intent, UserHandle.CURRENT, null); return true; } } return false; } /** * Returns {@code true} if the key will be handled globally. */ boolean shouldHandleGlobalKey(int keyCode, KeyEvent event) { return mKeyMapping.get(keyCode) != null; } private void loadGlobalKeys(Context context) { XmlResourceParser parser = null; try { parser = context.getResources().getXml(com.android.internal.R.xml.global_keys); XmlUtils.beginDocument(parser, TAG_GLOBAL_KEYS); int version = parser.getAttributeIntValue(null, ATTR_VERSION, 0); if (GLOBAL_KEY_FILE_VERSION == version) { while (true) { XmlUtils.nextElement(parser); String element = parser.getName(); if (element == null) { break; } if (TAG_KEY.equals(element)) { String keyCodeName = parser.getAttributeValue(null, ATTR_KEY_CODE); String componentName = parser.getAttributeValue(null, ATTR_COMPONENT); int keyCode = KeyEvent.keyCodeFromString(keyCodeName); if (keyCode != KeyEvent.KEYCODE_UNKNOWN) { mKeyMapping.put(keyCode, ComponentName.unflattenFromString( componentName)); } } } } } catch (Resources.NotFoundException e) { Log.w(TAG, "global keys file not found", e); } catch (XmlPullParserException e) { Log.w(TAG, "XML parser exception reading global keys file", e); } catch (IOException e) { Log.w(TAG, "I/O exception reading global keys file", e); } finally { if (parser != null) { parser.close(); } } } }
policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +15 −0 Original line number Diff line number Diff line Loading @@ -441,6 +441,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { PowerManager.WakeLock mBroadcastWakeLock; boolean mHavePendingMediaKeyRepeatWithWakeLock; // Maps global key codes to the components that will handle them. private GlobalKeyManager mGlobalKeyManager; // Fallback actions by key code. private final SparseArray<KeyCharacterMap.FallbackAction> mFallbackActions = new SparseArray<KeyCharacterMap.FallbackAction>(); Loading Loading @@ -898,6 +901,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { mScreenshotChordEnabled = mContext.getResources().getBoolean( com.android.internal.R.bool.config_enableScreenshotChord); mGlobalKeyManager = new GlobalKeyManager(mContext); // Controls rotation and the like. initializeHdmiState(); Loading Loading @@ -2140,6 +2145,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { return -1; } if (mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)) { return -1; } // Let the application handle the key. return 0; } Loading Loading @@ -3585,6 +3594,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } // If the key would be handled globally, just return the result, don't worry about special // key processing. if (mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) { return result; } // Handle special keys. switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_DOWN: Loading