旨在学习记录把搜索到的设备添加显示的整个java层的流程,细节的东西暂无深入。
在蓝牙设置界面:
进入界面以后类BluetoothSettings用于显示蓝牙的列表信息,此类继承DeviceListPreferenceFragment.这个父类很关
键,它实现BluetoothCallback接口,这个接口是Settingslib模块里面的. 而在Settings模块的mk文件中有把此模块编译引
入。下面先简单看一下Settingslib中的这个BluetoothCallback接口.
package com.android.settingslib.bluetooth;
/**
* BluetoothCallback provides a callback interface for the settings
* UI to receive events from {@link BluetoothEventManager}.
*/
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);
}
从各个函数的名字也可以看出每个函数的大概功能。而我们目前关注的是每个搜索到的蓝牙设备是如何添加到列表进行显示的,那么
我们关注
onDeviceAdded.
可以由前面可知
DeviceListPreferenceFragment
实现了settingslib包中的BluetoothCallBack.在
DeviceListPreference
Fragment
当中我们看
onDeviceAdded
具体实现如下:
public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
if (mDevicePreferenceMap.get(cachedDevice) != null) {
return;
}
// Prevent updates while the list shows one of the state messages
if (mLocalAdapter.getBluetoothState() != BluetoothAdapter.STATE_ON) return;
if (mFilter.matches(cachedDevice.getDevice())) {
createDevicePreference(cachedDevice);
}
}
符合要求后会进一步调用
createDevicePreference
void createDevicePreference(CachedBluetoothDevice cachedDevice) {
if (mDeviceListGroup == null) {
Log.w(TAG, "Trying to create a device preference before the list group/category "
+ "exists!");
return;
}
BluetoothDevicePreference preference = new BluetoothDevicePreference(
getActivity(), cachedDevice);
initDevicePreference(preference);
mDeviceListGroup.addPreference(preference);//在此处就完成了添加
mDevicePreferenceMap.put(cachedDevice, preference);
}
如上最终把搜索到的蓝牙设备信息封装成一个prefrence放到mDeviceListGroup当中.
mDeviceListGroup是一个PrefrenceGroup
mDeviceListGroup
= (PreferenceCategory) findPreference(KEY_BT_DEVICE_LIST)
用于显示添加到的蓝牙列表.
那么问题来了什么时候会调用这个
BluetoothCallback接口的
onDeviceAdded那?
此处我们只考虑搜索到时候的显示问题,调用
蓝牙adapter的
startScanning
开始进行搜索,当搜索到蓝牙设备时,会由底层上
报给JNI然后往上层回调(此流程暂无分析)。那么我们在进入到Bluetooth模块去找相应的回调。
在Bluetooth模块的btservice包下有JniCallBacks类。进入后你会发现很多的在JNI层调用的函数。此处我们关注两个
void devicePropertyChangedCallback(byte[] address, int[] types, byte[][] val) {
mRemoteDevices.devicePropertyChangedCallback(address, types, val);
}
void deviceFoundCallback(byte[] address) {
mRemoteDevices.deviceFoundCallback(address);//当发现设备时最终底层通过JNI技术会调用的这里.
}
devicePropertyChangedCallback
上这个接口会在
deviceFoundCallback
执行前被调用,用于初始化java层的搜索到设备的
属性。重点关注deviceFoundCallback这个函数。至于这个函数在C++如何调用过来的,它是在com_android_bluetooth_btservice_
AdapterService.cpp这个cpp文件中有对应的方法,具体流程由于自身c语言功底问题没有深入研究。
那么我们此时的重点就放到了JniCallbacks这个类的相关方法中。mRemoteDevices是RemoteDevices类,也位于btservice包下。
那么就调用到它的
deviceFoundCallback
放方法中了.
void deviceFoundCallback(byte[] address) {
// The device properties are already registered - we can send the intent
// now
BluetoothDevice device = getDevice(address);
debugLog("deviceFoundCallback: Remote Address is:" + device);
DeviceProperties deviceProp = getDeviceProperties(device);
if (deviceProp == null) {
errorLog("Device Properties is null for Device:" + device);
return;
}
Intent intent = new Intent(BluetoothDevice.ACTION_FOUND);//这就是应用开发是监听的FOUND广播
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
intent.putExtra(BluetoothDevice.EXTRA_CLASS,
new BluetoothClass(deviceProp.mBluetoothClass));
intent.putExtra(BluetoothDevice.EXTRA_RSSI, deviceProp.mRssi);
intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProp.mName);
mAdapterService.sendBroadcastMultiplePermissions(intent,
new String[] {AdapterService.BLUETOOTH_PERM,
android.Manifest.permission.ACCESS_COARSE_LOCATION});
}
把搜索到的设备信息封装到一个inten当中,再以广播的形式发出去.总结来说就是底层找到设备以后,通过JNI会调用相应的接口
然后进行,在几个接口的相互调用后会发出一个
String ACTION_FOUND =
"android.bluetooth.device.action.FOUND"广播,并在int
ent当中封装了一些设备的基本信息如name.
那么接下来我们就该想是谁怎么样处理了这个广播那?一般来说此时肯定应该是去Settings模块找谁注册这个广播的,但是由我
们前面的分析可知,Settings模块里面的
onDeviceAdded
方法是实现了Settingslib当中的接口。跟踪查找代码,最终发现在setting
slib的BluetoothEventManager类中,动态的注册了FOUND的广播
addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());
广播的注册进行了简单的封装处理,此处不作为主要内容分析。接下来看onRecive方法
private class DeviceFoundHandler implements Handler {
public void onReceive(Context context, Intent intent,
BluetoothDevice device) {
short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);
BluetoothClass btClass = intent.getParcelableExtra(BluetoothDevice.EXTRA_CLASS);
String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
android.util.Log.d("zy_test","DeviceFoundHandler name = "+name);
// TODO Pick up UUID. They should be available for 2.1 devices.
// Skip for now, there's a bluez problem and we are not getting uuids even for 2.1.
CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
if (cachedDevice == null) {
cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);
Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice: "
+ cachedDevice);
// callback to UI to create Preference for new device
dispatchDeviceAdded(cachedDevice);//此处是关键
}
cachedDevice.setRssi(rssi);
cachedDevice.setBtClass(btClass);
cachedDevice.setNewName(name);
cachedDevice.setVisible(true);
}
}
经过一系列的判断后,最终调用到
dispatchDeviceAdded.
void dispatchDeviceAdded(CachedBluetoothDevice cachedDevice) {
synchronized (mCallbacks) {
for (BluetoothCallback callback : mCallbacks) {
callback.onDeviceAdded(cachedDevice);
}
}
}
由上可知依次调用了mCallbacks的onDeviceAdded方法,看起来没错应该就是我们前面的
DeviceListPreferenceFragment
实现的
那个了。验证一下:
mCallbacks在
BluetoothEventManager中声明如下
private final Collection<BluetoothCallback> mCallbacks =
new ArrayList<BluetoothCallback>();
它的添加元素的方法在:
/** Register to start receiving callbacks for Bluetooth events. */
public void registerCallback(BluetoothCallback callback) {
synchronized (mCallbacks) {
mCallbacks.add(callback);
}
}
很显然,我们的
DeviceListPreferenceFragment
也应该是调用了
registerCallback
是接口的
.我们再去找一下.
@Override
public void onResume() {
super.onResume();
if (mLocalManager == null || isUiRestricted()) return;
mLocalManager.setForegroundActivity(getActivity());
mLocalManager.getEventManager().registerCallback(this);//这里完成注册.
updateProgressUi(mLocalAdapter.isDiscovering());
}
mLocalManager.getEventManager()获取的就是
BluetoothEventManager
对象.至此结合我们前面的分析完成了把搜索到的蓝牙设
备添加到列表显示的过程。
总的来说说就是:底层搜索到蓝牙设备后,通过JNI技术把相关的设备信息封装然后传递到java层的Bluetooth模块当中,java层收
到这个消息以后会往外发送一个FOUND的广播,这个广播的intent携带了当前设备的一些基本信息。而在Setingslib模块中注册这个广
播,然后调用相应的添加接口。而在Settings模块正好实现了这个接口.