主要涉及的文件有:

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?
  1. @Override
  2. boolean preprocessEvent(InputDevice device, RawInputEvent event) {
  3. if (mPolicy.preprocessInputEventTq(event)) {
  4. return true;
  5. }
  6. switch (event.type) {
  7. case RawInputEvent.EV_KEY: {
  8. // XXX begin hack
  9. if (DEBUG) {
  10. if (event.keycode == KeyEvent.KEYCODE_G) {
  11. if (event.value != 0) {
  12. // G down
  13. mPolicy.screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
  14. }
  15. return false;
  16. }
  17. if (event.keycode == KeyEvent.KEYCODE_D) {
  18. if (event.value != 0) {
  19. //dump();
  20. }
  21. return false;
  22. }
  23. }
  24. // XXX end hack
  25. boolean screenIsOff = !mPowerManager.isScreenOn();
  26. boolean screenIsDim = !mPowerManager.isScreenBright();
  27. int actions = mPolicy.interceptKeyTq(event, !screenIsOff);/**********按键预处理********//
  28. if ((actions & WindowManagerPolicy.ACTION_GO_TO_SLEEP) != 0) {
  29. mPowerManager.goToSleep(event.when);
  30. }
  31. if (screenIsOff) {
  32. event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
  33. }
  34. if (screenIsDim) {
  35. event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
  36. }
  37. if ((actions & WindowManagerPolicy.ACTION_POKE_USER_ACTIVITY) != 0) {
  38. mPowerManager.userActivity(event.when, false,
  39. LocalPowerManager.BUTTON_EVENT, false);
  40. }
  41. if ((actions & WindowManagerPolicy.ACTION_PASS_TO_USER) != 0) {
  42. if (event.value != 0 && mPolicy.isAppSwitchKeyTqTiLwLi(event.keycode)) {
  43. filterQueue(this);
  44. mKeyWaiter.appSwitchComing();
  45. }
  46. return true;
  47. } else {
  48. return false;
  49. }
  50. }
  51. case RawInputEvent.EV_REL: {
  52. boolean screenIsOff = !mPowerManager.isScreenOn();
  53. boolean screenIsDim = !mPowerManager.isScreenBright();
  54. if (screenIsOff) {
  55. if (!mPolicy.isWakeRelMovementTq(event.deviceId,
  56. device.classes, event)) {
  57. //Slog.i(TAG, "dropping because screenIsOff and !isWakeKey");
  58. return false;
  59. }
  60. event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
  61. }
  62. if (screenIsDim) {
  63. event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
  64. }
  65. return true;
  66. }
  67. case RawInputEvent.EV_ABS: {
  68. boolean screenIsOff = !mPowerManager.isScreenOn();
  69. boolean screenIsDim = !mPowerManager.isScreenBright();
  70. if (screenIsOff) {
  71. if (!mPolicy.isWakeAbsMovementTq(event.deviceId,
  72. device.classes, event)) {
  73. //Slog.i(TAG, "dropping because screenIsOff and !isWakeKey");
  74. return false;
  75. }
  76. event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
  77. }
  78. if (screenIsDim) {
  79. event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
  80. }
  81. return true;
  82. }
  83. default:
  84. return true;
  85. }
  86. }
        @Override
