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