@Override public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) { ... KeyEvent fallbackEvent = null; if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { final KeyCharacterMap kcm = event.getKeyCharacterMap(); final int keyCode = event.getKeyCode(); final int metaState = event.getMetaState(); final boolean initialDown = event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0;
// Check for fallback actions specified by the key character map. final FallbackAction fallbackAction; if (initialDown) { fallbackAction = kcm.getFallbackAction(keyCode, metaState); } else { fallbackAction = mFallbackActions.get(keyCode); }
if (fallbackAction != null) { if (DEBUG_INPUT) { Slog.d(TAG, "Fallback: keyCode=" + fallbackAction.keyCode + " metaState=" + Integer.toHexString(fallbackAction.metaState)); }
@Override public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) { ... // 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! if (!down) { cancelPreloadRecentApps();
// If an incoming call is ringing, HOME is totally disabled. // (The user is already on the InCallUI at this point, // and his ONLY options are to answer or reject the call.) TelecomManager telecomManager = getTelecommService(); if (telecomManager != null && telecomManager.isRinging()) { Log.i(TAG, "Ignoring HOME; there's a ringing incoming call."); return -1; }
// Delay handling home if a double-tap is possible. if (mDoubleTapOnHomeBehavior != DOUBLE_TAP_HOME_NOTHING) { mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable); // just in case mHomeDoubleTapPending = true; mHandler.postDelayed(mHomeDoubleTapTimeoutRunnable, ViewConfiguration.getDoubleTapTimeout()); return -1; }
handleShortPressOnHome(); 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_SCRIM || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) { // 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; } } }
// Remember that home is pressed and handle special actions. if (repeatCount == 0) { mHomePressed = true; if (mHomeDoubleTapPending) { mHomeDoubleTapPending = false; mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable); handleDoubleTapOnHome(); } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI || mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) { preloadRecentApps(); } } else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) { if (!keyguardOn) { handleLongPressOnHome(event.getDeviceId()); } } return -1; }
// Let the application handle the key. return 0; }
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; }
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; } }
// no keyguard stuff to worry about, just launch home! try { ActivityManagerNative.getDefault().stopAppSwitches(); } catch (RemoteException e) { } if (mRecentsVisible) { // Hide Recents and notify it to launch Home if (awakenFromDreams) { awakenDreams(); } sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY); hideRecentApps(false, true); } else { // Otherwise, just launch Home sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY); startDockOrHome(true /*fromHomeKey*/, awakenFromDreams); } }
// Amount of time after a call to stopAppSwitches() during which we will // prevent further untrusted switches from happening. static final long APP_SWITCH_DELAY_TIME = 5*1000;
然后我们可以看一下mHander的handleMessage方法的具体实现:
1 2 3 4 5
case DO_PENDING_ACTIVITY_LAUNCHES_MSG: { synchronized (ActivityManagerService.this) { mStackSupervisor.doPendingActivityLaunchesLocked(true); } } break;
@Override public void closeSystemDialogs(String reason) { enforceNotIsolatedCaller("closeSystemDialogs");
final int pid = Binder.getCallingPid(); final int uid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); try { synchronized (this) { // Only allow this from foreground processes, so that background // applications can't abuse it to prevent system UI from being shown. if (uid >= Process.FIRST_APPLICATION_UID) { ProcessRecord proc; synchronized (mPidsSelfLocked) { proc = mPidsSelfLocked.get(pid); } if (proc.curRawAdj > ProcessList.PERCEPTIBLE_APP_ADJ) { Slog.w(TAG, "Ignoring closeSystemDialogs " + reason + " from background process " + proc); return; } } closeSystemDialogsLocked(reason); } } finally { Binder.restoreCallingIdentity(origId); } }