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