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