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