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