Android 蓝牙设备类型判断代码介绍

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);
	//已连接/绑定设备列表
	Set bondedDevices = 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; } 。。。 }