一、前言
本文側重點: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!