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