Android 蓝牙开发(八)hfp接听、挂断电话
转载请注明出处:http://blog.csdn.net/vnanyesheshou/article/details/71429860
本文已授权微信公众号 fanfan程序媛 独家发布 扫一扫文章底部的二维码或在微信搜索 fanfan程序媛 即可关注
继续研究hfp相关功能。蓝牙耳机可以控制手机接听、拒接、挂断电话,拨打电话等功能。本文主要分析下起这些操作的大致流程。
在系统应用Bluetooth中com_android_bluetooth.cpp提供了多个回调方法,由hardware、协议栈回调过来。蓝牙耳机的一些控制命令都会发到这里。
本文基于Android4.3源码。
1 接通电话 |
蓝牙耳机控制手机接通电话,回掉com_android_bluetooth.cpp中的answer_call_callback()函数,该函数主要操作是调用HeadsetStateMachine的onAnswerCall()函数,代码如下:
在onAnswerCall()中发送消息(消息类型STACK_EVENT,StackEvent事件类型EVENT_TYPE_ANSWER_CALL)向状体机,此时通话尚未接通,audio没有连接,所以此时处于Connected状态。状态机收到该消息后调用processAnswerCall()函数。processAnswerCall()代码如下:
private void processAnswerCall() {if (mPhoneProxy != null) {try {//mPhoneProxy是通过bindservice 获取的。mPhoneProxy.answerCall();} catch (RemoteException e) {}} else {}
}
初始化的时候会bind service,绑定的该service为系统应用Phone下的BluetoothPhoneService(AndroidManifest中该service的action为android.bluetooth.IBluetoothHeadsetPhone),代码如下:
//参数为android.bluetooth.IBluetoothHeadsetPhone
Intent intent = new Intent(IBluetoothHeadsetPhone.class.getName());
//resolveSystemService该方法是hide的,由系统使用的特殊功能来解决系统应用程序的服务意图。
intent.setComponent(intent.resolveSystemService(context.getPackageManager(), 0));
if (intent.getComponent() == null || !context.bindService(intent, mConnection, 0)) {Log.e(TAG, "Could not bind to Bluetooth Headset Phone Service");
}
绑定service成功回调mConnection,在其成功回调中设置的mPhoneProxy。通过mPhoneProxy来调用service中提供的接口。mPhoneProxy.answerCall()跳到BluetoothPhoneService中answerCall。
public boolean answerCall() {//申请权限,修改电话状态enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);return PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
}
PhoneUtils调用answerCall,在这里面去接通电话。answerCall()就不具体分析了。
2 拒接、挂断电话 |
蓝牙耳机控制手机拒接、挂断电话,回掉com_android_bluetooth.cpp中的hangup_call_callback()函数,该函数主要操作是调用HeadsetStateMachine的onHangupCall()函数,代码如下:
private void onHangupCall() {StackEvent event = new StackEvent(EVENT_TYPE_HANGUP_CALL);sendMessage(STACK_EVENT, event);
}
此时HeadsetStateMachine可能处于Conneted或AudioOn状态,这两种状态收到该消息的处理一样,都是调用processHangupCall(),代码如下:
private void processHangupCall() {if (isVirtualCallInProgress()) {//对于虚拟电话,结束。terminateScoUsingVirtualVoiceCall();} else {if (mPhoneProxy != null) {try { //挂断电话mPhoneProxy.hangupCall();} catch (RemoteException e) {}} else {}}
}
对于虚拟电话则直接将其结束。真实的通话跳到BluetoothPhoneService的hangupCall。
public boolean hangupCall() {enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);if (mCM.hasActiveFgCall()) { //挂断正在进行的通话return PhoneUtils.hangupActiveCall(mCM.getActiveFgCall());} else if (mCM.hasActiveRingingCall()) { //停止正在响铃的电话return PhoneUtils.hangupRingingCall(mCM.getFirstActiveRingingCall());} else if (mCM.hasActiveBgCall()) { //挂断保持的电话return PhoneUtils.hangupHoldingCall(mCM.getFirstActiveBgCall());}return false;
}
hangupCall中会根据状态处理通话,优先处理正在进行的通话、其次是尚未接通的电话、最后是保持的电话。
3 更改通话音量 |
蓝牙耳机更改通话的音量,回掉com_android_bluetooth.cpp中的volume_control_callback()函数,该函数主要操作是调用HeadsetStateMachine的onVolumeChnaged()函数,代码如下:
private void onVolumeChanged(int type, int volume) {StackEvent event = new StackEvent(EVENT_TYPE_VOLUME_CHANGED);event.valueInt = type;event.valueInt2 = volume;sendMessage(STACK_EVENT, event);
}
此时HeadsetStateMachine可能处于Conneted或AudioOn状态,这两种状态收到该消息的处理一样,都是调用processVolumeEvent,代码如下:
private void processVolumeEvent(int volumeType, int volume) {if (volumeType == HeadsetHalConstants.VOLUME_TYPE_SPK) {mPhoneState.setSpeakerVolume(volume);//是否在ui上显示int flag = (getCurrentState() == mAudioOn) ? AudioManager.FLAG_SHOW_UI : 0;//设置SCO通道声音大小。mAudioManager.setStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO, volume, flag);} else if (volumeType == HeadsetHalConstants.VOLUME_TYPE_MIC) {// 只是存了下该volume值,并没有设置mic。mPhoneState.setMicVolume(volume);} else {}
}
更改音量两种类型,VOLUME_TYPE_MIC类型,保存了下该值,并没有看到具体用该值的地方。对于VOLUME_TYPE_SPK类型的,会设置SCO声音大小。如果此时处于AudioOn状态,则会在UI上显示。
4 拨打电话 |
蓝牙耳机进行拨打电话,回掉com_android_bluetooth.cpp中的dial_call_callback函数,该函数主要操作是调用HeadsetStateMachine的onDialCall()函数,代码如下:
private void onDialCall(String number) {StackEvent event = new StackEvent(EVENT_TYPE_DIAL_CALL);event.valueString = number;sendMessage(STACK_EVENT, event);
}
此时HeadsetStateMachine可能处于Conneted或AudioOn状态,这两种状态收到该消息的处理一样,都是调用processDialCall,代码如下:
private void processDialCall(String number) {String dialNumber;if ((number == null) || (number.length() == 0)) {//获取最近向外打的电话号码dialNumber = mPhonebook.getLastDialledNumber();if (dialNumber == null) { //没有最近拨打的电话,回应erroratResponseCodeNative(HeadsetHalConstants.AT_RESPONSE_ERROR, 0);return;}} else if (number.charAt(0) == '>') {//测试} else {// Remove trailing ';'if (number.charAt(number.length() - 1) == ';') {number = number.substring(0, number.length() - 1);}dialNumber = PhoneNumberUtils.convertPreDial(number);}terminateScoUsingVirtualVoiceCall(); // 终止虚拟呼叫 Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,Uri.fromParts(SCHEME_TEL, dialNumber, null));intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);mService.startActivity(intent); //开启拨打电话的界面mDialingOut = true;sendMessageDelayed(DIALING_OUT_TIMEOUT, DIALING_OUT_TIMEOUT_VALUE);
}
蓝牙耳机发过来的命令可能携带电话号码,也可能不带,对于没有电话号码则查询最近的拨打电话记录,拨打最近拨打的电话。对于有号码,则拨打该号码。
Intent.ACTION_CALL_PRIVILEGED(该变量是hide的,执行任何号码的呼叫,紧急或不紧急):”android.intent.action.CALL_PRIVILEGED”
通过该action打开系统应用Phone中的OutgoingCallBroadcaster界面,向外进行拨打电话。
欢迎扫一扫关注我的微信公众号,定期推送优质技术文章:
Android 蓝牙开发(八)hfp接听、挂断电话相关推荐
- android 关闭蓝牙打电话功能,Android蓝牙开发【八】hfp接听、挂断电话
继续研究hfp相关功能.蓝牙耳机可以控制手机接听.拒接.挂断电话,拨打电话等功能.本文主要分析下起这些操作的大致流程. 在系统应用Bluetooth中com_android_bluetooth.cpp ...
- android自动接听和挂断电话
实现android自动接听和挂断电话功能.代码如下: 添加权限 <uses-permission android:name="android.permission.CALL_PHONE ...
- Android(AIDL)自动重复拨号及挂断/接听电话
Android默认没有提供挂断/接听电话的api,需要伪装com/android/internal/telephony/ITelephony.aidl的接口来欺骗系统.而自动重复拨号可以通过(Broa ...
- Android蓝牙开发(一)蓝牙模块及核心API
本文主要介绍Android蓝牙开发中基础知识:蓝牙模块及核心API. 关于蓝牙的连接及通讯功能实现,欢迎查阅下一篇文章:Android蓝牙开发(二)蓝牙消息传输实现. 蓝牙模块 从蓝牙4.0开始包含两 ...
- HFP:不活跃的车载设备在打电话时,不能挂断电话
Android P:Only active device can hung up call . 非 active device 不能挂断电话. step1:车载先连接 手机 step2:蓝牙耳机再连接 ...
- Android蓝牙开发 — 经典蓝牙BLE蓝牙
一,前期基础知识储备 1)蓝牙是一种支持设备之间短距离通信的无线电技术(其他还包括红外,WIFI): 支持移动电话.笔记本电脑.无线耳机等设备之间进行信息的交换: Android支持的蓝牙协议栈:Bl ...
- android 自动挂断,android实现接通和挂断电话
本文实例为大家分享了android实现接通和挂断电话的具体代码,供大家参考,具体内容如下 关键代码:[PhoneUtils类] package com.ebupt.phonerecorddemo.se ...
- android挂断电话广播,android实现接通和挂断电话
android实现接通和挂断电话 发布时间:2020-08-21 01:52:02 来源:脚本之家 阅读:230 作者:WillenWu 本文实例为大家分享了android实现接通和挂断电话的具体代码 ...
- Android - 蓝牙开发
文章目录 科普 SIG 类型 制式 选择 逻辑链路控制适配协议 (L2CAP) L2CAP的功能 蓝牙框架和 RFCOMM 协议 蓝牙安全 白名单机制 编程 蓝牙权限 Classic Bluetoot ...
最新文章
- connection could not be established with host smtp.exmail.qq.com
- 2012秋江苏省计算机二级上机试题,江苏省高校计算机等级考试二级2012秋资料.doc...
- 【POJ - 1486】Sorting Slides(思维建图,二分图求必须边,关建边,图论)
- 强封锁之后,华为正寻求10亿美元贷款;苹果发布iOS 12.3.1正式版,出击垃圾短信;联想CFO为“联想搬出中国”言论道歉;...
- java纯数字正则表达式_JAVA验证数字的正则表达式,来一发
- CentOS 7系统升级备份恢复实验记录
- 美国大学计算机与信息科学,【计算机学术讲堂】美国福特汉姆大学计算机与信息科学系Md Zakirul Alam Bhuiyan博士莅临我院作学术报告...
- 接管客厅第一步:联想智能音箱体验评测
- intellij IDEA 报 非法字符 \65279 原因及解决方法
- oracle安装最后一步完成了就消失了_Oracle安装过程中遇到的一些问题及解决方案...
- 华为音量键只能调通话_华为手机音量键的隐藏功能,知道一个就会好用不少!...
- 搞定Prometheus普罗米修斯监控系统
- 解读APP新一代验证登录方式——一键登录/免密认证
- 【linux】运行run文件显示cannot execute binary file
- ST MCU的国产替代
- IM软件中的语音录制与播放【iOS】
- Hcash:见证量子计算和后量子密码的“矛盾较量”
- Web前端工程师常去的15个技术网站
- SecureCRT 使用rz上传文件报错 Zmodem transfer canceled by remote side或失败
- java 键盘输入多种方法
热门文章
- 【JAVA项目实战】【图书管理系统】用户查询功能【Servlet】+【Jsp】+【Mysql】
- 第一次使用Eclipse:编写简单的Java小程序
- C语言数据结构——遍历二叉树
- 帝国CMS开发主播/直播视频网站源码+WAP/可封装APP运营
- 区块链教程、区块链指南、区块链中文手册、区块链原理
- ^_^ 给力,找了好久,终让我找到了,好多VB源码免费下载,路过的朋友快看看吧
- 纯DOS下安装Linux
- 华为快应用 - web标签无法加载部分网页
- 如何理解计算机网络的体系结构,如何理解计算机组成和计算机体系结构?
- Amazon EC2 Deep Dive 亚马逊EC2深度解析 Lynda课程中文字幕