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