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