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  * <div class="special reference">
     58  * <h3>Developer Guides</h3>
     59  * <p>For more information about using Bluetooth, read the
     60  * <a href="{@docRoot}guide/topics/wireless/bluetooth.html">Bluetooth</a> developer guide.</p>
     61  * </div>
     62  *
     63  * {@see BluetoothAdapter}
     64  * {@see BluetoothSocket}
     65  */
     66 public final class BluetoothDevice implements Parcelable {
     67     private static final String TAG = "BluetoothDevice";
     68     private static final boolean DBG = false;
     69 
     70     /**
     71      * Sentinel error value for this class. Guaranteed to not equal any other
     72      * integer constant in this class. Provided as a convenience for functions
     73      * that require a sentinel error value, for example:
     74      * <p><code>Intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
     75      * BluetoothDevice.ERROR)</code>
     76      */
     77     public static final int ERROR = Integer.MIN_VALUE;
     78 
     79     /**
     80      * Broadcast Action: Remote device discovered.
     81      * <p>Sent when a remote device is found during discovery.
     82      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
     83      * #EXTRA_CLASS}. Can contain the extra fields {@link #EXTRA_NAME} and/or
     84      * {@link #EXTRA_RSSI} if they are available.
     85      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
     86      */
     87      // TODO: Change API to not broadcast RSSI if not available (incoming connection)
     88     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     89     public static final String ACTION_FOUND =
     90             "android.bluetooth.device.action.FOUND";
     91 
     92     /**
     93      * Broadcast Action: Remote device disappeared.
     94      * <p>Sent when a remote device that was found in the last discovery is not
     95      * found in the current discovery.
     96      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
     97      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
     98      * @hide
     99      */
    100     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    101     public static final String ACTION_DISAPPEARED =
    102             "android.bluetooth.device.action.DISAPPEARED";
    103 
    104     /**
    105      * Broadcast Action: Bluetooth class of a remote device has changed.
    106      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
    107      * #EXTRA_CLASS}.
    108      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    109      * @see {@link BluetoothClass}
    110      */
    111     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    112     public static final String ACTION_CLASS_CHANGED =
    113             "android.bluetooth.device.action.CLASS_CHANGED";
    114 
    115     /**
    116      * Broadcast Action: Indicates a low level (ACL) connection has been
    117      * established with a remote device.
    118      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
    119      * <p>ACL connections are managed automatically by the Android Bluetooth
    120      * stack.
    121      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    122      */
    123     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    124     public static final String ACTION_ACL_CONNECTED =
    125             "android.bluetooth.device.action.ACL_CONNECTED";
    126 
    127     /**
    128      * Broadcast Action: Indicates that a low level (ACL) disconnection has
    129      * been requested for a remote device, and it will soon be disconnected.
    130      * <p>This is useful for graceful disconnection. Applications should use
    131      * this intent as a hint to immediately terminate higher level connections
    132      * (RFCOMM, L2CAP, or profile connections) to the remote device.
    133      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
    134      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    135      */
    136     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    137     public static final String ACTION_ACL_DISCONNECT_REQUESTED =
    138             "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED";
    139 
    140     /**
    141      * Broadcast Action: Indicates a low level (ACL) disconnection from a
    142      * remote device.
    143      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
    144      * <p>ACL connections are managed automatically by the Android Bluetooth
    145      * stack.
    146      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    147      */
    148     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    149     public static final String ACTION_ACL_DISCONNECTED =
    150             "android.bluetooth.device.action.ACL_DISCONNECTED";
    151 
    152     /**
    153      * Broadcast Action: Indicates the friendly name of a remote device has
    154      * been retrieved for the first time, or changed since the last retrieval.
    155      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
    156      * #EXTRA_NAME}.
    157      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    158      */
    159     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    160     public static final String ACTION_NAME_CHANGED =
    161             "android.bluetooth.device.action.NAME_CHANGED";
    162 
    163     /**
    164      * Broadcast Action: Indicates the alias of a remote device has been
    165      * changed.
    166      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
    167      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    168      *
    169      * @hide
    170      */
    171     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    172     public static final String ACTION_ALIAS_CHANGED =
    173             "android.bluetooth.device.action.ALIAS_CHANGED";
    174 
    175     /**
    176      * Broadcast Action: Indicates a change in the bond state of a remote
    177      * device. For example, if a device is bonded (paired).
    178      * <p>Always contains the extra fields {@link #EXTRA_DEVICE}, {@link
    179      * #EXTRA_BOND_STATE} and {@link #EXTRA_PREVIOUS_BOND_STATE}.
    180      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    181      */
    182     // Note: When EXTRA_BOND_STATE is BOND_NONE then this will also
    183     // contain a hidden extra field EXTRA_REASON with the result code.
    184     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    185     public static final String ACTION_BOND_STATE_CHANGED =
    186             "android.bluetooth.device.action.BOND_STATE_CHANGED";
    187 
    188     /**
    189      * Used as a Parcelable {@link BluetoothDevice} extra field in every intent
    190      * broadcast by this class. It contains the {@link BluetoothDevice} that
    191      * the intent applies to.
    192      */
    193     public static final String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
    194 
    195     /**
    196      * Used as a String extra field in {@link #ACTION_NAME_CHANGED} and {@link
    197      * #ACTION_FOUND} intents. It contains the friendly Bluetooth name.
    198      */
    199     public static final String EXTRA_NAME = "android.bluetooth.device.extra.NAME";
    200 
    201     /**
    202      * Used as an optional short extra field in {@link #ACTION_FOUND} intents.
    203      * Contains the RSSI value of the remote device as reported by the
    204      * Bluetooth hardware.
    205      */
    206     public static final String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI";
    207 
    208     /**
    209      * Used as a Parcelable {@link BluetoothClass} extra field in {@link
    210      * #ACTION_FOUND} and {@link #ACTION_CLASS_CHANGED} intents.
    211      */
    212     public static final String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS";
    213 
    214     /**
    215      * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
    216      * Contains the bond state of the remote device.
    217      * <p>Possible values are:
    218      * {@link #BOND_NONE},
    219      * {@link #BOND_BONDING},
    220      * {@link #BOND_BONDED}.
    221       */
    222     public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE";
    223     /**
    224      * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
    225      * Contains the previous bond state of the remote device.
    226      * <p>Possible values are:
    227      * {@link #BOND_NONE},
    228      * {@link #BOND_BONDING},
    229      * {@link #BOND_BONDED}.
    230       */
    231     public static final String EXTRA_PREVIOUS_BOND_STATE =
    232             "android.bluetooth.device.extra.PREVIOUS_BOND_STATE";
    233     /**
    234      * Indicates the remote device is not bonded (paired).
    235      * <p>There is no shared link key with the remote device, so communication
    236      * (if it is allowed at all) will be unauthenticated and unencrypted.
    237      */
    238     public static final int BOND_NONE = 10;
    239     /**
    240      * Indicates bonding (pairing) is in progress with the remote device.
    241      */
    242     public static final int BOND_BONDING = 11;
    243     /**
    244      * Indicates the remote device is bonded (paired).
    245      * <p>A shared link keys exists locally for the remote device, so
    246      * communication can be authenticated and encrypted.
    247      * <p><i>Being bonded (paired) with a remote device does not necessarily
    248      * mean the device is currently connected. It just means that the pending
    249      * procedure was completed at some earlier time, and the link key is still
    250      * stored locally, ready to use on the next connection.
    251      * </i>
    252      */
    253     public static final int BOND_BONDED = 12;
    254 
    255     /** @hide */
    256     public static final String EXTRA_REASON = "android.bluetooth.device.extra.REASON";
    257     /** @hide */
    258     public static final String EXTRA_PAIRING_VARIANT =
    259             "android.bluetooth.device.extra.PAIRING_VARIANT";
    260     /** @hide */
    261     public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY";
    262 
    263     /**
    264      * Broadcast Action: This intent is used to broadcast the {@link UUID}
    265      * wrapped as a {@link android.os.ParcelUuid} of the remote device after it
    266      * has been fetched. This intent is sent only when the UUIDs of the remote
    267      * device are requested to be fetched using Service Discovery Protocol
    268      * <p> Always contains the extra field {@link #EXTRA_DEVICE}
    269      * <p> Always contains the extra field {@link #EXTRA_UUID}
    270      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    271      */
    272     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    273     public static final String ACTION_UUID =
    274             "android.bluetooth.device.action.UUID";
    275 
    276     /**
    277      * Broadcast Action: Indicates a failure to retrieve the name of a remote
    278      * device.
    279      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
    280      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    281      * @hide
    282      */
    283     //TODO: is this actually useful?
    284     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    285     public static final String ACTION_NAME_FAILED =
    286             "android.bluetooth.device.action.NAME_FAILED";
    287 
    288     /** @hide */
    289     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    290     public static final String ACTION_PAIRING_REQUEST =
    291             "android.bluetooth.device.action.PAIRING_REQUEST";
    292     /** @hide */
    293     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    294     public static final String ACTION_PAIRING_CANCEL =
    295             "android.bluetooth.device.action.PAIRING_CANCEL";
    296 
    297     /** @hide */
    298     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    299     public static final String ACTION_CONNECTION_ACCESS_REQUEST =
    300             "android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST";
    301 
    302     /** @hide */
    303     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    304     public static final String ACTION_CONNECTION_ACCESS_REPLY =
    305             "android.bluetooth.device.action.CONNECTION_ACCESS_REPLY";
    306 
    307     /** @hide */
    308     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    309     public static final String ACTION_CONNECTION_ACCESS_CANCEL =
    310             "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL";
    311 
    312     /**
    313      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intent.
    314      * @hide
    315      */
    316     public static final String EXTRA_ACCESS_REQUEST_TYPE =
    317         "android.bluetooth.device.extra.ACCESS_REQUEST_TYPE";
    318 
    319     /**@hide*/
    320     public static final int REQUEST_TYPE_PROFILE_CONNECTION = 1;
    321 
    322     /**@hide*/
    323     public static final int REQUEST_TYPE_PHONEBOOK_ACCESS = 2;
    324 
    325     /**
    326      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents,
    327      * Contains package name to return reply intent to.
    328      * @hide
    329      */
    330     public static final String EXTRA_PACKAGE_NAME = "android.bluetooth.device.extra.PACKAGE_NAME";
    331 
    332     /**
    333      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents,
    334      * Contains class name to return reply intent to.
    335      * @hide
    336      */
    337     public static final String EXTRA_CLASS_NAME = "android.bluetooth.device.extra.CLASS_NAME";
    338 
    339     /**
    340      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intent.
    341      * @hide
    342      */
    343     public static final String EXTRA_CONNECTION_ACCESS_RESULT =
    344         "android.bluetooth.device.extra.CONNECTION_ACCESS_RESULT";
    345 
    346     /**@hide*/
    347     public static final int CONNECTION_ACCESS_YES = 1;
    348 
    349     /**@hide*/
    350     public static final int CONNECTION_ACCESS_NO = 2;
    351 
    352     /**
    353      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intents,
    354      * Contains boolean to indicate if the allowed response is once-for-all so that
    355      * next request will be granted without asking user again.
    356      * @hide
    357      */
    358     public static final String EXTRA_ALWAYS_ALLOWED =
    359         "android.bluetooth.device.extra.ALWAYS_ALLOWED";
    360 
    361     /**
    362      * A bond attempt succeeded
    363      * @hide
    364      */
    365     public static final int BOND_SUCCESS = 0;
    366 
    367     /**
    368      * A bond attempt failed because pins did not match, or remote device did
    369      * not respond to pin request in time
    370      * @hide
    371      */
    372     public static final int UNBOND_REASON_AUTH_FAILED = 1;
    373 
    374     /**
    375      * A bond attempt failed because the other side explicitly rejected
    376      * bonding
    377      * @hide
    378      */
    379     public static final int UNBOND_REASON_AUTH_REJECTED = 2;
    380 
    381     /**
    382      * A bond attempt failed because we canceled the bonding process
    383      * @hide
    384      */
    385     public static final int UNBOND_REASON_AUTH_CANCELED = 3;
    386 
    387     /**
    388      * A bond attempt failed because we could not contact the remote device
    389      * @hide
    390      */
    391     public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
    392 
    393     /**
    394      * A bond attempt failed because a discovery is in progress
    395      * @hide
    396      */
    397     public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
    398 
    399     /**
    400      * A bond attempt failed because of authentication timeout
    401      * @hide
    402      */
    403     public static final int UNBOND_REASON_AUTH_TIMEOUT = 6;
    404 
    405     /**
    406      * A bond attempt failed because of repeated attempts
    407      * @hide
    408      */
    409     public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7;
    410 
    411     /**
    412      * A bond attempt failed because we received an Authentication Cancel
    413      * by remote end
    414      * @hide
    415      */
    416     public static final int UNBOND_REASON_REMOTE_AUTH_CANCELED = 8;
    417 
    418     /**
    419      * An existing bond was explicitly revoked
    420      * @hide
    421      */
    422     public static final int UNBOND_REASON_REMOVED = 9;
    423 
    424     /**
    425      * The user will be prompted to enter a pin
    426      * @hide
    427      */
    428     public static final int PAIRING_VARIANT_PIN = 0;
    429 
    430     /**
    431      * The user will be prompted to enter a passkey
    432      * @hide
    433      */
    434     public static final int PAIRING_VARIANT_PASSKEY = 1;
    435 
    436     /**
    437      * The user will be prompted to confirm the passkey displayed on the screen
    438      * @hide
    439      */
    440     public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2;
    441 
    442     /**
    443      * The user will be prompted to accept or deny the incoming pairing request
    444      * @hide
    445      */
    446     public static final int PAIRING_VARIANT_CONSENT = 3;
    447 
    448     /**
    449      * The user will be prompted to enter the passkey displayed on remote device
    450      * This is used for Bluetooth 2.1 pairing.
    451      * @hide
    452      */
    453     public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4;
    454 
    455     /**
    456      * The user will be prompted to enter the PIN displayed on remote device.
    457      * This is used for Bluetooth 2.0 pairing.
    458      * @hide
    459      */
    460     public static final int PAIRING_VARIANT_DISPLAY_PIN = 5;
    461 
    462     /**
    463      * The user will be prompted to accept or deny the OOB pairing request
    464      * @hide
    465      */
    466     public static final int PAIRING_VARIANT_OOB_CONSENT = 6;
    467 
    468     /**
    469      * Used as an extra field in {@link #ACTION_UUID} intents,
    470      * Contains the {@link android.os.ParcelUuid}s of the remote device which
    471      * is a parcelable version of {@link UUID}.
    472      */
    473     public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
    474 
    475     /**
    476      * Lazy initialization. Guaranteed final after first object constructed, or
    477      * getService() called.
    478      * TODO: Unify implementation of sService amongst BluetoothFoo API's
    479      */
    480     private static IBluetooth sService;
    481 
    482     private final String mAddress;
    483 
    484     /*package*/ static IBluetooth getService() {
    485         synchronized (BluetoothDevice.class) {
    486             if (sService == null) {
    487                 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
    488                 sService = adapter.getBluetoothService(mStateChangeCallback);
    489             }
    490         }
    491         return sService;
    492     }
    493 
    494     static IBluetoothManagerCallback mStateChangeCallback = new IBluetoothManagerCallback.Stub() {
    495 
    496         public void onBluetoothServiceUp(IBluetooth bluetoothService)
    497                 throws RemoteException {
    498             synchronized (BluetoothDevice.class) {
    499                 sService = bluetoothService;
    500             }
    501         }
    502 
    503         public void onBluetoothServiceDown()
    504             throws RemoteException {
    505             synchronized (BluetoothDevice.class) {
    506                 sService = null;
    507             }
    508         }
    509     };
    510     /**
    511      * Create a new BluetoothDevice
    512      * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB",
    513      * and is validated in this constructor.
    514      * @param address valid Bluetooth MAC address
    515      * @throws RuntimeException Bluetooth is not available on this platform
    516      * @throws IllegalArgumentException address is invalid
    517      * @hide
    518      */
    519     /*package*/ BluetoothDevice(String address) {
    520         getService();  // ensures sService is initialized
    521         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
    522             throw new IllegalArgumentException(address + " is not a valid Bluetooth address");
    523         }
    524 
    525         mAddress = address;
    526     }
    527 
    528     @Override
    529     public boolean equals(Object o) {
    530         if (o instanceof BluetoothDevice) {
    531             return mAddress.equals(((BluetoothDevice)o).getAddress());
    532         }
    533         return false;
    534     }
    535 
    536     @Override
    537     public int hashCode() {
    538         return mAddress.hashCode();
    539     }
    540 
    541     /**
    542      * Returns a string representation of this BluetoothDevice.
    543      * <p>Currently this is the Bluetooth hardware address, for example
    544      * "00:11:22:AA:BB:CC". However, you should always use {@link #getAddress}
    545      * if you explicitly require the Bluetooth hardware address in case the
    546      * {@link #toString} representation changes in the future.
    547      * @return string representation of this BluetoothDevice
    548      */
    549     @Override
    550     public String toString() {
    551         return mAddress;
    552     }
    553 
    554     public int describeContents() {
    555         return 0;
    556     }
    557 
    558     public static final Parcelable.Creator<BluetoothDevice> CREATOR =
    559             new Parcelable.Creator<BluetoothDevice>() {
    560         public BluetoothDevice createFromParcel(Parcel in) {
    561             return new BluetoothDevice(in.readString());
    562         }
    563         public BluetoothDevice[] newArray(int size) {
    564             return new BluetoothDevice[size];
    565         }
    566     };
    567 
    568     public void writeToParcel(Parcel out, int flags) {
    569         out.writeString(mAddress);
    570     }
    571 
    572     /**
    573      * Returns the hardware address of this BluetoothDevice.
    574      * <p> For example, "00:11:22:AA:BB:CC".
    575      * @return Bluetooth hardware address as string
    576      */
    577     public String getAddress() {
    578         if (DBG) Log.d(TAG, "mAddress: " + mAddress);
    579         return mAddress;
    580     }
    581 
    582     /**
    583      * Get the friendly Bluetooth name of the remote device.
    584      *
    585      * <p>The local adapter will automatically retrieve remote names when
    586      * performing a device scan, and will cache them. This method just returns
    587      * the name for this device from the cache.
    588      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
    589      *
    590      * @return the Bluetooth name, or null if there was a problem.
    591      */
    592     public String getName() {
    593         if (sService == null) {
    594             Log.e(TAG, "BT not enabled. Cannot get Remote Device name");
    595             return null;
    596         }
    597         try {
    598             return sService.getRemoteName(this);
    599         } catch (RemoteException e) {Log.e(TAG, "", e);}
    600         return null;
    601     }
    602 
    603     /**
    604      * Get the Bluetooth alias of the remote device.
    605      * <p>Alias is the locally modified name of a remote device.
    606      *
    607      * @return the Bluetooth alias, or null if no alias or there was a problem
    608      * @hide
    609      */
    610     public String getAlias() {
    611         if (sService == null) {
    612             Log.e(TAG, "BT not enabled. Cannot get Remote Device Alias");
    613             return null;
    614         }
    615         try {
    616             return sService.getRemoteAlias(this);
    617         } catch (RemoteException e) {Log.e(TAG, "", e);}
    618         return null;
    619     }
    620 
    621     /**
    622      * Set the Bluetooth alias of the remote device.
    623      * <p>Alias is the locally modified name of a remote device.
    624      * <p>This methoid overwrites the alias. The changed
    625      * alias is saved in the local storage so that the change
    626      * is preserved over power cycle.
    627      *
    628      * @return true on success, false on error
    629      * @hide
    630      */
    631     public boolean setAlias(String alias) {
    632         if (sService == null) {
    633             Log.e(TAG, "BT not enabled. Cannot set Remote Device name");
    634             return false;
    635         }
    636         try {
    637             return sService.setRemoteAlias(this, alias);
    638         } catch (RemoteException e) {Log.e(TAG, "", e);}
    639         return false;
    640     }
    641 
    642     /**
    643      * Get the Bluetooth alias of the remote device.
    644      * If Alias is null, get the Bluetooth name instead.
    645      * @see #getAlias()
    646      * @see #getName()
    647      *
    648      * @return the Bluetooth alias, or null if no alias or there was a problem
    649      * @hide
    650      */
    651     public String getAliasName() {
    652         String name = getAlias();
    653         if (name == null) {
    654             name = getName();
    655         }
    656         return name;
    657     }
    658 
    659     /**
    660      * Start the bonding (pairing) process with the remote device.
    661      * <p>This is an asynchronous call, it will return immediately. Register
    662      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
    663      * the bonding process completes, and its result.
    664      * <p>Android system services will handle the necessary user interactions
    665      * to confirm and complete the bonding process.
    666      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    667      *
    668      * @return false on immediate error, true if bonding will begin
    669      * @hide
    670      */
    671     public boolean createBond() {
    672         if (sService == null) {
    673             Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device");
    674             return false;
    675         }
    676         try {
    677             return sService.createBond(this);
    678         } catch (RemoteException e) {Log.e(TAG, "", e);}
    679         return false;
    680     }
    681 
    682     /**
    683      * Start the bonding (pairing) process with the remote device using the
    684      * Out Of Band mechanism.
    685      *
    686      * <p>This is an asynchronous call, it will return immediately. Register
    687      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
    688      * the bonding process completes, and its result.
    689      *
    690      * <p>Android system services will handle the necessary user interactions
    691      * to confirm and complete the bonding process.
    692      *
    693      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    694      *
    695      * @param hash - Simple Secure pairing hash
    696      * @param randomizer - The random key obtained using OOB
    697      * @return false on immediate error, true if bonding will begin
    698      *
    699      * @hide
    700      */
    701     public boolean createBondOutOfBand(byte[] hash, byte[] randomizer) {
    702         //TODO(BT)
    703         /*
    704         try {
    705             return sService.createBondOutOfBand(this, hash, randomizer);
    706         } catch (RemoteException e) {Log.e(TAG, "", e);}*/
    707         return false;
    708     }
    709 
    710     /**
    711      * Set the Out Of Band data for a remote device to be used later
    712      * in the pairing mechanism. Users can obtain this data through other
    713      * trusted channels
    714      *
    715      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    716      *
    717      * @param hash Simple Secure pairing hash
    718      * @param randomizer The random key obtained using OOB
    719      * @return false on error; true otherwise
    720      *
    721      * @hide
    722      */
    723     public boolean setDeviceOutOfBandData(byte[] hash, byte[] randomizer) {
    724       //TODO(BT)
    725       /*
    726       try {
    727         return sService.setDeviceOutOfBandData(this, hash, randomizer);
    728       } catch (RemoteException e) {Log.e(TAG, "", e);} */
    729       return false;
    730     }
    731 
    732     /**
    733      * Cancel an in-progress bonding request started with {@link #createBond}.
    734      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    735      *
    736      * @return true on success, false on error
    737      * @hide
    738      */
    739     public boolean cancelBondProcess() {
    740         if (sService == null) {
    741             Log.e(TAG, "BT not enabled. Cannot cancel Remote Device bond");
    742             return false;
    743         }
    744         try {
    745             return sService.cancelBondProcess(this);
    746         } catch (RemoteException e) {Log.e(TAG, "", e);}
    747         return false;
    748     }
    749 
    750     /**
    751      * Remove bond (pairing) with the remote device.
    752      * <p>Delete the link key associated with the remote device, and
    753      * immediately terminate connections to that device that require
    754      * authentication and encryption.
    755      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    756      *
    757      * @return true on success, false on error
    758      * @hide
    759      */
    760     public boolean removeBond() {
    761         if (sService == null) {
    762             Log.e(TAG, "BT not enabled. Cannot remove Remote Device bond");
    763             return false;
    764         }
    765         try {
    766             return sService.removeBond(this);
    767         } catch (RemoteException e) {Log.e(TAG, "", e);}
    768         return false;
    769     }
    770 
    771     /**
    772      * Get the bond state of the remote device.
    773      * <p>Possible values for the bond state are:
    774      * {@link #BOND_NONE},
    775      * {@link #BOND_BONDING},
    776      * {@link #BOND_BONDED}.
    777      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
    778      *
    779      * @return the bond state
    780      */
    781     public int getBondState() {
    782         if (sService == null) {
    783             Log.e(TAG, "BT not enabled. Cannot get bond state");
    784             return BOND_NONE;
    785         }
    786         try {
    787             return sService.getBondState(this);
    788         } catch (RemoteException e) {Log.e(TAG, "", e);}
    789         catch (NullPointerException npe) {
    790             // Handle case where bluetooth service proxy
    791             // is already null.
    792             Log.e(TAG, "NullPointerException for getBondState() of device ("+
    793                 getAddress()+")", npe);
    794         }
    795         return BOND_NONE;
    796     }
    797 
    798     /**
    799      * Get the Bluetooth class of the remote device.
    800      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
    801      *
    802      * @return Bluetooth class object, or null on error
    803      */
    804     public BluetoothClass getBluetoothClass() {
    805         if (sService == null) {
    806             Log.e(TAG, "BT not enabled. Cannot get Bluetooth Class");
    807             return null;
    808         }
    809         try {
    810             int classInt = sService.getRemoteClass(this);
    811             if (classInt == BluetoothClass.ERROR) return null;
    812             return new BluetoothClass(classInt);
    813         } catch (RemoteException e) {Log.e(TAG, "", e);}
    814         return null;
    815     }
    816 
    817     /**
    818      * Get trust state of a remote device.
    819      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
    820      * @hide
    821      */
    822     public boolean getTrustState() {
    823         //TODO(BT)
    824         /*
    825         try {
    826             return sService.getTrustState(this);
    827         } catch (RemoteException e) {
    828             Log.e(TAG, "", e);
    829         }*/
    830         return false;
    831     }
    832 
    833     /**
    834      * Set trust state for a remote device.
    835      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    836      * @param value the trust state value (true or false)
    837      * @hide
    838      */
    839     public boolean setTrust(boolean value) {
    840         //TODO(BT)
    841         /*
    842         try {
    843             return sService.setTrust(this, value);
    844         } catch (RemoteException e) {
    845             Log.e(TAG, "", e);
    846         }*/
    847         return false;
    848     }
    849 
    850     /**
    851      * Returns the supported features (UUIDs) of the remote device.
    852      *
    853      * <p>This method does not start a service discovery procedure to retrieve the UUIDs
    854      * from the remote device. Instead, the local cached copy of the service
    855      * UUIDs are returned.
    856      * <p>Use {@link #fetchUuidsWithSdp} if fresh UUIDs are desired.
    857      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
    858      *
    859      * @return the supported features (UUIDs) of the remote device,
    860      *         or null on error
    861      */
    862      public ParcelUuid[] getUuids() {
    863          if (sService == null) {
    864             Log.e(TAG, "BT not enabled. Cannot get remote device Uuids");
    865              return null;
    866          }
    867         try {
    868             return sService.getRemoteUuids(this);
    869         } catch (RemoteException e) {Log.e(TAG, "", e);}
    870         return null;
    871     }
    872 
    873      /**
    874       * Perform a service discovery on the remote device to get the UUIDs supported.
    875       *
    876       * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent,
    877       * with the UUIDs supported by the remote end. If there is an error
    878       * in getting the SDP records or if the process takes a long time,
    879       * {@link #ACTION_UUID} intent is sent with the UUIDs that is currently
    880       * present in the cache. Clients should use the {@link #getUuids} to get UUIDs
    881       * if service discovery is not to be performed.
    882       * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
    883       *
    884       * @return False if the sanity check fails, True if the process
    885       *               of initiating an ACL connection to the remote device
    886       *               was started.
    887       */
    888      public boolean fetchUuidsWithSdp() {
    889         try {
    890             return sService.fetchRemoteUuids(this);
    891         } catch (RemoteException e) {Log.e(TAG, "", e);}
    892             return false;
    893     }
    894 
    895     /** @hide */
    896     public int getServiceChannel(ParcelUuid uuid) {
    897         //TODO(BT)
    898         /*
    899          try {
    900              return sService.getRemoteServiceChannel(this, uuid);
    901          } catch (RemoteException e) {Log.e(TAG, "", e);}*/
    902          return BluetoothDevice.ERROR;
    903     }
    904 
    905     /** @hide */
    906     public boolean setPin(byte[] pin) {
    907         if (sService == null) {
    908             Log.e(TAG, "BT not enabled. Cannot set Remote Device pin");
    909             return false;
    910         }
    911         try {
    912             return sService.setPin(this, true, pin.length, pin);
    913         } catch (RemoteException e) {Log.e(TAG, "", e);}
    914         return false;
    915     }
    916 
    917     /** @hide */
    918     public boolean setPasskey(int passkey) {
    919         //TODO(BT)
    920         /*
    921         try {
    922             return sService.setPasskey(this, true, 4, passkey);
    923         } catch (RemoteException e) {Log.e(TAG, "", e);}*/
    924         return false;
    925     }
    926 
    927     /** @hide */
    928     public boolean setPairingConfirmation(boolean confirm) {
    929         if (sService == null) {
    930             Log.e(TAG, "BT not enabled. Cannot set pairing confirmation");
    931             return false;
    932         }
    933         try {
    934             return sService.setPairingConfirmation(this, confirm);
    935         } catch (RemoteException e) {Log.e(TAG, "", e);}
    936         return false;
    937     }
    938 
    939     /** @hide */
    940     public boolean setRemoteOutOfBandData() {
    941         // TODO(BT)
    942         /*
    943         try {
    944           return sService.setRemoteOutOfBandData(this);
    945       } catch (RemoteException e) {Log.e(TAG, "", e);}*/
    946       return false;
    947     }
    948 
    949     /** @hide */
    950     public boolean cancelPairingUserInput() {
    951         if (sService == null) {
    952             Log.e(TAG, "BT not enabled. Cannot create pairing user input");
    953             return false;
    954         }
    955         try {
    956             return sService.cancelBondProcess(this);
    957         } catch (RemoteException e) {Log.e(TAG, "", e);}
    958         return false;
    959     }
    960 
    961     /** @hide */
    962     public boolean isBluetoothDock() {
    963         // TODO(BT)
    964         /*
    965         try {
    966             return sService.isBluetoothDock(this);
    967         } catch (RemoteException e) {Log.e(TAG, "", e);}*/
    968         return false;
    969     }
    970 
    971     /**
    972      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
    973      * outgoing connection to this remote device on given channel.
    974      * <p>The remote device will be authenticated and communication on this
    975      * socket will be encrypted.
    976      * <p> Use this socket only if an authenticated socket link is possible.
    977      * Authentication refers to the authentication of the link key to
    978      * prevent man-in-the-middle type of attacks.
    979      * For example, for Bluetooth 2.1 devices, if any of the devices does not
    980      * have an input and output capability or just has the ability to
    981      * display a numeric key, a secure socket connection is not possible.
    982      * In such a case, use {#link createInsecureRfcommSocket}.
    983      * For more details, refer to the Security Model section 5.2 (vol 3) of
    984      * Bluetooth Core Specification version 2.1 + EDR.
    985      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
    986      * connection.
    987      * <p>Valid RFCOMM channels are in range 1 to 30.
    988      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
    989      *
    990      * @param channel RFCOMM channel to connect to
    991      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
    992      * @throws IOException on error, for example Bluetooth not available, or
    993      *                     insufficient permissions
    994      * @hide
    995      */
    996     public BluetoothSocket createRfcommSocket(int channel) throws IOException {
    997         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel,
    998                 null);
    999     }
   1000 
   1001     /**
   1002      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
   1003      * outgoing connection to this remote device using SDP lookup of uuid.
   1004      * <p>This is designed to be used with {@link
   1005      * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer
   1006      * Bluetooth applications.
   1007      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
   1008      * connection. This will also perform an SDP lookup of the given uuid to
   1009      * determine which channel to connect to.
   1010      * <p>The remote device will be authenticated and communication on this
   1011      * socket will be encrypted.
   1012      * <p> Use this socket only if an authenticated socket link is possible.
   1013      * Authentication refers to the authentication of the link key to
   1014      * prevent man-in-the-middle type of attacks.
   1015      * For example, for Bluetooth 2.1 devices, if any of the devices does not
   1016      * have an input and output capability or just has the ability to
   1017      * display a numeric key, a secure socket connection is not possible.
   1018      * In such a case, use {#link createInsecureRfcommSocketToServiceRecord}.
   1019      * For more details, refer to the Security Model section 5.2 (vol 3) of
   1020      * Bluetooth Core Specification version 2.1 + EDR.
   1021      * <p>Hint: If you are connecting to a Bluetooth serial board then try
   1022      * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
   1023      * However if you are connecting to an Android peer then please generate
   1024      * your own unique UUID.
   1025      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
   1026      *
   1027      * @param uuid service record uuid to lookup RFCOMM channel
   1028      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
   1029      * @throws IOException on error, for example Bluetooth not available, or
   1030      *                     insufficient permissions
   1031      */
   1032     public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {
   1033         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1,
   1034                 new ParcelUuid(uuid));
   1035     }
   1036 
   1037     /**
   1038      * Create an RFCOMM {@link BluetoothSocket} socket ready to start an insecure
   1039      * outgoing connection to this remote device using SDP lookup of uuid.
   1040      * <p> The communication channel will not have an authenticated link key
   1041      * i.e it will be subject to man-in-the-middle attacks. For Bluetooth 2.1
   1042      * devices, the link key will be encrypted, as encryption is mandatory.
   1043      * For legacy devices (pre Bluetooth 2.1 devices) the link key will
   1044      * be not be encrypted. Use {@link #createRfcommSocketToServiceRecord} if an
   1045      * encrypted and authenticated communication channel is desired.
   1046      * <p>This is designed to be used with {@link
   1047      * BluetoothAdapter#listenUsingInsecureRfcommWithServiceRecord} for peer-peer
   1048      * Bluetooth applications.
   1049      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
   1050      * connection. This will also perform an SDP lookup of the given uuid to
   1051      * determine which channel to connect to.
   1052      * <p>The remote device will be authenticated and communication on this
   1053      * socket will be encrypted.
   1054      * <p>Hint: If you are connecting to a Bluetooth serial board then try
   1055      * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
   1056      * However if you are connecting to an Android peer then please generate
   1057      * your own unique UUID.
   1058      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
   1059      *
   1060      * @param uuid service record uuid to lookup RFCOMM channel
   1061      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
   1062      * @throws IOException on error, for example Bluetooth not available, or
   1063      *                     insufficient permissions
   1064      */
   1065     public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException {
   1066         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1,
   1067                 new ParcelUuid(uuid));
   1068     }
   1069 
   1070     /**
   1071      * Construct an insecure RFCOMM socket ready to start an outgoing
   1072      * connection.
   1073      * Call #connect on the returned #BluetoothSocket to begin the connection.
   1074      * The remote device will not be authenticated and communication on this
   1075      * socket will not be encrypted.
   1076      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
   1077      *
   1078      * @param port    remote port
   1079      * @return An RFCOMM BluetoothSocket
   1080      * @throws IOException On error, for example Bluetooth not available, or
   1081      *                     insufficient permissions.
   1082      * @hide
   1083      */
   1084     public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
   1085         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port,
   1086                 null);
   1087     }
   1088 
   1089     /**
   1090      * Construct a SCO socket ready to start an outgoing connection.
   1091      * Call #connect on the returned #BluetoothSocket to begin the connection.
   1092      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
   1093      *
   1094      * @return a SCO BluetoothSocket
   1095      * @throws IOException on error, for example Bluetooth not available, or
   1096      *                     insufficient permissions.
   1097      * @hide
   1098      */
   1099     public BluetoothSocket createScoSocket() throws IOException {
   1100         return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null);
   1101     }
   1102 
   1103     /**
   1104      * Check that a pin is valid and convert to byte array.
   1105      *
   1106      * Bluetooth pin's are 1 to 16 bytes of UTF-8 characters.
   1107      * @param pin pin as java String
   1108      * @return the pin code as a UTF-8 byte array, or null if it is an invalid
   1109      *         Bluetooth pin.
   1110      * @hide
   1111      */
   1112     public static byte[] convertPinToBytes(String pin) {
   1113         if (pin == null) {
   1114             return null;
   1115         }
   1116         byte[] pinBytes;
   1117         try {
   1118             pinBytes = pin.getBytes("UTF-8");
   1119         } catch (UnsupportedEncodingException uee) {
   1120             Log.e(TAG, "UTF-8 not supported?!?");  // this should not happen
   1121             return null;
   1122         }
   1123         if (pinBytes.length <= 0 || pinBytes.length > 16) {
   1124             return null;
   1125         }
   1126         return pinBytes;
   1127     }
   1128 
   1129 }
   1130