Android 来电静音键拦截流程 接电话时按键后无声

转载 2012年03月30日 17:43:19

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接了电话和没接电话几个按键的事件就不同!

来电铃声和通话中的提示音

InCallTonePlayer packages/services/Telecomm/src/com/android/server/telecom/InCallTonePlayer.java,该类...
  • firedancer0089
  • firedancer0089
  • 2017年03月14日 10:22
  • 670

Android 事件捕捉和处理流程

1.    InputManagerService(IMS) 1.1     IMS初始化           在系统启动的时候,SystemServer会启动窗口管理服务WindowManage...
  • QQ18334373taikongyi
  • QQ18334373taikongyi
  • 2016年12月01日 09:46
  • 414

android电话音量静音的原理

事情是这样的,需求做一个悬浮窗要能够监听到音量按键,在电话响起的时候,死活监听不到,只能够收到一个action=ACTION_UP,表示不能理解,书上可不是这么说的,事件分发可不是这样的,除了什么问题...
  • qinxue24
  • qinxue24
  • 2017年06月15日 13:07
  • 434

android按键静音键功能实现

实现P931项目蓝牙键盘静音键功能以及打印F1,F2键信息打印 准备工作: 1.下载android4.0.3系统 git clone gitolite@scm:vc0882/sdk_4.0 (...
  • huanggenda568
  • huanggenda568
  • 2012年04月19日 15:55
  • 12856

Android 上千实例源码分析以及开源分析3

  • 2016年04月12日 15:22
  • 24KB
  • 下载

Android CM12.1 关机流程

Android CM12.1(android5.1) 关机流程 一、总关机流程图 之前查资料时从网上找的,觉得很正确。就借用一下别人的劳动成果吧~ 二、长按电源键准备关机    长按电源键是进入...
  • u011404910
  • u011404910
  • 2016年03月02日 10:58
  • 1206

android电话流程(打电话,接电话,挂断电话)(一)

(一)android打电话流程: 1、打电话的入口是在OutgoingCallBroadcaster这个类中,下层我就没深入去理解了,此类是继承的Activity,在其oncreate方法里面用in...
  • sunxingzhesunjinbiao
  • sunxingzhesunjinbiao
  • 2012年08月21日 19:58
  • 3440

一接打电话手机就自动变为静音震动模式的问题

不得不话,现在的智能机真是太智能了。今天接打电话时,发现手机会自动切换到震动模式。我调回普通模式,一接打电话,又自动进入震动模式了,真是智能得一塌糊涂。回忆了一下,之前是在锁屏界面不小心向左划了下屏幕...
  • huzgd
  • huzgd
  • 2011年04月30日 17:39
  • 11635

Android 关机流程 从kernel到framework

Android6.0关机流程 Android系统关机有如下方式:1.定时关机、2.命令行输入reboot重启、3.长按电源键出现关机对画框等,本文以长按电源键为例来分析基于Android 6.0的高通...
  • jinlu7611
  • jinlu7611
  • 2016年05月09日 17:25
  • 4005

android 关于屏幕截屏的几种办法

年末较闲,就上个星期查找各方面的资料关于android截图事情,自已也测试一些代码,已改改进或者优化。接下来进行总结一下。其实,如果真正android系统截屏是需要root权限的。但要用户使用都roo...
  • qq_16064871
  • qq_16064871
  • 2016年02月02日 11:02
  • 7759
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android 来电静音键拦截流程 接电话时按键后无声
举报原因:
原因补充:

(最多只允许输入30个字)