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      * Return true if Bluetooth is currently enabled and ready for use.
    409      * <p>Equivalent to:
    410      * <code>getBluetoothState() == STATE_ON</code>
    411      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
    412      *
    413      * @return true if the local adapter is turned on
    414      */
    415     public boolean isEnabled() {
    416         try {
    417             return mService.isEnabled();
    418         } catch (RemoteException e) {Log.e(TAG, "", e);}
    419         return false;
    420     }
    421 
    422     /**
    423      * Get the current state of the local Bluetooth adapter.
    424      * <p>Possible return values are
    425      * {@link #STATE_OFF},
    426      * {@link #STATE_TURNING_ON},
    427      * {@link #STATE_ON},
    428      * {@link #STATE_TURNING_OFF}.
    429      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
    430      *
    431      * @return current state of Bluetooth adapter
    432      */
    433     public int getState() {
    434         try {
    435             return mService.getBluetoothState();
    436         } catch (RemoteException e) {Log.e(TAG, "", e);}
    437         return STATE_OFF;
    438     }
    439 
    440     /**
    441      * Turn on the local Bluetooth adapter&mdash;do not use without explicit
    442      * user action to turn on Bluetooth.
    443      * <p>This powers on the underlying Bluetooth hardware, and starts all
    444      * Bluetooth system services.
    445      * <p class="caution"><strong>Bluetooth should never be enabled without
    446      * direct user consent</strong>. If you want to turn on Bluetooth in order
    447      * to create a wireless connection, you should use the {@link
    448      * #ACTION_REQUEST_ENABLE} Intent, which will raise a dialog that requests
    449      * user permission to turn on Bluetooth. The {@link #enable()} method is
    450      * provided only for applications that include a user interface for changing
    451      * system settings, such as a "power manager" app.</p>
    452      * <p>This is an asynchronous call: it will return immediately, and
    453      * clients should listen for {@link #ACTION_STATE_CHANGED}
    454      * to be notified of subsequent adapter state changes. If this call returns
    455      * true, then the adapter state will immediately transition from {@link
    456      * #STATE_OFF} to {@link #STATE_TURNING_ON}, and some time
    457      * later transition to either {@link #STATE_OFF} or {@link
    458      * #STATE_ON}. If this call returns false then there was an
    459      * immediate problem that will prevent the adapter from being turned on -
    460      * such as Airplane mode, or the adapter is already turned on.
    461      * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
    462      * permission
    463      *
    464      * @return true to indicate adapter startup has begun, or false on
    465      *         immediate error
    466      */
    467     public boolean enable() {
    468         try {
    469             return mService.enable();
    470         } catch (RemoteException e) {Log.e(TAG, "", e);}
    471         return false;
    472     }
    473 
    474     /**
    475      * Turn off the local Bluetooth adapter&mdash;do not use without explicit
    476      * user action to turn off Bluetooth.
    477      * <p>This gracefully shuts down all Bluetooth connections, stops Bluetooth
    478      * system services, and powers down the underlying Bluetooth hardware.
    479      * <p class="caution"><strong>Bluetooth should never be disabled without
    480      * direct user consent</strong>. The {@link #disable()} method is
    481      * provided only for applications that include a user interface for changing
    482      * system settings, such as a "power manager" app.</p>
    483      * <p>This is an asynchronous call: it will return immediately, and
    484      * clients should listen for {@link #ACTION_STATE_CHANGED}
    485      * to be notified of subsequent adapter state changes. If this call returns
    486      * true, then the adapter state will immediately transition from {@link
    487      * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time
    488      * later transition to either {@link #STATE_OFF} or {@link
    489      * #STATE_ON}. If this call returns false then there was an
    490      * immediate problem that will prevent the adapter from being turned off -
    491      * such as the adapter already being turned off.
    492      * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
    493      * permission
    494      *
    495      * @return true to indicate adapter shutdown has begun, or false on
    496      *         immediate error
    497      */
    498     public boolean disable() {
    499         try {
    500             return mService.disable(true);
    501         } catch (RemoteException e) {Log.e(TAG, "", e);}
    502         return false;
    503     }
    504 
    505     /**
    506      * Returns the hardware address of the local Bluetooth adapter.
    507      * <p>For example, "00:11:22:AA:BB:CC".
    508      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
    509      *
    510      * @return Bluetooth hardware address as string
    511      */
    512     public String getAddress() {
    513         try {
    514             return mService.getAddress();
    515         } catch (RemoteException e) {Log.e(TAG, "", e);}
    516         return null;
    517     }
    518 
    519     /**
    520      * Get the friendly Bluetooth name of the local Bluetooth adapter.
    521      * <p>This name is visible to remote Bluetooth devices.
    522      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
    523      *
    524      * @return the Bluetooth name, or null on error
    525      */
    526     public String getName() {
    527         try {
    528             return mService.getName();
    529         } catch (RemoteException e) {Log.e(TAG, "", e);}
    530         return null;
    531     }
    532 
    533     /**
    534      * Get the UUIDs supported by the local Bluetooth adapter.
    535      *
    536      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
    537      *
    538      * @return the UUIDs supported by the local Bluetooth Adapter.
    539      * @hide
    540      */
    541     public ParcelUuid[] getUuids() {
    542         if (getState() != STATE_ON) return null;
    543         try {
    544             return mService.getUuids();
    545         } catch (RemoteException e) {Log.e(TAG, "", e);}
    546         return null;
    547     }
    548 
    549     /**
    550      * Set the friendly Bluetooth name of the local Bluetooth adapter.
    551      * <p>This name is visible to remote Bluetooth devices.
    552      * <p>Valid Bluetooth names are a maximum of 248 bytes using UTF-8
    553      * encoding, although many remote devices can only display the first
    554      * 40 characters, and some may be limited to just 20.
    555      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
    556      * will return false. After turning on Bluetooth,
    557      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
    558      * to get the updated value.
    559      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
    560      *
    561      * @param name a valid Bluetooth name
    562      * @return     true if the name was set, false otherwise
    563      */
    564     public boolean setName(String name) {
    565         if (getState() != STATE_ON) return false;
    566         try {
    567             return mService.setName(name);
    568         } catch (RemoteException e) {Log.e(TAG, "", e);}
    569         return false;
    570     }
    571 
    572     /**
    573      * Get the current Bluetooth scan mode of the local Bluetooth adapter.
    574      * <p>The Bluetooth scan mode determines if the local adapter is
    575      * connectable and/or discoverable from remote Bluetooth devices.
    576      * <p>Possible values are:
    577      * {@link #SCAN_MODE_NONE},
    578      * {@link #SCAN_MODE_CONNECTABLE},
    579      * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
    580      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
    581      * will return {@link #SCAN_MODE_NONE}. After turning on Bluetooth,
    582      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
    583      * to get the updated value.
    584      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
    585      *
    586      * @return scan mode
    587      */
    588     public int getScanMode() {
    589         if (getState() != STATE_ON) return SCAN_MODE_NONE;
    590         try {
    591             return mService.getScanMode();
    592         } catch (RemoteException e) {Log.e(TAG, "", e);}
    593         return SCAN_MODE_NONE;
    594     }
    595 
    596     /**
    597      * Set the Bluetooth scan mode of the local Bluetooth adapter.
    598      * <p>The Bluetooth scan mode determines if the local adapter is
    599      * connectable and/or discoverable from remote Bluetooth devices.
    600      * <p>For privacy reasons, discoverable mode is automatically turned off
    601      * after <code>duration</code> seconds. For example, 120 seconds should be
    602      * enough for a remote device to initiate and complete its discovery
    603      * process.
    604      * <p>Valid scan mode values are:
    605      * {@link #SCAN_MODE_NONE},
    606      * {@link #SCAN_MODE_CONNECTABLE},
    607      * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
    608      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
    609      * will return false. After turning on Bluetooth,
    610      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
    611      * to get the updated value.
    612      * <p>Requires {@link android.Manifest.permission#WRITE_SECURE_SETTINGS}
    613      * <p>Applications cannot set the scan mode. They should use
    614      * <code>startActivityForResult(
    615      * BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE})
    616      * </code>instead.
    617      *
    618      * @param mode valid scan mode
    619      * @param duration time in seconds to apply scan mode, only used for
    620      *                 {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}
    621      * @return     true if the scan mode was set, false otherwise
    622      * @hide
    623      */
    624     public boolean setScanMode(int mode, int duration) {
    625         if (getState() != STATE_ON) return false;
    626         try {
    627             return mService.setScanMode(mode, duration);
    628         } catch (RemoteException e) {Log.e(TAG, "", e);}
    629         return false;
    630     }
    631 
    632     /** @hide */
    633     public boolean setScanMode(int mode) {
    634         if (getState() != STATE_ON) return false;
    635         return setScanMode(mode, 120);
    636     }
    637 
    638     /** @hide */
    639     public int getDiscoverableTimeout() {
    640         if (getState() != STATE_ON) return -1;
    641         try {
    642             return mService.getDiscoverableTimeout();
    643         } catch (RemoteException e) {Log.e(TAG, "", e);}
    644         return -1;
    645     }
    646 
    647     /** @hide */
    648     public void setDiscoverableTimeout(int timeout) {
    649         if (getState() != STATE_ON) return;
    650         try {
    651             mService.setDiscoverableTimeout(timeout);
    652         } catch (RemoteException e) {Log.e(TAG, "", e);}
    653     }
    654 
    655     /**
    656      * Start the remote device discovery process.
    657      * <p>The discovery process usually involves an inquiry scan of about 12
    658      * seconds, followed by a page scan of each new device to retrieve its
    659      * Bluetooth name.
    660      * <p>This is an asynchronous call, it will return immediately. Register
    661      * for {@link #ACTION_DISCOVERY_STARTED} and {@link
    662      * #ACTION_DISCOVERY_FINISHED} intents to determine exactly when the
    663      * discovery starts and completes. Register for {@link
    664      * BluetoothDevice#ACTION_FOUND} to be notified as remote Bluetooth devices
    665      * are found.
    666      * <p>Device discovery is a heavyweight procedure. New connections to
    667      * remote Bluetooth devices should not be attempted while discovery is in
    668      * progress, and existing connections will experience limited bandwidth
    669      * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
    670      * discovery. Discovery is not managed by the Activity,
    671      * but is run as a system service, so an application should always call
    672      * {@link BluetoothAdapter#cancelDiscovery()} even if it
    673      * did not directly request a discovery, just to be sure.
    674      * <p>Device discovery will only find remote devices that are currently
    675      * <i>discoverable</i> (inquiry scan enabled). Many Bluetooth devices are
    676      * not discoverable by default, and need to be entered into a special mode.
    677      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
    678      * will return false. After turning on Bluetooth,
    679      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
    680      * to get the updated value.
    681      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    682      *
    683      * @return true on success, false on error
    684      */
    685     public boolean startDiscovery() {
    686         if (getState() != STATE_ON) return false;
    687         try {
    688             return mService.startDiscovery();
    689         } catch (RemoteException e) {Log.e(TAG, "", e);}
    690         return false;
    691     }
    692 
    693     /**
    694      * Cancel the current device discovery process.
    695      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    696      * <p>Because discovery is a heavyweight procedure for the Bluetooth
    697      * adapter, this method should always be called before attempting to connect
    698      * to a remote device with {@link
    699      * android.bluetooth.BluetoothSocket#connect()}. Discovery is not managed by
    700      * the  Activity, but is run as a system service, so an application should
    701      * always call cancel discovery even if it did not directly request a
    702      * discovery, just to be sure.
    703      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
    704      * will return false. After turning on Bluetooth,
    705      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
    706      * to get the updated value.
    707      *
    708      * @return true on success, false on error
    709      */
    710     public boolean cancelDiscovery() {
    711         if (getState() != STATE_ON) return false;
    712         try {
    713             return mService.cancelDiscovery();
    714         } catch (RemoteException e) {Log.e(TAG, "", e);}
    715         return false;
    716     }
    717 
    718     /**
    719      * Return true if the local Bluetooth adapter is currently in the device
    720      * discovery process.
    721      * <p>Device discovery is a heavyweight procedure. New connections to
    722      * remote Bluetooth devices should not be attempted while discovery is in
    723      * progress, and existing connections will experience limited bandwidth
    724      * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
    725      * discovery.
    726      * <p>Applications can also register for {@link #ACTION_DISCOVERY_STARTED}
    727      * or {@link #ACTION_DISCOVERY_FINISHED} to be notified when discovery
    728      * starts or completes.
    729      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
    730      * will return false. After turning on Bluetooth,
    731      * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
    732      * to get the updated value.
    733      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
    734      *
    735      * @return true if discovering
    736      */
    737     public boolean isDiscovering() {
    738         if (getState() != STATE_ON) return false;
    739         try {
    740             return mService.isDiscovering();
    741         } catch (RemoteException e) {Log.e(TAG, "", e);}
    742         return false;
    743     }
    744 
    745     /**
    746      * Return the set of {@link BluetoothDevice} objects that are bonded
    747      * (paired) to the local adapter.
    748      * <p>If Bluetooth state is not {@link #STATE_ON}, this API
    749      * will return an empty set. 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 unmodifiable set of {@link BluetoothDevice}, or null on error
    755      */
    756     public Set<BluetoothDevice> getBondedDevices() {
    757         if (getState() != STATE_ON) {
    758             return toDeviceSet(new String[0]);
    759         }
    760         try {
    761             return toDeviceSet(mService.listBonds());
    762         } catch (RemoteException e) {Log.e(TAG, "", e);}
    763         return null;
    764     }
    765 
    766     /**
    767      * Get the current connection state of the local Bluetooth adapter.
    768      * This can be used to check whether the local Bluetooth adapter is connected
    769      * to any profile of any other remote Bluetooth Device.
    770      *
    771      * <p> Use this function along with {@link #ACTION_CONNECTION_STATE_CHANGED}
    772      * intent to get the connection state of the adapter.
    773      *
    774      * @return One of {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTED},
    775      * {@link #STATE_CONNECTING} or {@link #STATE_DISCONNECTED}
    776      *
    777      * @hide
    778      */
    779     public int getConnectionState() {
    780         if (getState() != STATE_ON) return BluetoothAdapter.STATE_DISCONNECTED;
    781         try {
    782             return mService.getAdapterConnectionState();
    783         } catch (RemoteException e) {Log.e(TAG, "getConnectionState:", e);}
    784         return BluetoothAdapter.STATE_DISCONNECTED;
    785     }
    786 
    787     /**
    788      * Get the current connection state of a profile.
    789      * This function can be used to check whether the local Bluetooth adapter
    790      * is connected to any remote device for a specific profile.
    791      * Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET},
    792      * {@link BluetoothProfile#A2DP}.
    793      *
    794      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
    795      *
    796      * <p> Return value can be one of
    797      * {@link BluetoothProfile#STATE_DISCONNECTED},
    798      * {@link BluetoothProfile#STATE_CONNECTING},
    799      * {@link BluetoothProfile#STATE_CONNECTED},
    800      * {@link BluetoothProfile#STATE_DISCONNECTING}
    801      */
    802     public int getProfileConnectionState(int profile) {
    803         if (getState() != STATE_ON) return BluetoothProfile.STATE_DISCONNECTED;
    804         try {
    805             return mService.getProfileConnectionState(profile);
    806         } catch (RemoteException e) {
    807             Log.e(TAG, "getProfileConnectionState:", e);
    808         }
    809         return BluetoothProfile.STATE_DISCONNECTED;
    810     }
    811 
    812     /**
    813     /**
    814      * Picks RFCOMM channels until none are left.
    815      * Avoids reserved channels.
    816      */
    817     private static class RfcommChannelPicker {
    818         private static final int[] RESERVED_RFCOMM_CHANNELS =  new int[] {
    819             10,  // HFAG
    820             11,  // HSAG
    821             12,  // OPUSH
    822             19,  // PBAP
    823         };
    824         private static LinkedList<Integer> sChannels;  // master list of non-reserved channels
    825         private static Random sRandom;
    826 
    827         private final LinkedList<Integer> mChannels;  // local list of channels left to try
    828 
    829         private final UUID mUuid;
    830 
    831         public RfcommChannelPicker(UUID uuid) {
    832             synchronized (RfcommChannelPicker.class) {
    833                 if (sChannels == null) {
    834                     // lazy initialization of non-reserved rfcomm channels
    835                     sChannels = new LinkedList<Integer>();
    836                     for (int i = 1; i <= BluetoothSocket.MAX_RFCOMM_CHANNEL; i++) {
    837                         sChannels.addLast(new Integer(i));
    838                     }
    839                     for (int reserved : RESERVED_RFCOMM_CHANNELS) {
    840                         sChannels.remove(new Integer(reserved));
    841                     }
    842                     sRandom = new Random();
    843                 }
    844                 mChannels = (LinkedList<Integer>)sChannels.clone();
    845             }
    846             mUuid = uuid;
    847         }
    848         /* Returns next random channel, or -1 if we're out */
    849         public int nextChannel() {
    850             if (mChannels.size() == 0) {
    851                 return -1;
    852             }
    853             return mChannels.remove(sRandom.nextInt(mChannels.size()));
    854         }
    855     }
    856 
    857     /**
    858      * Create a listening, secure RFCOMM Bluetooth socket.
    859      * <p>A remote device connecting to this socket will be authenticated and
    860      * communication on this socket will be encrypted.
    861      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
    862      * connections from a listening {@link BluetoothServerSocket}.
    863      * <p>Valid RFCOMM channels are in range 1 to 30.
    864      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
    865      * @param channel RFCOMM channel to listen on
    866      * @return a listening RFCOMM BluetoothServerSocket
    867      * @throws IOException on error, for example Bluetooth not available, or
    868      *                     insufficient permissions, or channel in use.
    869      * @hide
    870      */
    871     public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException {
    872         BluetoothServerSocket socket = new BluetoothServerSocket(
    873                 BluetoothSocket.TYPE_RFCOMM, true, true, channel);
    874         int errno = socket.mSocket.bindListen();
    875         if (errno != 0) {
    876             try {
    877                 socket.close();
    878             } catch (IOException e) {}
    879             socket.mSocket.throwErrnoNative(errno);
    880         }
    881         return socket;
    882     }
    883 
    884     /**
    885      * Create a listening, secure RFCOMM Bluetooth socket with Service Record.
    886      * <p>A remote device connecting to this socket will be authenticated and
    887      * communication on this socket will be encrypted.
    888      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
    889      * connections from a listening {@link BluetoothServerSocket}.
    890      * <p>The system will assign an unused RFCOMM channel to listen on.
    891      * <p>The system will also register a Service Discovery
    892      * Protocol (SDP) record with the local SDP server containing the specified
    893      * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
    894      * can use the same UUID to query our SDP server and discover which channel
    895      * to connect to. This SDP record will be removed when this socket is
    896      * closed, or if this application closes unexpectedly.
    897      * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
    898      * connect to this socket from another device using the same {@link UUID}.
    899      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
    900      * @param name service name for SDP record
    901      * @param uuid uuid for SDP record
    902      * @return a listening RFCOMM BluetoothServerSocket
    903      * @throws IOException on error, for example Bluetooth not available, or
    904      *                     insufficient permissions, or channel in use.
    905      */
    906     public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid)
    907             throws IOException {
    908         return createNewRfcommSocketAndRecord(name, uuid, true, true);
    909     }
    910 
    911     /**
    912      * Create a listening, insecure RFCOMM Bluetooth socket with Service Record.
    913      * <p>The link key is not required to be authenticated, i.e the communication may be
    914      * vulnerable to Man In the Middle attacks. For Bluetooth 2.1 devices,
    915      * the link will be encrypted, as encryption is mandartory.
    916      * For legacy devices (pre Bluetooth 2.1 devices) the link will not
    917      * be encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an
    918      * encrypted and authenticated communication channel is desired.
    919      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
    920      * connections from a listening {@link BluetoothServerSocket}.
    921      * <p>The system will assign an unused RFCOMM channel to listen on.
    922      * <p>The system will also register a Service Discovery
    923      * Protocol (SDP) record with the local SDP server containing the specified
    924      * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
    925      * can use the same UUID to query our SDP server and discover which channel
    926      * to connect to. This SDP record will be removed when this socket is
    927      * closed, or if this application closes unexpectedly.
    928      * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
    929      * connect to this socket from another device using the same {@link UUID}.
    930      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
    931      * @param name service name for SDP record
    932      * @param uuid uuid for SDP record
    933      * @return a listening RFCOMM BluetoothServerSocket
    934      * @throws IOException on error, for example Bluetooth not available, or
    935      *                     insufficient permissions, or channel in use.
    936      */
    937     public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)
    938             throws IOException {
    939         return createNewRfcommSocketAndRecord(name, uuid, false, false);
    940     }
    941 
    942      /**
    943      * Create a listening, encrypted,
    944      * RFCOMM Bluetooth socket with Service Record.
    945      * <p>The link will be encrypted, but the link key is not required to be authenticated
    946      * i.e the communication is vulnerable to Man In the Middle attacks. Use
    947      * {@link #listenUsingRfcommWithServiceRecord}, to ensure an authenticated link key.
    948      * <p> Use this socket if authentication of link key is not possible.
    949      * For example, for Bluetooth 2.1 devices, if any of the devices does not have
    950      * an input and output capability or just has the ability to display a numeric key,
    951      * a secure socket connection is not possible and this socket can be used.
    952      * Use {@link #listenUsingInsecureRfcommWithServiceRecord}, if encryption is not required.
    953      * For Bluetooth 2.1 devices, the link will be encrypted, as encryption is mandartory.
    954      * For more details, refer to the Security Model section 5.2 (vol 3) of
    955      * Bluetooth Core Specification version 2.1 + EDR.
    956      * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
    957      * connections from a listening {@link BluetoothServerSocket}.
    958      * <p>The system will assign an unused RFCOMM channel to listen on.
    959      * <p>The system will also register a Service Discovery
    960      * Protocol (SDP) record with the local SDP server containing the specified
    961      * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
    962      * can use the same UUID to query our SDP server and discover which channel
    963      * to connect to. This SDP record will be removed when this socket is
    964      * closed, or if this application closes unexpectedly.
    965      * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
    966      * connect to this socket from another device using the same {@link UUID}.
    967      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
    968      * @param name service name for SDP record
    969      * @param uuid uuid for SDP record
    970      * @return a listening RFCOMM BluetoothServerSocket
    971      * @throws IOException on error, for example Bluetooth not available, or
    972      *                     insufficient permissions, or channel in use.
    973      * @hide
    974      */
    975     public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(
    976             String name, UUID uuid) throws IOException {
    977         return createNewRfcommSocketAndRecord(name, uuid, false, true);
    978     }
    979 
    980     private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid,
    981             boolean auth, boolean encrypt) throws IOException {
    982         RfcommChannelPicker picker = new RfcommChannelPicker(uuid);
    983 
    984         BluetoothServerSocket socket;
    985         int channel;
    986         int errno;
    987         while (true) {
    988             channel = picker.nextChannel();
    989 
    990             if (channel == -1) {
    991                 throw new IOException("No available channels");
    992             }
    993 
    994             socket = new BluetoothServerSocket(
    995                     BluetoothSocket.TYPE_RFCOMM, auth, encrypt, channel);
    996             errno = socket.mSocket.bindListen();
    997             if (errno == 0) {
    998                 if (DBG) Log.d(TAG, "listening on RFCOMM channel " + channel);
    999                 break;  // success
   1000             } else if (errno == BluetoothSocket.EADDRINUSE) {
   1001                 if (DBG) Log.d(TAG, "RFCOMM channel " + channel + " in use");
   1002                 try {
   1003                     socket.close();
   1004                 } catch (IOException e) {}
   1005                 continue;  // try another channel
   1006             } else {
   1007                 try {
   1008                     socket.close();
   1009                 } catch (IOException e) {}
   1010                 socket.mSocket.throwErrnoNative(errno);  // Exception as a result of bindListen()
   1011             }
   1012         }
   1013 
   1014         int handle = -1;
   1015         try {
   1016             handle = mService.addRfcommServiceRecord(name, new ParcelUuid(uuid), channel,
   1017                     new Binder());
   1018         } catch (RemoteException e) {Log.e(TAG, "", e);}
   1019         if (handle == -1) {
   1020             try {
   1021                 socket.close();
   1022             } catch (IOException e) {}
   1023             throw new IOException("Not able to register SDP record for " + name);
   1024         }
   1025 
   1026         if (mServiceRecordHandler == null) {
   1027             mServiceRecordHandler = new Handler(Looper.getMainLooper()) {
   1028                     public void handleMessage(Message msg) {
   1029                         /* handle socket closing */
   1030                         int handle = msg.what;
   1031                         try {
   1032                             if (DBG) Log.d(TAG, "Removing service record " +
   1033                                            Integer.toHexString(handle));
   1034                             mService.removeServiceRecord(handle);
   1035                         } catch (RemoteException e) {Log.e(TAG, "", e);}
   1036                     }
   1037                 };
   1038         }
   1039         socket.setCloseHandler(mServiceRecordHandler, handle);
   1040         return socket;
   1041     }
   1042 
   1043 
   1044     /**
   1045      * Construct an unencrypted, unauthenticated, RFCOMM server socket.
   1046      * Call #accept to retrieve connections to this socket.
   1047      * @return An RFCOMM BluetoothServerSocket
   1048      * @throws IOException On error, for example Bluetooth not available, or
   1049      *                     insufficient permissions.
   1050      * @hide
   1051      */
   1052     public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException {
   1053         BluetoothServerSocket socket = new BluetoothServerSocket(
   1054                 BluetoothSocket.TYPE_RFCOMM, false, false, port);
   1055         int errno = socket.mSocket.bindListen();
   1056         if (errno != 0) {
   1057             try {
   1058                 socket.close();
   1059             } catch (IOException e) {}
   1060             socket.mSocket.throwErrnoNative(errno);
   1061         }
   1062         return socket;
   1063     }
   1064 
   1065      /**
   1066      * Construct an encrypted, RFCOMM server socket.
   1067      * Call #accept to retrieve connections to this socket.
   1068      * @return An RFCOMM BluetoothServerSocket
   1069      * @throws IOException On error, for example Bluetooth not available, or
   1070      *                     insufficient permissions.
   1071      * @hide
   1072      */
   1073     public BluetoothServerSocket listenUsingEncryptedRfcommOn(int port)
   1074             throws IOException {
   1075         BluetoothServerSocket socket = new BluetoothServerSocket(
   1076                 BluetoothSocket.TYPE_RFCOMM, false, true, port);
   1077         int errno = socket.mSocket.bindListen();
   1078         if (errno != 0) {
   1079             try {
   1080                 socket.close();
   1081             } catch (IOException e) {}
   1082             socket.mSocket.throwErrnoNative(errno);
   1083         }
   1084         return socket;
   1085     }
   1086 
   1087     /**
   1088      * Construct a SCO server socket.
   1089      * Call #accept to retrieve connections to this socket.
   1090      * @return A SCO BluetoothServerSocket
   1091      * @throws IOException On error, for example Bluetooth not available, or
   1092      *                     insufficient permissions.
   1093      * @hide
   1094      */
   1095     public static BluetoothServerSocket listenUsingScoOn() throws IOException {
   1096         BluetoothServerSocket socket = new BluetoothServerSocket(
   1097                 BluetoothSocket.TYPE_SCO, false, false, -1);
   1098         int errno = socket.mSocket.bindListen();
   1099         if (errno != 0) {
   1100             try {
   1101                 socket.close();
   1102             } catch (IOException e) {}
   1103             socket.mSocket.throwErrnoNative(errno);
   1104         }
   1105         return socket;
   1106     }
   1107 
   1108     /**
   1109      * Read the local Out of Band Pairing Data
   1110      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
   1111      *
   1112      * @return Pair<byte[], byte[]> of Hash and Randomizer
   1113      *
   1114      * @hide
   1115      */
   1116     public Pair<byte[], byte[]> readOutOfBandData() {
   1117         if (getState() != STATE_ON) return null;
   1118         try {
   1119             byte[] hash;
   1120             byte[] randomizer;
   1121 
   1122             byte[] ret = mService.readOutOfBandData();
   1123 
   1124             if (ret  == null || ret.length != 32) return null;
   1125 
   1126             hash = Arrays.copyOfRange(ret, 0, 16);
   1127             randomizer = Arrays.copyOfRange(ret, 16, 32);
   1128 
   1129             if (DBG) {
   1130                 Log.d(TAG, "readOutOfBandData:" + Arrays.toString(hash) +
   1131                   ":" + Arrays.toString(randomizer));
   1132             }
   1133             return new Pair<byte[], byte[]>(hash, randomizer);
   1134 
   1135         } catch (RemoteException e) {Log.e(TAG, "", e);}
   1136         return null;
   1137     }
   1138 
   1139     /**
   1140      * Get the profile proxy object associated with the profile.
   1141      *
   1142      * <p>Profile can be one of {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET} or
   1143      * {@link BluetoothProfile#A2DP}. Clients must implements
   1144      * {@link BluetoothProfile.ServiceListener} to get notified of
   1145      * the connection status and to get the proxy object.
   1146      *
   1147      * @param context Context of the application
   1148      * @param listener The service Listener for connection callbacks.
   1149      * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEALTH},
   1150      *                {@link BluetoothProfile#HEADSET} or {@link BluetoothProfile#A2DP}.
   1151      * @return true on success, false on error
   1152      */
   1153     public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,
   1154                                    int profile) {
   1155         if (context == null || listener == null) return false;
   1156 
   1157         if (profile == BluetoothProfile.HEADSET) {
   1158             BluetoothHeadset headset = new BluetoothHeadset(context, listener);
   1159             return true;
   1160         } else if (profile == BluetoothProfile.A2DP) {
   1161             BluetoothA2dp a2dp = new BluetoothA2dp(context, listener);
   1162             return true;
   1163         } else if (profile == BluetoothProfile.INPUT_DEVICE) {
   1164             BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener);
   1165             return true;
   1166         } else if (profile == BluetoothProfile.PAN) {
   1167             BluetoothPan pan = new BluetoothPan(context, listener);
   1168             return true;
   1169         } else if (profile == BluetoothProfile.HEALTH) {
   1170             BluetoothHealth health = new BluetoothHealth(context, listener);
   1171             return true;
   1172         } else {
   1173             return false;
   1174         }
   1175     }
   1176 
   1177     /**
   1178      * Close the connection of the profile proxy to the Service.
   1179      *
   1180      * <p> Clients should call this when they are no longer using
   1181      * the proxy obtained from {@link #getProfileProxy}.
   1182      * Profile can be one of  {@link BluetoothProfile#HEALTH}, {@link BluetoothProfile#HEADSET} or
   1183      * {@link BluetoothProfile#A2DP}
   1184      *
   1185      * @param profile
   1186      * @param proxy Profile proxy object
   1187      */
   1188     public void closeProfileProxy(int profile, BluetoothProfile proxy) {
   1189         if (proxy == null) return;
   1190 
   1191         switch (profile) {
   1192             case BluetoothProfile.HEADSET:
   1193                 BluetoothHeadset headset = (BluetoothHeadset)proxy;
   1194                 headset.close();
   1195                 break;
   1196             case BluetoothProfile.A2DP:
   1197                 BluetoothA2dp a2dp = (BluetoothA2dp)proxy;
   1198                 a2dp.close();
   1199                 break;
   1200             case BluetoothProfile.INPUT_DEVICE:
   1201                 BluetoothInputDevice iDev = (BluetoothInputDevice)proxy;
   1202                 iDev.close();
   1203                 break;
   1204             case BluetoothProfile.PAN:
   1205                 BluetoothPan pan = (BluetoothPan)proxy;
   1206                 pan.close();
   1207                 break;
   1208             case BluetoothProfile.HEALTH:
   1209                 BluetoothHealth health = (BluetoothHealth)proxy;
   1210                 health.close();
   1211                 break;
   1212         }
   1213     }
   1214 
   1215     /**
   1216      * Enable control of the Bluetooth Adapter for a single application.
   1217      *
   1218      * <p>Some applications need to use Bluetooth for short periods of time to
   1219      * transfer data but don't want all the associated implications like
   1220      * automatic connection to headsets etc.
   1221      *
   1222      * <p> Multiple applications can call this. This is reference counted and
   1223      * Bluetooth disabled only when no one else is using it. There will be no UI
   1224      * shown to the user while bluetooth is being enabled. Any user action will
   1225      * override this call. For example, if user wants Bluetooth on and the last
   1226      * user of this API wanted to disable Bluetooth, Bluetooth will not be
   1227      * turned off.
   1228      *
   1229      * <p> This API is only meant to be used by internal applications. Third
   1230      * party applications but use {@link #enable} and {@link #disable} APIs.
   1231      *
   1232      * <p> If this API returns true, it means the callback will be called.
   1233      * The callback will be called with the current state of Bluetooth.
   1234      * If the state is not what was requested, an internal error would be the
   1235      * reason. If Bluetooth is already on and if this function is called to turn
   1236      * it on, the api will return true and a callback will be called.
   1237      *
   1238      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
   1239      *
   1240      * @param on True for on, false for off.
   1241      * @param callback The callback to notify changes to the state.
   1242      * @hide
   1243      */
   1244     public boolean changeApplicationBluetoothState(boolean on,
   1245                                                    BluetoothStateChangeCallback callback) {
   1246         if (callback == null) return false;
   1247 
   1248         try {
   1249             return mService.changeApplicationBluetoothState(on, new
   1250                     StateChangeCallbackWrapper(callback), new Binder());
   1251         } catch (RemoteException e) {
   1252             Log.e(TAG, "changeBluetoothState", e);
   1253         }
   1254         return false;
   1255     }
   1256 
   1257     /**
   1258      * @hide
   1259      */
   1260     public interface BluetoothStateChangeCallback {
   1261         public void onBluetoothStateChange(boolean on);
   1262     }
   1263 
   1264     /**
   1265      * @hide
   1266      */
   1267     public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub {
   1268         private BluetoothStateChangeCallback mCallback;
   1269 
   1270         StateChangeCallbackWrapper(BluetoothStateChangeCallback
   1271                 callback) {
   1272             mCallback = callback;
   1273         }
   1274 
   1275         @Override
   1276         public void onBluetoothStateChange(boolean on) {
   1277             mCallback.onBluetoothStateChange(on);
   1278         }
   1279     }
   1280 
   1281     private Set<BluetoothDevice> toDeviceSet(String[] addresses) {
   1282         Set<BluetoothDevice> devices = new HashSet<BluetoothDevice>(addresses.length);
   1283         for (int i = 0; i < addresses.length; i++) {
   1284             devices.add(getRemoteDevice(addresses[i]));
   1285         }
   1286         return Collections.unmodifiableSet(devices);
   1287     }
   1288 
   1289     /**
   1290      * Validate a Bluetooth address, such as "00:43:A8:23:10:F0"
   1291      * <p>Alphabetic characters must be uppercase to be valid.
   1292      *
   1293      * @param address Bluetooth address as string
   1294      * @return true if the address is valid, false otherwise
   1295      */
   1296     public static boolean checkBluetoothAddress(String address) {
   1297         if (address == null || address.length() != ADDRESS_LENGTH) {
   1298             return false;
   1299         }
   1300         for (int i = 0; i < ADDRESS_LENGTH; i++) {
   1301             char c = address.charAt(i);
   1302             switch (i % 3) {
   1303             case 0:
   1304             case 1:
   1305                 if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
   1306                     // hex character, OK
   1307                     break;
   1308                 }
   1309                 return false;
   1310             case 2:
   1311                 if (c == ':') {
   1312                     break;  // OK
   1313                 }
   1314                 return false;
   1315             }
   1316         }
   1317         return true;
   1318     }
   1319 }
   1320