1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.bluetooth;
18 
19 import android.Manifest;
20 import android.annotation.IntDef;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.RequiresPermission;
24 import android.annotation.SdkConstant;
25 import android.annotation.SdkConstant.SdkConstantType;
26 import android.annotation.SuppressLint;
27 import android.annotation.SystemApi;
28 import android.compat.annotation.UnsupportedAppUsage;
29 import android.content.Context;
30 import android.os.Handler;
31 import android.os.Parcel;
32 import android.os.ParcelUuid;
33 import android.os.Parcelable;
34 import android.os.Process;
35 import android.os.RemoteException;
36 import android.util.Log;
37 
38 import java.io.IOException;
39 import java.io.UnsupportedEncodingException;
40 import java.lang.annotation.Retention;
41 import java.lang.annotation.RetentionPolicy;
42 import java.util.UUID;
43 
44 /**
45  * Represents a remote Bluetooth device. A {@link BluetoothDevice} lets you
46  * create a connection with the respective device or query information about
47  * it, such as the name, address, class, and bonding state.
48  *
49  * <p>This class is really just a thin wrapper for a Bluetooth hardware
50  * address. Objects of this class are immutable. Operations on this class
51  * are performed on the remote Bluetooth hardware address, using the
52  * {@link BluetoothAdapter} that was used to create this {@link
53  * BluetoothDevice}.
54  *
55  * <p>To get a {@link BluetoothDevice}, use
56  * {@link BluetoothAdapter#getRemoteDevice(String)
57  * BluetoothAdapter.getRemoteDevice(String)} to create one representing a device
58  * of a known MAC address (which you can get through device discovery with
59  * {@link BluetoothAdapter}) or get one from the set of bonded devices
60  * returned by {@link BluetoothAdapter#getBondedDevices()
61  * BluetoothAdapter.getBondedDevices()}. You can then open a
62  * {@link BluetoothSocket} for communication with the remote device, using
63  * {@link #createRfcommSocketToServiceRecord(UUID)} over Bluetooth BR/EDR or using
64  * {@link #createL2capChannel(int)} over Bluetooth LE.
65  *
66  * <p class="note"><strong>Note:</strong>
67  * Requires the {@link android.Manifest.permission#BLUETOOTH} permission.
68  *
69  * <div class="special reference">
70  * <h3>Developer Guides</h3>
71  * <p>
72  * For more information about using Bluetooth, read the <a href=
73  * "{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer
74  * guide.
75  * </p>
76  * </div>
77  *
78  * {@see BluetoothAdapter}
79  * {@see BluetoothSocket}
80  */
81 public final class BluetoothDevice implements Parcelable {
82     private static final String TAG = "BluetoothDevice";
83     private static final boolean DBG = false;
84 
85     /**
86      * Connection state bitmask as returned by getConnectionState.
87      */
88     private static final int CONNECTION_STATE_DISCONNECTED = 0;
89     private static final int CONNECTION_STATE_CONNECTED = 1;
90     private static final int CONNECTION_STATE_ENCRYPTED_BREDR = 2;
91     private static final int CONNECTION_STATE_ENCRYPTED_LE = 4;
92 
93     /**
94      * Sentinel error value for this class. Guaranteed to not equal any other
95      * integer constant in this class. Provided as a convenience for functions
96      * that require a sentinel error value, for example:
97      * <p><code>Intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
98      * BluetoothDevice.ERROR)</code>
99      */
100     public static final int ERROR = Integer.MIN_VALUE;
101 
102     /**
103      * Broadcast Action: Remote device discovered.
104      * <p>Sent when a remote device is found during discovery.
105      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
106      * #EXTRA_CLASS}. Can contain the extra fields {@link #EXTRA_NAME} and/or
107      * {@link #EXTRA_RSSI} if they are available.
108      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} and
109      * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} to receive.
110      */
111     // TODO: Change API to not broadcast RSSI if not available (incoming connection)
112     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
113     public static final String ACTION_FOUND =
114             "android.bluetooth.device.action.FOUND";
115 
116     /**
117      * Broadcast Action: Bluetooth class of a remote device has changed.
118      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
119      * #EXTRA_CLASS}.
120      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
121      * {@see BluetoothClass}
122      */
123     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
124     public static final String ACTION_CLASS_CHANGED =
125             "android.bluetooth.device.action.CLASS_CHANGED";
126 
127     /**
128      * Broadcast Action: Indicates a low level (ACL) connection has been
129      * established with a remote device.
130      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
131      * <p>ACL connections are managed automatically by the Android Bluetooth
132      * stack.
133      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
134      */
135     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
136     public static final String ACTION_ACL_CONNECTED =
137             "android.bluetooth.device.action.ACL_CONNECTED";
138 
139     /**
140      * Broadcast Action: Indicates that a low level (ACL) disconnection has
141      * been requested for a remote device, and it will soon be disconnected.
142      * <p>This is useful for graceful disconnection. Applications should use
143      * this intent as a hint to immediately terminate higher level connections
144      * (RFCOMM, L2CAP, or profile connections) to the remote device.
145      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
146      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
147      */
148     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
149     public static final String ACTION_ACL_DISCONNECT_REQUESTED =
150             "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED";
151 
152     /**
153      * Broadcast Action: Indicates a low level (ACL) disconnection from a
154      * remote device.
155      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
156      * <p>ACL connections are managed automatically by the Android Bluetooth
157      * stack.
158      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
159      */
160     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
161     public static final String ACTION_ACL_DISCONNECTED =
162             "android.bluetooth.device.action.ACL_DISCONNECTED";
163 
164     /**
165      * Broadcast Action: Indicates the friendly name of a remote device has
166      * been retrieved for the first time, or changed since the last retrieval.
167      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
168      * #EXTRA_NAME}.
169      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
170      */
171     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
172     public static final String ACTION_NAME_CHANGED =
173             "android.bluetooth.device.action.NAME_CHANGED";
174 
175     /**
176      * Broadcast Action: Indicates the alias of a remote device has been
177      * changed.
178      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
179      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
180      */
181     @SuppressLint("ActionValue")
182     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
183     public static final String ACTION_ALIAS_CHANGED =
184             "android.bluetooth.device.action.ALIAS_CHANGED";
185 
186     /**
187      * Broadcast Action: Indicates a change in the bond state of a remote
188      * device. For example, if a device is bonded (paired).
189      * <p>Always contains the extra fields {@link #EXTRA_DEVICE}, {@link
190      * #EXTRA_BOND_STATE} and {@link #EXTRA_PREVIOUS_BOND_STATE}.
191      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
192      */
193     // Note: When EXTRA_BOND_STATE is BOND_NONE then this will also
194     // contain a hidden extra field EXTRA_REASON with the result code.
195     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
196     public static final String ACTION_BOND_STATE_CHANGED =
197             "android.bluetooth.device.action.BOND_STATE_CHANGED";
198 
199     /**
200      * Broadcast Action: Indicates the battery level of a remote device has
201      * been retrieved for the first time, or changed since the last retrieval
202      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
203      * #EXTRA_BATTERY_LEVEL}.
204      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
205      *
206      * @hide
207      */
208     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
209     public static final String ACTION_BATTERY_LEVEL_CHANGED =
210             "android.bluetooth.device.action.BATTERY_LEVEL_CHANGED";
211 
212     /**
213      * Used as an Integer extra field in {@link #ACTION_BATTERY_LEVEL_CHANGED}
214      * intent. It contains the most recently retrieved battery level information
215      * ranging from 0% to 100% for a remote device, {@link #BATTERY_LEVEL_UNKNOWN}
216      * when the valid is unknown or there is an error
217      *
218      * @hide
219      */
220     public static final String EXTRA_BATTERY_LEVEL =
221             "android.bluetooth.device.extra.BATTERY_LEVEL";
222 
223     /**
224      * Used as the unknown value for {@link #EXTRA_BATTERY_LEVEL} and {@link #getBatteryLevel()}
225      *
226      * @hide
227      */
228     public static final int BATTERY_LEVEL_UNKNOWN = -1;
229 
230     /**
231      * Used as an error value for {@link #getBatteryLevel()} to represent bluetooth is off
232      *
233      * @hide
234      */
235     public static final int BATTERY_LEVEL_BLUETOOTH_OFF = -100;
236 
237     /**
238      * Used as a Parcelable {@link BluetoothDevice} extra field in every intent
239      * broadcast by this class. It contains the {@link BluetoothDevice} that
240      * the intent applies to.
241      */
242     public static final String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
243 
244     /**
245      * Used as a String extra field in {@link #ACTION_NAME_CHANGED} and {@link
246      * #ACTION_FOUND} intents. It contains the friendly Bluetooth name.
247      */
248     public static final String EXTRA_NAME = "android.bluetooth.device.extra.NAME";
249 
250     /**
251      * Used as an optional short extra field in {@link #ACTION_FOUND} intents.
252      * Contains the RSSI value of the remote device as reported by the
253      * Bluetooth hardware.
254      */
255     public static final String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI";
256 
257     /**
258      * Used as a Parcelable {@link BluetoothClass} extra field in {@link
259      * #ACTION_FOUND} and {@link #ACTION_CLASS_CHANGED} intents.
260      */
261     public static final String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS";
262 
263     /**
264      * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
265      * Contains the bond state of the remote device.
266      * <p>Possible values are:
267      * {@link #BOND_NONE},
268      * {@link #BOND_BONDING},
269      * {@link #BOND_BONDED}.
270      */
271     public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE";
272     /**
273      * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
274      * Contains the previous bond state of the remote device.
275      * <p>Possible values are:
276      * {@link #BOND_NONE},
277      * {@link #BOND_BONDING},
278      * {@link #BOND_BONDED}.
279      */
280     public static final String EXTRA_PREVIOUS_BOND_STATE =
281             "android.bluetooth.device.extra.PREVIOUS_BOND_STATE";
282     /**
283      * Indicates the remote device is not bonded (paired).
284      * <p>There is no shared link key with the remote device, so communication
285      * (if it is allowed at all) will be unauthenticated and unencrypted.
286      */
287     public static final int BOND_NONE = 10;
288     /**
289      * Indicates bonding (pairing) is in progress with the remote device.
290      */
291     public static final int BOND_BONDING = 11;
292     /**
293      * Indicates the remote device is bonded (paired).
294      * <p>A shared link keys exists locally for the remote device, so
295      * communication can be authenticated and encrypted.
296      * <p><i>Being bonded (paired) with a remote device does not necessarily
297      * mean the device is currently connected. It just means that the pending
298      * procedure was completed at some earlier time, and the link key is still
299      * stored locally, ready to use on the next connection.
300      * </i>
301      */
302     public static final int BOND_BONDED = 12;
303 
304     /**
305      * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
306      * intents for unbond reason.
307      *
308      * @hide
309      */
310     @UnsupportedAppUsage
311     public static final String EXTRA_REASON = "android.bluetooth.device.extra.REASON";
312 
313     /**
314      * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
315      * intents to indicate pairing method used. Possible values are:
316      * {@link #PAIRING_VARIANT_PIN},
317      * {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION},
318      */
319     public static final String EXTRA_PAIRING_VARIANT =
320             "android.bluetooth.device.extra.PAIRING_VARIANT";
321 
322     /**
323      * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
324      * intents as the value of passkey.
325      */
326     public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY";
327 
328     /**
329      * Bluetooth device type, Unknown
330      */
331     public static final int DEVICE_TYPE_UNKNOWN = 0;
332 
333     /**
334      * Bluetooth device type, Classic - BR/EDR devices
335      */
336     public static final int DEVICE_TYPE_CLASSIC = 1;
337 
338     /**
339      * Bluetooth device type, Low Energy - LE-only
340      */
341     public static final int DEVICE_TYPE_LE = 2;
342 
343     /**
344      * Bluetooth device type, Dual Mode - BR/EDR/LE
345      */
346     public static final int DEVICE_TYPE_DUAL = 3;
347 
348 
349     /** @hide */
350     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
351     @UnsupportedAppUsage
352     public static final String ACTION_SDP_RECORD =
353             "android.bluetooth.device.action.SDP_RECORD";
354 
355     /**
356      * Maximum length of a metadata entry, this is to avoid exploding Bluetooth
357      * disk usage
358      * @hide
359      */
360     @SystemApi
361     public static final int METADATA_MAX_LENGTH = 2048;
362 
363     /**
364      * Manufacturer name of this Bluetooth device
365      * Data type should be {@String} as {@link Byte} array.
366      * @hide
367      */
368     @SystemApi
369     public static final int METADATA_MANUFACTURER_NAME = 0;
370 
371     /**
372      * Model name of this Bluetooth device
373      * Data type should be {@String} as {@link Byte} array.
374      * @hide
375      */
376     @SystemApi
377     public static final int METADATA_MODEL_NAME = 1;
378 
379     /**
380      * Software version of this Bluetooth device
381      * Data type should be {@String} as {@link Byte} array.
382      * @hide
383      */
384     @SystemApi
385     public static final int METADATA_SOFTWARE_VERSION = 2;
386 
387     /**
388      * Hardware version of this Bluetooth device
389      * Data type should be {@String} as {@link Byte} array.
390      * @hide
391      */
392     @SystemApi
393     public static final int METADATA_HARDWARE_VERSION = 3;
394 
395     /**
396      * Package name of the companion app, if any
397      * Data type should be {@String} as {@link Byte} array.
398      * @hide
399      */
400     @SystemApi
401     public static final int METADATA_COMPANION_APP = 4;
402 
403     /**
404      * URI to the main icon shown on the settings UI
405      * Data type should be {@link Byte} array.
406      * @hide
407      */
408     @SystemApi
409     public static final int METADATA_MAIN_ICON = 5;
410 
411     /**
412      * Whether this device is an untethered headset with left, right and case
413      * Data type should be {@String} as {@link Byte} array.
414      * @hide
415      */
416     @SystemApi
417     public static final int METADATA_IS_UNTETHERED_HEADSET = 6;
418 
419     /**
420      * URI to icon of the left headset
421      * Data type should be {@link Byte} array.
422      * @hide
423      */
424     @SystemApi
425     public static final int METADATA_UNTETHERED_LEFT_ICON = 7;
426 
427     /**
428      * URI to icon of the right headset
429      * Data type should be {@link Byte} array.
430      * @hide
431      */
432     @SystemApi
433     public static final int METADATA_UNTETHERED_RIGHT_ICON = 8;
434 
435     /**
436      * URI to icon of the headset charging case
437      * Data type should be {@link Byte} array.
438      * @hide
439      */
440     @SystemApi
441     public static final int METADATA_UNTETHERED_CASE_ICON = 9;
442 
443     /**
444      * Battery level of left headset
445      * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
446      * as invalid.
447      * @hide
448      */
449     @SystemApi
450     public static final int METADATA_UNTETHERED_LEFT_BATTERY = 10;
451 
452     /**
453      * Battery level of rigth headset
454      * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
455      * as invalid.
456      * @hide
457      */
458     @SystemApi
459     public static final int METADATA_UNTETHERED_RIGHT_BATTERY = 11;
460 
461     /**
462      * Battery level of the headset charging case
463      * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
464      * as invalid.
465      * @hide
466      */
467     @SystemApi
468     public static final int METADATA_UNTETHERED_CASE_BATTERY = 12;
469 
470     /**
471      * Whether the left headset is charging
472      * Data type should be {@String} as {@link Byte} array.
473      * @hide
474      */
475     @SystemApi
476     public static final int METADATA_UNTETHERED_LEFT_CHARGING = 13;
477 
478     /**
479      * Whether the right headset is charging
480      * Data type should be {@String} as {@link Byte} array.
481      * @hide
482      */
483     @SystemApi
484     public static final int METADATA_UNTETHERED_RIGHT_CHARGING = 14;
485 
486     /**
487      * Whether the headset charging case is charging
488      * Data type should be {@String} as {@link Byte} array.
489      * @hide
490      */
491     @SystemApi
492     public static final int METADATA_UNTETHERED_CASE_CHARGING = 15;
493 
494     /**
495      * URI to the enhanced settings UI slice
496      * Data type should be {@String} as {@link Byte} array, null means
497      * the UI does not exist.
498      * @hide
499      */
500     @SystemApi
501     public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16;
502 
503     /**
504      * Broadcast Action: This intent is used to broadcast the {@link UUID}
505      * wrapped as a {@link android.os.ParcelUuid} of the remote device after it
506      * has been fetched. This intent is sent only when the UUIDs of the remote
507      * device are requested to be fetched using Service Discovery Protocol
508      * <p> Always contains the extra field {@link #EXTRA_DEVICE}
509      * <p> Always contains the extra field {@link #EXTRA_UUID}
510      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} to receive.
511      */
512     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
513     public static final String ACTION_UUID =
514             "android.bluetooth.device.action.UUID";
515 
516     /** @hide */
517     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
518     public static final String ACTION_MAS_INSTANCE =
519             "android.bluetooth.device.action.MAS_INSTANCE";
520 
521     /**
522      * Broadcast Action: Indicates a failure to retrieve the name of a remote
523      * device.
524      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
525      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
526      *
527      * @hide
528      */
529     //TODO: is this actually useful?
530     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
531     public static final String ACTION_NAME_FAILED =
532             "android.bluetooth.device.action.NAME_FAILED";
533 
534     /**
535      * Broadcast Action: This intent is used to broadcast PAIRING REQUEST
536      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} to
537      * receive.
538      */
539     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
540     public static final String ACTION_PAIRING_REQUEST =
541             "android.bluetooth.device.action.PAIRING_REQUEST";
542     /** @hide */
543     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
544     @UnsupportedAppUsage
545     public static final String ACTION_PAIRING_CANCEL =
546             "android.bluetooth.device.action.PAIRING_CANCEL";
547 
548     /** @hide */
549     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
550     public static final String ACTION_CONNECTION_ACCESS_REQUEST =
551             "android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST";
552 
553     /** @hide */
554     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
555     public static final String ACTION_CONNECTION_ACCESS_REPLY =
556             "android.bluetooth.device.action.CONNECTION_ACCESS_REPLY";
557 
558     /** @hide */
559     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
560     public static final String ACTION_CONNECTION_ACCESS_CANCEL =
561             "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL";
562 
563     /**
564      * Intent to broadcast silence mode changed.
565      * Alway contains the extra field {@link #EXTRA_DEVICE}
566      *
567      * @hide
568      */
569     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
570     @SystemApi
571     public static final String ACTION_SILENCE_MODE_CHANGED =
572             "android.bluetooth.device.action.SILENCE_MODE_CHANGED";
573 
574     /**
575      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intent.
576      *
577      * @hide
578      */
579     public static final String EXTRA_ACCESS_REQUEST_TYPE =
580             "android.bluetooth.device.extra.ACCESS_REQUEST_TYPE";
581 
582     /** @hide */
583     public static final int REQUEST_TYPE_PROFILE_CONNECTION = 1;
584 
585     /** @hide */
586     public static final int REQUEST_TYPE_PHONEBOOK_ACCESS = 2;
587 
588     /** @hide */
589     public static final int REQUEST_TYPE_MESSAGE_ACCESS = 3;
590 
591     /** @hide */
592     public static final int REQUEST_TYPE_SIM_ACCESS = 4;
593 
594     /**
595      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents,
596      * Contains package name to return reply intent to.
597      *
598      * @hide
599      */
600     public static final String EXTRA_PACKAGE_NAME = "android.bluetooth.device.extra.PACKAGE_NAME";
601 
602     /**
603      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents,
604      * Contains class name to return reply intent to.
605      *
606      * @hide
607      */
608     public static final String EXTRA_CLASS_NAME = "android.bluetooth.device.extra.CLASS_NAME";
609 
610     /**
611      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intent.
612      *
613      * @hide
614      */
615     public static final String EXTRA_CONNECTION_ACCESS_RESULT =
616             "android.bluetooth.device.extra.CONNECTION_ACCESS_RESULT";
617 
618     /** @hide */
619     public static final int CONNECTION_ACCESS_YES = 1;
620 
621     /** @hide */
622     public static final int CONNECTION_ACCESS_NO = 2;
623 
624     /**
625      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intents,
626      * Contains boolean to indicate if the allowed response is once-for-all so that
627      * next request will be granted without asking user again.
628      *
629      * @hide
630      */
631     public static final String EXTRA_ALWAYS_ALLOWED =
632             "android.bluetooth.device.extra.ALWAYS_ALLOWED";
633 
634     /**
635      * A bond attempt succeeded
636      *
637      * @hide
638      */
639     public static final int BOND_SUCCESS = 0;
640 
641     /**
642      * A bond attempt failed because pins did not match, or remote device did
643      * not respond to pin request in time
644      *
645      * @hide
646      */
647     @UnsupportedAppUsage
648     public static final int UNBOND_REASON_AUTH_FAILED = 1;
649 
650     /**
651      * A bond attempt failed because the other side explicitly rejected
652      * bonding
653      *
654      * @hide
655      */
656     @UnsupportedAppUsage
657     public static final int UNBOND_REASON_AUTH_REJECTED = 2;
658 
659     /**
660      * A bond attempt failed because we canceled the bonding process
661      *
662      * @hide
663      */
664     public static final int UNBOND_REASON_AUTH_CANCELED = 3;
665 
666     /**
667      * A bond attempt failed because we could not contact the remote device
668      *
669      * @hide
670      */
671     @UnsupportedAppUsage
672     public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
673 
674     /**
675      * A bond attempt failed because a discovery is in progress
676      *
677      * @hide
678      */
679     @UnsupportedAppUsage
680     public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
681 
682     /**
683      * A bond attempt failed because of authentication timeout
684      *
685      * @hide
686      */
687     @UnsupportedAppUsage
688     public static final int UNBOND_REASON_AUTH_TIMEOUT = 6;
689 
690     /**
691      * A bond attempt failed because of repeated attempts
692      *
693      * @hide
694      */
695     @UnsupportedAppUsage
696     public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7;
697 
698     /**
699      * A bond attempt failed because we received an Authentication Cancel
700      * by remote end
701      *
702      * @hide
703      */
704     @UnsupportedAppUsage
705     public static final int UNBOND_REASON_REMOTE_AUTH_CANCELED = 8;
706 
707     /**
708      * An existing bond was explicitly revoked
709      *
710      * @hide
711      */
712     public static final int UNBOND_REASON_REMOVED = 9;
713 
714     /**
715      * The user will be prompted to enter a pin or
716      * an app will enter a pin for user.
717      */
718     public static final int PAIRING_VARIANT_PIN = 0;
719 
720     /**
721      * The user will be prompted to enter a passkey
722      *
723      * @hide
724      */
725     public static final int PAIRING_VARIANT_PASSKEY = 1;
726 
727     /**
728      * The user will be prompted to confirm the passkey displayed on the screen or
729      * an app will confirm the passkey for the user.
730      */
731     public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2;
732 
733     /**
734      * The user will be prompted to accept or deny the incoming pairing request
735      *
736      * @hide
737      */
738     public static final int PAIRING_VARIANT_CONSENT = 3;
739 
740     /**
741      * The user will be prompted to enter the passkey displayed on remote device
742      * This is used for Bluetooth 2.1 pairing.
743      *
744      * @hide
745      */
746     public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4;
747 
748     /**
749      * The user will be prompted to enter the PIN displayed on remote device.
750      * This is used for Bluetooth 2.0 pairing.
751      *
752      * @hide
753      */
754     public static final int PAIRING_VARIANT_DISPLAY_PIN = 5;
755 
756     /**
757      * The user will be prompted to accept or deny the OOB pairing request
758      *
759      * @hide
760      */
761     public static final int PAIRING_VARIANT_OOB_CONSENT = 6;
762 
763     /**
764      * The user will be prompted to enter a 16 digit pin or
765      * an app will enter a 16 digit pin for user.
766      *
767      * @hide
768      */
769     public static final int PAIRING_VARIANT_PIN_16_DIGITS = 7;
770 
771     /**
772      * Used as an extra field in {@link #ACTION_UUID} intents,
773      * Contains the {@link android.os.ParcelUuid}s of the remote device which
774      * is a parcelable version of {@link UUID}.
775      */
776     public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
777 
778     /** @hide */
779     public static final String EXTRA_SDP_RECORD =
780             "android.bluetooth.device.extra.SDP_RECORD";
781 
782     /** @hide */
783     @UnsupportedAppUsage
784     public static final String EXTRA_SDP_SEARCH_STATUS =
785             "android.bluetooth.device.extra.SDP_SEARCH_STATUS";
786 
787     /** @hide */
788     @IntDef(prefix = "ACCESS_", value = {ACCESS_UNKNOWN,
789             ACCESS_ALLOWED, ACCESS_REJECTED})
790     @Retention(RetentionPolicy.SOURCE)
791     public @interface AccessPermission{}
792 
793     /**
794      * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
795      * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
796      *
797      * @hide
798      */
799     @SystemApi
800     public static final int ACCESS_UNKNOWN = 0;
801 
802     /**
803      * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
804      * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
805      *
806      * @hide
807      */
808     @SystemApi
809     public static final int ACCESS_ALLOWED = 1;
810 
811     /**
812      * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
813      * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
814      *
815      * @hide
816      */
817     @SystemApi
818     public static final int ACCESS_REJECTED = 2;
819 
820     /**
821      * No preference of physical transport for GATT connections to remote dual-mode devices
822      */
823     public static final int TRANSPORT_AUTO = 0;
824 
825     /**
826      * Prefer BR/EDR transport for GATT connections to remote dual-mode devices
827      */
828     public static final int TRANSPORT_BREDR = 1;
829 
830     /**
831      * Prefer LE transport for GATT connections to remote dual-mode devices
832      */
833     public static final int TRANSPORT_LE = 2;
834 
835     /**
836      * Bluetooth LE 1M PHY. Used to refer to LE 1M Physical Channel for advertising, scanning or
837      * connection.
838      */
839     public static final int PHY_LE_1M = 1;
840 
841     /**
842      * Bluetooth LE 2M PHY. Used to refer to LE 2M Physical Channel for advertising, scanning or
843      * connection.
844      */
845     public static final int PHY_LE_2M = 2;
846 
847     /**
848      * Bluetooth LE Coded PHY. Used to refer to LE Coded Physical Channel for advertising, scanning
849      * or connection.
850      */
851     public static final int PHY_LE_CODED = 3;
852 
853     /**
854      * Bluetooth LE 1M PHY mask. Used to specify LE 1M Physical Channel as one of many available
855      * options in a bitmask.
856      */
857     public static final int PHY_LE_1M_MASK = 1;
858 
859     /**
860      * Bluetooth LE 2M PHY mask. Used to specify LE 2M Physical Channel as one of many available
861      * options in a bitmask.
862      */
863     public static final int PHY_LE_2M_MASK = 2;
864 
865     /**
866      * Bluetooth LE Coded PHY mask. Used to specify LE Coded Physical Channel as one of many
867      * available options in a bitmask.
868      */
869     public static final int PHY_LE_CODED_MASK = 4;
870 
871     /**
872      * No preferred coding when transmitting on the LE Coded PHY.
873      */
874     public static final int PHY_OPTION_NO_PREFERRED = 0;
875 
876     /**
877      * Prefer the S=2 coding to be used when transmitting on the LE Coded PHY.
878      */
879     public static final int PHY_OPTION_S2 = 1;
880 
881     /**
882      * Prefer the S=8 coding to be used when transmitting on the LE Coded PHY.
883      */
884     public static final int PHY_OPTION_S8 = 2;
885 
886 
887     /** @hide */
888     public static final String EXTRA_MAS_INSTANCE =
889             "android.bluetooth.device.extra.MAS_INSTANCE";
890 
891     /**
892      * Lazy initialization. Guaranteed final after first object constructed, or
893      * getService() called.
894      * TODO: Unify implementation of sService amongst BluetoothFoo API's
895      */
896     private static volatile IBluetooth sService;
897 
898     private final String mAddress;
899 
900     /*package*/
901     @UnsupportedAppUsage
getService()902     static IBluetooth getService() {
903         synchronized (BluetoothDevice.class) {
904             if (sService == null) {
905                 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
906                 sService = adapter.getBluetoothService(sStateChangeCallback);
907             }
908         }
909         return sService;
910     }
911 
912     static IBluetoothManagerCallback sStateChangeCallback = new IBluetoothManagerCallback.Stub() {
913 
914         public void onBluetoothServiceUp(IBluetooth bluetoothService)
915                 throws RemoteException {
916             synchronized (BluetoothDevice.class) {
917                 if (sService == null) {
918                     sService = bluetoothService;
919                 }
920             }
921         }
922 
923         public void onBluetoothServiceDown()
924                 throws RemoteException {
925             synchronized (BluetoothDevice.class) {
926                 sService = null;
927             }
928         }
929 
930         public void onBrEdrDown() {
931             if (DBG) Log.d(TAG, "onBrEdrDown: reached BLE ON state");
932         }
933     };
934 
935     /**
936      * Create a new BluetoothDevice
937      * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB",
938      * and is validated in this constructor.
939      *
940      * @param address valid Bluetooth MAC address
941      * @throws RuntimeException Bluetooth is not available on this platform
942      * @throws IllegalArgumentException address is invalid
943      * @hide
944      */
945     @UnsupportedAppUsage
BluetoothDevice(String address)946     /*package*/ BluetoothDevice(String address) {
947         getService();  // ensures sService is initialized
948         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
949             throw new IllegalArgumentException(address + " is not a valid Bluetooth address");
950         }
951 
952         mAddress = address;
953     }
954 
955     @Override
equals(Object o)956     public boolean equals(Object o) {
957         if (o instanceof BluetoothDevice) {
958             return mAddress.equals(((BluetoothDevice) o).getAddress());
959         }
960         return false;
961     }
962 
963     @Override
hashCode()964     public int hashCode() {
965         return mAddress.hashCode();
966     }
967 
968     /**
969      * Returns a string representation of this BluetoothDevice.
970      * <p>Currently this is the Bluetooth hardware address, for example
971      * "00:11:22:AA:BB:CC". However, you should always use {@link #getAddress}
972      * if you explicitly require the Bluetooth hardware address in case the
973      * {@link #toString} representation changes in the future.
974      *
975      * @return string representation of this BluetoothDevice
976      */
977     @Override
toString()978     public String toString() {
979         return mAddress;
980     }
981 
982     @Override
describeContents()983     public int describeContents() {
984         return 0;
985     }
986 
987     public static final @android.annotation.NonNull Parcelable.Creator<BluetoothDevice> CREATOR =
988             new Parcelable.Creator<BluetoothDevice>() {
989                 public BluetoothDevice createFromParcel(Parcel in) {
990                     return new BluetoothDevice(in.readString());
991                 }
992 
993                 public BluetoothDevice[] newArray(int size) {
994                     return new BluetoothDevice[size];
995                 }
996             };
997 
998     @Override
writeToParcel(Parcel out, int flags)999     public void writeToParcel(Parcel out, int flags) {
1000         out.writeString(mAddress);
1001     }
1002 
1003     /**
1004      * Returns the hardware address of this BluetoothDevice.
1005      * <p> For example, "00:11:22:AA:BB:CC".
1006      *
1007      * @return Bluetooth hardware address as string
1008      */
getAddress()1009     public String getAddress() {
1010         if (DBG) Log.d(TAG, "mAddress: " + mAddress);
1011         return mAddress;
1012     }
1013 
1014     /**
1015      * Get the friendly Bluetooth name of the remote device.
1016      *
1017      * <p>The local adapter will automatically retrieve remote names when
1018      * performing a device scan, and will cache them. This method just returns
1019      * the name for this device from the cache.
1020      *
1021      * @return the Bluetooth name, or null if there was a problem.
1022      */
1023     @RequiresPermission(Manifest.permission.BLUETOOTH)
getName()1024     public String getName() {
1025         final IBluetooth service = sService;
1026         if (service == null) {
1027             Log.e(TAG, "BT not enabled. Cannot get Remote Device name");
1028             return null;
1029         }
1030         try {
1031             String name = service.getRemoteName(this);
1032             if (name != null) {
1033                 // remove whitespace characters from the name
1034                 return name
1035                         .replace('\t', ' ')
1036                         .replace('\n', ' ')
1037                         .replace('\r', ' ');
1038             }
1039             return null;
1040         } catch (RemoteException e) {
1041             Log.e(TAG, "", e);
1042         }
1043         return null;
1044     }
1045 
1046     /**
1047      * Get the Bluetooth device type of the remote device.
1048      *
1049      * @return the device type {@link #DEVICE_TYPE_CLASSIC}, {@link #DEVICE_TYPE_LE} {@link
1050      * #DEVICE_TYPE_DUAL}. {@link #DEVICE_TYPE_UNKNOWN} if it's not available
1051      */
1052     @RequiresPermission(Manifest.permission.BLUETOOTH)
getType()1053     public int getType() {
1054         final IBluetooth service = sService;
1055         if (service == null) {
1056             Log.e(TAG, "BT not enabled. Cannot get Remote Device type");
1057             return DEVICE_TYPE_UNKNOWN;
1058         }
1059         try {
1060             return service.getRemoteType(this);
1061         } catch (RemoteException e) {
1062             Log.e(TAG, "", e);
1063         }
1064         return DEVICE_TYPE_UNKNOWN;
1065     }
1066 
1067     /**
1068      * Get the Bluetooth alias of the remote device.
1069      * <p>Alias is the locally modified name of a remote device.
1070      *
1071      * @return the Bluetooth alias, the friendly device name if no alias, or
1072      * null if there was a problem
1073      */
1074     @Nullable
1075     @RequiresPermission(Manifest.permission.BLUETOOTH)
getAlias()1076     public String getAlias() {
1077         final IBluetooth service = sService;
1078         if (service == null) {
1079             Log.e(TAG, "BT not enabled. Cannot get Remote Device Alias");
1080             return null;
1081         }
1082         try {
1083             String alias = service.getRemoteAlias(this);
1084             if (alias == null) {
1085                 return getName();
1086             }
1087             return alias;
1088         } catch (RemoteException e) {
1089             Log.e(TAG, "", e);
1090         }
1091         return null;
1092     }
1093 
1094     /**
1095      * Set the Bluetooth alias of the remote device.
1096      * <p>Alias is the locally modified name of a remote device.
1097      * <p>This methoid overwrites the alias. The changed
1098      * alias is saved in the local storage so that the change
1099      * is preserved over power cycle.
1100      *
1101      * @return true on success, false on error
1102      * @hide
1103      */
1104     @UnsupportedAppUsage
1105     @RequiresPermission(Manifest.permission.BLUETOOTH)
setAlias(@onNull String alias)1106     public boolean setAlias(@NonNull String alias) {
1107         final IBluetooth service = sService;
1108         if (service == null) {
1109             Log.e(TAG, "BT not enabled. Cannot set Remote Device name");
1110             return false;
1111         }
1112         try {
1113             return service.setRemoteAlias(this, alias);
1114         } catch (RemoteException e) {
1115             Log.e(TAG, "", e);
1116         }
1117         return false;
1118     }
1119 
1120     /**
1121      * Get the Bluetooth alias of the remote device.
1122      * If Alias is null, get the Bluetooth name instead.
1123      *
1124      * @return the Bluetooth alias, or null if no alias or there was a problem
1125      * @hide
1126      * @see #getAlias()
1127      * @see #getName()
1128      */
1129     @UnsupportedAppUsage(publicAlternatives = "Use {@link #getName()} instead.")
getAliasName()1130     public String getAliasName() {
1131         String name = getAlias();
1132         if (name == null) {
1133             name = getName();
1134         }
1135         return name;
1136     }
1137 
1138     /**
1139      * Get the most recent identified battery level of this Bluetooth device
1140      *
1141      * @return Battery level in percents from 0 to 100, {@link #BATTERY_LEVEL_BLUETOOTH_OFF} if
1142      * Bluetooth is disabled or {@link #BATTERY_LEVEL_UNKNOWN} if device is disconnected, or does
1143      * not have any battery reporting service, or return value is invalid
1144      * @hide
1145      */
1146     @UnsupportedAppUsage
1147     @RequiresPermission(Manifest.permission.BLUETOOTH)
getBatteryLevel()1148     public int getBatteryLevel() {
1149         final IBluetooth service = sService;
1150         if (service == null) {
1151             Log.e(TAG, "Bluetooth disabled. Cannot get remote device battery level");
1152             return BATTERY_LEVEL_BLUETOOTH_OFF;
1153         }
1154         try {
1155             return service.getBatteryLevel(this);
1156         } catch (RemoteException e) {
1157             Log.e(TAG, "", e);
1158         }
1159         return BATTERY_LEVEL_UNKNOWN;
1160     }
1161 
1162     /**
1163      * Start the bonding (pairing) process with the remote device.
1164      * <p>This is an asynchronous call, it will return immediately. Register
1165      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
1166      * the bonding process completes, and its result.
1167      * <p>Android system services will handle the necessary user interactions
1168      * to confirm and complete the bonding process.
1169      *
1170      * @return false on immediate error, true if bonding will begin
1171      */
1172     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
createBond()1173     public boolean createBond() {
1174         return createBond(TRANSPORT_AUTO);
1175     }
1176 
1177     /**
1178      * Start the bonding (pairing) process with the remote device using the
1179      * specified transport.
1180      *
1181      * <p>This is an asynchronous call, it will return immediately. Register
1182      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
1183      * the bonding process completes, and its result.
1184      * <p>Android system services will handle the necessary user interactions
1185      * to confirm and complete the bonding process.
1186      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
1187      *
1188      * @param transport The transport to use for the pairing procedure.
1189      * @return false on immediate error, true if bonding will begin
1190      * @throws IllegalArgumentException if an invalid transport was specified
1191      * @hide
1192      */
1193     @UnsupportedAppUsage
createBond(int transport)1194     public boolean createBond(int transport) {
1195         return createBondOutOfBand(transport, null);
1196     }
1197 
1198     /**
1199      * Start the bonding (pairing) process with the remote device using the
1200      * Out Of Band mechanism.
1201      *
1202      * <p>This is an asynchronous call, it will return immediately. Register
1203      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
1204      * the bonding process completes, and its result.
1205      *
1206      * <p>Android system services will handle the necessary user interactions
1207      * to confirm and complete the bonding process.
1208      *
1209      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
1210      *
1211      * @param transport - Transport to use
1212      * @param oobData - Out Of Band data
1213      * @return false on immediate error, true if bonding will begin
1214      * @hide
1215      */
createBondOutOfBand(int transport, OobData oobData)1216     public boolean createBondOutOfBand(int transport, OobData oobData) {
1217         final IBluetooth service = sService;
1218         if (service == null) {
1219             Log.w(TAG, "BT not enabled, createBondOutOfBand failed");
1220             return false;
1221         }
1222         try {
1223             return service.createBond(this, transport, oobData);
1224         } catch (RemoteException e) {
1225             Log.e(TAG, "", e);
1226         }
1227         return false;
1228     }
1229 
1230     /**
1231      * Gets whether bonding was initiated locally
1232      *
1233      * @return true if bonding is initiated locally, false otherwise
1234      *
1235      * @hide
1236      */
1237     @UnsupportedAppUsage
1238     @RequiresPermission(Manifest.permission.BLUETOOTH)
isBondingInitiatedLocally()1239     public boolean isBondingInitiatedLocally() {
1240         final IBluetooth service = sService;
1241         if (service == null) {
1242             Log.w(TAG, "BT not enabled, isBondingInitiatedLocally failed");
1243             return false;
1244         }
1245         try {
1246             return service.isBondingInitiatedLocally(this);
1247         } catch (RemoteException e) {
1248             Log.e(TAG, "", e);
1249         }
1250         return false;
1251     }
1252 
1253     /**
1254      * Set the Out Of Band data for a remote device to be used later
1255      * in the pairing mechanism. Users can obtain this data through other
1256      * trusted channels
1257      *
1258      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
1259      *
1260      * @param hash Simple Secure pairing hash
1261      * @param randomizer The random key obtained using OOB
1262      * @return false on error; true otherwise
1263      * @hide
1264      */
setDeviceOutOfBandData(byte[] hash, byte[] randomizer)1265     public boolean setDeviceOutOfBandData(byte[] hash, byte[] randomizer) {
1266         //TODO(BT)
1267       /*
1268       try {
1269         return sService.setDeviceOutOfBandData(this, hash, randomizer);
1270       } catch (RemoteException e) {Log.e(TAG, "", e);} */
1271         return false;
1272     }
1273 
1274     /**
1275      * Cancel an in-progress bonding request started with {@link #createBond}.
1276      *
1277      * @return true on success, false on error
1278      * @hide
1279      */
1280     @SystemApi
1281     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
cancelBondProcess()1282     public boolean cancelBondProcess() {
1283         final IBluetooth service = sService;
1284         if (service == null) {
1285             Log.e(TAG, "BT not enabled. Cannot cancel Remote Device bond");
1286             return false;
1287         }
1288         try {
1289             Log.i(TAG, "cancelBondProcess() for device " + getAddress()
1290                     + " called by pid: " + Process.myPid()
1291                     + " tid: " + Process.myTid());
1292             return service.cancelBondProcess(this);
1293         } catch (RemoteException e) {
1294             Log.e(TAG, "", e);
1295         }
1296         return false;
1297     }
1298 
1299     /**
1300      * Remove bond (pairing) with the remote device.
1301      * <p>Delete the link key associated with the remote device, and
1302      * immediately terminate connections to that device that require
1303      * authentication and encryption.
1304      *
1305      * @return true on success, false on error
1306      * @hide
1307      */
1308     @SystemApi
1309     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
removeBond()1310     public boolean removeBond() {
1311         final IBluetooth service = sService;
1312         if (service == null) {
1313             Log.e(TAG, "BT not enabled. Cannot remove Remote Device bond");
1314             return false;
1315         }
1316         try {
1317             Log.i(TAG, "removeBond() for device " + getAddress()
1318                     + " called by pid: " + Process.myPid()
1319                     + " tid: " + Process.myTid());
1320             return service.removeBond(this);
1321         } catch (RemoteException e) {
1322             Log.e(TAG, "", e);
1323         }
1324         return false;
1325     }
1326 
1327     /**
1328      * Get the bond state of the remote device.
1329      * <p>Possible values for the bond state are:
1330      * {@link #BOND_NONE},
1331      * {@link #BOND_BONDING},
1332      * {@link #BOND_BONDED}.
1333      *
1334      * @return the bond state
1335      */
1336     @RequiresPermission(Manifest.permission.BLUETOOTH)
getBondState()1337     public int getBondState() {
1338         final IBluetooth service = sService;
1339         if (service == null) {
1340             Log.e(TAG, "BT not enabled. Cannot get bond state");
1341             return BOND_NONE;
1342         }
1343         try {
1344             return service.getBondState(this);
1345         } catch (RemoteException e) {
1346             Log.e(TAG, "", e);
1347         }
1348         return BOND_NONE;
1349     }
1350 
1351     /**
1352      * Returns whether there is an open connection to this device.
1353      *
1354      * @return True if there is at least one open connection to this device.
1355      * @hide
1356      */
1357     @SystemApi
1358     @RequiresPermission(Manifest.permission.BLUETOOTH)
isConnected()1359     public boolean isConnected() {
1360         final IBluetooth service = sService;
1361         if (service == null) {
1362             // BT is not enabled, we cannot be connected.
1363             return false;
1364         }
1365         try {
1366             return service.getConnectionState(this) != CONNECTION_STATE_DISCONNECTED;
1367         } catch (RemoteException e) {
1368             Log.e(TAG, "", e);
1369             return false;
1370         }
1371     }
1372 
1373     /**
1374      * Returns whether there is an open connection to this device
1375      * that has been encrypted.
1376      *
1377      * @return True if there is at least one encrypted connection to this device.
1378      * @hide
1379      */
1380     @SystemApi
1381     @RequiresPermission(Manifest.permission.BLUETOOTH)
isEncrypted()1382     public boolean isEncrypted() {
1383         final IBluetooth service = sService;
1384         if (service == null) {
1385             // BT is not enabled, we cannot be connected.
1386             return false;
1387         }
1388         try {
1389             return service.getConnectionState(this) > CONNECTION_STATE_CONNECTED;
1390         } catch (RemoteException e) {
1391             Log.e(TAG, "", e);
1392             return false;
1393         }
1394     }
1395 
1396     /**
1397      * Get the Bluetooth class of the remote device.
1398      *
1399      * @return Bluetooth class object, or null on error
1400      */
1401     @RequiresPermission(Manifest.permission.BLUETOOTH)
getBluetoothClass()1402     public BluetoothClass getBluetoothClass() {
1403         final IBluetooth service = sService;
1404         if (service == null) {
1405             Log.e(TAG, "BT not enabled. Cannot get Bluetooth Class");
1406             return null;
1407         }
1408         try {
1409             int classInt = service.getRemoteClass(this);
1410             if (classInt == BluetoothClass.ERROR) return null;
1411             return new BluetoothClass(classInt);
1412         } catch (RemoteException e) {
1413             Log.e(TAG, "", e);
1414         }
1415         return null;
1416     }
1417 
1418     /**
1419      * Returns the supported features (UUIDs) of the remote device.
1420      *
1421      * <p>This method does not start a service discovery procedure to retrieve the UUIDs
1422      * from the remote device. Instead, the local cached copy of the service
1423      * UUIDs are returned.
1424      * <p>Use {@link #fetchUuidsWithSdp} if fresh UUIDs are desired.
1425      *
1426      * @return the supported features (UUIDs) of the remote device, or null on error
1427      */
1428     @RequiresPermission(Manifest.permission.BLUETOOTH)
getUuids()1429     public ParcelUuid[] getUuids() {
1430         final IBluetooth service = sService;
1431         if (service == null || !isBluetoothEnabled()) {
1432             Log.e(TAG, "BT not enabled. Cannot get remote device Uuids");
1433             return null;
1434         }
1435         try {
1436             return service.getRemoteUuids(this);
1437         } catch (RemoteException e) {
1438             Log.e(TAG, "", e);
1439         }
1440         return null;
1441     }
1442 
1443     /**
1444      * Perform a service discovery on the remote device to get the UUIDs supported.
1445      *
1446      * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent,
1447      * with the UUIDs supported by the remote end. If there is an error
1448      * in getting the SDP records or if the process takes a long time,
1449      * {@link #ACTION_UUID} intent is sent with the UUIDs that is currently
1450      * present in the cache. Clients should use the {@link #getUuids} to get UUIDs
1451      * if service discovery is not to be performed.
1452      *
1453      * @return False if the check fails, True if the process of initiating an ACL connection
1454      * to the remote device was started.
1455      */
1456     @RequiresPermission(Manifest.permission.BLUETOOTH)
fetchUuidsWithSdp()1457     public boolean fetchUuidsWithSdp() {
1458         final IBluetooth service = sService;
1459         if (service == null || !isBluetoothEnabled()) {
1460             Log.e(TAG, "BT not enabled. Cannot fetchUuidsWithSdp");
1461             return false;
1462         }
1463         try {
1464             return service.fetchRemoteUuids(this);
1465         } catch (RemoteException e) {
1466             Log.e(TAG, "", e);
1467         }
1468         return false;
1469     }
1470 
1471     /**
1472      * Perform a service discovery on the remote device to get the SDP records associated
1473      * with the specified UUID.
1474      *
1475      * <p>This API is asynchronous and {@link #ACTION_SDP_RECORD} intent is sent,
1476      * with the SDP records found on the remote end. If there is an error
1477      * in getting the SDP records or if the process takes a long time,
1478      * {@link #ACTION_SDP_RECORD} intent is sent with an status value in
1479      * {@link #EXTRA_SDP_SEARCH_STATUS} different from 0.
1480      * Detailed status error codes can be found by members of the Bluetooth package in
1481      * the AbstractionLayer class.
1482      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
1483      * The SDP record data will be stored in the intent as {@link #EXTRA_SDP_RECORD}.
1484      * The object type will match one of the SdpXxxRecord types, depending on the UUID searched
1485      * for.
1486      *
1487      * @return False if the check fails, True if the process
1488      *               of initiating an ACL connection to the remote device
1489      *               was started.
1490      */
1491     /** @hide */
sdpSearch(ParcelUuid uuid)1492     public boolean sdpSearch(ParcelUuid uuid) {
1493         final IBluetooth service = sService;
1494         if (service == null) {
1495             Log.e(TAG, "BT not enabled. Cannot query remote device sdp records");
1496             return false;
1497         }
1498         try {
1499             return service.sdpSearch(this, uuid);
1500         } catch (RemoteException e) {
1501             Log.e(TAG, "", e);
1502         }
1503         return false;
1504     }
1505 
1506     /**
1507      * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
1508      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
1509      *
1510      * @return true pin has been set false for error
1511      */
setPin(byte[] pin)1512     public boolean setPin(byte[] pin) {
1513         final IBluetooth service = sService;
1514         if (service == null) {
1515             Log.e(TAG, "BT not enabled. Cannot set Remote Device pin");
1516             return false;
1517         }
1518         try {
1519             return service.setPin(this, true, pin.length, pin);
1520         } catch (RemoteException e) {
1521             Log.e(TAG, "", e);
1522         }
1523         return false;
1524     }
1525 
1526     /**
1527      * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
1528      *
1529      * @return true pin has been set false for error
1530      * @hide
1531      */
1532     @UnsupportedAppUsage
1533     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
setPin(@onNull String pin)1534     public boolean setPin(@NonNull String pin) {
1535         byte[] pinBytes = convertPinToBytes(pin);
1536         if (pinBytes == null) {
1537             return false;
1538         }
1539         return setPin(pinBytes);
1540     }
1541 
1542     /**
1543      * Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing.
1544      *
1545      * @return true confirmation has been sent out false for error
1546      */
1547     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
setPairingConfirmation(boolean confirm)1548     public boolean setPairingConfirmation(boolean confirm) {
1549         final IBluetooth service = sService;
1550         if (service == null) {
1551             Log.e(TAG, "BT not enabled. Cannot set pairing confirmation");
1552             return false;
1553         }
1554         try {
1555             return service.setPairingConfirmation(this, confirm);
1556         } catch (RemoteException e) {
1557             Log.e(TAG, "", e);
1558         }
1559         return false;
1560     }
1561 
1562     /**
1563      * Cancels pairing to this device
1564      *
1565      * @return true if pairing cancelled successfully, false otherwise
1566      *
1567      * @hide
1568      */
1569     @UnsupportedAppUsage
1570     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
cancelPairing()1571     public boolean cancelPairing() {
1572         final IBluetooth service = sService;
1573         if (service == null) {
1574             Log.e(TAG, "BT not enabled. Cannot cancel pairing");
1575             return false;
1576         }
1577         try {
1578             return service.cancelBondProcess(this);
1579         } catch (RemoteException e) {
1580             Log.e(TAG, "", e);
1581         }
1582         return false;
1583     }
1584 
isBluetoothEnabled()1585     boolean isBluetoothEnabled() {
1586         boolean ret = false;
1587         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
1588         if (adapter != null && adapter.isEnabled()) {
1589             ret = true;
1590         }
1591         return ret;
1592     }
1593 
1594     /**
1595      * Gets whether the phonebook access is allowed for this bluetooth device
1596      *
1597      * @return Whether the phonebook access is allowed to this device. Can be {@link
1598      * #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
1599      * @hide
1600      */
1601     @UnsupportedAppUsage
1602     @RequiresPermission(Manifest.permission.BLUETOOTH)
getPhonebookAccessPermission()1603     public @AccessPermission int getPhonebookAccessPermission() {
1604         final IBluetooth service = sService;
1605         if (service == null) {
1606             return ACCESS_UNKNOWN;
1607         }
1608         try {
1609             return service.getPhonebookAccessPermission(this);
1610         } catch (RemoteException e) {
1611             Log.e(TAG, "", e);
1612         }
1613         return ACCESS_UNKNOWN;
1614     }
1615 
1616     /**
1617      * Sets whether the {@link BluetoothDevice} enters silence mode. Audio will not
1618      * be routed to the {@link BluetoothDevice} if set to {@code true}.
1619      *
1620      * When the {@link BluetoothDevice} enters silence mode, and the {@link BluetoothDevice}
1621      * is an active device (for A2DP or HFP), the active device for that profile
1622      * will be set to null.
1623      * If the {@link BluetoothDevice} exits silence mode while the A2DP or HFP
1624      * active device is null, the {@link BluetoothDevice} will be set as the
1625      * active device for that profile.
1626      * If the {@link BluetoothDevice} is disconnected, it exits silence mode.
1627      * If the {@link BluetoothDevice} is set as the active device for A2DP or
1628      * HFP, while silence mode is enabled, then the device will exit silence mode.
1629      * If the {@link BluetoothDevice} is in silence mode, AVRCP position change
1630      * event and HFP AG indicators will be disabled.
1631      * If the {@link BluetoothDevice} is not connected with A2DP or HFP, it cannot
1632      * enter silence mode.
1633      *
1634      * <p> Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
1635      *
1636      * @param silence true to enter silence mode, false to exit
1637      * @return true on success, false on error.
1638      * @throws IllegalStateException if Bluetooth is not turned ON.
1639      * @hide
1640      */
1641     @SystemApi
1642     @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
setSilenceMode(boolean silence)1643     public boolean setSilenceMode(boolean silence) {
1644         final IBluetooth service = sService;
1645         if (service == null) {
1646             throw new IllegalStateException("Bluetooth is not turned ON");
1647         }
1648         try {
1649             return service.setSilenceMode(this, silence);
1650         } catch (RemoteException e) {
1651             Log.e(TAG, "setSilenceMode fail", e);
1652             return false;
1653         }
1654     }
1655 
1656     /**
1657      * Check whether the {@link BluetoothDevice} is in silence mode
1658      *
1659      * <p> Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
1660      *
1661      * @return true on device in silence mode, otherwise false.
1662      * @throws IllegalStateException if Bluetooth is not turned ON.
1663      * @hide
1664      */
1665     @SystemApi
1666     @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
isInSilenceMode()1667     public boolean isInSilenceMode() {
1668         final IBluetooth service = sService;
1669         if (service == null) {
1670             throw new IllegalStateException("Bluetooth is not turned ON");
1671         }
1672         try {
1673             return service.getSilenceMode(this);
1674         } catch (RemoteException e) {
1675             Log.e(TAG, "isInSilenceMode fail", e);
1676             return false;
1677         }
1678     }
1679 
1680     /**
1681      * Sets whether the phonebook access is allowed to this device.
1682      *
1683      * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link
1684      * #ACCESS_REJECTED}.
1685      * @return Whether the value has been successfully set.
1686      * @hide
1687      */
1688     @SystemApi
1689     @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
setPhonebookAccessPermission(@ccessPermission int value)1690     public boolean setPhonebookAccessPermission(@AccessPermission int value) {
1691         final IBluetooth service = sService;
1692         if (service == null) {
1693             return false;
1694         }
1695         try {
1696             return service.setPhonebookAccessPermission(this, value);
1697         } catch (RemoteException e) {
1698             Log.e(TAG, "", e);
1699         }
1700         return false;
1701     }
1702 
1703     /**
1704      * Gets whether message access is allowed to this bluetooth device
1705      *
1706      * @return Whether the message access is allowed to this device.
1707      * @hide
1708      */
1709     @UnsupportedAppUsage
1710     @RequiresPermission(Manifest.permission.BLUETOOTH)
getMessageAccessPermission()1711     public @AccessPermission int getMessageAccessPermission() {
1712         final IBluetooth service = sService;
1713         if (service == null) {
1714             return ACCESS_UNKNOWN;
1715         }
1716         try {
1717             return service.getMessageAccessPermission(this);
1718         } catch (RemoteException e) {
1719             Log.e(TAG, "", e);
1720         }
1721         return ACCESS_UNKNOWN;
1722     }
1723 
1724     /**
1725      * Sets whether the message access is allowed to this device.
1726      *
1727      * @param value Can be {@link #ACCESS_UNKNOWN} if the device is unbonded,
1728      * {@link #ACCESS_ALLOWED} if the permission is being granted, or {@link #ACCESS_REJECTED} if
1729      * the permission is not being granted.
1730      * @return Whether the value has been successfully set.
1731      * @hide
1732      */
1733     @SystemApi
1734     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
setMessageAccessPermission(@ccessPermission int value)1735     public boolean setMessageAccessPermission(@AccessPermission int value) {
1736         // Validates param value is one of the accepted constants
1737         if (value != ACCESS_ALLOWED && value != ACCESS_REJECTED && value != ACCESS_UNKNOWN) {
1738             throw new IllegalArgumentException(value + "is not a valid AccessPermission value");
1739         }
1740         final IBluetooth service = sService;
1741         if (service == null) {
1742             return false;
1743         }
1744         try {
1745             return service.setMessageAccessPermission(this, value);
1746         } catch (RemoteException e) {
1747             Log.e(TAG, "", e);
1748         }
1749         return false;
1750     }
1751 
1752     /**
1753      * Gets whether sim access is allowed for this bluetooth device
1754      *
1755      * @return Whether the Sim access is allowed to this device.
1756      * @hide
1757      */
1758     @SystemApi
1759     @RequiresPermission(Manifest.permission.BLUETOOTH)
getSimAccessPermission()1760     public @AccessPermission int getSimAccessPermission() {
1761         final IBluetooth service = sService;
1762         if (service == null) {
1763             return ACCESS_UNKNOWN;
1764         }
1765         try {
1766             return service.getSimAccessPermission(this);
1767         } catch (RemoteException e) {
1768             Log.e(TAG, "", e);
1769         }
1770         return ACCESS_UNKNOWN;
1771     }
1772 
1773     /**
1774      * Sets whether the Sim access is allowed to this device.
1775      *
1776      * @param value Can be {@link #ACCESS_UNKNOWN} if the device is unbonded,
1777      * {@link #ACCESS_ALLOWED} if the permission is being granted, or {@link #ACCESS_REJECTED} if
1778      * the permission is not being granted.
1779      * @return Whether the value has been successfully set.
1780      * @hide
1781      */
1782     @SystemApi
1783     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
setSimAccessPermission(int value)1784     public boolean setSimAccessPermission(int value) {
1785         final IBluetooth service = sService;
1786         if (service == null) {
1787             return false;
1788         }
1789         try {
1790             return service.setSimAccessPermission(this, value);
1791         } catch (RemoteException e) {
1792             Log.e(TAG, "", e);
1793         }
1794         return false;
1795     }
1796 
1797     /**
1798      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
1799      * outgoing connection to this remote device on given channel.
1800      * <p>The remote device will be authenticated and communication on this
1801      * socket will be encrypted.
1802      * <p> Use this socket only if an authenticated socket link is possible.
1803      * Authentication refers to the authentication of the link key to
1804      * prevent man-in-the-middle type of attacks.
1805      * For example, for Bluetooth 2.1 devices, if any of the devices does not
1806      * have an input and output capability or just has the ability to
1807      * display a numeric key, a secure socket connection is not possible.
1808      * In such a case, use {@link createInsecureRfcommSocket}.
1809      * For more details, refer to the Security Model section 5.2 (vol 3) of
1810      * Bluetooth Core Specification version 2.1 + EDR.
1811      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
1812      * connection.
1813      * <p>Valid RFCOMM channels are in range 1 to 30.
1814      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1815      *
1816      * @param channel RFCOMM channel to connect to
1817      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
1818      * @throws IOException on error, for example Bluetooth not available, or insufficient
1819      * permissions
1820      * @hide
1821      */
1822     @UnsupportedAppUsage
createRfcommSocket(int channel)1823     public BluetoothSocket createRfcommSocket(int channel) throws IOException {
1824         if (!isBluetoothEnabled()) {
1825             Log.e(TAG, "Bluetooth is not enabled");
1826             throw new IOException();
1827         }
1828         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel,
1829                 null);
1830     }
1831 
1832     /**
1833      * Create an L2cap {@link BluetoothSocket} ready to start a secure
1834      * outgoing connection to this remote device on given channel.
1835      * <p>The remote device will be authenticated and communication on this
1836      * socket will be encrypted.
1837      * <p> Use this socket only if an authenticated socket link is possible.
1838      * Authentication refers to the authentication of the link key to
1839      * prevent man-in-the-middle type of attacks.
1840      * For example, for Bluetooth 2.1 devices, if any of the devices does not
1841      * have an input and output capability or just has the ability to
1842      * display a numeric key, a secure socket connection is not possible.
1843      * In such a case, use {@link createInsecureRfcommSocket}.
1844      * For more details, refer to the Security Model section 5.2 (vol 3) of
1845      * Bluetooth Core Specification version 2.1 + EDR.
1846      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
1847      * connection.
1848      * <p>Valid L2CAP PSM channels are in range 1 to 2^16.
1849      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1850      *
1851      * @param channel L2cap PSM/channel to connect to
1852      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
1853      * @throws IOException on error, for example Bluetooth not available, or insufficient
1854      * permissions
1855      * @hide
1856      */
createL2capSocket(int channel)1857     public BluetoothSocket createL2capSocket(int channel) throws IOException {
1858         return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, true, true, this, channel,
1859                 null);
1860     }
1861 
1862     /**
1863      * Create an L2cap {@link BluetoothSocket} ready to start an insecure
1864      * outgoing connection to this remote device on given channel.
1865      * <p>The remote device will be not authenticated and communication on this
1866      * socket will not be encrypted.
1867      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
1868      * connection.
1869      * <p>Valid L2CAP PSM channels are in range 1 to 2^16.
1870      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1871      *
1872      * @param channel L2cap PSM/channel to connect to
1873      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
1874      * @throws IOException on error, for example Bluetooth not available, or insufficient
1875      * permissions
1876      * @hide
1877      */
createInsecureL2capSocket(int channel)1878     public BluetoothSocket createInsecureL2capSocket(int channel) throws IOException {
1879         return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, false, false, this, channel,
1880                 null);
1881     }
1882 
1883     /**
1884      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
1885      * outgoing connection to this remote device using SDP lookup of uuid.
1886      * <p>This is designed to be used with {@link
1887      * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer
1888      * Bluetooth applications.
1889      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
1890      * connection. This will also perform an SDP lookup of the given uuid to
1891      * determine which channel to connect to.
1892      * <p>The remote device will be authenticated and communication on this
1893      * socket will be encrypted.
1894      * <p> Use this socket only if an authenticated socket link is possible.
1895      * Authentication refers to the authentication of the link key to
1896      * prevent man-in-the-middle type of attacks.
1897      * For example, for Bluetooth 2.1 devices, if any of the devices does not
1898      * have an input and output capability or just has the ability to
1899      * display a numeric key, a secure socket connection is not possible.
1900      * In such a case, use {@link #createInsecureRfcommSocketToServiceRecord}.
1901      * For more details, refer to the Security Model section 5.2 (vol 3) of
1902      * Bluetooth Core Specification version 2.1 + EDR.
1903      * <p>Hint: If you are connecting to a Bluetooth serial board then try
1904      * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
1905      * However if you are connecting to an Android peer then please generate
1906      * your own unique UUID.
1907      *
1908      * @param uuid service record uuid to lookup RFCOMM channel
1909      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
1910      * @throws IOException on error, for example Bluetooth not available, or insufficient
1911      * permissions
1912      */
1913     @RequiresPermission(Manifest.permission.BLUETOOTH)
createRfcommSocketToServiceRecord(UUID uuid)1914     public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {
1915         if (!isBluetoothEnabled()) {
1916             Log.e(TAG, "Bluetooth is not enabled");
1917             throw new IOException();
1918         }
1919 
1920         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1,
1921                 new ParcelUuid(uuid));
1922     }
1923 
1924     /**
1925      * Create an RFCOMM {@link BluetoothSocket} socket ready to start an insecure
1926      * outgoing connection to this remote device using SDP lookup of uuid.
1927      * <p> The communication channel will not have an authenticated link key
1928      * i.e it will be subject to man-in-the-middle attacks. For Bluetooth 2.1
1929      * devices, the link key will be encrypted, as encryption is mandatory.
1930      * For legacy devices (pre Bluetooth 2.1 devices) the link key will
1931      * be not be encrypted. Use {@link #createRfcommSocketToServiceRecord} if an
1932      * encrypted and authenticated communication channel is desired.
1933      * <p>This is designed to be used with {@link
1934      * BluetoothAdapter#listenUsingInsecureRfcommWithServiceRecord} for peer-peer
1935      * Bluetooth applications.
1936      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
1937      * connection. This will also perform an SDP lookup of the given uuid to
1938      * determine which channel to connect to.
1939      * <p>The remote device will be authenticated and communication on this
1940      * socket will be encrypted.
1941      * <p>Hint: If you are connecting to a Bluetooth serial board then try
1942      * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
1943      * However if you are connecting to an Android peer then please generate
1944      * your own unique UUID.
1945      *
1946      * @param uuid service record uuid to lookup RFCOMM channel
1947      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
1948      * @throws IOException on error, for example Bluetooth not available, or insufficient
1949      * permissions
1950      */
1951     @RequiresPermission(Manifest.permission.BLUETOOTH)
createInsecureRfcommSocketToServiceRecord(UUID uuid)1952     public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException {
1953         if (!isBluetoothEnabled()) {
1954             Log.e(TAG, "Bluetooth is not enabled");
1955             throw new IOException();
1956         }
1957         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1,
1958                 new ParcelUuid(uuid));
1959     }
1960 
1961     /**
1962      * Construct an insecure RFCOMM socket ready to start an outgoing
1963      * connection.
1964      * Call #connect on the returned #BluetoothSocket to begin the connection.
1965      * The remote device will not be authenticated and communication on this
1966      * socket will not be encrypted.
1967      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
1968      *
1969      * @param port remote port
1970      * @return An RFCOMM BluetoothSocket
1971      * @throws IOException On error, for example Bluetooth not available, or insufficient
1972      * permissions.
1973      * @hide
1974      */
1975     @UnsupportedAppUsage(publicAlternatives = "Use "
1976             + "{@link #createInsecureRfcommSocketToServiceRecord} instead.")
createInsecureRfcommSocket(int port)1977     public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
1978         if (!isBluetoothEnabled()) {
1979             Log.e(TAG, "Bluetooth is not enabled");
1980             throw new IOException();
1981         }
1982         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port,
1983                 null);
1984     }
1985 
1986     /**
1987      * Construct a SCO socket ready to start an outgoing connection.
1988      * Call #connect on the returned #BluetoothSocket to begin the connection.
1989      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
1990      *
1991      * @return a SCO BluetoothSocket
1992      * @throws IOException on error, for example Bluetooth not available, or insufficient
1993      * permissions.
1994      * @hide
1995      */
1996     @UnsupportedAppUsage
createScoSocket()1997     public BluetoothSocket createScoSocket() throws IOException {
1998         if (!isBluetoothEnabled()) {
1999             Log.e(TAG, "Bluetooth is not enabled");
2000             throw new IOException();
2001         }
2002         return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null);
2003     }
2004 
2005     /**
2006      * Check that a pin is valid and convert to byte array.
2007      *
2008      * Bluetooth pin's are 1 to 16 bytes of UTF-8 characters.
2009      *
2010      * @param pin pin as java String
2011      * @return the pin code as a UTF-8 byte array, or null if it is an invalid Bluetooth pin.
2012      * @hide
2013      */
2014     @UnsupportedAppUsage
convertPinToBytes(String pin)2015     public static byte[] convertPinToBytes(String pin) {
2016         if (pin == null) {
2017             return null;
2018         }
2019         byte[] pinBytes;
2020         try {
2021             pinBytes = pin.getBytes("UTF-8");
2022         } catch (UnsupportedEncodingException uee) {
2023             Log.e(TAG, "UTF-8 not supported?!?");  // this should not happen
2024             return null;
2025         }
2026         if (pinBytes.length <= 0 || pinBytes.length > 16) {
2027             return null;
2028         }
2029         return pinBytes;
2030     }
2031 
2032     /**
2033      * Connect to GATT Server hosted by this device. Caller acts as GATT client.
2034      * The callback is used to deliver results to Caller, such as connection status as well
2035      * as any further GATT client operations.
2036      * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
2037      * GATT client operations.
2038      *
2039      * @param callback GATT callback handler that will receive asynchronous callbacks.
2040      * @param autoConnect Whether to directly connect to the remote device (false) or to
2041      * automatically connect as soon as the remote device becomes available (true).
2042      * @throws IllegalArgumentException if callback is null
2043      */
connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback)2044     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
2045             BluetoothGattCallback callback) {
2046         return (connectGatt(context, autoConnect, callback, TRANSPORT_AUTO));
2047     }
2048 
2049     /**
2050      * Connect to GATT Server hosted by this device. Caller acts as GATT client.
2051      * The callback is used to deliver results to Caller, such as connection status as well
2052      * as any further GATT client operations.
2053      * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
2054      * GATT client operations.
2055      *
2056      * @param callback GATT callback handler that will receive asynchronous callbacks.
2057      * @param autoConnect Whether to directly connect to the remote device (false) or to
2058      * automatically connect as soon as the remote device becomes available (true).
2059      * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
2060      * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
2061      * BluetoothDevice#TRANSPORT_LE}
2062      * @throws IllegalArgumentException if callback is null
2063      */
connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport)2064     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
2065             BluetoothGattCallback callback, int transport) {
2066         return (connectGatt(context, autoConnect, callback, transport, PHY_LE_1M_MASK));
2067     }
2068 
2069     /**
2070      * Connect to GATT Server hosted by this device. Caller acts as GATT client.
2071      * The callback is used to deliver results to Caller, such as connection status as well
2072      * as any further GATT client operations.
2073      * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
2074      * GATT client operations.
2075      *
2076      * @param callback GATT callback handler that will receive asynchronous callbacks.
2077      * @param autoConnect Whether to directly connect to the remote device (false) or to
2078      * automatically connect as soon as the remote device becomes available (true).
2079      * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
2080      * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
2081      * BluetoothDevice#TRANSPORT_LE}
2082      * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link
2083      * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, and {@link
2084      * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect}
2085      * is set to true.
2086      * @throws NullPointerException if callback is null
2087      */
connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, int phy)2088     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
2089             BluetoothGattCallback callback, int transport, int phy) {
2090         return connectGatt(context, autoConnect, callback, transport, phy, null);
2091     }
2092 
2093     /**
2094      * Connect to GATT Server hosted by this device. Caller acts as GATT client.
2095      * The callback is used to deliver results to Caller, such as connection status as well
2096      * as any further GATT client operations.
2097      * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
2098      * GATT client operations.
2099      *
2100      * @param callback GATT callback handler that will receive asynchronous callbacks.
2101      * @param autoConnect Whether to directly connect to the remote device (false) or to
2102      * automatically connect as soon as the remote device becomes available (true).
2103      * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
2104      * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
2105      * BluetoothDevice#TRANSPORT_LE}
2106      * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link
2107      * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, an d{@link
2108      * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect}
2109      * is set to true.
2110      * @param handler The handler to use for the callback. If {@code null}, callbacks will happen on
2111      * an un-specified background thread.
2112      * @throws NullPointerException if callback is null
2113      */
connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, int phy, Handler handler)2114     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
2115             BluetoothGattCallback callback, int transport, int phy,
2116             Handler handler) {
2117         return connectGatt(context, autoConnect, callback, transport, false, phy, handler);
2118     }
2119 
2120     /**
2121      * Connect to GATT Server hosted by this device. Caller acts as GATT client.
2122      * The callback is used to deliver results to Caller, such as connection status as well
2123      * as any further GATT client operations.
2124      * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
2125      * GATT client operations.
2126      *
2127      * @param callback GATT callback handler that will receive asynchronous callbacks.
2128      * @param autoConnect Whether to directly connect to the remote device (false) or to
2129      * automatically connect as soon as the remote device becomes available (true).
2130      * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
2131      * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
2132      * BluetoothDevice#TRANSPORT_LE}
2133      * @param opportunistic Whether this GATT client is opportunistic. An opportunistic GATT client
2134      * does not hold a GATT connection. It automatically disconnects when no other GATT connections
2135      * are active for the remote device.
2136      * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link
2137      * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, an d{@link
2138      * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect}
2139      * is set to true.
2140      * @param handler The handler to use for the callback. If {@code null}, callbacks will happen on
2141      * an un-specified background thread.
2142      * @return A BluetoothGatt instance. You can use BluetoothGatt to conduct GATT client
2143      * operations.
2144      * @hide
2145      */
2146     @UnsupportedAppUsage
connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback, int transport, boolean opportunistic, int phy, Handler handler)2147     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
2148             BluetoothGattCallback callback, int transport,
2149             boolean opportunistic, int phy, Handler handler) {
2150         if (callback == null) {
2151             throw new NullPointerException("callback is null");
2152         }
2153 
2154         // TODO(Bluetooth) check whether platform support BLE
2155         //     Do the check here or in GattServer?
2156         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2157         IBluetoothManager managerService = adapter.getBluetoothManager();
2158         try {
2159             IBluetoothGatt iGatt = managerService.getBluetoothGatt();
2160             if (iGatt == null) {
2161                 // BLE is not supported
2162                 return null;
2163             }
2164             BluetoothGatt gatt = new BluetoothGatt(iGatt, this, transport, opportunistic, phy);
2165             gatt.connect(autoConnect, callback, handler);
2166             return gatt;
2167         } catch (RemoteException e) {
2168             Log.e(TAG, "", e);
2169         }
2170         return null;
2171     }
2172 
2173     /**
2174      * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can
2175      * be used to start a secure outgoing connection to the remote device with the same dynamic
2176      * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only.
2177      * <p>This is designed to be used with {@link BluetoothAdapter#listenUsingL2capChannel()} for
2178      * peer-peer Bluetooth applications.
2179      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection.
2180      * <p>Application using this API is responsible for obtaining PSM value from remote device.
2181      * <p>The remote device will be authenticated and communication on this socket will be
2182      * encrypted.
2183      * <p> Use this socket if an authenticated socket link is possible. Authentication refers
2184      * to the authentication of the link key to prevent man-in-the-middle type of attacks.
2185      *
2186      * @param psm dynamic PSM value from remote device
2187      * @return a CoC #BluetoothSocket ready for an outgoing connection
2188      * @throws IOException on error, for example Bluetooth not available, or insufficient
2189      * permissions
2190      */
2191     @RequiresPermission(Manifest.permission.BLUETOOTH)
createL2capChannel(int psm)2192     public @NonNull BluetoothSocket createL2capChannel(int psm) throws IOException {
2193         if (!isBluetoothEnabled()) {
2194             Log.e(TAG, "createL2capChannel: Bluetooth is not enabled");
2195             throw new IOException();
2196         }
2197         if (DBG) Log.d(TAG, "createL2capChannel: psm=" + psm);
2198         return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, true, true, this, psm,
2199                 null);
2200     }
2201 
2202     /**
2203      * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can
2204      * be used to start a secure outgoing connection to the remote device with the same dynamic
2205      * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only.
2206      * <p>This is designed to be used with {@link
2207      * BluetoothAdapter#listenUsingInsecureL2capChannel()} for peer-peer Bluetooth applications.
2208      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection.
2209      * <p>Application using this API is responsible for obtaining PSM value from remote device.
2210      * <p> The communication channel may not have an authenticated link key, i.e. it may be subject
2211      * to man-in-the-middle attacks. Use {@link #createL2capChannel(int)} if an encrypted and
2212      * authenticated communication channel is possible.
2213      *
2214      * @param psm dynamic PSM value from remote device
2215      * @return a CoC #BluetoothSocket ready for an outgoing connection
2216      * @throws IOException on error, for example Bluetooth not available, or insufficient
2217      * permissions
2218      */
2219     @RequiresPermission(Manifest.permission.BLUETOOTH)
createInsecureL2capChannel(int psm)2220     public @NonNull BluetoothSocket createInsecureL2capChannel(int psm) throws IOException {
2221         if (!isBluetoothEnabled()) {
2222             Log.e(TAG, "createInsecureL2capChannel: Bluetooth is not enabled");
2223             throw new IOException();
2224         }
2225         if (DBG) {
2226             Log.d(TAG, "createInsecureL2capChannel: psm=" + psm);
2227         }
2228         return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, false, false, this, psm,
2229                 null);
2230     }
2231 
2232     /**
2233      * Set a keyed metadata of this {@link BluetoothDevice} to a
2234      * {@link String} value.
2235      * Only bonded devices's metadata will be persisted across Bluetooth
2236      * restart.
2237      * Metadata will be removed when the device's bond state is moved to
2238      * {@link #BOND_NONE}.
2239      *
2240      * @param key must be within the list of BluetoothDevice.METADATA_*
2241      * @param value a byte array data to set for key. Must be less than
2242      * {@link BluetoothAdapter#METADATA_MAX_LENGTH} characters in length
2243      * @return true on success, false on error
2244      * @hide
2245     */
2246     @SystemApi
2247     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
setMetadata(int key, @NonNull byte[] value)2248     public boolean setMetadata(int key, @NonNull byte[] value) {
2249         final IBluetooth service = sService;
2250         if (service == null) {
2251             Log.e(TAG, "Bluetooth is not enabled. Cannot set metadata");
2252             return false;
2253         }
2254         if (value.length > METADATA_MAX_LENGTH) {
2255             throw new IllegalArgumentException("value length is " + value.length
2256                     + ", should not over " + METADATA_MAX_LENGTH);
2257         }
2258         try {
2259             return service.setMetadata(this, key, value);
2260         } catch (RemoteException e) {
2261             Log.e(TAG, "setMetadata fail", e);
2262             return false;
2263         }
2264     }
2265 
2266     /**
2267      * Get a keyed metadata for this {@link BluetoothDevice} as {@link String}
2268      *
2269      * @param key must be within the list of BluetoothDevice.METADATA_*
2270      * @return Metadata of the key as byte array, null on error or not found
2271      * @hide
2272      */
2273     @SystemApi
2274     @Nullable
2275     @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
getMetadata(int key)2276     public byte[] getMetadata(int key) {
2277         final IBluetooth service = sService;
2278         if (service == null) {
2279             Log.e(TAG, "Bluetooth is not enabled. Cannot get metadata");
2280             return null;
2281         }
2282         try {
2283             return service.getMetadata(this, key);
2284         } catch (RemoteException e) {
2285             Log.e(TAG, "getMetadata fail", e);
2286             return null;
2287         }
2288     }
2289 }
2290