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