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     /** 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 explicitly 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     /** The user will be prompted to accept or deny the OOB pairing request
    329      * @hide */
    330     public static final int PAIRING_VARIANT_OOB_CONSENT = 5;
    331     /**
    332      * Used as an extra field in {@link #ACTION_UUID} intents,
    333      * Contains the {@link android.os.ParcelUuid}s of the remote device which
    334      * is a parcelable version of {@link UUID}.
    335      * @hide
    336      */
    337     public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
    338 
    339     /**
    340      * Lazy initialization. Guaranteed final after first object constructed, or
    341      * getService() called.
    342      * TODO: Unify implementation of sService amongst BluetoothFoo API's
    343      */
    344     private static IBluetooth sService;
    345 
    346     private final String mAddress;
    347 
    348     /*package*/ static IBluetooth getService() {
    349         synchronized (BluetoothDevice.class) {
    350             if (sService == null) {
    351                 IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
    352                 if (b == null) {
    353                     throw new RuntimeException("Bluetooth service not available");
    354                 }
    355                 sService = IBluetooth.Stub.asInterface(b);
    356             }
    357         }
    358         return sService;
    359     }
    360 
    361     /**
    362      * Create a new BluetoothDevice
    363      * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB",
    364      * and is validated in this constructor.
    365      * @param address valid Bluetooth MAC address
    366      * @throws RuntimeException Bluetooth is not available on this platform
    367      * @throws IllegalArgumentException address is invalid
    368      * @hide
    369      */
    370     /*package*/ BluetoothDevice(String address) {
    371         getService();  // ensures sService is initialized
    372         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
    373             throw new IllegalArgumentException(address + " is not a valid Bluetooth address");
    374         }
    375 
    376         mAddress = address;
    377     }
    378 
    379     @Override
    380     public boolean equals(Object o) {
    381         if (o instanceof BluetoothDevice) {
    382             return mAddress.equals(((BluetoothDevice)o).getAddress());
    383         }
    384         return false;
    385     }
    386 
    387     @Override
    388     public int hashCode() {
    389         return mAddress.hashCode();
    390     }
    391 
    392     /**
    393      * Returns a string representation of this BluetoothDevice.
    394      * <p>Currently this is the Bluetooth hardware address, for example
    395      * "00:11:22:AA:BB:CC". However, you should always use {@link #getAddress}
    396      * if you explicitly require the Bluetooth hardware address in case the
    397      * {@link #toString} representation changes in the future.
    398      * @return string representation of this BluetoothDevice
    399      */
    400     @Override
    401     public String toString() {
    402         return mAddress;
    403     }
    404 
    405     public int describeContents() {
    406         return 0;
    407     }
    408 
    409     public static final Parcelable.Creator<BluetoothDevice> CREATOR =
    410             new Parcelable.Creator<BluetoothDevice>() {
    411         public BluetoothDevice createFromParcel(Parcel in) {
    412             return new BluetoothDevice(in.readString());
    413         }
    414         public BluetoothDevice[] newArray(int size) {
    415             return new BluetoothDevice[size];
    416         }
    417     };
    418 
    419     public void writeToParcel(Parcel out, int flags) {
    420         out.writeString(mAddress);
    421     }
    422 
    423     /**
    424      * Returns the hardware address of this BluetoothDevice.
    425      * <p> For example, "00:11:22:AA:BB:CC".
    426      * @return Bluetooth hardware address as string
    427      */
    428     public String getAddress() {
    429         return mAddress;
    430     }
    431 
    432     /**
    433      * Get the friendly Bluetooth name of the remote device.
    434      *
    435      * <p>The local adapter will automatically retrieve remote names when
    436      * performing a device scan, and will cache them. This method just returns
    437      * the name for this device from the cache.
    438      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
    439      *
    440      * @return the Bluetooth name, or null if there was a problem.
    441      */
    442     public String getName() {
    443         try {
    444             return sService.getRemoteName(mAddress);
    445         } catch (RemoteException e) {Log.e(TAG, "", e);}
    446         return null;
    447     }
    448 
    449     /**
    450      * Start the bonding (pairing) process with the remote device.
    451      * <p>This is an asynchronous call, it will return immediately. Register
    452      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
    453      * the bonding process completes, and its result.
    454      * <p>Android system services will handle the necessary user interactions
    455      * to confirm and complete the bonding process.
    456      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    457      *
    458      * @return false on immediate error, true if bonding will begin
    459      * @hide
    460      */
    461     public boolean createBond() {
    462         try {
    463             return sService.createBond(mAddress);
    464         } catch (RemoteException e) {Log.e(TAG, "", e);}
    465         return false;
    466     }
    467 
    468     /**
    469      * Start the bonding (pairing) process with the remote device using the
    470      * Out Of Band mechanism.
    471      *
    472      * <p>This is an asynchronous call, it will return immediately. Register
    473      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
    474      * the bonding process completes, and its result.
    475      *
    476      * <p>Android system services will handle the necessary user interactions
    477      * to confirm and complete the bonding process.
    478      *
    479      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    480      *
    481      * @param hash - Simple Secure pairing hash
    482      * @param randomizer - The random key obtained using OOB
    483      * @return false on immediate error, true if bonding will begin
    484      *
    485      * @hide
    486      */
    487     public boolean createBondOutOfBand(byte[] hash, byte[] randomizer) {
    488         try {
    489             return sService.createBondOutOfBand(mAddress, hash, randomizer);
    490         } catch (RemoteException e) {Log.e(TAG, "", e);}
    491         return false;
    492     }
    493 
    494     /**
    495      * Set the Out Of Band data for a remote device to be used later
    496      * in the pairing mechanism. Users can obtain this data through other
    497      * trusted channels
    498      *
    499      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    500      *
    501      * @param hash Simple Secure pairing hash
    502      * @param randomizer The random key obtained using OOB
    503      * @return false on error; true otherwise
    504      *
    505      * @hide
    506      */
    507     public boolean setDeviceOutOfBandData(byte[] hash, byte[] randomizer) {
    508       try {
    509         return sService.setDeviceOutOfBandData(mAddress, hash, randomizer);
    510       } catch (RemoteException e) {Log.e(TAG, "", e);}
    511       return false;
    512     }
    513 
    514     /**
    515      * Cancel an in-progress bonding request started with {@link #createBond}.
    516      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    517      *
    518      * @return true on success, false on error
    519      * @hide
    520      */
    521     public boolean cancelBondProcess() {
    522         try {
    523             return sService.cancelBondProcess(mAddress);
    524         } catch (RemoteException e) {Log.e(TAG, "", e);}
    525         return false;
    526     }
    527 
    528     /**
    529      * Remove bond (pairing) with the remote device.
    530      * <p>Delete the link key associated with the remote device, and
    531      * immediately terminate connections to that device that require
    532      * authentication and encryption.
    533      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    534      *
    535      * @return true on success, false on error
    536      * @hide
    537      */
    538     public boolean removeBond() {
    539         try {
    540             return sService.removeBond(mAddress);
    541         } catch (RemoteException e) {Log.e(TAG, "", e);}
    542         return false;
    543     }
    544 
    545     /**
    546      * Get the bond state of the remote device.
    547      * <p>Possible values for the bond state are:
    548      * {@link #BOND_NONE},
    549      * {@link #BOND_BONDING},
    550      * {@link #BOND_BONDED}.
    551      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
    552      *
    553      * @return the bond state
    554      */
    555     public int getBondState() {
    556         try {
    557             return sService.getBondState(mAddress);
    558         } catch (RemoteException e) {Log.e(TAG, "", e);}
    559         return BOND_NONE;
    560     }
    561 
    562     /**
    563      * Get the Bluetooth class of the remote device.
    564      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
    565      *
    566      * @return Bluetooth class object, or null on error
    567      */
    568     public BluetoothClass getBluetoothClass() {
    569         try {
    570             int classInt = sService.getRemoteClass(mAddress);
    571             if (classInt == BluetoothClass.ERROR) return null;
    572             return new BluetoothClass(classInt);
    573         } catch (RemoteException e) {Log.e(TAG, "", e);}
    574         return null;
    575     }
    576 
    577     /**
    578      * Get trust state of a remote device.
    579      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
    580      * @hide
    581      */
    582     public boolean getTrustState() {
    583         try {
    584             return sService.getTrustState(mAddress);
    585         } catch (RemoteException e) {
    586             Log.e(TAG, "", e);
    587         }
    588         return false;
    589     }
    590 
    591     /**
    592      * Set trust state for a remote device.
    593      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    594      * @param value the trust state value (true or false)
    595      * @hide
    596      */
    597     public boolean setTrust(boolean value) {
    598         try {
    599             return sService.setTrust(mAddress, value);
    600         } catch (RemoteException e) {
    601             Log.e(TAG, "", e);
    602         }
    603         return false;
    604     }
    605 
    606     /** @hide */
    607      public ParcelUuid[] getUuids() {
    608         try {
    609             return sService.getRemoteUuids(mAddress);
    610         } catch (RemoteException e) {Log.e(TAG, "", e);}
    611         return null;
    612     }
    613 
    614      /**
    615       *  Perform a SDP query on the remote device to get the UUIDs
    616       *  supported. This API is asynchronous and an Intent is sent,
    617       *  with the UUIDs supported by the remote end. If there is an error
    618       *  in getting the SDP records or if the process takes a long time,
    619       *  an Intent is sent with the UUIDs that is currently present in the
    620       *  cache. Clients should use the {@link #getUuids} to get UUIDs
    621       *  is SDP is not to be performed.
    622       *
    623       *  @return False if the sanity check fails, True if the process
    624       *               of initiating an ACL connection to the remote device
    625       *               was started.
    626       *  @hide
    627       */
    628      public boolean fetchUuidsWithSdp() {
    629         try {
    630             return sService.fetchRemoteUuids(mAddress, null, null);
    631         } catch (RemoteException e) {Log.e(TAG, "", e);}
    632         return false;
    633     }
    634 
    635     /** @hide */
    636     public int getServiceChannel(ParcelUuid uuid) {
    637          try {
    638              return sService.getRemoteServiceChannel(mAddress, uuid);
    639          } catch (RemoteException e) {Log.e(TAG, "", e);}
    640          return BluetoothDevice.ERROR;
    641     }
    642 
    643     /** @hide */
    644     public boolean setPin(byte[] pin) {
    645         try {
    646             return sService.setPin(mAddress, pin);
    647         } catch (RemoteException e) {Log.e(TAG, "", e);}
    648         return false;
    649     }
    650 
    651     /** @hide */
    652     public boolean setPasskey(int passkey) {
    653         try {
    654             return sService.setPasskey(mAddress, passkey);
    655         } catch (RemoteException e) {Log.e(TAG, "", e);}
    656         return false;
    657     }
    658 
    659     /** @hide */
    660     public boolean setPairingConfirmation(boolean confirm) {
    661         try {
    662             return sService.setPairingConfirmation(mAddress, confirm);
    663         } catch (RemoteException e) {Log.e(TAG, "", e);}
    664         return false;
    665     }
    666 
    667     /** @hide */
    668     public boolean setRemoteOutOfBandData() {
    669         try {
    670           return sService.setRemoteOutOfBandData(mAddress);
    671       } catch (RemoteException e) {Log.e(TAG, "", e);}
    672       return false;
    673     }
    674 
    675     /** @hide */
    676     public boolean cancelPairingUserInput() {
    677         try {
    678             return sService.cancelPairingUserInput(mAddress);
    679         } catch (RemoteException e) {Log.e(TAG, "", e);}
    680         return false;
    681     }
    682 
    683     /** @hide */
    684     public boolean isBluetoothDock() {
    685         try {
    686             return sService.isBluetoothDock(mAddress);
    687         } catch (RemoteException e) {Log.e(TAG, "", e);}
    688         return false;
    689     }
    690 
    691     /**
    692      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
    693      * outgoing connection to this remote device on given channel.
    694      * <p>The remote device will be authenticated and communication on this
    695      * socket will be encrypted.
    696      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
    697      * connection.
    698      * <p>Valid RFCOMM channels are in range 1 to 30.
    699      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
    700      *
    701      * @param channel RFCOMM channel to connect to
    702      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
    703      * @throws IOException on error, for example Bluetooth not available, or
    704      *                     insufficient permissions
    705      * @hide
    706      */
    707     public BluetoothSocket createRfcommSocket(int channel) throws IOException {
    708         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel,
    709                 null);
    710     }
    711 
    712     /**
    713      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
    714      * outgoing connection to this remote device using SDP lookup of uuid.
    715      * <p>This is designed to be used with {@link
    716      * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer
    717      * Bluetooth applications.
    718      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
    719      * connection. This will also perform an SDP lookup of the given uuid to
    720      * determine which channel to connect to.
    721      * <p>The remote device will be authenticated and communication on this
    722      * socket will be encrypted.
    723      * <p>Hint: If you are connecting to a Bluetooth serial board then try
    724      * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
    725      * However if you are connecting to an Android peer then please generate
    726      * your own unique UUID.
    727      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
    728      *
    729      * @param uuid service record uuid to lookup RFCOMM channel
    730      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
    731      * @throws IOException on error, for example Bluetooth not available, or
    732      *                     insufficient permissions
    733      */
    734     public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {
    735         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1,
    736                 new ParcelUuid(uuid));
    737     }
    738 
    739     /**
    740      * Construct an insecure RFCOMM socket ready to start an outgoing
    741      * connection.
    742      * Call #connect on the returned #BluetoothSocket to begin the connection.
    743      * The remote device will not be authenticated and communication on this
    744      * socket will not be encrypted.
    745      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
    746      *
    747      * @param port    remote port
    748      * @return An RFCOMM BluetoothSocket
    749      * @throws IOException On error, for example Bluetooth not available, or
    750      *                     insufficient permissions.
    751      * @hide
    752      */
    753     public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
    754         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port,
    755                 null);
    756     }
    757 
    758     /**
    759      * Construct a SCO socket ready to start an outgoing connection.
    760      * Call #connect on the returned #BluetoothSocket to begin the connection.
    761      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
    762      *
    763      * @return a SCO BluetoothSocket
    764      * @throws IOException on error, for example Bluetooth not available, or
    765      *                     insufficient permissions.
    766      * @hide
    767      */
    768     public BluetoothSocket createScoSocket() throws IOException {
    769         return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null);
    770     }
    771 
    772     /**
    773      * Check that a pin is valid and convert to byte array.
    774      *
    775      * Bluetooth pin's are 1 to 16 bytes of UTF-8 characters.
    776      * @param pin pin as java String
    777      * @return the pin code as a UTF-8 byte array, or null if it is an invalid
    778      *         Bluetooth pin.
    779      * @hide
    780      */
    781     public static byte[] convertPinToBytes(String pin) {
    782         if (pin == null) {
    783             return null;
    784         }
    785         byte[] pinBytes;
    786         try {
    787             pinBytes = pin.getBytes("UTF-8");
    788         } catch (UnsupportedEncodingException uee) {
    789             Log.e(TAG, "UTF-8 not supported?!?");  // this should not happen
    790             return null;
    791         }
    792         if (pinBytes.length <= 0 || pinBytes.length > 16) {
    793             return null;
    794         }
    795         return pinBytes;
    796     }
    797 
    798 }
    799