上周遇到一个这样的问题:监听Home键。
对于Back键的监听比较容易,可以在多个系统回调处拦截,使用onKeydown方法可以处理菜单键和back键。
@Override
public void onBackPressed() {
// super.onBackPressed();//注释掉这行,back键不退出activity
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
return super.dispatchKeyEvent(event);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return super.onKeyDown(keyCode, event);
}
但这些方法不能处理Home事件,因为Home键是系统键,可以将程序退出放在后台,所以这个事件是直接分发给系统,系统接收到之后做相应处理,Home键的事件不是直接传递到应用里面,在framework层就已经被拦截,所以在上述监听Back键的回调方法中是收不到Home键的事件的。
查阅了网上的资料,总结下方法:
1. 对Home键的监听主要通过注册广播接收器实现
拦截让窗口关闭的系统动作,然后根据Intent里面的具体参数,分析当前到底是Home键, 应用切换键,还是其他功能按键。
在使用广播监听使用ACTION_CLOSE_SYSTEM_DIALOGS。
下面是http://blog.youkuaiyun.com/way_ping_li/article/details/8953622里给出的封装好了的监听Home键的方法:
/**
* Home键监听封装
*
* @author way
*
*/
public class HomeWatcher {
static final String TAG = "HomeWatcher";
private Context mContext;
private IntentFilter mFilter;
private OnHomePressedListener mListener;
private InnerRecevier mRecevier;
// 回调接口
public interface OnHomePressedListener {
public void onHomePressed();
public void onHomeLongPressed();
}
public HomeWatcher(Context context) {
mContext = context;
mFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
}
/**
* 设置监听
*
* @param listener
*/
public void setOnHomePressedListener(OnHomePressedListener listener) {
mListener = listener;
mRecevier = new InnerRecevier();
}
/**
* 开始监听,注册广播
*/
public void startWatch() {
if (mRecevier != null) {
mContext.registerReceiver(mRecevier, mFilter);
}
}
/**
* 停止监听,注销广播
*/
public void stopWatch() {
if (mRecevier != null) {
mContext.unregisterReceiver(mRecevier);
}
}
/**
* 广播接收者
*/
class InnerRecevier extends BroadcastReceiver {
final String SYSTEM_DIALOG_REASON_KEY = "reason";
final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
if (reason != null) {
Log.e(TAG, "action:" + action + ",reason:" + reason);
if (mListener != null) {
if (reason.equals(SYSTEM_DIALOG_REASON_HOME_KEY)) {
// 短按home键
mListener.onHomePressed();
} else if (reason
.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
// 长按home键
mListener.onHomeLongPressed();
}
}
}
}
}
}
}
注意到上面是采用动态注册,那采用静态注册呢?
<receiver android:name="~~~~" >
<intent-filter>
<action android:name="android.intent.action.CLOSE_SYSTEM_DIALOGS" />
</intent-filter>
</receiver>
结果你会发现静态注册不起作用,即收不到onReceive回调。
接下来,我们需要在应用中开启监听,下面是以在Activity中根据需要在其他合适的时机注册和注销。
比如在Activity的onResume和onPause里面分别调用。
2. framework中PhoneWindowManager.java 处理
来自http://862123204-qq-com.iteye.com/blog/1888532
想要完全监听home键需要在framework层去处理。
/frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
里面去修改private void handleLongPressOnHome() 这个方法。
private void handleLongPressOnHome() {
// We can't initialize this in init() since the configuration hasn't been loaded yet.
if (mLongPressOnHomeBehavior < 0) {
mLongPressOnHomeBehavior
= mContext.getResources().getInteger(R.integer.config_longPressOnHomeBehavior);
if (mLongPressOnHomeBehavior < LONG_PRESS_HOME_NOTHING ||
mLongPressOnHomeBehavior > LONG_PRESS_HOME_RECENT_SYSTEM_UI) {
mLongPressOnHomeBehavior = LONG_PRESS_HOME_NOTHING;
}
}
if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) {
performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
// Eat the longpress so it won't dismiss the recent apps dialog when
// the user lets go of the home key
mHomeLongPressed = true;
}
if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_DIALOG) {
showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS);
} else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI) {
try {
IStatusBarService statusbar = getStatusBarService();
if (statusbar != null) {
statusbar.toggleRecentApps();
}
} catch (RemoteException e) {
Slog.e(TAG, "RemoteException when showing recent apps", e);
// re-acquire status bar service next time it is needed.
mStatusBarService = null;
}
}
}