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