Android system server之WindowManagerService按鍵訊息傳播流程
主要涉及的檔案有:
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(絕對值,如觸控式螢幕)。
- @Override
- boolean preprocessEvent(InputDevice device, RawInputEvent event) {
- if (mPolicy.preprocessInputEventTq(event)) {
- returntrue;
- }
- 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);
- }
- returnfalse;
- }
- if (event.keycode == KeyEvent.KEYCODE_D) {
- if (event.value != 0) {
- //dump();
- }
- returnfalse;
- }
- }
- // 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();
- }
- returntrue;
- } else {
- returnfalse;
- }
- }
- 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");
- returnfalse;
- }
- event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
- }
- if (screenIsDim) {
- event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
- }
- returntrue;
- }
- 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");
- returnfalse;
- }
- event.flags |= WindowManagerPolicy.FLAG_WOKE_HERE;
- }
- if (screenIsDim) {
- event.flags |= WindowManagerPolicy.FLAG_BRIGHT_HERE;
- }
- returntrue;
- }
- default:
- returntrue;
- }
- }
@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?- /** {@inheritDoc} */
/** {@inheritDoc} */
[java]
view plaincopyprint?
- //2.3中名為interceptKeyBeforeQueueing
- publicint interceptKeyTq(RawInputEvent event, boolean screenIsOn) {
- int result = ACTION_PASS_TO_USER;
- finalboolean 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.
- finalboolean 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;
- finalboolean 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);
- } elseif (isMusicActive()) {
- handleVolumeKey(AudioManager.STREAM_MUSIC, event.keycode);
- }
- }
- }
- }
- } elseif (!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();
- } elseif (code == KeyEvent.KEYCODE_POWER) {
- if (phoneServ.isRinging()) {
- // Pressing Power while there's a ringing incoming
- // call should silence the ringer.
- phoneServ.silenceRinger();
- handled = true;
- } elseif (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;
- }
- }
- } elseif (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));
- }
- } elseif (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);
- }
- }
- } elseif ((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;
- }
//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?
- privatevoid 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);
- } elseif (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
- } elseif (eventType != TOUCH_EVENT
- && eventType != LONG_TOUCH_EVENT
- && eventType != CHEEK_EVENT) {
- mPowerManager.userActivity(curTime, false,
- eventType, false);
- } elseif (mLastTouchEventType != eventType
- || (curTime - mLastUserActivityCallTime)
- >= MIN_TIME_BETWEEN_USERACTIVITIES) {
- mLastUserActivityCallTime = curTime;
- mLastTouchEventType = eventType;
- mPowerManager.userActivity(curTime, false,