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.os.IBinder;
     22 import android.os.Parcel;
     23 import android.os.Parcelable;
     24 import android.os.ParcelUuid;
     25 import android.os.RemoteException;
     26 import android.os.ServiceManager;
     27 import android.util.Log;
     28 
     29 import java.io.IOException;
     30 import java.io.UnsupportedEncodingException;
     31 import java.util.UUID;
     32 
     33 /**
     34  * Represents a remote Bluetooth device. A {@link BluetoothDevice} lets you
     35  * create a connection with the repective device or query information about
     36  * it, such as the name, address, class, and bonding state.
     37  *
     38  * <p>This class is really just a thin wrapper for a Bluetooth hardware
     39  * address. Objects of this class are immutable. Operations on this class
     40  * are performed on the remote Bluetooth hardware address, using the
     41  * {@link BluetoothAdapter} that was used to create this {@link
     42  * BluetoothDevice}.
     43  *
     44  * <p>To get a {@link BluetoothDevice}, use
     45  * {@link BluetoothAdapter#getRemoteDevice(String)
     46  * BluetoothAdapter.getRemoteDevice(String)} to create one representing a device
     47  * of a known MAC address (which you can get through device discovery with
     48  * {@link BluetoothAdapter}) or get one from the set of bonded devices
     49  * returned by {@link BluetoothAdapter#getBondedDevices()
     50  * BluetoothAdapter.getBondedDevices()}. You can then open a
     51  * {@link BluetoothSocket} for communciation with the remote device, using
     52  * {@link #createRfcommSocketToServiceRecord(UUID)}.
     53  *
     54  * <p class="note"><strong>Note:</strong>
     55  * Requires the {@link android.Manifest.permission#BLUETOOTH} permission.
     56  *
     57  * {@see BluetoothAdapter}
     58  * {@see BluetoothSocket}
     59  */
     60 public final class BluetoothDevice implements Parcelable {
     61     private static final String TAG = "BluetoothDevice";
     62 
     63     /**
     64      * Sentinel error value for this class. Guaranteed to not equal any other
     65      * integer constant in this class. Provided as a convenience for functions
     66      * that require a sentinel error value, for example:
     67      * <p><code>Intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
     68      * BluetoothDevice.ERROR)</code>
     69      */
     70     public static final int ERROR = Integer.MIN_VALUE;
     71 
     72     /**
     73      * Broadcast Action: Remote device discovered.
     74      * <p>Sent when a remote device is found during discovery.
     75      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
     76      * #EXTRA_CLASS}. Can contain the extra fields {@link #EXTRA_NAME} and/or
     77      * {@link #EXTRA_RSSI} if they are available.
     78      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
     79      */
     80      // TODO: Change API to not broadcast RSSI if not available (incoming connection)
     81     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     82     public static final String ACTION_FOUND =
     83             "android.bluetooth.device.action.FOUND";
     84 
     85     /**
     86      * Broadcast Action: Remote device disappeared.
     87      * <p>Sent when a remote device that was found in the last discovery is not
     88      * found in the current discovery.
     89      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
     90      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
     91      * @hide
     92      */
     93     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     94     public static final String ACTION_DISAPPEARED =
     95             "android.bluetooth.device.action.DISAPPEARED";
     96 
     97     /**
     98      * Broadcast Action: Bluetooth class of a remote device has changed.
     99      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
    100      * #EXTRA_CLASS}.
    101      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    102      * @see {@link BluetoothClass}
    103      */
    104     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    105     public static final String ACTION_CLASS_CHANGED =
    106             "android.bluetooth.device.action.CLASS_CHANGED";
    107 
    108     /**
    109      * Broadcast Action: Indicates a low level (ACL) connection has been
    110      * established with a remote device.
    111      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
    112      * <p>ACL connections are managed automatically by the Android Bluetooth
    113      * stack.
    114      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    115      */
    116     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    117     public static final String ACTION_ACL_CONNECTED =
    118             "android.bluetooth.device.action.ACL_CONNECTED";
    119 
    120     /**
    121      * Broadcast Action: Indicates that a low level (ACL) disconnection has
    122      * been requested for a remote device, and it will soon be disconnected.
    123      * <p>This is useful for graceful disconnection. Applications should use
    124      * this intent as a hint to immediately terminate higher level connections
    125      * (RFCOMM, L2CAP, or profile connections) to the remote device.
    126      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
    127      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    128      */
    129     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    130     public static final String ACTION_ACL_DISCONNECT_REQUESTED =
    131             "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED";
    132 
    133     /**
    134      * Broadcast Action: Indicates a low level (ACL) disconnection from a
    135      * remote device.
    136      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
    137      * <p>ACL connections are managed automatically by the Android Bluetooth
    138      * stack.
    139      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    140      */
    141     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    142     public static final String ACTION_ACL_DISCONNECTED =
    143             "android.bluetooth.device.action.ACL_DISCONNECTED";
    144 
    145     /**
    146      * Broadcast Action: Indicates the friendly name of a remote device has
    147      * been retrieved for the first time, or changed since the last retrieval.
    148      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
    149      * #EXTRA_NAME}.
    150      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    151      */
    152     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    153     public static final String ACTION_NAME_CHANGED =
    154             "android.bluetooth.device.action.NAME_CHANGED";
    155 
    156     /**
    157      * Broadcast Action: Indicates a change in the bond state of a remote
    158      * device. For example, if a device is bonded (paired).
    159      * <p>Always contains the extra fields {@link #EXTRA_DEVICE}, {@link
    160      * #EXTRA_BOND_STATE} and {@link #EXTRA_PREVIOUS_BOND_STATE}.
    161      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    162      */
    163     // Note: When EXTRA_BOND_STATE is BOND_NONE then this will also
    164     // contain a hidden extra field EXTRA_REASON with the result code.
    165     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    166     public static final String ACTION_BOND_STATE_CHANGED =
    167             "android.bluetooth.device.action.BOND_STATE_CHANGED";
    168 
    169     /**
    170      * Used as a Parcelable {@link BluetoothDevice} extra field in every intent
    171      * broadcast by this class. It contains the {@link BluetoothDevice} that
    172      * the intent applies to.
    173      */
    174     public static final String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
    175 
    176     /**
    177      * Used as a String extra field in {@link #ACTION_NAME_CHANGED} and {@link
    178      * #ACTION_FOUND} intents. It contains the friendly Bluetooth name.
    179      */
    180     public static final String EXTRA_NAME = "android.bluetooth.device.extra.NAME";
    181 
    182     /**
    183      * Used as an optional short extra field in {@link #ACTION_FOUND} intents.
    184      * Contains the RSSI value of the remote device as reported by the
    185      * Bluetooth hardware.
    186      */
    187     public static final String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI";
    188 
    189     /**
    190      * Used as an Parcelable {@link BluetoothClass} extra field in {@link
    191      * #ACTION_FOUND} and {@link #ACTION_CLASS_CHANGED} intents.
    192      */
    193     public static final String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS";
    194 
    195     /**
    196      * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
    197      * Contains the bond state of the remote device.
    198      * <p>Possible values are:
    199      * {@link #BOND_NONE},
    200      * {@link #BOND_BONDING},
    201      * {@link #BOND_BONDED}.
    202       */
    203     public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE";
    204     /**
    205      * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
    206      * Contains the previous bond state of the remote device.
    207      * <p>Possible values are:
    208      * {@link #BOND_NONE},
    209      * {@link #BOND_BONDING},
    210      * {@link #BOND_BONDED}.
    211       */
    212     public static final String EXTRA_PREVIOUS_BOND_STATE =
    213             "android.bluetooth.device.extra.PREVIOUS_BOND_STATE";
    214     /**
    215      * Indicates the remote device is not bonded (paired).
    216      * <p>There is no shared link key with the remote device, so communication
    217      * (if it is allowed at all) will be unauthenticated and unencrypted.
    218      */
    219     public static final int BOND_NONE = 10;
    220     /**
    221      * Indicates bonding (pairing) is in progress with the remote device.
    222      */
    223     public static final int BOND_BONDING = 11;
    224     /**
    225      * Indicates the remote device is bonded (paired).
    226      * <p>A shared link keys exists locally for the remote device, so
    227      * communication can be authenticated and encrypted.
    228      * <p><i>Being bonded (paired) with a remote device does not necessarily
    229      * mean the device is currently connected. It just means that the ponding
    230      * procedure was compeleted at some earlier time, and the link key is still
    231      * stored locally, ready to use on the next connection.
    232      * </i>
    233      */
    234     public static final int BOND_BONDED = 12;
    235 
    236     /** @hide */
    237     public static final String EXTRA_REASON = "android.bluetooth.device.extra.REASON";
    238     /** @hide */
    239     public static final String EXTRA_PAIRING_VARIANT =
    240             "android.bluetooth.device.extra.PAIRING_VARIANT";
    241     /** @hide */
    242     public static final String EXTRA_PASSKEY = "android.bluetooth.device.extra.PASSKEY";
    243 
    244     /**
    245      * Broadcast Action: This intent is used to broadcast the {@link UUID}
    246      * wrapped as a {@link android.os.ParcelUuid} of the remote device after it
    247      * has been fetched. This intent is sent only when the UUIDs of the remote
    248      * device are requested to be fetched using Service Discovery Protocol
    249      * <p> Always contains the extra field {@link #EXTRA_DEVICE}
    250      * <p> Always contains the extra filed {@link #EXTRA_UUID}
    251      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    252      * @hide
    253      */
    254     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    255     public static final String ACTION_UUID =
    256             "android.bleutooth.device.action.UUID";
    257 
    258     /**
    259      * Broadcast Action: Indicates a failure to retrieve the name of a remote
    260      * device.
    261      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
    262      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    263      * @hide
    264      */
    265     //TODO: is this actually useful?
    266     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    267     public static final String ACTION_NAME_FAILED =
    268             "android.bluetooth.device.action.NAME_FAILED";
    269 
    270     /** @hide */
    271     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    272     public static final String ACTION_PAIRING_REQUEST =
    273             "android.bluetooth.device.action.PAIRING_REQUEST";
    274     /** @hide */
    275     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    276     public static final String ACTION_PAIRING_CANCEL =
    277             "android.bluetooth.device.action.PAIRING_CANCEL";
    278 
    279     /** A bond attempt succeeded
    280      * @hide */
    281     public static final int BOND_SUCCESS = 0;
    282     /** A bond attempt failed because pins did not match, or remote device did
    283      * not respond to pin request in time
    284      * @hide */
    285     public static final int UNBOND_REASON_AUTH_FAILED = 1;
    286     /** A bond attempt failed because the other side explicilty rejected
    287      * bonding
    288      * @hide */
    289     public static final int UNBOND_REASON_AUTH_REJECTED = 2;
    290     /** A bond attempt failed because we canceled the bonding process
    291      * @hide */
    292     public static final int UNBOND_REASON_AUTH_CANCELED = 3;
    293     /** A bond attempt failed because we could not contact the remote device
    294      * @hide */
    295     public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
    296     /** A bond attempt failed because a discovery is in progress
    297      * @hide */
    298     public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
    299     /** A bond attempt failed because of authentication timeout
    300      * @hide */
    301     public static final int UNBOND_REASON_AUTH_TIMEOUT = 6;
    302     /** A bond attempt failed because of repeated attempts
    303      * @hide */
    304     public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7;
    305     /** A bond attempt failed because we received an Authentication Cancel
    306      *  by remote end
    307      * @hide */
    308     public static final int UNBOND_REASON_REMOTE_AUTH_CANCELED = 8;
    309     /** An existing bond was explicitly revoked
    310      * @hide */
    311     public static final int UNBOND_REASON_REMOVED = 9;
    312 
    313     /** The user will be prompted to enter a pin
    314      * @hide */
    315     public static final int PAIRING_VARIANT_PIN = 0;
    316     /** The user will be prompted to enter a passkey
    317      * @hide */
    318     public static final int PAIRING_VARIANT_PASSKEY = 1;
    319     /** The user will be prompted to confirm the passkey displayed on the screen
    320      * @hide */
    321     public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2;
    322     /** The user will be prompted to accept or deny the incoming pairing request
    323      * @hide */
    324     public static final int PAIRING_VARIANT_CONSENT = 3;
    325     /** The user will be prompted to enter the passkey displayed on remote device
    326      * @hide */
    327     public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4;
    328 
    329     /**
    330      * Used as an extra field in {@link #ACTION_UUID} intents,
    331      * Contains the {@link android.os.ParcelUuid}s of the remote device which
    332      * is a parcelable version of {@link UUID}.
    333      * @hide
    334      */
    335     public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
    336 
    337     /**
    338      * Lazy initialization. Guaranteed final after first object constructed, or
    339      * getService() called.
    340      * TODO: Unify implementation of sService amongst BluetoothFoo API's
    341      */
    342     private static IBluetooth sService;
    343 
    344     private final String mAddress;
    345 
    346     /*package*/ static IBluetooth getService() {
    347         synchronized (BluetoothDevice.class) {
    348             if (sService == null) {
    349                 IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
    350                 if (b == null) {
    351                     throw new RuntimeException("Bluetooth service not available");
    352                 }
    353                 sService = IBluetooth.Stub.asInterface(b);
    354             }
    355         }
    356         return sService;
    357     }
    358 
    359     /**
    360      * Create a new BluetoothDevice
    361      * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB",
    362      * and is validated in this constructor.
    363      * @param address valid Bluetooth MAC address
    364      * @throws RuntimeException Bluetooth is not available on this platform
    365      * @throws IllegalArgumentException address is invalid
    366      * @hide
    367      */
    368     /*package*/ BluetoothDevice(String address) {
    369         getService();  // ensures sService is initialized
    370         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
    371             throw new IllegalArgumentException(address + " is not a valid Bluetooth address");
    372         }
    373 
    374         mAddress = address;
    375     }
    376 
    377     @Override
    378     public boolean equals(Object o) {
    379         if (o instanceof BluetoothDevice) {
    380             return mAddress.equals(((BluetoothDevice)o).getAddress());
    381         }
    382         return false;
    383     }
    384 
    385     @Override
    386     public int hashCode() {
    387         return mAddress.hashCode();
    388     }
    389 
    390     /**
    391      * Returns a string representation of this BluetoothDevice.
    392      * <p>Currently this is the Bluetooth hardware address, for example
    393      * "00:11:22:AA:BB:CC". However, you should always use {@link #getAddress}
    394      * if you explicitly require the Bluetooth hardware address in case the
    395      * {@link #toString} representation changes in the future.
    396      * @return string representation of this BluetoothDevice
    397      */
    398     @Override
    399     public String toString() {
    400         return mAddress;
    401     }
    402 
    403     public int describeContents() {
    404         return 0;
    405     }
    406 
    407     public static final Parcelable.Creator<BluetoothDevice> CREATOR =
    408             new Parcelable.Creator<BluetoothDevice>() {
    409         public BluetoothDevice createFromParcel(Parcel in) {
    410             return new BluetoothDevice(in.readString());
    411         }
    412         public BluetoothDevice[] newArray(int size) {
    413             return new BluetoothDevice[size];
    414         }
    415     };
    416 
    417     public void writeToParcel(Parcel out, int flags) {
    418         out.writeString(mAddress);
    419     }
    420 
    421     /**
    422      * Returns the hardware address of this BluetoothDevice.
    423      * <p> For example, "00:11:22:AA:BB:CC".
    424      * @return Bluetooth hardware address as string
    425      */
    426     public String getAddress() {
    427         return mAddress;
    428     }
    429 
    430     /**
    431      * Get the friendly Bluetooth name of the remote device.
    432      *
    433      * <p>The local adapter will automatically retrieve remote names when
    434      * performing a device scan, and will cache them. This method just returns
    435      * the name for this device from the cache.
    436      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
    437      *
    438      * @return the Bluetooth name, or null if there was a problem.
    439      */
    440     public String getName() {
    441         try {
    442             return sService.getRemoteName(mAddress);
    443         } catch (RemoteException e) {Log.e(TAG, "", e);}
    444         return null;
    445     }
    446 
    447     /**
    448      * Start the bonding (pairing) process with the remote device.
    449      * <p>This is an asynchronous call, it will return immediately. Register
    450      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
    451      * the bonding process completes, and its result.
    452      * <p>Android system services will handle the necessary user interactions
    453      * to confirm and complete the bonding process.
    454      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    455      *
    456      * @return false on immediate error, true if bonding will begin
    457      * @hide
    458      */
    459     public boolean createBond() {
    460         try {
    461             return sService.createBond(mAddress);
    462         } catch (RemoteException e) {Log.e(TAG, "", e);}
    463         return false;
    464     }
    465 
    466     /**
    467      * Cancel an in-progress bonding request started with {@link #createBond}.
    468      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    469      *
    470      * @return true on sucess, false on error
    471      * @hide
    472      */
    473     public boolean cancelBondProcess() {
    474         try {
    475             return sService.cancelBondProcess(mAddress);
    476         } catch (RemoteException e) {Log.e(TAG, "", e);}
    477         return false;
    478     }
    479 
    480     /**
    481      * Remove bond (pairing) with the remote device.
    482      * <p>Delete the link key associated with the remote device, and
    483      * immediately terminate connections to that device that require
    484      * authentication and encryption.
    485      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    486      *
    487      * @return true on sucess, false on error
    488      * @hide
    489      */
    490     public boolean removeBond() {
    491         try {
    492             return sService.removeBond(mAddress);
    493         } catch (RemoteException e) {Log.e(TAG, "", e);}
    494         return false;
    495     }
    496 
    497     /**
    498      * Get the bond state of the remote device.
    499      * <p>Possible values for the bond state are:
    500      * {@link #BOND_NONE},
    501      * {@link #BOND_BONDING},
    502      * {@link #BOND_BONDED}.
    503      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
    504      *
    505      * @return the bond state
    506      */
    507     public int getBondState() {
    508         try {
    509             return sService.getBondState(mAddress);
    510         } catch (RemoteException e) {Log.e(TAG, "", e);}
    511         return BOND_NONE;
    512     }
    513 
    514     /**
    515      * Get the Bluetooth class of the remote device.
    516      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
    517      *
    518      * @return Bluetooth class object, or null on error
    519      */
    520     public BluetoothClass getBluetoothClass() {
    521         try {
    522             int classInt = sService.getRemoteClass(mAddress);
    523             if (classInt == BluetoothClass.ERROR) return null;
    524             return new BluetoothClass(classInt);
    525         } catch (RemoteException e) {Log.e(TAG, "", e);}
    526         return null;
    527     }
    528 
    529     /**
    530      * Get trust state of a remote device.
    531      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
    532      * @hide
    533      */
    534     public boolean getTrustState() {
    535         try {
    536             return sService.getTrustState(mAddress);
    537         } catch (RemoteException e) {
    538             Log.e(TAG, "", e);
    539         }
    540         return false;
    541     }
    542 
    543     /**
    544      * Set trust state for a remote device.
    545      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    546      * @param value the trust state value (true or false)
    547      * @hide
    548      */
    549     public boolean setTrust(boolean value) {
    550         try {
    551             return sService.setTrust(mAddress, value);
    552         } catch (RemoteException e) {
    553             Log.e(TAG, "", e);
    554         }
    555         return false;
    556     }
    557 
    558     /** @hide */
    559      public ParcelUuid[] getUuids() {
    560         try {
    561             return sService.getRemoteUuids(mAddress);
    562         } catch (RemoteException e) {Log.e(TAG, "", e);}
    563         return null;
    564     }
    565 
    566      /**
    567       *  Perform a SDP query on the remote device to get the UUIDs
    568       *  supported. This API is asynchronous and an Intent is sent,
    569       *  with the UUIDs supported by the remote end. If there is an error
    570       *  in getting the SDP records or if the process takes a long time,
    571       *  an Intent is sent with the UUIDs that is currently present in the
    572       *  cache. Clients should use the {@link getUuids} to get UUIDs
    573       *  is SDP is not to be performed.
    574       *
    575       *  @return False if the sanity check fails, True if the process
    576       *               of initiating an ACL connection to the remote device
    577       *               was started.
    578       *  @hide
    579       */
    580      public boolean fetchUuidsWithSdp() {
    581         try {
    582             return sService.fetchRemoteUuids(mAddress, null, null);
    583         } catch (RemoteException e) {Log.e(TAG, "", e);}
    584         return false;
    585     }
    586 
    587     /** @hide */
    588     public int getServiceChannel(ParcelUuid uuid) {
    589          try {
    590              return sService.getRemoteServiceChannel(mAddress, uuid);
    591          } catch (RemoteException e) {Log.e(TAG, "", e);}
    592          return BluetoothDevice.ERROR;
    593     }
    594 
    595     /** @hide */
    596     public boolean setPin(byte[] pin) {
    597         try {
    598             return sService.setPin(mAddress, pin);
    599         } catch (RemoteException e) {Log.e(TAG, "", e);}
    600         return false;
    601     }
    602 
    603     /** @hide */
    604     public boolean setPasskey(int passkey) {
    605         try {
    606             return sService.setPasskey(mAddress, passkey);
    607         } catch (RemoteException e) {Log.e(TAG, "", e);}
    608         return false;
    609     }
    610 
    611     /** @hide */
    612     public boolean setPairingConfirmation(boolean confirm) {
    613         try {
    614             return sService.setPairingConfirmation(mAddress, confirm);
    615         } catch (RemoteException e) {Log.e(TAG, "", e);}
    616         return false;
    617     }
    618 
    619     /** @hide */
    620     public boolean cancelPairingUserInput() {
    621         try {
    622             return sService.cancelPairingUserInput(mAddress);
    623         } catch (RemoteException e) {Log.e(TAG, "", e);}
    624         return false;
    625     }
    626 
    627     /** @hide */
    628     public boolean isBluetoothDock() {
    629         try {
    630             return sService.isBluetoothDock(mAddress);
    631         } catch (RemoteException e) {Log.e(TAG, "", e);}
    632         return false;
    633     }
    634 
    635     /**
    636      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
    637      * outgoing connection to this remote device on given channel.
    638      * <p>The remote device will be authenticated and communication on this
    639      * socket will be encrypted.
    640      * <p>Use {@link BluetoothSocket#connect} to intiate the outgoing
    641      * connection.
    642      * <p>Valid RFCOMM channels are in range 1 to 30.
    643      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
    644      *
    645      * @param channel RFCOMM channel to connect to
    646      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
    647      * @throws IOException on error, for example Bluetooth not available, or
    648      *                     insufficient permissions
    649      * @hide
    650      */
    651     public BluetoothSocket createRfcommSocket(int channel) throws IOException {
    652         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel,
    653                 null);
    654     }
    655 
    656     /**
    657      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
    658      * outgoing connection to this remote device using SDP lookup of uuid.
    659      * <p>This is designed to be used with {@link
    660      * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer
    661      * Bluetooth applications.
    662      * <p>Use {@link BluetoothSocket#connect} to intiate the outgoing
    663      * connection. This will also perform an SDP lookup of the given uuid to
    664      * determine which channel to connect to.
    665      * <p>The remote device will be authenticated and communication on this
    666      * socket will be encrypted.
    667      * <p>Hint: If you are connecting to a Bluetooth serial board then try
    668      * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
    669      * However if you are connecting to an Android peer then please generate
    670      * your own unique UUID.
    671      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
    672      *
    673      * @param uuid service record uuid to lookup RFCOMM channel
    674      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
    675      * @throws IOException on error, for example Bluetooth not available, or
    676      *                     insufficient permissions
    677      */
    678     public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {
    679         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1,
    680                 new ParcelUuid(uuid));
    681     }
    682 
    683     /**
    684      * Construct an insecure RFCOMM socket ready to start an outgoing
    685      * connection.
    686      * Call #connect on the returned #BluetoothSocket to begin the connection.
    687      * The remote device will not be authenticated and communication on this
    688      * socket will not be encrypted.
    689      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
    690      *
    691      * @param port    remote port
    692      * @return An RFCOMM BluetoothSocket
    693      * @throws IOException On error, for example Bluetooth not available, or
    694      *                     insufficient permissions.
    695      * @hide
    696      */
    697     public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
    698         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port,
    699                 null);
    700     }
    701 
    702     /**
    703      * Construct a SCO socket ready to start an outgoing connection.
    704      * Call #connect on the returned #BluetoothSocket to begin the connection.
    705      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
    706      *
    707      * @return a SCO BluetoothSocket
    708      * @throws IOException on error, for example Bluetooth not available, or
    709      *                     insufficient permissions.
    710      * @hide
    711      */
    712     public BluetoothSocket createScoSocket() throws IOException {
    713         return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null);
    714     }
    715 
    716     /**
    717      * Check that a pin is valid and convert to byte array.
    718      *
    719      * Bluetooth pin's are 1 to 16 bytes of UTF8 characters.
    720      * @param pin pin as java String
    721      * @return the pin code as a UTF8 byte array, or null if it is an invalid
    722      *         Bluetooth pin.
    723      * @hide
    724      */
    725     public static byte[] convertPinToBytes(String pin) {
    726         if (pin == null) {
    727             return null;
    728         }
    729         byte[] pinBytes;
    730         try {
    731             pinBytes = pin.getBytes("UTF8");
    732         } catch (UnsupportedEncodingException uee) {
    733             Log.e(TAG, "UTF8 not supported?!?");  // this should not happen
    734             return null;
    735         }
    736         if (pinBytes.length <= 0 || pinBytes.length > 16) {
    737             return null;
    738         }
    739         return pinBytes;
    740     }
    741 
    742 }
    743