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