Android 藍牙框架 一、前言 二、功能簡單介紹 三、詳解四大部分(client、service、bluetooth、settinglib) 四、寫在最後

一、前言

本文側重點:Android中藍牙代碼結構分析。
代碼來源於Android P,本文相關代碼:
client:
frameworks/base/core/java/android/bluetooth/*
system/bt/binder/android/bluetooth/**.aidl
servie:
framework/base/services/core/java/com/android/server/BluetoothService.java
framework/base/services/core/java/com/android/server/BluetoothManagerService.java
bluetooth:
package/app/bluetooth
(上面是aosp源碼提供的藍牙實現。而芯片廠商提供的代碼一般這部分是沒有源碼的,比如mtkbluetooth.apk直接替換此apk。但aosp提供的源碼供我們學習還是可以的。)
settingslib:
vendor/mediatek/proprietary/packages/apps/SettingsLib/src/com/android/settingslib/bluetooth/

(SettingsLib原生frameworks/base/packages/SettingsLib也有,上面是MTK定製,主要區別是對協議的修改添加一些支持等)

上面四個部分是藍牙核心的地方。對於系統的應用從AndroidP開始。AOSP已經原生支持對藍牙的各種接口了。只要芯片廠商對接好系統藍牙接口我們就可以依賴原生接口開發自己想要的應用app,下面是功能應用的表格:

功能 依賴項
Diar 通話相關,來去電走Android原生telecom流程。聯繫人/通話記錄依賴原生contactsprovider
music 音樂相關,走原生Mediasession
settings 藍牙設置相關,用settingsLib控制,開關連接等
其他 其他應用依賴於Android自身支持的協議(profile)比如GATT低功耗藍牙,OPP文件傳輸,等等

注:
1、本文以分析整體爲主。讀者需要對framework中service/client結構熟悉(此文有介紹這種結構:PackageManagerService服務框架詳解)。另外建議閱讀時去翻翻對應路徑下的源碼,便於理解。
2、本文以整體框架講解的思想來闡述。特殊流程會源碼講解,講解時只列出源碼關鍵代碼行。大部分只總結它的作用。需要讀者自行去結合源碼理解。

二、功能簡單介紹

首先藍牙服務和AMS、PMS等系統衆多服務一樣,也是service/client結構。不理解S/C結構的同學可以直接理解爲普通的API調用,直接調用最終在BluetoothManagerService.java代碼裏,方法名大部分都一樣。

2.1、四部分(client、service、bluetooth、settinglib)

藍牙的代碼主要分爲標題的四個部分

2.1.1、client

客戶端主要代碼是BluetoothAdapter,我們平時開發時都是通過操作BluetoothAdapter的公開api來實現我們的功能。
除開BluetoothAdapter起到核心作用之外在com.android.bluetooth下還默認提供一些默認協議API級的支持。這些協議都是一個獨立的profile實現。這些profile使我們可以控制藍牙工作於我們想要的場景下。通常這部分三方apk使用較多。

名稱 簡單介紹
A2dp 音頻
Gatt 低功耗
Headset 藍牙耳機
Health 健康
Socket 面向連接,套接字,基於RFCOMM

2.2.2、service

代碼:BluetoothManagerService.java
service管理:
BluetoothManagerService裏主要是framework層實現藍牙功能的地方。我們從BluetoothAdapter調用方法都會調用到BluetoothManagerService裏,而BluetoothManagerService裏的大部分實現又是通過綁定bluetooth apk裏的service(AdapterService)來實現。這樣BluetoothManagerService既起到了統一framework藍牙實現的地方,又讓Bluetooth apk可以有豐富的profile具體功能實現。
Profile理解:
一個藍牙硬件模塊根據藍牙規範(比如藍牙4.0)。會默認實現很多自帶的協議。由於制定協議的人多個組等其他原因。藍牙規範是有很多個細分的協議協同工作。可以理解爲一種通信規範。一個標準的藍牙模塊肯定得把藍牙規範裏的協議都實現。而Profile的存在的意義就是。不管你標準有多少個協議,我只要我想要的功能,別的我不管。比如A2dp音頻協議。我只需要藍牙工作於A2dp就可以了。當然A2dp可能是基於其中某幾個協議上的協議。但是別的協議它沒有。用JavaScript的思想來理解Profile,它就是一個切面。

2.2.3、bluetooth

bluetooth是藍牙協議具體實現的地方。比如BluetoothAdapter#enable打開藍牙的時候,跟蹤代碼最後的調用就會跟蹤到bluetooth apk裏。而打開操作就在bluetooth中的AdapterService。這個是service就是藍牙功能的服務。在BluetoothManagerService中會綁定AdapterService,拿到服務後,就間接提供給client中的BluetoothAdapter API使用。下面用連個截圖來展示它的豐富的實現


bluetooth apk由於是具體的實現,所以它會實現所有的協議。
除開client中提供的profile,還有settingslib中系統藍牙操作功能實現的Profile。這些豐富的profile會在下一小節列出。

2.2.4、settingslib

settingsLib和其他三個部分是相對而言比較獨立的一個部分。因爲它只是封裝操作。以便settings可以更方便的控制管理
settingslib主要是服務系統app:settings使用,編譯時一般也是編譯settings的時候一起編譯settingslib。
只有系統級權限(集成到系統中,system/app、framework等)纔可以調用settingslib,普通三方應用開發者無法使用
settingslib中藍牙代碼相當於也是操作BluetoothAdapter,BluetoothAdapter間接調用BluetoothManagerService來實現功能.
在SettingsLib\src\com\android\settingslib\bluetooth中我們還能看到像com.android.bluetooth路徑下那些協議之外的一些協議

名稱 簡單介紹 名稱 簡單介紹
A2dp 音頻 Headset 藍牙耳機
HearingAid 助聽器 Hfp 免提
Hid 人機接口設備 Map 信息訪問
Opp 對象推送 Pan 個人局域網
Pbap 電話薄 Sap 會話通知

看到這些協議,settingslib服務於系統就很好理解了。一個手機連上藍牙。那麼手機設置支持藍牙相關的操作也就是這些協議支持的功能

三、詳解四大部分(client、service、bluetooth、settinglib)

文章第二段對Android藍牙框架代碼已經有了一個簡單的介紹。就是這四個部分代碼支撐着藍牙的各種功能。接下來將詳細介紹四個部分比較核心的內容。

3.1、BluetoothAdapter詳細介紹(client)

BluetoothAdapter部分主要是api使用,所以這部分以表格方式列出信息方便查閱
第一個表是BluetoothAdapter定義的一些狀態和通知:

作用類型 關鍵字 介紹
開關通知 ACTION_STATE_CHANGED 上次狀態和當前狀態
開關狀態定義 AdapterState 描述當前藍牙狀態
請求掃描 ACTION_REQUEST_DISCOVERABLE 請求掃描,默認120秒,可帶時間參數 activity#resulet
請求掃描 ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE 一直允許掃描 activity#resulet
請求打開/關閉 ACTION_REQUEST_ENABLE、ACTION_REQUEST_DISABLE 請求打開/關閉activity#resulet
掃描狀態通知 ACTION_SCAN_MODE_CHANGED 上次狀態和當前狀態
掃描狀態定義 ScanMode 描述掃描狀態
掃描開始/結束通知 ACTION_DISCOVERY_STARTED、ACTION_DISCOVERY_FINISHED
名字改變通知 ACTION_LOCAL_NAME_CHANGED 帶名字參數
連接狀態通知 ACTION_CONNECTION_STATE_CHANGED 帶當前和上次狀態
LE下狀態通知 ACTION_BLE_STATE_CHANGED 藍牙只在低功耗模式時狀態變化
mac地址變化 ACTION_BLUETOOTH_ADDRESS_CHANGED 帶參數
連接類型 ACTION_BLE_ACL_CONNECTED
斷開連接類型 ACTION_BLE_ACL_CONNECTED

上面這些豐富的廣播通知是在bluetooth apk裏的實現的。bluetooth中的btservice中收到狀態的時候直接發出廣播

第二個表是BluetoothAdapter.java內部方法(方法只是提及,不包括所有,類似或者不重要的省略):

方法 作用 方法 作用
getDefaultAdapter 拿對象 getRemoteDevice 遠端設備
getBluetoothLeAdvertiser LE廣播數據 getPeriodicAdvertisingManager LE註冊管理
getBluetoothLeScanner 掃描 isEnabled
getState 狀態 getLeState LE狀態
enable 打開 getAddress 地址
setName 名字 factoryReset 出廠設置
getUuids uuid getBluetoothClass 遠端設備信息判斷設備類型是否提供某個service等
setScanMode 掃描模式 setDiscoverableTimeout 超時時間
cancelDiscovery 取消 isDiscovering 是否掃描
isLe*** LE設備功能支持判斷 getMaxConnectedAudioDevices 最大audio設備數
requestControllerActivityEnergyInfo 獲取藍牙信息比如電量 getBondedDevices 已配對設備
getSupportedProfiles 支持的協議 getConnectionState 連接狀態
getProfileConnectionState 協議連接狀態 listen*** 創建service監聽例如開氣socket服務
getProfileProxy 客戶端拿到服務比如pbap closeProfileProxy 關閉連接
enableNoAutoConnect 打開 checkBluetoothAddress 有效地址判斷
getBluetoothManager 獲得bluetoothmanagerservice getBluetoothService 獲得藍牙服務
startLeScan LE開始掃描 stopLeScan 停止le掃描

BluetoothAdapter小結
1、BluetoothAdapter的重要信息上面基本都列出來了。除了常規的開關監聽等操作外。還有很多掃描連接狀態等得廣播通知發送出來。
2、我們的apk客戶端想要和某個profile服務綁定時,通過getProfileProxy來拿到服務和監聽
3、低功耗LE設備也提供了一些操作方法

3.2、BluetoothManagerService詳細介紹(service)

BluetoothManagerService功能實現比較分散,下面以講解比較重要的幾個代碼流程邏輯爲主。
BluetoothManagerService這部分主要是功能的詳細實現。而BluetoothManagerService和其他系統service不太一樣。它這裏的實現也只是表面封裝一下。具體的實現是通過綁定bluetooth apk裏的AdapterService,然後通過AdapterService來實現。下面我們看下怎麼調用到AdapterService的。

3.2.1、系統api調用流程

BluetoothManagerService調用到package/app/bluetooth
BluetoothAdapter->BluetoothManagerService->AdapterService(bluetooth apk)上面client部分列出的方法大部分都是這個操作流程,走到bluetooth裏的具體實現。

查看BluetoothAdapter調用邏輯,和其他系統api一樣,藍牙也是S/C結構。那麼具體實現就都會集中到BluetoothManagerService。查看BluetoothManagerService代碼我們很容發現裏面的詳細實現主要有兩個間接調用mManagerService和mBluetooth 。我們跟一下這兩個對象。
BluetoothManagerService.java代碼片段:

IBluetoothManager mManagerService =  IBluetoothManager.Stub.asInterface(ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE));
 private void handleEnable(boolean quietMode) {
       ...
                Intent i = new Intent(IBluetooth.class.getName());
                if (!doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
                        UserHandle.CURRENT)) {
                   ...
                }
private class BluetoothServiceConnection implements ServiceConnection {
        public void onServiceConnected(ComponentName componentName, IBinder service) {
            ...
            msg.obj = service;
            mHandler.sendMessage(msg);
        }
mBluetooth = IBluetooth.Stub.asInterface(Binder.allowBlocking(service));  

mManagerService很好理解就是綁定到了我們的BluetoothManagerService服務。
mManagerService在打開藍牙的時候會間接調用到handleEnable方法,handleEnable的dobind會綁定BluetoothService,回調到BluetoothServiceConnection方法中把service賦值給mBluetooth,這樣我們就可以拿到Bluetooth app裏的service(AdapterService)進行操作了。

3.2.2、BluetoothAdapter和Bluetooth apk其他協議綁定調用

這個流程和BluetoothManagerService沒什麼關係,但是和3.2.1極其相似,所以放在這裏講。
普通三方apk可以通過BluetoothAdapter#getProfileProxy來拿到協議,並通過協議進行具體操作。操作實際也會操作到Bluetooth apk裏。我們以settingslib連接使用profile來講解。整體流程大致如下:
settingslib->settingslib#setBluetoothStateOn->bluetoothadater#getProfileProxy->bluetooth apk profile service
1、settinglib中LocalBluetoothAdapter打開藍牙
首先除了默認的BluetoothAdapter#enable可以打開外,settinglib中LocalBluetoothAdapter#enable也可以打開,打開時代碼會走到LocalBluetoothProfileManager#setBluetoothStateOn。我們以HidProfile爲代表來講

// Called from LocalBluetoothAdapter when state changes to ON
    void setBluetoothStateOn() {
        if (mHidProfile == null) {
        mHidProfile = new HidProfile(mContext, mLocalAdapter, mDeviceManager, this);
        addProfile(mHidProfile, HidProfile.NAME,
                BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED);
       }

2、HidProfile拿到bluetooth apk中的HidProfile服務

public class HidProfile implements LocalBluetoothProfile {
   public void onServiceConnected(int profile, BluetoothProfile proxy) {
            if (V) Log.d(TAG,"Bluetooth service connected");
            mService = (BluetoothHidHost) proxy;
          ....
     HidProfile(Context context, LocalBluetoothAdapter adapter,
        CachedBluetoothDeviceManager deviceManager,
        LocalBluetoothProfileManager profileManager) {
        ...
        adapter.getProfileProxy(context, new HidHostServiceListener(),
                BluetoothProfile.HID_HOST);
    }

這裏的HidProfile代碼在settinglib中,創建時核心的調用到了adapter.getProfileProxy。這裏就是framework層通過BluetoothAdapter拿到bluetooth apk中的profile service核心邏輯
BluetoothAdapter#getProfileProxy

public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,
            int profile) {
        ....
        if (profile == BluetoothProfile.HEADSET) {
            BluetoothHeadset headset = new BluetoothHeadset(context, listener);
            return true;
        } 
        ....
        else if (profile == BluetoothProfile.HID_HOST) {
            BluetoothHidHost iDev = new BluetoothHidHost(context, listener);
            return true;
        } 

這裏又會新創建一個HID的profile對象BluetoothHidHost。(這裏容易和settingslib中的HidProfile混淆,這個HID還好名字有區別,別的profile名字極其類似。)BluetoothHidHost在路徑frameworks\base\core\java\android\bluetooth

 private final ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            if (DBG) Log.d(TAG, "Proxy object connected");
            mService = IBluetoothHealth.Stub.asInterface(Binder.allowBlocking(service));

            if (mServiceListener != null) {
                mServiceListener.onServiceConnected(BluetoothProfile.HEALTH, BluetoothHealth.this);
            }
        }
      ...
BluetoothHidHost(Context context, ServiceListener l) {
        ...
        doBind();
    }
boolean doBind() {
        Intent intent = new Intent(IBluetoothHidHost.class.getName());
        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
        intent.setComponent(comp);
        if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
                mContext.getUser())) {
            Log.e(TAG, "Could not bind to Bluetooth HID Service with " + intent);
            return false;
        }
        return true;
    }

dobind時,就和上面講解的API調用流程比較類似,綁定服務,並把bluetooth apk裏的service,回調給mConnection。這樣BluetoothHidHost就綁定了bluetooth apk裏的HIDProfile service 並獲得代理對象。在mConnection中,又通過剛纔HidProfile 傳入的listenner回調傳回service,讓HidProfile 也擁有了Bluetooth apk中的這個service。
3、流程概述
<1>、1,2流程下來。settinglib中打開時就會創建支持的profile,這些profile創建的時候,都大同小異的讓BluetoothAdapter也創一個名字類似的profile,讓兩個profile都拿到bluetooth apk中對應協議的service。當profile拿到service了,有了bluetooth apk具體的實現了,就能調用到具體的功能上了。
<2>、注意這裏的service和協議的service/client中的service要區分開。client也是在要bluetooth apk運行一個服務來供系統使用。
<3>、三方應用可以BluetoothAdapter#getProfileProxy來拿到profile操作。一般profile實現的方法也不多,只能調用一些簡單的方法。有哪些公開api直接打開某個profile就能看到

BluetoothManagerService小結
由於service的特性,就是各個功能的具體實現。所以對於service的分析一般都是流程爲主。BluetoothManagerService的功能和系統其他服務比相對比較簡單。基本就是綁定bluetoothapk 的service,具體的實現還是都在Bluetooth apk裏。

3.3、bluetooth apk

這部分代碼芯片廠商一般有自己的私有定製,未開放源碼,學習這部分參考AOSP源碼package/app/bluetooth
Bluetooth apk裏就是我們藍牙功能具體的實現了。常規打開關閉功能在AdapterService入口實現。這些方法最後跟蹤都會跟蹤到native方法上。由於方法流程很多,這裏以打開流程來舉例介紹

3.3.1、AdapterService#enable

enable就是打開的入口,我們跟一下打開流程
1、狀態機開始工作

private AdapterState mAdapterStateMachine;
 public synchronized boolean enable(boolean quietMode) {
        ...
        mAdapterStateMachine.sendMessage(AdapterState.BLE_TURN_ON);
    }

AdapterState.java代碼片段
    private TurningOnState mTurningOnState = new TurningOnState();
    private TurningBleOnState mTurningBleOnState = new TurningBleOnState();
    private TurningOffState mTurningOffState = new TurningOffState();
    private TurningBleOffState mTurningBleOffState = new TurningBleOffState();
    private OnState mOnState = new OnState();
    private OffState mOffState = new OffState();
    private BleOnState mBleOnState = new BleOnState();
private AdapterState(AdapterService service) {
        super(TAG);
        addState(mOnState);
        addState(mBleOnState);
        addState(mOffState);
        addState(mTurningOnState);
        addState(mTurningOffState);
        addState(mTurningBleOnState);
        addState(mTurningBleOffState);
        mAdapterService = service;
        setInitialState(mOffState);
    }

打開的工作交給了AdapterState。AdapterState 是一個狀態機,狀態機改變狀態時就會執行類的一些行爲。Android的狀態機制一般用於複雜狀態+複雜操作。這裏你可以簡單理解爲狀態切一下就會去執行對應操作。
構造函數默認是mOffState,收到BLE_TURN_ON消息。那麼第一個地方就是OffState的processMessage處理BLE_TURN_ON,消息也是再直接傳遞到TurningBleOnState

 private class OffState extends BaseAdapterState {
        ...
        @Override
        public boolean processMessage(Message msg) {
            switch (msg.what) {
                case BLE_TURN_ON:
                    transitionTo(mTurningBleOnState);
                    break;
        }
    }

2、把打開消息傳給GattService

 private class TurningBleOnState extends BaseAdapterState {
        ...
        @Override
        public void enter() {
            super.enter();
            sendMessageDelayed(BLE_START_TIMEOUT, BLE_START_TIMEOUT_DELAY);
            mAdapterService.bringUpBle();
        }
      ...
        @Override
        public boolean processMessage(Message msg) {
            switch (msg.what) {
                case BLE_STARTED:
                    transitionTo(mBleOnState);
                    break;

    void bringUpBle() {
        ...
        //Start Gatt service
        setProfileServiceState(GattService.class, BluetoothAdapter.STATE_ON);
    }

  class AdapterServiceHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MESSAGE_PROFILE_SERVICE_STATE_CHANGED:
                    processProfileServiceStateChanged((ProfileService) msg.obj, msg.arg1);
                    break;

3、GattService打開藍牙

private void processProfileServiceStateChanged(ProfileService profile, int state) {
            switch (state) {
                case BluetoothAdapter.STATE_ON:
                    ...
                    if (GattService.class.getSimpleName().equals(profile.getName())) {
                        enableNativeWithGuestFlag();
                    } 
private void enableNativeWithGuestFlag() {
        boolean isGuest = UserManager.get(this).isGuestUser();
        if (!enableNative(isGuest)) {
            Log.e(TAG, "enableNative() returned false");
        }
    }

這樣就調用到了底層實現的native方法

3.3.2、其他協議啓動

上面3.3.1講解BluetoothAdapter#enable時,BluetoothManagerService代碼從BluetoothManagerService調用到bluetooh apk的Adapterservice最後一步BluetoothServiceConnection 回調MESSAGE_BLUETOOTH_SERVICE_CONNECTED信息,代碼從這裏接着開始。
1、framwork調用到bluetooth apk裏

private class BluetoothHandler extends Handler {
        ...
        @Override
        public void handleMessage(Message msg) {
case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: {
                    IBinder service = (IBinder) msg.obj;
                    try {
                        mBluetoothLock.writeLock().lock();
                        if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
                            mBluetoothGatt = IBluetoothGatt.Stub.asInterface(Binder.allowBlocking(service));
                            continueFromBleOnState();
                            break;
                        } 

    private void continueFromBleOnState() {
         ...
         mBluetooth.onLeServiceUp();
    }

BluetoothManagerService#enable講解最後這裏拿到了service。同時也是這裏的continueFromBleOnState,開起了bluetooth apk裏其他所有支持的profile的service。
2、Adapterservice#startProfileServices
接着又是狀態機一頓切換,切換流程和上面狀態機一樣,這裏簡略

void onLeServiceUp() {
        mAdapterStateMachine.sendMessage(AdapterState.USER_TURN_ON);
    }
 private class TurningOnState extends BaseAdapterState {
        @Override
        public void enter() {
            ...
            mAdapterService.startProfileServices();
        }

void startProfileServices() {
        Class[] supportedProfileServices = Config.getSupportedProfiles();
        ...
            setAllProfileServiceStates(supportedProfileServices, BluetoothAdapter.STATE_ON);
        }
    }
private void setAllProfileServiceStates(Class[] services, int state) {
        for (Class service : services) {
            if (GattService.class.getSimpleName().equals(service.getSimpleName())) {
                continue;
            }
            setProfileServiceState(service, state);
        }
    }

 private void setProfileServiceState(Class service, int state) {
        Intent intent = new Intent(this, service);
        intent.putExtra(EXTRA_ACTION, ACTION_SERVICE_STATE_CHANGED);
        intent.putExtra(BluetoothAdapter.EXTRA_STATE, state);
        startService(intent);
    }

Config.getSupportedProfiles拿到的是配置文件中列出來支持的所有協議。然後全部把profile的狀態置爲STATE_ON
最後一個for循環遍歷startService開起所有支持的服務

bluetooth apk小結
1、bluetooth apk是藍牙功能實現的地方。
2、bluetooth apk裏的代碼主要靠adapterservice工作運行。
3、adapterservice提供了底層so庫的入口。也提供了供framework使用的方法。
4、adapterservice藍牙操作相關主要靠AdapterState狀態機來切換

3.4、SettingsLib

1、SettingsLib和bluetoothAdapter類似以API運用爲主,這部分以表格方式
2、首先SettingsLib包含了很多功能,它的目的是封裝一些操作。專注服務於settings app。本文只對settingslib中bluetooth部分分析。本文開頭部分簡單介紹settingsLib的時候對路徑下的profile進行了表格統計,並說明了他們的功能。settingslib中的bletooth代碼除了這部分協議,剩下幾個LocalManager對藍牙的操作封裝處理。這個Manager我們也先以表格的形式簡單統計說明。

名稱 簡單介紹
LocalBluetoothAdapter 絕大部分都是對BluetoothAdapter間接調用
CachedBluetoothDeviceManager 管理已配對設備列表
BluetoothEventManager 接收藍牙相關廣播和藍牙的一些回調,並根據UI操作執行到對應的事件
LocalBluetoothProfileManager 對外提供可用profile的訪問
LocalBluetoothManager 統一管理CachedBluetoothDeviceManager、LocalBluetoothProfileManager、BluetoothEventManager創建和獲取

有了前面三個部分的講解,settingslib的代碼看起來就很簡單了。接下來分開解析

3.4.1、LocalBluetoothAdapter裝飾者

LocalBluetoothAdapter用的是裝飾者模式,代理了BluetoothAdapter的一些方法,並擴展了極少功能。通篇LocalBluetoothAdapter的代碼除了代理外就把藍牙打開狀態傳給了LocalBluetoothProfileManager

public boolean enable() {
        return mAdapter.enable();
    }

 synchronized void setBluetoothStateInt(int state) {
        mState = state;
        if (state == BluetoothAdapter.STATE_ON) {
            ...
            if (mProfileManager != null) {
                mProfileManager.setBluetoothStateOn();
            }
        }
    }

3.4.2、CachedBluetoothDeviceManager配對設備

CachedBluetoothDeviceManager管理已連接設備,裏邊用兩個ArrayList一個Map來存儲。助聽器設備單獨用了一個list存儲。

對象 作用
List<CachedBluetoothDevice> mCachedDevices 已配對設備
List<CachedBluetoothDevice> mHearingAidDevicesNotAddedInCache 助聽器列表供UI顯示
final Map<Long, CachedBluetoothDevice> mCachedDevicesMapForHearingAids 助聽器是兩個設備時,另一個設備存在這個list裏

下面是CachedBluetoothDeviceManager提供的方法列表

方法 作用
getCachedDevicesCopy 拷貝已配對設備List
onDeviceDisappeared 設備消失
onDeviceNameUpdated 設備名稱更新
findDevice 存儲的兩個list中查找
addDevice 添加設備到對應list/map
isPairAddedInCache 是否在配對列表中
getHearingAidPairDeviceSummary 已配對助聽描述
addDeviceNotaddedInMap 添加到map
updateHearingAidsDevices 助聽設備刷新狀態後更新列表
getName 有名字返回名字,沒有名字返回mac地址
clearNonBondedDevices 從三個列表中移除沒有綁定過狀態的設備
onScanningStateChanged 開始掃描更新排序狀態
onBtClassChanged 藍牙設備描述變化
onUuidChanged uuid變化
onBluetoothStateChanged 藍牙開關,關閉需清空列表,打卡需刷新信息
onActiveDeviceChanged profile是否存活
onHiSyncIdChanged 助聽設備類型變化
getHearingAidOtherDevice 獲得助聽設備
hearingAidSwitchDisplayDevice 助聽設備一對,選擇哪個顯示到UI列表
onProfileConnectionStateChanged 協議監聽刷新助聽設備列表
onDeviceUnpaired 取消配對,更新列表
dispatchAudioModeChanged audio狀態變化

3.4.3、BluetoothEventManager處理Event變化

BluetoothEventManager接收藍牙相關廣播和藍牙的一些回調,並根據UI操作執行到對應的事件。
BluetoothEventManager設計思想也很簡單,就是監聽所有需要關心的藍牙廣播。收到狀態後把傳給CallBack或者其他Manager
1、構造函數監聽廣播

 BluetoothEventManager(LocalBluetoothAdapter adapter,
            CachedBluetoothDeviceManager deviceManager, Context context) {
        ...
        // 藍牙開關
        addHandler(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedHandler());
        // 藍牙連接
        addHandler(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED,
                new ConnectionStateChangedHandler());

        // 藍牙發現廣播
        addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, new ScanningStateChangedHandler(true));
        addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, new ScanningStateChangedHandler(false));
        addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());
        addHandler(BluetoothDevice.ACTION_DISAPPEARED, new DeviceDisappearedHandler());
        addHandler(BluetoothDevice.ACTION_NAME_CHANGED, new NameChangedHandler());
        addHandler(BluetoothDevice.ACTION_ALIAS_CHANGED, new NameChangedHandler());

        //配對
        addHandler(BluetoothDevice.ACTION_BOND_STATE_CHANGED, new BondStateChangedHandler());

        // 遠端設備描述信息
        addHandler(BluetoothDevice.ACTION_CLASS_CHANGED, new ClassChangedHandler());
        addHandler(BluetoothDevice.ACTION_UUID, new UuidChangedHandler());
        addHandler(BluetoothDevice.ACTION_BATTERY_LEVEL_CHANGED, new BatteryLevelChangedHandler());

        // 藍牙底座設備狀態,比如車載電源充電狀態
        addHandler(Intent.ACTION_DOCK_EVENT, new DockEventHandler());

        //藍牙協議開始活動廣播
        addHandler(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED,
                   new ActiveDeviceChangedHandler());
        addHandler(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED,
                   new ActiveDeviceChangedHandler());
        addHandler(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED,
                   new ActiveDeviceChangedHandler());

        // 音頻策略,聯繫人
        addHandler(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED,
                new AudioModeChangedHandler());
        addHandler(TelephonyManager.ACTION_PHONE_STATE_CHANGED,
                new AudioModeChangedHandler());
       ...
    }

2、回調給監聽
廣播來了,就遍歷回調Callback,給manager設置狀態。以StateChanged舉例:

private class AdapterStateChangedHandler implements Handler {
        public void onReceive(Context context, Intent intent,
                BluetoothDevice device) {
            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
                                    BluetoothAdapter.ERROR);
            // Reregister Profile Broadcast Receiver as part of TURN OFF
            if (state == BluetoothAdapter.STATE_OFF)
            {
                context.unregisterReceiver(mProfileBroadcastReceiver);
                registerProfileIntentReceiver();
            }
            // update local profiles and get paired devices
            mLocalAdapter.setBluetoothStateInt(state);
            // send callback to update UI and possibly start scanning
            synchronized (mCallbacks) {
                for (BluetoothCallback callback : mCallbacks) {
                    callback.onBluetoothStateChanged(state);
                }
            }
            // Inform CachedDeviceManager that the adapter state has changed
            mDeviceManager.onBluetoothStateChanged(state);
        }
    }

**3、BluetoothCallback **
親切的BluetoothCallback ,我們監聽都是從這兒來監聽

public interface BluetoothCallback {
    void onBluetoothStateChanged(int bluetoothState);
    void onScanningStateChanged(boolean started);
    void onDeviceAdded(CachedBluetoothDevice cachedDevice);
    void onDeviceDeleted(CachedBluetoothDevice cachedDevice);
    void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState);
    void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state);
    void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile);
    void onAudioModeChanged();
    default void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice,
            int state, int bluetoothProfile) {
    }
}

3.4.4、LocalBluetoothProfileManager

LocalBluetoothProfileManager是統一管理settings支持的profile的地方,提供profile的訪問和狀態變化監聽。profile創建和綁定的流程在BluetoothManagerService部分已經分析。這些profile也是文章開頭部分列出settinglib中的profile。用了Map<String, LocalBluetoothProfile>mProfileNameMap 來存儲。

private A2dpProfile mA2dpProfile;
    private A2dpSinkProfile mA2dpSinkProfile;
    private HeadsetProfile mHeadsetProfile;
    private HfpClientProfile mHfpClientProfile;
    private MapProfile mMapProfile;
    private MapClientProfile mMapClientProfile;
    private HidProfile mHidProfile;
    private HidDeviceProfile mHidDeviceProfile;
    private OppProfile mOppProfile;
    private PanProfile mPanProfile;
    private PbapClientProfile mPbapClientProfile;
    private PbapServerProfile mPbapProfile;
    private final boolean mUsePbapPce;
    private final boolean mUseMapClient;
    private HearingAidProfile mHearingAidProfile;

創建的代碼都在打開藍牙的時候調用setBluetoothStateOn

 void setBluetoothStateOn() {
        if (mHidProfile == null) {
        mHidProfile = new HidProfile(mContext, mLocalAdapter, mDeviceManager, this);
        addProfile(mHidProfile, HidProfile.NAME,
                BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED);
       }
       if (mPanProfile == null) {
        mPanProfile = new PanProfile(mContext, mLocalAdapter);
        addPanProfile(mPanProfile, PanProfile.NAME,
                BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
       }
       if (mHidDeviceProfile == null) {
       mHidDeviceProfile = new HidDeviceProfile(mContext, mLocalAdapter, mDeviceManager, this);
       addProfile(mHidDeviceProfile, HidDeviceProfile.NAME,
                BluetoothHidDevice.ACTION_CONNECTION_STATE_CHANGED);
       }
    ....
    //等等其他profile創建

3.4.5、LocalBluetoothManager

LocalBluetoothManager是這個manager裏最簡單的了就是創建着幾個manager,方便對外獲取manager。

private LocalBluetoothManager(LocalBluetoothAdapter adapter, Context context) {
        mContext = context;
        mLocalAdapter = adapter;

        mCachedDeviceManager = new CachedBluetoothDeviceManager(context, this);
        mEventManager = new BluetoothEventManager(mLocalAdapter,
                mCachedDeviceManager, context);
        mProfileManager = new LocalBluetoothProfileManager(context,
                mLocalAdapter, mCachedDeviceManager, mEventManager);
        mEventManager.readPairedDevices();
    }

SettingsLib小結
1、SettingsLib主要供settings使用,封裝一些操作。
2、四個部分(代理Adapter、管理配對設備、管理profile、監聽藍牙狀態)

四、寫在最後

1、通篇文章下來,我們可以看到Android藍牙的架構並不複雜。client提供對外接口,service通過綁定Bluetooth中Adapterservice對接上具體實現。最後settingslib封裝一些操作供settings使用更便捷。層次分明。不像其他系統service和別的系統service有很多相互作用操作。
2、框架層的講解爲的是幫助大家對Android藍牙整體的理解。往細了講,service、Bluetooth、settings裏邊還有很多細節代碼可以扣。每個profile還有很具體的用法用例。
3、源碼真香

Read the fucking source code!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章