1 /**
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5  * except in compliance with the License. You may obtain a copy of the License at
6  *
7  * <p>http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * <p>Unless required by applicable law or agreed to in writing, software distributed under the
10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11  * express or implied. See the License for the specific language governing permissions and
12  * limitations under the License.
13  */
14 package android.bluetooth;
15 
16 import static java.util.Objects.requireNonNull;
17 
18 import android.annotation.IntDef;
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.SystemApi;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 
25 import java.lang.annotation.Retention;
26 import java.lang.annotation.RetentionPolicy;
27 
28 /**
29  * Out Of Band Data for Bluetooth device pairing.
30  *
31  * <p>This object represents optional data obtained from a remote device through an out-of-band
32  * channel (eg. NFC, QR).
33  *
34  * <p>References: <a
35  * href="https://members.nfc-forum.org//apps/group_public/download.php/24620/NFCForum-AD-BTSSP_1_1.pdf">NFC
36  * AD Forum SSP 1.1 (AD)</a>
37  *
38  * <p>Core Specification Supplement (CSS) V9
39  *
40  * <p>There are several BR/EDR Examples
41  *
42  * <p>Negotiated Handover: Bluetooth Carrier Configuration Record: - OOB Data Length - Device
43  * Address - Class of Device - Simple Pairing Hash C - Simple Pairing Randomizer R - Service Class
44  * UUID - Bluetooth Local Name
45  *
46  * <p>Static Handover: Bluetooth Carrier Configuration Record: - OOB Data Length - Device Address -
47  * Class of Device - Service Class UUID - Bluetooth Local Name
48  *
49  * <p>Simplified Tag Format for Single BT Carrier: Bluetooth OOB Data Record: - OOB Data Length -
50  * Device Address - Class of Device - Service Class UUID - Bluetooth Local Name
51  *
52  * @hide
53  */
54 @SystemApi
55 public final class OobData implements Parcelable {
56 
57     private static final String TAG = "OobData";
58 
59     /** The {@link OobData#mClassicLength} may be. (AD 3.1.1) (CSS 1.6.2) @hide */
60     @SystemApi public static final int OOB_LENGTH_OCTETS = 2;
61 
62     /**
63      * The length for the {@link OobData#mDeviceAddressWithType}(6) and Address Type(1). (AD 3.1.2)
64      * (CSS 1.6.2)
65      *
66      * @hide
67      */
68     @SystemApi public static final int DEVICE_ADDRESS_OCTETS = 7;
69 
70     /** The Class of Device is 3 octets. (AD 3.1.3) (CSS 1.6.2) @hide */
71     @SystemApi public static final int CLASS_OF_DEVICE_OCTETS = 3;
72 
73     /** The Confirmation data must be 16 octets. (AD 3.2.2) (CSS 1.6.2) @hide */
74     @SystemApi public static final int CONFIRMATION_OCTETS = 16;
75 
76     /** The Randomizer data must be 16 octets. (AD 3.2.3) (CSS 1.6.2) @hide */
77     @SystemApi public static final int RANDOMIZER_OCTETS = 16;
78 
79     /** The LE Device Role length is 1 octet. (AD 3.3.2) (CSS 1.17) @hide */
80     @SystemApi public static final int LE_DEVICE_ROLE_OCTETS = 1;
81 
82     /** The {@link OobData#mLeTemporaryKey} length. (3.4.1) @hide */
83     @SystemApi public static final int LE_TK_OCTETS = 16;
84 
85     /** The {@link OobData#mLeAppearance} length. (3.4.1) @hide */
86     @SystemApi public static final int LE_APPEARANCE_OCTETS = 2;
87 
88     /** The {@link OobData#mLeFlags} length. (3.4.1) @hide */
89     @SystemApi public static final int LE_DEVICE_FLAG_OCTETS = 1; // 1 octet to hold the 0-4 value.
90 
91     // Le Roles
92     /** @hide */
93     @Retention(RetentionPolicy.SOURCE)
94     @IntDef(
95             prefix = {"LE_DEVICE_ROLE_"},
96             value = {
97                 LE_DEVICE_ROLE_PERIPHERAL_ONLY,
98                 LE_DEVICE_ROLE_CENTRAL_ONLY,
99                 LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL,
100                 LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL
101             })
102     public @interface LeRole {}
103 
104     /** @hide */
105     @SystemApi public static final int LE_DEVICE_ROLE_PERIPHERAL_ONLY = 0x00;
106 
107     /** @hide */
108     @SystemApi public static final int LE_DEVICE_ROLE_CENTRAL_ONLY = 0x01;
109 
110     /** @hide */
111     @SystemApi public static final int LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL = 0x02;
112 
113     /** @hide */
114     @SystemApi public static final int LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL = 0x03;
115 
116     // Le Flags
117     /** @hide */
118     @Retention(RetentionPolicy.SOURCE)
119     @IntDef(
120             prefix = {"LE_FLAG_"},
121             value = {
122                 LE_FLAG_LIMITED_DISCOVERY_MODE,
123                 LE_FLAG_GENERAL_DISCOVERY_MODE,
124                 LE_FLAG_BREDR_NOT_SUPPORTED,
125                 LE_FLAG_SIMULTANEOUS_CONTROLLER,
126                 LE_FLAG_SIMULTANEOUS_HOST
127             })
128     public @interface LeFlag {}
129 
130     /** @hide */
131     @SystemApi public static final int LE_FLAG_LIMITED_DISCOVERY_MODE = 0x00;
132 
133     /** @hide */
134     @SystemApi public static final int LE_FLAG_GENERAL_DISCOVERY_MODE = 0x01;
135 
136     /** @hide */
137     @SystemApi public static final int LE_FLAG_BREDR_NOT_SUPPORTED = 0x02;
138 
139     /** @hide */
140     @SystemApi public static final int LE_FLAG_SIMULTANEOUS_CONTROLLER = 0x03;
141 
142     /** @hide */
143     @SystemApi public static final int LE_FLAG_SIMULTANEOUS_HOST = 0x04;
144 
145     /**
146      * Builds an {@link OobData} object and validates that the required combination of values are
147      * present to create the LE specific OobData type.
148      *
149      * @hide
150      */
151     @SystemApi
152     public static final class LeBuilder {
153 
154         /**
155          * It is recommended that this Hash C is generated anew for each pairing.
156          *
157          * <p>It should be noted that on passive NFC this isn't possible as the data is static and
158          * immutable.
159          */
160         private byte[] mConfirmationHash = null;
161 
162         /**
163          * Optional, but adds more validity to the pairing.
164          *
165          * <p>If not present a value of 0 is assumed.
166          */
167         private byte[] mRandomizerHash =
168                 new byte[] {
169                     0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
170                     0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
171                 };
172 
173         /**
174          * The Bluetooth Device user-friendly name presented over Bluetooth Technology.
175          *
176          * <p>This is the name that may be displayed to the device user as part of the UI.
177          */
178         private byte[] mDeviceName = null;
179 
180         /**
181          * Sets the Bluetooth Device name to be used for UI purposes.
182          *
183          * <p>Optional attribute.
184          *
185          * @param deviceName byte array representing the name, may be 0 in length, not null.
186          * @return {@link OobData#ClassicBuilder}
187          * @throws NullPointerException if deviceName is null.
188          * @hide
189          */
190         @NonNull
191         @SystemApi
setDeviceName(@onNull byte[] deviceName)192         public LeBuilder setDeviceName(@NonNull byte[] deviceName) {
193             requireNonNull(deviceName);
194             this.mDeviceName = deviceName;
195             return this;
196         }
197 
198         /**
199          * The Bluetooth Device Address is the address to which the OOB data belongs.
200          *
201          * <p>The length MUST be {@link OobData#DEVICE_ADDRESS_OCTETS} octets.
202          *
203          * <p>Address is encoded in Little Endian order.
204          *
205          * <p>e.g. 00:01:02:03:04:05 would be x05x04x03x02x01x00
206          */
207         private final byte[] mDeviceAddressWithType;
208 
209         /**
210          * During an LE connection establishment, one must be in the Peripheral mode and the other
211          * in the Central role.
212          *
213          * <p>Possible Values: {@link LE_DEVICE_ROLE_PERIPHERAL_ONLY} Only Peripheral supported
214          * {@link LE_DEVICE_ROLE_CENTRAL_ONLY} Only Central supported {@link
215          * LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL} Central & Peripheral supported; Peripheral
216          * Preferred {@link LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL} Only peripheral supported; Central
217          * Preferred 0x04 - 0xFF Reserved
218          */
219         private final @LeRole int mLeDeviceRole;
220 
221         /**
222          * Temporary key value from the Security Manager.
223          *
224          * <p>Must be {@link LE_TK_OCTETS} in size
225          */
226         private byte[] mLeTemporaryKey = null;
227 
228         /**
229          * Defines the representation of the external appearance of the device.
230          *
231          * <p>For example, a mouse, remote control, or keyboard.
232          *
233          * <p>Used for visual on discovering device to represent icon/string/etc...
234          */
235         private byte[] mLeAppearance = null;
236 
237         /**
238          * Contains which discoverable mode to use, BR/EDR support and capability.
239          *
240          * <p>Possible LE Flags: {@link LE_FLAG_LIMITED_DISCOVERY_MODE} LE Limited Discoverable
241          * Mode. {@link LE_FLAG_GENERAL_DISCOVERY_MODE} LE General Discoverable Mode. {@link
242          * LE_FLAG_BREDR_NOT_SUPPORTED} BR/EDR Not Supported. Bit 37 of LMP Feature Mask
243          * Definitions. {@link LE_FLAG_SIMULTANEOUS_CONTROLLER} Simultaneous LE and BR/EDR to Same
244          * Device Capable (Controller). Bit 49 of LMP Feature Mask Definitions. {@link
245          * LE_FLAG_SIMULTANEOUS_HOST} Simultaneous LE and BR/EDR to Same Device Capable (Host). Bit
246          * 55 of LMP Feature Mask Definitions. <b>0x05- 0x07 Reserved</b>
247          */
248         private @LeFlag int mLeFlags = LE_FLAG_GENERAL_DISCOVERY_MODE; // Invalid default
249 
250         /**
251          * Main creation method for creating a LE version of {@link OobData}.
252          *
253          * <p>This object will allow the caller to call {@link LeBuilder#build()} to build the data
254          * object or add any option information to the builder.
255          *
256          * @param deviceAddressWithType the LE device address plus the address type (7 octets); not
257          *     null.
258          * @param leDeviceRole whether the device supports Peripheral, Central, Both including
259          *     preference; not null. (1 octet)
260          * @param confirmationHash Array consisting of {@link OobData#CONFIRMATION_OCTETS} octets of
261          *     data. Data is derived from controller/host stack and is required for pairing OOB.
262          *     <p>Possible Values: {@link LE_DEVICE_ROLE_PERIPHERAL_ONLY} Only Peripheral supported
263          *     {@link LE_DEVICE_ROLE_CENTRAL_ONLY} Only Central supported {@link
264          *     LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL} Central & Peripheral supported; Peripheral
265          *     Preferred {@link LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL} Only peripheral supported;
266          *     Central Preferred 0x04 - 0xFF Reserved
267          * @throws IllegalArgumentException if any of the values fail to be set.
268          * @throws NullPointerException if any argument is null.
269          * @hide
270          */
271         @SystemApi
LeBuilder( @onNull byte[] confirmationHash, @NonNull byte[] deviceAddressWithType, @LeRole int leDeviceRole)272         public LeBuilder(
273                 @NonNull byte[] confirmationHash,
274                 @NonNull byte[] deviceAddressWithType,
275                 @LeRole int leDeviceRole) {
276             requireNonNull(confirmationHash);
277             requireNonNull(deviceAddressWithType);
278             if (confirmationHash.length != OobData.CONFIRMATION_OCTETS) {
279                 throw new IllegalArgumentException(
280                         "confirmationHash must be "
281                                 + OobData.CONFIRMATION_OCTETS
282                                 + " octets in length.");
283             }
284             this.mConfirmationHash = confirmationHash;
285             if (deviceAddressWithType.length != OobData.DEVICE_ADDRESS_OCTETS) {
286                 throw new IllegalArgumentException(
287                         "confirmationHash must be "
288                                 + OobData.DEVICE_ADDRESS_OCTETS
289                                 + " octets in length.");
290             }
291             this.mDeviceAddressWithType = deviceAddressWithType;
292             if (leDeviceRole < LE_DEVICE_ROLE_PERIPHERAL_ONLY
293                     || leDeviceRole > LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL) {
294                 throw new IllegalArgumentException("leDeviceRole must be a valid value.");
295             }
296             this.mLeDeviceRole = leDeviceRole;
297         }
298 
299         /**
300          * Sets the Temporary Key value to be used by the LE Security Manager during LE pairing.
301          *
302          * @param leTemporaryKey byte array that shall be 16 bytes. Please see Bluetooth CSSv6, Part
303          *     A 1.8 for a detailed description.
304          * @return {@link OobData#Builder}
305          * @throws IllegalArgumentException if the leTemporaryKey is an invalid format.
306          * @throws NullinterException if leTemporaryKey is null.
307          * @hide
308          */
309         @NonNull
310         @SystemApi
setLeTemporaryKey(@onNull byte[] leTemporaryKey)311         public LeBuilder setLeTemporaryKey(@NonNull byte[] leTemporaryKey) {
312             requireNonNull(leTemporaryKey);
313             if (leTemporaryKey.length != LE_TK_OCTETS) {
314                 throw new IllegalArgumentException(
315                         "leTemporaryKey must be " + LE_TK_OCTETS + " octets in length.");
316             }
317             this.mLeTemporaryKey = leTemporaryKey;
318             return this;
319         }
320 
321         /**
322          * @param randomizerHash byte array consisting of {@link OobData#RANDOMIZER_OCTETS} octets
323          *     of data. Data is derived from controller/host stack and is required for pairing OOB.
324          *     Also, randomizerHash may be all 0s or null in which case it becomes all 0s.
325          * @throws IllegalArgumentException if null or incorrect length randomizerHash was passed.
326          * @throws NullPointerException if randomizerHash is null.
327          * @hide
328          */
329         @NonNull
330         @SystemApi
setRandomizerHash(@onNull byte[] randomizerHash)331         public LeBuilder setRandomizerHash(@NonNull byte[] randomizerHash) {
332             requireNonNull(randomizerHash);
333             if (randomizerHash.length != OobData.RANDOMIZER_OCTETS) {
334                 throw new IllegalArgumentException(
335                         "randomizerHash must be "
336                                 + OobData.RANDOMIZER_OCTETS
337                                 + " octets in length.");
338             }
339             this.mRandomizerHash = randomizerHash;
340             return this;
341         }
342 
343         /**
344          * Sets the LE Flags necessary for the pairing scenario or discovery mode.
345          *
346          * @param leFlags enum value representing the 1 octet of data about discovery modes.
347          *     <p>Possible LE Flags: {@link LE_FLAG_LIMITED_DISCOVERY_MODE} LE Limited Discoverable
348          *     Mode. {@link LE_FLAG_GENERAL_DISCOVERY_MODE} LE General Discoverable Mode. {@link
349          *     LE_FLAG_BREDR_NOT_SUPPORTED} BR/EDR Not Supported. Bit 37 of LMP Feature Mask
350          *     Definitions. {@link LE_FLAG_SIMULTANEOUS_CONTROLLER} Simultaneous LE and BR/EDR to
351          *     Same Device Capable (Controller) Bit 49 of LMP Feature Mask Definitions. {@link
352          *     LE_FLAG_SIMULTANEOUS_HOST} Simultaneous LE and BR/EDR to Same Device Capable (Host).
353          *     Bit 55 of LMP Feature Mask Definitions. 0x05- 0x07 Reserved
354          * @throws IllegalArgumentException for invalid flag
355          * @hide
356          */
357         @NonNull
358         @SystemApi
setLeFlags(@eFlag int leFlags)359         public LeBuilder setLeFlags(@LeFlag int leFlags) {
360             if (leFlags < LE_FLAG_LIMITED_DISCOVERY_MODE || leFlags > LE_FLAG_SIMULTANEOUS_HOST) {
361                 throw new IllegalArgumentException("leFlags must be a valid value.");
362             }
363             this.mLeFlags = leFlags;
364             return this;
365         }
366 
367         /**
368          * Validates and builds the {@link OobData} object for LE Security.
369          *
370          * @return {@link OobData} with given builder values
371          * @throws IllegalStateException if either of the 2 required fields were not set.
372          * @hide
373          */
374         @NonNull
375         @SystemApi
build()376         public OobData build() {
377             final OobData oob =
378                     new OobData(
379                             this.mDeviceAddressWithType,
380                             this.mLeDeviceRole,
381                             this.mConfirmationHash);
382 
383             // If we have values, set them, otherwise use default
384             oob.mLeTemporaryKey =
385                     (this.mLeTemporaryKey != null) ? this.mLeTemporaryKey : oob.mLeTemporaryKey;
386             oob.mLeAppearance =
387                     (this.mLeAppearance != null) ? this.mLeAppearance : oob.mLeAppearance;
388             oob.mLeFlags = (this.mLeFlags != 0xF) ? this.mLeFlags : oob.mLeFlags;
389             oob.mDeviceName = (this.mDeviceName != null) ? this.mDeviceName : oob.mDeviceName;
390             oob.mRandomizerHash = this.mRandomizerHash;
391             return oob;
392         }
393     }
394 
395     /**
396      * Builds an {@link OobData} object and validates that the required combination of values are
397      * present to create the Classic specific OobData type.
398      *
399      * @hide
400      */
401     @SystemApi
402     public static final class ClassicBuilder {
403         // Used by both Classic and LE
404         /**
405          * It is recommended that this Hash C is generated anew for each pairing.
406          *
407          * <p>It should be noted that on passive NFC this isn't possible as the data is static and
408          * immutable.
409          *
410          * @hide
411          */
412         private byte[] mConfirmationHash = null;
413 
414         /**
415          * Optional, but adds more validity to the pairing.
416          *
417          * <p>If not present a value of 0 is assumed.
418          *
419          * @hide
420          */
421         private byte[] mRandomizerHash =
422                 new byte[] {
423                     0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
424                     0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
425                 };
426 
427         /**
428          * The Bluetooth Device user-friendly name presented over Bluetooth Technology.
429          *
430          * <p>This is the name that may be displayed to the device user as part of the UI.
431          *
432          * @hide
433          */
434         private byte[] mDeviceName = null;
435 
436         /**
437          * This length value provides the absolute length of total OOB data block used for Bluetooth
438          * BR/EDR
439          *
440          * <p>OOB communication, which includes the length field itself and the Bluetooth Device
441          * Address.
442          *
443          * <p>The minimum length that may be represented in this field is 8.
444          *
445          * @hide
446          */
447         private final byte[] mClassicLength;
448 
449         /**
450          * The Bluetooth Device Address is the address to which the OOB data belongs.
451          *
452          * <p>The length MUST be {@link OobData#DEVICE_ADDRESS_OCTETS} octets.
453          *
454          * <p>Address is encoded in Little Endian order.
455          *
456          * <p>e.g. 00:01:02:03:04:05 would be x05x04x03x02x01x00
457          *
458          * @hide
459          */
460         private final byte[] mDeviceAddressWithType;
461 
462         /**
463          * Class of Device information is to be used to provide a graphical representation to the
464          * user as part of UI involving operations.
465          *
466          * <p>This is not to be used to determine a particular service can be used.
467          *
468          * <p>The length MUST be {@link OobData#CLASS_OF_DEVICE_OCTETS} octets.
469          *
470          * @hide
471          */
472         private byte[] mClassOfDevice = null;
473 
474         /**
475          * Main creation method for creating a Classic version of {@link OobData}.
476          *
477          * <p>This object will allow the caller to call {@link ClassicBuilder#build()} to build the
478          * data object or add any option information to the builder.
479          *
480          * @param confirmationHash byte array consisting of {@link OobData#CONFIRMATION_OCTETS}
481          *     octets of data. Data is derived from controller/host stack and is required for
482          *     pairing OOB.
483          * @param classicLength byte array representing the length of data from 8-65535 across 2
484          *     octets (0xXXXX).
485          * @param deviceAddressWithType byte array representing the Bluetooth Address of the device
486          *     that owns the OOB data. (i.e. the originator) [6 octets]
487          * @throws IllegalArgumentException if any of the values fail to be set.
488          * @throws NullPointerException if any argument is null.
489          * @hide
490          */
491         @SystemApi
ClassicBuilder( @onNull byte[] confirmationHash, @NonNull byte[] classicLength, @NonNull byte[] deviceAddressWithType)492         public ClassicBuilder(
493                 @NonNull byte[] confirmationHash,
494                 @NonNull byte[] classicLength,
495                 @NonNull byte[] deviceAddressWithType) {
496             requireNonNull(confirmationHash);
497             requireNonNull(classicLength);
498             requireNonNull(deviceAddressWithType);
499             if (confirmationHash.length != OobData.CONFIRMATION_OCTETS) {
500                 throw new IllegalArgumentException(
501                         "confirmationHash must be "
502                                 + OobData.CONFIRMATION_OCTETS
503                                 + " octets in length.");
504             }
505             this.mConfirmationHash = confirmationHash;
506             if (classicLength.length != OOB_LENGTH_OCTETS) {
507                 throw new IllegalArgumentException(
508                         "classicLength must be " + OOB_LENGTH_OCTETS + " octets in length.");
509             }
510             this.mClassicLength = classicLength;
511             if (deviceAddressWithType.length != DEVICE_ADDRESS_OCTETS) {
512                 throw new IllegalArgumentException(
513                         "deviceAddressWithType must be "
514                                 + DEVICE_ADDRESS_OCTETS
515                                 + " octets in length.");
516             }
517             this.mDeviceAddressWithType = deviceAddressWithType;
518         }
519 
520         /**
521          * @param randomizerHash byte array consisting of {@link OobData#RANDOMIZER_OCTETS} octets
522          *     of data. Data is derived from controller/host stack and is required for pairing OOB.
523          *     Also, randomizerHash may be all 0s or null in which case it becomes all 0s.
524          * @throws IllegalArgumentException if null or incorrect length randomizerHash was passed.
525          * @throws NullPointerException if randomizerHash is null.
526          * @hide
527          */
528         @NonNull
529         @SystemApi
setRandomizerHash(@onNull byte[] randomizerHash)530         public ClassicBuilder setRandomizerHash(@NonNull byte[] randomizerHash) {
531             requireNonNull(randomizerHash);
532             if (randomizerHash.length != OobData.RANDOMIZER_OCTETS) {
533                 throw new IllegalArgumentException(
534                         "randomizerHash must be "
535                                 + OobData.RANDOMIZER_OCTETS
536                                 + " octets in length.");
537             }
538             this.mRandomizerHash = randomizerHash;
539             return this;
540         }
541 
542         /**
543          * Sets the Bluetooth Device name to be used for UI purposes.
544          *
545          * <p>Optional attribute.
546          *
547          * @param deviceName byte array representing the name, may be 0 in length, not null.
548          * @return {@link OobData#ClassicBuilder}
549          * @throws NullPointerException if deviceName is null
550          * @hide
551          */
552         @NonNull
553         @SystemApi
setDeviceName(@onNull byte[] deviceName)554         public ClassicBuilder setDeviceName(@NonNull byte[] deviceName) {
555             requireNonNull(deviceName);
556             this.mDeviceName = deviceName;
557             return this;
558         }
559 
560         /**
561          * Sets the Bluetooth Class of Device; used for UI purposes only.
562          *
563          * <p>Not an indicator of available services!
564          *
565          * <p>Optional attribute.
566          *
567          * @param classOfDevice byte array of {@link OobData#CLASS_OF_DEVICE_OCTETS} octets.
568          * @return {@link OobData#ClassicBuilder}
569          * @throws IllegalArgumentException if length is not equal to {@link
570          *     OobData#CLASS_OF_DEVICE_OCTETS} octets.
571          * @throws NullPointerException if classOfDevice is null.
572          * @hide
573          */
574         @NonNull
575         @SystemApi
setClassOfDevice(@onNull byte[] classOfDevice)576         public ClassicBuilder setClassOfDevice(@NonNull byte[] classOfDevice) {
577             requireNonNull(classOfDevice);
578             if (classOfDevice.length != OobData.CLASS_OF_DEVICE_OCTETS) {
579                 throw new IllegalArgumentException(
580                         "classOfDevice must be "
581                                 + OobData.CLASS_OF_DEVICE_OCTETS
582                                 + " octets in length.");
583             }
584             this.mClassOfDevice = classOfDevice;
585             return this;
586         }
587 
588         /**
589          * Validates and builds the {@link OobData} object for Classic Security.
590          *
591          * @return {@link OobData} with previously given builder values.
592          * @hide
593          */
594         @NonNull
595         @SystemApi
build()596         public OobData build() {
597             final OobData oob =
598                     new OobData(
599                             this.mClassicLength,
600                             this.mDeviceAddressWithType,
601                             this.mConfirmationHash);
602             // If we have values, set them, otherwise use default
603             oob.mDeviceName = (this.mDeviceName != null) ? this.mDeviceName : oob.mDeviceName;
604             oob.mClassOfDevice =
605                     (this.mClassOfDevice != null) ? this.mClassOfDevice : oob.mClassOfDevice;
606             oob.mRandomizerHash = this.mRandomizerHash;
607             return oob;
608         }
609     }
610 
611     // Members (Defaults for Optionals must be set or Parceling fails on NPE)
612     // Both
613     private final byte[] mDeviceAddressWithType;
614     private final byte[] mConfirmationHash;
615     private byte[] mRandomizerHash =
616             new byte[] {
617                 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
618                 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
619             };
620     // Default the name to "Bluetooth Device"
621     private byte[] mDeviceName =
622             new byte[] {
623                 // Bluetooth
624                 0x42,
625                 0x6c,
626                 0x75,
627                 0x65,
628                 0x74,
629                 0x6f,
630                 0x6f,
631                 0x74,
632                 0x68,
633                 // <space>Device
634                 0x20,
635                 0x44,
636                 0x65,
637                 0x76,
638                 0x69,
639                 0x63,
640                 0x65
641             };
642 
643     // Classic
644     private final byte[] mClassicLength;
645     private byte[] mClassOfDevice = new byte[CLASS_OF_DEVICE_OCTETS];
646 
647     // LE
648     private final @LeRole int mLeDeviceRole;
649     private byte[] mLeTemporaryKey = new byte[LE_TK_OCTETS];
650     private byte[] mLeAppearance = new byte[LE_APPEARANCE_OCTETS];
651     private @LeFlag int mLeFlags = LE_FLAG_LIMITED_DISCOVERY_MODE;
652 
653     /**
654      * @return byte array representing the MAC address of a bluetooth device. The Address is 6
655      *     octets long with a 1 octet address type associated with the address.
656      *     <p>For classic this will be 6 byte address plus the default of PUBLIC_ADDRESS Address
657      *     Type. For LE there are more choices for Address Type.
658      * @hide
659      */
660     @NonNull
661     @SystemApi
getDeviceAddressWithType()662     public byte[] getDeviceAddressWithType() {
663         return mDeviceAddressWithType;
664     }
665 
666     /**
667      * @return byte array representing the confirmationHash value which is used to confirm the
668      *     identity to the controller.
669      * @hide
670      */
671     @NonNull
672     @SystemApi
getConfirmationHash()673     public byte[] getConfirmationHash() {
674         return mConfirmationHash;
675     }
676 
677     /**
678      * @return byte array representing the randomizerHash value which is used to verify the identity
679      *     of the controller.
680      * @hide
681      */
682     @NonNull
683     @SystemApi
getRandomizerHash()684     public byte[] getRandomizerHash() {
685         return mRandomizerHash;
686     }
687 
688     /**
689      * @return Device Name used for displaying name in UI.
690      *     <p>Also, this will be populated with the LE Local Name if the data is for LE.
691      * @hide
692      */
693     @Nullable
694     @SystemApi
getDeviceName()695     public byte[] getDeviceName() {
696         return mDeviceName;
697     }
698 
699     /**
700      * @return byte array representing the oob data length which is the length of all of the data
701      *     including these octets.
702      * @hide
703      */
704     @NonNull
705     @SystemApi
getClassicLength()706     public byte[] getClassicLength() {
707         return mClassicLength;
708     }
709 
710     /**
711      * @return byte array representing the class of device for UI display.
712      *     <p>Does not indicate services available; for display only.
713      * @hide
714      */
715     @NonNull
716     @SystemApi
getClassOfDevice()717     public byte[] getClassOfDevice() {
718         return mClassOfDevice;
719     }
720 
721     /**
722      * @return Temporary Key used for LE pairing.
723      * @hide
724      */
725     @Nullable
726     @SystemApi
getLeTemporaryKey()727     public byte[] getLeTemporaryKey() {
728         return mLeTemporaryKey;
729     }
730 
731     /**
732      * @return Appearance used for LE pairing. For use in UI situations when determining what sort
733      *     of icons or text to display regarding the device.
734      * @hide
735      */
736     @Nullable
737     @SystemApi
getLeAppearance()738     public byte[] getLeAppearance() {
739         return mLeAppearance;
740     }
741 
742     /**
743      * @return Flags used to determining discoverable mode to use, BR/EDR Support, and Capability.
744      *     <p>Possible LE Flags: {@link LE_FLAG_LIMITED_DISCOVERY_MODE} LE Limited Discoverable
745      *     Mode. {@link LE_FLAG_GENERAL_DISCOVERY_MODE} LE General Discoverable Mode. {@link
746      *     LE_FLAG_BREDR_NOT_SUPPORTED} BR/EDR Not Supported. Bit 37 of LMP Feature Mask
747      *     Definitions. {@link LE_FLAG_SIMULTANEOUS_CONTROLLER} Simultaneous LE and BR/EDR to Same
748      *     Device Capable (Controller). Bit 49 of LMP Feature Mask Definitions. {@link
749      *     LE_FLAG_SIMULTANEOUS_HOST} Simultaneous LE and BR/EDR to Same Device Capable (Host). Bit
750      *     55 of LMP Feature Mask Definitions. <b>0x05- 0x07 Reserved</b>
751      * @hide
752      */
753     @NonNull
754     @SystemApi
755     @LeFlag
getLeFlags()756     public int getLeFlags() {
757         return mLeFlags;
758     }
759 
760     /**
761      * @return the supported and preferred roles of the LE device.
762      *     <p>Possible Values: {@link LE_DEVICE_ROLE_PERIPHERAL_ONLY} Only Peripheral supported
763      *     {@link LE_DEVICE_ROLE_CENTRAL_ONLY} Only Central supported {@link
764      *     LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL} Central & Peripheral supported; Peripheral
765      *     Preferred {@link LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL} Only peripheral supported; Central
766      *     Preferred 0x04 - 0xFF Reserved
767      * @hide
768      */
769     @NonNull
770     @SystemApi
771     @LeRole
getLeDeviceRole()772     public int getLeDeviceRole() {
773         return mLeDeviceRole;
774     }
775 
776     /** Classic Security Constructor */
OobData( @onNull byte[] classicLength, @NonNull byte[] deviceAddressWithType, @NonNull byte[] confirmationHash)777     private OobData(
778             @NonNull byte[] classicLength,
779             @NonNull byte[] deviceAddressWithType,
780             @NonNull byte[] confirmationHash) {
781         mClassicLength = classicLength;
782         mDeviceAddressWithType = deviceAddressWithType;
783         mConfirmationHash = confirmationHash;
784         mLeDeviceRole = -1; // Satisfy final
785     }
786 
787     /** LE Security Constructor */
OobData( @onNull byte[] deviceAddressWithType, @LeRole int leDeviceRole, @NonNull byte[] confirmationHash)788     private OobData(
789             @NonNull byte[] deviceAddressWithType,
790             @LeRole int leDeviceRole,
791             @NonNull byte[] confirmationHash) {
792         mDeviceAddressWithType = deviceAddressWithType;
793         mLeDeviceRole = leDeviceRole;
794         mConfirmationHash = confirmationHash;
795         mClassicLength = new byte[OOB_LENGTH_OCTETS]; // Satisfy final
796     }
797 
OobData(Parcel in)798     private OobData(Parcel in) {
799         // Both
800         mDeviceAddressWithType = in.createByteArray();
801         mConfirmationHash = in.createByteArray();
802         mRandomizerHash = in.createByteArray();
803         mDeviceName = in.createByteArray();
804 
805         // Classic
806         mClassicLength = in.createByteArray();
807         mClassOfDevice = in.createByteArray();
808 
809         // LE
810         mLeDeviceRole = in.readInt();
811         mLeTemporaryKey = in.createByteArray();
812         mLeAppearance = in.createByteArray();
813         mLeFlags = in.readInt();
814     }
815 
816     /** @hide */
817     @Override
describeContents()818     public int describeContents() {
819         return 0;
820     }
821 
822     /** @hide */
823     @Override
writeToParcel(@onNull Parcel out, int flags)824     public void writeToParcel(@NonNull Parcel out, int flags) {
825         // Both
826         // Required
827         out.writeByteArray(mDeviceAddressWithType);
828         // Required
829         out.writeByteArray(mConfirmationHash);
830         // Optional
831         out.writeByteArray(mRandomizerHash);
832         // Optional
833         out.writeByteArray(mDeviceName);
834 
835         // Classic
836         // Required
837         out.writeByteArray(mClassicLength);
838         // Optional
839         out.writeByteArray(mClassOfDevice);
840 
841         // LE
842         // Required
843         out.writeInt(mLeDeviceRole);
844         // Required
845         out.writeByteArray(mLeTemporaryKey);
846         // Optional
847         out.writeByteArray(mLeAppearance);
848         // Optional
849         out.writeInt(mLeFlags);
850     }
851 
852     // For Parcelable
853     public static final @android.annotation.NonNull Parcelable.Creator<OobData> CREATOR =
854             new Parcelable.Creator<OobData>() {
855                 public OobData createFromParcel(Parcel in) {
856                     return new OobData(in);
857                 }
858 
859                 public OobData[] newArray(int size) {
860                     return new OobData[size];
861                 }
862             };
863 
864     /**
865      * @return a {@link String} representation of the OobData object.
866      * @hide
867      */
868     @Override
869     @NonNull
toString()870     public String toString() {
871         return "OobData: \n\t"
872                 // Both
873                 + "Device Address With Type: "
874                 + toHexString(mDeviceAddressWithType)
875                 + "\n\t"
876                 + "Confirmation: "
877                 + toHexString(mConfirmationHash)
878                 + "\n\t"
879                 + "Randomizer: "
880                 + toHexString(mRandomizerHash)
881                 + "\n\t"
882                 + "Device Name: "
883                 + toHexString(mDeviceName)
884                 + "\n\t"
885                 // Classic
886                 + "OobData Length: "
887                 + toHexString(mClassicLength)
888                 + "\n\t"
889                 + "Class of Device: "
890                 + toHexString(mClassOfDevice)
891                 + "\n\t"
892                 // LE
893                 + "LE Device Role: "
894                 + toHexString(mLeDeviceRole)
895                 + "\n\t"
896                 + "LE Temporary Key: "
897                 + toHexString(mLeTemporaryKey)
898                 + "\n\t"
899                 + "LE Appearance: "
900                 + toHexString(mLeAppearance)
901                 + "\n\t"
902                 + "LE Flags: "
903                 + toHexString(mLeFlags)
904                 + "\n\t";
905     }
906 
907     @NonNull
toHexString(int b)908     private String toHexString(int b) {
909         return toHexString(new byte[] {(byte) b});
910     }
911 
912     @NonNull
toHexString(byte[] array)913     private String toHexString(byte[] array) {
914         if (array == null) return "null";
915         StringBuilder builder = new StringBuilder(array.length * 2);
916         for (byte b : array) {
917             builder.append(String.format("%02x", b));
918         }
919         return builder.toString();
920     }
921 }
922