• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009-2016 The Android Open Source Project
3  * Copyright (C) 2015 Samsung LSI
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package android.bluetooth;
19 
20 import android.Manifest;
21 import android.annotation.IntDef;
22 import android.annotation.RequiresPermission;
23 import android.annotation.SdkConstant;
24 import android.annotation.SdkConstant.SdkConstantType;
25 import android.annotation.SystemApi;
26 import android.bluetooth.le.BluetoothLeAdvertiser;
27 import android.bluetooth.le.BluetoothLeScanner;
28 import android.bluetooth.le.ScanCallback;
29 import android.bluetooth.le.ScanFilter;
30 import android.bluetooth.le.ScanRecord;
31 import android.bluetooth.le.ScanResult;
32 import android.bluetooth.le.ScanSettings;
33 import android.content.Context;
34 import android.os.BatteryStats;
35 import android.os.Binder;
36 import android.os.IBinder;
37 import android.os.ParcelUuid;
38 import android.os.RemoteException;
39 import android.os.ResultReceiver;
40 import android.os.ServiceManager;
41 import android.os.SynchronousResultReceiver;
42 import android.os.SystemProperties;
43 import android.util.Log;
44 import android.util.Pair;
45 
46 import java.io.IOException;
47 import java.lang.annotation.Retention;
48 import java.lang.annotation.RetentionPolicy;
49 import java.util.ArrayList;
50 import java.util.Arrays;
51 import java.util.Collections;
52 import java.util.HashMap;
53 import java.util.HashSet;
54 import java.util.List;
55 import java.util.Locale;
56 import java.util.Map;
57 import java.util.Set;
58 import java.util.UUID;
59 import java.util.concurrent.TimeoutException;
60 import java.util.concurrent.locks.ReentrantReadWriteLock;
61 
62 /**
63  * Represents the local device Bluetooth adapter. The {@link BluetoothAdapter}
64  * lets you perform fundamental Bluetooth tasks, such as initiate
65  * device discovery, query a list of bonded (paired) devices,
66  * instantiate a {@link BluetoothDevice} using a known MAC address, and create
67  * a {@link BluetoothServerSocket} to listen for connection requests from other
68  * devices, and start a scan for Bluetooth LE devices.
69  *
70  * <p>To get a {@link BluetoothAdapter} representing the local Bluetooth
71  * adapter, when running on JELLY_BEAN_MR1 and below, call the
72  * static {@link #getDefaultAdapter} method; when running on JELLY_BEAN_MR2 and
73  * higher, call {@link BluetoothManager#getAdapter}.
74  * Fundamentally, this is your starting point for all
75  * Bluetooth actions. Once you have the local adapter, you can get a set of
76  * {@link BluetoothDevice} objects representing all paired devices with
77  * {@link #getBondedDevices()}; start device discovery with
78  * {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to
79  * listen for incoming connection requests with
80  * {@link #listenUsingRfcommWithServiceRecord(String,UUID)}; or start a scan for
81  * Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}.
82  *
83  * <p>This class is thread safe.
84  *
85  * <p class="note"><strong>Note:</strong>
86  * Most methods require the {@link android.Manifest.permission#BLUETOOTH}
87  * permission and some also require the
88  * {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
89  *
90  * <div class="special reference">
91  * <h3>Developer Guides</h3>
92  * <p>
93  *  For more information about using Bluetooth, read the <a href=
94  * "{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer
95  * guide.
96  * </p>
97  * </div>
98  *
99  * {@see BluetoothDevice}
100  * {@see BluetoothServerSocket}
101  */
102 public final class BluetoothAdapter {
103     private static final String TAG = "BluetoothAdapter";
104     private static final boolean DBG = true;
105     private static final boolean VDBG = false;
106 
107     /**
108      * Default MAC address reported to a client that does not have the
109      * android.permission.LOCAL_MAC_ADDRESS permission.
110      *
111      * @hide
112      */
113     public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00";
114 
115     /**
116      * Sentinel error value for this class. Guaranteed to not equal any other
117      * integer constant in this class. Provided as a convenience for functions
118      * that require a sentinel error value, for example:
119      * <p><code>Intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
120      * BluetoothAdapter.ERROR)</code>
121      */
122     public static final int ERROR = Integer.MIN_VALUE;
123 
124     /**
125      * Broadcast Action: The state of the local Bluetooth adapter has been
126      * changed.
127      * <p>For example, Bluetooth has been turned on or off.
128      * <p>Always contains the extra fields {@link #EXTRA_STATE} and {@link
129      * #EXTRA_PREVIOUS_STATE} containing the new and old states
130      * respectively.
131      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
132      */
133     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
134     public static final String ACTION_STATE_CHANGED =
135             "android.bluetooth.adapter.action.STATE_CHANGED";
136 
137     /**
138      * Used as an int extra field in {@link #ACTION_STATE_CHANGED}
139      * intents to request the current power state. Possible values are:
140      * {@link #STATE_OFF},
141      * {@link #STATE_TURNING_ON},
142      * {@link #STATE_ON},
143      * {@link #STATE_TURNING_OFF},
144      */
145     public static final String EXTRA_STATE =
146             "android.bluetooth.adapter.extra.STATE";
147     /**
148      * Used as an int extra field in {@link #ACTION_STATE_CHANGED}
149      * intents to request the previous power state. Possible values are:
150      * {@link #STATE_OFF},
151      * {@link #STATE_TURNING_ON},
152      * {@link #STATE_ON},
153      * {@link #STATE_TURNING_OFF}
154      */
155     public static final String EXTRA_PREVIOUS_STATE =
156             "android.bluetooth.adapter.extra.PREVIOUS_STATE";
157 
158     /** @hide */
159     @IntDef({STATE_OFF, STATE_TURNING_ON, STATE_ON, STATE_TURNING_OFF, STATE_BLE_TURNING_ON,
160             STATE_BLE_ON, STATE_BLE_TURNING_OFF})
161     @Retention(RetentionPolicy.SOURCE)
162     public @interface AdapterState {}
163 
164     /**
165      * Indicates the local Bluetooth adapter is off.
166      */
167     public static final int STATE_OFF = 10;
168     /**
169      * Indicates the local Bluetooth adapter is turning on. However local
170      * clients should wait for {@link #STATE_ON} before attempting to
171      * use the adapter.
172      */
173     public static final int STATE_TURNING_ON = 11;
174     /**
175      * Indicates the local Bluetooth adapter is on, and ready for use.
176      */
177     public static final int STATE_ON = 12;
178     /**
179      * Indicates the local Bluetooth adapter is turning off. Local clients
180      * should immediately attempt graceful disconnection of any remote links.
181      */
182     public static final int STATE_TURNING_OFF = 13;
183 
184     /**
185      * Indicates the local Bluetooth adapter is turning Bluetooth LE mode on.
186      * @hide
187      */
188     public static final int STATE_BLE_TURNING_ON = 14;
189 
190     /**
191      * Indicates the local Bluetooth adapter is in LE only mode.
192      * @hide
193      */
194     public static final int STATE_BLE_ON = 15;
195 
196     /**
197      * Indicates the local Bluetooth adapter is turning off LE only mode.
198      * @hide
199      */
200     public static final int STATE_BLE_TURNING_OFF = 16;
201 
202     /**
203      * Activity Action: Show a system activity that requests discoverable mode.
204      * This activity will also request the user to turn on Bluetooth if it
205      * is not currently enabled.
206      * <p>Discoverable mode is equivalent to {@link
207      * #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. It allows remote devices to see
208      * this Bluetooth adapter when they perform a discovery.
209      * <p>For privacy, Android is not discoverable by default.
210      * <p>The sender of this Intent can optionally use extra field {@link
211      * #EXTRA_DISCOVERABLE_DURATION} to request the duration of
212      * discoverability. Currently the default duration is 120 seconds, and
213      * maximum duration is capped at 300 seconds for each request.
214      * <p>Notification of the result of this activity is posted using the
215      * {@link android.app.Activity#onActivityResult} callback. The
216      * <code>resultCode</code>
217      * will be the duration (in seconds) of discoverability or
218      * {@link android.app.Activity#RESULT_CANCELED} if the user rejected
219      * discoverability or an error has occurred.
220      * <p>Applications can also listen for {@link #ACTION_SCAN_MODE_CHANGED}
221      * for global notification whenever the scan mode changes. For example, an
222      * application can be notified when the device has ended discoverability.
223      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
224      */
225     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
226     public static final String ACTION_REQUEST_DISCOVERABLE =
227             "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
228 
229     /**
230      * Used as an optional int extra field in {@link
231      * #ACTION_REQUEST_DISCOVERABLE} intents to request a specific duration
232      * for discoverability in seconds. The current default is 120 seconds, and
233      * requests over 300 seconds will be capped. These values could change.
234      */
235     public static final String EXTRA_DISCOVERABLE_DURATION =
236             "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION";
237 
238     /**
239      * Activity Action: Show a system activity that allows the user to turn on
240      * Bluetooth.
241      * <p>This system activity will return once Bluetooth has completed turning
242      * on, or the user has decided not to turn Bluetooth on.
243      * <p>Notification of the result of this activity is posted using the
244      * {@link android.app.Activity#onActivityResult} callback. The
245      * <code>resultCode</code>
246      * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been
247      * turned on or {@link android.app.Activity#RESULT_CANCELED} if the user
248      * has rejected the request or an error has occurred.
249      * <p>Applications can also listen for {@link #ACTION_STATE_CHANGED}
250      * for global notification whenever Bluetooth is turned on or off.
251      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
252      */
253     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
254     public static final String ACTION_REQUEST_ENABLE =
255             "android.bluetooth.adapter.action.REQUEST_ENABLE";
256 
257     /**
258      * Activity Action: Show a system activity that allows user to enable BLE scans even when
259      * Bluetooth is turned off.<p>
260      *
261      * Notification of result of this activity is posted using
262      * {@link android.app.Activity#onActivityResult}. The <code>resultCode</code> will be
263      * {@link android.app.Activity#RESULT_OK} if BLE scan always available setting is turned on or
264      * {@link android.app.Activity#RESULT_CANCELED} if the user has rejected the request or an
265      * error occurred.
266      *
267      * @hide
268      */
269     @SystemApi
270     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
271     public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE =
272             "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
273 
274     /**
275      * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter
276      * has changed.
277      * <p>Always contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link
278      * #EXTRA_PREVIOUS_SCAN_MODE} containing the new and old scan modes
279      * respectively.
280      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
281      */
282     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
283     public static final String ACTION_SCAN_MODE_CHANGED =
284             "android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
285 
286     /**
287      * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED}
288      * intents to request the current scan mode. Possible values are:
289      * {@link #SCAN_MODE_NONE},
290      * {@link #SCAN_MODE_CONNECTABLE},
291      * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE},
292      */
293     public static final String EXTRA_SCAN_MODE = "android.bluetooth.adapter.extra.SCAN_MODE";
294     /**
295      * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED}
296      * intents to request the previous scan mode. Possible values are:
297      * {@link #SCAN_MODE_NONE},
298      * {@link #SCAN_MODE_CONNECTABLE},
299      * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE},
300      */
301     public static final String EXTRA_PREVIOUS_SCAN_MODE =
302             "android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE";
303 
304     /** @hide */
305     @IntDef({SCAN_MODE_NONE, SCAN_MODE_CONNECTABLE, SCAN_MODE_CONNECTABLE_DISCOVERABLE})
306     @Retention(RetentionPolicy.SOURCE)
307     public @interface ScanMode {}
308 
309     /**
310      * Indicates that both inquiry scan and page scan are disabled on the local
311      * Bluetooth adapter. Therefore this device is neither discoverable
312      * nor connectable from remote Bluetooth devices.
313      */
314     public static final int SCAN_MODE_NONE = 20;
315     /**
316      * Indicates that inquiry scan is disabled, but page scan is enabled on the
317      * local Bluetooth adapter. Therefore this device is not discoverable from
318      * remote Bluetooth devices, but is connectable from remote devices that
319      * have previously discovered this device.
320      */
321     public static final int SCAN_MODE_CONNECTABLE = 21;
322     /**
323      * Indicates that both inquiry scan and page scan are enabled on the local
324      * Bluetooth adapter. Therefore this device is both discoverable and
325      * connectable from remote Bluetooth devices.
326      */
327     public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23;
328 
329     /**
330      * Broadcast Action: The local Bluetooth adapter has started the remote
331      * device discovery process.
332      * <p>This usually involves an inquiry scan of about 12 seconds, followed
333      * by a page scan of each new device to retrieve its Bluetooth name.
334      * <p>Register for {@link BluetoothDevice#ACTION_FOUND} to be notified as
335      * remote Bluetooth devices are found.
336      * <p>Device discovery is a heavyweight procedure. New connections to
337      * remote Bluetooth devices should not be attempted while discovery is in
338      * progress, and existing connections will experience limited bandwidth
339      * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
340      * discovery.
341      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
342      */
343     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
344     public static final String ACTION_DISCOVERY_STARTED =
345             "android.bluetooth.adapter.action.DISCOVERY_STARTED";
346     /**
347      * Broadcast Action: The local Bluetooth adapter has finished the device
348      * discovery process.
349      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
350      */
351     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
352     public static final String ACTION_DISCOVERY_FINISHED =
353             "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
354 
355     /**
356      * Broadcast Action: The local Bluetooth adapter has changed its friendly
357      * Bluetooth name.
358      * <p>This name is visible to remote Bluetooth devices.
359      * <p>Always contains the extra field {@link #EXTRA_LOCAL_NAME} containing
360      * the name.
361      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
362      */
363     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
364     public static final String ACTION_LOCAL_NAME_CHANGED =
365             "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED";
366     /**
367      * Used as a String extra field in {@link #ACTION_LOCAL_NAME_CHANGED}
368      * intents to request the local Bluetooth name.
369      */
370     public static final String EXTRA_LOCAL_NAME = "android.bluetooth.adapter.extra.LOCAL_NAME";
371 
372     /**
373      * Intent used to broadcast the change in connection state of the local
374      * Bluetooth adapter to a profile of the remote device. When the adapter is
375      * not connected to any profiles of any remote devices and it attempts a
376      * connection to a profile this intent will sent. Once connected, this intent
377      * will not be sent for any more connection attempts to any profiles of any
378      * remote device. When the adapter disconnects from the last profile its
379      * connected to of any remote device, this intent will be sent.
380      *
381      * <p> This intent is useful for applications that are only concerned about
382      * whether the local adapter is connected to any profile of any device and
383      * are not really concerned about which profile. For example, an application
384      * which displays an icon to display whether Bluetooth is connected or not
385      * can use this intent.
386      *
387      * <p>This intent will have 3 extras:
388      * {@link #EXTRA_CONNECTION_STATE} - The current connection state.
389      * {@link #EXTRA_PREVIOUS_CONNECTION_STATE}- The previous connection state.
390      * {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
391      *
392      * {@link #EXTRA_CONNECTION_STATE} or {@link #EXTRA_PREVIOUS_CONNECTION_STATE}
393      * can be any of {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
394      * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
395      *
396      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
397      */
398     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
399     public static final String ACTION_CONNECTION_STATE_CHANGED =
400         "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED";
401 
402     /**
403      * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED}
404      *
405      * This extra represents the current connection state.
406      */
407     public static final String EXTRA_CONNECTION_STATE =
408         "android.bluetooth.adapter.extra.CONNECTION_STATE";
409 
410     /**
411      * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED}
412      *
413      * This extra represents the previous connection state.
414      */
415     public static final String EXTRA_PREVIOUS_CONNECTION_STATE =
416           "android.bluetooth.adapter.extra.PREVIOUS_CONNECTION_STATE";
417 
418     /**
419      * Broadcast Action: The Bluetooth adapter state has changed in LE only mode.
420      * @hide
421      */
422     @SystemApi
423     public static final String ACTION_BLE_STATE_CHANGED =
424         "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
425 
426     /**
427      * Broadcast Action: The notifys Bluetooth ACL connected event. This will be
428      * by BLE Always on enabled application to know the ACL_CONNECTED event
429      * when Bluetooth state in STATE_BLE_ON. This denotes GATT connection
430      * as Bluetooth LE is the only feature available in STATE_BLE_ON
431      *
432      * This is counterpart of {@link BluetoothDevice#ACTION_ACL_CONNECTED} which
433      * works in Bluetooth state STATE_ON
434      * @hide
435      */
436     public static final String ACTION_BLE_ACL_CONNECTED =
437         "android.bluetooth.adapter.action.BLE_ACL_CONNECTED";
438 
439     /**
440      * Broadcast Action: The notifys Bluetooth ACL connected event. This will be
441      * by BLE Always on enabled application to know the ACL_DISCONNECTED event
442      * when Bluetooth state in STATE_BLE_ON. This denotes GATT disconnection as Bluetooth
443      * LE is the only feature available in STATE_BLE_ON
444      *
445      * This is counterpart of {@link BluetoothDevice#ACTION_ACL_DISCONNECTED} which
446      * works in Bluetooth state STATE_ON
447      * @hide
448      */
449     public static final String ACTION_BLE_ACL_DISCONNECTED =
450         "android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED";
451 
452     /** The profile is in disconnected state */
453     public static final int STATE_DISCONNECTED  = 0;
454     /** The profile is in connecting state */
455     public static final int STATE_CONNECTING    = 1;
456     /** The profile is in connected state */
457     public static final int STATE_CONNECTED     = 2;
458     /** The profile is in disconnecting state */
459     public static final int STATE_DISCONNECTING = 3;
460 
461     /** @hide */
462     public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager";
463     private final IBinder mToken;
464 
465 
466     /** When creating a ServerSocket using listenUsingRfcommOn() or
467      *  listenUsingL2capOn() use SOCKET_CHANNEL_AUTO_STATIC to create
468      *  a ServerSocket that auto assigns a channel number to the first
469      *  bluetooth socket.
470      *  The channel number assigned to this first Bluetooth Socket will
471      *  be stored in the ServerSocket, and reused for subsequent Bluetooth
472      *  sockets.
473      * @hide */
474     public static final int SOCKET_CHANNEL_AUTO_STATIC_NO_SDP = -2;
475 
476 
477     private static final int ADDRESS_LENGTH = 17;
478 
479     /**
480      * Lazily initialized singleton. Guaranteed final after first object
481      * constructed.
482      */
483     private static BluetoothAdapter sAdapter;
484 
485     private static BluetoothLeScanner sBluetoothLeScanner;
486     private static BluetoothLeAdvertiser sBluetoothLeAdvertiser;
487 
488     private final IBluetoothManager mManagerService;
489     private IBluetooth mService;
490     private final ReentrantReadWriteLock mServiceLock =
491         new ReentrantReadWriteLock();
492 
493     private final Object mLock = new Object();
494     private final Map<LeScanCallback, ScanCallback> mLeScanClients;
495 
496     /**
497      * Get a handle to the default local Bluetooth adapter.
498      * <p>Currently Android only supports one Bluetooth adapter, but the API
499      * could be extended to support more. This will always return the default
500      * adapter.
501      * @return the default local adapter, or null if Bluetooth is not supported
502      *         on this hardware platform
503      */
getDefaultAdapter()504     public static synchronized BluetoothAdapter getDefaultAdapter() {
505         if (sAdapter == null) {
506             IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);
507             if (b != null) {
508                 IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b);
509                 sAdapter = new BluetoothAdapter(managerService);
510             } else {
511                 Log.e(TAG, "Bluetooth binder is null");
512             }
513         }
514         return sAdapter;
515     }
516 
517     /**
518      * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance.
519      */
BluetoothAdapter(IBluetoothManager managerService)520     BluetoothAdapter(IBluetoothManager managerService) {
521 
522         if (managerService == null) {
523             throw new IllegalArgumentException("bluetooth manager service is null");
524         }
525         try {
526             mServiceLock.writeLock().lock();
527             mService = managerService.registerAdapter(mManagerCallback);
528         } catch (RemoteException e) {
529             Log.e(TAG, "", e);
530         } finally {
531             mServiceLock.writeLock().unlock();
532         }
533         mManagerService = managerService;
534         mLeScanClients = new HashMap<LeScanCallback, ScanCallback>();
535         mToken = new Binder();
536     }
537 
538     /**
539      * Get a {@link BluetoothDevice} object for the given Bluetooth hardware
540      * address.
541      * <p>Valid Bluetooth hardware addresses must be upper case, in a format
542      * such as "00:11:22:33:AA:BB". The helper {@link #checkBluetoothAddress} is
543      * available to validate a Bluetooth address.
544      * <p>A {@link BluetoothDevice} will always be returned for a valid
545      * hardware address, even if this adapter has never seen that device.
546      *
547      * @param address valid Bluetooth MAC address
548      * @throws IllegalArgumentException if address is invalid
549      */
getRemoteDevice(String address)550     public BluetoothDevice getRemoteDevice(String address) {
551         return new BluetoothDevice(address);
552     }
553 
554     /**
555      * Get a {@link BluetoothDevice} object for the given Bluetooth hardware
556      * address.
557      * <p>Valid Bluetooth hardware addresses must be 6 bytes. This method
558      * expects the address in network byte order (MSB first).
559      * <p>A {@link BluetoothDevice} will always be returned for a valid
560      * hardware address, even if this adapter has never seen that device.
561      *
562      * @param address Bluetooth MAC address (6 bytes)
563      * @throws IllegalArgumentException if address is invalid
564      */
getRemoteDevice(byte[] address)565     public BluetoothDevice getRemoteDevice(byte[] address) {
566         if (address == null || address.length != 6) {
567             throw new IllegalArgumentException("Bluetooth address must have 6 bytes");
568         }
569         return new BluetoothDevice(String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X",
570                 address[0], address[1], address[2], address[3], address[4], address[5]));
571     }
572 
573     /**
574      * Returns a {@link BluetoothLeAdvertiser} object for Bluetooth LE Advertising operations.
575      * Will return null if Bluetooth is turned off or if Bluetooth LE Advertising is not
576      * supported on this device.
577      * <p>
578      * Use {@link #isMultipleAdvertisementSupported()} to check whether LE Advertising is supported
579      * on this device before calling this method.
580      */
getBluetoothLeAdvertiser()581     public BluetoothLeAdvertiser getBluetoothLeAdvertiser() {
582         if (!getLeAccess()) return null;
583         if (!isMultipleAdvertisementSupported() && !isPeripheralModeSupported()) {
584             Log.e(TAG, "Bluetooth LE advertising not supported");
585             return null;
586         }
587         synchronized(mLock) {
588             if (sBluetoothLeAdvertiser == null) {
589                 sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService);
590             }
591         }
592         return sBluetoothLeAdvertiser;
593     }
594 
595     /**
596      * Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations.
597      */
getBluetoothLeScanner()598     public BluetoothLeScanner getBluetoothLeScanner() {
599         if (!getLeAccess()) return null;
600         synchronized(mLock) {
601             if (sBluetoothLeScanner == null) {
602                 sBluetoothLeScanner = new BluetoothLeScanner(mManagerService);
603             }
604         }
605         return sBluetoothLeScanner;
606     }
607 
608     /**
609      * Return true if Bluetooth is currently enabled and ready for use.
610      * <p>Equivalent to:
611      * <code>getBluetoothState() == STATE_ON</code>
612      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
613      *
614      * @return true if the local adapter is turned on
615      */
616     @RequiresPermission(Manifest.permission.BLUETOOTH)
isEnabled()617     public boolean isEnabled() {
618         try {
619             mServiceLock.readLock().lock();
620             if (mService != null) return mService.isEnabled();
621         } catch (RemoteException e) {
622             Log.e(TAG, "", e);
623         } finally {
624             mServiceLock.readLock().unlock();
625         }
626 
627         return false;
628     }
629 
630     /**
631      * Return true if Bluetooth LE(Always BLE On feature) is currently
632      * enabled and ready for use
633      * <p>This returns true if current state is either STATE_ON or STATE_BLE_ON
634      *
635      * @return true if the local Bluetooth LE adapter is turned on
636      * @hide
637      */
638     @SystemApi
isLeEnabled()639     public boolean isLeEnabled() {
640        final int state = getLeState();
641        if (state == BluetoothAdapter.STATE_ON) {
642            if (DBG) Log.d (TAG, "STATE_ON");
643        } else if (state == BluetoothAdapter.STATE_BLE_ON) {
644            if (DBG) Log.d (TAG, "STATE_BLE_ON");
645        } else {
646            if (DBG) Log.d (TAG, "STATE_OFF");
647            return false;
648        }
649        return true;
650     }
651 
652     /**
653      * Performs action based on user action to turn BT ON
654      * or OFF if BT is in BLE_ON state
655      */
notifyUserAction(boolean enable)656     private void notifyUserAction(boolean enable) {
657         try {
658             mServiceLock.readLock().lock();
659             if (mService == null) {
660                 Log.e(TAG, "mService is null");
661                 return;
662             }
663             if (enable) {
664                 mService.onLeServiceUp(); //NA:TODO implementation pending
665             } else {
666                 mService.onBrEdrDown(); //NA:TODO implementation pending
667             }
668         } catch (RemoteException e) {
669             Log.e(TAG, "", e);
670         } finally {
671             mServiceLock.readLock().unlock();
672         }
673     }
674 
675     /**
676      * Turns off Bluetooth LE which was earlier turned on by calling EnableBLE().
677      *
678      * <p> If the internal Adapter state is STATE_BLE_ON, this would trigger the transition
679      * to STATE_OFF and completely shut-down Bluetooth
680      *
681      * <p> If the Adapter state is STATE_ON, This would unregister the existance of
682      * special Bluetooth LE application and hence the further turning off of Bluetooth
683      * from UI would ensure the complete turn-off of Bluetooth rather than staying back
684      * BLE only state
685      *
686      * <p>This is an asynchronous call: it will return immediately, and
687      * clients should listen for {@link #ACTION_BLE_STATE_CHANGED}
688      * to be notified of subsequent adapter state changes If this call returns
689      * true, then the adapter state will immediately transition from {@link
690      * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time
691      * later transition to either {@link #STATE_BLE_ON} or {@link
692      * #STATE_OFF} based on the existance of the further Always BLE ON enabled applications
693      * If this call returns false then there was an
694      * immediate problem that will prevent the QAdapter from being turned off -
695      * such as the QAadapter already being turned off.
696      *
697      * @return true to indicate success, or false on
698      *         immediate error
699      * @hide
700      */
701     @SystemApi
disableBLE()702     public boolean disableBLE() {
703         if (!isBleScanAlwaysAvailable()) return false;
704 
705         int state = getLeState();
706         if (state == BluetoothAdapter.STATE_ON) {
707             if (DBG) Log.d (TAG, "STATE_ON: shouldn't disable");
708             try {
709                 mManagerService.updateBleAppCount(mToken, false);
710             } catch (RemoteException e) {
711                 Log.e(TAG, "", e);
712             }
713             return true;
714 
715         } else if (state == BluetoothAdapter.STATE_BLE_ON) {
716             if (DBG) Log.d (TAG, "STATE_BLE_ON");
717             int bleAppCnt = 0;
718             try {
719                 bleAppCnt = mManagerService.updateBleAppCount(mToken, false);
720             } catch (RemoteException e) {
721                 Log.e(TAG, "", e);
722             }
723             if (bleAppCnt == 0) {
724                 // Disable only if there are no other clients
725                 notifyUserAction(false);
726             }
727             return true;
728         }
729 
730         if (DBG) Log.d (TAG, "STATE_OFF: Already disabled");
731         return false;
732     }
733 
734     /**
735      * Special Applications who want to only turn on Bluetooth Low Energy (BLE) would
736      * EnableBLE, EnableBLE brings-up Bluetooth so that application can access
737      * only LE related feature (Bluetooth GATT layers interfaces using the respective class)
738      * EnableBLE in turn registers the existance of a special App which wants to
739      * turn on Bluetooth Low enrgy part without making it visible at the settings UI
740      * as Bluetooth ON.
741      * <p>Invoking EnableBLE when Bluetooth is already in ON state, would just registers
742      * the existance of special Application and doesn't do anything to current BT state.
743      * when user turn OFF Bluetooth from UI, if there is an existance of special app, Bluetooth
744      * would stay in BLE_ON state so that LE features are still acessible to the special
745      * Applications.
746      *
747      * <p>This is an asynchronous call: it will return immediately, and
748      * clients should listen for {@link #ACTION_BLE_STATE_CHANGED}
749      * to be notified of subsequent adapter state changes. If this call returns
750      * true, then the adapter state will immediately transition from {@link
751      * #STATE_OFF} to {@link #STATE_BLE_TURNING_ON}, and some time
752      * later transition to either {@link #STATE_OFF} or {@link
753      * #STATE_BLE_ON}. If this call returns false then there was an
754      * immediate problem that will prevent the adapter from being turned on -
755      * such as Airplane mode, or the adapter is already turned on.
756      * (@link #ACTION_BLE_STATE_CHANGED) returns the Bluetooth Adapter's various
757      * states, It includes all the classic Bluetooth Adapter states along with
758      * internal BLE only states
759      *
760      * @return true to indicate Bluetooth LE start-up has begun, or false on
761      *         immediate error
762      * @hide
763      */
764     @SystemApi
enableBLE()765     public boolean enableBLE() {
766         if (!isBleScanAlwaysAvailable()) return false;
767 
768         if (isLeEnabled() == true) {
769             if (DBG) Log.d(TAG, "enableBLE(): BT is already enabled..!");
770             try {
771                 mManagerService.updateBleAppCount(mToken, true);
772             } catch (RemoteException e) {
773                 Log.e(TAG, "", e);
774             }
775             return true;
776         }
777 
778         try {
779             if (DBG) Log.d(TAG, "Calling enableBLE");
780             mManagerService.updateBleAppCount(mToken, true);
781             return mManagerService.enable();
782         } catch (RemoteException e) {
783             Log.e(TAG, "", e);
784         }
785 
786         return false;
787     }
788 
789     /**
790      * Get the current state of the local Bluetooth adapter.
791      * <p>Possible return values are
792      * {@link #STATE_OFF},
793      * {@link #STATE_TURNING_ON},
794      * {@link #STATE_ON},
795      * {@link #STATE_TURNING_OFF}.
796      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
797      *
798      * @return current state of Bluetooth adapter
799      */
800     @RequiresPermission(Manifest.permission.BLUETOOTH)
801     @AdapterState
getState()802     public int getState() {
803         int state = BluetoothAdapter.STATE_OFF;
804 
805         try {
806             mServiceLock.readLock().lock();
807             if (mService != null) {
808                 state = mService.getState();
809             }
810         } catch (RemoteException e) {
811             Log.e(TAG, "", e);
812         } finally {
813             mServiceLock.readLock().unlock();
814         }
815 
816         // Consider all internal states as OFF
817         if (state == BluetoothAdapter.STATE_BLE_ON
818             || state == BluetoothAdapter.STATE_BLE_TURNING_ON
819             || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) {
820             if (VDBG) Log.d(TAG, "Consider internal state as OFF");
821             state = BluetoothAdapter.STATE_OFF;
822         }
823         if (VDBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + state);
824         return state;
825     }
826 
827     /**
828      * Get the current state of the local Bluetooth adapter
829      * <p>This returns current internal state of Adapter including LE ON/OFF
830      *
831      * <p>Possible return values are
832      * {@link #STATE_OFF},
833      * {@link #STATE_BLE_TURNING_ON},
834      * {@link #STATE_BLE_ON},
835      * {@link #STATE_TURNING_ON},
836      * {@link #STATE_ON},
837      * {@link #STATE_TURNING_OFF},
838      * {@link #STATE_BLE_TURNING_OFF}.
839      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
840      *
841      * @return current state of Bluetooth adapter
842      * @hide
843      */
844     @RequiresPermission(Manifest.permission.BLUETOOTH)
845     @AdapterState
getLeState()846     public int getLeState() {
847         int state = BluetoothAdapter.STATE_OFF;
848 
849         try {
850             mServiceLock.readLock().lock();
851             if (mService != null) {
852                 state = mService.getState();
853             }
854         } catch (RemoteException e) {
855             Log.e(TAG, "", e);
856         } finally {
857             mServiceLock.readLock().unlock();
858         }
859 
860         if (VDBG) Log.d(TAG,"getLeState() returning " + state);
861         return state;
862     }
863 
getLeAccess()864     boolean getLeAccess() {
865         if(getLeState() == STATE_ON)
866             return true;
867 
868         else if (getLeState() == STATE_BLE_ON)
869             return true; // TODO: FILTER SYSTEM APPS HERE <--
870 
871         return false;
872     }
873 
874     /**
875      * Turn on the local Bluetooth adapter&mdash;do not use without explicit
876      * user action to turn on Bluetooth.
877      * <p>This powers on the underlying Bluetooth hardware, and starts all
878      * Bluetooth system services.
879      * <p class="caution"><strong>Bluetooth should never be enabled without
880      * direct user consent</strong>. If you want to turn on Bluetooth in order
881      * to create a wireless connection, you should use the {@link
882      * #ACTION_REQUEST_ENABLE} Intent, which will raise a dialog that requests
883      * user permission to turn on Bluetooth. The {@link #enable()} method is
884      * provided only for applications that include a user interface for changing
885      * system settings, such as a "power manager" app.</p>
886      * <p>This is an asynchronous call: it will return immediately, and
887      * clients should listen for {@link #ACTION_STATE_CHANGED}
888      * to be notified of subsequent adapter state changes. If this call returns
889      * true, then the adapter state will immediately transition from {@link
890      * #STATE_OFF} to {@link #STATE_TURNING_ON}, and some time
891      * later transition to either {@link #STATE_OFF} or {@link
892      * #STATE_ON}. If this call returns false then there was an
893      * immediate problem that will prevent the adapter from being turned on -
894      * such as Airplane mode, or the adapter is already turned on.
895      * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
896      * permission
897      *
898      * @return true to indicate adapter startup has begun, or false on
899      *         immediate error
900      */
901     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
enable()902     public boolean enable() {
903         if (isEnabled() == true) {
904             if (DBG) Log.d(TAG, "enable(): BT is already enabled..!");
905             return true;
906         }
907         try {
908             return mManagerService.enable();
909         } catch (RemoteException e) {Log.e(TAG, "", e);}
910         return false;
911     }
912 
913     /**
914      * Turn off the local Bluetooth adapter&mdash;do not use without explicit
915      * user action to turn off Bluetooth.
916      * <p>This gracefully shuts down all Bluetooth connections, stops Bluetooth
917      * system services, and powers down the underlying Bluetooth hardware.
918      * <p class="caution"><strong>Bluetooth should never be disabled without
919      * direct user consent</strong>. The {@link #disable()} method is
920      * provided only for applications that include a user interface for changing
921      * system settings, such as a "power manager" app.</p>
922      * <p>This is an asynchronous call: it will return immediately, and
923      * clients should listen for {@link #ACTION_STATE_CHANGED}
924      * to be notified of subsequent adapter state changes. If this call returns
925      * true, then the adapter state will immediately transition from {@link
926      * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time
927      * later transition to either {@link #STATE_OFF} or {@link
928      * #STATE_ON}. If this call returns false then there was an
929      * immediate problem that will prevent the adapter from being turned off -
930      * such as the adapter already being turned off.
931      * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
932      * permission
933      *
934      * @return true to indicate adapter shutdown has begun, or false on
935      *         immediate error
936      */
937     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
disable()938     public boolean disable() {
939         try {
940             return mManagerService.disable(true);
941         } catch (RemoteException e) {Log.e(TAG, "", e);}
942         return false;
943     }
944 
945     /**
946      * Turn off the local Bluetooth adapter and don't persist the setting.
947      *
948      * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
949      * permission
950      *
951      * @return true to indicate adapter shutdown has begun, or false on
952      *         immediate error
953      * @hide
954      */
disable(boolean persist)955     public boolean disable(boolean persist) {
956 
957         try {
958             return mManagerService.disable(persist);
959         } catch (RemoteException e) {Log.e(TAG, "", e);}
960         return false;
961     }
962 
963     /**
964      * Returns the hardware address of the local Bluetooth adapter.
965      * <p>For example, "00:11:22:AA:BB:CC".
966      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
967      *
968      * @return Bluetooth hardware address as string
969      */
970     @RequiresPermission(Manifest.permission.BLUETOOTH)
getAddress()971     public String getAddress() {
972         try {
973             return mManagerService.getAddress();
974         } catch (RemoteException e) {Log.e(TAG, "", e);}
975         return null;
976     }
977 
978     /**
979      * Get the friendly Bluetooth name of the local Bluetooth adapter.
980      * <p>This name is visible to remote Bluetooth devices.
981      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
982      *
983      * @return the Bluetooth name, or null on error
984      */
getName()985     public String getName() {
986         try {
987             return mManagerService.getName();
988         } catch (RemoteException e) {Log.e(TAG, "", e);}
989         return null;
990     }
991 
992     /**
993      * enable or disable Bluetooth HCI snoop log.
994      *
995      * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
996      * permission
997      *
998      * @return true to indicate configure HCI log successfully, or false on
999      *         immediate error
1000      * @hide
1001      */
configHciSnoopLog(boolean enable)1002     public boolean configHciSnoopLog(boolean enable) {
1003         try {
1004             mServiceLock.readLock().lock();
1005             if (mService != null) return mService.configHciSnoopLog(enable);
1006         } catch (RemoteException e) {
1007             Log.e(TAG, "", e);
1008         } finally {
1009             mServiceLock.readLock().unlock();
1010         }
1011         return false;
1012     }
1013 
1014     /**
1015      * Factory reset bluetooth settings.
1016      *
1017      * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}
1018      * permission
1019      *
1020      * @return true to indicate that the config file was successfully cleared
1021      *
1022      * @hide
1023      */
factoryReset()1024     public boolean factoryReset() {
1025         try {
1026             mServiceLock.readLock().lock();
1027             if (mService != null) {
1028                 return mService.factoryReset();
1029             }
1030             SystemProperties.set("persist.bluetooth.factoryreset", "true");
1031         } catch (RemoteException e) {
1032             Log.e(TAG, "", e);
1033         } finally {
1034             mServiceLock.readLock().unlock();
1035         }
1036         return false;
1037     }
1038 
1039     /**
1040      * Get the UUIDs supported by the local Bluetooth adapter.
1041      *
1042      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1043      *
1044      * @return the UUIDs supported by the local Bluetooth Adapter.
1045      * @hide
1046      */
getUuids()1047     public ParcelUuid[] getUuids() {
1048         if (getState() != STATE_ON) return null;
1049         try {
1050             mServiceLock.readLock().lock();
1051             if (mService != null) return mService.getUuids();
1052         } catch (RemoteException e) {
1053             Log.e(TAG, "", e);
1054         } finally {
1055             mServiceLock.readLock().unlock();
1056         }
1057         return null;
1058     }
1059 
1060     /**
1061      * Set the friendly Bluetooth name of the local Bluetooth adapter.
1062      * <p>This name is visible to remote Bluetooth devices.
1063      * <p>Valid Bluetooth names are a maximum of 248 bytes using UTF-8
1064      * encoding, although many remote devices can only display the first
1065      * 40 characters, and some may be limited to just 20.
1066      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
1067      * will return false. After turning on Bluetooth,
1068      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
1069      * to get the updated value.
1070      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
1071      *
1072      * @param name a valid Bluetooth name
1073      * @return     true if the name was set, false otherwise
1074      */
1075     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
setName(String name)1076     public boolean setName(String name) {
1077         if (getState() != STATE_ON) return false;
1078         try {
1079             mServiceLock.readLock().lock();
1080             if (mService != null) return mService.setName(name);
1081         } catch (RemoteException e) {
1082             Log.e(TAG, "", e);
1083         } finally {
1084             mServiceLock.readLock().unlock();
1085         }
1086         return false;
1087     }
1088 
1089     /**
1090      * Get the current Bluetooth scan mode of the local Bluetooth adapter.
1091      * <p>The Bluetooth scan mode determines if the local adapter is
1092      * connectable and/or discoverable from remote Bluetooth devices.
1093      * <p>Possible values are:
1094      * {@link #SCAN_MODE_NONE},
1095      * {@link #SCAN_MODE_CONNECTABLE},
1096      * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
1097      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
1098      * will return {@link #SCAN_MODE_NONE}. After turning on Bluetooth,
1099      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
1100      * to get the updated value.
1101      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1102      *
1103      * @return scan mode
1104      */
1105     @RequiresPermission(Manifest.permission.BLUETOOTH)
1106     @ScanMode
getScanMode()1107     public int getScanMode() {
1108         if (getState() != STATE_ON) return SCAN_MODE_NONE;
1109         try {
1110             mServiceLock.readLock().lock();
1111             if (mService != null) return mService.getScanMode();
1112         } catch (RemoteException e) {
1113             Log.e(TAG, "", e);
1114         } finally {
1115             mServiceLock.readLock().unlock();
1116         }
1117         return SCAN_MODE_NONE;
1118     }
1119 
1120     /**
1121      * Set the Bluetooth scan mode of the local Bluetooth adapter.
1122      * <p>The Bluetooth scan mode determines if the local adapter is
1123      * connectable and/or discoverable from remote Bluetooth devices.
1124      * <p>For privacy reasons, discoverable mode is automatically turned off
1125      * after <code>duration</code> seconds. For example, 120 seconds should be
1126      * enough for a remote device to initiate and complete its discovery
1127      * process.
1128      * <p>Valid scan mode values are:
1129      * {@link #SCAN_MODE_NONE},
1130      * {@link #SCAN_MODE_CONNECTABLE},
1131      * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
1132      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
1133      * will return false. After turning on Bluetooth,
1134      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
1135      * to get the updated value.
1136      * <p>Requires {@link android.Manifest.permission#WRITE_SECURE_SETTINGS}
1137      * <p>Applications cannot set the scan mode. They should use
1138      * <code>startActivityForResult(
1139      * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE})
1140      * </code>instead.
1141      *
1142      * @param mode valid scan mode
1143      * @param duration time in seconds to apply scan mode, only used for
1144      *                 {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}
1145      * @return     true if the scan mode was set, false otherwise
1146      * @hide
1147      */
setScanMode(@canMode int mode, int duration)1148     public boolean setScanMode(@ScanMode int mode, int duration) {
1149         if (getState() != STATE_ON) return false;
1150         try {
1151             mServiceLock.readLock().lock();
1152             if (mService != null) return mService.setScanMode(mode, duration);
1153         } catch (RemoteException e) {
1154             Log.e(TAG, "", e);
1155         } finally {
1156             mServiceLock.readLock().unlock();
1157         }
1158         return false;
1159     }
1160 
1161     /** @hide */
setScanMode(int mode)1162     public boolean setScanMode(int mode) {
1163         if (getState() != STATE_ON) return false;
1164         /* getDiscoverableTimeout() to use the latest from NV than use 0 */
1165         return setScanMode(mode, getDiscoverableTimeout());
1166     }
1167 
1168     /** @hide */
getDiscoverableTimeout()1169     public int getDiscoverableTimeout() {
1170         if (getState() != STATE_ON) return -1;
1171         try {
1172             mServiceLock.readLock().lock();
1173             if (mService != null) return mService.getDiscoverableTimeout();
1174         } catch (RemoteException e) {
1175             Log.e(TAG, "", e);
1176         } finally {
1177             mServiceLock.readLock().unlock();
1178         }
1179         return -1;
1180     }
1181 
1182     /** @hide */
setDiscoverableTimeout(int timeout)1183     public void setDiscoverableTimeout(int timeout) {
1184         if (getState() != STATE_ON) return;
1185         try {
1186             mServiceLock.readLock().lock();
1187             if (mService != null) mService.setDiscoverableTimeout(timeout);
1188         } catch (RemoteException e) {
1189             Log.e(TAG, "", e);
1190         } finally {
1191             mServiceLock.readLock().unlock();
1192         }
1193     }
1194 
1195     /**
1196      * Start the remote device discovery process.
1197      * <p>The discovery process usually involves an inquiry scan of about 12
1198      * seconds, followed by a page scan of each new device to retrieve its
1199      * Bluetooth name.
1200      * <p>This is an asynchronous call, it will return immediately. Register
1201      * for {@link #ACTION_DISCOVERY_STARTED} and {@link
1202      * #ACTION_DISCOVERY_FINISHED} intents to determine exactly when the
1203      * discovery starts and completes. Register for {@link
1204      * BluetoothDevice#ACTION_FOUND} to be notified as remote Bluetooth devices
1205      * are found.
1206      * <p>Device discovery is a heavyweight procedure. New connections to
1207      * remote Bluetooth devices should not be attempted while discovery is in
1208      * progress, and existing connections will experience limited bandwidth
1209      * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
1210      * discovery. Discovery is not managed by the Activity,
1211      * but is run as a system service, so an application should always call
1212      * {@link BluetoothAdapter#cancelDiscovery()} even if it
1213      * did not directly request a discovery, just to be sure.
1214      * <p>Device discovery will only find remote devices that are currently
1215      * <i>discoverable</i> (inquiry scan enabled). Many Bluetooth devices are
1216      * not discoverable by default, and need to be entered into a special mode.
1217      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
1218      * will return false. After turning on Bluetooth,
1219      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
1220      * to get the updated value.
1221      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
1222      *
1223      * @return true on success, false on error
1224      */
1225     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
startDiscovery()1226     public boolean startDiscovery() {
1227         if (getState() != STATE_ON) return false;
1228         try {
1229             mServiceLock.readLock().lock();
1230             if (mService != null) return mService.startDiscovery();
1231         } catch (RemoteException e) {
1232             Log.e(TAG, "", e);
1233         } finally {
1234             mServiceLock.readLock().unlock();
1235         }
1236         return false;
1237     }
1238 
1239     /**
1240      * Cancel the current device discovery process.
1241      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
1242      * <p>Because discovery is a heavyweight procedure for the Bluetooth
1243      * adapter, this method should always be called before attempting to connect
1244      * to a remote device with {@link
1245      * android.bluetooth.BluetoothSocket#connect()}. Discovery is not managed by
1246      * the  Activity, but is run as a system service, so an application should
1247      * always call cancel discovery even if it did not directly request a
1248      * discovery, just to be sure.
1249      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
1250      * will return false. After turning on Bluetooth,
1251      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
1252      * to get the updated value.
1253      *
1254      * @return true on success, false on error
1255      */
1256     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
cancelDiscovery()1257     public boolean cancelDiscovery() {
1258         if (getState() != STATE_ON) return false;
1259         try {
1260             mServiceLock.readLock().lock();
1261             if (mService != null) return mService.cancelDiscovery();
1262         } catch (RemoteException e) {
1263             Log.e(TAG, "", e);
1264         } finally {
1265             mServiceLock.readLock().unlock();
1266         }
1267         return false;
1268     }
1269 
1270     /**
1271      * Return true if the local Bluetooth adapter is currently in the device
1272      * discovery process.
1273      * <p>Device discovery is a heavyweight procedure. New connections to
1274      * remote Bluetooth devices should not be attempted while discovery is in
1275      * progress, and existing connections will experience limited bandwidth
1276      * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
1277      * discovery.
1278      * <p>Applications can also register for {@link #ACTION_DISCOVERY_STARTED}
1279      * or {@link #ACTION_DISCOVERY_FINISHED} to be notified when discovery
1280      * starts or completes.
1281      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
1282      * will return false. After turning on Bluetooth,
1283      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
1284      * to get the updated value.
1285      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
1286      *
1287      * @return true if discovering
1288      */
1289     @RequiresPermission(Manifest.permission.BLUETOOTH)
isDiscovering()1290     public boolean isDiscovering() {
1291         if (getState() != STATE_ON) return false;
1292         try {
1293             mServiceLock.readLock().lock();
1294             if (mService != null) return mService.isDiscovering();
1295         } catch (RemoteException e) {
1296             Log.e(TAG, "", e);
1297         } finally {
1298             mServiceLock.readLock().unlock();
1299         }
1300         return false;
1301     }
1302 
1303     /**
1304      * Return true if the multi advertisement is supported by the chipset
1305      *
1306      * @return true if Multiple Advertisement feature is supported
1307      */
isMultipleAdvertisementSupported()1308     public boolean isMultipleAdvertisementSupported() {
1309         if (getState() != STATE_ON) return false;
1310         try {
1311             mServiceLock.readLock().lock();
1312             if (mService != null) return mService.isMultiAdvertisementSupported();
1313         } catch (RemoteException e) {
1314             Log.e(TAG, "failed to get isMultipleAdvertisementSupported, error: ", e);
1315         } finally {
1316             mServiceLock.readLock().unlock();
1317         }
1318         return false;
1319     }
1320 
1321     /**
1322      * Returns {@code true} if BLE scan is always available, {@code false} otherwise. <p>
1323      *
1324      * If this returns {@code true}, application can issue {@link BluetoothLeScanner#startScan} and
1325      * fetch scan results even when Bluetooth is turned off.<p>
1326      *
1327      * To change this setting, use {@link #ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE}.
1328      *
1329      * @hide
1330      */
1331     @SystemApi
isBleScanAlwaysAvailable()1332     public boolean isBleScanAlwaysAvailable() {
1333         try {
1334             return mManagerService.isBleScanAlwaysAvailable();
1335         } catch (RemoteException e) {
1336             Log.e(TAG, "remote expection when calling isBleScanAlwaysAvailable", e);
1337             return false;
1338         }
1339     }
1340 
1341     /**
1342      * Returns whether peripheral mode is supported.
1343      *
1344      * @hide
1345      */
isPeripheralModeSupported()1346     public boolean isPeripheralModeSupported() {
1347         if (getState() != STATE_ON) return false;
1348         try {
1349             mServiceLock.readLock().lock();
1350             if (mService != null) return mService.isPeripheralModeSupported();
1351         } catch (RemoteException e) {
1352             Log.e(TAG, "failed to get peripheral mode capability: ", e);
1353         } finally {
1354             mServiceLock.readLock().unlock();
1355         }
1356         return false;
1357     }
1358 
1359     /**
1360      * Return true if offloaded filters are supported
1361      *
1362      * @return true if chipset supports on-chip filtering
1363      */
isOffloadedFilteringSupported()1364     public boolean isOffloadedFilteringSupported() {
1365         if (!getLeAccess()) return false;
1366         try {
1367             mServiceLock.readLock().lock();
1368             if (mService != null) return mService.isOffloadedFilteringSupported();
1369         } catch (RemoteException e) {
1370             Log.e(TAG, "failed to get isOffloadedFilteringSupported, error: ", e);
1371         } finally {
1372             mServiceLock.readLock().unlock();
1373         }
1374         return false;
1375     }
1376 
1377     /**
1378      * Return true if offloaded scan batching is supported
1379      *
1380      * @return true if chipset supports on-chip scan batching
1381      */
isOffloadedScanBatchingSupported()1382     public boolean isOffloadedScanBatchingSupported() {
1383         if (!getLeAccess()) return false;
1384         try {
1385             mServiceLock.readLock().lock();
1386             if (mService != null) return mService.isOffloadedScanBatchingSupported();
1387         } catch (RemoteException e) {
1388             Log.e(TAG, "failed to get isOffloadedScanBatchingSupported, error: ", e);
1389         } finally {
1390             mServiceLock.readLock().unlock();
1391         }
1392         return false;
1393     }
1394 
1395     /**
1396      * Return true if hardware has entries available for matching beacons
1397      *
1398      * @return true if there are hw entries available for matching beacons
1399      * @hide
1400      */
isHardwareTrackingFiltersAvailable()1401     public boolean isHardwareTrackingFiltersAvailable() {
1402         if (!getLeAccess()) return false;
1403         try {
1404             IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
1405             if (iGatt == null) {
1406                 // BLE is not supported
1407                 return false;
1408             }
1409             return (iGatt.numHwTrackFiltersAvailable() != 0);
1410         } catch (RemoteException e) {
1411             Log.e(TAG, "", e);
1412         }
1413         return false;
1414     }
1415 
1416     /**
1417      * Return the record of {@link BluetoothActivityEnergyInfo} object that
1418      * has the activity and energy info. This can be used to ascertain what
1419      * the controller has been up to, since the last sample.
1420      * @param updateType Type of info, cached vs refreshed.
1421      *
1422      * @return a record with {@link BluetoothActivityEnergyInfo} or null if
1423      * report is unavailable or unsupported
1424      * @deprecated use the asynchronous
1425      * {@link #requestControllerActivityEnergyInfo(ResultReceiver)} instead.
1426      * @hide
1427      */
1428     @Deprecated
getControllerActivityEnergyInfo(int updateType)1429     public BluetoothActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) {
1430         SynchronousResultReceiver receiver = new SynchronousResultReceiver();
1431         requestControllerActivityEnergyInfo(receiver);
1432         try {
1433             SynchronousResultReceiver.Result result = receiver.awaitResult(1000);
1434             if (result.bundle != null) {
1435                 return result.bundle.getParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY);
1436             }
1437         } catch (TimeoutException e) {
1438             Log.e(TAG, "getControllerActivityEnergyInfo timed out");
1439         }
1440         return null;
1441     }
1442 
1443     /**
1444      * Request the record of {@link BluetoothActivityEnergyInfo} object that
1445      * has the activity and energy info. This can be used to ascertain what
1446      * the controller has been up to, since the last sample.
1447      *
1448      * A null value for the activity info object may be sent if the bluetooth service is
1449      * unreachable or the device does not support reporting such information.
1450      *
1451      * @param result The callback to which to send the activity info.
1452      * @hide
1453      */
requestControllerActivityEnergyInfo(ResultReceiver result)1454     public void requestControllerActivityEnergyInfo(ResultReceiver result) {
1455         try {
1456             mServiceLock.readLock().lock();
1457             if (mService != null) {
1458                 mService.requestActivityInfo(result);
1459                 result = null;
1460             }
1461         } catch (RemoteException e) {
1462             Log.e(TAG, "getControllerActivityEnergyInfoCallback: " + e);
1463         } finally {
1464             mServiceLock.readLock().unlock();
1465             if (result != null) {
1466                 // Only send an immediate result if we failed.
1467                 result.send(0, null);
1468             }
1469         }
1470     }
1471 
1472     /**
1473      * Return the set of {@link BluetoothDevice} objects that are bonded
1474      * (paired) to the local adapter.
1475      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
1476      * will return an empty set. After turning on Bluetooth,
1477      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
1478      * to get the updated value.
1479      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
1480      *
1481      * @return unmodifiable set of {@link BluetoothDevice}, or null on error
1482      */
1483     @RequiresPermission(Manifest.permission.BLUETOOTH)
getBondedDevices()1484     public Set<BluetoothDevice> getBondedDevices() {
1485         if (getState() != STATE_ON) {
1486             return toDeviceSet(new BluetoothDevice[0]);
1487         }
1488         try {
1489             mServiceLock.readLock().lock();
1490             if (mService != null) return toDeviceSet(mService.getBondedDevices());
1491             return toDeviceSet(new BluetoothDevice[0]);
1492         } catch (RemoteException e) {
1493             Log.e(TAG, "", e);
1494         } finally {
1495             mServiceLock.readLock().unlock();
1496         }
1497         return null;
1498     }
1499 
1500     /**
1501      * Get the current connection state of the local Bluetooth adapter.
1502      * This can be used to check whether the local Bluetooth adapter is connected
1503      * to any profile of any other remote Bluetooth Device.
1504      *
1505      * <p> Use this function along with {@link #ACTION_CONNECTION_STATE_CHANGED}
1506      * intent to get the connection state of the adapter.
1507      *
1508      * @return One of {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTED},
1509      * {@link #STATE_CONNECTING} or {@link #STATE_DISCONNECTED}
1510      *
1511      * @hide
1512      */
getConnectionState()1513     public int getConnectionState() {
1514         if (getState() != STATE_ON) return BluetoothAdapter.STATE_DISCONNECTED;
1515         try {
1516             mServiceLock.readLock().lock();
1517             if (mService != null) return mService.getAdapterConnectionState();
1518         } catch (RemoteException e) {
1519             Log.e(TAG, "getConnectionState:", e);
1520         } finally {
1521             mServiceLock.readLock().unlock();
1522         }
1523         return BluetoothAdapter.STATE_DISCONNECTED;
1524     }
1525 
1526     /**
1527      * Get the current connection state of a profile.
1528      * This function can be used to check whether the local Bluetooth adapter
1529      * is connected to any remote device for a specific profile.
1530      * Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET},
1531      * {@link BluetoothProfile#A2DP}.
1532      *
1533      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
1534      *
1535      * <p> Return value can be one of
1536      * {@link BluetoothProfile#STATE_DISCONNECTED},
1537      * {@link BluetoothProfile#STATE_CONNECTING},
1538      * {@link BluetoothProfile#STATE_CONNECTED},
1539      * {@link BluetoothProfile#STATE_DISCONNECTING}
1540      */
1541     @RequiresPermission(Manifest.permission.BLUETOOTH)
getProfileConnectionState(int profile)1542     public int getProfileConnectionState(int profile) {
1543         if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED;
1544         try {
1545             mServiceLock.readLock().lock();
1546             if (mService != null) return mService.getProfileConnectionState(profile);
1547         } catch (RemoteException e) {
1548             Log.e(TAG, "getProfileConnectionState:", e);
1549         } finally {
1550             mServiceLock.readLock().unlock();
1551         }
1552         return BluetoothProfile.STATE_DISCONNECTED;
1553     }
1554 
1555     /**
1556      * Create a listening, secure RFCOMM Bluetooth socket.
1557      * <p>A remote device connecting to this socket will be authenticated and
1558      * communication on this socket will be encrypted.
1559      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
1560      * connections from a listening {@link BluetoothServerSocket}.
1561      * <p>Valid RFCOMM channels are in range 1 to 30.
1562      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
1563      * @param channel RFCOMM channel to listen on
1564      * @return a listening RFCOMM BluetoothServerSocket
1565      * @throws IOException on error, for example Bluetooth not available, or
1566      *                     insufficient permissions, or channel in use.
1567      * @hide
1568      */
listenUsingRfcommOn(int channel)1569     public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException {
1570         return listenUsingRfcommOn(channel, false, false);
1571     }
1572 
1573     /**
1574      * Create a listening, secure RFCOMM Bluetooth socket.
1575      * <p>A remote device connecting to this socket will be authenticated and
1576      * communication on this socket will be encrypted.
1577      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
1578      * connections from a listening {@link BluetoothServerSocket}.
1579      * <p>Valid RFCOMM channels are in range 1 to 30.
1580      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
1581      * <p>To auto assign a channel without creating a SDP record use
1582      * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as channel number.
1583      * @param channel RFCOMM channel to listen on
1584      * @param mitm    enforce man-in-the-middle protection for authentication.
1585      * @param min16DigitPin enforce a pin key length og minimum 16 digit for sec mode 2 connections.
1586      * @return a listening RFCOMM BluetoothServerSocket
1587      * @throws IOException on error, for example Bluetooth not available, or
1588      *                     insufficient permissions, or channel in use.
1589      * @hide
1590      */
listenUsingRfcommOn(int channel, boolean mitm, boolean min16DigitPin)1591     public BluetoothServerSocket listenUsingRfcommOn(int channel, boolean mitm,
1592             boolean min16DigitPin)
1593             throws IOException {
1594         BluetoothServerSocket socket = new BluetoothServerSocket(
1595                 BluetoothSocket.TYPE_RFCOMM, true, true, channel, mitm, min16DigitPin);
1596         int errno = socket.mSocket.bindListen();
1597         if (channel == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
1598             socket.setChannel(socket.mSocket.getPort());
1599         }
1600         if (errno != 0) {
1601             //TODO(BT): Throw the same exception error code
1602             // that the previous code was using.
1603             //socket.mSocket.throwErrnoNative(errno);
1604             throw new IOException("Error: " + errno);
1605         }
1606         return socket;
1607     }
1608 
1609     /**
1610      * Create a listening, secure RFCOMM Bluetooth socket with Service Record.
1611      * <p>A remote device connecting to this socket will be authenticated and
1612      * communication on this socket will be encrypted.
1613      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
1614      * connections from a listening {@link BluetoothServerSocket}.
1615      * <p>The system will assign an unused RFCOMM channel to listen on.
1616      * <p>The system will also register a Service Discovery
1617      * Protocol (SDP) record with the local SDP server containing the specified
1618      * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
1619      * can use the same UUID to query our SDP server and discover which channel
1620      * to connect to. This SDP record will be removed when this socket is
1621      * closed, or if this application closes unexpectedly.
1622      * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
1623      * connect to this socket from another device using the same {@link UUID}.
1624      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1625      * @param name service name for SDP record
1626      * @param uuid uuid for SDP record
1627      * @return a listening RFCOMM BluetoothServerSocket
1628      * @throws IOException on error, for example Bluetooth not available, or
1629      *                     insufficient permissions, or channel in use.
1630      */
1631     @RequiresPermission(Manifest.permission.BLUETOOTH)
listenUsingRfcommWithServiceRecord(String name, UUID uuid)1632     public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid)
1633             throws IOException {
1634         return createNewRfcommSocketAndRecord(name, uuid, true, true);
1635     }
1636 
1637     /**
1638      * Create a listening, insecure RFCOMM Bluetooth socket with Service Record.
1639      * <p>The link key is not required to be authenticated, i.e the communication may be
1640      * vulnerable to Man In the Middle attacks. For Bluetooth 2.1 devices,
1641      * the link will be encrypted, as encryption is mandartory.
1642      * For legacy devices (pre Bluetooth 2.1 devices) the link will not
1643      * be encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an
1644      * encrypted and authenticated communication channel is desired.
1645      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
1646      * connections from a listening {@link BluetoothServerSocket}.
1647      * <p>The system will assign an unused RFCOMM channel to listen on.
1648      * <p>The system will also register a Service Discovery
1649      * Protocol (SDP) record with the local SDP server containing the specified
1650      * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
1651      * can use the same UUID to query our SDP server and discover which channel
1652      * to connect to. This SDP record will be removed when this socket is
1653      * closed, or if this application closes unexpectedly.
1654      * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
1655      * connect to this socket from another device using the same {@link UUID}.
1656      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1657      * @param name service name for SDP record
1658      * @param uuid uuid for SDP record
1659      * @return a listening RFCOMM BluetoothServerSocket
1660      * @throws IOException on error, for example Bluetooth not available, or
1661      *                     insufficient permissions, or channel in use.
1662      */
1663     @RequiresPermission(Manifest.permission.BLUETOOTH)
listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)1664     public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)
1665             throws IOException {
1666         return createNewRfcommSocketAndRecord(name, uuid, false, false);
1667     }
1668 
1669      /**
1670      * Create a listening, encrypted,
1671      * RFCOMM Bluetooth socket with Service Record.
1672      * <p>The link will be encrypted, but the link key is not required to be authenticated
1673      * i.e the communication is vulnerable to Man In the Middle attacks. Use
1674      * {@link #listenUsingRfcommWithServiceRecord}, to ensure an authenticated link key.
1675      * <p> Use this socket if authentication of link key is not possible.
1676      * For example, for Bluetooth 2.1 devices, if any of the devices does not have
1677      * an input and output capability or just has the ability to display a numeric key,
1678      * a secure socket connection is not possible and this socket can be used.
1679      * Use {@link #listenUsingInsecureRfcommWithServiceRecord}, if encryption is not required.
1680      * For Bluetooth 2.1 devices, the link will be encrypted, as encryption is mandartory.
1681      * For more details, refer to the Security Model section 5.2 (vol 3) of
1682      * Bluetooth Core Specification version 2.1 + EDR.
1683      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
1684      * connections from a listening {@link BluetoothServerSocket}.
1685      * <p>The system will assign an unused RFCOMM channel to listen on.
1686      * <p>The system will also register a Service Discovery
1687      * Protocol (SDP) record with the local SDP server containing the specified
1688      * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
1689      * can use the same UUID to query our SDP server and discover which channel
1690      * to connect to. This SDP record will be removed when this socket is
1691      * closed, or if this application closes unexpectedly.
1692      * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
1693      * connect to this socket from another device using the same {@link UUID}.
1694      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1695      * @param name service name for SDP record
1696      * @param uuid uuid for SDP record
1697      * @return a listening RFCOMM BluetoothServerSocket
1698      * @throws IOException on error, for example Bluetooth not available, or
1699      *                     insufficient permissions, or channel in use.
1700      * @hide
1701      */
listenUsingEncryptedRfcommWithServiceRecord( String name, UUID uuid)1702     public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(
1703             String name, UUID uuid) throws IOException {
1704         return createNewRfcommSocketAndRecord(name, uuid, false, true);
1705     }
1706 
1707 
createNewRfcommSocketAndRecord(String name, UUID uuid, boolean auth, boolean encrypt)1708     private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid,
1709             boolean auth, boolean encrypt) throws IOException {
1710         BluetoothServerSocket socket;
1711         socket = new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, auth,
1712                         encrypt, new ParcelUuid(uuid));
1713         socket.setServiceName(name);
1714         int errno = socket.mSocket.bindListen();
1715         if (errno != 0) {
1716             //TODO(BT): Throw the same exception error code
1717             // that the previous code was using.
1718             //socket.mSocket.throwErrnoNative(errno);
1719             throw new IOException("Error: " + errno);
1720         }
1721         return socket;
1722     }
1723 
1724     /**
1725      * Construct an unencrypted, unauthenticated, RFCOMM server socket.
1726      * Call #accept to retrieve connections to this socket.
1727      * @return An RFCOMM BluetoothServerSocket
1728      * @throws IOException On error, for example Bluetooth not available, or
1729      *                     insufficient permissions.
1730      * @hide
1731      */
listenUsingInsecureRfcommOn(int port)1732     public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException {
1733         BluetoothServerSocket socket = new BluetoothServerSocket(
1734                 BluetoothSocket.TYPE_RFCOMM, false, false, port);
1735         int errno = socket.mSocket.bindListen();
1736         if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
1737             socket.setChannel(socket.mSocket.getPort());
1738         }
1739         if (errno != 0) {
1740             //TODO(BT): Throw the same exception error code
1741             // that the previous code was using.
1742             //socket.mSocket.throwErrnoNative(errno);
1743             throw new IOException("Error: " + errno);
1744         }
1745         return socket;
1746     }
1747 
1748      /**
1749      * Construct an encrypted, RFCOMM server socket.
1750      * Call #accept to retrieve connections to this socket.
1751      * @return An RFCOMM BluetoothServerSocket
1752      * @throws IOException On error, for example Bluetooth not available, or
1753      *                     insufficient permissions.
1754      * @hide
1755      */
listenUsingEncryptedRfcommOn(int port)1756     public BluetoothServerSocket listenUsingEncryptedRfcommOn(int port)
1757             throws IOException {
1758         BluetoothServerSocket socket = new BluetoothServerSocket(
1759                 BluetoothSocket.TYPE_RFCOMM, false, true, port);
1760         int errno = socket.mSocket.bindListen();
1761         if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
1762             socket.setChannel(socket.mSocket.getPort());
1763         }
1764         if (errno < 0) {
1765             //TODO(BT): Throw the same exception error code
1766             // that the previous code was using.
1767             //socket.mSocket.throwErrnoNative(errno);
1768             throw new IOException("Error: " + errno);
1769         }
1770         return socket;
1771     }
1772 
1773     /**
1774      * Construct a SCO server socket.
1775      * Call #accept to retrieve connections to this socket.
1776      * @return A SCO BluetoothServerSocket
1777      * @throws IOException On error, for example Bluetooth not available, or
1778      *                     insufficient permissions.
1779      * @hide
1780      */
listenUsingScoOn()1781     public static BluetoothServerSocket listenUsingScoOn() throws IOException {
1782         BluetoothServerSocket socket = new BluetoothServerSocket(
1783                 BluetoothSocket.TYPE_SCO, false, false, -1);
1784         int errno = socket.mSocket.bindListen();
1785         if (errno < 0) {
1786             //TODO(BT): Throw the same exception error code
1787             // that the previous code was using.
1788             //socket.mSocket.throwErrnoNative(errno);
1789         }
1790         return socket;
1791     }
1792 
1793     /**
1794      * Construct an encrypted, authenticated, L2CAP server socket.
1795      * Call #accept to retrieve connections to this socket.
1796      * <p>To auto assign a port without creating a SDP record use
1797      * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number.
1798      * @param port    the PSM to listen on
1799      * @param mitm    enforce man-in-the-middle protection for authentication.
1800      * @param min16DigitPin enforce a pin key length og minimum 16 digit for sec mode 2 connections.
1801      * @return An L2CAP BluetoothServerSocket
1802      * @throws IOException On error, for example Bluetooth not available, or
1803      *                     insufficient permissions.
1804      * @hide
1805      */
listenUsingL2capOn(int port, boolean mitm, boolean min16DigitPin)1806     public BluetoothServerSocket listenUsingL2capOn(int port, boolean mitm, boolean min16DigitPin)
1807             throws IOException {
1808         BluetoothServerSocket socket = new BluetoothServerSocket(
1809                 BluetoothSocket.TYPE_L2CAP, true, true, port, mitm, min16DigitPin);
1810         int errno = socket.mSocket.bindListen();
1811         if(port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
1812             socket.setChannel(socket.mSocket.getPort());
1813         }
1814         if (errno != 0) {
1815             //TODO(BT): Throw the same exception error code
1816             // that the previous code was using.
1817             //socket.mSocket.throwErrnoNative(errno);
1818             throw new IOException("Error: " + errno);
1819         }
1820         return socket;
1821     }
1822 
1823     /**
1824      * Construct an encrypted, authenticated, L2CAP server socket.
1825      * Call #accept to retrieve connections to this socket.
1826      * <p>To auto assign a port without creating a SDP record use
1827      * {@link SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number.
1828      * @param port    the PSM to listen on
1829      * @return An L2CAP BluetoothServerSocket
1830      * @throws IOException On error, for example Bluetooth not available, or
1831      *                     insufficient permissions.
1832      * @hide
1833      */
listenUsingL2capOn(int port)1834     public BluetoothServerSocket listenUsingL2capOn(int port) throws IOException {
1835         return listenUsingL2capOn(port, false, false);
1836     }
1837 
1838     /**
1839      * Read the local Out of Band Pairing Data
1840      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1841      *
1842      * @return Pair<byte[], byte[]> of Hash and Randomizer
1843      *
1844      * @hide
1845      */
readOutOfBandData()1846     public Pair<byte[], byte[]> readOutOfBandData() {
1847         if (getState() != STATE_ON) return null;
1848         //TODO(BT
1849         /*
1850         try {
1851             byte[] hash;
1852             byte[] randomizer;
1853 
1854             byte[] ret = null;
1855             mServiceLock.readLock().lock();
1856             if (mService != null) mService.readOutOfBandData();
1857 
1858             if (ret  == null || ret.length != 32) return null;
1859 
1860             hash = Arrays.copyOfRange(ret, 0, 16);
1861             randomizer = Arrays.copyOfRange(ret, 16, 32);
1862 
1863             if (DBG) {
1864                 Log.d(TAG, "readOutOfBandData:" + Arrays.toString(hash) +
1865                   ":" + Arrays.toString(randomizer));
1866             }
1867             return new Pair<byte[], byte[]>(hash, randomizer);
1868 
1869         } catch (RemoteException e) {
1870             Log.e(TAG, "", e);
1871         } finally {
1872             mServiceLock.readLock().unlock();
1873         }
1874         */
1875         return null;
1876     }
1877 
1878     /**
1879      * Get the profile proxy object associated with the profile.
1880      *
1881      * <p>Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET},
1882      * {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#GATT}, or
1883      * {@link BluetoothProfile#GATT_SERVER}. Clients must implement
1884      * {@link BluetoothProfile.ServiceListener} to get notified of
1885      * the connection status and to get the proxy object.
1886      *
1887      * @param context Context of the application
1888      * @param listener The service Listener for connection callbacks.
1889      * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEALTH},
1890      *                {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}.
1891      *                {@link BluetoothProfile#GATT} or {@link BluetoothProfile#GATT_SERVER}.
1892      * @return true on success, false on error
1893      */
getProfileProxy(Context context, BluetoothProfile.ServiceListener listener, int profile)1894     public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,
1895                                    int profile) {
1896         if (context == null || listener == null) return false;
1897 
1898         if (profile == BluetoothProfile.HEADSET) {
1899             BluetoothHeadset headset = new BluetoothHeadset(context, listener);
1900             return true;
1901         } else if (profile == BluetoothProfile.A2DP) {
1902             BluetoothA2dp a2dp = new BluetoothA2dp(context, listener);
1903             return true;
1904         } else if (profile == BluetoothProfile.A2DP_SINK) {
1905             BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener);
1906             return true;
1907         } else if (profile == BluetoothProfile.AVRCP_CONTROLLER) {
1908             BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener);
1909             return true;
1910         } else if (profile == BluetoothProfile.INPUT_DEVICE) {
1911             BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener);
1912             return true;
1913         } else if (profile == BluetoothProfile.PAN) {
1914             BluetoothPan pan = new BluetoothPan(context, listener);
1915             return true;
1916         } else if (profile == BluetoothProfile.HEALTH) {
1917             BluetoothHealth health = new BluetoothHealth(context, listener);
1918             return true;
1919         } else if (profile == BluetoothProfile.MAP) {
1920             BluetoothMap map = new BluetoothMap(context, listener);
1921             return true;
1922         } else if (profile == BluetoothProfile.HEADSET_CLIENT) {
1923             BluetoothHeadsetClient headsetClient = new BluetoothHeadsetClient(context, listener);
1924             return true;
1925         } else if (profile == BluetoothProfile.SAP) {
1926             BluetoothSap sap = new BluetoothSap(context, listener);
1927             return true;
1928         } else if (profile == BluetoothProfile.PBAP_CLIENT) {
1929             BluetoothPbapClient pbapClient = new BluetoothPbapClient(context, listener);
1930             return true;
1931         } else {
1932             return false;
1933         }
1934     }
1935 
1936     /**
1937      * Close the connection of the profile proxy to the Service.
1938      *
1939      * <p> Clients should call this when they are no longer using
1940      * the proxy obtained from {@link #getProfileProxy}.
1941      * Profile can be one of  {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET} or
1942      * {@link BluetoothProfile#A2DP}
1943      *
1944      * @param profile
1945      * @param proxy Profile proxy object
1946      */
closeProfileProxy(int profile, BluetoothProfile proxy)1947     public void closeProfileProxy(int profile, BluetoothProfile proxy) {
1948         if (proxy == null) return;
1949 
1950         switch (profile) {
1951             case BluetoothProfile.HEADSET:
1952                 BluetoothHeadset headset = (BluetoothHeadset)proxy;
1953                 headset.close();
1954                 break;
1955             case BluetoothProfile.A2DP:
1956                 BluetoothA2dp a2dp = (BluetoothA2dp)proxy;
1957                 a2dp.close();
1958                 break;
1959             case BluetoothProfile.A2DP_SINK:
1960                 BluetoothA2dpSink a2dpSink = (BluetoothA2dpSink)proxy;
1961                 a2dpSink.close();
1962                 break;
1963             case BluetoothProfile.AVRCP_CONTROLLER:
1964                 BluetoothAvrcpController avrcp = (BluetoothAvrcpController)proxy;
1965                 avrcp.close();
1966                 break;
1967             case BluetoothProfile.INPUT_DEVICE:
1968                 BluetoothInputDevice iDev = (BluetoothInputDevice)proxy;
1969                 iDev.close();
1970                 break;
1971             case BluetoothProfile.PAN:
1972                 BluetoothPan pan = (BluetoothPan)proxy;
1973                 pan.close();
1974                 break;
1975             case BluetoothProfile.HEALTH:
1976                 BluetoothHealth health = (BluetoothHealth)proxy;
1977                 health.close();
1978                 break;
1979            case BluetoothProfile.GATT:
1980                 BluetoothGatt gatt = (BluetoothGatt)proxy;
1981                 gatt.close();
1982                 break;
1983             case BluetoothProfile.GATT_SERVER:
1984                 BluetoothGattServer gattServer = (BluetoothGattServer)proxy;
1985                 gattServer.close();
1986                 break;
1987             case BluetoothProfile.MAP:
1988                 BluetoothMap map = (BluetoothMap)proxy;
1989                 map.close();
1990                 break;
1991             case BluetoothProfile.HEADSET_CLIENT:
1992                 BluetoothHeadsetClient headsetClient = (BluetoothHeadsetClient)proxy;
1993                 headsetClient.close();
1994                 break;
1995             case BluetoothProfile.SAP:
1996                 BluetoothSap sap = (BluetoothSap)proxy;
1997                 sap.close();
1998                 break;
1999             case BluetoothProfile.PBAP_CLIENT:
2000                 BluetoothPbapClient pbapClient = (BluetoothPbapClient)proxy;
2001                 pbapClient.close();
2002                 break;
2003         }
2004     }
2005 
2006     final private IBluetoothManagerCallback mManagerCallback =
2007         new IBluetoothManagerCallback.Stub() {
2008             public void onBluetoothServiceUp(IBluetooth bluetoothService) {
2009                 if (VDBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
2010 
2011                 mServiceLock.writeLock().lock();
2012                 mService = bluetoothService;
2013                 mServiceLock.writeLock().unlock();
2014 
2015                 synchronized (mProxyServiceStateCallbacks) {
2016                     for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ) {
2017                         try {
2018                             if (cb != null) {
2019                                 cb.onBluetoothServiceUp(bluetoothService);
2020                             } else {
2021                                 Log.d(TAG, "onBluetoothServiceUp: cb is null!!!");
2022                             }
2023                         } catch (Exception e) {
2024                             Log.e(TAG,"",e);
2025                         }
2026                     }
2027                 }
2028             }
2029 
2030             public void onBluetoothServiceDown() {
2031                 if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService);
2032 
2033                 try {
2034                     mServiceLock.writeLock().lock();
2035                     mService = null;
2036                     if (mLeScanClients != null) mLeScanClients.clear();
2037                     if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup();
2038                     if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup();
2039                 } finally {
2040                     mServiceLock.writeLock().unlock();
2041                 }
2042 
2043                 synchronized (mProxyServiceStateCallbacks) {
2044                     for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
2045                         try {
2046                             if (cb != null) {
2047                                 cb.onBluetoothServiceDown();
2048                             } else {
2049                                 Log.d(TAG, "onBluetoothServiceDown: cb is null!!!");
2050                             }
2051                         } catch (Exception e) {
2052                             Log.e(TAG,"",e);
2053                         }
2054                     }
2055                 }
2056             }
2057 
2058             public void onBrEdrDown() {
2059                 if (VDBG) Log.i(TAG, "on QBrEdrDown: ");
2060             }
2061     };
2062 
2063     /**
2064      * Enable the Bluetooth Adapter, but don't auto-connect devices
2065      * and don't persist state. Only for use by system applications.
2066      * @hide
2067      */
enableNoAutoConnect()2068     public boolean enableNoAutoConnect() {
2069         if (isEnabled() == true){
2070             if (DBG) Log.d(TAG, "enableNoAutoConnect(): BT is already enabled..!");
2071             return true;
2072         }
2073         try {
2074             return mManagerService.enableNoAutoConnect();
2075         } catch (RemoteException e) {Log.e(TAG, "", e);}
2076         return false;
2077     }
2078 
2079     /**
2080      * Enable control of the Bluetooth Adapter for a single application.
2081      *
2082      * <p>Some applications need to use Bluetooth for short periods of time to
2083      * transfer data but don't want all the associated implications like
2084      * automatic connection to headsets etc.
2085      *
2086      * <p> Multiple applications can call this. This is reference counted and
2087      * Bluetooth disabled only when no one else is using it. There will be no UI
2088      * shown to the user while bluetooth is being enabled. Any user action will
2089      * override this call. For example, if user wants Bluetooth on and the last
2090      * user of this API wanted to disable Bluetooth, Bluetooth will not be
2091      * turned off.
2092      *
2093      * <p> This API is only meant to be used by internal applications. Third
2094      * party applications but use {@link #enable} and {@link #disable} APIs.
2095      *
2096      * <p> If this API returns true, it means the callback will be called.
2097      * The callback will be called with the current state of Bluetooth.
2098      * If the state is not what was requested, an internal error would be the
2099      * reason. If Bluetooth is already on and if this function is called to turn
2100      * it on, the api will return true and a callback will be called.
2101      *
2102      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
2103      *
2104      * @param on True for on, false for off.
2105      * @param callback The callback to notify changes to the state.
2106      * @hide
2107      */
changeApplicationBluetoothState(boolean on, BluetoothStateChangeCallback callback)2108     public boolean changeApplicationBluetoothState(boolean on,
2109                                                    BluetoothStateChangeCallback callback) {
2110         if (callback == null) return false;
2111 
2112         //TODO(BT)
2113         /*
2114         try {
2115             mServiceLock.readLock().lock();
2116             if (mService != null) {
2117                 return mService.changeApplicationBluetoothState(on, new
2118                     StateChangeCallbackWrapper(callback), new Binder());
2119             }
2120         } catch (RemoteException e) {
2121             Log.e(TAG, "changeBluetoothState", e);
2122         } finally {
2123             mServiceLock.readLock().unlock();
2124         }
2125         */
2126         return false;
2127     }
2128 
2129     /**
2130      * @hide
2131      */
2132     public interface BluetoothStateChangeCallback {
onBluetoothStateChange(boolean on)2133         public void onBluetoothStateChange(boolean on);
2134     }
2135 
2136     /**
2137      * @hide
2138      */
2139     public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub {
2140         private BluetoothStateChangeCallback mCallback;
2141 
StateChangeCallbackWrapper(BluetoothStateChangeCallback callback)2142         StateChangeCallbackWrapper(BluetoothStateChangeCallback
2143                 callback) {
2144             mCallback = callback;
2145         }
2146 
2147         @Override
onBluetoothStateChange(boolean on)2148         public void onBluetoothStateChange(boolean on) {
2149             mCallback.onBluetoothStateChange(on);
2150         }
2151     }
2152 
toDeviceSet(BluetoothDevice[] devices)2153     private Set<BluetoothDevice> toDeviceSet(BluetoothDevice[] devices) {
2154         Set<BluetoothDevice> deviceSet = new HashSet<BluetoothDevice>(Arrays.asList(devices));
2155         return Collections.unmodifiableSet(deviceSet);
2156     }
2157 
finalize()2158     protected void finalize() throws Throwable {
2159         try {
2160             mManagerService.unregisterAdapter(mManagerCallback);
2161         } catch (RemoteException e) {
2162             Log.e(TAG, "", e);
2163         } finally {
2164             super.finalize();
2165         }
2166     }
2167 
2168 
2169     /**
2170      * Validate a String Bluetooth address, such as "00:43:A8:23:10:F0"
2171      * <p>Alphabetic characters must be uppercase to be valid.
2172      *
2173      * @param address Bluetooth address as string
2174      * @return true if the address is valid, false otherwise
2175      */
checkBluetoothAddress(String address)2176     public static boolean checkBluetoothAddress(String address) {
2177         if (address == null || address.length() != ADDRESS_LENGTH) {
2178             return false;
2179         }
2180         for (int i = 0; i < ADDRESS_LENGTH; i++) {
2181             char c = address.charAt(i);
2182             switch (i % 3) {
2183             case 0:
2184             case 1:
2185                 if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
2186                     // hex character, OK
2187                     break;
2188                 }
2189                 return false;
2190             case 2:
2191                 if (c == ':') {
2192                     break;  // OK
2193                 }
2194                 return false;
2195             }
2196         }
2197         return true;
2198     }
2199 
getBluetoothManager()2200     /*package*/ IBluetoothManager getBluetoothManager() {
2201             return mManagerService;
2202     }
2203 
2204     final private ArrayList<IBluetoothManagerCallback> mProxyServiceStateCallbacks = new ArrayList<IBluetoothManagerCallback>();
2205 
getBluetoothService(IBluetoothManagerCallback cb)2206     /*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) {
2207         synchronized (mProxyServiceStateCallbacks) {
2208             if (cb == null) {
2209                 Log.w(TAG, "getBluetoothService() called with no BluetoothManagerCallback");
2210             } else if (!mProxyServiceStateCallbacks.contains(cb)) {
2211                 mProxyServiceStateCallbacks.add(cb);
2212             }
2213         }
2214         return mService;
2215     }
2216 
removeServiceStateCallback(IBluetoothManagerCallback cb)2217     /*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) {
2218         synchronized (mProxyServiceStateCallbacks) {
2219             mProxyServiceStateCallbacks.remove(cb);
2220         }
2221     }
2222 
2223     /**
2224      * Callback interface used to deliver LE scan results.
2225      *
2226      * @see #startLeScan(LeScanCallback)
2227      * @see #startLeScan(UUID[], LeScanCallback)
2228      */
2229     public interface LeScanCallback {
2230         /**
2231          * Callback reporting an LE device found during a device scan initiated
2232          * by the {@link BluetoothAdapter#startLeScan} function.
2233          *
2234          * @param device Identifies the remote device
2235          * @param rssi The RSSI value for the remote device as reported by the
2236          *             Bluetooth hardware. 0 if no RSSI value is available.
2237          * @param scanRecord The content of the advertisement record offered by
2238          *                   the remote device.
2239          */
onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord)2240         public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord);
2241     }
2242 
2243     /**
2244      * Starts a scan for Bluetooth LE devices.
2245      *
2246      * <p>Results of the scan are reported using the
2247      * {@link LeScanCallback#onLeScan} callback.
2248      *
2249      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
2250      *
2251      * @param callback the callback LE scan results are delivered
2252      * @return true, if the scan was started successfully
2253      * @deprecated use {@link BluetoothLeScanner#startScan(List, ScanSettings, ScanCallback)}
2254      *             instead.
2255      */
2256     @Deprecated
2257     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
startLeScan(LeScanCallback callback)2258     public boolean startLeScan(LeScanCallback callback) {
2259         return startLeScan(null, callback);
2260     }
2261 
2262     /**
2263      * Starts a scan for Bluetooth LE devices, looking for devices that
2264      * advertise given services.
2265      *
2266      * <p>Devices which advertise all specified services are reported using the
2267      * {@link LeScanCallback#onLeScan} callback.
2268      *
2269      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
2270      *
2271      * @param serviceUuids Array of services to look for
2272      * @param callback the callback LE scan results are delivered
2273      * @return true, if the scan was started successfully
2274      * @deprecated use {@link BluetoothLeScanner#startScan(List, ScanSettings, ScanCallback)}
2275      *             instead.
2276      */
2277     @Deprecated
2278     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
startLeScan(final UUID[] serviceUuids, final LeScanCallback callback)2279     public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback) {
2280         if (DBG) Log.d(TAG, "startLeScan(): " + Arrays.toString(serviceUuids));
2281         if (callback == null) {
2282             if (DBG) Log.e(TAG, "startLeScan: null callback");
2283             return false;
2284         }
2285         BluetoothLeScanner scanner = getBluetoothLeScanner();
2286         if (scanner == null) {
2287             if (DBG) Log.e(TAG, "startLeScan: cannot get BluetoothLeScanner");
2288             return false;
2289         }
2290 
2291         synchronized(mLeScanClients) {
2292             if (mLeScanClients.containsKey(callback)) {
2293                 if (DBG) Log.e(TAG, "LE Scan has already started");
2294                 return false;
2295             }
2296 
2297             try {
2298                 IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
2299                 if (iGatt == null) {
2300                     // BLE is not supported
2301                     return false;
2302                 }
2303 
2304                 ScanCallback scanCallback = new ScanCallback() {
2305                     @Override
2306                     public void onScanResult(int callbackType, ScanResult result) {
2307                         if (callbackType != ScanSettings.CALLBACK_TYPE_ALL_MATCHES) {
2308                             // Should not happen.
2309                             Log.e(TAG, "LE Scan has already started");
2310                             return;
2311                         }
2312                         ScanRecord scanRecord = result.getScanRecord();
2313                         if (scanRecord == null) {
2314                             return;
2315                         }
2316                         if (serviceUuids != null) {
2317                             List<ParcelUuid> uuids = new ArrayList<ParcelUuid>();
2318                             for (UUID uuid : serviceUuids) {
2319                                 uuids.add(new ParcelUuid(uuid));
2320                             }
2321                             List<ParcelUuid> scanServiceUuids = scanRecord.getServiceUuids();
2322                             if (scanServiceUuids == null || !scanServiceUuids.containsAll(uuids)) {
2323                                 if (DBG) Log.d(TAG, "uuids does not match");
2324                                 return;
2325                             }
2326                         }
2327                         callback.onLeScan(result.getDevice(), result.getRssi(),
2328                                 scanRecord.getBytes());
2329                     }
2330                 };
2331                 ScanSettings settings = new ScanSettings.Builder()
2332                     .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
2333                     .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
2334 
2335                 List<ScanFilter> filters = new ArrayList<ScanFilter>();
2336                 if (serviceUuids != null && serviceUuids.length > 0) {
2337                     // Note scan filter does not support matching an UUID array so we put one
2338                     // UUID to hardware and match the whole array in callback.
2339                     ScanFilter filter = new ScanFilter.Builder().setServiceUuid(
2340                             new ParcelUuid(serviceUuids[0])).build();
2341                     filters.add(filter);
2342                 }
2343                 scanner.startScan(filters, settings, scanCallback);
2344 
2345                 mLeScanClients.put(callback, scanCallback);
2346                 return true;
2347 
2348             } catch (RemoteException e) {
2349                 Log.e(TAG,"",e);
2350             }
2351         }
2352         return false;
2353     }
2354 
2355     /**
2356      * Stops an ongoing Bluetooth LE device scan.
2357      *
2358      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
2359      *
2360      * @param callback used to identify which scan to stop
2361      *        must be the same handle used to start the scan
2362      * @deprecated Use {@link BluetoothLeScanner#stopScan(ScanCallback)} instead.
2363      */
2364     @Deprecated
2365     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
stopLeScan(LeScanCallback callback)2366     public void stopLeScan(LeScanCallback callback) {
2367         if (DBG) Log.d(TAG, "stopLeScan()");
2368         BluetoothLeScanner scanner = getBluetoothLeScanner();
2369         if (scanner == null) {
2370             return;
2371         }
2372         synchronized (mLeScanClients) {
2373             ScanCallback scanCallback = mLeScanClients.remove(callback);
2374             if (scanCallback == null) {
2375                 if (DBG) Log.d(TAG, "scan not started yet");
2376                 return;
2377             }
2378             scanner.stopScan(scanCallback);
2379         }
2380     }
2381 }
2382