http://yelinsen.iteye.com/blog/834866
现在在做双卡双待的项目!作为主要核心Phone遇到的问题也是千奇百怪!
今天就被一个问题困扰了一下午--来电后按声音按键需要静音!因为是双Phone对象所以对应的RINGER也有两个!
分析一下解BUG流程!
最开始以为按键处理会在InCallScreen.java里面的
Java代码
1.public boolean onKeyDown(int keyCode, KeyEvent event):
2. case KeyEvent.KEYCODE_VOLUME_UP:
3. case KeyEvent.KEYCODE_VOLUME_DOWN:
4.
5. Phone phone = PhoneApp.getInstance().getPhoneInCall();
6. if (phone.getState() == Phone.State.RINGING) {
7. // If an incoming call is ringing, the VOLUME buttons are
8. // actually handled by the PhoneWindowManager. (We do
9. // this to make sure that we'll respond to them even if
10. // the InCallScreen hasn't come to the foreground yet.)
11. //
12. // We'd only ever get here in the extremely rare case that the
13. // incoming call started ringing *after*
14. // PhoneWindowManager.interceptKeyTq() but before the event
15. // got here, or else if the PhoneWindowManager had some
16. // problem connecting to the ITelephony service.
17. Log.w(LOG_TAG, "VOLUME key: incoming call is ringing!"
18. + " (PhoneWindowManager should have handled this key.)");
19. // But go ahead and handle the key as normal, since the
20. // PhoneWindowManager presumably did NOT handle it:
21.
22. //TODO DSDS get the subscription from Phone
23. //int subscription = mPhone.getSubscriptionInfo();
24. final CallNotifier notifier;
25. if (TelephonyManager.isDsdsEnabled()) {
26. // Get the CallNotifier associated with the phone.
27. notifier = PhoneApp.getInstance().getCallNotifier(phone.getSubscription());
28. } else {
29. notifier = PhoneApp.getInstance().notifier;
30. }
31. if (notifier.isRinging()) {
32. // ringer is actually playing, so silence it.
33. PhoneUtils.setAudioControlState(PhoneUtils.AUDIO_IDLE);
34. if (DBG) log("VOLUME key: silence ringer");
35. notifier.silenceRinger();
36. }
37.
38. // As long as an incoming call is ringing, we always
39. // consume the VOLUME keys.
40. return true;
41. }
42. break;
public boolean onKeyDown(int keyCode, KeyEvent event):
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
Phone phone = PhoneApp.getInstance().getPhoneInCall();
if (phone.getState() == Phone.State.RINGING) {
// If an incoming call is ringing, the VOLUME buttons are
// actually handled by the PhoneWindowManager. (We do
// this to make sure that we'll respond to them even if
// the InCallScreen hasn't come to the foreground yet.)
//
// We'd only ever get here in the extremely rare case that the
// incoming call started ringing *after*
// PhoneWindowManager.interceptKeyTq() but before the event
// got here, or else if the PhoneWindowManager had some
// problem connecting to the ITelephony service.
Log.w(LOG_TAG, "VOLUME key: incoming call is ringing!"
+ " (PhoneWindowManager should have handled this key.)");
// But go ahead and handle the key as normal, since the
// PhoneWindowManager presumably did NOT handle it:
//TODO DSDS get the subscription from Phone
//int subscription = mPhone.getSubscriptionInfo();
final CallNotifier notifier;
if (TelephonyManager.isDsdsEnabled()) {
// Get the CallNotifier associated with the phone.
notifier = PhoneApp.getInstance().getCallNotifier(phone.getSubscription());
} else {
notifier = PhoneApp.getInstance().notifier;
}
if (notifier.isRinging()) {
// ringer is actually playing, so silence it.
PhoneUtils.setAudioControlState(PhoneUtils.AUDIO_IDLE);
if (DBG) log("VOLUME key: silence ringer");
notifier.silenceRinger();
}
// As long as an incoming call is ringing, we always
// consume the VOLUME keys.
return true;
}
break;
后来发现了这行注释
// Note there's no KeyEvent.KEYCODE_ENDCALL case here.
// The standard system-wide handling of the ENDCALL key
// (see PhoneWindowManager's handling of KEYCODE_ENDCALL)
// already implements exactly what the UI spec wants,
// namely (1) "hang up" if there's a current active call,
// or (2) "don't answer" if there's a current ringing call.
原来在WindowManagerService会有一个 int actions = mPolicy.interceptKeyTq(event, !screenIsOff);
对应的PhoneWindowManager里会有一个
Java代码
1.public int interceptKeyTq(RawInputEvent event, boolean screenIsOn);
public int interceptKeyTq(RawInputEvent event, boolean screenIsOn);
方法
此方法可以在最初的位置进行拦截事件处理!
Java代码
1.// If an incoming call is ringing, either VOLUME key means
2. // "silence ringer". We handle these keys here, rather than
3. // in the InCallScreen, to make sure we'll respond to them
4. // even if the InCallScreen hasn't come to the foreground yet.
5.
6. // Look for the DOWN event here, to agree with the "fallback"
7. // behavior in the InCallScreen.
8. if (down) {
9. try {
10. ITelephony phoneServ = getPhoneInterface();
11. if (phoneServ != null) {
12. if (phoneServ.isRinging()) {
13. Log.i(TAG, "interceptKeyTq:"
14. + " VOLUME key-down while ringing: Silence ringer!");
15. // Silence the ringer. (It's safe to call this
16. // even if the ringer has already been silenced.)
17. phoneServ.silenceRinger();
18.
19. // And *don't* pass this key thru to the current activity
20. // (which is probably the InCallScreen.)
21. result &= ~ACTION_PASS_TO_USER;
22. }
23. } else {
24. Log.w(TAG, "VOLUME button: Unable to find ITelephony interface");
25. }
26. } catch (RemoteException ex) {
27. Log.w(TAG, "VOLUME button: RemoteException from getPhoneInterface()", ex);
28. }
29. }
// 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);
}
}
phoneServ.silenceRinger();
Java代码
1.PhoneInterfaceManager.java
2.public void silenceRinger() {
3. if (DBG)
4. log("silenceRinger...");
5. // TODO: find a more appropriate permission to check here.
6. // (That can probably wait till the big TelephonyManager API overhaul.
7. // For now, protect this call with the MODIFY_PHONE_STATE permission.)
8. enforceModifyPermission();
9. sendRequestAsync(CMD_SILENCE_RINGER);
10. }
PhoneInterfaceManager.java
public void silenceRinger() {
if (DBG)
log("silenceRinger...");
// TODO: find a more appropriate permission to check here.
// (That can probably wait till the big TelephonyManager API overhaul.
// For now, protect this call with the MODIFY_PHONE_STATE permission.)
enforceModifyPermission();
sendRequestAsync(CMD_SILENCE_RINGER);
}
最终调用的是
Java代码
1.PhoneUtils.setAudioControlState(PhoneUtils.AUDIO_IDLE);
2. mApp.getCallNotifier(i).silenceRinger();
PhoneUtils.setAudioControlState(PhoneUtils.AUDIO_IDLE);
mApp.getCallNotifier(i).silenceRinger();
以此来电时按声音键会静音!
当然在InCallScreen.java里面那个是个候补!呵呵呵!这样做的好处就是当你在任何界面做为前台进程时都可以按声音键关掉你的来电铃声!
当然在InCallScreen.java里面的也对按键进行了拦截
比如
Java代码
1.public boolean dispatchKeyEvent(KeyEvent event) {
2. // if (DBG) log("dispatchKeyEvent(event " + event + ")...");
3.
4. // Intercept some events before they get dispatched to our views.
5. switch (event.getKeyCode()) {
6. case KeyEvent.KEYCODE_DPAD_CENTER:
7. case KeyEvent.KEYCODE_DPAD_UP:
8. case KeyEvent.KEYCODE_DPAD_DOWN:
9. case KeyEvent.KEYCODE_DPAD_LEFT:
10. case KeyEvent.KEYCODE_DPAD_RIGHT:
11. // Disable DPAD keys and trackball clicks if the touch lock
12. // overlay is up, since "touch lock" really means "disable
13. // the DTMF dialpad" (rather than only disabling touch events.)
14. if (mDialer.isOpened() && isTouchLocked()) {
15. if (DBG) log("- ignoring DPAD event while touch-locked...");
16. return true;
17. }
18. break;
19.
20. default:
21. break;
22. }
23.
24. return super.dispatchKeyEvent(event);
25. }
public boolean dispatchKeyEvent(KeyEvent event) {
// if (DBG) log("dispatchKeyEvent(event " + event + ")...");
// Intercept some events before they get dispatched to our views.
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_DPAD_DOWN:
case KeyEvent.KEYCODE_DPAD_LEFT:
case KeyEvent.KEYCODE_DPAD_RIGHT:
// Disable DPAD keys and trackball clicks if the touch lock
// overlay is up, since "touch lock" really means "disable
// the DTMF dialpad" (rather than only disabling touch events.)
if (mDialer.isOpened() && isTouchLocked()) {
if (DBG) log("- ignoring DPAD event while touch-locked...");
return true;
}
break;
default:
break;
}
return super.dispatchKeyEvent(event);
}
这样做是为了区别某哥界面的状态对应的按键事件!比如Incallscreen接了电话和没接电话几个按键的事件就不同!