1 /* 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 package com.android.internal.policy.impl; 17 18 import android.content.ComponentName; 19 import android.content.Context; 20 import android.content.Intent; 21 import android.content.res.Resources; 22 import android.content.res.XmlResourceParser; 23 import android.os.UserHandle; 24 import android.util.Log; 25 import android.util.SparseArray; 26 import android.view.KeyEvent; 27 28 import com.android.internal.util.XmlUtils; 29 30 import org.xmlpull.v1.XmlPullParserException; 31 32 import java.io.IOException; 33 34 /** 35 * Stores a mapping of global keys. 36 * <p> 37 * A global key will NOT go to the foreground application and instead only ever be sent via targeted 38 * broadcast to the specified component. The action of the intent will be 39 * {@link Intent#ACTION_GLOBAL_BUTTON} and the KeyEvent will be included in the intent with 40 * {@link Intent#EXTRA_KEY_EVENT}. 41 */ 42 final class GlobalKeyManager { 43 44 private static final String TAG = "GlobalKeyManager"; 45 46 private static final String TAG_GLOBAL_KEYS = "global_keys"; 47 private static final String ATTR_VERSION = "version"; 48 private static final String TAG_KEY = "key"; 49 private static final String ATTR_KEY_CODE = "keyCode"; 50 private static final String ATTR_COMPONENT = "component"; 51 52 private static final int GLOBAL_KEY_FILE_VERSION = 1; 53 54 private SparseArray<ComponentName> mKeyMapping; 55 56 public GlobalKeyManager(Context context) { 57 mKeyMapping = new SparseArray<ComponentName>(); 58 loadGlobalKeys(context); 59 } 60 61 /** 62 * Broadcasts an intent if the keycode is part of the global key mapping. 63 * 64 * @param context context used to broadcast the event 65 * @param keyCode keyCode which triggered this function 66 * @param event keyEvent which trigged this function 67 * @return {@code true} if this was handled 68 */ 69 boolean handleGlobalKey(Context context, int keyCode, KeyEvent event) { 70 if (mKeyMapping.size() > 0) { 71 ComponentName component = mKeyMapping.get(keyCode); 72 if (component != null) { 73 Intent intent = new Intent(Intent.ACTION_GLOBAL_BUTTON) 74 .setComponent(component) 75 .putExtra(Intent.EXTRA_KEY_EVENT, event); 76 context.sendBroadcastAsUser(intent, UserHandle.CURRENT, null); 77 return true; 78 } 79 } 80 return false; 81 } 82 83 /** 84 * Returns {@code true} if the key will be handled globally. 85 */ 86 boolean shouldHandleGlobalKey(int keyCode, KeyEvent event) { 87 return mKeyMapping.get(keyCode) != null; 88 } 89 90 private void loadGlobalKeys(Context context) { 91 XmlResourceParser parser = null; 92 try { 93 parser = context.getResources().getXml(com.android.internal.R.xml.global_keys); 94 XmlUtils.beginDocument(parser, TAG_GLOBAL_KEYS); 95 int version = parser.getAttributeIntValue(null, ATTR_VERSION, 0); 96 if (GLOBAL_KEY_FILE_VERSION == version) { 97 while (true) { 98 XmlUtils.nextElement(parser); 99 String element = parser.getName(); 100 if (element == null) { 101 break; 102 } 103 if (TAG_KEY.equals(element)) { 104 String keyCodeName = parser.getAttributeValue(null, ATTR_KEY_CODE); 105 String componentName = parser.getAttributeValue(null, ATTR_COMPONENT); 106 int keyCode = KeyEvent.keyCodeFromString(keyCodeName); 107 if (keyCode != KeyEvent.KEYCODE_UNKNOWN) { 108 mKeyMapping.put(keyCode, ComponentName.unflattenFromString( 109 componentName)); 110 } 111 } 112 } 113 } 114 } catch (Resources.NotFoundException e) { 115 Log.w(TAG, "global keys file not found", e); 116 } catch (XmlPullParserException e) { 117 Log.w(TAG, "XML parser exception reading global keys file", e); 118 } catch (IOException e) { 119 Log.w(TAG, "I/O exception reading global keys file", e); 120 } finally { 121 if (parser != null) { 122 parser.close(); 123 } 124 } 125 } 126 } 127