一、前言
本文侧重点: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 |
已配对设备 |
List |
助听器列表供UI显示 |
final Map |
助听器是两个设备时,另一个设备存在这个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
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!