Android 来电静音键拦截流程

简介: 现在在做双卡双待的项目!作为主要核心Phone遇到的问题也是千奇百怪! 今天就被一个问题困扰了一下午--来电后按声音按键需要静音!因为是双Phone对象所以对应的RINGER也有两个! 分析一下解BUG流程! 最开始以为按键处理会在InCallScreen.
现在在做双卡双待的项目!作为主要核心Phone遇到的问题也是千奇百怪!
今天就被一个问题困扰了一下午--来电后按声音按键需要静音!因为是双Phone对象所以对应的RINGER也有两个!
分析一下解BUG流程!
最开始以为按键处理会在InCallScreen.java里面的
    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里会有一个
public int interceptKeyTq(RawInputEvent event, boolean screenIsOn);

方法
此方法可以在最初的位置进行拦截事件处理!
// 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();
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);
	}

最终调用的是
PhoneUtils.setAudioControlState(PhoneUtils.AUDIO_IDLE);
				mApp.getCallNotifier(i).silenceRinger();

以此来电时按声音键会静音!

当然在InCallScreen.java里面那个是个候补!呵呵呵!这样做的好处就是当你在任何界面做为前台进程时都可以按声音键关掉你的来电铃声!
当然在InCallScreen.java里面的也对按键进行了拦截
比如
 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接了电话和没接电话几个按键的事件就不同!
目录
相关文章
|
安全 算法 小程序
【03】微信支付商户申请下户到配置完整流程-微信开放平台创建APP应用-填写上传基础资料-生成安卓证书-获取Apk签名-申请+配置完整流程-优雅草卓伊凡
【03】微信支付商户申请下户到配置完整流程-微信开放平台创建APP应用-填写上传基础资料-生成安卓证书-获取Apk签名-申请+配置完整流程-优雅草卓伊凡
960 28
【03】微信支付商户申请下户到配置完整流程-微信开放平台创建APP应用-填写上传基础资料-生成安卓证书-获取Apk签名-申请+配置完整流程-优雅草卓伊凡
|
前端开发 Java Shell
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
961 20
【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
NoSQL 应用服务中间件 PHP
布谷一对一直播源码android版环境配置流程及功能明细
部署需基于 CentOS 7.9 系统,硬盘不低于 40G,使用宝塔面板安装环境,包括 PHP 7.3(含 Redis、Fileinfo 扩展)、Nginx、MySQL 5.6、Redis 和最新 Composer。Swoole 扩展需按步骤配置。2021.08.05 后部署需将站点目录设为 public 并用 ThinkPHP 伪静态。开发环境建议 Windows 操作系统与最新 Android Studio,基础配置涉及 APP 名称修改、接口域名更换、包名调整及第三方登录分享(如 QQ、微信)的配置,同时需完成阿里云与腾讯云相关设置。
|
缓存 前端开发 Android开发
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
691 12
【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
|
Dart 前端开发 Android开发
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
491 4
【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
监控 Shell Linux
Android调试终极指南:ADB安装+多设备连接+ANR日志抓取全流程解析,覆盖环境变量配置/多设备调试/ANR日志分析全流程,附Win/Mac/Linux三平台解决方案
ADB(Android Debug Bridge)是安卓开发中的重要工具,用于连接电脑与安卓设备,实现文件传输、应用管理、日志抓取等功能。本文介绍了 ADB 的基本概念、安装配置及常用命令。包括:1) 基本命令如 `adb version` 和 `adb devices`;2) 权限操作如 `adb root` 和 `adb shell`;3) APK 操作如安装、卸载应用;4) 文件传输如 `adb push` 和 `adb pull`;5) 日志记录如 `adb logcat`;6) 系统信息获取如屏幕截图和录屏。通过这些功能,用户可高效调试和管理安卓设备。
|
Dart 前端开发 Android开发
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
610 1
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
|
测试技术 Android开发 开发者
【03】优雅草央千澈详解关于APP签名以及分发-上架完整流程-第三篇安卓APP上架华为商店后面的步骤-华为应用商店相对比较麻烦一些-华为商店安卓上架
【03】优雅草央千澈详解关于APP签名以及分发-上架完整流程-第三篇安卓APP上架华为商店后面的步骤-华为应用商店相对比较麻烦一些-华为商店安卓上架
339 16
|
Android开发
Android面试之Activity启动流程简述
Android面试之Activity启动流程简述
342 6
|
XML 前端开发 Android开发
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程
Android面试高频知识点(3) 详解Android View的绘制流程