Android 蓝牙设备类型判断
一、前言
Android 蓝牙设备有各种类型,比如蓝牙手机,蓝牙耳机,蓝牙手环,蓝牙鼠标键盘,蓝牙玩具,健康检测设备等等。
有些场景需要具体区分就需要进行判断了。一个是扫描到后图标显示设备类型,还是可能是具体处理的区别。
这些设备的类型,硬件设备本身其实是有定义的,
但是也不排除有些设备定义不正确,这些都是要我们开发者进行调试才清楚的。
二、蓝牙类型获取api
BluetoothDevice bluetoothDevice; //蓝牙设备对象,怎么获取后面接收 int type = device.getType(); //(1)简单类型 BluetoothClass bluetoothClass = device.getBluetoothClass(); int deviceClassType = bluetoothClass.getDeviceClass(); //(2)clss tyep int deviceType = bluetoothClass.getMajorDeviceClass(); //(3)具体类型
getMajorDeviceClass 才是详细类型的数值。
其实把这几个type 都打印出来就能看到数值了。
三、各个蓝牙类型获取api详解
1、getType() 方法的类型
这个方法获取的是大致的类型。
具体类型的定义:
packages\modules\Bluetooth\framework\java\android\bluetooth\BluetoothDevice.java
/** * Bluetooth device type, Unknown */ public static final int DEVICE_TYPE_UNKNOWN = 0; /** * Bluetooth device type, Classic - BR/EDR devices,经典-BR/EDR设备 */ public static final int DEVICE_TYPE_CLASSIC = 1; /** * Bluetooth device type, Low Energy - LE-only,低能耗-仅限LE */ public static final int DEVICE_TYPE_LE = 2; /** * Bluetooth device type, Dual Mode - BR/EDR/LE,双模式-BR/EDR/LE */ public static final int DEVICE_TYPE_DUAL = 3;
Android13 的蓝牙源码是在这个目录,旧的源码是在framework 目录下的。
比如手机设备的值为3,蓝牙耳机、蓝牙鼠标键盘值为1;
但是这个不能区分具体类型比较。所以getType() 一般不怎么使用。
2、getDeviceClass()方法的类型
这个类型没怎么用过,网上也没几个人用。
因为他定义的类型代码中并未进行分类,需要自己去蓝牙相关协议对比确认。
具体类型的定义:
packages\modules\Bluetooth\framework\java\android\bluetooth\BluetoothClass.java
/** * Return the (major and minor) device class component of this * {@link BluetoothClass}. *Values returned from this function can be compared with the * public constants in {@link BluetoothClass.Device} to determine which * device class is encoded in this Bluetooth class. * * @return device class component */ public int getDeviceClass() { return (mClass & Device.BITMASK); } /** * Return the Bluetooth Class of Device (CoD) value including the * {@link BluetoothClass.Service}, {@link BluetoothClass.Device.Major} and * minor device fields. * *
This value is an integer representation of Bluetooth CoD as in * Bluetooth specification. * * @see https://www.bluetooth.com/specifications/assigned-numbers/baseband * * @hide */ @TestApi //这个是隐藏的,也是蓝牙设备类型的COD数值。 public int getClassOfDevice() { return mClass; }
这里看不出啥,但是可以知道与蓝牙的COD数值相关,COD 具体类型的定义有兴趣的可以自己搜索。
下面的 getMajorDeviceClass 方法的值也是基于 蓝牙COD的。
从后面日志看 getDeviceClass 方法还更具体一些。
3、getMajorDeviceClass()
这个类型是在 DeviceClass 对象基础上的类型!
下面的代码类型定义都是在 BluetoothClass.java 这个类里面。
具体类型的定义:
//获取具体类型 public int getMajorDeviceClass() { return (mClass & Device.Major.BITMASK); } //内部类定义具体数据 public static class Device { private static final int BITMASK = 0x1FFC; /** * Defines all major device class constants. *See {@link BluetoothClass.Device} for minor classes. */ public static class Major { private static final int BITMASK = 0x1F00; public static final int MISC = 0x0000; public static final int COMPUTER = 0x0100; //电脑设备 public static final int PHONE = 0x0200; //手机设备 public static final int NETWORKING = 0x0300; //网络设备 ,不清楚什么设备 public static final int AUDIO_VIDEO = 0x0400; //音频视频设备,蓝牙耳机音响 public static final int PERIPHERAL = 0x0500; //外部设备,比如蓝牙鼠标键盘,蓝牙遥控器 public static final int IMAGING = 0x0600; //影像设备 public static final int WEARABLE = 0x0700; //穿戴设备 public static final int TOY = 0x0800; //玩具设备 public static final int HEALTH = 0x0900; //健康检测设备 public static final int UNCATEGORIZED = 0x1F00; } 。。。 }
注意这里是16进制的数值,日志打印中是十进制的数,需要转换后对比。
4、查看日志打印
//监听各种蓝牙广播 public void registerBroadcast(Context context) { DebugLog.debug(""); final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED); intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED); intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED); intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); intentFilter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST); intentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED); intentFilter.addAction(BluetoothDevice.ACTION_FOUND); context.registerReceiver(mReceiver, intentFilter); } //打印广播后的日志 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); DebugLog.info("action = " + action); if (action == null) { DebugLog.error("action == null!"); return; } BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (device == null) { DebugLog.error("device == null!"); return; } int type = device.getType(); int getDeviceClassType = device.getBluetoothClass().getDeviceClass(); int getMajorDeviceClassType = device.getBluetoothClass().getMajorDeviceClass(); DebugLog.info("device = " + device); DebugLog.info("getAlias = " + device.getAlias()); DebugLog.info("type = " + type); DebugLog.info("getDeviceClassType = " + getDeviceClassType); DebugLog.info("getMajorDeviceClassType = " + getMajorDeviceClassType); } };
这里有蓝牙手机、耳机、音箱、鼠标、键盘、遥控器。
具体日志打印如下:
//普通手机 action = android.bluetooth.device.action.ACL_CONNECTED device = F0:5C:77:F4:5E:65 getAlias = Pixel 4 type = 1(最开始打印这个) --》 type = 3(后面打印这个) getDeviceClassType = 524 // -->0x20c getMajorDeviceClassType = 512 // -->0x200 //蓝牙耳机 action = android.bluetooth.device.action.BOND_STATE_CHANGED//其他广播也打印,这边不一一写 device = 0D:3F:91:E2:FF:D3 getAlias = Y-12 type = 1 getDeviceClassType = 1028 // -->0x404 getMajorDeviceClassType = 1024 // -->0x400 //蓝牙音箱,和耳机一样 action = android.bluetooth.device.action.BOND_STATE_CHANGED device = 11:75:58:11:AC:7C getAlias = A19 type = 1 getDeviceClassType = 1028 getMajorDeviceClassType = 1024 //蓝牙鼠标 action = android.bluetooth.device.action.ACL_CONNECTED device = 34:88:5D:AC:32:D1 getAlias = Bluetooth Mouse M336/M337/M535 type = 1 getDeviceClassType = 1408 // -->0x580 getMajorDeviceClassType = 1280 // -->0x500 //蓝牙键盘 action = android.bluetooth.device.action.PAIRING_REQUEST device = 34:88:5D:C1:4A:9D getAlias = Keyboard K380 type = 1 getDeviceClassType = 1344 // -->0x540 getMajorDeviceClassType = 1280 //蓝牙遥控器 action = android.bluetooth.device.action.BOND_STATE_CHANGED device = 54:03:84:90:FB:72 getAlias = Horion control FB72 type = 2 getDeviceClassType = 1292// -->0x50c getMajorDeviceClassType = 1280
Android系统代码蓝牙连接界面上也是使用的 getMajorDeviceClassType 返回的值,显示对应的图标。
上面也看到了 getDeviceClassType 可以具体区分蓝牙键盘和鼠标。
其他没遇见的类型可以自己打印这些数据查看一下信息即可。
类型判断参考:
https://www.codenong.com/js12b69fe68246/
从上面日志看 getMajorDeviceClassType 很多蓝牙设备会相同,但是 getDeviceClassType 不一样。
getDeviceClassType 类型还更详细!
看起来 getDeviceClassType 是在 getMajorDeviceClassType 的类型上加上具体类型值。
蓝牙类型 SOD相关值介绍:
https://blog.csdn.net/Atlas12345/article/details/104872833
四、蓝牙对象 BluetoothDevice 获取
1、广播监听
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); //发现设备广播 filter.addAction(BluetoothDevice.ACTION_DISCOVERY_FINISHED));//搜索结束广播 ... private BroadcastReceiver receiver = new BroadcastReceiver(){ @Override public void onReceive(Context context, Intent intent){ String action = intent.getAction(); if(BluetoothDevice.ACTION_FOUND.equals(action)){//发现蓝牙设备 BluetoothDevice device0 =intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); } else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {//蓝牙绑定状态改变 BluetoothDevice device1 =intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); }else if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {//蓝牙耳机连接状态 BluetoothDevice device3 =intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); }else if (action.equals(BluetoothDevice.ACTION_PAIRING_REQUEST)) {//蓝牙配对请求状态 } ...//还有其他蓝牙相关广播 } };
这里可以看到蓝牙相关的广播都是会有蓝牙对象回调的!
2、遍历所有扫描到的蓝牙设备
// LocalBluetoothManager 是SettingsLib里面的类,估计要源码应用或者导入SettingsLib包的应用才能获取到这个类。 LocalBluetoothManager mBluetoothManager = LocalBluetoothManager.getInstance(context, mOnInitCallback); //已连接/绑定设备列表 SetbondedDevices = mBluetoothManager.getBluetoothAdapter().getBondedDevices(); LogUtil.debug("bondedDevices size = " + bondedDevices.size()); //未从已连接设备列表中找到断开的api,从所有的设备列表中进行判断连接状态后断开 Collection cachedDevices = mBluetoothManager.getCachedDeviceManager().getCachedDevicesCopy(); LogUtil.debug("cachedDevices size = " + cachedDevices.size());
这个方法,普通应用是无法调用到的!
普通应用只能扫描发现蓝牙,把搜索的蓝牙放到列表中进行判断处理!
五、总结
1、蓝牙类型获取api
BluetoothDevice bluetoothDevice; //蓝牙设备对象 int type = device.getType(); //(1)功耗类型 BluetoothClass bluetoothClass = device.getBluetoothClass(); int deviceClassType = bluetoothClass.getDeviceClass(); //(2)更细的具体类型,系统代码中未定义相关数值 int deviceType = bluetoothClass.getMajorDeviceClass(); //(3)主要使用的具体类型,能简单区分类别
系统应用中也是使用 getMajorDeviceClass 进行判断的。
2、具体类型的定义:
BluetoothClass.java 这个类里面。 //获取具体类型 public int getMajorDeviceClass() { return (mClass & Device.Major.BITMASK); } //内部类定义具体数据 public static class Device { private static final int BITMASK = 0x1FFC; /** * Defines all major device class constants. *See {@link BluetoothClass.Device} for minor classes. */ public static class Major { private static final int BITMASK = 0x1F00; public static final int MISC = 0x0000; public static final int COMPUTER = 0x0100; //电脑设备,对应10进制 256 public static final int PHONE = 0x0200; //手机设备,512 public static final int NETWORKING = 0x0300; //网络设备 ,不清楚什么设备,768 public static final int AUDIO_VIDEO = 0x0400; //音频视频设备,蓝牙耳机音响,1024 public static final int PERIPHERAL = 0x0500; //外部设备,比如蓝牙鼠标键盘,蓝牙遥控器,1280 public static final int IMAGING = 0x0600; //影像设备,1536 public static final int WEARABLE = 0x0700; //穿戴设备,1792 public static final int TOY = 0x0800; //玩具设备,2048 public static final int HEALTH = 0x0900; //健康检测设备,2304 public static final int UNCATEGORIZED = 0x1F00; } 。。。 }