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