android 关闭蓝牙打电话功能,Android蓝牙开发【八】hfp接听、挂断电话
繼續(xù)研究hfp相關(guān)功能。藍(lán)牙耳機(jī)可以控制手機(jī)接聽、拒接、掛斷電話,撥打電話等功能。本文主要分析下起這些操作的大致流程。
在系統(tǒng)應(yīng)用Bluetooth中com_android_bluetooth.cpp提供了多個回調(diào)方法,由hardware、協(xié)議棧回調(diào)過來。藍(lán)牙耳機(jī)的一些控制命令都會發(fā)到這里。
本文基于Android4.3源碼。
1 接通電話
藍(lán)牙耳機(jī)控制手機(jī)接通電話,回掉com_android_bluetooth.cpp中的answer_call_callback()函數(shù),該函數(shù)主要操作是調(diào)用HeadsetStateMachine的onAnswerCall()函數(shù),代碼如下:
在onAnswerCall()中發(fā)送消息(消息類型STACK_EVENT,StackEvent事件類型EVENT_TYPE_ANSWER_CALL)向狀體機(jī),此時通話尚未接通,audio沒有連接,所以此時處于Connected狀態(tài)。狀態(tài)機(jī)收到該消息后調(diào)用processAnswerCall()函數(shù)。processAnswerCall()代碼如下:
private void processAnswerCall() {
if (mPhoneProxy != null) {
try {
//mPhoneProxy是通過bindservice 獲取的。
mPhoneProxy.answerCall();
} catch (RemoteException e) {
}
} else {
}
}
初始化的時候會bind service,綁定的該service為系統(tǒng)應(yīng)用Phone下的BluetoothPhoneService(AndroidManifest中該service的action為android.bluetooth.IBluetoothHeadsetPhone),代碼如下:
//參數(shù)為android.bluetooth.IBluetoothHeadsetPhone
Intent intent = new Intent(IBluetoothHeadsetPhone.class.getName());
//resolveSystemService該方法是hide的,由系統(tǒng)使用的特殊功能來解決系統(tǒng)應(yīng)用程序的服務(wù)意圖。
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成功回調(diào)mConnection,在其成功回調(diào)中設(shè)置的mPhoneProxy。通過mPhoneProxy來調(diào)用service中提供的接口。mPhoneProxy.answerCall()跳到BluetoothPhoneService中answerCall。
public boolean answerCall() {
//申請權(quán)限,修改電話狀態(tài)
enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
return PhoneUtils.answerCall(mCM.getFirstActiveRingingCall());
}
PhoneUtils調(diào)用answerCall,在這里面去接通電話。answerCall()就不具體分析了。
2 拒接、掛斷電話
藍(lán)牙耳機(jī)控制手機(jī)拒接、掛斷電話,回掉com_android_bluetooth.cpp中的hangup_call_callback()函數(shù),該函數(shù)主要操作是調(diào)用HeadsetStateMachine的onHangupCall()函數(shù),代碼如下:
private void onHangupCall() {
StackEvent event = new StackEvent(EVENT_TYPE_HANGUP_CALL);
sendMessage(STACK_EVENT, event);
}
此時HeadsetStateMachine可能處于Conneted或AudioOn狀態(tài),這兩種狀態(tài)收到該消息的處理一樣,都是調(diào)用processHangupCall(),代碼如下:
private void processHangupCall() {
if (isVirtualCallInProgress()) {
//對于虛擬電話,結(jié)束。
terminateScoUsingVirtualVoiceCall();
} else {
if (mPhoneProxy != null) {
try { //掛斷電話
mPhoneProxy.hangupCall();
} catch (RemoteException e) {
}
} else {
}
}
}
對于虛擬電話則直接將其結(jié)束。真實(shí)的通話跳到BluetoothPhoneService的hangupCall。
public boolean hangupCall() {
enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, null);
if (mCM.hasActiveFgCall()) { //掛斷正在進(jìn)行的通話
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中會根據(jù)狀態(tài)處理通話,優(yōu)先處理正在進(jìn)行的通話、其次是尚未接通的電話、最后是保持的電話。
3 更改通話音量
藍(lán)牙耳機(jī)更改通話的音量,回掉com_android_bluetooth.cpp中的volume_control_callback()函數(shù),該函數(shù)主要操作是調(diào)用HeadsetStateMachine的onVolumeChnaged()函數(shù),代碼如下:
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狀態(tài),這兩種狀態(tài)收到該消息的處理一樣,都是調(diào)用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;
//設(shè)置SCO通道聲音大小。
mAudioManager.setStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO, volume, flag);
} else if (volumeType == HeadsetHalConstants.VOLUME_TYPE_MIC) {
// 只是存了下該volume值,并沒有設(shè)置mic。
mPhoneState.setMicVolume(volume);
} else {
}
}
更改音量兩種類型,VOLUME_TYPE_MIC類型,保存了下該值,并沒有看到具體用該值的地方。對于VOLUME_TYPE_SPK類型的,會設(shè)置SCO聲音大小。如果此時處于AudioOn狀態(tài),則會在UI上顯示。
4 撥打電話
藍(lán)牙耳機(jī)進(jìn)行撥打電話,回掉com_android_bluetooth.cpp中的dial_call_callback函數(shù),該函數(shù)主要操作是調(diào)用HeadsetStateMachine的onDialCall()函數(shù),代碼如下:
private void onDialCall(String number) {
StackEvent event = new StackEvent(EVENT_TYPE_DIAL_CALL);
event.valueString = number;
sendMessage(STACK_EVENT, event);
}
此時HeadsetStateMachine可能處于Conneted或AudioOn狀態(tài),這兩種狀態(tài)收到該消息的處理一樣,都是調(diào)用processDialCall,代碼如下:
private void processDialCall(String number) {
String dialNumber;
if ((number == null) || (number.length() == 0)) {
//獲取最近向外打的電話號碼
dialNumber = mPhonebook.getLastDialledNumber();
if (dialNumber == null) { //沒有最近撥打的電話,回應(yīng)error
atResponseCodeNative(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);
}
藍(lán)牙耳機(jī)發(fā)過來的命令可能攜帶電話號碼,也可能不帶,對于沒有電話號碼則查詢最近的撥打電話記錄,撥打最近撥打的電話。對于有號碼,則撥打該號碼。
Intent.ACTION_CALL_PRIVILEGED(該變量是hide的,執(zhí)行任何號碼的呼叫,緊急或不緊急):”android.intent.action.CALL_PRIVILEGED”
通過該action打開系統(tǒng)應(yīng)用Phone中的OutgoingCallBroadcaster界面,向外進(jìn)行撥打電話。
總結(jié)
以上是生活随笔為你收集整理的android 关闭蓝牙打电话功能,Android蓝牙开发【八】hfp接听、挂断电话的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 背头多少钱啊?
- 下一篇: android项目编码规范,Androi