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