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