1 /* 2 * Copyright (C) 2009 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.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.SuppressLint; 22 import android.annotation.SystemApi; 23 import android.compat.annotation.UnsupportedAppUsage; 24 import android.os.ParcelUuid; 25 26 import java.nio.ByteBuffer; 27 import java.nio.ByteOrder; 28 import java.util.Arrays; 29 import java.util.HashSet; 30 import java.util.UUID; 31 32 /** 33 * Static helper methods and constants to decode the ParcelUuid of remote devices. 34 * 35 * @hide 36 */ 37 @SystemApi 38 @SuppressLint("AndroidFrameworkBluetoothPermission") 39 public final class BluetoothUuid { 40 41 /* See Bluetooth Assigned Numbers document - SDP section, to get the values of UUIDs 42 * for the various services. 43 * 44 * The following 128 bit values are calculated as: 45 * uuid * 2^96 + BASE_UUID 46 */ 47 48 /** @hide */ 49 @NonNull 50 @SystemApi 51 public static final ParcelUuid A2DP_SINK = 52 ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB"); 53 /** @hide */ 54 @NonNull 55 @SystemApi 56 public static final ParcelUuid A2DP_SOURCE = 57 ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB"); 58 /** @hide */ 59 @NonNull 60 @SystemApi 61 public static final ParcelUuid ADV_AUDIO_DIST = 62 ParcelUuid.fromString("0000110D-0000-1000-8000-00805F9B34FB"); 63 /** @hide */ 64 @NonNull 65 @SystemApi 66 public static final ParcelUuid HSP = 67 ParcelUuid.fromString("00001108-0000-1000-8000-00805F9B34FB"); 68 /** @hide */ 69 @NonNull 70 @SystemApi 71 public static final ParcelUuid HSP_AG = 72 ParcelUuid.fromString("00001112-0000-1000-8000-00805F9B34FB"); 73 /** @hide */ 74 @NonNull 75 @SystemApi 76 public static final ParcelUuid HFP = 77 ParcelUuid.fromString("0000111E-0000-1000-8000-00805F9B34FB"); 78 /** @hide */ 79 @NonNull 80 @SystemApi 81 public static final ParcelUuid HFP_AG = 82 ParcelUuid.fromString("0000111F-0000-1000-8000-00805F9B34FB"); 83 /** @hide */ 84 @NonNull 85 @SystemApi 86 public static final ParcelUuid AVRCP_CONTROLLER = 87 ParcelUuid.fromString("0000110E-0000-1000-8000-00805F9B34FB"); 88 /** @hide */ 89 @NonNull 90 @SystemApi 91 public static final ParcelUuid AVRCP_TARGET = 92 ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB"); 93 /** @hide */ 94 @NonNull 95 @SystemApi 96 public static final ParcelUuid OBEX_OBJECT_PUSH = 97 ParcelUuid.fromString("00001105-0000-1000-8000-00805f9b34fb"); 98 /** @hide */ 99 @NonNull 100 @SystemApi 101 public static final ParcelUuid HID = 102 ParcelUuid.fromString("00001124-0000-1000-8000-00805f9b34fb"); 103 /** @hide */ 104 @NonNull 105 @SystemApi 106 public static final ParcelUuid HOGP = 107 ParcelUuid.fromString("00001812-0000-1000-8000-00805f9b34fb"); 108 /** @hide */ 109 @NonNull 110 @SystemApi 111 public static final ParcelUuid PANU = 112 ParcelUuid.fromString("00001115-0000-1000-8000-00805F9B34FB"); 113 /** @hide */ 114 @NonNull 115 @SystemApi 116 public static final ParcelUuid NAP = 117 ParcelUuid.fromString("00001116-0000-1000-8000-00805F9B34FB"); 118 /** @hide */ 119 @NonNull 120 @SystemApi 121 public static final ParcelUuid BNEP = 122 ParcelUuid.fromString("0000000f-0000-1000-8000-00805F9B34FB"); 123 /** @hide */ 124 @NonNull 125 @SystemApi 126 public static final ParcelUuid PBAP_PCE = 127 ParcelUuid.fromString("0000112e-0000-1000-8000-00805F9B34FB"); 128 /** @hide */ 129 @NonNull 130 @SystemApi 131 public static final ParcelUuid PBAP_PSE = 132 ParcelUuid.fromString("0000112f-0000-1000-8000-00805F9B34FB"); 133 /** @hide */ 134 @NonNull 135 @SystemApi 136 public static final ParcelUuid MAP = 137 ParcelUuid.fromString("00001134-0000-1000-8000-00805F9B34FB"); 138 /** @hide */ 139 @NonNull 140 @SystemApi 141 public static final ParcelUuid MNS = 142 ParcelUuid.fromString("00001133-0000-1000-8000-00805F9B34FB"); 143 /** @hide */ 144 @NonNull 145 @SystemApi 146 public static final ParcelUuid MAS = 147 ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB"); 148 /** @hide */ 149 @NonNull 150 @SystemApi 151 public static final ParcelUuid SAP = 152 ParcelUuid.fromString("0000112D-0000-1000-8000-00805F9B34FB"); 153 /** @hide */ 154 @NonNull 155 @SystemApi 156 public static final ParcelUuid HEARING_AID = 157 ParcelUuid.fromString("0000FDF0-0000-1000-8000-00805f9b34fb"); 158 /** Placeholder until specification is released 159 * @hide */ 160 @NonNull 161 @SystemApi 162 public static final ParcelUuid LE_AUDIO = 163 ParcelUuid.fromString("EEEEEEEE-EEEE-EEEE-EEEE-EEEEEEEEEEEE"); 164 /** @hide */ 165 @NonNull 166 @SystemApi 167 public static final ParcelUuid DIP = 168 ParcelUuid.fromString("00001200-0000-1000-8000-00805F9B34FB"); 169 /** @hide */ 170 @NonNull 171 @SystemApi 172 public static final ParcelUuid VOLUME_CONTROL = 173 ParcelUuid.fromString("00001844-0000-1000-8000-00805F9B34FB"); 174 /** @hide */ 175 @NonNull 176 @SystemApi 177 public static final ParcelUuid BASE_UUID = 178 ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB"); 179 180 /** 181 * Length of bytes for 16 bit UUID 182 * 183 * @hide 184 */ 185 @SystemApi 186 public static final int UUID_BYTES_16_BIT = 2; 187 /** 188 * Length of bytes for 32 bit UUID 189 * 190 * @hide 191 */ 192 @SystemApi 193 public static final int UUID_BYTES_32_BIT = 4; 194 /** 195 * Length of bytes for 128 bit UUID 196 * 197 * @hide 198 */ 199 @SystemApi 200 public static final int UUID_BYTES_128_BIT = 16; 201 202 /** 203 * Returns true if there any common ParcelUuids in uuidA and uuidB. 204 * 205 * @param uuidA - List of ParcelUuids 206 * @param uuidB - List of ParcelUuids 207 * 208 * @hide 209 */ 210 @SystemApi containsAnyUuid(@ullable ParcelUuid[] uuidA, @Nullable ParcelUuid[] uuidB)211 public static boolean containsAnyUuid(@Nullable ParcelUuid[] uuidA, 212 @Nullable ParcelUuid[] uuidB) { 213 if (uuidA == null && uuidB == null) return true; 214 215 if (uuidA == null) { 216 return uuidB.length == 0; 217 } 218 219 if (uuidB == null) { 220 return uuidA.length == 0; 221 } 222 223 HashSet<ParcelUuid> uuidSet = new HashSet<ParcelUuid>(Arrays.asList(uuidA)); 224 for (ParcelUuid uuid : uuidB) { 225 if (uuidSet.contains(uuid)) return true; 226 } 227 return false; 228 } 229 230 /** 231 * Extract the Service Identifier or the actual uuid from the Parcel Uuid. 232 * For example, if 0000110B-0000-1000-8000-00805F9B34FB is the parcel Uuid, 233 * this function will return 110B 234 * 235 * @param parcelUuid 236 * @return the service identifier. 237 */ getServiceIdentifierFromParcelUuid(ParcelUuid parcelUuid)238 private static int getServiceIdentifierFromParcelUuid(ParcelUuid parcelUuid) { 239 UUID uuid = parcelUuid.getUuid(); 240 long value = (uuid.getMostSignificantBits() & 0xFFFFFFFF00000000L) >>> 32; 241 return (int) value; 242 } 243 244 /** 245 * Parse UUID from bytes. The {@code uuidBytes} can represent a 16-bit, 32-bit or 128-bit UUID, 246 * but the returned UUID is always in 128-bit format. 247 * Note UUID is little endian in Bluetooth. 248 * 249 * @param uuidBytes Byte representation of uuid. 250 * @return {@link ParcelUuid} parsed from bytes. 251 * @throws IllegalArgumentException If the {@code uuidBytes} cannot be parsed. 252 * 253 * @hide 254 */ 255 @NonNull 256 @SystemApi parseUuidFrom(@ullable byte[] uuidBytes)257 public static ParcelUuid parseUuidFrom(@Nullable byte[] uuidBytes) { 258 if (uuidBytes == null) { 259 throw new IllegalArgumentException("uuidBytes cannot be null"); 260 } 261 int length = uuidBytes.length; 262 if (length != UUID_BYTES_16_BIT && length != UUID_BYTES_32_BIT 263 && length != UUID_BYTES_128_BIT) { 264 throw new IllegalArgumentException("uuidBytes length invalid - " + length); 265 } 266 267 // Construct a 128 bit UUID. 268 if (length == UUID_BYTES_128_BIT) { 269 ByteBuffer buf = ByteBuffer.wrap(uuidBytes).order(ByteOrder.LITTLE_ENDIAN); 270 long msb = buf.getLong(8); 271 long lsb = buf.getLong(0); 272 return new ParcelUuid(new UUID(msb, lsb)); 273 } 274 275 // For 16 bit and 32 bit UUID we need to convert them to 128 bit value. 276 // 128_bit_value = uuid * 2^96 + BASE_UUID 277 long shortUuid; 278 if (length == UUID_BYTES_16_BIT) { 279 shortUuid = uuidBytes[0] & 0xFF; 280 shortUuid += (uuidBytes[1] & 0xFF) << 8; 281 } else { 282 shortUuid = uuidBytes[0] & 0xFF; 283 shortUuid += (uuidBytes[1] & 0xFF) << 8; 284 shortUuid += (uuidBytes[2] & 0xFF) << 16; 285 shortUuid += (uuidBytes[3] & 0xFF) << 24; 286 } 287 long msb = BASE_UUID.getUuid().getMostSignificantBits() + (shortUuid << 32); 288 long lsb = BASE_UUID.getUuid().getLeastSignificantBits(); 289 return new ParcelUuid(new UUID(msb, lsb)); 290 } 291 292 /** 293 * Parse UUID to bytes. The returned value is shortest representation, a 16-bit, 32-bit or 294 * 128-bit UUID, Note returned value is little endian (Bluetooth). 295 * 296 * @param uuid uuid to parse. 297 * @return shortest representation of {@code uuid} as bytes. 298 * @throws IllegalArgumentException If the {@code uuid} is null. 299 * 300 * @hide 301 */ uuidToBytes(ParcelUuid uuid)302 public static byte[] uuidToBytes(ParcelUuid uuid) { 303 if (uuid == null) { 304 throw new IllegalArgumentException("uuid cannot be null"); 305 } 306 307 if (is16BitUuid(uuid)) { 308 byte[] uuidBytes = new byte[UUID_BYTES_16_BIT]; 309 int uuidVal = getServiceIdentifierFromParcelUuid(uuid); 310 uuidBytes[0] = (byte) (uuidVal & 0xFF); 311 uuidBytes[1] = (byte) ((uuidVal & 0xFF00) >> 8); 312 return uuidBytes; 313 } 314 315 if (is32BitUuid(uuid)) { 316 byte[] uuidBytes = new byte[UUID_BYTES_32_BIT]; 317 int uuidVal = getServiceIdentifierFromParcelUuid(uuid); 318 uuidBytes[0] = (byte) (uuidVal & 0xFF); 319 uuidBytes[1] = (byte) ((uuidVal & 0xFF00) >> 8); 320 uuidBytes[2] = (byte) ((uuidVal & 0xFF0000) >> 16); 321 uuidBytes[3] = (byte) ((uuidVal & 0xFF000000) >> 24); 322 return uuidBytes; 323 } 324 325 // Construct a 128 bit UUID. 326 long msb = uuid.getUuid().getMostSignificantBits(); 327 long lsb = uuid.getUuid().getLeastSignificantBits(); 328 329 byte[] uuidBytes = new byte[UUID_BYTES_128_BIT]; 330 ByteBuffer buf = ByteBuffer.wrap(uuidBytes).order(ByteOrder.LITTLE_ENDIAN); 331 buf.putLong(8, msb); 332 buf.putLong(0, lsb); 333 return uuidBytes; 334 } 335 336 /** 337 * Check whether the given parcelUuid can be converted to 16 bit bluetooth uuid. 338 * 339 * @param parcelUuid 340 * @return true if the parcelUuid can be converted to 16 bit uuid, false otherwise. 341 * 342 * @hide 343 */ 344 @UnsupportedAppUsage is16BitUuid(ParcelUuid parcelUuid)345 public static boolean is16BitUuid(ParcelUuid parcelUuid) { 346 UUID uuid = parcelUuid.getUuid(); 347 if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) { 348 return false; 349 } 350 return ((uuid.getMostSignificantBits() & 0xFFFF0000FFFFFFFFL) == 0x1000L); 351 } 352 353 354 /** 355 * Check whether the given parcelUuid can be converted to 32 bit bluetooth uuid. 356 * 357 * @param parcelUuid 358 * @return true if the parcelUuid can be converted to 32 bit uuid, false otherwise. 359 * 360 * @hide 361 */ 362 @UnsupportedAppUsage is32BitUuid(ParcelUuid parcelUuid)363 public static boolean is32BitUuid(ParcelUuid parcelUuid) { 364 UUID uuid = parcelUuid.getUuid(); 365 if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) { 366 return false; 367 } 368 if (is16BitUuid(parcelUuid)) { 369 return false; 370 } 371 return ((uuid.getMostSignificantBits() & 0xFFFFFFFFL) == 0x1000L); 372 } 373 BluetoothUuid()374 private BluetoothUuid() {} 375 } 376