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