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