主要涉及的文件有:
WindowManagerService.java ? frameworks\base\services\java\com\android\server\
PhoneWindow.java ? ? ? ? ? ? ? ? ? ??frameworks\policies\base\phone\com\android\internal\policy\impl
KeyInputQueue.java ? ? ? ? ? ? ? ? ? frameworks\base\services\java\com\android\server
com_android_server_KeyInputQueue.cpp ? ?frameworks\base\services\jni
EventHub.cpp ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? frameworks\base\libs\ui
WindowManagerService.java主要有兩個線程,一個負責分發按鍵的InputDisapath Thread,另一個負責從底層讀取按鍵消息InputDeviceRender Thread。
WindowManagerService.java的成員類KeyQ(),負責獲取各種按鍵設備的狀態,它繼承于KeyInputQueue類。通過線程InputDeviceRender Thread的readEvent對按鍵消息不停讀取,然后調用KeyQ實例化后的processEvent函數告訴該按鍵是否應該傳給上層。接著WindowManagerService通過InputDisPatch Thread在按鍵消息隊列里取出,并進行分發。
由此可知,InputDisapath線程負責分發,InputDeviceRender線程通過jni方式調用android_server_KeyInputQueue_readEvent(),在這里負責轉化C++的按鍵消息為java的格式,android_server_KeyInputQueue_readEvent在EventHub.cpp中獲取按鍵消息。
具體一些細節代碼如下:
WindowManagerService中的KeyQ()類,preporcessEvent函數負責對按鍵進行預處理,?主要的事件類型包括EV_KEY(按鍵事件)、EV_REL(相對值,如鼠標移動,報告相對于最后一次位置的偏移)和EV_ABS(絕對值,如觸摸屏)。
[java] view plaincopyprint?
@Override ??boolean ?preprocessEvent(InputDevice?device,?RawInputEvent?event)?{??????if ?(mPolicy.preprocessInputEventTq(event))?{?? ????????return ?true ;?? ????}?? ?? ????switch ?(event.type)?{?? ????????case ?RawInputEvent.EV_KEY:?{?? ???????????? ?? ????????????if ?(DEBUG)?{?? ????????????????if ?(event.keycode?==?KeyEvent.KEYCODE_G)?{?? ????????????????????if ?(event.value?!=?0 )?{?? ?????????????????????????? ????????????????????????mPolicy.screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);?? ????????????????????}?? ????????????????????return ?false ;?? ????????????????}?? ????????????????if ?(event.keycode?==?KeyEvent.KEYCODE_D)?{?? ????????????????????if ?(event.value?!=?0 )?{?? ?????????????????????????? ????????????????????}?? ????????????????????return ?false ;?? ????????????????}?? ????????????}?? ???????????? ?? ?? ????????????boolean ?screenIsOff?=?!mPowerManager.isScreenOn();?? ????????????boolean ?screenIsDim?=?!mPowerManager.isScreenBright();?? ????????????int ?actions?=?mPolicy.interceptKeyTq(event,?!screenIsOff);/?? ?? ????????????if ?((actions?&?WindowManagerPolicy.ACTION_GO_TO_SLEEP)?!=?0 )?{?? ????????????????mPowerManager.goToSleep(event.when);?? ????????????}?? ?? ????????????if ?(screenIsOff)?{?? ????????????????event.flags?|=?WindowManagerPolicy.FLAG_WOKE_HERE;?? ????????????}?? ????????????if ?(screenIsDim)?{?? ????????????????event.flags?|=?WindowManagerPolicy.FLAG_BRIGHT_HERE;?? ????????????}?? ????????????if ?((actions?&?WindowManagerPolicy.ACTION_POKE_USER_ACTIVITY)?!=?0 )?{?? ????????????????mPowerManager.userActivity(event.when,?false ,?? ????????????????????????LocalPowerManager.BUTTON_EVENT,?false );?? ????????????}?? ?? ????????????if ?((actions?&?WindowManagerPolicy.ACTION_PASS_TO_USER)?!=?0 )?{?? ????????????????if ?(event.value?!=?0 ?&&?mPolicy.isAppSwitchKeyTqTiLwLi(event.keycode))?{?? ????????????????????filterQueue(this );?? ????????????????????mKeyWaiter.appSwitchComing();?? ????????????????}?? ????????????????return ?true ;?? ????????????}?else ?{?? ????????????????return ?false ;?? ????????????}?? ????????}?? ?? ????????case ?RawInputEvent.EV_REL:?{?? ????????????boolean ?screenIsOff?=?!mPowerManager.isScreenOn();?? ????????????boolean ?screenIsDim?=?!mPowerManager.isScreenBright();?? ????????????if ?(screenIsOff)?{?? ????????????????if ?(!mPolicy.isWakeRelMovementTq(event.deviceId,?? ????????????????????????device.classes,?event))?{?? ?????????????????????? ????????????????????return ?false ;?? ????????????????}?? ????????????????event.flags?|=?WindowManagerPolicy.FLAG_WOKE_HERE;?? ????????????}?? ????????????if ?(screenIsDim)?{?? ????????????????event.flags?|=?WindowManagerPolicy.FLAG_BRIGHT_HERE;?? ????????????}?? ????????????return ?true ;?? ????????}?? ?? ????????case ?RawInputEvent.EV_ABS:?{?? ????????????boolean ?screenIsOff?=?!mPowerManager.isScreenOn();?? ????????????boolean ?screenIsDim?=?!mPowerManager.isScreenBright();?? ????????????if ?(screenIsOff)?{?? ????????????????if ?(!mPolicy.isWakeAbsMovementTq(event.deviceId,?? ????????????????????????device.classes,?event))?{?? ?????????????????????? ????????????????????return ?false ;?? ????????????????}?? ????????????????event.flags?|=?WindowManagerPolicy.FLAG_WOKE_HERE;?? ????????????}?? ????????????if ?(screenIsDim)?{?? ????????????????event.flags?|=?WindowManagerPolicy.FLAG_BRIGHT_HERE;?? ????????????}?? ????????????return ?true ;?? ????????}?? ?? ????????default :?? ????????????return ?true ;?? ????}?? }??
@Overrideboolean preprocessEvent(InputDevice device, RawInputEvent event) {if (mPolicy.preprocessInputEventTq(event)) {return true;}switch (event.type) {case RawInputEvent.EV_KEY: {// XXX begin hackif (DEBUG) {if (event.keycode == KeyEvent.KEYCODE_G) {if (event.value != 0) {// G downmPolicy.screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);}return false;}if (event.keycode == KeyEvent.KEYCODE_D) {if (event.value != 0) {//dump();}return false;}}// XXX end hackboolean screenIsOff = !mPowerManager.isScreenOn();boolean screenIsDim = !mPowerManager.isScreenBright();int actions = mPolicy.interceptKeyTq(event, !screenIsOff);/**********按鍵預處理********//if ((actions & WindowManagerPolicy.ACTION_GO_TO_SLEEP) != 0) {mPowerManager.goToSleep(event.when);}if (screenIsOff) {event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;}if (screenIsDim) {event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;}if ((actions & WindowManagerPolicy.ACTION_POKE_USER_ACTIVITY) != 0) {mPowerManager.userActivity(event.when, false,LocalPowerManager.BUTTON_EVENT, false);}if ((actions & WindowManagerPolicy.ACTION_PASS_TO_USER) != 0) {if (event.value != 0 && mPolicy.isAppSwitchKeyTqTiLwLi(event.keycode)) {filterQueue(this);mKeyWaiter.appSwitchComing();}return true;} else {return false;}}case RawInputEvent.EV_REL: {boolean screenIsOff = !mPowerManager.isScreenOn();boolean screenIsDim = !mPowerManager.isScreenBright();if (screenIsOff) {if (!mPolicy.isWakeRelMovementTq(event.deviceId,device.classes, event)) {//Slog.i(TAG, "dropping because screenIsOff and !isWakeKey");return false;}event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;}if (screenIsDim) {event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;}return true;}case RawInputEvent.EV_ABS: {boolean screenIsOff = !mPowerManager.isScreenOn();boolean screenIsDim = !mPowerManager.isScreenBright();if (screenIsOff) {if (!mPolicy.isWakeAbsMovementTq(event.deviceId,device.classes, event)) {//Slog.i(TAG, "dropping because screenIsOff and !isWakeKey");return false;}event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;}if (screenIsDim) {event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;}return true;}default:return true;}}
preporcessEvent調用了InterceptKeyTQ
PhoneWindowManager.java中的InterceptKeyTQ判斷該按鍵是否應該送給上層,還是在此層進行截取,如待機休眠喚醒則在此層進行截取。
[java] view plaincopyprint?
????
??/** {@inheritDoc} */
[java] view plaincopyprint?
?? ????public ?int ?interceptKeyTq(RawInputEvent?event,?boolean ?screenIsOn)?{?? ????????int ?result?=?ACTION_PASS_TO_USER;?? ????????final ?boolean ?isWakeKey?=?isWakeKeyTq(event);?? ?????????? ?????????? ?????????? ?????????? ????????final ?boolean ?keyguardActive?=?(screenIsOn???? ????????????????????????????????????????mKeyguardMediator.isShowingAndNotHidden()?:?? ????????????????????????????????????????mKeyguardMediator.isShowing());?? ?? ?? ????????if ?(false )?{?? ????????????Log.d(TAG,?"interceptKeyTq?event=" ?+?event?+?"?keycode=" ?+?event.keycode?? ??????????????????+?"?screenIsOn=" ?+?screenIsOn?+?"?keyguardActive=" ?+?keyguardActive);?? ????????}?? ?? ?? ????????if ?(keyguardActive)?{?? ????????????if ?(screenIsOn)?{?? ?????????????????? ????????????????result?|=?ACTION_PASS_TO_USER;?? ????????????}?else ?{?? ?????????????????? ????????????????result?&=?~ACTION_PASS_TO_USER;?? ?? ?? ????????????????final ?boolean ?isKeyDown?=?? ????????????????????????(event.type?==?RawInputEvent.EV_KEY)?&&?(event.value?!=?0 );?? ????????????????if ?(isWakeKey?&&?isKeyDown)?{?? ?? ?? ?????????????????????? ?????????????????????? ???????????????????? ?? ????????????????????if ?(!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(event.keycode)?? ????????????????????????????&&?(event.keycode?==?KeyEvent.KEYCODE_VOLUME_DOWN?? ????????????????????????????????||?event.keycode?==?KeyEvent.KEYCODE_VOLUME_UP))?{?? ?????????????????????????? ?????????????????????????? ????????????????????????if ?(isInCall())?{?? ????????????????????????????handleVolumeKey(AudioManager.STREAM_VOICE_CALL,?event.keycode);?? ????????????????????????}?else ?if ?(isMusicActive())?{?? ????????????????????????????handleVolumeKey(AudioManager.STREAM_MUSIC,?event.keycode);?? ????????????????????????}?? ????????????????????}?? ????????????????}?? ????????????}?? ????????}?else ?if ?(!screenIsOn)?{?? ?????????????? ?????????????? ?????????????? ?????????????? ????????????if ?(isInCall()?&&?event.type?==?RawInputEvent.EV_KEY?&&?? ?????????????????????(event.keycode?==?KeyEvent.KEYCODE_VOLUME_DOWN?? ????????????????????????????????||?event.keycode?==?KeyEvent.KEYCODE_VOLUME_UP))?{?? ????????????????result?&=?~ACTION_PASS_TO_USER;?? ????????????????handleVolumeKey(AudioManager.STREAM_VOICE_CALL,?event.keycode);?? ????????????}?? ????????????if ?(isWakeKey)?{?? ?????????????????? ?????????????????? ????????????????result?|=?ACTION_POKE_USER_ACTIVITY;?? ????????????????result?&=?~ACTION_PASS_TO_USER;?? ????????????}?? ????????}?? ?? ?? ????????int ?type?=?event.type;?? ????????int ?code?=?event.keycode;?? ????????boolean ?down?=?event.value?!=?0 ;?? ?? ?? ????????if ?(type?==?RawInputEvent.EV_KEY)?{?? ????????????if ?(code?==?KeyEvent.KEYCODE_ENDCALL?? ????????????????????||?code?==?KeyEvent.KEYCODE_POWER)?{?? ????????????????if ?(down)?{?? ????????????????????boolean ?handled?=?false ;?? ????????????????????boolean ?hungUp?=?false ;?? ?????????????????????? ?????????????????????? ?????????????????????? ????????????????????ITelephony?phoneServ?=?getPhoneInterface();?? ????????????????????if ?(phoneServ?!=?null )?{?? ????????????????????????try ?{?? ????????????????????????????if ?(code?==?KeyEvent.KEYCODE_ENDCALL)?{?? ????????????????????????????????handled?=?hungUp?=?phoneServ.endCall();?? ????????????????????????????}?else ?if ?(code?==?KeyEvent.KEYCODE_POWER)?{?? ????????????????????????????????if ?(phoneServ.isRinging())?{?? ?????????????????????????????????????? ?????????????????????????????????????? ????????????????????????????????????phoneServ.silenceRinger();?? ????????????????????????????????????handled?=?true ;?? ????????????????????????????????}?else ?if ?(phoneServ.isOffhook()?&&?? ???????????????????????????????????????????((mIncallPowerBehavior?? ?????????????????????????????????????????????&?Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP)?? ????????????????????????????????????????????!=?0 ))?{?? ?????????????????????????????????????? ?????????????????????????????????????? ????????????????????????????????????handled?=?hungUp?=?phoneServ.endCall();?? ????????????????????????????????}?? ????????????????????????????}?? ????????????????????????}?catch ?(RemoteException?ex)?{?? ????????????????????????????Log.w(TAG,?"ITelephony?threw?RemoteException" ?+?ex);?? ????????????????????????}?? ????????????????????}?else ?{?? ????????????????????????Log.w(TAG,?"!!!?Unable?to?find?ITelephony?interface?!!!" );?? ????????????????????}?? ?? ?? ????????????????????if ?(!screenIsOn?? ????????????????????????????||?(handled?&&?code?!=?KeyEvent.KEYCODE_POWER)?? ????????????????????????????||?(handled?&&?hungUp?&&?code?==?KeyEvent.KEYCODE_POWER))?{?? ????????????????????????mShouldTurnOffOnKeyUp?=?false ;?? ????????????????????}?else ?{?? ?????????????????????????? ????????????????????????mShouldTurnOffOnKeyUp?=?true ;?? ????????????????????????mHandler.postDelayed(mPowerLongPress,?? ????????????????????????????????ViewConfiguration.getGlobalActionKeyTimeout());?? ????????????????????????result?&=?~ACTION_PASS_TO_USER;?? ????????????????????}?? ????????????????}?else ?{?? ????????????????????mHandler.removeCallbacks(mPowerLongPress);?? ????????????????????if ?(mShouldTurnOffOnKeyUp)?{?? ????????????????????????mShouldTurnOffOnKeyUp?=?false ;?? ????????????????????????boolean ?gohome,?sleeps;?? ????????????????????????if ?(code?==?KeyEvent.KEYCODE_ENDCALL)?{?? ????????????????????????????gohome?=?(mEndcallBehavior?? ??????????????????????????????????????&?Settings.System.END_BUTTON_BEHAVIOR_HOME)?!=?0 ;?? ????????????????????????????sleeps?=?(mEndcallBehavior?? ??????????????????????????????????????&?Settings.System.END_BUTTON_BEHAVIOR_SLEEP)?!=?0 ;?? ????????????????????????}?else ?{?? ????????????????????????????gohome?=?false ;?? ????????????????????????????sleeps?=?true ;?? ????????????????????????}?? ????????????????????????if ?(keyguardActive?? ????????????????????????????????||?(sleeps?&&?!gohome)?? ????????????????????????????????||?(gohome?&&?!goHome()?&&?sleeps))?{?? ?????????????????????????????? ?????????????????????????????? ????????????????????????????Log.d(TAG,?"I'm?tired?mEndcallBehavior=0x" ?? ????????????????????????????????????+?Integer.toHexString(mEndcallBehavior));?? ????????????????????????????result?&=?~ACTION_POKE_USER_ACTIVITY;?? ????????????????????????????result?|=?ACTION_GO_TO_SLEEP;?? ????????????????????????}?? ????????????????????????result?&=?~ACTION_PASS_TO_USER;?? ????????????????????}?? ????????????????}?? ????????????}?else ?if ?(isMediaKey(code))?{?? ?????????????????? ?????????????????? ?????????????????? ????????????????if ?((result?&?ACTION_PASS_TO_USER)?==?0 )?{?? ?????????????????????? ?????????????????????? ?????????????????????? ????????????????????KeyEvent?keyEvent?=?new ?KeyEvent(event.when,?event.when,?? ????????????????????????????down???KeyEvent.ACTION_DOWN?:?KeyEvent.ACTION_UP,?? ????????????????????????????code,?0 );?? ????????????????????mBroadcastWakeLock.acquire();?? ????????????????????mHandler.post(new ?PassHeadsetKey(keyEvent));?? ????????????????}?? ????????????}?else ?if ?(code?==?KeyEvent.KEYCODE_CALL)?{?? ?????????????????? ?????????????????? ?????????????????? ???????????????? ?? ?? ?? ?????????????????? ?????????????????? ????????????????if ?(down)?{?? ????????????????????try ?{?? ????????????????????????ITelephony?phoneServ?=?getPhoneInterface();?? ????????????????????????if ?(phoneServ?!=?null )?{?? ????????????????????????????if ?(phoneServ.isRinging())?{?? ????????????????????????????????Log.i(TAG,?"interceptKeyTq:" ?? ??????????????????????????????????????+?"?CALL?key-down?while?ringing:?Answer?the?call!" );?? ????????????????????????????????phoneServ.answerRingingCall();?? ?? ?? ?????????????????????????????????? ?????????????????????????????????? ????????????????????????????????result?&=?~ACTION_PASS_TO_USER;?? ????????????????????????????}?? ????????????????????????}?else ?{?? ????????????????????????????Log.w(TAG,?"CALL?button:?Unable?to?find?ITelephony?interface" );?? ????????????????????????}?? ????????????????????}?catch ?(RemoteException?ex)?{?? ????????????????????????Log.w(TAG,?"CALL?button:?RemoteException?from?getPhoneInterface()" ,?ex);?? ????????????????????}?? ????????????????}?? ????????????}?else ?if ?((code?==?KeyEvent.KEYCODE_VOLUME_UP)?? ???????????????????????||?(code?==?KeyEvent.KEYCODE_VOLUME_DOWN))?{?? ?????????????????? ?????????????????? ?????????????????? ?????????????????? ?? ?? ?????????????????? ?????????????????? ????????????????if ?(down)?{?? ????????????????????try ?{?? ????????????????????????ITelephony?phoneServ?=?getPhoneInterface();?? ????????????????????????if ?(phoneServ?!=?null )?{?? ????????????????????????????if ?(phoneServ.isRinging())?{?? ????????????????????????????????Log.i(TAG,?"interceptKeyTq:" ?? ??????????????????????????????????????+?"?VOLUME?key-down?while?ringing:?Silence?ringer!" );?? ?????????????????????????????????? ?????????????????????????????????? ????????????????????????????????phoneServ.silenceRinger();?? ?? ?? ?????????????????????????????????? ?????????????????????????????????? ????????????????????????????????result?&=?~ACTION_PASS_TO_USER;?? ????????????????????????????}?? ????????????????????????}?else ?{?? ????????????????????????????Log.w(TAG,?"VOLUME?button:?Unable?to?find?ITelephony?interface" );?? ????????????????????????}?? ????????????????????}?catch ?(RemoteException?ex)?{?? ????????????????????????Log.w(TAG,?"VOLUME?button:?RemoteException?from?getPhoneInterface()" ,?ex);?? ????????????????????}?? ????????????????}?? ????????????}?? ????????}?? ?? ?? ????????return ?result;?? ????}??
//2.3中名為interceptKeyBeforeQueueingpublic int interceptKeyTq(RawInputEvent event, boolean screenIsOn) {int result = ACTION_PASS_TO_USER;final boolean isWakeKey = isWakeKeyTq(event);// If screen is off then we treat the case where the keyguard is open but hidden// the same as if it were open and in front.// This will prevent any keys other than the power button from waking the screen// when the keyguard is hidden by another activity.final boolean keyguardActive = (screenIsOn ?mKeyguardMediator.isShowingAndNotHidden() :mKeyguardMediator.isShowing());if (false) {Log.d(TAG, "interceptKeyTq event=" + event + " keycode=" + event.keycode+ " screenIsOn=" + screenIsOn + " keyguardActive=" + keyguardActive);}if (keyguardActive) {if (screenIsOn) {// when the screen is on, always give the event to the keyguardresult |= ACTION_PASS_TO_USER;} else {// otherwise, don't pass it to the userresult &= ~ACTION_PASS_TO_USER;final boolean isKeyDown =(event.type == RawInputEvent.EV_KEY) && (event.value != 0);if (isWakeKey && isKeyDown) {// tell the mediator about a wake key, it may decide to// turn on the screen depending on whether the key is// appropriate.if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(event.keycode)&& (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN|| event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) {// when keyguard is showing and screen off, we need// to handle the volume key for calls and ?music hereif (isInCall()) {handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode);} else if (isMusicActive()) {handleVolumeKey(AudioManager.STREAM_MUSIC, event.keycode);}}}}} else if (!screenIsOn) {// If we are in-call with screen off and keyguard is not showing,// then handle the volume key ourselves.// This is necessary because the phone app will disable the keyguard// when the proximity sensor is in use.if (isInCall() && event.type == RawInputEvent.EV_KEY &&(event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN|| event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) {result &= ~ACTION_PASS_TO_USER;handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode);}if (isWakeKey) {// a wake key has a sole purpose of waking the device; don't pass// it to the userresult |= ACTION_POKE_USER_ACTIVITY;result &= ~ACTION_PASS_TO_USER;}}int type = event.type;int code = event.keycode;boolean down = event.value != 0;if (type == RawInputEvent.EV_KEY) {if (code == KeyEvent.KEYCODE_ENDCALL|| code == KeyEvent.KEYCODE_POWER) {if (down) {boolean handled = false;boolean hungUp = false;// key repeats are generated by the window manager, and we don't see them// here, so unless the driver is doing something it shouldn't be, we know// this is the real press event.ITelephony phoneServ = getPhoneInterface();if (phoneServ != null) {try {if (code == KeyEvent.KEYCODE_ENDCALL) {handled = hungUp = phoneServ.endCall();} else if (code == KeyEvent.KEYCODE_POWER) {if (phoneServ.isRinging()) {// Pressing Power while there's a ringing incoming// call should silence the ringer.phoneServ.silenceRinger();handled = true;} else if (phoneServ.isOffhook() &&((mIncallPowerBehavior& Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP)!= 0)) {// Otherwise, if "Power button ends call" is enabled,// the Power button will hang up any current active call.handled = hungUp = phoneServ.endCall();}}} catch (RemoteException ex) {Log.w(TAG, "ITelephony threw RemoteException" + ex);}} else {Log.w(TAG, "!!! Unable to find ITelephony interface !!!");}if (!screenIsOn|| (handled && code != KeyEvent.KEYCODE_POWER)|| (handled && hungUp && code == KeyEvent.KEYCODE_POWER)) {mShouldTurnOffOnKeyUp = false;} else {// only try to turn off the screen if we didn't already hang upmShouldTurnOffOnKeyUp = true;mHandler.postDelayed(mPowerLongPress,ViewConfiguration.getGlobalActionKeyTimeout());result &= ~ACTION_PASS_TO_USER;}} else {mHandler.removeCallbacks(mPowerLongPress);if (mShouldTurnOffOnKeyUp) {mShouldTurnOffOnKeyUp = false;boolean gohome, sleeps;if (code == KeyEvent.KEYCODE_ENDCALL) {gohome = (mEndcallBehavior& Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0;sleeps = (mEndcallBehavior& Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0;} else {gohome = false;sleeps = true;}if (keyguardActive|| (sleeps && !gohome)|| (gohome && !goHome() && sleeps)) {// they must already be on the keyguad or home screen,// go to sleep insteadLog.d(TAG, "I'm tired mEndcallBehavior=0x"+ Integer.toHexString(mEndcallBehavior));result &= ~ACTION_POKE_USER_ACTIVITY;result |= ACTION_GO_TO_SLEEP;}result &= ~ACTION_PASS_TO_USER;}}} else if (isMediaKey(code)) {// This key needs to be handled even if the screen is off.// If others need to be handled while it's off, this is a reasonable// pattern to follow.if ((result & ACTION_PASS_TO_USER) == 0) {// Only do this if we would otherwise not pass it to the user. In that// case, the PhoneWindow class will do the same thing, except it will// only do it if the showing app doesn't process the key on its own.KeyEvent keyEvent = new KeyEvent(event.when, event.when,down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,code, 0);mBroadcastWakeLock.acquire();mHandler.post(new PassHeadsetKey(keyEvent));}} else if (code == KeyEvent.KEYCODE_CALL) {// If an incoming call is ringing, answer it!// (We handle this key here, rather than in the InCallScreen, to make// sure we'll respond to the key even if the InCallScreen hasn't come to// the foreground yet.)// We answer the call on the DOWN event, to agree with// the "fallback" behavior in the InCallScreen.if (down) {try {ITelephony phoneServ = getPhoneInterface();if (phoneServ != null) {if (phoneServ.isRinging()) {Log.i(TAG, "interceptKeyTq:"+ " CALL key-down while ringing: Answer the call!");phoneServ.answerRingingCall();// And *don't* pass this key thru to the current activity// (which is presumably the InCallScreen.)result &= ~ACTION_PASS_TO_USER;}} else {Log.w(TAG, "CALL button: Unable to find ITelephony interface");}} catch (RemoteException ex) {Log.w(TAG, "CALL button: RemoteException from getPhoneInterface()", ex);}}} else if ((code == KeyEvent.KEYCODE_VOLUME_UP)|| (code == KeyEvent.KEYCODE_VOLUME_DOWN)) {// If an incoming call is ringing, either VOLUME key means// "silence ringer". ?We handle these keys here, rather than// in the InCallScreen, to make sure we'll respond to them// even if the InCallScreen hasn't come to the foreground yet.// Look for the DOWN event here, to agree with the "fallback"// behavior in the InCallScreen.if (down) {try {ITelephony phoneServ = getPhoneInterface();if (phoneServ != null) {if (phoneServ.isRinging()) {Log.i(TAG, "interceptKeyTq:"+ " VOLUME key-down while ringing: Silence ringer!");// Silence the ringer. ?(It's safe to call this// even if the ringer has already been silenced.)phoneServ.silenceRinger();// And *don't* pass this key thru to the current activity// (which is probably the InCallScreen.)result &= ~ACTION_PASS_TO_USER;}} else {Log.w(TAG, "VOLUME button: Unable to find ITelephony interface");}} catch (RemoteException ex) {Log.w(TAG, "VOLUME button: RemoteException from getPhoneInterface()", ex);}}}}return result;}
WindowManagerService中的InputDispatcherThread線程process,在里頭調用mQueue(KeyQ類)的getEvent函數來獲取隊列中的消息,處理后分發。
[java] view plaincopyprint?
private ?void ?process()?{?????????????android.os.Process.setThreadPriority(?? ???????????????????android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);?? ?? ????????????? ???????????KeyEvent?lastKey?=?null ;?? ?? ????????????? ???????????long ?lastKeyTime?=?SystemClock.uptimeMillis();?? ???????????long ?nextKeyTime?=?lastKeyTime+LONG_WAIT;?? ???????????long ?downTime?=?0 ;?? ?? ????????????? ???????????int ?keyRepeatCount?=?0 ;?? ?? ????????????? ???????????boolean ?configChanged?=?false ;?? ?? ???????????while ?(true )?{?? ???????????????long ?curTime?=?SystemClock.uptimeMillis();?? ?? ???????????????if ?(DEBUG_INPUT)?Slog.v(?? ???????????????????TAG,?"Waiting?for?next?key:?now=" ?+?curTime?? ???????????????????+?",?repeat?@?" ?+?nextKeyTime);?? ?? ????????????????? ????????????????? ????????????????? ????????????????? ???????????????QueuedEvent?ev?=?mQueue.getEvent(?? ???????????????????(int )((!configChanged?&&?curTime?<?nextKeyTime)?? ?????????????????????????????(nextKeyTime-curTime)?:?0 ));?? ?? ???????????????if ?(DEBUG_INPUT?&&?ev?!=?null )?Slog.v(?? ???????????????????????TAG,?"Event:?type=" ?+?ev.classType?+?"?data=" ?+?ev.event);?? ?? ???????????????if ?(MEASURE_LATENCY)?{?? ???????????????????lt.sample("2?got?event??????????????" ,?System.nanoTime()?-?ev.whenNano);?? ???????????????}?? ?? ???????????????if ?(lastKey?!=?null ?&&?!mPolicy.allowKeyRepeat())?{?? ????????????????????? ???????????????????lastKey?=?null ;?? ???????????????????downTime?=?0 ;?? ???????????????????lastKeyTime?=?curTime;?? ???????????????????nextKeyTime?=?curTime?+?LONG_WAIT;?? ???????????????}?? ???????????????try ?{?? ???????????????????if ?(ev?!=?null )?{?? ???????????????????????curTime?=?SystemClock.uptimeMillis();?? ???????????????????????int ?eventType;?? ???????????????????????if ?(ev.classType?==?RawInputEvent.CLASS_TOUCHSCREEN)?{?? ???????????????????????????eventType?=?eventType((MotionEvent)ev.event);?? ???????????????????????}?else ?if ?(ev.classType?==?RawInputEvent.CLASS_KEYBOARD?||?? ???????????????????????????????????ev.classType?==?RawInputEvent.CLASS_TRACKBALL)?{?? ???????????????????????????eventType?=?LocalPowerManager.BUTTON_EVENT;?? ???????????????????????}?else ?{?? ???????????????????????????eventType?=?LocalPowerManager.OTHER_EVENT;?? ???????????????????????}?? ???????????????????????try ?{?? ???????????????????????????if ?((curTime?-?mLastBatteryStatsCallTime)?? ???????????????????????????????????>=?MIN_TIME_BETWEEN_USERACTIVITIES)?{?? ???????????????????????????????mLastBatteryStatsCallTime?=?curTime;?? ???????????????????????????????mBatteryStats.noteInputEvent();?? ???????????????????????????}?? ???????????????????????}?catch ?(RemoteException?e)?{?? ????????????????????????????? ???????????????????????}?? ?? ???????????????????????if ?(ev.classType?==?RawInputEvent.CLASS_CONFIGURATION_CHANGED)?{?? ????????????????????????????? ???????????????????????}?else ?if ?(eventType?!=?TOUCH_EVENT?? ???????????????????????????????&&?eventType?!=?LONG_TOUCH_EVENT?? ???????????????????????????????&&?eventType?!=?CHEEK_EVENT)?{?? ???????????????????????????mPowerManager.userActivity(curTime,?false ,?? ???????????????????????????????????eventType,?false );?? ???????????????????????}?else ?if ?(mLastTouchEventType?!=?eventType?? ???????????????????????????????||?(curTime?-?mLastUserActivityCallTime)?? ???????????????????????????????>=?MIN_TIME_BETWEEN_USERACTIVITIES)?{?? ???????????????????????????mLastUserActivityCallTime?=?curTime;?? ???????????????????????????mLastTouchEventType?=?eventType;?? ???????????????????????????mPowerManager.userActivity(curTime,?false ,?? ???????????????????????????????????eventType,?false );?? ???????????????????????}?? ?? ???????????????????????switch ?(ev.classType)?{?? ???????????????????????????case ?RawInputEvent.CLASS_KEYBOARD:?? ???????????????????????????????KeyEvent?ke?=?(KeyEvent)ev.event;?? ???????????????????????????????if ?(ke.isDown())?{?? ???????????????????????????????????lastKey?=?ke;?? ???????????????????????????????????downTime?=?curTime;?? ???????????????????????????????????keyRepeatCount?=?0 ;?? ???????????????????????????????????lastKeyTime?=?curTime;?? ???????????????????????????????????nextKeyTime?=?lastKeyTime?? ???????????????????????????????????????????+?ViewConfiguration.getLongPressTimeout();?? ???????????????????????????????????if ?(DEBUG_INPUT)?Slog.v(?? ???????????????????????????????????????TAG,?"Received?key?down:?first?repeat?@?" ?? ???????????????????????????????????????+?nextKeyTime);?? ???????????????????????????????}?else ?{?? ???????????????????????????????????lastKey?=?null ;?? ???????????????????????????????????downTime?=?0 ;?? ????????????????????????????????????? ???????????????????????????????????lastKeyTime?=?curTime;?? ???????????????????????????????????nextKeyTime?=?curTime?+?LONG_WAIT;?? ???????????????????????????????????if ?(DEBUG_INPUT)?Slog.v(?? ???????????????????????????????????????TAG,?"Received?key?up:?ignore?repeat?@?" ?? ???????????????????????????????????????+?nextKeyTime);?? ???????????????????????????????}?? ???????????????????????????????dispatchKey((KeyEvent)ev.event,?0 ,?0 );?? ???????????????????????????????mQueue.recycleEvent(ev);?? ???????????????????????????????break ;?? ???????????????????????????case ?RawInputEvent.CLASS_TOUCHSCREEN:?? ????????????????????????????????? ???????????????????????????????dispatchPointer(ev,?(MotionEvent)ev.event,?0 ,?0 );?? ???????????????????????????????break ;?? ???????????????????????????case ?RawInputEvent.CLASS_TRACKBALL:?? ???????????????????????????????dispatchTrackball(ev,?(MotionEvent)ev.event,?0 ,?0 );?? ???????????????????????????????break ;?? ???????????????????????????case ?RawInputEvent.CLASS_CONFIGURATION_CHANGED:?? ???????????????????????????????configChanged?=?true ;?? ???????????????????????????????break ;?? ???????????????????????????default :?? ???????????????????????????????mQueue.recycleEvent(ev);?? ???????????????????????????break ;?? ???????????????????????}?? ?? ???????????????????}?else ?if ?(configChanged)?{?? ???????????????????????configChanged?=?false ;?? ???????????????????????sendNewConfiguration();?? ?? ???????????????????}?else ?if ?(lastKey?!=?null )?{?? ???????????????????????curTime?=?SystemClock.uptimeMillis();?? ?? ????????????????????????? ????????????????????????? ???????????????????????if ?(DEBUG_INPUT)?Slog.v(?? ???????????????????????????TAG,?"Key?timeout:?repeat=" ?+?nextKeyTime?? ???????????????????????????+?",?now=" ?+?curTime);?? ???????????????????????if ?(curTime?<?nextKeyTime)?{?? ???????????????????????????continue ;?? ???????????????????????}?? ?? ???????????????????????lastKeyTime?=?nextKeyTime;?? ???????????????????????nextKeyTime?=?nextKeyTime?+?KEY_REPEAT_DELAY;?? ???????????????????????keyRepeatCount++;?? ???????????????????????if ?(DEBUG_INPUT)?Slog.v(?? ???????????????????????????TAG,?"Key?repeat:?count=" ?+?keyRepeatCount?? ???????????????????????????+?",?next?@?" ?+?nextKeyTime);?? ???????????????????????KeyEvent?newEvent;?? ???????????????????????if ?(downTime?!=?0 ?&&?(downTime?? ???????????????????????????????+?ViewConfiguration.getLongPressTimeout())?? ???????????????????????????????<=?curTime)?{?? ???????????????????????????newEvent?=?KeyEvent.changeTimeRepeat(lastKey,?? ???????????????????????????????????curTime,?keyRepeatCount,?? ???????????????????????????????????lastKey.getFlags()?|?KeyEvent.FLAG_LONG_PRESS);?? ???????????????????????????downTime?=?0 ;?? ???????????????????????}?else ?{?? ???????????????????????????newEvent?=?KeyEvent.changeTimeRepeat(lastKey,?? ???????????????????????????????????curTime,?keyRepeatCount);?? ???????????????????????}?? ???????????????????????dispatchKey(newEvent,?0 ,?0 );?? ?? ???????????????????}?else ?{?? ???????????????????????curTime?=?SystemClock.uptimeMillis();?? ?? ???????????????????????lastKeyTime?=?curTime;?? ???????????????????????nextKeyTime?=?curTime?+?LONG_WAIT;?? ???????????????????}?? ?? ???????????????}?catch ?(Exception?e)?{?? ???????????????????Slog.e(TAG,?? ???????????????????????"Input?thread?received?uncaught?exception:?" ?+?e,?e);?? ???????????????}?? ???????????}?? ???????}?? ???}??
private void process() {android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);// The last key event we sawKeyEvent lastKey = null;// Last keydown time for auto-repeating keyslong lastKeyTime = SystemClock.uptimeMillis();long nextKeyTime = lastKeyTime+LONG_WAIT;long downTime = 0;// How many successive repeats we generatedint keyRepeatCount = 0;// Need to report that configuration has changed?boolean configChanged = false;while (true) {long curTime = SystemClock.uptimeMillis();if (DEBUG_INPUT) Slog.v(TAG, "Waiting for next key: now=" + curTime+ ", repeat @ " + nextKeyTime);// Retrieve next event, waiting only as long as the next// repeat timeout. If the configuration has changed, then// don't wait at all -- we'll report the change as soon as// we have processed all events.QueuedEvent ev = mQueue.getEvent(//*****獲取隊列中的消息***//(int)((!configChanged && curTime < nextKeyTime)? (nextKeyTime-curTime) : 0));if (DEBUG_INPUT && ev != null) Slog.v(TAG, "Event: type=" + ev.classType + " data=" + ev.event);if (MEASURE_LATENCY) {lt.sample("2 got event ", System.nanoTime() - ev.whenNano);}if (lastKey != null && !mPolicy.allowKeyRepeat()) {// cancel key repeat at the request of the policy.lastKey = null;downTime = 0;lastKeyTime = curTime;nextKeyTime = curTime + LONG_WAIT;}try {if (ev != null) {curTime = SystemClock.uptimeMillis();int eventType;if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) {eventType = eventType((MotionEvent)ev.event);} else if (ev.classType == RawInputEvent.CLASS_KEYBOARD ||ev.classType == RawInputEvent.CLASS_TRACKBALL) {eventType = LocalPowerManager.BUTTON_EVENT;} else {eventType = LocalPowerManager.OTHER_EVENT;}try {if ((curTime - mLastBatteryStatsCallTime)>= MIN_TIME_BETWEEN_USERACTIVITIES) {mLastBatteryStatsCallTime = curTime;mBatteryStats.noteInputEvent();}} catch (RemoteException e) {// Ignore}if (ev.classType == RawInputEvent.CLASS_CONFIGURATION_CHANGED) {// do not wake screen in this case} else if (eventType != TOUCH_EVENT&& eventType != LONG_TOUCH_EVENT&& eventType != CHEEK_EVENT) {mPowerManager.userActivity(curTime, false,eventType, false);} else if (mLastTouchEventType != eventType|| (curTime - mLastUserActivityCallTime)>= MIN_TIME_BETWEEN_USERACTIVITIES) {mLastUserActivityCallTime = curTime;mLastTouchEventType = eventType;mPowerManager.userActivity(curTime, false,eventType, false);}switch (ev.classType) {case RawInputEvent.CLASS_KEYBOARD:KeyEvent ke = (KeyEvent)ev.event;if (ke.isDown()) {lastKey = ke;downTime = curTime;keyRepeatCount = 0;lastKeyTime = curTime;nextKeyTime = lastKeyTime+ ViewConfiguration.getLongPressTimeout();if (DEBUG_INPUT) Slog.v(TAG, "Received key down: first repeat @ "+ nextKeyTime);} else {lastKey = null;downTime = 0;// Arbitrary long timeout.lastKeyTime = curTime;nextKeyTime = curTime + LONG_WAIT;if (DEBUG_INPUT) Slog.v(TAG, "Received key up: ignore repeat @ "+ nextKeyTime);}dispatchKey((KeyEvent)ev.event, 0, 0);mQueue.recycleEvent(ev);break;case RawInputEvent.CLASS_TOUCHSCREEN://Slog.i(TAG, "Read next event " + ev);dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);break;case RawInputEvent.CLASS_TRACKBALL:dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0);break;case RawInputEvent.CLASS_CONFIGURATION_CHANGED:configChanged = true;break;default:mQueue.recycleEvent(ev);break;}} else if (configChanged) {configChanged = false;sendNewConfiguration();} else if (lastKey != null) {curTime = SystemClock.uptimeMillis();// Timeout occurred while key was down. If it is at or// past the key repeat time, dispatch the repeat.if (DEBUG_INPUT) Slog.v(TAG, "Key timeout: repeat=" + nextKeyTime+ ", now=" + curTime);if (curTime < nextKeyTime) {continue;}lastKeyTime = nextKeyTime;nextKeyTime = nextKeyTime + KEY_REPEAT_DELAY;keyRepeatCount++;if (DEBUG_INPUT) Slog.v(TAG, "Key repeat: count=" + keyRepeatCount+ ", next @ " + nextKeyTime);KeyEvent newEvent;if (downTime != 0 && (downTime+ ViewConfiguration.getLongPressTimeout())<= curTime) {newEvent = KeyEvent.changeTimeRepeat(lastKey,curTime, keyRepeatCount,lastKey.getFlags() | KeyEvent.FLAG_LONG_PRESS);downTime = 0;} else {newEvent = KeyEvent.changeTimeRepeat(lastKey,curTime, keyRepeatCount);}dispatchKey(newEvent, 0, 0);} else {curTime = SystemClock.uptimeMillis();lastKeyTime = curTime;nextKeyTime = curTime + LONG_WAIT;}} catch (Exception e) {Slog.e(TAG,"Input thread received uncaught exception: " + e, e);}}}}
個人水平有限,有錯誤歡迎指出,謝謝。
補充:
1、生成
存在這樣一個線程,它不斷地從driver讀取Event,并把它放到RawEvent隊列中。這個隊列中的RawEvent既有按鍵,也有觸摸、軌跡球等事件。
RawEvent隊列中的每個RawEvent最后都會通過一系列轉化,最終變為KeyEvent被發送給另外一個線程,即輸入線程,也就是一個Activity的主線程。
2、傳遞
KeyEvent傳遞過程主要可以劃分為三步:過濾器、View樹、Activity
過濾器部分主要對應著PhoneWindowManager.java中的interceptKeyTq和interceptKeyTi這兩個方法。它們的代碼可以在frameworks/base/policy/base/phone/com/Android/internal/policy/impl/PhoneWindowManager.java中看到。
這兩個過濾器最大的不同就是interceptKeyTq用于RawEvent,而interceptKeyTi用于KeyEvent。
在一個沒有實體鍵盤的機器上,Power鍵會被interceptKeyTq這個過濾器吃掉用來調用關機對話框或者使機器休眠。而Home鍵會被interceptKeyTi這個過濾器吃掉,用來把當前Activity切換到后臺并把桌面程序切換到前臺。所以,應用程序在View和Activity的onKeyDown/Up中是監聽不到這兩個按鍵的。除了這兩個鍵以外的按鍵,都有機會繼續前進。接下來,KeyEvent會先經過interceptKeyTi過濾器,如果這個過濾器不吃掉的話,就會繼續前進,進入View樹,如果沒有被哪個View吃掉的話,最后進入到Activity的onKeyDown/Up方法中。
當一個KeyEvent經過上面的過程還沒有被吃掉的話,系統就會利用它做一些定制的功能。比如音量鍵被系統用來調整聲音,多媒體按鍵用來控制媒體播放,搜索鍵用來快速打開搜索功能,返回鍵用來退出當前Activity等
總結
以上是生活随笔 為你收集整理的Android system server之WindowManagerService按键消息传播流程 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。