1.藍牙耳機接聽電話
這個就對應HFP(Hands-freeProfile),Free your Hand,藍牙的初衷之一。先來看這個功能的場景,手機來電,手機與藍牙耳機已鏈接,這時會優先觸發藍牙接聽電話的代碼流程,起步代碼在phone\src\com\android\phone\nCallScreen.java的connectBluetoothAudio() /disconnectBluetoothAudio(),只看鏈接部分好了,注意下面代碼裏的註釋,html
[java] view plaincopyjava
- /* package */ void connectBluetoothAudio() {
- if (VDBG) log("connectBluetoothAudio()...");
- if (mBluetoothHeadset != null) {
- // TODO(BT) check return
- mBluetoothHeadset.connectAudio();
- }
- // Watch out: The bluetooth connection doesn't happen instantly;
- // the connectAudio() call returns instantly but does its real
- // work in another thread. The mBluetoothConnectionPending flag
- // is just a little trickery to ensure that the onscreen UI updates
- // instantly. (See isBluetoothAudioConnectedOrPending() above.)
- mBluetoothConnectionPending = true;
- mBluetoothConnectionRequestTime = SystemClock.elapsedRealtime();
接下來就跳到藍牙應用的管轄範圍,代碼在packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetService.java,[java] view plaincopyandroid
- public boolean connectAudio() {
- HeadsetService service = getService();
- if (service == null) return false;
- return service.connectAudio();
- }
很明顯下一個目標是HeadsetService,直接看具體實現,這部分代碼跳轉都比較清晰,下面代碼會先判斷當前狀態是否正確,關於HeadsetStateMachine幾個狀態能夠參持這個/packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetStateMachine.java的最前的代碼註釋。[java] view plaincopyapp
- boolean connectAudio() {
- // TODO(BT) BLUETOOTH or BLUETOOTH_ADMIN permission
- enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
- if (!mStateMachine.isConnected()) {
- return false;
- }
- if (mStateMachine.isAudioOn()) {
- return false;
- }
- mStateMachine.sendMessage(HeadsetStateMachine.CONNECT_AUDIO);
- return true;
- }
走進HeadsetStateMachine狀態機,找到CONNECT_AUDIO分支,就看帶Native的方法connectAudioNative(getByteAddress(mCurrentDevice));[java] view plaincopyspa
- static jboolean connectAudioNative(JNIEnv *env, jobject object, jbyteArray address) {
- jbyte *addr;
- bt_status_t status;
-
- if (!sBluetoothHfpInterface) return JNI_FALSE;
-
- addr = env->GetByteArrayElements(address, NULL);
- if (!addr) {
- jniThrowIOException(env, EINVAL);
- return JNI_FALSE;
- }
- //鏈接在這裏
- if ( (status = sBluetoothHfpInterface->connect_audio((bt_bdaddr_t *)addr)) !=
- BT_STATUS_SUCCESS) {
- ALOGE("Failed HF audio connection, status: %d", status);
- }
- env->ReleaseByteArrayElements(address, addr, 0);
- return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
- }
上面代碼還能夠進一步跟到下面/external/bluetooth/bluedroid/btif/src/btif_hf.c,到了這裏其實流程已經結束了,對於這裏消息流轉估計要放到之後再寫了[java] view plaincopy.net
- static bt_status_t connect_audio( bt_bdaddr_t *bd_addr )
- {
- CHECK_BTHF_INIT();
- if (is_connected(bd_addr))
- {
- BTA_AgAudioOpen(btif_hf_cb.handle);
- /* Inform the application that the audio connection has been initiated successfully */
- btif_transfer_context(btif_in_hf_generic_evt, BTIF_HFP_CB_AUDIO_CONNECTING,
- (char *)bd_addr, sizeof(bt_bdaddr_t), NULL);
- return BT_STATUS_SUCCESS;
- }
- return BT_STATUS_FAIL;
- }
2.在藍牙列表中鏈接藍牙耳機
A2dp的鏈接過程,在藍牙搜索結果列表鏈接一個藍牙耳機,既然是從設備列表開始,因此起步代碼天然是這個了orm
[java] view plaincopyhtm
- DevicePickerFragment.java (settings\src\com\android\settings\bluetooth) 3884 2013-6-26
- void onClicked() {
- int bondState = mCachedDevice.getBondState();
- if (mCachedDevice.isConnected()) {
- askDisconnect();
- } else if (bondState == BluetoothDevice.BOND_BONDED) {
- mCachedDevice.connect(true);
- } .......
- }
-
- void connect(boolean connectAllProfiles) {
- if (!ensurePaired()) { //要先確保配對
- return;
- }
- mConnectAttempted = SystemClock.elapsedRealtime();
- connectWithoutResettingTimer(connectAllProfiles);//沒別的了,只能看到這裏
- }
代碼路徑這裏packages/apps/Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java,具體代碼看下面[java] view plaincopyblog
- // Try to initialize the profiles if they were not.
- ...........
- // Reset the only-show-one-error-dialog tracking variable
- mIsConnectingErrorPossible = true;
-
- int preferredProfiles = 0;
- for (LocalBluetoothProfile profile : mProfiles) {
- if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) {
- if (profile.isPreferred(mDevice)) {
- ++preferredProfiles;
- connectInt(profile);//鏈接在這裏,
- }
- }
- }
- .............
connectInt的實現很簡單,直接跳過看裏面的profile.connect(mDevice),這裏的profile是指A2dpProfile,因此connet()方法的具體實如今[java] view plaincopyget
- public boolean connect(BluetoothDevice device) {
- if (mService == null) return false;
- List<BluetoothDevice> sinks = getConnectedDevices();
- if (sinks != null) {
- for (BluetoothDevice sink : sinks) {
- mService.disconnect(sink);
- }}
- return mService.connect(device);
- }
下面是 BluetoothA2dp.java (frameworks\base\core\java\android\bluetooth) ,爲何是這樣看下這個private BluetoothA2dp mService;就知道了[java] view plaincopy
- public boolean connect(BluetoothDevice device) {
- if (mService != null && isEnabled() &&
- isValidDevice(device)) {
- try {
- return mService.connect(device);
- } catch (RemoteException e) {
- Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
- return false;
- }
- }...........
- return false;
-
- Binder跳轉
- public boolean connect(BluetoothDevice device) {
- A2dpService service = getService();
- if (service == null) return false;
- return service.connect(device);
- }
-
- }
以後的跳轉和第一部分藍牙接聽電話跳轉過程相似,就不重複了,最後會來到packages/apps/Bluetooth/jni/com_android_bluetooth_a2dp.cpp的connectA2dpNative,一樣到下面的代碼,咱們能看到的開放的代碼也就是這些,再下面要看vendor的具體實現了。[java] view plaincopy
- static jboolean connectA2dpNative(JNIEnv *env, jobject object, jbyteArray address) {
- jbyte *addr;
- bt_bdaddr_t * btAddr;
- bt_status_t status;
-
- ALOGI("%s: sBluetoothA2dpInterface: %p", __FUNCTION__, sBluetoothA2dpInterface);
- if (!sBluetoothA2dpInterface) return JNI_FALSE;
-
- addr = env->GetByteArrayElements(address, NULL);
- btAddr = (bt_bdaddr_t *) addr;
- if (!addr) {
- jniThrowIOException(env, EINVAL);
- return JNI_FALSE;
- }
- if ((status = sBluetoothA2dpInterface->connect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {
- ALOGE("Failed HF connection, status: %d", status);
- }
- env->ReleaseByteArrayElements(address, addr, 0);
- return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
分類: android,android_bluetooth