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