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 respective 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 communication 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 pending
    230      * procedure was completed 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     /** @hide */
    280     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    281     public static final String ACTION_CONNECTION_ACCESS_REQUEST =
    282             "android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST";
    283 
    284     /** @hide */
    285     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    286     public static final String ACTION_CONNECTION_ACCESS_REPLY =
    287             "android.bluetooth.device.action.CONNECTION_ACCESS_REPLY";
    288 
    289     /** @hide */
    290     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    291     public static final String ACTION_CONNECTION_ACCESS_CANCEL =
    292             "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL";
    293     /**
    294      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intent.
    295      * @hide
    296      */
    297     public static final String EXTRA_CONNECTION_ACCESS_RESULT =
    298         "android.bluetooth.device.extra.CONNECTION_ACCESS_RESULT";
    299 
    300     /**@hide*/
    301     public static final int CONNECTION_ACCESS_YES = 1;
    302 
    303     /**@hide*/
    304     public static final int CONNECTION_ACCESS_NO = 2;
    305 
    306     /** A bond attempt succeeded
    307      * @hide */
    308     public static final int BOND_SUCCESS = 0;
    309     /** A bond attempt failed because pins did not match, or remote device did
    310      * not respond to pin request in time
    311      * @hide */
    312     public static final int UNBOND_REASON_AUTH_FAILED = 1;
    313     /** A bond attempt failed because the other side explicitly rejected
    314      * bonding
    315      * @hide */
    316     public static final int UNBOND_REASON_AUTH_REJECTED = 2;
    317     /** A bond attempt failed because we canceled the bonding process
    318      * @hide */
    319     public static final int UNBOND_REASON_AUTH_CANCELED = 3;
    320     /** A bond attempt failed because we could not contact the remote device
    321      * @hide */
    322     public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
    323     /** A bond attempt failed because a discovery is in progress
    324      * @hide */
    325     public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
    326     /** A bond attempt failed because of authentication timeout
    327      * @hide */
    328     public static final int UNBOND_REASON_AUTH_TIMEOUT = 6;
    329     /** A bond attempt failed because of repeated attempts
    330      * @hide */
    331     public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7;
    332     /** A bond attempt failed because we received an Authentication Cancel
    333      *  by remote end
    334      * @hide */
    335     public static final int UNBOND_REASON_REMOTE_AUTH_CANCELED = 8;
    336     /** An existing bond was explicitly revoked
    337      * @hide */
    338     public static final int UNBOND_REASON_REMOVED = 9;
    339 
    340     /** The user will be prompted to enter a pin
    341      * @hide */
    342     public static final int PAIRING_VARIANT_PIN = 0;
    343     /** The user will be prompted to enter a passkey
    344      * @hide */
    345     public static final int PAIRING_VARIANT_PASSKEY = 1;
    346     /** The user will be prompted to confirm the passkey displayed on the screen
    347      * @hide */
    348     public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2;
    349     /** The user will be prompted to accept or deny the incoming pairing request
    350      * @hide */
    351     public static final int PAIRING_VARIANT_CONSENT = 3;
    352     /** The user will be prompted to enter the passkey displayed on remote device
    353      * @hide */
    354     public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4;
    355     /** The user will be prompted to accept or deny the OOB pairing request
    356      * @hide */
    357     public static final int PAIRING_VARIANT_OOB_CONSENT = 5;
    358     /**
    359      * Used as an extra field in {@link #ACTION_UUID} intents,
    360      * Contains the {@link android.os.ParcelUuid}s of the remote device which
    361      * is a parcelable version of {@link UUID}.
    362      * @hide
    363      */
    364     public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
    365 
    366     /**
    367      * Lazy initialization. Guaranteed final after first object constructed, or
    368      * getService() called.
    369      * TODO: Unify implementation of sService amongst BluetoothFoo API's
    370      */
    371     private static IBluetooth sService;
    372 
    373     private final String mAddress;
    374 
    375     /*package*/ static IBluetooth getService() {
    376         synchronized (BluetoothDevice.class) {
    377             if (sService == null) {
    378                 IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
    379                 if (b == null) {
    380                     throw new RuntimeException("Bluetooth service not available");
    381                 }
    382                 sService = IBluetooth.Stub.asInterface(b);
    383             }
    384         }
    385         return sService;
    386     }
    387 
    388     /**
    389      * Create a new BluetoothDevice
    390      * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB",
    391      * and is validated in this constructor.
    392      * @param address valid Bluetooth MAC address
    393      * @throws RuntimeException Bluetooth is not available on this platform
    394      * @throws IllegalArgumentException address is invalid
    395      * @hide
    396      */
    397     /*package*/ BluetoothDevice(String address) {
    398         getService();  // ensures sService is initialized
    399         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
    400             throw new IllegalArgumentException(address + " is not a valid Bluetooth address");
    401         }
    402 
    403         mAddress = address;
    404     }
    405 
    406     @Override
    407     public boolean equals(Object o) {
    408         if (o instanceof BluetoothDevice) {
    409             return mAddress.equals(((BluetoothDevice)o).getAddress());
    410         }
    411         return false;
    412     }
    413 
    414     @Override
    415     public int hashCode() {
    416         return mAddress.hashCode();
    417     }
    418 
    419     /**
    420      * Returns a string representation of this BluetoothDevice.
    421      * <p>Currently this is the Bluetooth hardware address, for example
    422      * "00:11:22:AA:BB:CC". However, you should always use {@link #getAddress}
    423      * if you explicitly require the Bluetooth hardware address in case the
    424      * {@link #toString} representation changes in the future.
    425      * @return string representation of this BluetoothDevice
    426      */
    427     @Override
    428     public String toString() {
    429         return mAddress;
    430     }
    431 
    432     public int describeContents() {
    433         return 0;
    434     }
    435 
    436     public static final Parcelable.Creator<BluetoothDevice> CREATOR =
    437             new Parcelable.Creator<BluetoothDevice>() {
    438         public BluetoothDevice createFromParcel(Parcel in) {
    439             return new BluetoothDevice(in.readString());
    440         }
    441         public BluetoothDevice[] newArray(int size) {
    442             return new BluetoothDevice[size];
    443         }
    444     };
    445 
    446     public void writeToParcel(Parcel out, int flags) {
    447         out.writeString(mAddress);
    448     }
    449 
    450     /**
    451      * Returns the hardware address of this BluetoothDevice.
    452      * <p> For example, "00:11:22:AA:BB:CC".
    453      * @return Bluetooth hardware address as string
    454      */
    455     public String getAddress() {
    456         return mAddress;
    457     }
    458 
    459     /**
    460      * Get the friendly Bluetooth name of the remote device.
    461      *
    462      * <p>The local adapter will automatically retrieve remote names when
    463      * performing a device scan, and will cache them. This method just returns
    464      * the name for this device from the cache.
    465      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
    466      *
    467      * @return the Bluetooth name, or null if there was a problem.
    468      */
    469     public String getName() {
    470         try {
    471             return sService.getRemoteName(mAddress);
    472         } catch (RemoteException e) {Log.e(TAG, "", e);}
    473         return null;
    474     }
    475 
    476     /**
    477      * Start the bonding (pairing) process with the remote device.
    478      * <p>This is an asynchronous call, it will return immediately. Register
    479      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
    480      * the bonding process completes, and its result.
    481      * <p>Android system services will handle the necessary user interactions
    482      * to confirm and complete the bonding process.
    483      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    484      *
    485      * @return false on immediate error, true if bonding will begin
    486      * @hide
    487      */
    488     public boolean createBond() {
    489         try {
    490             return sService.createBond(mAddress);
    491         } catch (RemoteException e) {Log.e(TAG, "", e);}
    492         return false;
    493     }
    494 
    495     /**
    496      * Start the bonding (pairing) process with the remote device using the
    497      * Out Of Band mechanism.
    498      *
    499      * <p>This is an asynchronous call, it will return immediately. Register
    500      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
    501      * the bonding process completes, and its result.
    502      *
    503      * <p>Android system services will handle the necessary user interactions
    504      * to confirm and complete the bonding process.
    505      *
    506      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    507      *
    508      * @param hash - Simple Secure pairing hash
    509      * @param randomizer - The random key obtained using OOB
    510      * @return false on immediate error, true if bonding will begin
    511      *
    512      * @hide
    513      */
    514     public boolean createBondOutOfBand(byte[] hash, byte[] randomizer) {
    515         try {
    516             return sService.createBondOutOfBand(mAddress, hash, randomizer);
    517         } catch (RemoteException e) {Log.e(TAG, "", e);}
    518         return false;
    519     }
    520 
    521     /**
    522      * Set the Out Of Band data for a remote device to be used later
    523      * in the pairing mechanism. Users can obtain this data through other
    524      * trusted channels
    525      *
    526      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    527      *
    528      * @param hash Simple Secure pairing hash
    529      * @param randomizer The random key obtained using OOB
    530      * @return false on error; true otherwise
    531      *
    532      * @hide
    533      */
    534     public boolean setDeviceOutOfBandData(byte[] hash, byte[] randomizer) {
    535       try {
    536         return sService.setDeviceOutOfBandData(mAddress, hash, randomizer);
    537       } catch (RemoteException e) {Log.e(TAG, "", e);}
    538       return false;
    539     }
    540 
    541     /**
    542      * Cancel an in-progress bonding request started with {@link #createBond}.
    543      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    544      *
    545      * @return true on success, false on error
    546      * @hide
    547      */
    548     public boolean cancelBondProcess() {
    549         try {
    550             return sService.cancelBondProcess(mAddress);
    551         } catch (RemoteException e) {Log.e(TAG, "", e);}
    552         return false;
    553     }
    554 
    555     /**
    556      * Remove bond (pairing) with the remote device.
    557      * <p>Delete the link key associated with the remote device, and
    558      * immediately terminate connections to that device that require
    559      * authentication and encryption.
    560      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    561      *
    562      * @return true on success, false on error
    563      * @hide
    564      */
    565     public boolean removeBond() {
    566         try {
    567             return sService.removeBond(mAddress);
    568         } catch (RemoteException e) {Log.e(TAG, "", e);}
    569         return false;
    570     }
    571 
    572     /**
    573      * Get the bond state of the remote device.
    574      * <p>Possible values for the bond state are:
    575      * {@link #BOND_NONE},
    576      * {@link #BOND_BONDING},
    577      * {@link #BOND_BONDED}.
    578      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
    579      *
    580      * @return the bond state
    581      */
    582     public int getBondState() {
    583         try {
    584             return sService.getBondState(mAddress);
    585         } catch (RemoteException e) {Log.e(TAG, "", e);}
    586         return BOND_NONE;
    587     }
    588 
    589     /**
    590      * Get the Bluetooth class of the remote device.
    591      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
    592      *
    593      * @return Bluetooth class object, or null on error
    594      */
    595     public BluetoothClass getBluetoothClass() {
    596         try {
    597             int classInt = sService.getRemoteClass(mAddress);
    598             if (classInt == BluetoothClass.ERROR) return null;
    599             return new BluetoothClass(classInt);
    600         } catch (RemoteException e) {Log.e(TAG, "", e);}
    601         return null;
    602     }
    603 
    604     /**
    605      * Get trust state of a remote device.
    606      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
    607      * @hide
    608      */
    609     public boolean getTrustState() {
    610         try {
    611             return sService.getTrustState(mAddress);
    612         } catch (RemoteException e) {
    613             Log.e(TAG, "", e);
    614         }
    615         return false;
    616     }
    617 
    618     /**
    619      * Set trust state for a remote device.
    620      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    621      * @param value the trust state value (true or false)
    622      * @hide
    623      */
    624     public boolean setTrust(boolean value) {
    625         try {
    626             return sService.setTrust(mAddress, value);
    627         } catch (RemoteException e) {
    628             Log.e(TAG, "", e);
    629         }
    630         return false;
    631     }
    632 
    633     /** @hide */
    634      public ParcelUuid[] getUuids() {
    635         try {
    636             return sService.getRemoteUuids(mAddress);
    637         } catch (RemoteException e) {Log.e(TAG, "", e);}
    638         return null;
    639     }
    640 
    641      /**
    642       *  Perform a SDP query on the remote device to get the UUIDs
    643       *  supported. This API is asynchronous and an Intent is sent,
    644       *  with the UUIDs supported by the remote end. If there is an error
    645       *  in getting the SDP records or if the process takes a long time,
    646       *  an Intent is sent with the UUIDs that is currently present in the
    647       *  cache. Clients should use the {@link #getUuids} to get UUIDs
    648       *  is SDP is not to be performed.
    649       *
    650       *  @return False if the sanity check fails, True if the process
    651       *               of initiating an ACL connection to the remote device
    652       *               was started.
    653       *  @hide
    654       */
    655      public boolean fetchUuidsWithSdp() {
    656         try {
    657             return sService.fetchRemoteUuids(mAddress, null, null);
    658         } catch (RemoteException e) {Log.e(TAG, "", e);}
    659         return false;
    660     }
    661 
    662     /** @hide */
    663     public int getServiceChannel(ParcelUuid uuid) {
    664          try {
    665              return sService.getRemoteServiceChannel(mAddress, uuid);
    666          } catch (RemoteException e) {Log.e(TAG, "", e);}
    667          return BluetoothDevice.ERROR;
    668     }
    669 
    670     /** @hide */
    671     public boolean setPin(byte[] pin) {
    672         try {
    673             return sService.setPin(mAddress, pin);
    674         } catch (RemoteException e) {Log.e(TAG, "", e);}
    675         return false;
    676     }
    677 
    678     /** @hide */
    679     public boolean setPasskey(int passkey) {
    680         try {
    681             return sService.setPasskey(mAddress, passkey);
    682         } catch (RemoteException e) {Log.e(TAG, "", e);}
    683         return false;
    684     }
    685 
    686     /** @hide */
    687     public boolean setPairingConfirmation(boolean confirm) {
    688         try {
    689             return sService.setPairingConfirmation(mAddress, confirm);
    690         } catch (RemoteException e) {Log.e(TAG, "", e);}
    691         return false;
    692     }
    693 
    694     /** @hide */
    695     public boolean setRemoteOutOfBandData() {
    696         try {
    697           return sService.setRemoteOutOfBandData(mAddress);
    698       } catch (RemoteException e) {Log.e(TAG, "", e);}
    699       return false;
    700     }
    701 
    702     /** @hide */
    703     public boolean cancelPairingUserInput() {
    704         try {
    705             return sService.cancelPairingUserInput(mAddress);
    706         } catch (RemoteException e) {Log.e(TAG, "", e);}
    707         return false;
    708     }
    709 
    710     /** @hide */
    711     public boolean isBluetoothDock() {
    712         try {
    713             return sService.isBluetoothDock(mAddress);
    714         } catch (RemoteException e) {Log.e(TAG, "", e);}
    715         return false;
    716     }
    717 
    718     /**
    719      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
    720      * outgoing connection to this remote device on given channel.
    721      * <p>The remote device will be authenticated and communication on this
    722      * socket will be encrypted.
    723      * <p> Use this socket only if an authenticated socket link is possible.
    724      * Authentication refers to the authentication of the link key to
    725      * prevent man-in-the-middle type of attacks.
    726      * For example, for Bluetooth 2.1 devices, if any of the devices does not
    727      * have an input and output capability or just has the ability to
    728      * display a numeric key, a secure socket connection is not possible.
    729      * In such a case, use {#link createInsecureRfcommSocket}.
    730      * For more details, refer to the Security Model section 5.2 (vol 3) of
    731      * Bluetooth Core Specification version 2.1 + EDR.
    732      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
    733      * connection.
    734      * <p>Valid RFCOMM channels are in range 1 to 30.
    735      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
    736      *
    737      * @param channel RFCOMM channel to connect to
    738      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
    739      * @throws IOException on error, for example Bluetooth not available, or
    740      *                     insufficient permissions
    741      * @hide
    742      */
    743     public BluetoothSocket createRfcommSocket(int channel) throws IOException {
    744         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel,
    745                 null);
    746     }
    747 
    748     /**
    749      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
    750      * outgoing connection to this remote device using SDP lookup of uuid.
    751      * <p>This is designed to be used with {@link
    752      * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer
    753      * Bluetooth applications.
    754      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
    755      * connection. This will also perform an SDP lookup of the given uuid to
    756      * determine which channel to connect to.
    757      * <p>The remote device will be authenticated and communication on this
    758      * socket will be encrypted.
    759      * <p> Use this socket only if an authenticated socket link is possible.
    760      * Authentication refers to the authentication of the link key to
    761      * prevent man-in-the-middle type of attacks.
    762      * For example, for Bluetooth 2.1 devices, if any of the devices does not
    763      * have an input and output capability or just has the ability to
    764      * display a numeric key, a secure socket connection is not possible.
    765      * In such a case, use {#link createInsecureRfcommSocketToServiceRecord}.
    766      * For more details, refer to the Security Model section 5.2 (vol 3) of
    767      * Bluetooth Core Specification version 2.1 + EDR.
    768      * <p>Hint: If you are connecting to a Bluetooth serial board then try
    769      * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
    770      * However if you are connecting to an Android peer then please generate
    771      * your own unique UUID.
    772          * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
    773      *
    774      * @param uuid service record uuid to lookup RFCOMM channel
    775      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
    776      * @throws IOException on error, for example Bluetooth not available, or
    777      *                     insufficient permissions
    778      */
    779     public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {
    780         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1,
    781                 new ParcelUuid(uuid));
    782     }
    783 
    784     /**
    785      * Create an RFCOMM {@link BluetoothSocket} socket ready to start an insecure
    786      * outgoing connection to this remote device using SDP lookup of uuid.
    787      * <p> The communication channel will not have an authenticated link key
    788      * i.e it will be subject to man-in-the-middle attacks. For Bluetooth 2.1
    789      * devices, the link key will be encrypted, as encryption is mandatory.
    790      * For legacy devices (pre Bluetooth 2.1 devices) the link key will
    791      * be not be encrypted. Use {@link #createRfcommSocketToServiceRecord} if an
    792      * encrypted and authenticated communication channel is desired.
    793      * <p>This is designed to be used with {@link
    794      * BluetoothAdapter#listenUsingInsecureRfcommWithServiceRecord} for peer-peer
    795      * Bluetooth applications.
    796      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
    797      * connection. This will also perform an SDP lookup of the given uuid to
    798      * determine which channel to connect to.
    799      * <p>The remote device will be authenticated and communication on this
    800      * socket will be encrypted.
    801      * <p>Hint: If you are connecting to a Bluetooth serial board then try
    802      * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
    803      * However if you are connecting to an Android peer then please generate
    804      * your own unique UUID.
    805      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
    806      *
    807      * @param uuid service record uuid to lookup RFCOMM channel
    808      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
    809      * @throws IOException on error, for example Bluetooth not available, or
    810      *                     insufficient permissions
    811      */
    812     public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException {
    813         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1,
    814                 new ParcelUuid(uuid));
    815     }
    816 
    817     /**
    818      * Construct an insecure RFCOMM socket ready to start an outgoing
    819      * connection.
    820      * Call #connect on the returned #BluetoothSocket to begin the connection.
    821      * The remote device will not be authenticated and communication on this
    822      * socket will not be encrypted.
    823      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
    824      *
    825      * @param port    remote port
    826      * @return An RFCOMM BluetoothSocket
    827      * @throws IOException On error, for example Bluetooth not available, or
    828      *                     insufficient permissions.
    829      * @hide
    830      */
    831     public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
    832         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port,
    833                 null);
    834     }
    835 
    836     /**
    837      * Construct a SCO socket ready to start an outgoing connection.
    838      * Call #connect on the returned #BluetoothSocket to begin the connection.
    839      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
    840      *
    841      * @return a SCO BluetoothSocket
    842      * @throws IOException on error, for example Bluetooth not available, or
    843      *                     insufficient permissions.
    844      * @hide
    845      */
    846     public BluetoothSocket createScoSocket() throws IOException {
    847         return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null);
    848     }
    849 
    850     /**
    851      * Check that a pin is valid and convert to byte array.
    852      *
    853      * Bluetooth pin's are 1 to 16 bytes of UTF-8 characters.
    854      * @param pin pin as java String
    855      * @return the pin code as a UTF-8 byte array, or null if it is an invalid
    856      *         Bluetooth pin.
    857      * @hide
    858      */
    859     public static byte[] convertPinToBytes(String pin) {
    860         if (pin == null) {
    861             return null;
    862         }
    863         byte[] pinBytes;
    864         try {
    865             pinBytes = pin.getBytes("UTF-8");
    866         } catch (UnsupportedEncodingException uee) {
    867             Log.e(TAG, "UTF-8 not supported?!?");  // this should not happen
    868             return null;
    869         }
    870         if (pinBytes.length <= 0 || pinBytes.length > 16) {
    871             return null;
    872         }
    873         return pinBytes;
    874     }
    875 
    876 }
    877