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