• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()) {
469             return null;
470         }
471         synchronized(mLock) {
472             if (sBluetoothLeAdvertiser == null) {
473                 sBluetoothLeAdvertiser = new BluetoothLeAdvertiser(mManagerService);
474             }
475         }
476         return sBluetoothLeAdvertiser;
477     }
478 
479     /**
480      * Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations.
481      */
getBluetoothLeScanner()482     public BluetoothLeScanner getBluetoothLeScanner() {
483         if (getState() != STATE_ON) {
484             return null;
485         }
486         synchronized(mLock) {
487             if (sBluetoothLeScanner == null) {
488                 sBluetoothLeScanner = new BluetoothLeScanner(mManagerService);
489             }
490         }
491         return sBluetoothLeScanner;
492     }
493 
494     /**
495      * Return true if Bluetooth is currently enabled and ready for use.
496      * <p>Equivalent to:
497      * <code>getBluetoothState() == STATE_ON</code>
498      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
499      *
500      * @return true if the local adapter is turned on
501      */
isEnabled()502     public boolean isEnabled() {
503 
504         try {
505             synchronized(mManagerCallback) {
506                 if (mService != null) return mService.isEnabled();
507             }
508         } catch (RemoteException e) {Log.e(TAG, "", e);}
509         return false;
510     }
511 
512     /**
513      * Get the current state of the local Bluetooth adapter.
514      * <p>Possible return values are
515      * {@link #STATE_OFF},
516      * {@link #STATE_TURNING_ON},
517      * {@link #STATE_ON},
518      * {@link #STATE_TURNING_OFF}.
519      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
520      *
521      * @return current state of Bluetooth adapter
522      */
getState()523     public int getState() {
524         try {
525             synchronized(mManagerCallback) {
526                 if (mService != null)
527                 {
528                     int state=  mService.getState();
529                     if (VDBG) Log.d(TAG, "" + hashCode() + ": getState(). Returning " + state);
530                     return state;
531                 }
532                 // TODO(BT) there might be a small gap during STATE_TURNING_ON that
533                 //          mService is null, handle that case
534             }
535         } catch (RemoteException e) {Log.e(TAG, "", e);}
536         if (DBG) Log.d(TAG, "" + hashCode() + ": getState() :  mService = null. Returning STATE_OFF");
537         return STATE_OFF;
538     }
539 
540     /**
541      * Turn on the local Bluetooth adapter&mdash;do not use without explicit
542      * user action to turn on Bluetooth.
543      * <p>This powers on the underlying Bluetooth hardware, and starts all
544      * Bluetooth system services.
545      * <p class="caution"><strong>Bluetooth should never be enabled without
546      * direct user consent</strong>. If you want to turn on Bluetooth in order
547      * to create a wireless connection, you should use the {@link
548      * #ACTION_REQUEST_ENABLE} Intent, which will raise a dialog that requests
549      * user permission to turn on Bluetooth. The {@link #enable()} method is
550      * provided only for applications that include a user interface for changing
551      * system settings, such as a "power manager" app.</p>
552      * <p>This is an asynchronous call: it will return immediately, and
553      * clients should listen for {@link #ACTION_STATE_CHANGED}
554      * to be notified of subsequent adapter state changes. If this call returns
555      * true, then the adapter state will immediately transition from {@link
556      * #STATE_OFF} to {@link #STATE_TURNING_ON}, and some time
557      * later transition to either {@link #STATE_OFF} or {@link
558      * #STATE_ON}. If this call returns false then there was an
559      * immediate problem that will prevent the adapter from being turned on -
560      * such as Airplane mode, or the adapter is already turned on.
561      * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
562      * permission
563      *
564      * @return true to indicate adapter startup has begun, or false on
565      *         immediate error
566      */
enable()567     public boolean enable() {
568         if (isEnabled() == true){
569             if (DBG) Log.d(TAG, "enable(): BT is already enabled..!");
570             return true;
571         }
572         try {
573             return mManagerService.enable();
574         } catch (RemoteException e) {Log.e(TAG, "", e);}
575         return false;
576     }
577 
578     /**
579      * Turn off the local Bluetooth adapter&mdash;do not use without explicit
580      * user action to turn off Bluetooth.
581      * <p>This gracefully shuts down all Bluetooth connections, stops Bluetooth
582      * system services, and powers down the underlying Bluetooth hardware.
583      * <p class="caution"><strong>Bluetooth should never be disabled without
584      * direct user consent</strong>. The {@link #disable()} method is
585      * provided only for applications that include a user interface for changing
586      * system settings, such as a "power manager" app.</p>
587      * <p>This is an asynchronous call: it will return immediately, and
588      * clients should listen for {@link #ACTION_STATE_CHANGED}
589      * to be notified of subsequent adapter state changes. If this call returns
590      * true, then the adapter state will immediately transition from {@link
591      * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time
592      * later transition to either {@link #STATE_OFF} or {@link
593      * #STATE_ON}. If this call returns false then there was an
594      * immediate problem that will prevent the adapter from being turned off -
595      * such as the adapter already being turned off.
596      * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
597      * permission
598      *
599      * @return true to indicate adapter shutdown has begun, or false on
600      *         immediate error
601      */
disable()602     public boolean disable() {
603         try {
604             return mManagerService.disable(true);
605         } catch (RemoteException e) {Log.e(TAG, "", e);}
606         return false;
607     }
608 
609     /**
610      * Turn off the local Bluetooth adapter and don't persist the setting.
611      *
612      * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
613      * permission
614      *
615      * @return true to indicate adapter shutdown has begun, or false on
616      *         immediate error
617      * @hide
618      */
disable(boolean persist)619     public boolean disable(boolean persist) {
620 
621         try {
622             return mManagerService.disable(persist);
623         } catch (RemoteException e) {Log.e(TAG, "", e);}
624         return false;
625     }
626 
627     /**
628      * Returns the hardware address of the local Bluetooth adapter.
629      * <p>For example, "00:11:22:AA:BB:CC".
630      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
631      *
632      * @return Bluetooth hardware address as string
633      */
getAddress()634     public String getAddress() {
635         try {
636             return mManagerService.getAddress();
637         } catch (RemoteException e) {Log.e(TAG, "", e);}
638         return null;
639     }
640 
641     /**
642      * Get the friendly Bluetooth name of the local Bluetooth adapter.
643      * <p>This name is visible to remote Bluetooth devices.
644      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
645      *
646      * @return the Bluetooth name, or null on error
647      */
getName()648     public String getName() {
649         try {
650             return mManagerService.getName();
651         } catch (RemoteException e) {Log.e(TAG, "", e);}
652         return null;
653     }
654 
655     /**
656      * enable or disable Bluetooth HCI snoop log.
657      *
658      * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
659      * permission
660      *
661      * @return true to indicate configure HCI log successfully, or false on
662      *         immediate error
663      * @hide
664      */
configHciSnoopLog(boolean enable)665     public boolean configHciSnoopLog(boolean enable) {
666         try {
667             synchronized(mManagerCallback) {
668                 if (mService != null) return mService.configHciSnoopLog(enable);
669             }
670         } catch (RemoteException e) {Log.e(TAG, "", e);}
671         return false;
672     }
673 
674     /**
675      * Get the UUIDs supported by the local Bluetooth adapter.
676      *
677      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
678      *
679      * @return the UUIDs supported by the local Bluetooth Adapter.
680      * @hide
681      */
getUuids()682     public ParcelUuid[] getUuids() {
683         if (getState() != STATE_ON) return null;
684         try {
685             synchronized(mManagerCallback) {
686                 if (mService != null) return mService.getUuids();
687             }
688         } catch (RemoteException e) {Log.e(TAG, "", e);}
689         return null;
690     }
691 
692     /**
693      * Set the friendly Bluetooth name of the local Bluetooth adapter.
694      * <p>This name is visible to remote Bluetooth devices.
695      * <p>Valid Bluetooth names are a maximum of 248 bytes using UTF-8
696      * encoding, although many remote devices can only display the first
697      * 40 characters, and some may be limited to just 20.
698      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
699      * will return false. After turning on Bluetooth,
700      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
701      * to get the updated value.
702      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
703      *
704      * @param name a valid Bluetooth name
705      * @return     true if the name was set, false otherwise
706      */
setName(String name)707     public boolean setName(String name) {
708         if (getState() != STATE_ON) return false;
709         try {
710             synchronized(mManagerCallback) {
711                 if (mService != null) return mService.setName(name);
712             }
713         } catch (RemoteException e) {Log.e(TAG, "", e);}
714         return false;
715     }
716 
717     /**
718      * Get the current Bluetooth scan mode of the local Bluetooth adapter.
719      * <p>The Bluetooth scan mode determines if the local adapter is
720      * connectable and/or discoverable from remote Bluetooth devices.
721      * <p>Possible values are:
722      * {@link #SCAN_MODE_NONE},
723      * {@link #SCAN_MODE_CONNECTABLE},
724      * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
725      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
726      * will return {@link #SCAN_MODE_NONE}. After turning on Bluetooth,
727      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
728      * to get the updated value.
729      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
730      *
731      * @return scan mode
732      */
getScanMode()733     public int getScanMode() {
734         if (getState() != STATE_ON) return SCAN_MODE_NONE;
735         try {
736             synchronized(mManagerCallback) {
737                 if (mService != null) return mService.getScanMode();
738             }
739         } catch (RemoteException e) {Log.e(TAG, "", e);}
740         return SCAN_MODE_NONE;
741     }
742 
743     /**
744      * Set the Bluetooth scan mode of the local Bluetooth adapter.
745      * <p>The Bluetooth scan mode determines if the local adapter is
746      * connectable and/or discoverable from remote Bluetooth devices.
747      * <p>For privacy reasons, discoverable mode is automatically turned off
748      * after <code>duration</code> seconds. For example, 120 seconds should be
749      * enough for a remote device to initiate and complete its discovery
750      * process.
751      * <p>Valid scan mode values are:
752      * {@link #SCAN_MODE_NONE},
753      * {@link #SCAN_MODE_CONNECTABLE},
754      * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
755      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
756      * will return false. After turning on Bluetooth,
757      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
758      * to get the updated value.
759      * <p>Requires {@link android.Manifest.permission#WRITE_SECURE_SETTINGS}
760      * <p>Applications cannot set the scan mode. They should use
761      * <code>startActivityForResult(
762      * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE})
763      * </code>instead.
764      *
765      * @param mode valid scan mode
766      * @param duration time in seconds to apply scan mode, only used for
767      *                 {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}
768      * @return     true if the scan mode was set, false otherwise
769      * @hide
770      */
setScanMode(int mode, int duration)771     public boolean setScanMode(int mode, int duration) {
772         if (getState() != STATE_ON) return false;
773         try {
774             synchronized(mManagerCallback) {
775                 if (mService != null) return mService.setScanMode(mode, duration);
776             }
777         } catch (RemoteException e) {Log.e(TAG, "", e);}
778         return false;
779     }
780 
781     /** @hide */
setScanMode(int mode)782     public boolean setScanMode(int mode) {
783         if (getState() != STATE_ON) return false;
784         /* getDiscoverableTimeout() to use the latest from NV than use 0 */
785         return setScanMode(mode, getDiscoverableTimeout());
786     }
787 
788     /** @hide */
getDiscoverableTimeout()789     public int getDiscoverableTimeout() {
790         if (getState() != STATE_ON) return -1;
791         try {
792             synchronized(mManagerCallback) {
793                 if (mService != null) return mService.getDiscoverableTimeout();
794             }
795         } catch (RemoteException e) {Log.e(TAG, "", e);}
796         return -1;
797     }
798 
799     /** @hide */
setDiscoverableTimeout(int timeout)800     public void setDiscoverableTimeout(int timeout) {
801         if (getState() != STATE_ON) return;
802         try {
803             synchronized(mManagerCallback) {
804                 if (mService != null) mService.setDiscoverableTimeout(timeout);
805             }
806         } catch (RemoteException e) {Log.e(TAG, "", e);}
807     }
808 
809     /**
810      * Start the remote device discovery process.
811      * <p>The discovery process usually involves an inquiry scan of about 12
812      * seconds, followed by a page scan of each new device to retrieve its
813      * Bluetooth name.
814      * <p>This is an asynchronous call, it will return immediately. Register
815      * for {@link #ACTION_DISCOVERY_STARTED} and {@link
816      * #ACTION_DISCOVERY_FINISHED} intents to determine exactly when the
817      * discovery starts and completes. Register for {@link
818      * BluetoothDevice#ACTION_FOUND} to be notified as remote Bluetooth devices
819      * are found.
820      * <p>Device discovery is a heavyweight procedure. New connections to
821      * remote Bluetooth devices should not be attempted while discovery is in
822      * progress, and existing connections will experience limited bandwidth
823      * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
824      * discovery. Discovery is not managed by the Activity,
825      * but is run as a system service, so an application should always call
826      * {@link BluetoothAdapter#cancelDiscovery()} even if it
827      * did not directly request a discovery, just to be sure.
828      * <p>Device discovery will only find remote devices that are currently
829      * <i>discoverable</i> (inquiry scan enabled). Many Bluetooth devices are
830      * not discoverable by default, and need to be entered into a special mode.
831      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
832      * will return false. After turning on Bluetooth,
833      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
834      * to get the updated value.
835      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
836      *
837      * @return true on success, false on error
838      */
startDiscovery()839     public boolean startDiscovery() {
840         if (getState() != STATE_ON) return false;
841         try {
842             synchronized(mManagerCallback) {
843                 if (mService != null) return mService.startDiscovery();
844             }
845         } catch (RemoteException e) {Log.e(TAG, "", e);}
846         return false;
847     }
848 
849     /**
850      * Cancel the current device discovery process.
851      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
852      * <p>Because discovery is a heavyweight procedure for the Bluetooth
853      * adapter, this method should always be called before attempting to connect
854      * to a remote device with {@link
855      * android.bluetooth.BluetoothSocket#connect()}. Discovery is not managed by
856      * the  Activity, but is run as a system service, so an application should
857      * always call cancel discovery even if it did not directly request a
858      * discovery, just to be sure.
859      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
860      * will return false. After turning on Bluetooth,
861      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
862      * to get the updated value.
863      *
864      * @return true on success, false on error
865      */
cancelDiscovery()866     public boolean cancelDiscovery() {
867         if (getState() != STATE_ON) return false;
868         try {
869             synchronized(mManagerCallback) {
870                 if (mService != null) return mService.cancelDiscovery();
871             }
872         } catch (RemoteException e) {Log.e(TAG, "", e);}
873         return false;
874     }
875 
876     /**
877      * Return true if the local Bluetooth adapter is currently in the device
878      * discovery process.
879      * <p>Device discovery is a heavyweight procedure. New connections to
880      * remote Bluetooth devices should not be attempted while discovery is in
881      * progress, and existing connections will experience limited bandwidth
882      * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
883      * discovery.
884      * <p>Applications can also register for {@link #ACTION_DISCOVERY_STARTED}
885      * or {@link #ACTION_DISCOVERY_FINISHED} to be notified when discovery
886      * starts or completes.
887      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
888      * will return false. After turning on Bluetooth,
889      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
890      * to get the updated value.
891      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
892      *
893      * @return true if discovering
894      */
isDiscovering()895     public boolean isDiscovering() {
896         if (getState() != STATE_ON) return false;
897         try {
898             synchronized(mManagerCallback) {
899                 if (mService != null ) return mService.isDiscovering();
900             }
901         } catch (RemoteException e) {Log.e(TAG, "", e);}
902         return false;
903     }
904 
905     /**
906      * Return true if the multi advertisement is supported by the chipset
907      *
908      * @return true if Multiple Advertisement feature is supported
909      */
isMultipleAdvertisementSupported()910     public boolean isMultipleAdvertisementSupported() {
911         if (getState() != STATE_ON) return false;
912         try {
913             return mService.isMultiAdvertisementSupported();
914         } catch (RemoteException e) {
915             Log.e(TAG, "failed to get isMultipleAdvertisementSupported, error: ", e);
916         }
917         return false;
918     }
919 
920     /**
921      * Return true if offloaded filters are supported
922      *
923      * @return true if chipset supports on-chip filtering
924      */
isOffloadedFilteringSupported()925     public boolean isOffloadedFilteringSupported() {
926         if (getState() != STATE_ON) return false;
927         try {
928             return mService.isOffloadedFilteringSupported();
929         } catch (RemoteException e) {
930             Log.e(TAG, "failed to get isOffloadedFilteringSupported, error: ", e);
931         }
932         return false;
933     }
934 
935     /**
936      * Return true if offloaded scan batching is supported
937      *
938      * @return true if chipset supports on-chip scan batching
939      */
isOffloadedScanBatchingSupported()940     public boolean isOffloadedScanBatchingSupported() {
941         if (getState() != STATE_ON) return false;
942         try {
943             return mService.isOffloadedScanBatchingSupported();
944         } catch (RemoteException e) {
945             Log.e(TAG, "failed to get isOffloadedScanBatchingSupported, error: ", e);
946         }
947         return false;
948     }
949 
950     /**
951      * Return the record of {@link BluetoothActivityEnergyInfo} object that
952      * has the activity and energy info. This can be used to ascertain what
953      * the controller has been up to, since the last sample.
954      * @param updateType Type of info, cached vs refreshed.
955      *
956      * @return a record with {@link BluetoothActivityEnergyInfo} or null if
957      * report is unavailable or unsupported
958      * @hide
959      */
getControllerActivityEnergyInfo(int updateType)960     public BluetoothActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) {
961         if (getState() != STATE_ON) return null;
962         try {
963             BluetoothActivityEnergyInfo record;
964             if (!mService.isActivityAndEnergyReportingSupported()) {
965                 return null;
966             }
967             synchronized(this) {
968                 if (updateType == ACTIVITY_ENERGY_INFO_REFRESHED) {
969                     mService.getActivityEnergyInfoFromController();
970                     wait(CONTROLLER_ENERGY_UPDATE_TIMEOUT_MILLIS);
971                 }
972                 record = mService.reportActivityInfo();
973                 if (record.isValid()) {
974                     return record;
975                 } else {
976                     return null;
977                 }
978             }
979         } catch (InterruptedException e) {
980             Log.e(TAG, "getControllerActivityEnergyInfoCallback wait interrupted: " + e);
981         } catch (RemoteException e) {
982             Log.e(TAG, "getControllerActivityEnergyInfoCallback: " + e);
983         }
984         return null;
985     }
986 
987     /**
988      * Return the set of {@link BluetoothDevice} objects that are bonded
989      * (paired) to the local adapter.
990      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
991      * will return an empty set. After turning on Bluetooth,
992      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
993      * to get the updated value.
994      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
995      *
996      * @return unmodifiable set of {@link BluetoothDevice}, or null on error
997      */
getBondedDevices()998     public Set<BluetoothDevice> getBondedDevices() {
999         if (getState() != STATE_ON) {
1000             return toDeviceSet(new BluetoothDevice[0]);
1001         }
1002         try {
1003             synchronized(mManagerCallback) {
1004                 if (mService != null) return toDeviceSet(mService.getBondedDevices());
1005             }
1006             return toDeviceSet(new BluetoothDevice[0]);
1007         } catch (RemoteException e) {Log.e(TAG, "", e);}
1008         return null;
1009     }
1010 
1011     /**
1012      * Get the current connection state of the local Bluetooth adapter.
1013      * This can be used to check whether the local Bluetooth adapter is connected
1014      * to any profile of any other remote Bluetooth Device.
1015      *
1016      * <p> Use this function along with {@link #ACTION_CONNECTION_STATE_CHANGED}
1017      * intent to get the connection state of the adapter.
1018      *
1019      * @return One of {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTED},
1020      * {@link #STATE_CONNECTING} or {@link #STATE_DISCONNECTED}
1021      *
1022      * @hide
1023      */
getConnectionState()1024     public int getConnectionState() {
1025         if (getState() != STATE_ON) return BluetoothAdapter.STATE_DISCONNECTED;
1026         try {
1027             synchronized(mManagerCallback) {
1028                 if (mService != null) return mService.getAdapterConnectionState();
1029             }
1030         } catch (RemoteException e) {Log.e(TAG, "getConnectionState:", e);}
1031         return BluetoothAdapter.STATE_DISCONNECTED;
1032     }
1033 
1034     /**
1035      * Get the current connection state of a profile.
1036      * This function can be used to check whether the local Bluetooth adapter
1037      * is connected to any remote device for a specific profile.
1038      * Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET},
1039      * {@link BluetoothProfile#A2DP}.
1040      *
1041      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
1042      *
1043      * <p> Return value can be one of
1044      * {@link BluetoothProfile#STATE_DISCONNECTED},
1045      * {@link BluetoothProfile#STATE_CONNECTING},
1046      * {@link BluetoothProfile#STATE_CONNECTED},
1047      * {@link BluetoothProfile#STATE_DISCONNECTING}
1048      */
getProfileConnectionState(int profile)1049     public int getProfileConnectionState(int profile) {
1050         if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED;
1051         try {
1052             synchronized(mManagerCallback) {
1053                 if (mService != null) return mService.getProfileConnectionState(profile);
1054             }
1055         } catch (RemoteException e) {
1056             Log.e(TAG, "getProfileConnectionState:", e);
1057         }
1058         return BluetoothProfile.STATE_DISCONNECTED;
1059     }
1060 
1061     /**
1062      * Create a listening, secure RFCOMM Bluetooth socket.
1063      * <p>A remote device connecting to this socket will be authenticated and
1064      * communication on this socket will be encrypted.
1065      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
1066      * connections from a listening {@link BluetoothServerSocket}.
1067      * <p>Valid RFCOMM channels are in range 1 to 30.
1068      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
1069      * @param channel RFCOMM channel to listen on
1070      * @return a listening RFCOMM BluetoothServerSocket
1071      * @throws IOException on error, for example Bluetooth not available, or
1072      *                     insufficient permissions, or channel in use.
1073      * @hide
1074      */
listenUsingRfcommOn(int channel)1075     public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException {
1076         BluetoothServerSocket socket = new BluetoothServerSocket(
1077                 BluetoothSocket.TYPE_RFCOMM, true, true, channel);
1078         int errno = socket.mSocket.bindListen();
1079         if (errno != 0) {
1080             //TODO(BT): Throw the same exception error code
1081             // that the previous code was using.
1082             //socket.mSocket.throwErrnoNative(errno);
1083             throw new IOException("Error: " + errno);
1084         }
1085         return socket;
1086     }
1087 
1088     /**
1089      * Create a listening, secure RFCOMM Bluetooth socket with Service Record.
1090      * <p>A remote device connecting to this socket will be authenticated and
1091      * communication on this socket will be encrypted.
1092      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
1093      * connections from a listening {@link BluetoothServerSocket}.
1094      * <p>The system will assign an unused RFCOMM channel to listen on.
1095      * <p>The system will also register a Service Discovery
1096      * Protocol (SDP) record with the local SDP server containing the specified
1097      * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
1098      * can use the same UUID to query our SDP server and discover which channel
1099      * to connect to. This SDP record will be removed when this socket is
1100      * closed, or if this application closes unexpectedly.
1101      * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
1102      * connect to this socket from another device using the same {@link UUID}.
1103      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1104      * @param name service name for SDP record
1105      * @param uuid uuid for SDP record
1106      * @return a listening RFCOMM BluetoothServerSocket
1107      * @throws IOException on error, for example Bluetooth not available, or
1108      *                     insufficient permissions, or channel in use.
1109      */
listenUsingRfcommWithServiceRecord(String name, UUID uuid)1110     public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid)
1111             throws IOException {
1112         return createNewRfcommSocketAndRecord(name, uuid, true, true);
1113     }
1114 
1115     /**
1116      * Create a listening, insecure RFCOMM Bluetooth socket with Service Record.
1117      * <p>The link key is not required to be authenticated, i.e the communication may be
1118      * vulnerable to Man In the Middle attacks. For Bluetooth 2.1 devices,
1119      * the link will be encrypted, as encryption is mandartory.
1120      * For legacy devices (pre Bluetooth 2.1 devices) the link will not
1121      * be encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an
1122      * encrypted and authenticated communication channel is desired.
1123      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
1124      * connections from a listening {@link BluetoothServerSocket}.
1125      * <p>The system will assign an unused RFCOMM channel to listen on.
1126      * <p>The system will also register a Service Discovery
1127      * Protocol (SDP) record with the local SDP server containing the specified
1128      * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
1129      * can use the same UUID to query our SDP server and discover which channel
1130      * to connect to. This SDP record will be removed when this socket is
1131      * closed, or if this application closes unexpectedly.
1132      * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
1133      * connect to this socket from another device using the same {@link UUID}.
1134      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1135      * @param name service name for SDP record
1136      * @param uuid uuid for SDP record
1137      * @return a listening RFCOMM BluetoothServerSocket
1138      * @throws IOException on error, for example Bluetooth not available, or
1139      *                     insufficient permissions, or channel in use.
1140      */
listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)1141     public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)
1142             throws IOException {
1143         return createNewRfcommSocketAndRecord(name, uuid, false, false);
1144     }
1145 
1146      /**
1147      * Create a listening, encrypted,
1148      * RFCOMM Bluetooth socket with Service Record.
1149      * <p>The link will be encrypted, but the link key is not required to be authenticated
1150      * i.e the communication is vulnerable to Man In the Middle attacks. Use
1151      * {@link #listenUsingRfcommWithServiceRecord}, to ensure an authenticated link key.
1152      * <p> Use this socket if authentication of link key is not possible.
1153      * For example, for Bluetooth 2.1 devices, if any of the devices does not have
1154      * an input and output capability or just has the ability to display a numeric key,
1155      * a secure socket connection is not possible and this socket can be used.
1156      * Use {@link #listenUsingInsecureRfcommWithServiceRecord}, if encryption is not required.
1157      * For Bluetooth 2.1 devices, the link will be encrypted, as encryption is mandartory.
1158      * For more details, refer to the Security Model section 5.2 (vol 3) of
1159      * Bluetooth Core Specification version 2.1 + EDR.
1160      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
1161      * connections from a listening {@link BluetoothServerSocket}.
1162      * <p>The system will assign an unused RFCOMM channel to listen on.
1163      * <p>The system will also register a Service Discovery
1164      * Protocol (SDP) record with the local SDP server containing the specified
1165      * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
1166      * can use the same UUID to query our SDP server and discover which channel
1167      * to connect to. This SDP record will be removed when this socket is
1168      * closed, or if this application closes unexpectedly.
1169      * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
1170      * connect to this socket from another device using the same {@link UUID}.
1171      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1172      * @param name service name for SDP record
1173      * @param uuid uuid for SDP record
1174      * @return a listening RFCOMM BluetoothServerSocket
1175      * @throws IOException on error, for example Bluetooth not available, or
1176      *                     insufficient permissions, or channel in use.
1177      * @hide
1178      */
listenUsingEncryptedRfcommWithServiceRecord( String name, UUID uuid)1179     public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(
1180             String name, UUID uuid) throws IOException {
1181         return createNewRfcommSocketAndRecord(name, uuid, false, true);
1182     }
1183 
1184 
createNewRfcommSocketAndRecord(String name, UUID uuid, boolean auth, boolean encrypt)1185     private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid,
1186             boolean auth, boolean encrypt) throws IOException {
1187         BluetoothServerSocket socket;
1188         socket = new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, auth,
1189                         encrypt, new ParcelUuid(uuid));
1190         socket.setServiceName(name);
1191         int errno = socket.mSocket.bindListen();
1192         if (errno != 0) {
1193             //TODO(BT): Throw the same exception error code
1194             // that the previous code was using.
1195             //socket.mSocket.throwErrnoNative(errno);
1196             throw new IOException("Error: " + errno);
1197         }
1198         return socket;
1199     }
1200 
1201     /**
1202      * Construct an unencrypted, unauthenticated, RFCOMM server socket.
1203      * Call #accept to retrieve connections to this socket.
1204      * @return An RFCOMM BluetoothServerSocket
1205      * @throws IOException On error, for example Bluetooth not available, or
1206      *                     insufficient permissions.
1207      * @hide
1208      */
listenUsingInsecureRfcommOn(int port)1209     public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException {
1210         BluetoothServerSocket socket = new BluetoothServerSocket(
1211                 BluetoothSocket.TYPE_RFCOMM, false, false, port);
1212         int errno = socket.mSocket.bindListen();
1213         if (errno != 0) {
1214             //TODO(BT): Throw the same exception error code
1215             // that the previous code was using.
1216             //socket.mSocket.throwErrnoNative(errno);
1217             throw new IOException("Error: " + errno);
1218         }
1219         return socket;
1220     }
1221 
1222      /**
1223      * Construct an encrypted, RFCOMM server socket.
1224      * Call #accept to retrieve connections to this socket.
1225      * @return An RFCOMM BluetoothServerSocket
1226      * @throws IOException On error, for example Bluetooth not available, or
1227      *                     insufficient permissions.
1228      * @hide
1229      */
listenUsingEncryptedRfcommOn(int port)1230     public BluetoothServerSocket listenUsingEncryptedRfcommOn(int port)
1231             throws IOException {
1232         BluetoothServerSocket socket = new BluetoothServerSocket(
1233                 BluetoothSocket.TYPE_RFCOMM, false, true, port);
1234         int errno = socket.mSocket.bindListen();
1235         if (errno < 0) {
1236             //TODO(BT): Throw the same exception error code
1237             // that the previous code was using.
1238             //socket.mSocket.throwErrnoNative(errno);
1239             throw new IOException("Error: " + errno);
1240         }
1241         return socket;
1242     }
1243 
1244     /**
1245      * Construct a SCO server socket.
1246      * Call #accept to retrieve connections to this socket.
1247      * @return A SCO BluetoothServerSocket
1248      * @throws IOException On error, for example Bluetooth not available, or
1249      *                     insufficient permissions.
1250      * @hide
1251      */
listenUsingScoOn()1252     public static BluetoothServerSocket listenUsingScoOn() throws IOException {
1253         BluetoothServerSocket socket = new BluetoothServerSocket(
1254                 BluetoothSocket.TYPE_SCO, false, false, -1);
1255         int errno = socket.mSocket.bindListen();
1256         if (errno < 0) {
1257             //TODO(BT): Throw the same exception error code
1258             // that the previous code was using.
1259             //socket.mSocket.throwErrnoNative(errno);
1260         }
1261         return socket;
1262     }
1263 
1264     /**
1265      * Read the local Out of Band Pairing Data
1266      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1267      *
1268      * @return Pair<byte[], byte[]> of Hash and Randomizer
1269      *
1270      * @hide
1271      */
readOutOfBandData()1272     public Pair<byte[], byte[]> readOutOfBandData() {
1273         if (getState() != STATE_ON) return null;
1274         //TODO(BT
1275         /*
1276         try {
1277             byte[] hash;
1278             byte[] randomizer;
1279 
1280             byte[] ret = mService.readOutOfBandData();
1281 
1282             if (ret  == null || ret.length != 32) return null;
1283 
1284             hash = Arrays.copyOfRange(ret, 0, 16);
1285             randomizer = Arrays.copyOfRange(ret, 16, 32);
1286 
1287             if (DBG) {
1288                 Log.d(TAG, "readOutOfBandData:" + Arrays.toString(hash) +
1289                   ":" + Arrays.toString(randomizer));
1290             }
1291             return new Pair<byte[], byte[]>(hash, randomizer);
1292 
1293         } catch (RemoteException e) {Log.e(TAG, "", e);}*/
1294         return null;
1295     }
1296 
1297     /**
1298      * Get the profile proxy object associated with the profile.
1299      *
1300      * <p>Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET},
1301      * {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#GATT}, or
1302      * {@link BluetoothProfile#GATT_SERVER}. Clients must implement
1303      * {@link BluetoothProfile.ServiceListener} to get notified of
1304      * the connection status and to get the proxy object.
1305      *
1306      * @param context Context of the application
1307      * @param listener The service Listener for connection callbacks.
1308      * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEALTH},
1309      *                {@link BluetoothProfile#HEADSET} or {@link BluetoothProfile#A2DP}.
1310      * @return true on success, false on error
1311      */
getProfileProxy(Context context, BluetoothProfile.ServiceListener listener, int profile)1312     public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,
1313                                    int profile) {
1314         if (context == null || listener == null) return false;
1315 
1316         if (profile == BluetoothProfile.HEADSET) {
1317             BluetoothHeadset headset = new BluetoothHeadset(context, listener);
1318             return true;
1319         } else if (profile == BluetoothProfile.A2DP) {
1320             BluetoothA2dp a2dp = new BluetoothA2dp(context, listener);
1321             return true;
1322         } else if (profile == BluetoothProfile.A2DP_SINK) {
1323             BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener);
1324             return true;
1325         } else if (profile == BluetoothProfile.AVRCP_CONTROLLER) {
1326             BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener);
1327             return true;
1328         } else if (profile == BluetoothProfile.INPUT_DEVICE) {
1329             BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener);
1330             return true;
1331         } else if (profile == BluetoothProfile.PAN) {
1332             BluetoothPan pan = new BluetoothPan(context, listener);
1333             return true;
1334         } else if (profile == BluetoothProfile.HEALTH) {
1335             BluetoothHealth health = new BluetoothHealth(context, listener);
1336             return true;
1337         } else if (profile == BluetoothProfile.MAP) {
1338             BluetoothMap map = new BluetoothMap(context, listener);
1339             return true;
1340         } else if (profile == BluetoothProfile.HEADSET_CLIENT) {
1341             BluetoothHeadsetClient headsetClient = new BluetoothHeadsetClient(context, listener);
1342             return true;
1343         } else {
1344             return false;
1345         }
1346     }
1347 
1348     /**
1349      * Close the connection of the profile proxy to the Service.
1350      *
1351      * <p> Clients should call this when they are no longer using
1352      * the proxy obtained from {@link #getProfileProxy}.
1353      * Profile can be one of  {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET} or
1354      * {@link BluetoothProfile#A2DP}
1355      *
1356      * @param profile
1357      * @param proxy Profile proxy object
1358      */
closeProfileProxy(int profile, BluetoothProfile proxy)1359     public void closeProfileProxy(int profile, BluetoothProfile proxy) {
1360         if (proxy == null) return;
1361 
1362         switch (profile) {
1363             case BluetoothProfile.HEADSET:
1364                 BluetoothHeadset headset = (BluetoothHeadset)proxy;
1365                 headset.close();
1366                 break;
1367             case BluetoothProfile.A2DP:
1368                 BluetoothA2dp a2dp = (BluetoothA2dp)proxy;
1369                 a2dp.close();
1370                 break;
1371             case BluetoothProfile.A2DP_SINK:
1372                 BluetoothA2dpSink a2dpSink = (BluetoothA2dpSink)proxy;
1373                 a2dpSink.close();
1374                 break;
1375             case BluetoothProfile.AVRCP_CONTROLLER:
1376                 BluetoothAvrcpController avrcp = (BluetoothAvrcpController)proxy;
1377                 avrcp.close();
1378                 break;
1379             case BluetoothProfile.INPUT_DEVICE:
1380                 BluetoothInputDevice iDev = (BluetoothInputDevice)proxy;
1381                 iDev.close();
1382                 break;
1383             case BluetoothProfile.PAN:
1384                 BluetoothPan pan = (BluetoothPan)proxy;
1385                 pan.close();
1386                 break;
1387             case BluetoothProfile.HEALTH:
1388                 BluetoothHealth health = (BluetoothHealth)proxy;
1389                 health.close();
1390                 break;
1391            case BluetoothProfile.GATT:
1392                 BluetoothGatt gatt = (BluetoothGatt)proxy;
1393                 gatt.close();
1394                 break;
1395             case BluetoothProfile.GATT_SERVER:
1396                 BluetoothGattServer gattServer = (BluetoothGattServer)proxy;
1397                 gattServer.close();
1398                 break;
1399             case BluetoothProfile.MAP:
1400                 BluetoothMap map = (BluetoothMap)proxy;
1401                 map.close();
1402                 break;
1403             case BluetoothProfile.HEADSET_CLIENT:
1404                 BluetoothHeadsetClient headsetClient = (BluetoothHeadsetClient)proxy;
1405                 headsetClient.close();
1406                 break;
1407         }
1408     }
1409 
1410     final private IBluetoothManagerCallback mManagerCallback =
1411         new IBluetoothManagerCallback.Stub() {
1412             public void onBluetoothServiceUp(IBluetooth bluetoothService) {
1413                 if (VDBG) Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
1414                 synchronized (mManagerCallback) {
1415                     mService = bluetoothService;
1416                     for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
1417                         try {
1418                             if (cb != null) {
1419                                 cb.onBluetoothServiceUp(bluetoothService);
1420                             } else {
1421                                 Log.d(TAG, "onBluetoothServiceUp: cb is null!!!");
1422                             }
1423                         } catch (Exception e)  { Log.e(TAG,"",e);}
1424                     }
1425                 }
1426             }
1427 
1428             public void onBluetoothServiceDown() {
1429                 if (VDBG) Log.d(TAG, "onBluetoothServiceDown: " + mService);
1430                 synchronized (mManagerCallback) {
1431                     mService = null;
1432                     mLeScanClients.clear();
1433                     if (sBluetoothLeAdvertiser != null) sBluetoothLeAdvertiser.cleanup();
1434                     if (sBluetoothLeScanner != null) sBluetoothLeScanner.cleanup();
1435                     for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks ){
1436                         try {
1437                             if (cb != null) {
1438                                 cb.onBluetoothServiceDown();
1439                             } else {
1440                                 Log.d(TAG, "onBluetoothServiceDown: cb is null!!!");
1441                             }
1442                         } catch (Exception e)  { Log.e(TAG,"",e);}
1443                     }
1444                 }
1445             }
1446     };
1447 
1448     /**
1449      * Enable the Bluetooth Adapter, but don't auto-connect devices
1450      * and don't persist state. Only for use by system applications.
1451      * @hide
1452      */
enableNoAutoConnect()1453     public boolean enableNoAutoConnect() {
1454         if (isEnabled() == true){
1455             if (DBG) Log.d(TAG, "enableNoAutoConnect(): BT is already enabled..!");
1456             return true;
1457         }
1458         try {
1459             return mManagerService.enableNoAutoConnect();
1460         } catch (RemoteException e) {Log.e(TAG, "", e);}
1461         return false;
1462     }
1463 
1464     /**
1465      * Enable control of the Bluetooth Adapter for a single application.
1466      *
1467      * <p>Some applications need to use Bluetooth for short periods of time to
1468      * transfer data but don't want all the associated implications like
1469      * automatic connection to headsets etc.
1470      *
1471      * <p> Multiple applications can call this. This is reference counted and
1472      * Bluetooth disabled only when no one else is using it. There will be no UI
1473      * shown to the user while bluetooth is being enabled. Any user action will
1474      * override this call. For example, if user wants Bluetooth on and the last
1475      * user of this API wanted to disable Bluetooth, Bluetooth will not be
1476      * turned off.
1477      *
1478      * <p> This API is only meant to be used by internal applications. Third
1479      * party applications but use {@link #enable} and {@link #disable} APIs.
1480      *
1481      * <p> If this API returns true, it means the callback will be called.
1482      * The callback will be called with the current state of Bluetooth.
1483      * If the state is not what was requested, an internal error would be the
1484      * reason. If Bluetooth is already on and if this function is called to turn
1485      * it on, the api will return true and a callback will be called.
1486      *
1487      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
1488      *
1489      * @param on True for on, false for off.
1490      * @param callback The callback to notify changes to the state.
1491      * @hide
1492      */
changeApplicationBluetoothState(boolean on, BluetoothStateChangeCallback callback)1493     public boolean changeApplicationBluetoothState(boolean on,
1494                                                    BluetoothStateChangeCallback callback) {
1495         if (callback == null) return false;
1496 
1497         //TODO(BT)
1498         /*
1499         try {
1500             return mService.changeApplicationBluetoothState(on, new
1501                     StateChangeCallbackWrapper(callback), new Binder());
1502         } catch (RemoteException e) {
1503             Log.e(TAG, "changeBluetoothState", e);
1504         }*/
1505         return false;
1506     }
1507 
1508     /**
1509      * @hide
1510      */
1511     public interface BluetoothStateChangeCallback {
onBluetoothStateChange(boolean on)1512         public void onBluetoothStateChange(boolean on);
1513     }
1514 
1515     /**
1516      * @hide
1517      */
1518     public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub {
1519         private BluetoothStateChangeCallback mCallback;
1520 
StateChangeCallbackWrapper(BluetoothStateChangeCallback callback)1521         StateChangeCallbackWrapper(BluetoothStateChangeCallback
1522                 callback) {
1523             mCallback = callback;
1524         }
1525 
1526         @Override
onBluetoothStateChange(boolean on)1527         public void onBluetoothStateChange(boolean on) {
1528             mCallback.onBluetoothStateChange(on);
1529         }
1530     }
1531 
toDeviceSet(BluetoothDevice[] devices)1532     private Set<BluetoothDevice> toDeviceSet(BluetoothDevice[] devices) {
1533         Set<BluetoothDevice> deviceSet = new HashSet<BluetoothDevice>(Arrays.asList(devices));
1534         return Collections.unmodifiableSet(deviceSet);
1535     }
1536 
finalize()1537     protected void finalize() throws Throwable {
1538         try {
1539             mManagerService.unregisterAdapter(mManagerCallback);
1540         } catch (RemoteException e) {
1541             Log.e(TAG, "", e);
1542         } finally {
1543             super.finalize();
1544         }
1545     }
1546 
1547 
1548     /**
1549      * Validate a String Bluetooth address, such as "00:43:A8:23:10:F0"
1550      * <p>Alphabetic characters must be uppercase to be valid.
1551      *
1552      * @param address Bluetooth address as string
1553      * @return true if the address is valid, false otherwise
1554      */
checkBluetoothAddress(String address)1555     public static boolean checkBluetoothAddress(String address) {
1556         if (address == null || address.length() != ADDRESS_LENGTH) {
1557             return false;
1558         }
1559         for (int i = 0; i < ADDRESS_LENGTH; i++) {
1560             char c = address.charAt(i);
1561             switch (i % 3) {
1562             case 0:
1563             case 1:
1564                 if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
1565                     // hex character, OK
1566                     break;
1567                 }
1568                 return false;
1569             case 2:
1570                 if (c == ':') {
1571                     break;  // OK
1572                 }
1573                 return false;
1574             }
1575         }
1576         return true;
1577     }
1578 
getBluetoothManager()1579     /*package*/ IBluetoothManager getBluetoothManager() {
1580             return mManagerService;
1581     }
1582 
1583     private ArrayList<IBluetoothManagerCallback> mProxyServiceStateCallbacks = new ArrayList<IBluetoothManagerCallback>();
1584 
getBluetoothService(IBluetoothManagerCallback cb)1585     /*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) {
1586         synchronized (mManagerCallback) {
1587             if (cb == null) {
1588                 Log.w(TAG, "getBluetoothService() called with no BluetoothManagerCallback");
1589             } else if (!mProxyServiceStateCallbacks.contains(cb)) {
1590                 mProxyServiceStateCallbacks.add(cb);
1591             }
1592         }
1593         return mService;
1594     }
1595 
removeServiceStateCallback(IBluetoothManagerCallback cb)1596     /*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) {
1597         synchronized (mManagerCallback) {
1598             mProxyServiceStateCallbacks.remove(cb);
1599         }
1600     }
1601 
1602     /**
1603      * Callback interface used to deliver LE scan results.
1604      *
1605      * @see #startLeScan(LeScanCallback)
1606      * @see #startLeScan(UUID[], LeScanCallback)
1607      */
1608     public interface LeScanCallback {
1609         /**
1610          * Callback reporting an LE device found during a device scan initiated
1611          * by the {@link BluetoothAdapter#startLeScan} function.
1612          *
1613          * @param device Identifies the remote device
1614          * @param rssi The RSSI value for the remote device as reported by the
1615          *             Bluetooth hardware. 0 if no RSSI value is available.
1616          * @param scanRecord The content of the advertisement record offered by
1617          *                   the remote device.
1618          */
onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord)1619         public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord);
1620     }
1621 
1622     /**
1623      * Starts a scan for Bluetooth LE devices.
1624      *
1625      * <p>Results of the scan are reported using the
1626      * {@link LeScanCallback#onLeScan} callback.
1627      *
1628      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
1629      *
1630      * @param callback the callback LE scan results are delivered
1631      * @return true, if the scan was started successfully
1632      * @deprecated use {@link BluetoothLeScanner#startScan(List, ScanSettings, ScanCallback)}
1633      *             instead.
1634      */
1635     @Deprecated
startLeScan(LeScanCallback callback)1636     public boolean startLeScan(LeScanCallback callback) {
1637         return startLeScan(null, callback);
1638     }
1639 
1640     /**
1641      * Starts a scan for Bluetooth LE devices, looking for devices that
1642      * advertise given services.
1643      *
1644      * <p>Devices which advertise all specified services are reported using the
1645      * {@link LeScanCallback#onLeScan} callback.
1646      *
1647      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
1648      *
1649      * @param serviceUuids Array of services to look for
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(final UUID[] serviceUuids, final LeScanCallback callback)1656     public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback) {
1657         if (DBG) Log.d(TAG, "startLeScan(): " + serviceUuids);
1658         if (callback == null) {
1659             if (DBG) Log.e(TAG, "startLeScan: null callback");
1660             return false;
1661         }
1662         BluetoothLeScanner scanner = getBluetoothLeScanner();
1663         if (scanner == null) {
1664             if (DBG) Log.e(TAG, "startLeScan: cannot get BluetoothLeScanner");
1665             return false;
1666         }
1667 
1668         synchronized(mLeScanClients) {
1669             if (mLeScanClients.containsKey(callback)) {
1670                 if (DBG) Log.e(TAG, "LE Scan has already started");
1671                 return false;
1672             }
1673 
1674             try {
1675                 IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
1676                 if (iGatt == null) {
1677                     // BLE is not supported
1678                     return false;
1679                 }
1680 
1681                 ScanCallback scanCallback = new ScanCallback() {
1682                     @Override
1683                     public void onScanResult(int callbackType, ScanResult result) {
1684                         if (callbackType != ScanSettings.CALLBACK_TYPE_ALL_MATCHES) {
1685                             // Should not happen.
1686                             Log.e(TAG, "LE Scan has already started");
1687                             return;
1688                         }
1689                         ScanRecord scanRecord = result.getScanRecord();
1690                         if (scanRecord == null) {
1691                             return;
1692                         }
1693                         if (serviceUuids != null) {
1694                             List<ParcelUuid> uuids = new ArrayList<ParcelUuid>();
1695                             for (UUID uuid : serviceUuids) {
1696                                 uuids.add(new ParcelUuid(uuid));
1697                             }
1698                             List<ParcelUuid> scanServiceUuids = scanRecord.getServiceUuids();
1699                             if (scanServiceUuids == null || !scanServiceUuids.containsAll(uuids)) {
1700                                 if (DBG) Log.d(TAG, "uuids does not match");
1701                                 return;
1702                             }
1703                         }
1704                         callback.onLeScan(result.getDevice(), result.getRssi(),
1705                                 scanRecord.getBytes());
1706                     }
1707                 };
1708                 ScanSettings settings = new ScanSettings.Builder()
1709                     .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
1710                     .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
1711 
1712                 List<ScanFilter> filters = new ArrayList<ScanFilter>();
1713                 if (serviceUuids != null && serviceUuids.length > 0) {
1714                     // Note scan filter does not support matching an UUID array so we put one
1715                     // UUID to hardware and match the whole array in callback.
1716                     ScanFilter filter = new ScanFilter.Builder().setServiceUuid(
1717                             new ParcelUuid(serviceUuids[0])).build();
1718                     filters.add(filter);
1719                 }
1720                 scanner.startScan(filters, settings, scanCallback);
1721 
1722                 mLeScanClients.put(callback, scanCallback);
1723                 return true;
1724 
1725             } catch (RemoteException e) {
1726                 Log.e(TAG,"",e);
1727             }
1728         }
1729         return false;
1730     }
1731 
1732     /**
1733      * Stops an ongoing Bluetooth LE device scan.
1734      *
1735      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
1736      *
1737      * @param callback used to identify which scan to stop
1738      *        must be the same handle used to start the scan
1739      * @deprecated Use {@link BluetoothLeScanner#stopScan(ScanCallback)} instead.
1740      */
1741     @Deprecated
stopLeScan(LeScanCallback callback)1742     public void stopLeScan(LeScanCallback callback) {
1743         if (DBG) Log.d(TAG, "stopLeScan()");
1744         BluetoothLeScanner scanner = getBluetoothLeScanner();
1745         if (scanner == null) {
1746             return;
1747         }
1748         synchronized (mLeScanClients) {
1749             ScanCallback scanCallback = mLeScanClients.remove(callback);
1750             if (scanCallback == null) {
1751                 if (DBG) Log.d(TAG, "scan not started yet");
1752                 return;
1753             }
1754             scanner.stopScan(scanCallback);
1755         }
1756     }
1757 }
1758