1. 程式人生 > >Android 藍芽開發(八)hfp接聽、結束通話電話

Android 藍芽開發(八)hfp接聽、結束通話電話

本文已授權微信公眾號 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) { //沒有最近撥打的電話,迴應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);
}

藍芽耳機發過來的命令可能攜帶電話號碼,也可能不帶,對於沒有電話號碼則查詢最近的撥打電話記錄,撥打最近撥打的電話。對於有號碼,則撥打該號碼。
Intent.ACTION_CALL_PRIVILEGED(該變數是hide的,執行任何號碼的呼叫,緊急或不緊急):”android.intent.action.CALL_PRIVILEGED”
通過該action開啟系統應用Phone中的OutgoingCallBroadcaster介面,向外進行撥打電話。

歡迎掃一掃關注我的微信公眾號,定期推送優質技術文章:

這裡寫圖片描述

相關推薦

Android 開發hfp接聽結束通話電話

本文已授權微信公眾號 fanfan程式媛 獨家釋出 掃一掃文章底部的二維碼或在微信搜尋 fanfan程式媛 即可關注 繼續研究hfp相關功能。藍芽耳機可以控制手機接聽、拒接、結束通話電話,撥打電話等功能。本文主要分析下起這些操作的大致流程。 在

Android 開發hfp音訊連線

本文已授權微信公眾號 fanfan程式媛 獨家釋出 掃一掃文章底部的二維碼或在微信搜尋 fanfan程式媛 即可關注 接著上一篇hfp連線繼續,檢視藍芽通話時如何進行處理的。hfp連線有兩個連線,一個是hfp連線(在設定介面顯示的是手機音訊),另

Android開發之開啟和裝置搜尋

Android藍芽開發系列目錄: 一、判斷是否系統是否支援藍芽 在使用藍芽之前,我們首先要判斷手機裝置是否支援藍芽,雖然現在基本都支援藍芽了,但是為了程式碼的嚴謹性我們還是需要在程式碼中判斷: private BluetoothManager bluetoothma

Android開發 BLE4.0低功耗

一、BLE4.0低功耗藍芽 Bluetooth Low Energy,藍芽低功耗,是從藍芽4.0開始支援的技術。相較傳統藍芽,傳輸速度更快、覆蓋範圍廣、安全性高、延時短、耗電低等特點。 二、關鍵術語 1.GATT(通用屬性配置):通用屬性配置檔案,用於ble鏈路上傳送和接

Android 開發A2DP基本功能

本文主要是Android做為Audio Source端,A2DP的基本操作:包括連線、斷開連線、設定優先順序、獲取優先順序、獲取A2DP連線狀態、獲取A2DP連線的裝置列表等功能。 1 簡介 A2DP全名是Advanced Audio Distrib

Android 開發A2DP原始碼分析

上一篇說了下A2DP的一些基本操作,這篇分析下系統應用、系統原始碼是如何操作A2DP的。尤其是其連線過程,基於Android4.3原始碼。Andorid手機一般都是做為A2DP Audio Source端。 1 連線過程 媒體音訊也就是A2DP,首先連線的藍芽裝置需要

Android 開發2——低功耗

低功耗藍芽官方文件 本文章是參考官網,然後加入自己實踐中的理解完成!沒有看上一篇的讀者,可以先閱讀一下前一篇,這是一個系列。 官網地址:https://developer.android.com/guide/topics/connectivity/bluetooth-le Android 4.3 (API

Android BLE低功耗開發關於GATT伺服器的理論與搭建

前言 本來寫完Android開發之BlueTooth--最簡單的Andorid傳統藍芽通訊Demo之後,我打算寫一篇Android開發之BlueTooth--最簡單的Andorid低功耗(BLE)藍芽通訊Demo的。後來看了看官方的文件,我的天,谷歌給給出的sample裡

Android使用

轉載自: https://blog.csdn.net/duo_shine/article/details/70259928 藍芽使用(一)http://blog.csdn.net/duo_shine/article/details/70257113  藍芽韌體升級:http://b

開發掃描裝置

一、申請位置許可權 在Android6.0以後要掃描藍芽裝置,還需要請求位置許可權: <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <

iOS開發在裝置端實現Central角色

若想在裝置上實現Central角色的功能,主要有以下步驟: 2.搜尋周圍廣播的裝置 3.與一個外設進行連線,並探索外設提供的服務 4.向外設傳送讀寫characteristic的請求,如果有需要訂閱characteristic值得更新,來跟蹤資料的變化。 myCe

iOS開發:iOS 4.0中心模式 程式碼實現

上一篇簡單介紹了藍芽的部分基礎知識,詳細的東西大家可以去github上搜babyBluetooth,裡面有一些學習資料 iOS連線外設的流程 建立中心管理者 掃描外設 discoverPeripheral 連線外設 connectPeripheral

Android開發【六】hfp連線

本文主要內容是藍芽手機音訊的連線、斷開流程分析,對應藍芽HFP profile。 該文章是基於Android原始碼4.3的 1 hfp簡單介紹 HFP (Hands-free Profile),讓藍芽裝置(如藍芽耳機)可以控制電話,如接聽、結束通話、拒接、語音撥號等,

ios開發app作為外設被連線的實現

再上一節說了app作為central連線peripheral的情況,這一節介紹如何使用app釋出一個peripheral,給其他的central連線 還是這張圖,central模式用的都是左邊的類,而peripheral模式用的是右邊的類 peripheral模式的流

android 通訊

實現功能:藍芽配對 在上篇的基礎上,配對第一個找到的藍芽裝置 1、重寫Handler中找到藍芽裝置後的邏輯 /** 判斷是否是第一個發現的藍芽裝置*/ private boolean hasF

Android通訊————功能的相關許可權

根據sdk中的docs的文件說明,使用Android的藍芽裝置時,只需要申請兩個許可權即可保證藍芽的正常的工作(其實在與藍芽相關的許可權一共有3個,其中BLUETOOTH_PRIVILEGED許可權只有系統應用可以使用,在這裡就不說明了),今天我們需要使用的兩個

iOS 開發——CoreBluetooth開發

最近要做關於iOS上的藍芽開發專案,為此閱讀了蘋果的官方文件,這裡做一些翻譯和摘錄和大家共享交流。(如需轉載請註明出處) 關於Core BlueTooth Core BlueTooth是一個iOS的開發框架,其中包含了若干類,能夠和低功耗藍芽(符合藍芽4

iOS開發相關基礎知識

藍芽常見名稱和縮寫 MFI ======= make for ipad ,iphone, itouch 專們為蘋果裝置製作的裝置 BLE ==== buletouch low energy,藍芽4.0裝置因為低耗電,所以也叫做BLE peripher

Android撥打接聽結束通話電話操作

Android2.3之前的系統可以通過反射機制呼叫ITelephone的方法來結束通話電話,因為Android2.3以後增加了對permission  android.permission.MODIFY_PHONE_STATE 的限制,之前的反射的方法不能用了,我們可以通過

Android開發之經典2.0開發全記錄

前言部分 最近因為需要開始藍芽相關開發,所以在網上搜索了很多內容,並且結合自己的開發過程做了一個總結,先儲備上,也許可能幫到正在做藍芽開發的同學。 藍芽很早就是android裝置上基本通訊功能了,只是以前的沒有那麼多藍芽裝置,現在藍芽裝置種類繁多,所以經常會有人遇到藍芽相關的開發