blob: 5bfc54d267caaa200a6877eb68de0d647247eab1 [file] [log] [blame]
Jaikumar Ganesh879bf5b2009-05-05 22:26:12 -07001/*
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
17package android.bluetooth;
18
Nick Pelly03759e52009-09-28 12:33:17 -070019import android.os.ParcelUuid;
20
Wei Wangc3868042014-04-15 14:57:16 -070021import java.nio.ByteBuffer;
22import java.nio.ByteOrder;
Jaikumar Ganesh55a0c032009-09-16 12:30:02 -070023import java.util.Arrays;
24import java.util.HashSet;
Jaikumar Ganesh166a60e2010-12-10 12:48:58 -080025import java.util.UUID;
Jaikumar Ganesh879bf5b2009-05-05 22:26:12 -070026
27/**
Jack He910201b2017-08-22 16:06:54 -070028 * Static helper methods and constants to decode the ParcelUuid of remote devices.
29 *
30 * @hide
31 */
Jaikumar Ganesh879bf5b2009-05-05 22:26:12 -070032public final class BluetoothUuid {
33
34 /* See Bluetooth Assigned Numbers document - SDP section, to get the values of UUIDs
35 * for the various services.
36 *
37 * The following 128 bit values are calculated as:
38 * uuid * 2^96 + BASE_UUID
39 */
Jaikumar Ganesh55a0c032009-09-16 12:30:02 -070040 public static final ParcelUuid AudioSink =
41 ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB");
42 public static final ParcelUuid AudioSource =
43 ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB");
44 public static final ParcelUuid AdvAudioDist =
45 ParcelUuid.fromString("0000110D-0000-1000-8000-00805F9B34FB");
46 public static final ParcelUuid HSP =
47 ParcelUuid.fromString("00001108-0000-1000-8000-00805F9B34FB");
Jaikumar Ganesh166a60e2010-12-10 12:48:58 -080048 public static final ParcelUuid HSP_AG =
49 ParcelUuid.fromString("00001112-0000-1000-8000-00805F9B34FB");
Jaikumar Ganesh55a0c032009-09-16 12:30:02 -070050 public static final ParcelUuid Handsfree =
51 ParcelUuid.fromString("0000111E-0000-1000-8000-00805F9B34FB");
Jaikumar Ganesh166a60e2010-12-10 12:48:58 -080052 public static final ParcelUuid Handsfree_AG =
53 ParcelUuid.fromString("0000111F-0000-1000-8000-00805F9B34FB");
Jaikumar Ganesh55a0c032009-09-16 12:30:02 -070054 public static final ParcelUuid AvrcpController =
55 ParcelUuid.fromString("0000110E-0000-1000-8000-00805F9B34FB");
56 public static final ParcelUuid AvrcpTarget =
57 ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB");
58 public static final ParcelUuid ObexObjectPush =
59 ParcelUuid.fromString("00001105-0000-1000-8000-00805f9b34fb");
Jaikumar Ganesh5d0b83e2010-06-04 10:23:03 -070060 public static final ParcelUuid Hid =
Adam Powell026e8572010-06-21 16:23:42 -070061 ParcelUuid.fromString("00001124-0000-1000-8000-00805f9b34fb");
Andre Eisenbach1f0c3da2013-03-07 18:07:35 -080062 public static final ParcelUuid Hogp =
63 ParcelUuid.fromString("00001812-0000-1000-8000-00805f9b34fb");
Danica Chang41f1a092010-08-11 14:54:43 -070064 public static final ParcelUuid PANU =
65 ParcelUuid.fromString("00001115-0000-1000-8000-00805F9B34FB");
66 public static final ParcelUuid NAP =
67 ParcelUuid.fromString("00001116-0000-1000-8000-00805F9B34FB");
Jaikumar Ganesh43d545d2010-08-23 18:32:03 -070068 public static final ParcelUuid BNEP =
69 ParcelUuid.fromString("0000000f-0000-1000-8000-00805F9B34FB");
Matthew Xie947b3922014-11-20 21:53:26 -080070 public static final ParcelUuid PBAP_PCE =
71 ParcelUuid.fromString("0000112e-0000-1000-8000-00805F9B34FB");
Jaikumar Ganesh166a60e2010-12-10 12:48:58 -080072 public static final ParcelUuid PBAP_PSE =
73 ParcelUuid.fromString("0000112f-0000-1000-8000-00805F9B34FB");
Matthew Xiece145222013-07-18 17:31:50 -070074 public static final ParcelUuid MAP =
Kim Schulz6816ee22013-08-22 11:18:02 +020075 ParcelUuid.fromString("00001134-0000-1000-8000-00805F9B34FB");
Matthew Xiece145222013-07-18 17:31:50 -070076 public static final ParcelUuid MNS =
77 ParcelUuid.fromString("00001133-0000-1000-8000-00805F9B34FB");
Kim Schulz6816ee22013-08-22 11:18:02 +020078 public static final ParcelUuid MAS =
79 ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB");
Jack He910201b2017-08-22 16:06:54 -070080 public static final ParcelUuid SAP =
Casper Bonded8355fb2015-03-19 10:36:45 +010081 ParcelUuid.fromString("0000112D-0000-1000-8000-00805F9B34FB");
Jack He910201b2017-08-22 16:06:54 -070082
Wei Wang2f7544c2013-10-29 21:05:37 -070083 public static final ParcelUuid BASE_UUID =
84 ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
85
Wei Wangc3868042014-04-15 14:57:16 -070086 /** Length of bytes for 16 bit UUID */
87 public static final int UUID_BYTES_16_BIT = 2;
88 /** Length of bytes for 32 bit UUID */
89 public static final int UUID_BYTES_32_BIT = 4;
90 /** Length of bytes for 128 bit UUID */
91 public static final int UUID_BYTES_128_BIT = 16;
Jaikumar Ganesh879bf5b2009-05-05 22:26:12 -070092
Nick Pellyee1402d2009-10-02 20:34:18 -070093 public static final ParcelUuid[] RESERVED_UUIDS = {
Jack He910201b2017-08-22 16:06:54 -070094 AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget,
95 ObexObjectPush, PANU, NAP, MAP, MNS, MAS, SAP};
Nick Pellyee1402d2009-10-02 20:34:18 -070096
Jaikumar Ganesh55a0c032009-09-16 12:30:02 -070097 public static boolean isAudioSource(ParcelUuid uuid) {
Jaikumar Ganesh879bf5b2009-05-05 22:26:12 -070098 return uuid.equals(AudioSource);
99 }
100
Jaikumar Ganesh55a0c032009-09-16 12:30:02 -0700101 public static boolean isAudioSink(ParcelUuid uuid) {
Jaikumar Ganesh879bf5b2009-05-05 22:26:12 -0700102 return uuid.equals(AudioSink);
103 }
104
Jaikumar Ganesh55a0c032009-09-16 12:30:02 -0700105 public static boolean isAdvAudioDist(ParcelUuid uuid) {
Jaikumar Ganesh879bf5b2009-05-05 22:26:12 -0700106 return uuid.equals(AdvAudioDist);
107 }
108
Jaikumar Ganesh55a0c032009-09-16 12:30:02 -0700109 public static boolean isHandsfree(ParcelUuid uuid) {
Jaikumar Ganesh4eb5ccc2009-07-14 12:21:26 -0700110 return uuid.equals(Handsfree);
Jaikumar Ganesh879bf5b2009-05-05 22:26:12 -0700111 }
112
Jaikumar Ganesh55a0c032009-09-16 12:30:02 -0700113 public static boolean isHeadset(ParcelUuid uuid) {
Jaikumar Ganesh671065d2009-07-30 13:32:25 -0700114 return uuid.equals(HSP);
115 }
116
Jaikumar Ganesh55a0c032009-09-16 12:30:02 -0700117 public static boolean isAvrcpController(ParcelUuid uuid) {
Jaikumar Ganesh671065d2009-07-30 13:32:25 -0700118 return uuid.equals(AvrcpController);
Jaikumar Ganesh879bf5b2009-05-05 22:26:12 -0700119 }
Jackson Fan0d538762009-08-19 21:01:29 +0800120
Jaikumar Ganesh55a0c032009-09-16 12:30:02 -0700121 public static boolean isAvrcpTarget(ParcelUuid uuid) {
Jackson Fan0d538762009-08-19 21:01:29 +0800122 return uuid.equals(AvrcpTarget);
123 }
Jaikumar Ganesh55a0c032009-09-16 12:30:02 -0700124
Jaikumar Ganesh5d0b83e2010-06-04 10:23:03 -0700125 public static boolean isInputDevice(ParcelUuid uuid) {
126 return uuid.equals(Hid);
127 }
128
Jaikumar Ganesh43d545d2010-08-23 18:32:03 -0700129 public static boolean isPanu(ParcelUuid uuid) {
Danica Chang41f1a092010-08-11 14:54:43 -0700130 return uuid.equals(PANU);
131 }
132
Jaikumar Ganesh43d545d2010-08-23 18:32:03 -0700133 public static boolean isNap(ParcelUuid uuid) {
Danica Chang41f1a092010-08-11 14:54:43 -0700134 return uuid.equals(NAP);
135 }
Jaikumar Ganesh43d545d2010-08-23 18:32:03 -0700136
137 public static boolean isBnep(ParcelUuid uuid) {
138 return uuid.equals(BNEP);
139 }
Jack He910201b2017-08-22 16:06:54 -0700140
Matthew Xiece145222013-07-18 17:31:50 -0700141 public static boolean isMap(ParcelUuid uuid) {
142 return uuid.equals(MAP);
143 }
Jack He910201b2017-08-22 16:06:54 -0700144
Matthew Xiece145222013-07-18 17:31:50 -0700145 public static boolean isMns(ParcelUuid uuid) {
146 return uuid.equals(MNS);
147 }
Jack He910201b2017-08-22 16:06:54 -0700148
Kim Schulz6816ee22013-08-22 11:18:02 +0200149 public static boolean isMas(ParcelUuid uuid) {
150 return uuid.equals(MAS);
151 }
Jack He910201b2017-08-22 16:06:54 -0700152
Casper Bonded8355fb2015-03-19 10:36:45 +0100153 public static boolean isSap(ParcelUuid uuid) {
154 return uuid.equals(SAP);
155 }
Matthew Xiece145222013-07-18 17:31:50 -0700156
Jaikumar Ganesh55a0c032009-09-16 12:30:02 -0700157 /**
158 * Returns true if ParcelUuid is present in uuidArray
159 *
160 * @param uuidArray - Array of ParcelUuids
161 * @param uuid
162 */
163 public static boolean isUuidPresent(ParcelUuid[] uuidArray, ParcelUuid uuid) {
Jack He910201b2017-08-22 16:06:54 -0700164 if ((uuidArray == null || uuidArray.length == 0) && uuid == null) {
Jaikumar Ganesh391e8a72009-09-21 12:48:51 -0700165 return true;
Jack He910201b2017-08-22 16:06:54 -0700166 }
Jaikumar Ganesh391e8a72009-09-21 12:48:51 -0700167
Jack He910201b2017-08-22 16:06:54 -0700168 if (uuidArray == null) {
Jaikumar Ganesh391e8a72009-09-21 12:48:51 -0700169 return false;
Jack He910201b2017-08-22 16:06:54 -0700170 }
Jaikumar Ganesh391e8a72009-09-21 12:48:51 -0700171
Jack He910201b2017-08-22 16:06:54 -0700172 for (ParcelUuid element : uuidArray) {
Jaikumar Ganesh55a0c032009-09-16 12:30:02 -0700173 if (element.equals(uuid)) return true;
174 }
175 return false;
176 }
177
178 /**
179 * Returns true if there any common ParcelUuids in uuidA and uuidB.
180 *
181 * @param uuidA - List of ParcelUuids
182 * @param uuidB - List of ParcelUuids
Jaikumar Ganesh55a0c032009-09-16 12:30:02 -0700183 */
184 public static boolean containsAnyUuid(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
185 if (uuidA == null && uuidB == null) return true;
Jaikumar Ganesh97c84ce2009-09-16 17:50:52 -0700186
187 if (uuidA == null) {
Jack He9e045d22017-08-22 21:21:23 -0700188 return uuidB.length == 0;
Jaikumar Ganesh97c84ce2009-09-16 17:50:52 -0700189 }
190
191 if (uuidB == null) {
Jack He9e045d22017-08-22 21:21:23 -0700192 return uuidA.length == 0;
Jaikumar Ganesh97c84ce2009-09-16 17:50:52 -0700193 }
Jaikumar Ganesh55a0c032009-09-16 12:30:02 -0700194
Jack He910201b2017-08-22 16:06:54 -0700195 HashSet<ParcelUuid> uuidSet = new HashSet<ParcelUuid>(Arrays.asList(uuidA));
196 for (ParcelUuid uuid : uuidB) {
Jaikumar Ganesh55a0c032009-09-16 12:30:02 -0700197 if (uuidSet.contains(uuid)) return true;
198 }
199 return false;
200 }
201
202 /**
203 * Returns true if all the ParcelUuids in ParcelUuidB are present in
204 * ParcelUuidA
205 *
206 * @param uuidA - Array of ParcelUuidsA
207 * @param uuidB - Array of ParcelUuidsB
Jaikumar Ganesh55a0c032009-09-16 12:30:02 -0700208 */
209 public static boolean containsAllUuids(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
210 if (uuidA == null && uuidB == null) return true;
Jaikumar Ganesh97c84ce2009-09-16 17:50:52 -0700211
212 if (uuidA == null) {
Jack He9e045d22017-08-22 21:21:23 -0700213 return uuidB.length == 0;
Jaikumar Ganesh97c84ce2009-09-16 17:50:52 -0700214 }
215
216 if (uuidB == null) return true;
Jaikumar Ganesh55a0c032009-09-16 12:30:02 -0700217
Jack He910201b2017-08-22 16:06:54 -0700218 HashSet<ParcelUuid> uuidSet = new HashSet<ParcelUuid>(Arrays.asList(uuidA));
219 for (ParcelUuid uuid : uuidB) {
Jaikumar Ganesh55a0c032009-09-16 12:30:02 -0700220 if (!uuidSet.contains(uuid)) return false;
221 }
222 return true;
223 }
224
Jaikumar Ganesh166a60e2010-12-10 12:48:58 -0800225 /**
226 * Extract the Service Identifier or the actual uuid from the Parcel Uuid.
227 * For example, if 0000110B-0000-1000-8000-00805F9B34FB is the parcel Uuid,
228 * this function will return 110B
Jack He910201b2017-08-22 16:06:54 -0700229 *
Jaikumar Ganesh166a60e2010-12-10 12:48:58 -0800230 * @param parcelUuid
231 * @return the service identifier.
232 */
233 public static int getServiceIdentifierFromParcelUuid(ParcelUuid parcelUuid) {
234 UUID uuid = parcelUuid.getUuid();
235 long value = (uuid.getMostSignificantBits() & 0x0000FFFF00000000L) >>> 32;
Jack He910201b2017-08-22 16:06:54 -0700236 return (int) value;
Jaikumar Ganesh166a60e2010-12-10 12:48:58 -0800237 }
Wei Wang2f7544c2013-10-29 21:05:37 -0700238
239 /**
Wei Wangc3868042014-04-15 14:57:16 -0700240 * Parse UUID from bytes. The {@code uuidBytes} can represent a 16-bit, 32-bit or 128-bit UUID,
241 * but the returned UUID is always in 128-bit format.
242 * Note UUID is little endian in Bluetooth.
243 *
244 * @param uuidBytes Byte representation of uuid.
245 * @return {@link ParcelUuid} parsed from bytes.
246 * @throws IllegalArgumentException If the {@code uuidBytes} cannot be parsed.
247 */
248 public static ParcelUuid parseUuidFrom(byte[] uuidBytes) {
249 if (uuidBytes == null) {
250 throw new IllegalArgumentException("uuidBytes cannot be null");
251 }
252 int length = uuidBytes.length;
Jack He9e045d22017-08-22 21:21:23 -0700253 if (length != UUID_BYTES_16_BIT && length != UUID_BYTES_32_BIT
254 && length != UUID_BYTES_128_BIT) {
Wei Wangc3868042014-04-15 14:57:16 -0700255 throw new IllegalArgumentException("uuidBytes length invalid - " + length);
256 }
257
258 // Construct a 128 bit UUID.
259 if (length == UUID_BYTES_128_BIT) {
260 ByteBuffer buf = ByteBuffer.wrap(uuidBytes).order(ByteOrder.LITTLE_ENDIAN);
261 long msb = buf.getLong(8);
262 long lsb = buf.getLong(0);
263 return new ParcelUuid(new UUID(msb, lsb));
264 }
265
266 // For 16 bit and 32 bit UUID we need to convert them to 128 bit value.
267 // 128_bit_value = uuid * 2^96 + BASE_UUID
268 long shortUuid;
269 if (length == UUID_BYTES_16_BIT) {
270 shortUuid = uuidBytes[0] & 0xFF;
271 shortUuid += (uuidBytes[1] & 0xFF) << 8;
272 } else {
Jack He910201b2017-08-22 16:06:54 -0700273 shortUuid = uuidBytes[0] & 0xFF;
Wei Wangc3868042014-04-15 14:57:16 -0700274 shortUuid += (uuidBytes[1] & 0xFF) << 8;
275 shortUuid += (uuidBytes[2] & 0xFF) << 16;
276 shortUuid += (uuidBytes[3] & 0xFF) << 24;
277 }
278 long msb = BASE_UUID.getUuid().getMostSignificantBits() + (shortUuid << 32);
279 long lsb = BASE_UUID.getUuid().getLeastSignificantBits();
280 return new ParcelUuid(new UUID(msb, lsb));
281 }
282
283 /**
Jack He910201b2017-08-22 16:06:54 -0700284 * Parse UUID to bytes. The returned value is shortest representation, a 16-bit, 32-bit or
285 * 128-bit UUID, Note returned value is little endian (Bluetooth).
Jakub Pawlowski4648fc32016-10-24 13:56:54 -0700286 *
287 * @param uuid uuid to parse.
288 * @return shortest representation of {@code uuid} as bytes.
289 * @throws IllegalArgumentException If the {@code uuid} is null.
290 */
291 public static byte[] uuidToBytes(ParcelUuid uuid) {
292 if (uuid == null) {
293 throw new IllegalArgumentException("uuid cannot be null");
294 }
295
296 if (is16BitUuid(uuid)) {
297 byte[] uuidBytes = new byte[UUID_BYTES_16_BIT];
298 int uuidVal = getServiceIdentifierFromParcelUuid(uuid);
Jack He910201b2017-08-22 16:06:54 -0700299 uuidBytes[0] = (byte) (uuidVal & 0xFF);
300 uuidBytes[1] = (byte) ((uuidVal & 0xFF00) >> 8);
Jakub Pawlowski4648fc32016-10-24 13:56:54 -0700301 return uuidBytes;
302 }
303
304 if (is32BitUuid(uuid)) {
305 byte[] uuidBytes = new byte[UUID_BYTES_32_BIT];
306 int uuidVal = getServiceIdentifierFromParcelUuid(uuid);
Jack He910201b2017-08-22 16:06:54 -0700307 uuidBytes[0] = (byte) (uuidVal & 0xFF);
308 uuidBytes[1] = (byte) ((uuidVal & 0xFF00) >> 8);
309 uuidBytes[2] = (byte) ((uuidVal & 0xFF0000) >> 16);
310 uuidBytes[3] = (byte) ((uuidVal & 0xFF000000) >> 24);
Jakub Pawlowski4648fc32016-10-24 13:56:54 -0700311 return uuidBytes;
312 }
313
314 // Construct a 128 bit UUID.
315 long msb = uuid.getUuid().getMostSignificantBits();
316 long lsb = uuid.getUuid().getLeastSignificantBits();
317
318 byte[] uuidBytes = new byte[UUID_BYTES_128_BIT];
319 ByteBuffer buf = ByteBuffer.wrap(uuidBytes).order(ByteOrder.LITTLE_ENDIAN);
320 buf.putLong(8, msb);
321 buf.putLong(0, lsb);
322 return uuidBytes;
323 }
324
325 /**
Wei Wang2f7544c2013-10-29 21:05:37 -0700326 * Check whether the given parcelUuid can be converted to 16 bit bluetooth uuid.
Wei Wangc3868042014-04-15 14:57:16 -0700327 *
Wei Wang2f7544c2013-10-29 21:05:37 -0700328 * @param parcelUuid
329 * @return true if the parcelUuid can be converted to 16 bit uuid, false otherwise.
330 */
Wei Wanga8f5c7b2014-05-07 14:54:43 -0700331 public static boolean is16BitUuid(ParcelUuid parcelUuid) {
Wei Wangc3868042014-04-15 14:57:16 -0700332 UUID uuid = parcelUuid.getUuid();
333 if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) {
334 return false;
335 }
336 return ((uuid.getMostSignificantBits() & 0xFFFF0000FFFFFFFFL) == 0x1000L);
Wei Wang2f7544c2013-10-29 21:05:37 -0700337 }
Wei Wanga8f5c7b2014-05-07 14:54:43 -0700338
339
340 /**
341 * Check whether the given parcelUuid can be converted to 32 bit bluetooth uuid.
342 *
343 * @param parcelUuid
344 * @return true if the parcelUuid can be converted to 32 bit uuid, false otherwise.
345 */
346 public static boolean is32BitUuid(ParcelUuid parcelUuid) {
347 UUID uuid = parcelUuid.getUuid();
348 if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) {
349 return false;
350 }
351 if (is16BitUuid(parcelUuid)) {
352 return false;
353 }
354 return ((uuid.getMostSignificantBits() & 0xFFFFFFFFL) == 0x1000L);
355 }
Jaikumar Ganesh879bf5b2009-05-05 22:26:12 -0700356}