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