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