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