boolean preprocessEvent(InputDevice device, RawInputEvent event) {
if (mPolicy.preprocessInputEventTq(event)) {
return true;
}
switch (event.type) {
case RawInputEvent.EV_KEY: {
// XXX begin hack
if (DEBUG) {
if (event.keycode == KeyEvent.KEYCODE_G) {
if (event.value != 0) {
// G down
mPolicy.screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
}
return false;
}
if (event.keycode == KeyEvent.KEYCODE_D) {
if (event.value != 0) {
//dump();
}
return false;
}
}
// XXX end hack
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)) {
//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?
  1. /** {@inheritDoc} */
  /** {@inheritDoc} */
[java] view plaincopyprint?
  1. //2.3中名为interceptKeyBeforeQueueing
  2. public int interceptKeyTq(RawInputEvent event, boolean screenIsOn) {
  3. int result = ACTION_PASS_TO_USER;
  4. final boolean isWakeKey = isWakeKeyTq(event);
  5. // If screen is off then we treat the case where the keyguard is open but hidden
  6. // the same as if it were open and in front.
  7. // This will prevent any keys other than the power button from waking the screen
  8. // when the keyguard is hidden by another activity.
  9. final boolean keyguardActive = (screenIsOn ?
  10. mKeyguardMediator.isShowingAndNotHidden() :
  11. mKeyguardMediator.isShowing());
  12. if (false) {
  13. Log.d(TAG, "interceptKeyTq event=" + event + " keycode=" + event.keycode
  14. + " screenIsOn=" + screenIsOn + " keyguardActive=" + keyguardActive);
  15. }
  16. if (keyguardActive) {
  17. if (screenIsOn) {
  18. // when the screen is on, always give the event to the keyguard
  19. result |= ACTION_PASS_TO_USER;
  20. } else {
  21. // otherwise, don't pass it to the user
  22. result &= ~ACTION_PASS_TO_USER;
  23. final boolean isKeyDown =
  24. (event.type == RawInputEvent.EV_KEY) && (event.value != 0);
  25. if (isWakeKey && isKeyDown) {
  26. // tell the mediator about a wake key, it may decide to
  27. // turn on the screen depending on whether the key is
  28. // appropriate.
  29. if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(event.keycode)
  30. && (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN
  31. || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) {
  32. // when keyguard is showing and screen off, we need
  33. // to handle the volume key for calls and  music here
  34. if (isInCall()) {
  35. handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode);
  36. } else if (isMusicActive()) {
  37. handleVolumeKey(AudioManager.STREAM_MUSIC, event.keycode);
  38. }
  39. }
  40. }
  41. }
  42. } else if (!screenIsOn) {
  43. // If we are in-call with screen off and keyguard is not showing,
  44. // then handle the volume key ourselves.
  45. // This is necessary because the phone app will disable the keyguard
  46. // when the proximity sensor is in use.
  47. if (isInCall() && event.type == RawInputEvent.EV_KEY &&
  48. (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN
  49. || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) {
  50. result &= ~ACTION_PASS_TO_USER;
  51. handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode);
  52. }
  53. if (isWakeKey) {
  54. // a wake key has a sole purpose of waking the device; don't pass
  55. // it to the user
  56. result |= ACTION_POKE_USER_ACTIVITY;
  57. result &= ~ACTION_PASS_TO_USER;
  58. }
  59. }
  60. int type = event.type;
  61. int code = event.keycode;
  62. boolean down = event.value != 0;
  63. if (type == RawInputEvent.EV_KEY) {
  64. if (code == KeyEvent.KEYCODE_ENDCALL
  65. || code == KeyEvent.KEYCODE_POWER) {
  66. if (down) {
  67. boolean handled = false;
  68. boolean hungUp = false;
  69. // key repeats are generated by the window manager, and we don't see them
  70. // here, so unless the driver is doing something it shouldn't be, we know
  71. // this is the real press event.
  72. ITelephony phoneServ = getPhoneInterface();
  73. if (phoneServ != null) {
  74. try {
  75. if (code == KeyEvent.KEYCODE_ENDCALL) {
  76. handled = hungUp = phoneServ.endCall();
  77. } else if (code == KeyEvent.KEYCODE_POWER) {
  78. if (phoneServ.isRinging()) {
  79. // Pressing Power while there's a ringing incoming
  80. // call should silence the ringer.
  81. phoneServ.silenceRinger();
  82. handled = true;
  83. } else if (phoneServ.isOffhook() &&
  84. ((mIncallPowerBehavior
  85. & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP)
  86. != 0)) {
  87. // Otherwise, if "Power button ends call" is enabled,
  88. // the Power button will hang up any current active call.
  89. handled = hungUp = phoneServ.endCall();
  90. }
  91. }
  92. } catch (RemoteException ex) {
  93. Log.w(TAG, "ITelephony threw RemoteException" + ex);
  94. }
  95. } else {
  96. Log.w(TAG, "!!! Unable to find ITelephony interface !!!");
  97. }
  98. if (!screenIsOn
  99. || (handled && code != KeyEvent.KEYCODE_POWER)
  100. || (handled && hungUp && code == KeyEvent.KEYCODE_POWER)) {
  101. mShouldTurnOffOnKeyUp = false;
  102. } else {
  103. // only try to turn off the screen if we didn't already hang up
  104. mShouldTurnOffOnKeyUp = true;
  105. mHandler.postDelayed(mPowerLongPress,
  106. ViewConfiguration.getGlobalActionKeyTimeout());
  107. result &= ~ACTION_PASS_TO_USER;
  108. }
  109. } else {
  110. mHandler.removeCallbacks(mPowerLongPress);
  111. if (mShouldTurnOffOnKeyUp) {
  112. mShouldTurnOffOnKeyUp = false;
  113. boolean gohome, sleeps;
  114. if (code == KeyEvent.KEYCODE_ENDCALL) {
  115. gohome = (mEndcallBehavior
  116. & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0;
  117. sleeps = (mEndcallBehavior
  118. & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0;
  119. } else {
  120. gohome = false;
  121. sleeps = true;
  122. }
  123. if (keyguardActive
  124. || (sleeps && !gohome)
  125. || (gohome && !goHome() && sleeps)) {
  126. // they must already be on the keyguad or home screen,
  127. // go to sleep instead
  128. Log.d(TAG, "I'm tired mEndcallBehavior=0x"
  129. + Integer.toHexString(mEndcallBehavior));
  130. result &= ~ACTION_POKE_USER_ACTIVITY;
  131. result |= ACTION_GO_TO_SLEEP;
  132. }
  133. result &= ~ACTION_PASS_TO_USER;
  134. }
  135. }
  136. } else if (isMediaKey(code)) {
  137. // This key needs to be handled even if the screen is off.
  138. // If others need to be handled while it's off, this is a reasonable
  139. // pattern to follow.
  140. if ((result & ACTION_PASS_TO_USER) == 0) {
  141. // Only do this if we would otherwise not pass it to the user. In that
  142. // case, the PhoneWindow class will do the same thing, except it will
  143. // only do it if the showing app doesn't process the key on its own.
  144. KeyEvent keyEvent = new KeyEvent(event.when, event.when,
  145. down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
  146. code, 0);
  147. mBroadcastWakeLock.acquire();
  148. mHandler.post(new PassHeadsetKey(keyEvent));
  149. }
  150. } else if (code == KeyEvent.KEYCODE_CALL) {
  151. // If an incoming call is ringing, answer it!
  152. // (We handle this key here, rather than in the InCallScreen, to make
  153. // sure we'll respond to the key even if the InCallScreen hasn't come to
  154. // the foreground yet.)
  155. // We answer the call on the DOWN event, to agree with
  156. // the "fallback" behavior in the InCallScreen.
  157. if (down) {
  158. try {
  159. ITelephony phoneServ = getPhoneInterface();
  160. if (phoneServ != null) {
  161. if (phoneServ.isRinging()) {
  162. Log.i(TAG, "interceptKeyTq:"
  163. + " CALL key-down while ringing: Answer the call!");
  164. phoneServ.answerRingingCall();
  165. // And *don't* pass this key thru to the current activity
  166. // (which is presumably the InCallScreen.)
  167. result &= ~ACTION_PASS_TO_USER;
  168. }
  169. } else {
  170. Log.w(TAG, "CALL button: Unable to find ITelephony interface");
  171. }
  172. } catch (RemoteException ex) {
  173. Log.w(TAG, "CALL button: RemoteException from getPhoneInterface()", ex);
  174. }
  175. }
  176. } else if ((code == KeyEvent.KEYCODE_VOLUME_UP)
  177. || (code == KeyEvent.KEYCODE_VOLUME_DOWN)) {
  178. // If an incoming call is ringing, either VOLUME key means
  179. // "silence ringer".  We handle these keys here, rather than
  180. // in the InCallScreen, to make sure we'll respond to them
  181. // even if the InCallScreen hasn't come to the foreground yet.
  182. // Look for the DOWN event here, to agree with the "fallback"
  183. // behavior in the InCallScreen.
  184. if (down) {
  185. try {
  186. ITelephony phoneServ = getPhoneInterface();
  187. if (phoneServ != null) {
  188. if (phoneServ.isRinging()) {
  189. Log.i(TAG, "interceptKeyTq:"
  190. + " VOLUME key-down while ringing: Silence ringer!");
  191. // Silence the ringer.  (It's safe to call this
  192. // even if the ringer has already been silenced.)
  193. phoneServ.silenceRinger();
  194. // And *don't* pass this key thru to the current activity
  195. // (which is probably the InCallScreen.)
  196. result &= ~ACTION_PASS_TO_USER;
  197. }
  198. } else {
  199. Log.w(TAG, "VOLUME button: Unable to find ITelephony interface");
  200. }
  201. } catch (RemoteException ex) {
  202. Log.w(TAG, "VOLUME button: RemoteException from getPhoneInterface()", ex);
  203. }
  204. }
  205. }
  206. }
  207. return result;
  208. }
//2.3中名为interceptKeyBeforeQueueing
public 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 keyguard
result |= ACTION_PASS_TO_USER;
} else {
// otherwise, don't pass it to the user
result &= ~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 here
if (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 user
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;
// 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 up
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)) {
// they must already be on the keyguad or home screen,
// go to sleep instead
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)) {
// 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?
  1. private void process() {
  2. android.os.Process.setThreadPriority(
  3. android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
  4. // The last key event we saw
  5. KeyEvent lastKey = null;
  6. // Last keydown time for auto-repeating keys
  7. long lastKeyTime = SystemClock.uptimeMillis();
  8. long nextKeyTime = lastKeyTime+LONG_WAIT;
  9. long downTime = 0;
  10. // How many successive repeats we generated
  11. int keyRepeatCount = 0;
  12. // Need to report that configuration has changed?
  13. boolean configChanged = false;
  14. while (true) {
  15. long curTime = SystemClock.uptimeMillis();
  16. if (DEBUG_INPUT) Slog.v(
  17. TAG, "Waiting for next key: now=" + curTime
  18. + ", repeat @ " + nextKeyTime);
  19. // Retrieve next event, waiting only as long as the next
  20. // repeat timeout.  If the configuration has changed, then
  21. // don't wait at all -- we'll report the change as soon as
  22. // we have processed all events.
  23. QueuedEvent ev = mQueue.getEvent(//*****获取队列中的消息***//
  24. (int)((!configChanged && curTime < nextKeyTime)
  25. ? (nextKeyTime-curTime) : 0));
  26. if (DEBUG_INPUT && ev != null) Slog.v(
  27. TAG, "Event: type=" + ev.classType + " data=" + ev.event);
  28. if (MEASURE_LATENCY) {
  29. lt.sample("2 got event              ", System.nanoTime() - ev.whenNano);
  30. }
  31. if (lastKey != null && !mPolicy.allowKeyRepeat()) {
  32. // cancel key repeat at the request of the policy.
  33. lastKey = null;
  34. downTime = 0;
  35. lastKeyTime = curTime;
  36. nextKeyTime = curTime + LONG_WAIT;
  37. }
  38. try {
  39. if (ev != null) {
  40. curTime = SystemClock.uptimeMillis();
  41. int eventType;
  42. if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) {
  43. eventType = eventType((MotionEvent)ev.event);
  44. } else if (ev.classType == RawInputEvent.CLASS_KEYBOARD ||
  45. ev.classType == RawInputEvent.CLASS_TRACKBALL) {
  46. eventType = LocalPowerManager.BUTTON_EVENT;
  47. } else {
  48. eventType = LocalPowerManager.OTHER_EVENT;
  49. }
  50. try {
  51. if ((curTime - mLastBatteryStatsCallTime)
  52. >= MIN_TIME_BETWEEN_USERACTIVITIES) {
  53. mLastBatteryStatsCallTime = curTime;
  54. mBatteryStats.noteInputEvent();
  55. }
  56. } catch (RemoteException e) {
  57. // Ignore
  58. }
  59. if (ev.classType == RawInputEvent.CLASS_CONFIGURATION_CHANGED) {
  60. // do not wake screen in this case
  61. } else if (eventType != TOUCH_EVENT
  62. && eventType != LONG_TOUCH_EVENT
  63. && eventType != CHEEK_EVENT) {
  64. mPowerManager.userActivity(curTime, false,
  65. eventType, false);
  66. } else if (mLastTouchEventType != eventType
  67. || (curTime - mLastUserActivityCallTime)
  68. >= MIN_TIME_BETWEEN_USERACTIVITIES) {
  69. mLastUserActivityCallTime = curTime;
  70. mLastTouchEventType = eventType;
  71. mPowerManager.userActivity(curTime, false,
  72. eventType, false);
  73. }
  74. switch (ev.classType) {
  75. case RawInputEvent.CLASS_KEYBOARD:
  76. KeyEvent ke = (KeyEvent)ev.event;
  77. if (ke.isDown()) {
  78. lastKey = ke;
  79. downTime = curTime;
  80. keyRepeatCount = 0;
  81. lastKeyTime = curTime;
  82. nextKeyTime = lastKeyTime
  83. + ViewConfiguration.getLongPressTimeout();
  84. if (DEBUG_INPUT) Slog.v(
  85. TAG, "Received key down: first repeat @ "
  86. + nextKeyTime);
  87. } else {
  88. lastKey = null;
  89. downTime = 0;
  90. // Arbitrary long timeout.
  91. lastKeyTime = curTime;
  92. nextKeyTime = curTime + LONG_WAIT;
  93. if (DEBUG_INPUT) Slog.v(
  94. TAG, "Received key up: ignore repeat @ "
  95. + nextKeyTime);
  96. }
  97. dispatchKey((KeyEvent)ev.event, 0, 0);
  98. mQueue.recycleEvent(ev);
  99. break;
  100. case RawInputEvent.CLASS_TOUCHSCREEN:
  101. //Slog.i(TAG, "Read next event " + ev);
  102. dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);
  103. break;
  104. case RawInputEvent.CLASS_TRACKBALL:
  105. dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0);
  106. break;
  107. case RawInputEvent.CLASS_CONFIGURATION_CHANGED:
  108. configChanged = true;
  109. break;
  110. default:
  111. mQueue.recycleEvent(ev);
  112. break;
  113. }
  114. } else if (configChanged) {
  115. configChanged = false;
  116. sendNewConfiguration();
  117. } else if (lastKey != null) {
  118. curTime = SystemClock.uptimeMillis();
  119. // Timeout occurred while key was down.  If it is at or
  120. // past the key repeat time, dispatch the repeat.
  121. if (DEBUG_INPUT) Slog.v(
  122. TAG, "Key timeout: repeat=" + nextKeyTime
  123. + ", now=" + curTime);
  124. if (curTime < nextKeyTime) {
  125. continue;
  126. }
  127. lastKeyTime = nextKeyTime;
  128. nextKeyTime = nextKeyTime + KEY_REPEAT_DELAY;
  129. keyRepeatCount++;
  130. if (DEBUG_INPUT) Slog.v(
  131. TAG, "Key repeat: count=" + keyRepeatCount
  132. + ", next @ " + nextKeyTime);
  133. KeyEvent newEvent;
  134. if (downTime != 0 && (downTime
  135. + ViewConfiguration.getLongPressTimeout())
  136. <= curTime) {
  137. newEvent = KeyEvent.changeTimeRepeat(lastKey,
  138. curTime, keyRepeatCount,
  139. lastKey.getFlags() | KeyEvent.FLAG_LONG_PRESS);
  140. downTime = 0;
  141. } else {
  142. newEvent = KeyEvent.changeTimeRepeat(lastKey,
  143. curTime, keyRepeatCount);
  144. }
  145. dispatchKey(newEvent, 0, 0);
  146. } else {
  147. curTime = SystemClock.uptimeMillis();
  148. lastKeyTime = curTime;
  149. nextKeyTime = curTime + LONG_WAIT;
  150. }
  151. } catch (Exception e) {
  152. Slog.e(TAG,
  153. "Input thread received uncaught exception: " + e, e);
  154. }
  155. }
  156. }
  157. }
 private void process() {
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
// The last key event we saw
KeyEvent lastKey = null;
// Last keydown time for auto-repeating keys
long lastKeyTime = SystemClock.uptimeMillis();
long nextKeyTime = lastKeyTime+LONG_WAIT;
long downTime = 0;
// How many successive repeats we generated
int 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按键消息传播流程相关推荐

  1. Android System Server大纲之VibratorService

    Android System Server大纲之VibratorService vibrator Android System Server大纲之VibratorService 前言 Vibrator ...

  2. Android system server之WatchDog看门狗分析

    android -- WatchDog看门狗分析 在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界电磁场的干扰,造成程序的跑飞,而陷入死循环,程序的正常运行被打断,由单片机控制的系 ...

  3. Android system server之PackageManagerService详细分析

    概要 本篇主要分析了系统启动阶段包管理服务的启动流程,其中的几个接口在 apk 安装时也会被调用.包管理服务启动时主要做的工作大致有如下几方面: 1. 建立 java 层的 installer 与 c ...

  4. 【RK3288 Android 7.1 / KEN】双屏异显流程

    RK3288_Android 7.1 双屏异显流程 异显功能使能 控制代码位置: 触发异显 控制代码位置: 方法 1 主要流程: 方法 2 关键步骤: 异显流程 控制代码位置: setOnlyShow ...

  5. 图解Android - Zygote, System Server 启动分析

    Init 是所有Linux程序的起点,而Zygote于Android,正如它的英文意思,是所有java程序的'孵化池'(玩过星际虫族的兄弟都晓得的).用ps 输出可以看到 >adb shell ...

  6. 【Android】系统架构功能+init、zygote、system server、app等进程间关系分析

    文章目录 架构功能 Loader层 Linux内核层 硬件抽象层 (HAL) Android Runtime & 系统库 Framework层 App层 Syscall && ...

  7. android 按键消息,Android监听Home按键消息

    Android对屏幕下方常用的四个按键消息处理是不一致的: 搜索按键的消息在onKeyDown或者onKeyUp中接收: 菜单按键的消息在onCreateOptionsMenu.onKeyDown或o ...

  8. android物理按键输入法,Android输入法框架中按键消息的处理流程

    最近研究了一下Android输入法,发现Android输入法框架中按键消息的处理流程和一般应用程序的处理流程有很大的不同,故在此做个总结. 一.一些名词缩写 IMF(Input MethodFrame ...

  9. Android窗口管理服务WindowManagerService切换Activity窗口(App Transition)的过程分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8596449 在Android系统中,同一时刻只 ...

最新文章

  1. json请求 post vue_Spring Boot+Vueaxios异步请求数据的12种操作(上篇)
  2. [css] 用css画出一个圆圈,里面有个对号
  3. 【Codeforces - 977D】Divide by three, multiply by two(思维构造)
  4. Python学习笔记:模块与包
  5. 典型重构3 (Try/Catch)
  6. Python 面向对象 —— __init_ 与 __new__
  7. 【linux】最常用 150 个Linux命令汇总
  8. 拼多多打印订单有哪些软件?哪个软件好用呢?
  9. java购物系统需求分析_java网上购物系统需求分析.doc
  10. vb/vb.net开发技巧荟萃(七)
  11. jquery中判断元素是否含有某个类名
  12. 华为防火墙设置安全策略,封禁高危异常ip
  13. Linux 10个主流发行版本
  14. kudu学习资料总结
  15. 笨方法学习Python-习题36: 设计和调试
  16. 深入理解JVM—满足什么条件的对象才会进入老年代?
  17. GAVH39,PM1132,供电220v转5v芯片,SOT23-3,AC-DC小功率应用方案
  18. 小诗一首《钗头凤·七夕夜》
  19. TeXstudio 中英文混合编辑器显示异常
  20. 10个让你早起的技巧

热门文章

  1. 转:a标签中如果有button, 那么在IE下就不能跳转到herf的链接
  2. Android ----制作自己的Vendor
  3. string.Equals 比较2个字符串是否相同忽略大小写
  4. Linux CP文件夹略过目录的解决
  5. REST接口GET方法获取文件保存到本地(C#)
  6. UA STAT675 统计计算I 随机数生成6 Accept-Reject Algorithm
  7. UA MATH564 概率分布总结
  8. MFC用代码创建工具栏
  9. GIS影像数据集初步学习
  10. Windows内核工具Win64AST初步使用