• 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)具体类型
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    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; }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    这里看不出啥,但是可以知道与蓝牙的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; } 。。。 }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    注意这里是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);
            }
        };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    这里有蓝牙手机、耳机、音箱、鼠标、键盘、遥控器。
    具体日志打印如下:

    
    //普通手机
    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
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    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)) {//蓝牙配对请求状态
    		}
    		...//还有其他蓝牙相关广播
        }
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    这里可以看到蓝牙相关的广播都是会有蓝牙对象回调的!

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    这个方法,普通应用是无法调用到的!

    普通应用只能扫描发现蓝牙,把搜索的蓝牙放到列表中进行判断处理!

    五、总结

    1、蓝牙类型获取api

    BluetoothDevice bluetoothDevice; //蓝牙设备对象
    int type = device.getType(); //(1)功耗类型
    BluetoothClass bluetoothClass = device.getBluetoothClass();
    int deviceClassType = bluetoothClass.getDeviceClass(); //(2)更细的具体类型,系统代码中未定义相关数值
    int deviceType = bluetoothClass.getMajorDeviceClass(); //(3)主要使用的具体类型,能简单区分类别
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    系统应用中也是使用 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; } 。。。 }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
  • 相关阅读:
    Mybatis中传递多个参数的4种方法
    如何解决DNS解析错误
    工作流---流程变量
    【每日一题】打卡 55
    java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory 异常错误
    Web前端系列技术之Web APIs基础(从基础开始)②
    黑豹程序员-架构师学习路线图-百科:Java
    数据结构_绪论
    Shell 实现文件基本操作(切割、排序、去重)
    毛坏房无从下手,不知道怎么装
  • 原文地址:https://blog.csdn.net/wenzhi20102321/article/details/133777224