您的位置:首页 > 移动开发 > Android开发

Android 监听Home键按键事件

2016-10-11 19:30 441 查看

Android 监听Home键按键事件

标签(空格分隔):Android Home键

在Android开发中有很多按键事件需要在App中捕获从而做出一些针对性的操作,例如返回键,音量键等都可以直接在
dispatchKeyEvent
onKeyDown
等回调方法中捕获,但是Home键事件却不能在这个方法中捕获。在Android源码
KeyEvent
中对于Home键的定义有这样的注释:

This key is handled by the framework and is never delivered to applications.


就是说Home被系统Framework拦截了,并且不会抛出来让App捕获。

但是,很多时候需要在App中捕获Home键的按键事件并作出一些操作。查资料会发现大家都推荐去监听
ACTION_CLOSE_SYSTEM_DIALOGS
这个系统广播,在按下Home键后系统会发出这个广播,是不是可靠,我们来看下Android framework的源码。

先不管Android怎么从底层一步步把按键事件传递上来,这里直接从Framework中的
PhoneWindowManager
方法开始分析。

按键事件会在
PhoneWindowManager
中的
interceptKeyBeforeDispatching
方法中进行一些预处理,Home键的事件就是在这里被拦截并处理。

public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {
final int keyCode = event.getKeyCode();
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;

/** 这里省略不知道多少代码 */
if (keyCode == KeyEvent.KEYCODE_HOME) {
/** 这里也省略不知道多少代码 */
handleShortPressOnHome();
return -1;
}


可以看到短按Home键最终是调用
handleShortPressOnHome
这个方法,那我们来看下这个方法中究竟干了啥?

private void handleShortPressOnHome() {
// Turn on the connected TV and switch HDMI input if we're a HDMI playback device.
getHdmiControl().turnOnTv();

// If there's a dream running then use home to escape the dream
// but don't actually go home.
if (mDreamManagerInternal != null && mDreamManagerInternal.isDreaming()) {
mDreamManagerInternal.stopDream(false /*immediate*/);
return;
}

// Go home!
launchHomeFromHotKey();
}


可以看到这里最终调用了
launchHomeFromHotKey
这个方法。

void launchHomeFromHotKey(final boolean awakenFromDreams, final boolean respectKeyguard) {
if (respectKeyguard) {
if (isKeyguardShowingAndNotOccluded()) {
// don't launch home if keyguard showing
return;
}

if (!mHideLockScreen && mKeyguardDelegate.isInputRestricted()) {
// when in keyguard restricted mode, must first verify unlock
// before launching home
mKeyguardDelegate.verifyUnlock(new OnKeyguardExitResult() {
@Override
public void onKeyguardExitResult(boolean success) {
if (success) {
try {
ActivityManagerNative.getDefault().stopAppSwitches();
} catch (RemoteException e) {
}
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
startDockOrHome(true /*fromHomeKey*/, awakenFromDreams);
}
}
});
return;
}
}


可以看到最后调用了
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
这个方法里面就有我们要找的答案。

这个方法的实现如下:

void sendCloseSystemWindows(String reason) {
PhoneWindow.sendCloseSystemWindows(mContext, reason);
}


这里调到了PhoneWindow里面的

public static void sendCloseSystemWindows(Context context, String reason) {
if (ActivityManagerNative.isSystemReady()) {
try {
ActivityManagerNative.getDefault().closeSystemDialogs(reason);
} catch (RemoteException e) {
}
}
}


这个方法中调用的
ActivityManagerNative.getDefault()
本质是通过
jni
binder
调用得到
ActivityManagerService
的实例,调用
ActivityManagerService
closeSystemDialogs
方法,这个方法最终调用
ActivityManagerService
closeSystemDialogsLocked
方法:

void closeSystemDialogsLocked(String reason) {
Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
if (reason != null) {
intent.putExtra("reason", reason);
}
mWindowManager.closeSystemDialogs(reason);

mStackSupervisor.closeSystemDialogsLocked();

broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null,
AppOpsManager.OP_NONE, null, false, false,
-1, Process.SYSTEM_UID, UserHandle.USER_ALL);
}


这里就是答案了,可以看出这里最终通过
broadcastIntentLocked
发送了
ACTION_CLOSE_SYSTEM_DIALOGS
广播

至于具体的代码实现可以参考我封装的一个类HomeKeyListener
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android Home键