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