Android蓝牙开发系列文章-蓝牙设备类型知多少?

在写《Android蓝牙开发系列文章-蓝牙音箱连接》时,计划细化出一篇讲解蓝牙设备类型的文章,现在它来了~

阅读其他内容,可以点击《Android蓝牙开发系列文章-策划篇》,或者扫描文章下方的二维码关注我个人的公众号哈~

为什么要讲解蓝牙设备的分类?

设备的类型是表征设备能力的属性,设备类型的不同决定了UI中图标显示、扫描设备过程中的过滤以及在连接过程中通过什么类型的Profile进行连接。

细一点讲:

不同的蓝牙设备类型在UI中会有不同的UI显示,例如,鼠标设备显示为鼠标图标,音箱设备会显示音箱图标,耳机设备会显示耳机图标。

在扫描过程中,我们需要搜索到目标设备,这个设备类型往往是其中的一个匹配项,只有配对上了,我们才认为这个设备是我们的目标设备,才会对该设备进行下一步的流程:配对、连接等等。

在连接过程中,我们需要针对设备类型不同,通过不同的Profile发起连接,例如,对于音箱设备,我们需要通过A2DP Profile进行连接(如果忘记了,可以回头再看一下《Android蓝牙开发系列文章-蓝牙音箱连接》),对于鼠标设备,我们需要通过Input profile进行连接。

其他需求也可能会用到设备的类型。

目录

1.通过COD进行设备类型区分

2.Demo演示


1.通过COD进行设备类型区分

我们在扫描到设备后,可以通过mac地址构造一个BluetoothDevice对象,然后调用getBluetoothClass()方法获取其设备类型。

1227    /**
1228     * Get the Bluetooth class of the remote device.
1229     *
1230     * @return Bluetooth class object, or null on error
1231     */
1232    @RequiresPermission(Manifest.permission.BLUETOOTH)
1233    public BluetoothClass getBluetoothClass() {
1234        final IBluetooth service = sService;
1235        if (service == null) {
1236            Log.e(TAG, "BT not enabled. Cannot get Bluetooth Class");
1237            return null;
1238        }
1239        try {
1240            int classInt = service.getRemoteClass(this);
1241            if (classInt == BluetoothClass.ERROR) return null;
1242            return new BluetoothClass(classInt);
1243        } catch (RemoteException e) {
1244            Log.e(TAG, "", e);
1245        }
1246        return null;
1247    }

BluetoothClass类持有一个mClass变量,我们利用该变量来分辨设备类型。

从代码的注释,我们可以看到该变量就是蓝牙设备的COD,这个变量是三个部分组成的。

 private final int mClass;
282    /**
283     * Return the Bluetooth Class of Device (CoD) value including the
284     * {@link BluetoothClass.Service}, {@link BluetoothClass.Device.Major} and
285     * minor device fields.
286     *
287     * <p>This value is an integer representation of Bluetooth CoD as in
288     * Bluetooth specification.
289     *
290     * @see <a href="Bluetooth CoD">https://www.bluetooth.com/specifications/assigned-numbers/baseband</a>
291     *
292     * @hide
293     */
294    public int getClassOfDevice() {
295        return mClass;
296    }

这个32位变量用固定的某些位表示service Class/Major Class/Minor Class。为了表述更清晰一点,我画了一个图,如下所示。

 第2位到12位表示Major和Minor Class的组合,第8位到第12位表示Major Class,第14位到第23位表示Service Class。

这里提到了三个名词,下面分别进行解释:

 Service Class:

service class类型有如下几种,一个service表示蓝牙的一个能力,例如,蓝牙设备支持A2DP Service,则表示这个蓝牙设备可以作为一个音箱设备使用。

