1 /*
2  * Copyright (C) 2009-2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.bluetooth;
18 
19 import android.annotation.SdkConstant;
20 import android.annotation.SdkConstant.SdkConstantType;
21 import android.bluetooth.le.BluetoothLeAdvertiser;
22 import android.bluetooth.le.BluetoothLeScanner;
23 import android.bluetooth.le.ScanCallback;
24 import android.bluetooth.le.ScanFilter;
25 import android.bluetooth.le.ScanRecord;
26 import android.bluetooth.le.ScanResult;
27 import android.bluetooth.le.ScanSettings;
28 import android.content.Context;
29 import android.os.Handler;
30 import android.os.IBinder;
31 import android.os.Looper;
32 import android.os.ParcelUuid;
33 import android.os.RemoteException;
34 import android.os.ServiceManager;
35 import android.util.Log;
36 import android.util.Pair;
37 
38 import java.io.IOException;
39 import java.lang.ref.WeakReference;
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.Collections;
43 import java.util.HashMap;
44 import java.util.HashSet;
45 import java.util.List;
46 import java.util.Locale;
47 import java.util.Map;
48 import java.util.Set;
49 import java.util.UUID;
50 
51 /**
52  * Represents the local device Bluetooth adapter. The {@link BluetoothAdapter}
53  * lets you perform fundamental Bluetooth tasks, such as initiate
54  * device discovery, query a list of bonded (paired) devices,
55  * instantiate a {@link BluetoothDevice} using a known MAC address, and create
56  * a {@link BluetoothServerSocket} to listen for connection requests from other
57  * devices, and start a scan for Bluetooth LE devices.
58  *
59  * <p>To get a {@link BluetoothAdapter} representing the local Bluetooth
60  * adapter, when running on JELLY_BEAN_MR1 and below, call the
61  * static {@link #getDefaultAdapter} method; when running on JELLY_BEAN_MR2 and
62  * higher, retrieve it through
63  * {@link android.content.Context#getSystemService} with
64  * {@link android.content.Context#BLUETOOTH_SERVICE}.
65  * Fundamentally, this is your starting point for all
66  * Bluetooth actions. Once you have the local adapter, you can get a set of
67  * {@link BluetoothDevice} objects representing all paired devices with
68  * {@link #getBondedDevices()}; start device discovery with
69  * {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to
70  * listen for incoming connection requests with
71  * {@link #listenUsingRfcommWithServiceRecord(String,UUID)}; or start a scan for
72  * Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}.
73  *
74  * <p class="note"><strong>Note:</strong>
75  * Most methods require the {@link android.Manifest.permission#BLUETOOTH}
76  * permission and some also require the
77  * {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
78  *
79  * <div class="special reference">
80  * <h3>Developer Guides</h3>
81  * <p>For more information about using Bluetooth, read the
82  * <a href="{@docRoot}guide/topics/wireless/bluetooth.html">Bluetooth</a> developer guide.</p>
83  * </div>
84  *
85  * {@see BluetoothDevice}
86  * {@see BluetoothServerSocket}
87  */
88 public final class BluetoothAdapter {
89     private static final String TAG = "BluetoothAdapter";
90     private static final boolean DBG = true;
91     private static final boolean VDBG = false;
92 
93     /**
94      * Sentinel error value for this class. Guaranteed to not equal any other
95      * integer constant in this class. Provided as a convenience for functions
96      * that require a sentinel error value, for example:
97      * <p><code>Intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
98      * BluetoothAdapter.ERROR)</code>
99      */
100     public static final int ERROR = Integer.MIN_VALUE;
101 
102     /**
103      * Broadcast Action: The state of the local Bluetooth adapter has been
104      * changed.
105      * <p>For example, Bluetooth has been turned on or off.
106      * <p>Always contains the extra fields {@link #EXTRA_STATE} and {@link
107      * #EXTRA_PREVIOUS_STATE} containing the new and old states
108      * respectively.
109      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
110      */
111     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
112     public static final String ACTION_STATE_CHANGED =
113             "android.bluetooth.adapter.action.STATE_CHANGED";
114 
115     /**
116      * Used as an int extra field in {@link #ACTION_STATE_CHANGED}
117      * intents to request the current power state. Possible values are:
118      * {@link #STATE_OFF},
119      * {@link #STATE_TURNING_ON},
120      * {@link #STATE_ON},
121      * {@link #STATE_TURNING_OFF},
122      */
123     public static final String EXTRA_STATE =
124             "android.bluetooth.adapter.extra.STATE";
125     /**
126      * Used as an int extra field in {@link #ACTION_STATE_CHANGED}
127      * intents to request the previous power state. Possible values are:
128      * {@link #STATE_OFF},
129      * {@link #STATE_TURNING_ON},
130      * {@link #STATE_ON},
131      * {@link #STATE_TURNING_OFF},
132      */
133     public static final String EXTRA_PREVIOUS_STATE =
134             "android.bluetooth.adapter.extra.PREVIOUS_STATE";
135 
136     /**
137      * Indicates the local Bluetooth adapter is off.
138      */
139     public static final int STATE_OFF = 10;
140     /**
141      * Indicates the local Bluetooth adapter is turning on. However local
142      * clients should wait for {@link #STATE_ON} before attempting to
143      * use the adapter.
144      */
145     public static final int STATE_TURNING_ON = 11;
146     /**
147      * Indicates the local Bluetooth adapter is on, and ready for use.
148      */
149     public static final int STATE_ON = 12;
150     /**
151      * Indicates the local Bluetooth adapter is turning off. Local clients
152      * should immediately attempt graceful disconnection of any remote links.
153      */
154     public static final int STATE_TURNING_OFF = 13;
155 
156     /**
157      * Activity Action: Show a system activity that requests discoverable mode.
158      * This activity will also request the user to turn on Bluetooth if it
159      * is not currently enabled.
160      * <p>Discoverable mode is equivalent to {@link
161      * #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. It allows remote devices to see
162      * this Bluetooth adapter when they perform a discovery.
163      * <p>For privacy, Android is not discoverable by default.
164      * <p>The sender of this Intent can optionally use extra field {@link
165      * #EXTRA_DISCOVERABLE_DURATION} to request the duration of
166      * discoverability. Currently the default duration is 120 seconds, and
167      * maximum duration is capped at 300 seconds for each request.
168      * <p>Notification of the result of this activity is posted using the
169      * {@link android.app.Activity#onActivityResult} callback. The
170      * <code>resultCode</code>
171      * will be the duration (in seconds) of discoverability or
172      * {@link android.app.Activity#RESULT_CANCELED} if the user rejected
173      * discoverability or an error has occurred.
174      * <p>Applications can also listen for {@link #ACTION_SCAN_MODE_CHANGED}
175      * for global notification whenever the scan mode changes. For example, an
176      * application can be notified when the device has ended discoverability.
177      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
178      */
179     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
180     public static final String ACTION_REQUEST_DISCOVERABLE =
181             "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
182 
183     /**
184      * Used as an optional int extra field in {@link
185      * #ACTION_REQUEST_DISCOVERABLE} intents to request a specific duration
186      * for discoverability in seconds. The current default is 120 seconds, and
187      * requests over 300 seconds will be capped. These values could change.
188      */
189     public static final String EXTRA_DISCOVERABLE_DURATION =
190             "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION";
191 
192     /**
193      * Activity Action: Show a system activity that allows the user to turn on
194      * Bluetooth.
195      * <p>This system activity will return once Bluetooth has completed turning
196      * on, or the user has decided not to turn Bluetooth on.
197      * <p>Notification of the result of this activity is posted using the
198      * {@link android.app.Activity#onActivityResult} callback. The
199      * <code>resultCode</code>
200      * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been
201      * turned on or {@link android.app.Activity#RESULT_CANCELED} if the user
202      * has rejected the request or an error has occurred.
203      * <p>Applications can also listen for {@link #ACTION_STATE_CHANGED}
204      * for global notification whenever Bluetooth is turned on or off.
205      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
206      */
207     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
208     public static final String ACTION_REQUEST_ENABLE =
209             "android.bluetooth.adapter.action.REQUEST_ENABLE";
210 
211     /**
212      * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter
213      * has changed.
214      * <p>Always contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link
215      * #EXTRA_PREVIOUS_SCAN_MODE} containing the new and old scan modes
216      * respectively.
217      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
218      */
219     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
220     public static final String ACTION_SCAN_MODE_CHANGED =
221             "android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
222 
223     /**
224      * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED}
225      * intents to request the current scan mode. Possible values are:
226      * {@link #SCAN_MODE_NONE},
227      * {@link #SCAN_MODE_CONNECTABLE},
228      * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE},
229      */
230     public static final String EXTRA_SCAN_MODE = "android.bluetooth.adapter.extra.SCAN_MODE";
231     /**
232      * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED}
233      * intents to request the previous scan mode. Possible values are:
234      * {@link #SCAN_MODE_NONE},
235      * {@link #SCAN_MODE_CONNECTABLE},
236      * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE},
237      */
238     public static final String EXTRA_PREVIOUS_SCAN_MODE =
239             "android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE";
240 
241     /**
242      * Indicates that both inquiry scan and page scan are disabled on the local
243      * Bluetooth adapter. Therefore this device is neither discoverable
244      * nor connectable from remote Bluetooth devices.
245      */
246     public static final int SCAN_MODE_NONE = 20;
247     /**
248      * Indicates that inquiry scan is disabled, but page scan is enabled on the
249      * local Bluetooth adapter. Therefore this device is not discoverable from
250      * remote Bluetooth devices, but is connectable from remote devices that
251      * have previously discovered this device.
252      */
253     public static final int SCAN_MODE_CONNECTABLE = 21;
254     /**
255      * Indicates that both inquiry scan and page scan are enabled on the local
256      * Bluetooth adapter. Therefore this device is both discoverable and
257      * connectable from remote Bluetooth devices.
258      */
259     public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23;
260 
261     /**
262      * Broadcast Action: The local Bluetooth adapter has started the remote
263      * device discovery process.
264      * <p>This usually involves an inquiry scan of about 12 seconds, followed
265      * by a page scan of each new device to retrieve its Bluetooth name.
266      * <p>Register for {@link BluetoothDevice#ACTION_FOUND} to be notified as
267      * remote Bluetooth devices are found.
268      * <p>Device discovery is a heavyweight procedure. New connections to
269      * remote Bluetooth devices should not be attempted while discovery is in
270      * progress, and existing connections will experience limited bandwidth
271      * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
272      * discovery.
273      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
274      */
275     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
276     public static final String ACTION_DISCOVERY_STARTED =
277             "android.bluetooth.adapter.action.DISCOVERY_STARTED";
278     /**
279      * Broadcast Action: The local Bluetooth adapter has finished the device
280      * discovery process.
281      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
282      */
283     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
284     public static final String ACTION_DISCOVERY_FINISHED =
285             "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
286 
287     /**
288      * Broadcast Action: The local Bluetooth adapter has changed its friendly
289      * Bluetooth name.
290      * <p>This name is visible to remote Bluetooth devices.
291      * <p>Always contains the extra field {@link #EXTRA_LOCAL_NAME} containing
292      * the name.
293      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
294      */
295     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
296     public static final String ACTION_LOCAL_NAME_CHANGED =
297             "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED";
298     /**
299      * Used as a String extra field in {@link #ACTION_LOCAL_NAME_CHANGED}
300      * intents to request the local Bluetooth name.
301      */
302     public static final String EXTRA_LOCAL_NAME = "android.bluetooth.adapter.extra.LOCAL_NAME";
303 
304     /**
305      * Intent used to broadcast the change in connection state of the local
306      * Bluetooth adapter to a profile of the remote device. When the adapter is
307      * not connected to any profiles of any remote devices and it attempts a
308      * connection to a profile this intent will sent. Once connected, this intent
309      * will not be sent for any more connection attempts to any profiles of any
310      * remote device. When the adapter disconnects from the last profile its
311      * connected to of any remote device, this intent will be sent.
312      *
313      * <p> This intent is useful for applications that are only concerned about
314      * whether the local adapter is connected to any profile of any device and
315      * are not really concerned about which profile. For example, an application
316      * which displays an icon to display whether Bluetooth is connected or not
317      * can use this intent.
318      *
319      * <p>This intent will have 3 extras:
320      * {@link #EXTRA_CONNECTION_STATE} - The current connection state.
321      * {@link #EXTRA_PREVIOUS_CONNECTION_STATE}- The previous connection state.
322      * {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
323      *
324      * {@link #EXTRA_CONNECTION_STATE} or {@link #EXTRA_PREVIOUS_CONNECTION_STATE}
325      * can be any of {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
326      * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
327      *
328      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
329      */
330     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
331     public static final String ACTION_CONNECTION_STATE_CHANGED =
332         "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED";
333 
334     /**
335      * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED}
336      *
337      * This extra represents the current connection state.
338      */
339     public static final String EXTRA_CONNECTION_STATE =
340         "android.bluetooth.adapter.extra.CONNECTION_STATE";
341 
342     /**
343      * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED}
344      *
345      * This extra represents the previous connection state.
346      */
347     public static final String EXTRA_PREVIOUS_CONNECTION_STATE =
348           "android.bluetooth.adapter.extra.PREVIOUS_CONNECTION_STATE";
349 
350     /** The profile is in disconnected state */
351     public static final int STATE_DISCONNECTED  = 0;
352     /** The profile is in connecting state */
353     public static final int STATE_CONNECTING    = 1;
354     /** The profile is in connected state */
355     public static final int STATE_CONNECTED     = 2;
356     /** The profile is in disconnecting state */
357     public static final int STATE_DISCONNECTING = 3;
358 
359     /** @hide */
360     public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager";
361 
362     private static final int ADDRESS_LENGTH = 17;
363 
364     private static final int CONTROLLER_ENERGY_UPDATE_TIMEOUT_MILLIS = 30;
365     /** @hide */
366     public static final int ACTIVITY_ENERGY_INFO_CACHED = 0;
367     /** @hide */
368     public static final int ACTIVITY_ENERGY_INFO_REFRESHED = 1;
369 
370     /**
371      * Lazily initialized singleton. Guaranteed final after first object
372      * constructed.
373      */
374     private static BluetoothAdapter sAdapter;
375 
376     private static BluetoothLeScanner sBluetoothLeScanner;
377     private static BluetoothLeAdvertiser sBluetoothLeAdvertiser;
378 
379     private final IBluetoothManager mManagerService;
380     private IBluetooth mService;
381 
382     private final Object mLock = new Object();
383     private final Map<LeScanCallback, ScanCallback> mLeScanClients;
384 
385     /**
386      * Get a handle to the default local Bluetooth adapter.
387      * <p>Currently Android only supports one Bluetooth adapter, but the API
388      * could be extended to support more. This will always return the default
389      * adapter.
390      * @return the default local adapter, or null if Bluetooth is not supported
391      *         on this hardware platform
392      */
getDefaultAdapter()393     public static synchronized BluetoothAdapter getDefaultAdapter() {
394         if (sAdapter == null) {
395             IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);
396             if (b != null) {
397                 IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b);
398                 sAdapter = new BluetoothAdapter(managerService);
399             } else {
400                 Log.e(TAG, "Bluetooth binder is null");
401             }
402         }
403         return sAdapter;
404     }
405 
406     /**
407      * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance.
408      */
BluetoothAdapter(IBluetoothManager managerService)409     BluetoothAdapter(IBluetoothManager managerService) {
410 
411         if (managerService == null) {
412             throw new IllegalArgumentException("bluetooth manager service is null");
413         }
414         try {
415             mService = managerService.registerAdapter(mManagerCallback);
416         } catch (RemoteException e) {Log.e(TAG, "", e);}
417         mManagerService = managerService;
418         mLeScanClients = new HashMap<LeScanCallback, ScanCallback>();
419     }
420 
421     /**
422      * Get a {@link BluetoothDevice} object for the given Bluetooth hardware
423      * address.
424      * <p>Valid Bluetooth hardware addresses must be upper case, in a format
425      * such as "00:11:22:33:AA:BB". The helper {@link #checkBluetoothAddress} is
426      * available to validate a Bluetooth address.
427      * <p>A {@link BluetoothDevice} will always be returned for a valid
428      * hardware address, even if this adapter has never seen that device.
429      *
430      * @param address valid Bluetooth MAC address
431      * @throws IllegalArgumentException if address is invalid
432      */
getRemoteDevice(String address)433     public BluetoothDevice getRemoteDevice(String address) {
434         return new BluetoothDevice(address);
435     }
436 
437     /**
438      * Get a {@link BluetoothDevice} object for the given Bluetooth hardware
439      * address.
440      * <p>Valid Bluetooth hardware addresses must be 6 bytes. This method
441      * expects the address in network byte order (MSB first).
442      * <p>A {@link BluetoothDevice} will always be returned for a valid
443      * hardware address, even if this adapter has never seen that device.
444      *
445      * @param address Bluetooth MAC address (6 bytes)
446      * @throws IllegalArgumentException if address is invalid
447      */
getRemoteDevice(byte[] address)448     public BluetoothDevice getRemoteDevice(byte[] address) {
449         if (address == null || address.length != 6) {
450             throw new IllegalArgumentException("Bluetooth address must have 6 bytes");
451         }
452         return new BluetoothDevice(String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X",
453                 address[0], address[1], address[2], address[3], address[4], address[5]));
454     }
455 
456     /**
457      * Returns a {@link BluetoothLeAdvertiser} object for Bluetooth LE Advertising operations.
458      * Will return null if Bluetooth is turned off or if Bluetooth LE Advertising is not
459      * supported on this device.
460      * <p>
461      * Use {@link #isMultipleAdvertisementSupported()} to check whether LE Advertising is supported
462      * on this device before calling this method.
463      */
getBluetoothLeAdvertiser()464     public BluetoothLeAdvertiser getBluetoothLeAdvertiser() {
465         if (getState() != STATE_ON) {
466             return null;
467         }
468         if (!isMultipleAdvertisementSupported() && !isPeripheralModeSupported()) {
469             Log.e(TAG, "bluetooth le advertising not supported");
470             return null;
471         }
472         synchronized(mLock) {
473             if (sBluetoothLeAdvertiser == null) {
474                 sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService);
475             }
476         }
477         return sBluetoothLeAdvertiser;
478     }
479 
480     /**
481      * Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations.
482      */
getBluetoothLeScanner()483     public BluetoothLeScanner getBluetoothLeScanner() {
484         if (getState() != STATE_ON) {
485             return null;
486         }
487         synchronized(mLock) {
488             if (sBluetoothLeScanner == null) {
489                 sBluetoothLeScanner = new BluetoothLeScanner(mManagerService);
490             }
491         }
492         return sBluetoothLeScanner;
493     }
494 
495     /**
496      * Return true if Bluetooth is currently enabled and ready for use.
497      * <p>Equivalent to:
498      * <code>getBluetoothState() == STATE_ON</code>
499      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
500      *
501      * @return true if the local adapter is turned on
502      */
isEnabled()503     public boolean isEnabled() {
504 
505         try {
506             synchronized(mManagerCallback) {
507                 if (mService != null) return mService.isEnabled();
508             }
509         } catch (RemoteException e) {Log.e(TAG, "", e);}
510         return false;
511     }
512 
513     /**
514      * Get the current state of the local Bluetooth adapter.
515      * <p>Possible return values are
516      * {@link #STATE_OFF},
517      * {@link #STATE_TURNING_ON},
518      * {@link #STATE_ON},
519      * {@link #STATE_TURNING_OFF}.
520      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
521      *
522      * @return current state of Bluetooth adapter
523      */
getState()524     public int getState() {
525         try {
526             synchronized(mManagerCallback) {
527                 if (mService != null)
528                 {
529                     int state=  mService.getState();
530                     if (VDBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + state);
531                     return state;
532                 }
533                 // TODO(BT) there might be a small gap during STATE_TURNING_ON that
534                 //          mService is null, handle that case
535             }
536         } catch (RemoteException e) {Log.e(TAG, "", e);}
537         if (DBG) Log.d(TAG, "" + hashCode() + ": getState() :  mService = null. Returning STATE_OFF");
538         return STATE_OFF;
539     }
540 
541     /**
542      * Turn on the local Bluetooth adapter&mdash;do not use without explicit
543      * user action to turn on Bluetooth.
544      * <p>This powers on the underlying Bluetooth hardware, and starts all
545      * Bluetooth system services.
546      * <p class="caution"><strong>Bluetooth should never be enabled without
547      * direct user consent</strong>. If you want to turn on Bluetooth in order
548      * to create a wireless connection, you should use the {@link
549      * #ACTION_REQUEST_ENABLE} Intent, which will raise a dialog that requests
550      * user permission to turn on Bluetooth. The {@link #enable()} method is
551      * provided only for applications that include a user interface for changing
552      * system settings, such as a "power manager" app.</p>
553      * <p>This is an asynchronous call: it will return immediately, and
554      * clients should listen for {@link #ACTION_STATE_CHANGED}
555      * to be notified of subsequent adapter state changes. If this call returns
556      * true, then the adapter state will immediately transition from {@link
557      * #STATE_OFF} to {@link #STATE_TURNING_ON}, and some time
558      * later transition to either {@link #STATE_OFF} or {@link
559      * #STATE_ON}. If this call returns false then there was an
560      * immediate problem that will prevent the adapter from being turned on -
561      * such as Airplane mode, or the adapter is already turned on.
562      * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
563      * permission
564      *
565      * @return true to indicate adapter startup has begun, or false on
566      *         immediate error
567      */
enable()568     public boolean enable() {
569         if (isEnabled() == true){
570             if (DBG) Log.d(TAG, "enable(): BT is already enabled..!");
571             return true;
572         }
573         try {
574             return mManagerService.enable();
575         } catch (RemoteException e) {Log.e(TAG, "", e);}
576         return false;
577     }
578 
579     /**
580      * Turn off the local Bluetooth adapter&mdash;do not use without explicit
581      * user action to turn off Bluetooth.
582      * <p>This gracefully shuts down all Bluetooth connections, stops Bluetooth
583      * system services, and powers down the underlying Bluetooth hardware.
584      * <p class="caution"><strong>Bluetooth should never be disabled without
585      * direct user consent</strong>. The {@link #disable()} method is
586      * provided only for applications that include a user interface for changing
587      * system settings, such as a "power manager" app.</p>
588      * <p>This is an asynchronous call: it will return immediately, and
589      * clients should listen for {@link #ACTION_STATE_CHANGED}
590      * to be notified of subsequent adapter state changes. If this call returns
591      * true, then the adapter state will immediately transition from {@link
592      * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time
593      * later transition to either {@link #STATE_OFF} or {@link
594      * #STATE_ON}. If this call returns false then there was an
595      * immediate problem that will prevent the adapter from being turned off -
596      * such as the adapter already being turned off.
597      * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
598      * permission
599      *
600      * @return true to indicate adapter shutdown has begun, or false on
601      *         immediate error
602      */
disable()603     public boolean disable() {
604         try {
605             return mManagerService.disable(true);
606         } catch (RemoteException e) {Log.e(TAG, "", e);}
607         return false;
608     }
609 
610     /**
611      * Turn off the local Bluetooth adapter and don't persist the setting.
612      *
613      * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
614      * permission
615      *
616      * @return true to indicate adapter shutdown has begun, or false on
617      *         immediate error
618      * @hide
619      */
disable(boolean persist)620     public boolean disable(boolean persist) {
621 
622         try {
623             return mManagerService.disable(persist);
624         } catch (RemoteException e) {Log.e(TAG, "", e);}
625         return false;
626     }
627 
628     /**
629      * Returns the hardware address of the local Bluetooth adapter.
630      * <p>For example, "00:11:22:AA:BB:CC".
631      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
632      *
633      * @return Bluetooth hardware address as string
634      */
getAddress()635     public String getAddress() {
636         try {
637             return mManagerService.getAddress();
638         } catch (RemoteException e) {Log.e(TAG, "", e);}
639         return null;
640     }
641 
642     /**
643      * Get the friendly Bluetooth name of the local Bluetooth adapter.
644      * <p>This name is visible to remote Bluetooth devices.
645      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
646      *
647      * @return the Bluetooth name, or null on error
648      */
getName()649     public String getName() {
650         try {
651             return mManagerService.getName();
652         } catch (RemoteException e) {Log.e(TAG, "", e);}
653         return null;
654     }
655 
656     /**
657      * enable or disable Bluetooth HCI snoop log.
658      *
659      * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
660      * permission
661      *
662      * @return true to indicate configure HCI log successfully, or false on
663      *         immediate error
664      * @hide
665      */
configHciSnoopLog(boolean enable)666     public boolean configHciSnoopLog(boolean enable) {
667         try {
668             synchronized(mManagerCallback) {
669                 if (mService != null) return mService.configHciSnoopLog(enable);
670             }
671         } catch (RemoteException e) {Log.e(TAG, "", e);}
672         return false;
673     }
674 
675     /**
676      * Get the UUIDs supported by the local Bluetooth adapter.
677      *
678      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
679      *
680      * @return the UUIDs supported by the local Bluetooth Adapter.
681      * @hide
682      */
getUuids()683     public ParcelUuid[] getUuids() {
684         if (getState() != STATE_ON) return null;
685         try {
686             synchronized(mManagerCallback) {
687                 if (mService != null) return mService.getUuids();
688             }
689         } catch (RemoteException e) {Log.e(TAG, "", e);}
690         return null;
691     }
692 
693     /**
694      * Set the friendly Bluetooth name of the local Bluetooth adapter.
695      * <p>This name is visible to remote Bluetooth devices.
696      * <p>Valid Bluetooth names are a maximum of 248 bytes using UTF-8
697      * encoding, although many remote devices can only display the first
698      * 40 characters, and some may be limited to just 20.
699      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
700      * will return false. After turning on Bluetooth,
701      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
702      * to get the updated value.
703      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
704      *
705      * @param name a valid Bluetooth name
706      * @return     true if the name was set, false otherwise
707      */
setName(String name)708     public boolean setName(String name) {
709         if (getState() != STATE_ON) return false;
710         try {
711             synchronized(mManagerCallback) {
712                 if (mService != null) return mService.setName(name);
713             }
714         } catch (RemoteException e) {Log.e(TAG, "", e);}
715         return false;
716     }
717 
718     /**
719      * Get the current Bluetooth scan mode of the local Bluetooth adapter.
720      * <p>The Bluetooth scan mode determines if the local adapter is
721      * connectable and/or discoverable from remote Bluetooth devices.
722      * <p>Possible values are:
723      * {@link #SCAN_MODE_NONE},
724      * {@link #SCAN_MODE_CONNECTABLE},
725      * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
726      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
727      * will return {@link #SCAN_MODE_NONE}. After turning on Bluetooth,
728      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
729      * to get the updated value.
730      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
731      *
732      * @return scan mode
733      */
getScanMode()734     public int getScanMode() {
735         if (getState() != STATE_ON) return SCAN_MODE_NONE;
736         try {
737             synchronized(mManagerCallback) {
738                 if (mService != null) return mService.getScanMode();
739             }
740         } catch (RemoteException e) {Log.e(TAG, "", e);}
741         return SCAN_MODE_NONE;
742     }
743 
744     /**
745      * Set the Bluetooth scan mode of the local Bluetooth adapter.
746      * <p>The Bluetooth scan mode determines if the local adapter is
747      * connectable and/or discoverable from remote Bluetooth devices.
748      * <p>For privacy reasons, discoverable mode is automatically turned off
749      * after <code>duration</code> seconds. For example, 120 seconds should be
750      * enough for a remote device to initiate and complete its discovery
751      * process.
752      * <p>Valid scan mode values are:
753      * {@link #SCAN_MODE_NONE},
754      * {@link #SCAN_MODE_CONNECTABLE},
755      * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
756      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
757      * will return false. After turning on Bluetooth,
758      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
759      * to get the updated value.
760      * <p>Requires {@link android.Manifest.permission#WRITE_SECURE_SETTINGS}
761      * <p>Applications cannot set the scan mode. They should use
762      * <code>startActivityForResult(
763      * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE})
764      * </code>instead.
765      *
766      * @param mode valid scan mode
767      * @param duration time in seconds to apply scan mode, only used for
768      *                 {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}
769      * @return     true if the scan mode was set, false otherwise
770      * @hide
771      */
setScanMode(int mode, int duration)772     public boolean setScanMode(int mode, int duration) {
773         if (getState() != STATE_ON) return false;
774         try {
775             synchronized(mManagerCallback) {
776                 if (mService != null) return mService.setScanMode(mode, duration);
777             }
778         } catch (RemoteException e) {Log.e(TAG, "", e);}
779         return false;
780     }
781 
782     /** @hide */
setScanMode(int mode)783     public boolean setScanMode(int mode) {
784         if (getState() != STATE_ON) return false;
785         /* getDiscoverableTimeout() to use the latest from NV than use 0 */
786         return setScanMode(mode, getDiscoverableTimeout());
787     }
788 
789     /** @hide */
getDiscoverableTimeout()790     public int getDiscoverableTimeout() {
791         if (getState() != STATE_ON) return -1;
792         try {
793             synchronized(mManagerCallback) {
794                 if (mService != null) return mService.getDiscoverableTimeout();
795             }
796         } catch (RemoteException e) {Log.e(TAG, "", e);}
797         return -1;
798     }
799 
800     /** @hide */
setDiscoverableTimeout(int timeout)801     public void setDiscoverableTimeout(int timeout) {
802         if (getState() != STATE_ON) return;
803         try {
804             synchronized(mManagerCallback) {
805                 if (mService != null) mService.setDiscoverableTimeout(timeout);
806             }
807         } catch (RemoteException e) {Log.e(TAG, "", e);}
808     }
809 
810     /**
811      * Start the remote device discovery process.
812      * <p>The discovery process usually involves an inquiry scan of about 12
813      * seconds, followed by a page scan of each new device to retrieve its
814      * Bluetooth name.
815      * <p>This is an asynchronous call, it will return immediately. Register
816      * for {@link #ACTION_DISCOVERY_STARTED} and {@link
817      * #ACTION_DISCOVERY_FINISHED} intents to determine exactly when the
818      * discovery starts and completes. Register for {@link
819      * BluetoothDevice#ACTION_FOUND} to be notified as remote Bluetooth devices
820      * are found.
821      * <p>Device discovery is a heavyweight procedure. New connections to
822      * remote Bluetooth devices should not be attempted while discovery is in
823      * progress, and existing connections will experience limited bandwidth
824      * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
825      * discovery. Discovery is not managed by the Activity,
826      * but is run as a system service, so an application should always call
827      * {@link BluetoothAdapter#cancelDiscovery()} even if it
828      * did not directly request a discovery, just to be sure.
829      * <p>Device discovery will only find remote devices that are currently
830      * <i>discoverable</i> (inquiry scan enabled). Many Bluetooth devices are
831      * not discoverable by default, and need to be entered into a special mode.
832      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
833      * will return false. After turning on Bluetooth,
834      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
835      * to get the updated value.
836      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
837      *
838      * @return true on success, false on error
839      */
startDiscovery()840     public boolean startDiscovery() {
841         if (getState() != STATE_ON) return false;
842         try {
843             synchronized(mManagerCallback) {
844                 if (mService != null) return mService.startDiscovery();
845             }
846         } catch (RemoteException e) {Log.e(TAG, "", e);}
847         return false;
848     }
849 
850     /**
851      * Cancel the current device discovery process.
852      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
853      * <p>Because discovery is a heavyweight procedure for the Bluetooth
854      * adapter, this method should always be called before attempting to connect
855      * to a remote device with {@link
856      * android.bluetooth.BluetoothSocket#connect()}. Discovery is not managed by
857      * the  Activity, but is run as a system service, so an application should
858      * always call cancel discovery even if it did not directly request a
859      * discovery, just to be sure.
860      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
861      * will return false. After turning on Bluetooth,
862      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
863      * to get the updated value.
864      *
865      * @return true on success, false on error
866      */
cancelDiscovery()867     public boolean cancelDiscovery() {
868         if (getState() != STATE_ON) return false;
869         try {
870             synchronized(mManagerCallback) {
871                 if (mService != null) return mService.cancelDiscovery();
872             }
873         } catch (RemoteException e) {Log.e(TAG, "", e);}
874         return false;
875     }
876 
877     /**
878      * Return true if the local Bluetooth adapter is currently in the device
879      * discovery process.
880      * <p>Device discovery is a heavyweight procedure. New connections to
881      * remote Bluetooth devices should not be attempted while discovery is in
882      * progress, and existing connections will experience limited bandwidth
883      * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
884      * discovery.
885      * <p>Applications can also register for {@link #ACTION_DISCOVERY_STARTED}
886      * or {@link #ACTION_DISCOVERY_FINISHED} to be notified when discovery
887      * starts or completes.
888      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
889      * will return false. After turning on Bluetooth,
890      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
891      * to get the updated value.
892      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
893      *
894      * @return true if discovering
895      */
isDiscovering()896     public boolean isDiscovering() {
897         if (getState() != STATE_ON) return false;
898         try {
899             synchronized(mManagerCallback) {
900                 if (mService != null ) return mService.isDiscovering();
901             }
902         } catch (RemoteException e) {Log.e(TAG, "", e);}
903         return false;
904     }
905 
906     /**
907      * Return true if the multi advertisement is supported by the chipset
908      *
909      * @return true if Multiple Advertisement feature is supported
910      */
isMultipleAdvertisementSupported()911     public boolean isMultipleAdvertisementSupported() {
912         if (getState() != STATE_ON) return false;
913         try {
914             return mService.isMultiAdvertisementSupported();
915         } catch (RemoteException e) {
916             Log.e(TAG, "failed to get isMultipleAdvertisementSupported, error: ", e);
917         }
918         return false;
919     }
920 
921     /**
922      * Returns whether peripheral mode is supported.
923      *
924      * @hide
925      */
isPeripheralModeSupported()926     public boolean isPeripheralModeSupported() {
927         if (getState() != STATE_ON) return false;
928         try {
929             return mService.isPeripheralModeSupported();
930         } catch (RemoteException e) {
931             Log.e(TAG, "failed to get peripheral mode capability: ", e);
932         }
933         return false;
934     }
935 
936     /**
937      * Return true if offloaded filters are supported
938      *
939      * @return true if chipset supports on-chip filtering
940      */
isOffloadedFilteringSupported()941     public boolean isOffloadedFilteringSupported() {
942         if (getState() != STATE_ON) return false;
943         try {
944             return mService.isOffloadedFilteringSupported();
945         } catch (RemoteException e) {
946             Log.e(TAG, "failed to get isOffloadedFilteringSupported, error: ", e);
947         }
948         return false;
949     }
950 
951     /**
952      * Return true if offloaded scan batching is supported
953      *
954      * @return true if chipset supports on-chip scan batching
955      */
isOffloadedScanBatchingSupported()956     public boolean isOffloadedScanBatchingSupported() {
957         if (getState() != STATE_ON) return false;
958         try {
959             return mService.isOffloadedScanBatchingSupported();
960         } catch (RemoteException e) {
961             Log.e(TAG, "failed to get isOffloadedScanBatchingSupported, error: ", e);
962         }
963         return false;
964     }
965 
966     /**
967      * Return the record of {@link BluetoothActivityEnergyInfo} object that
968      * has the activity and energy info. This can be used to ascertain what
969      * the controller has been up to, since the last sample.
970      * @param updateType Type of info, cached vs refreshed.
971      *
972      * @return a record with {@link BluetoothActivityEnergyInfo} or null if
973      * report is unavailable or unsupported
974      * @hide
975      */
getControllerActivityEnergyInfo(int updateType)976     public BluetoothActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) {
977         if (getState() != STATE_ON) return null;
978         try {
979             BluetoothActivityEnergyInfo record;
980             if (!mService.isActivityAndEnergyReportingSupported()) {
981                 return null;
982             }
983             synchronized(this) {
984                 if (updateType == ACTIVITY_ENERGY_INFO_REFRESHED) {
985                     mService.getActivityEnergyInfoFromController();
986                     wait(CONTROLLER_ENERGY_UPDATE_TIMEOUT_MILLIS);
987                 }
988                 record = mService.reportActivityInfo();
989                 if (record.isValid()) {
990                     return record;
991                 } else {
992                     return null;
993                 }
994             }
995         } catch (InterruptedException e) {
996             Log.e(TAG, "getControllerActivityEnergyInfoCallback wait interrupted: " + e);
997         } catch (RemoteException e) {
998             Log.e(TAG, "getControllerActivityEnergyInfoCallback: " + e);
999         }
1000         return null;
1001     }
1002 
1003     /**
1004      * Return the set of {@link BluetoothDevice} objects that are bonded
1005      * (paired) to the local adapter.
1006      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
1007      * will return an empty set. After turning on Bluetooth,
1008      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
1009      * to get the updated value.
1010      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
1011      *
1012      * @return unmodifiable set of {@link BluetoothDevice}, or null on error
1013      */
getBondedDevices()1014     public Set<BluetoothDevice> getBondedDevices() {
1015         if (getState() != STATE_ON) {
1016             return toDeviceSet(new BluetoothDevice[0]);
1017         }
1018         try {
1019             synchronized(mManagerCallback) {
1020                 if (mService != null) return toDeviceSet(mService.getBondedDevices());
1021             }
1022             return toDeviceSet(new BluetoothDevice[0]);
1023         } catch (RemoteException e) {Log.e(TAG, "", e);}
1024         return null;
1025     }
1026 
1027     /**
1028      * Get the current connection state of the local Bluetooth adapter.
1029      * This can be used to check whether the local Bluetooth adapter is connected
1030      * to any profile of any other remote Bluetooth Device.
1031      *
1032      * <p> Use this function along with {@link #ACTION_CONNECTION_STATE_CHANGED}
1033      * intent to get the connection state of the adapter.
1034      *
1035      * @return One of {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTED},
1036      * {@link #STATE_CONNECTING} or {@link #STATE_DISCONNECTED}
1037      *
1038      * @hide
1039      */
getConnectionState()1040     public int getConnectionState() {
1041         if (getState() != STATE_ON) return BluetoothAdapter.STATE_DISCONNECTED;
1042         try {
1043             synchronized(mManagerCallback) {
1044                 if (mService != null) return mService.getAdapterConnectionState();
1045             }
1046         } catch (RemoteException e) {Log.e(TAG, "getConnectionState:", e);}
1047         return BluetoothAdapter.STATE_DISCONNECTED;
1048     }
1049 
1050     /**
1051      * Get the current connection state of a profile.
1052      * This function can be used to check whether the local Bluetooth adapter
1053      * is connected to any remote device for a specific profile.
1054      * Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET},
1055      * {@link BluetoothProfile#A2DP}.
1056      *
1057      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
1058      *
1059      * <p> Return value can be one of
1060      * {@link BluetoothProfile#STATE_DISCONNECTED},
1061      * {@link BluetoothProfile#STATE_CONNECTING},
1062      * {@link BluetoothProfile#STATE_CONNECTED},
1063      * {@link BluetoothProfile#STATE_DISCONNECTING}
1064      */
getProfileConnectionState(int profile)1065     public int getProfileConnectionState(int profile) {
1066         if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED;
1067         try {
1068             synchronized(mManagerCallback) {
1069                 if (mService != null) return mService.getProfileConnectionState(profile);
1070             }
1071         } catch (RemoteException e) {
1072             Log.e(TAG, "getProfileConnectionState:", e);
1073         }
1074         return BluetoothProfile.STATE_DISCONNECTED;
1075     }
1076 
1077     /**
1078      * Create a listening, secure RFCOMM Bluetooth socket.
1079      * <p>A remote device connecting to this socket will be authenticated and
1080      * communication on this socket will be encrypted.
1081      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
1082      * connections from a listening {@link BluetoothServerSocket}.
1083      * <p>Valid RFCOMM channels are in range 1 to 30.
1084      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
1085      * @param channel RFCOMM channel to listen on
1086      * @return a listening RFCOMM BluetoothServerSocket
1087      * @throws IOException on error, for example Bluetooth not available, or
1088      *                     insufficient permissions, or channel in use.
1089      * @hide
1090      */
listenUsingRfcommOn(int channel)1091     public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException {
1092         BluetoothServerSocket socket = new BluetoothServerSocket(
1093                 BluetoothSocket.TYPE_RFCOMM, true, true, channel);
1094         int errno = socket.mSocket.bindListen();
1095         if (errno != 0) {
1096             //TODO(BT): Throw the same exception error code
1097             // that the previous code was using.
1098             //socket.mSocket.throwErrnoNative(errno);
1099             throw new IOException("Error: " + errno);
1100         }
1101         return socket;
1102     }
1103 
1104     /**
1105      * Create a listening, secure RFCOMM Bluetooth socket with Service Record.
1106      * <p>A remote device connecting to this socket will be authenticated and
1107      * communication on this socket will be encrypted.
1108      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
1109      * connections from a listening {@link BluetoothServerSocket}.
1110      * <p>The system will assign an unused RFCOMM channel to listen on.
1111      * <p>The system will also register a Service Discovery
1112      * Protocol (SDP) record with the local SDP server containing the specified
1113      * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
1114      * can use the same UUID to query our SDP server and discover which channel
1115      * to connect to. This SDP record will be removed when this socket is
1116      * closed, or if this application closes unexpectedly.
1117      * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
1118      * connect to this socket from another device using the same {@link UUID}.
1119      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1120      * @param name service name for SDP record
1121      * @param uuid uuid for SDP record
1122      * @return a listening RFCOMM BluetoothServerSocket
1123      * @throws IOException on error, for example Bluetooth not available, or
1124      *                     insufficient permissions, or channel in use.
1125      */
listenUsingRfcommWithServiceRecord(String name, UUID uuid)1126     public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid)
1127             throws IOException {
1128         return createNewRfcommSocketAndRecord(name, uuid, true, true);
1129     }
1130 
1131     /**
1132      * Create a listening, insecure RFCOMM Bluetooth socket with Service Record.
1133      * <p>The link key is not required to be authenticated, i.e the communication may be
1134      * vulnerable to Man In the Middle attacks. For Bluetooth 2.1 devices,
1135      * the link will be encrypted, as encryption is mandartory.
1136      * For legacy devices (pre Bluetooth 2.1 devices) the link will not
1137      * be encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an
1138      * encrypted and authenticated communication channel is desired.
1139      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
1140      * connections from a listening {@link BluetoothServerSocket}.
1141      * <p>The system will assign an unused RFCOMM channel to listen on.
1142      * <p>The system will also register a Service Discovery
1143      * Protocol (SDP) record with the local SDP server containing the specified
1144      * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
1145      * can use the same UUID to query our SDP server and discover which channel
1146      * to connect to. This SDP record will be removed when this socket is
1147      * closed, or if this application closes unexpectedly.
1148      * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
1149      * connect to this socket from another device using the same {@link UUID}.
1150      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1151      * @param name service name for SDP record
1152      * @param uuid uuid for SDP record
1153      * @return a listening RFCOMM BluetoothServerSocket
1154      * @throws IOException on error, for example Bluetooth not available, or
1155      *                     insufficient permissions, or channel in use.
1156      */
listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)1157     public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)
1158             throws IOException {
1159         return createNewRfcommSocketAndRecord(name, uuid, false, false);
1160     }
1161 
1162      /**
1163      * Create a listening, encrypted,
1164      * RFCOMM Bluetooth socket with Service Record.
1165      * <p>The link will be encrypted, but the link key is not required to be authenticated
1166      * i.e the communication is vulnerable to Man In the Middle attacks. Use
1167      * {@link #listenUsingRfcommWithServiceRecord}, to ensure an authenticated link key.
1168      * <p> Use this socket if authentication of link key is not possible.
1169      * For example, for Bluetooth 2.1 devices, if any of the devices does not have
1170      * an input and output capability or just has the ability to display a numeric key,
1171      * a secure socket connection is not possible and this socket can be used.
1172      * Use {@link #listenUsingInsecureRfcommWithServiceRecord}, if encryption is not required.
1173      * For Bluetooth 2.1 devices, the link will be encrypted, as encryption is mandartory.
1174      * For more details, refer to the Security Model section 5.2 (vol 3) of
1175      * Bluetooth Core Specification version 2.1 + EDR.
1176      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
1177      * connections from a listening {@link BluetoothServerSocket}.
1178      * <p>The system will assign an unused RFCOMM channel to listen on.
1179      * <p>The system will also register a Service Discovery
1180      * Protocol (SDP) record with the local SDP server containing the specified
1181      * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
1182      * can use the same UUID to query our SDP server and discover which channel
1183      * to connect to. This SDP record will be removed when this socket is
1184      * closed, or if this application closes unexpectedly.
1185      * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
1186      * connect to this socket from another device using the same {@link UUID}.
1187      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1188      * @param name service name for SDP record
1189      * @param uuid uuid for SDP record
1190      * @return a listening RFCOMM BluetoothServerSocket
1191      * @throws IOException on error, for example Bluetooth not available, or
1192      *                     insufficient permissions, or channel in use.
1193      * @hide
1194      */
listenUsingEncryptedRfcommWithServiceRecord( String name, UUID uuid)1195     public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(
1196             String name, UUID uuid) throws IOException {
1197         return createNewRfcommSocketAndRecord(name, uuid, false, true);
1198     }
1199 
1200 
createNewRfcommSocketAndRecord(String name, UUID uuid, boolean auth, boolean encrypt)1201     private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid,
1202             boolean auth, boolean encrypt) throws IOException {
1203         BluetoothServerSocket socket;
1204         socket = new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, auth,
1205                         encrypt, new ParcelUuid(uuid));
1206         socket.setServiceName(name);
1207         int errno = socket.mSocket.bindListen();
1208         if (errno != 0) {
1209             //TODO(BT): Throw the same exception error code
1210             // that the previous code was using.
1211             //socket.mSocket.throwErrnoNative(errno);
1212             throw new IOException("Error: " + errno);
1213         }
1214         return socket;
1215     }
1216 
1217     /**
1218      * Construct an unencrypted, unauthenticated, RFCOMM server socket.
1219      * Call #accept to retrieve connections to this socket.
1220      * @return An RFCOMM BluetoothServerSocket
1221      * @throws IOException On error, for example Bluetooth not available, or
1222      *                     insufficient permissions.
1223      * @hide
1224      */
listenUsingInsecureRfcommOn(int port)1225     public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException {
1226         BluetoothServerSocket socket = new BluetoothServerSocket(
1227                 BluetoothSocket.TYPE_RFCOMM, false, false, port);
1228         int errno = socket.mSocket.bindListen();
1229         if (errno != 0) {
1230             //TODO(BT): Throw the same exception error code
1231             // that the previous code was using.
1232             //socket.mSocket.throwErrnoNative(errno);
1233             throw new IOException("Error: " + errno);
1234         }
1235         return socket;
1236     }
1237 
1238      /**
1239      * Construct an encrypted, RFCOMM server socket.
1240      * Call #accept to retrieve connections to this socket.
1241      * @return An RFCOMM BluetoothServerSocket
1242      * @throws IOException On error, for example Bluetooth not available, or
1243      *                     insufficient permissions.
1244      * @hide
1245      */
listenUsingEncryptedRfcommOn(int port)1246     public BluetoothServerSocket listenUsingEncryptedRfcommOn(int port)
1247             throws IOException {
1248         BluetoothServerSocket socket = new BluetoothServerSocket(
1249                 BluetoothSocket.TYPE_RFCOMM, false, true, port);
1250         int errno = socket.mSocket.bindListen();
1251         if (errno < 0) {
1252             //TODO(BT): Throw the same exception error code
1253             // that the previous code was using.
1254             //socket.mSocket.throwErrnoNative(errno);
1255             throw new IOException("Error: " + errno);
1256         }
1257         return socket;
1258     }
1259 
1260     /**
1261      * Construct a SCO server socket.
1262      * Call #accept to retrieve connections to this socket.
1263      * @return A SCO BluetoothServerSocket
1264      * @throws IOException On error, for example Bluetooth not available, or
1265      *                     insufficient permissions.
1266      * @hide
1267      */
listenUsingScoOn()1268     public static BluetoothServerSocket listenUsingScoOn() throws IOException {
1269         BluetoothServerSocket socket = new BluetoothServerSocket(
1270                 BluetoothSocket.TYPE_SCO, false, false, -1);
1271         int errno = socket.mSocket.bindListen();
1272         if (errno < 0) {
1273             //TODO(BT): Throw the same exception error code
1274             // that the previous code was using.
1275             //socket.mSocket.throwErrnoNative(errno);
1276         }
1277         return socket;
1278     }
1279 
1280     /**
1281      * Read the local Out of Band Pairing Data
1282      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1283      *
1284      * @return Pair<byte[], byte[]> of Hash and Randomizer
1285      *
1286      * @hide
1287      */
readOutOfBandData()1288     public Pair<byte[], byte[]> readOutOfBandData() {
1289         if (getState() != STATE_ON) return null;
1290         //TODO(BT
1291         /*
1292         try {
1293             byte[] hash;
1294             byte[] randomizer;
1295 
1296             byte[] ret = mService.readOutOfBandData();
1297 
1298             if (ret  == null || ret.length != 32) return null;
1299 
1300             hash = Arrays.copyOfRange(ret, 0, 16);
1301             randomizer = Arrays.copyOfRange(ret, 16, 32);
1302 
1303             if (DBG) {
1304                 Log.d(TAG, "readOutOfBandData:" + Arrays.toString(hash) +
1305                   ":" + Arrays.toString(randomizer));
1306             }
1307             return new Pair<byte[], byte[]>(hash, randomizer);
1308 
1309         } catch (RemoteException e) {Log.e(TAG, "", e);}*/
1310         return null;
1311     }
1312 
1313     /**
1314      * Get the profile proxy object associated with the profile.
1315      *
1316      * <p>Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET},
1317      * {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#GATT}, or
1318      * {@link BluetoothProfile#GATT_SERVER}. Clients must implement
1319      * {@link BluetoothProfile.ServiceListener} to get notified of
1320      * the connection status and to get the proxy object.
1321      *
1322      * @param context Context of the application
1323      * @param listener The service Listener for connection callbacks.
1324      * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEALTH},
1325      *                {@link BluetoothProfile#HEADSET} or {@link BluetoothProfile#A2DP}.
1326      * @return true on success, false on error
1327      */
getProfileProxy(Context context, BluetoothProfile.ServiceListener listener, int profile)1328     public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,
1329                                    int profile) {
1330         if (context == null || listener == null) return false;
1331 
1332         if (profile == BluetoothProfile.HEADSET) {
1333             BluetoothHeadset headset = new BluetoothHeadset(context, listener);
1334             return true;
1335         } else if (profile == BluetoothProfile.A2DP) {
1336             BluetoothA2dp a2dp = new BluetoothA2dp(context, listener);
1337             return true;
1338         } else if (profile == BluetoothProfile.A2DP_SINK) {
1339             BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener);
1340             return true;
1341         } else if (profile == BluetoothProfile.AVRCP_CONTROLLER) {
1342             BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener);
1343             return true;
1344         } else if (profile == BluetoothProfile.INPUT_DEVICE) {
1345             BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener);
1346             return true;
1347         } else if (profile == BluetoothProfile.PAN) {
1348             BluetoothPan pan = new BluetoothPan(context, listener);
1349             return true;
1350         } else if (profile == BluetoothProfile.HEALTH) {
1351             BluetoothHealth health = new BluetoothHealth(context, listener);
1352             return true;
1353         } else if (profile == BluetoothProfile.MAP) {
1354             BluetoothMap map = new BluetoothMap(context, listener);
1355             return true;
1356         } else if (profile == BluetoothProfile.HEADSET_CLIENT) {
1357             BluetoothHeadsetClient headsetClient = new BluetoothHeadsetClient(context, listener);
1358             return true;
1359         } else {
1360             return false;
1361         }
1362     }
1363 
1364     /**
1365      * Close the connection of the profile proxy to the Service.
1366      *
1367      * <p> Clients should call this when they are no longer using
1368      * the proxy obtained from {@link #getProfileProxy}.
1369      * Profile can be one of  {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET} or
1370      * {@link BluetoothProfile#A2DP}
1371      *
1372      * @param profile
1373      * @param proxy Profile proxy object
1374      */
closeProfileProxy(int profile, BluetoothProfile proxy)1375     public void closeProfileProxy(int profile, BluetoothProfile proxy) {
1376         if (proxy == null) return;
1377 
1378         switch (profile) {
1379             case BluetoothProfile.HEADSET:
1380                 BluetoothHeadset headset = (BluetoothHeadset)proxy;
1381                 headset.close();
1382                 break;
1383             case BluetoothProfile.A2DP:
1384                 BluetoothA2dp a2dp = (BluetoothA2dp)proxy;
1385                 a2dp.close();
1386                 break;
1387             case BluetoothProfile.A2DP_SINK:
1388                 BluetoothA2dpSink a2dpSink = (BluetoothA2dpSink)proxy;
1389                 a2dpSink.close();
1390                 break;
1391             case BluetoothProfile.AVRCP_CONTROLLER:
1392                 BluetoothAvrcpController avrcp = (BluetoothAvrcpController)proxy;
1393                 avrcp.close();
1394                 break;
1395             case BluetoothProfile.INPUT_DEVICE:
1396                 BluetoothInputDevice iDev = (BluetoothInputDevice)proxy;
1397                 iDev.close();
1398                 break;
1399             case BluetoothProfile.PAN:
1400                 BluetoothPan pan = (BluetoothPan)proxy;
1401                 pan.close();
1402                 break;
1403             case BluetoothProfile.HEALTH:
1404                 BluetoothHealth health = (BluetoothHealth)proxy;
1405                 health.close();
1406                 break;
1407            case BluetoothProfile.GATT:
1408                 BluetoothGatt gatt = (BluetoothGatt)proxy;
1409                 gatt.close();
1410                 break;
1411             case BluetoothProfile.GATT_SERVER:
1412                 BluetoothGattServer gattServer = (BluetoothGattServer)proxy;
1413                 gattServer.close();
1414                 break;
1415             case BluetoothProfile.MAP:
1416                 BluetoothMap map = (BluetoothMap)proxy;
1417                 map.close();
1418                 break;
1419             case BluetoothProfile.HEADSET_CLIENT:
1420                 BluetoothHeadsetClient headsetClient = (BluetoothHeadsetClient)proxy;
1421                 headsetClient.close();
1422                 break;
1423         }
1424     }
1425 
1426     final private IBluetoothManagerCallback mManagerCallback =
1427         new IBluetoothManagerCallback.Stub() {
1428             public void onBluetoothServiceUp(IBluetooth bluetoothService) {
1429                 if (VDBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
1430                 synchronized (mManagerCallback) {
1431                     mService = bluetoothService;
1432                     synchronized (mProxyServiceStateCallbacks) {
1433                         for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
1434                             try {
1435                                 if (cb != null) {
1436                                     cb.onBluetoothServiceUp(bluetoothService);
1437                                 } else {
1438                                     Log.d(TAG, "onBluetoothServiceUp: cb is null!!!");
1439                                 }
1440                             } catch (Exception e)  { Log.e(TAG,"",e);}
1441                         }
1442                     }
1443                 }
1444             }
1445 
1446             public void onBluetoothServiceDown() {
1447                 if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService);
1448                 synchronized (mManagerCallback) {
1449                     mService = null;
1450                     if (mLeScanClients != null) mLeScanClients.clear();
1451                     if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup();
1452                     if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup();
1453                     synchronized (mProxyServiceStateCallbacks) {
1454                         for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
1455                             try {
1456                                 if (cb != null) {
1457                                     cb.onBluetoothServiceDown();
1458                                 } else {
1459                                     Log.d(TAG, "onBluetoothServiceDown: cb is null!!!");
1460                                 }
1461                             } catch (Exception e)  { Log.e(TAG,"",e);}
1462                         }
1463                     }
1464                 }
1465             }
1466     };
1467 
1468     /**
1469      * Enable the Bluetooth Adapter, but don't auto-connect devices
1470      * and don't persist state. Only for use by system applications.
1471      * @hide
1472      */
enableNoAutoConnect()1473     public boolean enableNoAutoConnect() {
1474         if (isEnabled() == true){
1475             if (DBG) Log.d(TAG, "enableNoAutoConnect(): BT is already enabled..!");
1476             return true;
1477         }
1478         try {
1479             return mManagerService.enableNoAutoConnect();
1480         } catch (RemoteException e) {Log.e(TAG, "", e);}
1481         return false;
1482     }
1483 
1484     /**
1485      * Enable control of the Bluetooth Adapter for a single application.
1486      *
1487      * <p>Some applications need to use Bluetooth for short periods of time to
1488      * transfer data but don't want all the associated implications like
1489      * automatic connection to headsets etc.
1490      *
1491      * <p> Multiple applications can call this. This is reference counted and
1492      * Bluetooth disabled only when no one else is using it. There will be no UI
1493      * shown to the user while bluetooth is being enabled. Any user action will
1494      * override this call. For example, if user wants Bluetooth on and the last
1495      * user of this API wanted to disable Bluetooth, Bluetooth will not be
1496      * turned off.
1497      *
1498      * <p> This API is only meant to be used by internal applications. Third
1499      * party applications but use {@link #enable} and {@link #disable} APIs.
1500      *
1501      * <p> If this API returns true, it means the callback will be called.
1502      * The callback will be called with the current state of Bluetooth.
1503      * If the state is not what was requested, an internal error would be the
1504      * reason. If Bluetooth is already on and if this function is called to turn
1505      * it on, the api will return true and a callback will be called.
1506      *
1507      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1508      *
1509      * @param on True for on, false for off.
1510      * @param callback The callback to notify changes to the state.
1511      * @hide
1512      */
changeApplicationBluetoothState(boolean on, BluetoothStateChangeCallback callback)1513     public boolean changeApplicationBluetoothState(boolean on,
1514                                                    BluetoothStateChangeCallback callback) {
1515         if (callback == null) return false;
1516 
1517         //TODO(BT)
1518         /*
1519         try {
1520             return mService.changeApplicationBluetoothState(on, new
1521                     StateChangeCallbackWrapper(callback), new Binder());
1522         } catch (RemoteException e) {
1523             Log.e(TAG, "changeBluetoothState", e);
1524         }*/
1525         return false;
1526     }
1527 
1528     /**
1529      * @hide
1530      */
1531     public interface BluetoothStateChangeCallback {
onBluetoothStateChange(boolean on)1532         public void onBluetoothStateChange(boolean on);
1533     }
1534 
1535     /**
1536      * @hide
1537      */
1538     public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub {
1539         private BluetoothStateChangeCallback mCallback;
1540 
StateChangeCallbackWrapper(BluetoothStateChangeCallback callback)1541         StateChangeCallbackWrapper(BluetoothStateChangeCallback
1542                 callback) {
1543             mCallback = callback;
1544         }
1545 
1546         @Override
onBluetoothStateChange(boolean on)1547         public void onBluetoothStateChange(boolean on) {
1548             mCallback.onBluetoothStateChange(on);
1549         }
1550     }
1551 
toDeviceSet(BluetoothDevice[] devices)1552     private Set<BluetoothDevice> toDeviceSet(BluetoothDevice[] devices) {
1553         Set<BluetoothDevice> deviceSet = new HashSet<BluetoothDevice>(Arrays.asList(devices));
1554         return Collections.unmodifiableSet(deviceSet);
1555     }
1556 
finalize()1557     protected void finalize() throws Throwable {
1558         try {
1559             mManagerService.unregisterAdapter(mManagerCallback);
1560         } catch (RemoteException e) {
1561             Log.e(TAG, "", e);
1562         } finally {
1563             super.finalize();
1564         }
1565     }
1566 
1567 
1568     /**
1569      * Validate a String Bluetooth address, such as "00:43:A8:23:10:F0"
1570      * <p>Alphabetic characters must be uppercase to be valid.
1571      *
1572      * @param address Bluetooth address as string
1573      * @return true if the address is valid, false otherwise
1574      */
checkBluetoothAddress(String address)1575     public static boolean checkBluetoothAddress(String address) {
1576         if (address == null || address.length() != ADDRESS_LENGTH) {
1577             return false;
1578         }
1579         for (int i = 0; i < ADDRESS_LENGTH; i++) {
1580             char c = address.charAt(i);
1581             switch (i % 3) {
1582             case 0:
1583             case 1:
1584                 if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
1585                     // hex character, OK
1586                     break;
1587                 }
1588                 return false;
1589             case 2:
1590                 if (c == ':') {
1591                     break;  // OK
1592                 }
1593                 return false;
1594             }
1595         }
1596         return true;
1597     }
1598 
getBluetoothManager()1599     /*package*/ IBluetoothManager getBluetoothManager() {
1600             return mManagerService;
1601     }
1602 
1603     final private ArrayList<IBluetoothManagerCallback> mProxyServiceStateCallbacks = new ArrayList<IBluetoothManagerCallback>();
1604 
getBluetoothService(IBluetoothManagerCallback cb)1605     /*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) {
1606         synchronized (mProxyServiceStateCallbacks) {
1607             if (cb == null) {
1608                 Log.w(TAG, "getBluetoothService() called with no BluetoothManagerCallback");
1609             } else if (!mProxyServiceStateCallbacks.contains(cb)) {
1610                 mProxyServiceStateCallbacks.add(cb);
1611             }
1612         }
1613         return mService;
1614     }
1615 
removeServiceStateCallback(IBluetoothManagerCallback cb)1616     /*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) {
1617         synchronized (mProxyServiceStateCallbacks) {
1618             mProxyServiceStateCallbacks.remove(cb);
1619         }
1620     }
1621 
1622     /**
1623      * Callback interface used to deliver LE scan results.
1624      *
1625      * @see #startLeScan(LeScanCallback)
1626      * @see #startLeScan(UUID[], LeScanCallback)
1627      */
1628     public interface LeScanCallback {
1629         /**
1630          * Callback reporting an LE device found during a device scan initiated
1631          * by the {@link BluetoothAdapter#startLeScan} function.
1632          *
1633          * @param device Identifies the remote device
1634          * @param rssi The RSSI value for the remote device as reported by the
1635          *             Bluetooth hardware. 0 if no RSSI value is available.
1636          * @param scanRecord The content of the advertisement record offered by
1637          *                   the remote device.
1638          */
onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord)1639         public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord);
1640     }
1641 
1642     /**
1643      * Starts a scan for Bluetooth LE devices.
1644      *
1645      * <p>Results of the scan are reported using the
1646      * {@link LeScanCallback#onLeScan} callback.
1647      *
1648      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
1649      *
1650      * @param callback the callback LE scan results are delivered
1651      * @return true, if the scan was started successfully
1652      * @deprecated use {@link BluetoothLeScanner#startScan(List, ScanSettings, ScanCallback)}
1653      *             instead.
1654      */
1655     @Deprecated
startLeScan(LeScanCallback callback)1656     public boolean startLeScan(LeScanCallback callback) {
1657         return startLeScan(null, callback);
1658     }
1659 
1660     /**
1661      * Starts a scan for Bluetooth LE devices, looking for devices that
1662      * advertise given services.
1663      *
1664      * <p>Devices which advertise all specified services are reported using the
1665      * {@link LeScanCallback#onLeScan} callback.
1666      *
1667      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
1668      *
1669      * @param serviceUuids Array of services to look for
1670      * @param callback the callback LE scan results are delivered
1671      * @return true, if the scan was started successfully
1672      * @deprecated use {@link BluetoothLeScanner#startScan(List, ScanSettings, ScanCallback)}
1673      *             instead.
1674      */
1675     @Deprecated
startLeScan(final UUID[] serviceUuids, final LeScanCallback callback)1676     public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback) {
1677         if (DBG) Log.d(TAG, "startLeScan(): " + serviceUuids);
1678         if (callback == null) {
1679             if (DBG) Log.e(TAG, "startLeScan: null callback");
1680             return false;
1681         }
1682         BluetoothLeScanner scanner = getBluetoothLeScanner();
1683         if (scanner == null) {
1684             if (DBG) Log.e(TAG, "startLeScan: cannot get BluetoothLeScanner");
1685             return false;
1686         }
1687 
1688         synchronized(mLeScanClients) {
1689             if (mLeScanClients.containsKey(callback)) {
1690                 if (DBG) Log.e(TAG, "LE Scan has already started");
1691                 return false;
1692             }
1693 
1694             try {
1695                 IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
1696                 if (iGatt == null) {
1697                     // BLE is not supported
1698                     return false;
1699                 }
1700 
1701                 ScanCallback scanCallback = new ScanCallback() {
1702                     @Override
1703                     public void onScanResult(int callbackType, ScanResult result) {
1704                         if (callbackType != ScanSettings.CALLBACK_TYPE_ALL_MATCHES) {
1705                             // Should not happen.
1706                             Log.e(TAG, "LE Scan has already started");
1707                             return;
1708                         }
1709                         ScanRecord scanRecord = result.getScanRecord();
1710                         if (scanRecord == null) {
1711                             return;
1712                         }
1713                         if (serviceUuids != null) {
1714                             List<ParcelUuid> uuids = new ArrayList<ParcelUuid>();
1715                             for (UUID uuid : serviceUuids) {
1716                                 uuids.add(new ParcelUuid(uuid));
1717                             }
1718                             List<ParcelUuid> scanServiceUuids = scanRecord.getServiceUuids();
1719                             if (scanServiceUuids == null || !scanServiceUuids.containsAll(uuids)) {
1720                                 if (DBG) Log.d(TAG, "uuids does not match");
1721                                 return;
1722                             }
1723                         }
1724                         callback.onLeScan(result.getDevice(), result.getRssi(),
1725                                 scanRecord.getBytes());
1726                     }
1727                 };
1728                 ScanSettings settings = new ScanSettings.Builder()
1729                     .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
1730                     .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
1731 
1732                 List<ScanFilter> filters = new ArrayList<ScanFilter>();
1733                 if (serviceUuids != null && serviceUuids.length > 0) {
1734                     // Note scan filter does not support matching an UUID array so we put one
1735                     // UUID to hardware and match the whole array in callback.
1736                     ScanFilter filter = new ScanFilter.Builder().setServiceUuid(
1737                             new ParcelUuid(serviceUuids[0])).build();
1738                     filters.add(filter);
1739                 }
1740                 scanner.startScan(filters, settings, scanCallback);
1741 
1742                 mLeScanClients.put(callback, scanCallback);
1743                 return true;
1744 
1745             } catch (RemoteException e) {
1746                 Log.e(TAG,"",e);
1747             }
1748         }
1749         return false;
1750     }
1751 
1752     /**
1753      * Stops an ongoing Bluetooth LE device scan.
1754      *
1755      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
1756      *
1757      * @param callback used to identify which scan to stop
1758      *        must be the same handle used to start the scan
1759      * @deprecated Use {@link BluetoothLeScanner#stopScan(ScanCallback)} instead.
1760      */
1761     @Deprecated
stopLeScan(LeScanCallback callback)1762     public void stopLeScan(LeScanCallback callback) {
1763         if (DBG) Log.d(TAG, "stopLeScan()");
1764         BluetoothLeScanner scanner = getBluetoothLeScanner();
1765         if (scanner == null) {
1766             return;
1767         }
1768         synchronized (mLeScanClients) {
1769             ScanCallback scanCallback = mLeScanClients.remove(callback);
1770             if (scanCallback == null) {
1771                 if (DBG) Log.d(TAG, "scan not started yet");
1772                 return;
1773             }
1774             scanner.stopScan(scanCallback);
1775         }
1776     }
1777 }
1778