全称:Service Discovery Profile服务发现协议
使用场景:蓝牙设备之间的那些蓝牙服务可以使用
协议知识:
并没有客户端和服务端
packages\apps\Bluetooth\src\com\android\bluetooth\sdp
SdpManager.java
private boolean mDiscoveryInProgress = false;
BluetoothDevice mDevice;
mDiscoveryInProgress = mDevice.fetchUuidsWithSdp();
具体的代码也很简单,就不详细列出了,流程如下
首先看下RemoteDevices的fetchUuids方法,
void fetchUuids(BluetoothDevice device) {
if (mSdpTracker.contains(device)) return;
mSdpTracker.add(device);
Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT);
message.obj = device;
mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY);
mAdapterService.getRemoteServicesNative(Utils.getBytesFromAddress(device.getAddress()));
}
该方法首先发送一个延迟消息,延迟6s钟
private static final int UUID_INTENT_DELAY = 6000;
然后调用getRemoteServicesNative方法获取蓝牙服务,如果找到服务如何反馈呢?
流程图如下:
void devicePropertyChangedCallback(byte[] address, int[] types, byte[][] values) {
Intent intent;
byte[] val;
int type;
BluetoothDevice bdDevice = getDevice(address);
DeviceProperties device;
if (bdDevice == null) {
device = addDeviceProperties(address);
bdDevice = getDevice(address);
} else {
device = getDeviceProperties(bdDevice);
}
for (int j = 0; j < types.length && device != null; j++) {
type = types[j];
val = values[j];
if(val.length <= 0)
errorLog("devicePropertyChangedCallback: bdDevice: " + bdDevice
+ ", value is empty for type: " + type);
else {
synchronized(mObject) {
switch (type) {
case AbstractionLayer.BT_PROPERTY_BDNAME:
device.mName = new String(val);
intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bdDevice);
intent.putExtra(BluetoothDevice.EXTRA_NAME, device.mName);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM);
debugLog("Remote Device name is: " + device.mName);
break;
case AbstractionLayer.BT_PROPERTY_REMOTE_FRIENDLY_NAME:
if (device.mAlias != null) {
System.arraycopy(val, 0, device.mAlias, 0, val.length);
}
else {
device.mAlias = new String(val);
}
break;
case AbstractionLayer.BT_PROPERTY_BDADDR:
device.mAddress = val;
debugLog("Remote Address is:" + Utils.getAddressStringFromByte(val));
break;
case AbstractionLayer.BT_PROPERTY_CLASS_OF_DEVICE:
device.mBluetoothClass = Utils.byteArrayToInt(val);
intent = new Intent(BluetoothDevice.ACTION_CLASS_CHANGED);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, bdDevice);
intent.putExtra(BluetoothDevice.EXTRA_CLASS,
new BluetoothClass(device.mBluetoothClass));
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mAdapterService.sendBroadcast(intent, mAdapterService.BLUETOOTH_PERM);
debugLog("Remote class is:" + device.mBluetoothClass);
break;
case AbstractionLayer.BT_PROPERTY_UUIDS:
int numUuids = val.length/AbstractionLayer.BT_UUID_SIZE;
int state = mAdapterService.getState();
device.mUuids = Utils.byteArrayToUuid(val);
if (state == BluetoothAdapter.STATE_ON)
sendUuidIntent(bdDevice);
break;
case AbstractionLayer.BT_PROPERTY_TYPE_OF_DEVICE:
// The device type from hal layer, defined in bluetooth.h,
// matches the type defined in BluetoothDevice.java
device.mDeviceType = Utils.byteArrayToInt(val);
break;
case AbstractionLayer.BT_PROPERTY_REMOTE_RSSI:
// RSSI from hal is in one byte
device.mRssi = val[0];
break;
}
}
}
}
}
使用HashMap来保存不同远程蓝牙设备对应的DeviceProperties,
HashMap mDevices
而DeviceProperties保存远程蓝牙设备的各种信息,是RemoteDevices的一个内部类,仅取辅助作用。
class DeviceProperties {
private String mName;
private byte[] mAddress;
private int mBluetoothClass;
private short mRssi;
private ParcelUuid[] mUuids;
private int mDeviceType;
private String mAlias;
private int mBondState;
•••
}
其中ParcelUuid值对应远程蓝牙设备提供的服务, ParcelUuid具体值指什么呢,和蓝牙服务直接如何对应呢?答案就在BluetoothUuid.java中,相关代码如下,
/* See Bluetooth Assigned Numbers document - SDP section, to get the values of UUIDs
* for the various services.
* The following 128 bit values are calculated as:
* uuid * 2^96 + BASE_UUID
*/
public static final ParcelUuid AudioSink =
ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid AudioSource =
ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid AdvAudioDist =
ParcelUuid.fromString("0000110D-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid HSP =
ParcelUuid.fromString("00001108-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid HSP_AG =
ParcelUuid.fromString("00001112-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid Handsfree =
ParcelUuid.fromString("0000111E-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid Handsfree_AG =
ParcelUuid.fromString("0000111F-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid AvrcpController =
ParcelUuid.fromString("0000110E-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid AvrcpTarget =
ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid ObexObjectPush =
ParcelUuid.fromString("00001105-0000-1000-8000-00805f9b34fb");
public static final ParcelUuid Hid =
ParcelUuid.fromString("00001124-0000-1000-8000-00805f9b34fb");
public static final ParcelUuid Hogp =
ParcelUuid.fromString("00001812-0000-1000-8000-00805f9b34fb");
public static final ParcelUuid PANU =
ParcelUuid.fromString("00001115-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid NAP =
ParcelUuid.fromString("00001116-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid BNEP =
ParcelUuid.fromString("0000000f-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid PBAP_PCE =
ParcelUuid.fromString("0000112e-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid PBAP_PSE =
ParcelUuid.fromString("0000112f-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid MAP =
ParcelUuid.fromString("00001134-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid MNS =
ParcelUuid.fromString("00001133-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid MAS =
ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid SAP =
ParcelUuid.fromString("0000112D-0000-1000-8000-00805F9B34FB");
public static final ParcelUuid BASE_UUID =
ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
很明显的,对应值由名字就可以很清晰的看出来。
说了这么多,在我们自己开发的apk中,如何对应呢?
最后看下RemoteDevices的sendUuidIntent方法,
private void sendUuidIntent(BluetoothDevice device) {
DeviceProperties prop = getDeviceProperties(device);
Intent intent = new Intent(BluetoothDevice.ACTION_UUID);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
intent.putExtra(BluetoothDevice.EXTRA_UUID, prop == null? null: prop.mUuids);
mAdapterService.initProfilePriorities(device, prop == null? null: prop.mUuids);
mAdapterService.sendBroadcast(intent, AdapterService.BLUETOOTH_ADMIN_PERM);
//Remove the outstanding UUID request
mSdpTracker.remove(device);
}
该方法将对应的信息都打包通过广播发出去了,只要我们注册并且接收就可以了,我们自己开发的代码如下:
首先动态注册,
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_UUID);
registerReceiver(mReceiver, filter);
然后接收并且处理,
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_UUID.equals(action)) {
BluetoothDevice dev = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (!dev.equals(mDevice)) {
return;
}
Parcelable uuids[] = intent.getParcelableArrayExtra(BluetoothDevice.EXTRA_UUID);
if (uuids != null) {
for (Parcelable uuid : uuids) {
if (BluetoothUuid.PBAP_PSE.equals(uuid)) {
mServicesFragment.addService(ServicesFragment.Service.Type.PBAP, null);
} else if (BluetoothUuid.Handsfree_AG.equals(uuid)) {
mServicesFragment.addService(ServicesFragment.Service.Type.HFP, null);
} else if (BluetoothUuid.AvrcpTarget.equals(uuid) ||
BluetoothUuid.AudioSource.equals(uuid) ||
BluetoothUuid.AudioSink.equals(uuid)) {
Log.v(TAG, "Adding AVRCP");
mServicesFragment.addService(ServicesFragment.Service.Type.AVRCP, null);
}
}
}
mServicesFragment.persistServices();
if (mDiscoveryInProgress) {
Log.v(TAG, "fetching MAS instances");
mDevice.fetchMasInstances();
}
}
}
}
};
如此,大功告成了。