[go: nahoru, domu]

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