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