android4.0拦截HOME键
由于android4.0和2.3里面的按键机制有所不同,今天做了这样一个demo可以监听到HOME在android4.0上面,好了废话不说了直接先上原理在贴代码。
frameworks\base\policy\src\com\android\internal\policy\impl\PhoneWindowManager.java这个类是android4.0里面的按键管理类,上层UI监听的所有按键都在这个里面进行分发,所以要想监听到HOME键就要在这个类里面做文章,怎么做很简单找到HOME按键在该类中的处理过程就好解决了,可以在分发HOME键的时候发送一个广播然后在应用程序里面接收该广播就可以了,这个就是原理接下来直接贴代码。
/** {@inheritDoc} */
@Override
public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {
final boolean keyguardOn = keyguardOn();
final int keyCode = event.getKeyCode();
final int repeatCount = event.getRepeatCount();
final int metaState = event.getMetaState();
final int flags = event.getFlags();
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final boolean canceled = event.isCanceled();
if (false) {
Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount="
+ repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed);
}
// If we think we might have a volume down & power key chord on the way
// but we're not sure, then tell the dispatcher to wait a little while and
// try again later before dispatching.
if ((flags & KeyEvent.FLAG_FALLBACK) == 0) {
if (mVolumeDownKeyTriggered && !mPowerKeyTriggered) {
final long now = SystemClock.uptimeMillis();
final long timeoutTime = mVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS;
if (now < timeoutTime) {
return timeoutTime - now;
}
}
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
&& mVolumeDownKeyConsumedByScreenshotChord) {
if (!down) {
mVolumeDownKeyConsumedByScreenshotChord = false;
}
return -1;
}
}
// 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) {
// If we have released the home key, and didn't do anything else
// while it was pressed, then it is time to go home!
Intent myHomeKey = new Intent("HomeKeyDispatch");
myHomeKey.putExtra("HomeKey", "HomeKeyIntent");
mContext.sendBroadcast(myHomeKey);
if (mHomePressed && !down) {
mHomePressed = false;
if (!canceled) {
// If an incoming call is ringing, HOME is totally disabled.
// (The user is already on the InCallScreen at this point,
// and his ONLY options are to answer or reject the call.)
boolean incomingRinging = false;
try {
ITelephony telephonyService = getTelephonyService();
if (telephonyService != null) {
incomingRinging = telephonyService.isRinging();
}
} catch (RemoteException ex) {
Log.w(TAG, "RemoteException from getPhoneInterface()", ex);
}
if (incomingRinging) {
Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
} else {
launchHomeFromHotKey();
}
} else {
Log.i(TAG, "Ignoring HOME; event canceled.");
}
return -1;
}
// If a system window has focus, then it doesn't make sense
// right now to interact with applications.
WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
if (attrs != null) {
final int type = attrs.type;
if (type == WindowManager.LayoutParams.TYPE_KEYGUARD
|| type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) {
// the "app" is keyguard, so give it the key
return 0;
}
final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length;
for (int i=0; i<typeCount; i++) {
if (type == WINDOW_TYPES_WHERE_HOME_DOESNT_WORK[i]) {
// don't do anything, but also don't pass it to the app
return -1;
}
}
}
if (down) {
if (repeatCount == 0) {
mHomePressed = true;
} else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
if (!keyguardOn) {
handleLongPressOnHome();
}
}
}
return -1;
} else if (keyCode == KeyEvent.KEYCODE_MENU) {
// Hijack modified menu keys for debugging features
final int chordBug = KeyEvent.META_SHIFT_ON;
if (down && repeatCount == 0) {
if (mEnableShiftMenuBugReports && (metaState & chordBug) == chordBug) {
Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
mContext.sendOrderedBroadcast(intent, null);
return -1;
} else if (SHOW_PROCESSES_ON_ALT_MENU &&
(metaState & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) {
Intent service = new Intent();
service.setClassName(mContext, "com.android.server.LoadAverageService");
ContentResolver res = mContext.getContentResolver();
boolean shown = Settings.System.getInt(
res, Settings.System.SHOW_PROCESSES, 0) != 0;
if (!shown) {
mContext.startService(service);
} else {
mContext.stopService(service);
}
Settings.System.putInt(
res, Settings.System.SHOW_PROCESSES, shown ? 0 : 1);
return -1;
}
}
} else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
if (down) {
if (repeatCount == 0) {
mShortcutKeyPressed = keyCode;
mConsumeShortcutKeyUp = false;
}
} else if (keyCode == mShortcutKeyPressed) {
mShortcutKeyPressed = -1;
if (mConsumeShortcutKeyUp) {
mConsumeShortcutKeyUp = false;
return -1;
}
}
return 0;
} else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) {
if (down && repeatCount == 0) {
showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS);
}
return -1;
}
// Shortcuts are invoked through Search+key, so intercept those here
// Any printing key that is chorded with Search should be consumed
// even if no shortcut was invoked. This prevents text from being
// inadvertently inserted when using a keyboard that has built-in macro
// shortcut keys (that emit Search+x) and some of them are not registered.
if (mShortcutKeyPressed != -1) {
final KeyCharacterMap kcm = event.getKeyCharacterMap();
if (kcm.isPrintingKey(keyCode)) {
mConsumeShortcutKeyUp = true;
if (down && repeatCount == 0 && !keyguardOn) {
Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode, metaState);
if (shortcutIntent != null) {
shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
mContext.startActivity(shortcutIntent);
} catch (ActivityNotFoundException ex) {
Slog.w(TAG, "Dropping shortcut key combination because "
+ "the activity to which it is registered was not found: "
+ KeyEvent.keyCodeToString(mShortcutKeyPressed)
+ "+" + KeyEvent.keyCodeToString(keyCode), ex);
}
} else {
Slog.i(TAG, "Dropping unregistered shortcut key combination: "
+ KeyEvent.keyCodeToString(mShortcutKeyPressed)
+ "+" + KeyEvent.keyCodeToString(keyCode));
}
}
return -1;
}
}
粗体部分就是处理HOME键的地方我加了一个广播,在应用程序里面按下面的方式处理就能拦截到HOME键了
BroadcastReceiver myBroadcastReceivernew= new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub String homeKey = intent.getExtras().get("HomeKey").toString(); Log.i(tag, homeKey); } }; IntentFilter intentFilter = new IntentFilter( "HomeKeyDispatch" ); registerReceiver( myBroadcastReceivernew , intentFilter);
这样就可以拦截到HOME键了,希望大家相互讨论!