GlobalKeyManager.java revision d7c0c2ee45dd5367ac7863517de2e385fbd424f3
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
16package com.android.internal.policy.impl;
17
18import android.content.ComponentName;
19import android.content.Context;
20import android.content.Intent;
21import android.content.res.Resources;
22import android.content.res.XmlResourceParser;
23import android.os.UserHandle;
24import android.util.Log;
25import android.util.SparseArray;
26import android.view.KeyEvent;
27
28import com.android.internal.util.XmlUtils;
29
30import org.xmlpull.v1.XmlPullParserException;
31
32import java.io.IOException;
33import java.io.PrintWriter;
34
35/**
36 * Stores a mapping of global keys.
37 * <p>
38 * A global key will NOT go to the foreground application and instead only ever be sent via targeted
39 * broadcast to the specified component. The action of the intent will be
40 * {@link Intent#ACTION_GLOBAL_BUTTON} and the KeyEvent will be included in the intent with
41 * {@link Intent#EXTRA_KEY_EVENT}.
42 */
43final class GlobalKeyManager {
44
45    private static final String TAG = "GlobalKeyManager";
46
47    private static final String TAG_GLOBAL_KEYS = "global_keys";
48    private static final String ATTR_VERSION = "version";
49    private static final String TAG_KEY = "key";
50    private static final String ATTR_KEY_CODE = "keyCode";
51    private static final String ATTR_COMPONENT = "component";
52
53    private static final int GLOBAL_KEY_FILE_VERSION = 1;
54
55    private SparseArray<ComponentName> mKeyMapping;
56
57    public GlobalKeyManager(Context context) {
58        mKeyMapping = new SparseArray<ComponentName>();
59        loadGlobalKeys(context);
60    }
61
62    /**
63     * Broadcasts an intent if the keycode is part of the global key mapping.
64     *
65     * @param context context used to broadcast the event
66     * @param keyCode keyCode which triggered this function
67     * @param event keyEvent which trigged this function
68     * @return {@code true} if this was handled
69     */
70    boolean handleGlobalKey(Context context, int keyCode, KeyEvent event) {
71        if (mKeyMapping.size() > 0) {
72            ComponentName component = mKeyMapping.get(keyCode);
73            if (component != null) {
74                Intent intent = new Intent(Intent.ACTION_GLOBAL_BUTTON)
75                        .setComponent(component)
76                        .putExtra(Intent.EXTRA_KEY_EVENT, event);
77                context.sendBroadcastAsUser(intent, UserHandle.CURRENT, null);
78                return true;
79            }
80        }
81        return false;
82    }
83
84    /**
85     * Returns {@code true} if the key will be handled globally.
86     */
87    boolean shouldHandleGlobalKey(int keyCode, KeyEvent event) {
88        return mKeyMapping.get(keyCode) != null;
89    }
90
91    private void loadGlobalKeys(Context context) {
92        XmlResourceParser parser = null;
93        try {
94            parser = context.getResources().getXml(com.android.internal.R.xml.global_keys);
95            XmlUtils.beginDocument(parser, TAG_GLOBAL_KEYS);
96            int version = parser.getAttributeIntValue(null, ATTR_VERSION, 0);
97            if (GLOBAL_KEY_FILE_VERSION == version) {
98                while (true) {
99                    XmlUtils.nextElement(parser);
100                    String element = parser.getName();
101                    if (element == null) {
102                        break;
103                    }
104                    if (TAG_KEY.equals(element)) {
105                        String keyCodeName = parser.getAttributeValue(null, ATTR_KEY_CODE);
106                        String componentName = parser.getAttributeValue(null, ATTR_COMPONENT);
107                        int keyCode = KeyEvent.keyCodeFromString(keyCodeName);
108                        if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
109                            mKeyMapping.put(keyCode, ComponentName.unflattenFromString(
110                                    componentName));
111                        }
112                    }
113                }
114            }
115        } catch (Resources.NotFoundException e) {
116            Log.w(TAG, "global keys file not found", e);
117        } catch (XmlPullParserException e) {
118            Log.w(TAG, "XML parser exception reading global keys file", e);
119        } catch (IOException e) {
120            Log.w(TAG, "I/O exception reading global keys file", e);
121        } finally {
122            if (parser != null) {
123                parser.close();
124            }
125        }
126    }
127
128    public void dump(String prefix, PrintWriter pw) {
129        final int numKeys = mKeyMapping.size();
130        if (numKeys == 0) {
131            pw.print(prefix); pw.println("mKeyMapping.size=0");
132            return;
133        }
134        pw.print(prefix); pw.println("mKeyMapping={");
135        for (int i = 0; i < numKeys; ++i) {
136            pw.print("  ");
137            pw.print(prefix);
138            pw.print(KeyEvent.keyCodeToString(mKeyMapping.keyAt(i)));
139            pw.print("=");
140            pw.println(mKeyMapping.valueAt(i).flattenToString());
141        }
142        pw.print(prefix); pw.println("}");
143    }
144}
145