109    /**
110     * Defines all service class constants.
111     * <p>Each {@link BluetoothClass} encodes zero or more service classes.
112     */
113    public static final class Service {
114        private static final int BITMASK = 0xFFE000;
115
116        public static final int LIMITED_DISCOVERABILITY = 0x002000;
117        public static final int POSITIONING = 0x010000;
118        public static final int NETWORKING = 0x020000;
119        public static final int RENDER = 0x040000;
120        public static final int CAPTURE = 0x080000;
121        public static final int OBJECT_TRANSFER = 0x100000;
122        public static final int AUDIO = 0x200000;
123        public static final int TELEPHONY = 0x400000;
124        public static final int INFORMATION = 0x800000;
125    

我们可以利用hasService(int)来判断是否支持对于的service。

127    /**
128     * Return true if the specified service class is supported by this
129     * {@link BluetoothClass}.
130     * <p>Valid service classes are the public constants in
131     * {@link BluetoothClass.Service}. For example, {@link
132     * BluetoothClass.Service#AUDIO}.
133     *
134     * @param service valid service class
135     * @return true if the service class is supported
136     */
137    public boolean hasService(int service) {
138        return ((mClass & Service.BITMASK & service) != 0);
139    }
140

Major Class:

Major Class表示设备的大类型,这个区分粒度相对来说比较大,通过查看代码,我们可以看到蓝牙设备分为了Computer、Phone等几大类。

151    public static class Device {
152        private static final int BITMASK = 0x1FFC;
153
154        /**
155         * Defines all major device class constants.
156         * <p>See {@link BluetoothClass.Device} for minor classes.
157         */
158        public static class Major {
159            private static final int BITMASK = 0x1F00;
160
161            public static final int MISC = 0x0000;
162            public static final int COMPUTER = 0x0100;
163            public static final int PHONE = 0x0200;
164            public static final int NETWORKING = 0x0300;
165            public static final int AUDIO_VIDEO = 0x0400;
166            public static final int PERIPHERAL = 0x0500;
167            public static final int IMAGING = 0x0600;
168            public static final int WEARABLE = 0x0700;
169            public static final int TOY = 0x0800;
170            public static final int HEALTH = 0x0900;
171            public static final int UNCATEGORIZED = 0x1F00;
172        }
........

确定蓝牙设备属于哪个蓝牙类型大类可以调用如下接口:

256
257    /**
258     * Return the major device class component of this {@link BluetoothClass}.
259     * <p>Values returned from this function can be compared with the
260     * public constants in {@link BluetoothClass.Device.Major} to determine
261     * which major class is encoded in this Bluetooth class.
262     *
263     * @return major device class component
264     */
265    public int getMajorDeviceClass() {
266        return (mClass & Device.Major.BITMASK);
267    }

每个蓝牙设备大类可以进行进一步细化,例如,Computer大类可以进一步划分为如下几个小类:

174        // Devices in the COMPUTER major class
175        public static final int COMPUTER_UNCATEGORIZED = 0x0100;
176        public static final int COMPUTER_DESKTOP = 0x0104;
177        public static final int COMPUTER_SERVER = 0x0108;
178        public static final int COMPUTER_LAPTOP = 0x010C;
179        public static final int COMPUTER_HANDHELD_PC_PDA = 0x0110;
180        public static final int COMPUTER_PALM_SIZE_PC_PDA = 0x0114;
181        public static final int COMPUTER_WEARABLE = 0x0118;

综上,我们可以先用判断service class的方式来判断设备的能力,如果满足我们的要求,再进一步判断一下设备的Major Class,如果通过Major Class还不能定位到你的设备,则再进一步确定设备的小类。

2.Demo演示

我们利用《Android蓝牙开发系列文章-蓝牙音箱连接》中的demo为基础,来看一下我们的音箱是否支持a2dp profile以及它的Major Class是否为AUDIO_VIDEO。

在设备扫描到S7音箱后,判断一下是否满足a2dp Profile和Major Class,如果满足预期,则对这个设备发起配对、连接,如果不满足,则继续搜索设备。

 public void onReceive(Context context, Intent intent) {
            final String action = intent.getAction();
            Log.d(TAG, "onReceive intent = " + action);
            if(action.equals(BluetoothDevice.ACTION_FOUND)) {
                BluetoothDevice btdevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                final String address = btdevice.getAddress();
                final String deviceName = btdevice.getName();
                Log.d(TAG, "onReceive found device, deivce address = " + address + ",deviceName = " + deviceName);
                if(isTargetDevice(btdevice)) {
                    BluetoothClass btClass = btdevice.getBluetoothClass();
                    if(btClass.hasService(BluetoothClass.Service.AUDIO)) {
                        Log.d(TAG, "btdevice: " + btdevice + "support a2dp profile");
                    } else {
                        Log.d(TAG, "btdevice: " + btdevice + "not support a2dp profile");
                        return;
                    }
                    int majorClass = btClass.getMajorDeviceClass();
                    Log.d(TAG, "btClass: " + btClass + "majorClass = " + majorClass);
                    stopScan();
                    mHandler.sendEmptyMessageDelayed(MSG_PAIR, DELAYT_TIMES);
                }
            }

相关日志打印如下,我们可以看到该音箱的确支持A2dp Profile,且其Major Class为1024,转换成16进制数为0x400,等于AUDIO_VIDEO类型。

 --------- beginning of system
03-15 10:53:03.305 1311-1311/com.atlas.btdemo D/MainActivity: onReceive intent = android.bluetooth.device.action.FOUND
03-15 10:53:03.309 1311-1311/com.atlas.btdemo D/MainActivity: onReceive found device, deivce address = FC:58:FA:B4:45:EA,deviceName = S7
03-15 10:53:03.318 1311-1311/com.atlas.btdemo D/MainActivity: deivce :S7is target device
03-15 10:53:03.320 1311-1311/com.atlas.btdemo D/MainActivity: btdevice: FC:58:FA:B4:45:EAsupport a2dp profile
03-15 10:53:03.320 1311-1311/com.atlas.btdemo D/MainActivity: btClass: 260404majorClass = 1024
03-15 10:53:03.331 1311-1311/com.atlas.btdemo D/MainActivity: stop scan device
03-15 10:53:03.832 1311-1311/com.atlas.btdemo D/MainActivity: dispatchMessage, msg.what = 1
03-15 10:53:03.832 1311-1311/com.atlas.btdemo D/MainActivity: start pair device = FC:58:FA:B4:45:EA

 这里想再补充一点,最后不要只根据Major Class来进行设备类型的判断,因为有些设备制作的不标准,即虽然是一个蓝牙音箱,但是它的Major Class却不是0x400。

那应该怎么判断呢?其实我们只需要通过Service Class来判断就行了,因为一个蓝牙设备支持了A2dp Profile,则它就具有了作为音箱的能力,我们完全可以认为它就是一个音箱,不需要其他的条件判断了~

好了,本篇文章就到了这里,主要讲了BluetoothClass这个类型以及结合经验给大家一点判断设备类型的建议~

如果想持续关注本博客内容,请扫描关注个人微信公众号,或者微信搜索:万物互联技术。

发布了35 篇原创文章 · 获赞 17 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Atlas12345/article/details/104872833
今日推荐