做应用程序的时候,如果需要监听什么按钮,则只需要添加
对应的监听器,而在, 然后再类似于onClick()的方法中实现真正的处理。
但在针对整个系统级别的按钮监听呢,之前在解决一个硬件按钮声效的bug的时候对这部分的源代码了查看了下,所以记下哈
首先是KeyEvent这个类
每个按钮的点击,都是通过一系列的按键事件组成的,文档描述如下
Object used to report key and button events.
Each key press is described by a sequence of key events. A key press starts with a key event with ACTION_DOWN. If the key is held sufficiently long that it repeats, then the initial down is followed additional key events with ACTION_DOWN and a non-zero value for getRepeatCount(). The last key event is a ACTION_UP for the key up. If the key press is canceled, the key up event will have the FLAG_CANCELED flag set.
Key events are generally accompanied by a key code (getKeyCode()), scan code (getScanCode()) and meta state (getMetaState()). Key code constants are defined in this class. Scan code constants are raw device-specific codes obtained from the OS and so are not generally meaningful to applications unless interpreted using the KeyCharacterMap. Meta states describe the pressed state of key modifiers such as META_SHIFT_ON or META_ALT_ON.
即由ACTION_DOWN开始了一个按键的点击事件,然后根据持续的事件,接着会有一个非0的值来表示按键被持续hold的时间。当我们放开手之后,就是一个ACTION_UP的key up事件。此外KeyEvent还一定了一系列的KEYCODE. 常见的有
public static final int KEYCODE_HOME = 3;
/** Key code constant: Back key. */
public static final int KEYCODE_BACK = 4;
/** Key code constant: Call key. */
public static final int KEYCODE_CALL = 5;
像KEYCODE_HOME的说明 * This key is handled by the framework and is never delivered to applications. */
主页的按钮是由framework来处理的,而在应用程序中是不会接收到这个按钮的点击事件。那么framework中又是在那里对按键进行处理的呢?
在framework的phonewindow中有如下一段代码和注释
/**
* A key was pressed down and not handled by anything else in the window.
*
* @see #onKeyUp
* @see android.view.KeyEvent
*/
protected boolean onKeyDown(int featureId, int keyCode, KeyEvent event) {
/* ****************************************************************************
* HOW TO DECIDE WHERE YOUR KEY HANDLING GOES.
* 如何确定自定义的按键处理的代码应该放在哪里呢?
* If your key handling must happen before the app gets a crack at the event,
* it goes in PhoneWindowManager.
*如果处理必须在APP获取事件之前,需要在PhoneWindowManager中
* If your key handling should happen in all windows, and does not depend on
* the state of the current application, other than that the current
* application can override the behavior by handling the event itself, it
* should go in PhoneFallbackEventHandler.
*如果对按钮的处理需要在所有的窗口中都生效,而不是可以被当前的app覆盖从而进行处理的,需要在PhoneFallbackEventHandler,,,
* Only if your handling depends on the window, and the fact that it has
* a DecorView, should it go here. 如果按钮的处理与当前的窗口有关,那么就是放在phonewindow中
* ****************************************************************************/
final KeyEvent.DispatcherState dispatcher =
mDecor != null ? mDecor.getKeyDispatcherState() : null;
//Log.i(TAG, "Key down: repeat=" + event.getRepeatCount()
// + " flags=0x" + Integer.toHexString(event.getFlags()));
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
// Similar code is in PhoneFallbackEventHandler in case the window
// doesn't have one of these. In this case, we execute it here and
// eat the event instead, because we have mVolumeControlStreamType
// and they don't.
getAudioManager().handleKeyDown(event, mVolumeControlStreamType);
return true;
}
case KeyEvent.KEYCODE_MENU: {
onKeyDownPanel((featureId < 0) ? FEATURE_OPTIONS_PANEL : featureId, event);
return true;
}
case KeyEvent.KEYCODE_BACK: {
if (event.getRepeatCount() > 0) break;
if (featureId < 0) break;
// Currently don't do anything with long press.
if (dispatcher != null) {
dispatcher.startTracking(event, this);
}
return true;
}
}
return false;
}
所以,例如对于返回按钮的处理,上层的app可以获取callback的按钮事件,从而来处理返回按钮。例如关闭当前对话框等操作。因此对于callback按钮事件的处理就放在了phonewindow中。菜单按钮也是同样地道理。
那么像home键这样的不希望app来处理的系统级别的按钮呢?按照注释中的说明,对home键的处理应该在PhoneWindowManager。于是在PhoneWindowManager找到如下代码:
// First we always handle the home key here, so applications
// can never break it, although if keyguard is on, we do let
// it handle it, because that gives us the correct 5 second
// timeout.
if (keyCode == KeyEvent.KEYCODE_HOME) {
。。。。。
}
所以,要添加系统级别的按钮处理,例如我的这个任务,添加按钮声效,或者按钮震动反馈的时候就是在这里啦。~~~