1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.bluetooth;
18 
19 import android.annotation.Nullable;
20 import android.annotation.SystemApi;
21 import android.compat.annotation.UnsupportedAppUsage;
22 import android.os.Build;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 
26 /**
27  * Represents a Bluetooth class, which describes general characteristics and capabilities of a
28  * device. For example, a Bluetooth class will specify the general device type such as a phone, a
29  * computer, or headset, and whether it's capable of services such as audio or telephony.
30  *
31  * <p>Every Bluetooth class is composed of zero or more service classes, and exactly one device
32  * class. The device class is further broken down into major and minor device class components.
33  *
34  * <p>{@link BluetoothClass} is useful as a hint to roughly describe a device (for example to show
35  * an icon in the UI), but does not reliably describe which Bluetooth profiles or services are
36  * actually supported by a device. Accurate service discovery is done through SDP requests, which
37  * are automatically performed when creating an RFCOMM socket with {@link
38  * BluetoothDevice#createRfcommSocketToServiceRecord} and {@link
39  * BluetoothAdapter#listenUsingRfcommWithServiceRecord}
40  *
41  * <p>Use {@link BluetoothDevice#getBluetoothClass} to retrieve the class for a remote device.
42  * <!--
43  * The Bluetooth class is a 32 bit field. The format of these bits is defined at
44  * http://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
45  * (login required). This class contains that 32 bit field, and provides
46  * constants and methods to determine which Service Class(es) and Device Class
47  * are encoded in that field.
48  * -->
49  */
50 public final class BluetoothClass implements Parcelable {
51     /**
52      * Legacy error value. Applications should use null instead.
53      *
54      * @hide
55      */
56     public static final int ERROR = 0xFF000000;
57 
58     private final int mClass;
59 
60     /** @hide */
61     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
BluetoothClass(int classInt)62     public BluetoothClass(int classInt) {
63         mClass = classInt;
64     }
65 
66     @Override
equals(@ullable Object o)67     public boolean equals(@Nullable Object o) {
68         if (o instanceof BluetoothClass) {
69             return mClass == ((BluetoothClass) o).mClass;
70         }
71         return false;
72     }
73 
74     @Override
hashCode()75     public int hashCode() {
76         return mClass;
77     }
78 
79     @Override
toString()80     public String toString() {
81         return Integer.toHexString(mClass);
82     }
83 
84     @Override
describeContents()85     public int describeContents() {
86         return 0;
87     }
88 
89     public static final @android.annotation.NonNull Parcelable.Creator<BluetoothClass> CREATOR =
90             new Parcelable.Creator<BluetoothClass>() {
91                 public BluetoothClass createFromParcel(Parcel in) {
92                     return new BluetoothClass(in.readInt());
93                 }
94 
95                 public BluetoothClass[] newArray(int size) {
96                     return new BluetoothClass[size];
97                 }
98             };
99 
100     @Override
writeToParcel(Parcel out, int flags)101     public void writeToParcel(Parcel out, int flags) {
102         out.writeInt(mClass);
103     }
104 
105     /**
106      * Defines all service class constants.
107      *
108      * <p>Each {@link BluetoothClass} encodes zero or more service classes.
109      */
110     public static final class Service {
111         private static final int BITMASK = 0xFFE000;
112 
113         public static final int LIMITED_DISCOVERABILITY = 0x002000;
114 
115         /** Represent devices LE audio service */
116         public static final int LE_AUDIO = 0x004000;
117 
118         public static final int POSITIONING = 0x010000;
119         public static final int NETWORKING = 0x020000;
120         public static final int RENDER = 0x040000;
121         public static final int CAPTURE = 0x080000;
122         public static final int OBJECT_TRANSFER = 0x100000;
123         public static final int AUDIO = 0x200000;
124         public static final int TELEPHONY = 0x400000;
125         public static final int INFORMATION = 0x800000;
126     }
127 
128     /**
129      * Return true if the specified service class is supported by this {@link BluetoothClass}.
130      *
131      * <p>Valid service classes are the public constants in {@link BluetoothClass.Service}. For
132      * example, {@link BluetoothClass.Service#AUDIO}.
133      *
134      * @param service valid service class
135      * @return true if the service class is supported
136      */
hasService(int service)137     public boolean hasService(int service) {
138         return ((mClass & Service.BITMASK & service) != 0);
139     }
140 
141     /**
142      * Defines all device class constants.
143      *
144      * <p>Each {@link BluetoothClass} encodes exactly one device class, with major and minor
145      * components.
146      *
147      * <p>The constants in {@link BluetoothClass.Device} represent a combination of major and minor
148      * device components (the complete device class). The constants in {@link
149      * BluetoothClass.Device.Major} represent only major device classes.
150      *
151      * <p>See {@link BluetoothClass.Service} for service class constants.
152      */
153     public static class Device {
154         private static final int BITMASK = 0x1FFC;
155 
156         /**
157          * Defines all major device class constants.
158          *
159          * <p>See {@link BluetoothClass.Device} for minor classes.
160          */
161         public static class Major {
162             private static final int BITMASK = 0x1F00;
163 
164             public static final int MISC = 0x0000;
165             public static final int COMPUTER = 0x0100;
166             public static final int PHONE = 0x0200;
167             public static final int NETWORKING = 0x0300;
168             public static final int AUDIO_VIDEO = 0x0400;
169             public static final int PERIPHERAL = 0x0500;
170             public static final int IMAGING = 0x0600;
171             public static final int WEARABLE = 0x0700;
172             public static final int TOY = 0x0800;
173             public static final int HEALTH = 0x0900;
174             public static final int UNCATEGORIZED = 0x1F00;
175         }
176 
177         // Devices in the COMPUTER major class
178         public static final int COMPUTER_UNCATEGORIZED = 0x0100;
179         public static final int COMPUTER_DESKTOP = 0x0104;
180         public static final int COMPUTER_SERVER = 0x0108;
181         public static final int COMPUTER_LAPTOP = 0x010C;
182         public static final int COMPUTER_HANDHELD_PC_PDA = 0x0110;
183         public static final int COMPUTER_PALM_SIZE_PC_PDA = 0x0114;
184         public static final int COMPUTER_WEARABLE = 0x0118;
185 
186         // Devices in the PHONE major class
187         public static final int PHONE_UNCATEGORIZED = 0x0200;
188         public static final int PHONE_CELLULAR = 0x0204;
189         public static final int PHONE_CORDLESS = 0x0208;
190         public static final int PHONE_SMART = 0x020C;
191         public static final int PHONE_MODEM_OR_GATEWAY = 0x0210;
192         public static final int PHONE_ISDN = 0x0214;
193 
194         // Minor classes for the AUDIO_VIDEO major class
195         public static final int AUDIO_VIDEO_UNCATEGORIZED = 0x0400;
196         public static final int AUDIO_VIDEO_WEARABLE_HEADSET = 0x0404;
197         public static final int AUDIO_VIDEO_HANDSFREE = 0x0408;
198         // public static final int AUDIO_VIDEO_RESERVED              = 0x040C;
199         public static final int AUDIO_VIDEO_MICROPHONE = 0x0410;
200         public static final int AUDIO_VIDEO_LOUDSPEAKER = 0x0414;
201         public static final int AUDIO_VIDEO_HEADPHONES = 0x0418;
202         public static final int AUDIO_VIDEO_PORTABLE_AUDIO = 0x041C;
203         public static final int AUDIO_VIDEO_CAR_AUDIO = 0x0420;
204         public static final int AUDIO_VIDEO_SET_TOP_BOX = 0x0424;
205         public static final int AUDIO_VIDEO_HIFI_AUDIO = 0x0428;
206         public static final int AUDIO_VIDEO_VCR = 0x042C;
207         public static final int AUDIO_VIDEO_VIDEO_CAMERA = 0x0430;
208         public static final int AUDIO_VIDEO_CAMCORDER = 0x0434;
209         public static final int AUDIO_VIDEO_VIDEO_MONITOR = 0x0438;
210         public static final int AUDIO_VIDEO_VIDEO_DISPLAY_AND_LOUDSPEAKER = 0x043C;
211         public static final int AUDIO_VIDEO_VIDEO_CONFERENCING = 0x0440;
212         // public static final int AUDIO_VIDEO_RESERVED              = 0x0444;
213         public static final int AUDIO_VIDEO_VIDEO_GAMING_TOY = 0x0448;
214 
215         // Devices in the WEARABLE major class
216         public static final int WEARABLE_UNCATEGORIZED = 0x0700;
217         public static final int WEARABLE_WRIST_WATCH = 0x0704;
218         public static final int WEARABLE_PAGER = 0x0708;
219         public static final int WEARABLE_JACKET = 0x070C;
220         public static final int WEARABLE_HELMET = 0x0710;
221         public static final int WEARABLE_GLASSES = 0x0714;
222 
223         // Devices in the TOY major class
224         public static final int TOY_UNCATEGORIZED = 0x0800;
225         public static final int TOY_ROBOT = 0x0804;
226         public static final int TOY_VEHICLE = 0x0808;
227         public static final int TOY_DOLL_ACTION_FIGURE = 0x080C;
228         public static final int TOY_CONTROLLER = 0x0810;
229         public static final int TOY_GAME = 0x0814;
230 
231         // Devices in the HEALTH major class
232         public static final int HEALTH_UNCATEGORIZED = 0x0900;
233         public static final int HEALTH_BLOOD_PRESSURE = 0x0904;
234         public static final int HEALTH_THERMOMETER = 0x0908;
235         public static final int HEALTH_WEIGHING = 0x090C;
236         public static final int HEALTH_GLUCOSE = 0x0910;
237         public static final int HEALTH_PULSE_OXIMETER = 0x0914;
238         public static final int HEALTH_PULSE_RATE = 0x0918;
239         public static final int HEALTH_DATA_DISPLAY = 0x091C;
240 
241         // Devices in PERIPHERAL major class
242         public static final int PERIPHERAL_NON_KEYBOARD_NON_POINTING = 0x0500;
243         public static final int PERIPHERAL_KEYBOARD = 0x0540;
244         public static final int PERIPHERAL_POINTING = 0x0580;
245         public static final int PERIPHERAL_KEYBOARD_POINTING = 0x05C0;
246     }
247 
248     /**
249      * Return the major device class component of this {@link BluetoothClass}.
250      *
251      * <p>Values returned from this function can be compared with the public constants in {@link
252      * BluetoothClass.Device.Major} to determine which major class is encoded in this Bluetooth
253      * class.
254      *
255      * @return major device class component
256      */
getMajorDeviceClass()257     public int getMajorDeviceClass() {
258         return (mClass & Device.Major.BITMASK);
259     }
260 
261     /**
262      * Return the (major and minor) device class component of this {@link BluetoothClass}.
263      *
264      * <p>Values returned from this function can be compared with the public constants in {@link
265      * BluetoothClass.Device} to determine which device class is encoded in this Bluetooth class.
266      *
267      * @return device class component
268      */
getDeviceClass()269     public int getDeviceClass() {
270         return (mClass & Device.BITMASK);
271     }
272 
273     /**
274      * Return the Bluetooth Class of Device (CoD) value including the {@link
275      * BluetoothClass.Service}, {@link BluetoothClass.Device.Major} and minor device fields.
276      *
277      * <p>This value is an integer representation of Bluetooth CoD as in Bluetooth specification.
278      *
279      * @see <a href="Bluetooth
280      *     CoD">https://www.bluetooth.com/specifications/assigned-numbers/baseband</a>
281      * @hide
282      */
getClassOfDevice()283     public int getClassOfDevice() {
284         return mClass;
285     }
286 
287     public static final int PROFILE_HEADSET = 0;
288 
289     public static final int PROFILE_A2DP = 1;
290 
291     /** @hide */
292     @SystemApi public static final int PROFILE_OPP = 2;
293 
294     public static final int PROFILE_HID = 3;
295 
296     /** @hide */
297     @SystemApi public static final int PROFILE_PANU = 4;
298 
299     /** @hide */
300     @SystemApi public static final int PROFILE_NAP = 5;
301 
302     /** @hide */
303     @SystemApi public static final int PROFILE_A2DP_SINK = 6;
304 
305     /**
306      * Check class bits for possible bluetooth profile support. This is a simple heuristic that
307      * tries to guess if a device with the given class bits might support specified profile. It is
308      * not accurate for all devices. It tries to err on the side of false positives.
309      *
310      * @param profile the profile to be checked
311      * @return whether this device supports specified profile
312      */
doesClassMatch(int profile)313     public boolean doesClassMatch(int profile) {
314         if (profile == PROFILE_A2DP) {
315             if (hasService(Service.RENDER)) {
316                 return true;
317             }
318             // By the A2DP spec, sinks must indicate the RENDER service.
319             // However we found some that do not (Chordette). So lets also
320             // match on some other class bits.
321             switch (getDeviceClass()) {
322                 case Device.AUDIO_VIDEO_HIFI_AUDIO:
323                 case Device.AUDIO_VIDEO_HEADPHONES:
324                 case Device.AUDIO_VIDEO_LOUDSPEAKER:
325                 case Device.AUDIO_VIDEO_CAR_AUDIO:
326                     return true;
327                 default:
328                     return false;
329             }
330         } else if (profile == PROFILE_A2DP_SINK) {
331             if (hasService(Service.CAPTURE)) {
332                 return true;
333             }
334             // By the A2DP spec, srcs must indicate the CAPTURE service.
335             // However if some device that do not, we try to
336             // match on some other class bits.
337             switch (getDeviceClass()) {
338                 case Device.AUDIO_VIDEO_HIFI_AUDIO:
339                 case Device.AUDIO_VIDEO_SET_TOP_BOX:
340                 case Device.AUDIO_VIDEO_VCR:
341                     return true;
342                 default:
343                     return false;
344             }
345         } else if (profile == PROFILE_HEADSET) {
346             // The render service class is required by the spec for HFP, so is a
347             // pretty good signal
348             if (hasService(Service.RENDER)) {
349                 return true;
350             }
351             // Just in case they forgot the render service class
352             switch (getDeviceClass()) {
353                 case Device.AUDIO_VIDEO_HANDSFREE:
354                 case Device.AUDIO_VIDEO_WEARABLE_HEADSET:
355                 case Device.AUDIO_VIDEO_CAR_AUDIO:
356                     return true;
357                 default:
358                     return false;
359             }
360         } else if (profile == PROFILE_OPP) {
361             if (hasService(Service.OBJECT_TRANSFER)) {
362                 return true;
363             }
364 
365             switch (getDeviceClass()) {
366                 case Device.COMPUTER_UNCATEGORIZED:
367                 case Device.COMPUTER_DESKTOP:
368                 case Device.COMPUTER_SERVER:
369                 case Device.COMPUTER_LAPTOP:
370                 case Device.COMPUTER_HANDHELD_PC_PDA:
371                 case Device.COMPUTER_PALM_SIZE_PC_PDA:
372                 case Device.COMPUTER_WEARABLE:
373                 case Device.PHONE_UNCATEGORIZED:
374                 case Device.PHONE_CELLULAR:
375                 case Device.PHONE_CORDLESS:
376                 case Device.PHONE_SMART:
377                 case Device.PHONE_MODEM_OR_GATEWAY:
378                 case Device.PHONE_ISDN:
379                     return true;
380                 default:
381                     return false;
382             }
383         } else if (profile == PROFILE_HID) {
384             return getMajorDeviceClass() == Device.Major.PERIPHERAL;
385         } else if (profile == PROFILE_PANU || profile == PROFILE_NAP) {
386             // No good way to distinguish between the two, based on class bits.
387             if (hasService(Service.NETWORKING)) {
388                 return true;
389             }
390             return getMajorDeviceClass() == Device.Major.NETWORKING;
391         } else {
392             return false;
393         }
394     }
395 }
396