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.Manifest;
     20 import android.annotation.RequiresPermission;
     21 import android.annotation.SdkConstant;
     22 import android.annotation.SdkConstant.SdkConstantType;
     23 import android.annotation.SystemApi;
     24 import android.content.Context;
     25 import android.os.Parcel;
     26 import android.os.Parcelable;
     27 import android.os.ParcelUuid;
     28 import android.os.Process;
     29 import android.os.RemoteException;
     30 import android.util.Log;
     31 
     32 import java.io.IOException;
     33 import java.io.UnsupportedEncodingException;
     34 import java.util.UUID;
     35 
     36 /**
     37  * Represents a remote Bluetooth device. A {@link BluetoothDevice} lets you
     38  * create a connection with the respective device or query information about
     39  * it, such as the name, address, class, and bonding state.
     40  *
     41  * <p>This class is really just a thin wrapper for a Bluetooth hardware
     42  * address. Objects of this class are immutable. Operations on this class
     43  * are performed on the remote Bluetooth hardware address, using the
     44  * {@link BluetoothAdapter} that was used to create this {@link
     45  * BluetoothDevice}.
     46  *
     47  * <p>To get a {@link BluetoothDevice}, use
     48  * {@link BluetoothAdapter#getRemoteDevice(String)
     49  * BluetoothAdapter.getRemoteDevice(String)} to create one representing a device
     50  * of a known MAC address (which you can get through device discovery with
     51  * {@link BluetoothAdapter}) or get one from the set of bonded devices
     52  * returned by {@link BluetoothAdapter#getBondedDevices()
     53  * BluetoothAdapter.getBondedDevices()}. You can then open a
     54  * {@link BluetoothSocket} for communication with the remote device, using
     55  * {@link #createRfcommSocketToServiceRecord(UUID)}.
     56  *
     57  * <p class="note"><strong>Note:</strong>
     58  * Requires the {@link android.Manifest.permission#BLUETOOTH} permission.
     59  *
     60  * <div class="special reference">
     61  * <h3>Developer Guides</h3>
     62  * <p>For more information about using Bluetooth, read the
     63  * <a href="{@docRoot}guide/topics/wireless/bluetooth.html">Bluetooth</a> developer guide.</p>
     64  * </div>
     65  *
     66  * {@see BluetoothAdapter}
     67  * {@see BluetoothSocket}
     68  */
     69 public final class BluetoothDevice implements Parcelable {
     70     private static final String TAG = "BluetoothDevice";
     71     private static final boolean DBG = false;
     72 
     73     /**
     74      * Connection state bitmask as returned by getConnectionState.
     75      */
     76     private static final int CONNECTION_STATE_DISCONNECTED = 0;
     77     private static final int CONNECTION_STATE_CONNECTED = 1;
     78     private static final int CONNECTION_STATE_ENCRYPTED_BREDR = 2;
     79     private static final int CONNECTION_STATE_ENCRYPTED_LE = 4;
     80 
     81     /**
     82      * Sentinel error value for this class. Guaranteed to not equal any other
     83      * integer constant in this class. Provided as a convenience for functions
     84      * that require a sentinel error value, for example:
     85      * <p><code>Intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
     86      * BluetoothDevice.ERROR)</code>
     87      */
     88     public static final int ERROR = Integer.MIN_VALUE;
     89 
     90     /**
     91      * Broadcast Action: Remote device discovered.
     92      * <p>Sent when a remote device is found during discovery.
     93      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
     94      * #EXTRA_CLASS}. Can contain the extra fields {@link #EXTRA_NAME} and/or
     95      * {@link #EXTRA_RSSI} if they are available.
     96      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} and
     97      * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} to receive.
     98      */
     99      // TODO: Change API to not broadcast RSSI if not available (incoming connection)
    100     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    101     public static final String ACTION_FOUND =
    102             "android.bluetooth.device.action.FOUND";
    103 
    104     /**
    105      * Broadcast Action: Remote device disappeared.
    106      * <p>Sent when a remote device that was found in the last discovery is not
    107      * found in the current discovery.
    108      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
    109      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    110      * @hide
    111      */
    112     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    113     public static final String ACTION_DISAPPEARED =
    114             "android.bluetooth.device.action.DISAPPEARED";
    115 
    116     /**
    117      * Broadcast Action: Bluetooth class of a remote device has changed.
    118      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
    119      * #EXTRA_CLASS}.
    120      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    121      * {@see BluetoothClass}
    122      */
    123     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    124     public static final String ACTION_CLASS_CHANGED =
    125             "android.bluetooth.device.action.CLASS_CHANGED";
    126 
    127     /**
    128      * Broadcast Action: Indicates a low level (ACL) connection has been
    129      * established with a remote device.
    130      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
    131      * <p>ACL connections are managed automatically by the Android Bluetooth
    132      * stack.
    133      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    134      */
    135     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    136     public static final String ACTION_ACL_CONNECTED =
    137             "android.bluetooth.device.action.ACL_CONNECTED";
    138 
    139     /**
    140      * Broadcast Action: Indicates that a low level (ACL) disconnection has
    141      * been requested for a remote device, and it will soon be disconnected.
    142      * <p>This is useful for graceful disconnection. Applications should use
    143      * this intent as a hint to immediately terminate higher level connections
    144      * (RFCOMM, L2CAP, or profile connections) to the remote device.
    145      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
    146      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    147      */
    148     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    149     public static final String ACTION_ACL_DISCONNECT_REQUESTED =
    150             "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED";
    151 
    152     /**
    153      * Broadcast Action: Indicates a low level (ACL) disconnection from a
    154      * remote device.
    155      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
    156      * <p>ACL connections are managed automatically by the Android Bluetooth
    157      * stack.
    158      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    159      */
    160     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    161     public static final String ACTION_ACL_DISCONNECTED =
    162             "android.bluetooth.device.action.ACL_DISCONNECTED";
    163 
    164     /**
    165      * Broadcast Action: Indicates the friendly name of a remote device has
    166      * been retrieved for the first time, or changed since the last retrieval.
    167      * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
    168      * #EXTRA_NAME}.
    169      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    170      */
    171     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    172     public static final String ACTION_NAME_CHANGED =
    173             "android.bluetooth.device.action.NAME_CHANGED";
    174 
    175     /**
    176      * Broadcast Action: Indicates the alias of a remote device has been
    177      * changed.
    178      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
    179      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    180      *
    181      * @hide
    182      */
    183     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    184     public static final String ACTION_ALIAS_CHANGED =
    185             "android.bluetooth.device.action.ALIAS_CHANGED";
    186 
    187     /**
    188      * Broadcast Action: Indicates a change in the bond state of a remote
    189      * device. For example, if a device is bonded (paired).
    190      * <p>Always contains the extra fields {@link #EXTRA_DEVICE}, {@link
    191      * #EXTRA_BOND_STATE} and {@link #EXTRA_PREVIOUS_BOND_STATE}.
    192      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    193      */
    194     // Note: When EXTRA_BOND_STATE is BOND_NONE then this will also
    195     // contain a hidden extra field EXTRA_REASON with the result code.
    196     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    197     public static final String ACTION_BOND_STATE_CHANGED =
    198             "android.bluetooth.device.action.BOND_STATE_CHANGED";
    199 
    200     /**
    201      * Used as a Parcelable {@link BluetoothDevice} extra field in every intent
    202      * broadcast by this class. It contains the {@link BluetoothDevice} that
    203      * the intent applies to.
    204      */
    205     public static final String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
    206 
    207     /**
    208      * Used as a String extra field in {@link #ACTION_NAME_CHANGED} and {@link
    209      * #ACTION_FOUND} intents. It contains the friendly Bluetooth name.
    210      */
    211     public static final String EXTRA_NAME = "android.bluetooth.device.extra.NAME";
    212 
    213     /**
    214      * Used as an optional short extra field in {@link #ACTION_FOUND} intents.
    215      * Contains the RSSI value of the remote device as reported by the
    216      * Bluetooth hardware.
    217      */
    218     public static final String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI";
    219 
    220     /**
    221      * Used as a Parcelable {@link BluetoothClass} extra field in {@link
    222      * #ACTION_FOUND} and {@link #ACTION_CLASS_CHANGED} intents.
    223      */
    224     public static final String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS";
    225 
    226     /**
    227      * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
    228      * Contains the bond state of the remote device.
    229      * <p>Possible values are:
    230      * {@link #BOND_NONE},
    231      * {@link #BOND_BONDING},
    232      * {@link #BOND_BONDED}.
    233      */
    234     public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE";
    235     /**
    236      * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
    237      * Contains the previous bond state of the remote device.
    238      * <p>Possible values are:
    239      * {@link #BOND_NONE},
    240      * {@link #BOND_BONDING},
    241      * {@link #BOND_BONDED}.
    242      */
    243     public static final String EXTRA_PREVIOUS_BOND_STATE =
    244             "android.bluetooth.device.extra.PREVIOUS_BOND_STATE";
    245     /**
    246      * Indicates the remote device is not bonded (paired).
    247      * <p>There is no shared link key with the remote device, so communication
    248      * (if it is allowed at all) will be unauthenticated and unencrypted.
    249      */
    250     public static final int BOND_NONE = 10;
    251     /**
    252      * Indicates bonding (pairing) is in progress with the remote device.
    253      */
    254     public static final int BOND_BONDING = 11;
    255     /**
    256      * Indicates the remote device is bonded (paired).
    257      * <p>A shared link keys exists locally for the remote device, so
    258      * communication can be authenticated and encrypted.
    259      * <p><i>Being bonded (paired) with a remote device does not necessarily
    260      * mean the device is currently connected. It just means that the pending
    261      * procedure was completed at some earlier time, and the link key is still
    262      * stored locally, ready to use on the next connection.
    263      * </i>
    264      */
    265     public static final int BOND_BONDED = 12;
    266 
    267     /**
    268      * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
    269      * intents for unbond reason.
    270      * @hide
    271      */
    272     public static final String EXTRA_REASON = "android.bluetooth.device.extra.REASON";
    273 
    274     /**
    275      * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
    276      * intents to indicate pairing method used. Possible values are:
    277      * {@link #PAIRING_VARIANT_PIN},
    278      * {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION},
    279      */
    280     public static final String EXTRA_PAIRING_VARIANT =
    281             "android.bluetooth.device.extra.PAIRING_VARIANT";
    282 
    283     /**
    284      * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
    285      * intents as the value of passkey.
    286      */
    287     public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY";
    288 
    289     /**
    290      * Bluetooth device type, Unknown
    291      */
    292     public static final int DEVICE_TYPE_UNKNOWN = 0;
    293 
    294     /**
    295      * Bluetooth device type, Classic - BR/EDR devices
    296      */
    297     public static final int DEVICE_TYPE_CLASSIC = 1;
    298 
    299     /**
    300      * Bluetooth device type, Low Energy - LE-only
    301      */
    302     public static final int DEVICE_TYPE_LE = 2;
    303 
    304     /**
    305      * Bluetooth device type, Dual Mode - BR/EDR/LE
    306      */
    307     public static final int DEVICE_TYPE_DUAL = 3;
    308 
    309 
    310     /** @hide */
    311     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    312     public static final String ACTION_SDP_RECORD =
    313             "android.bluetooth.device.action.SDP_RECORD";
    314 
    315     /**
    316      * Broadcast Action: This intent is used to broadcast the {@link UUID}
    317      * wrapped as a {@link android.os.ParcelUuid} of the remote device after it
    318      * has been fetched. This intent is sent only when the UUIDs of the remote
    319      * device are requested to be fetched using Service Discovery Protocol
    320      * <p> Always contains the extra field {@link #EXTRA_DEVICE}
    321      * <p> Always contains the extra field {@link #EXTRA_UUID}
    322      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    323      */
    324     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    325     public static final String ACTION_UUID =
    326             "android.bluetooth.device.action.UUID";
    327 
    328     /** @hide */
    329     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    330     public static final String ACTION_MAS_INSTANCE =
    331             "android.bluetooth.device.action.MAS_INSTANCE";
    332 
    333     /**
    334      * Broadcast Action: Indicates a failure to retrieve the name of a remote
    335      * device.
    336      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
    337      * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
    338      * @hide
    339      */
    340     //TODO: is this actually useful?
    341     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    342     public static final String ACTION_NAME_FAILED =
    343             "android.bluetooth.device.action.NAME_FAILED";
    344 
    345     /**
    346      * Broadcast Action: This intent is used to broadcast PAIRING REQUEST
    347      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} to
    348      * receive.
    349      */
    350     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    351     public static final String ACTION_PAIRING_REQUEST =
    352             "android.bluetooth.device.action.PAIRING_REQUEST";
    353     /** @hide */
    354     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    355     public static final String ACTION_PAIRING_CANCEL =
    356             "android.bluetooth.device.action.PAIRING_CANCEL";
    357 
    358     /** @hide */
    359     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    360     public static final String ACTION_CONNECTION_ACCESS_REQUEST =
    361             "android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST";
    362 
    363     /** @hide */
    364     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    365     public static final String ACTION_CONNECTION_ACCESS_REPLY =
    366             "android.bluetooth.device.action.CONNECTION_ACCESS_REPLY";
    367 
    368     /** @hide */
    369     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    370     public static final String ACTION_CONNECTION_ACCESS_CANCEL =
    371             "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL";
    372 
    373     /**
    374      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intent.
    375      * @hide
    376      */
    377     public static final String EXTRA_ACCESS_REQUEST_TYPE =
    378         "android.bluetooth.device.extra.ACCESS_REQUEST_TYPE";
    379 
    380     /**@hide*/
    381     public static final int REQUEST_TYPE_PROFILE_CONNECTION = 1;
    382 
    383     /**@hide*/
    384     public static final int REQUEST_TYPE_PHONEBOOK_ACCESS = 2;
    385 
    386     /**@hide*/
    387     public static final int REQUEST_TYPE_MESSAGE_ACCESS = 3;
    388 
    389     /**@hide*/
    390     public static final int REQUEST_TYPE_SIM_ACCESS = 4;
    391 
    392     /**
    393      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents,
    394      * Contains package name to return reply intent to.
    395      * @hide
    396      */
    397     public static final String EXTRA_PACKAGE_NAME = "android.bluetooth.device.extra.PACKAGE_NAME";
    398 
    399     /**
    400      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents,
    401      * Contains class name to return reply intent to.
    402      * @hide
    403      */
    404     public static final String EXTRA_CLASS_NAME = "android.bluetooth.device.extra.CLASS_NAME";
    405 
    406     /**
    407      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intent.
    408      * @hide
    409      */
    410     public static final String EXTRA_CONNECTION_ACCESS_RESULT =
    411         "android.bluetooth.device.extra.CONNECTION_ACCESS_RESULT";
    412 
    413     /**@hide*/
    414     public static final int CONNECTION_ACCESS_YES = 1;
    415 
    416     /**@hide*/
    417     public static final int CONNECTION_ACCESS_NO = 2;
    418 
    419     /**
    420      * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intents,
    421      * Contains boolean to indicate if the allowed response is once-for-all so that
    422      * next request will be granted without asking user again.
    423      * @hide
    424      */
    425     public static final String EXTRA_ALWAYS_ALLOWED =
    426         "android.bluetooth.device.extra.ALWAYS_ALLOWED";
    427 
    428     /**
    429      * A bond attempt succeeded
    430      * @hide
    431      */
    432     public static final int BOND_SUCCESS = 0;
    433 
    434     /**
    435      * A bond attempt failed because pins did not match, or remote device did
    436      * not respond to pin request in time
    437      * @hide
    438      */
    439     public static final int UNBOND_REASON_AUTH_FAILED = 1;
    440 
    441     /**
    442      * A bond attempt failed because the other side explicitly rejected
    443      * bonding
    444      * @hide
    445      */
    446     public static final int UNBOND_REASON_AUTH_REJECTED = 2;
    447 
    448     /**
    449      * A bond attempt failed because we canceled the bonding process
    450      * @hide
    451      */
    452     public static final int UNBOND_REASON_AUTH_CANCELED = 3;
    453 
    454     /**
    455      * A bond attempt failed because we could not contact the remote device
    456      * @hide
    457      */
    458     public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
    459 
    460     /**
    461      * A bond attempt failed because a discovery is in progress
    462      * @hide
    463      */
    464     public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
    465 
    466     /**
    467      * A bond attempt failed because of authentication timeout
    468      * @hide
    469      */
    470     public static final int UNBOND_REASON_AUTH_TIMEOUT = 6;
    471 
    472     /**
    473      * A bond attempt failed because of repeated attempts
    474      * @hide
    475      */
    476     public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7;
    477 
    478     /**
    479      * A bond attempt failed because we received an Authentication Cancel
    480      * by remote end
    481      * @hide
    482      */
    483     public static final int UNBOND_REASON_REMOTE_AUTH_CANCELED = 8;
    484 
    485     /**
    486      * An existing bond was explicitly revoked
    487      * @hide
    488      */
    489     public static final int UNBOND_REASON_REMOVED = 9;
    490 
    491     /**
    492      * The user will be prompted to enter a pin or
    493      * an app will enter a pin for user.
    494      */
    495     public static final int PAIRING_VARIANT_PIN = 0;
    496 
    497     /**
    498      * The user will be prompted to enter a passkey
    499      * @hide
    500      */
    501     public static final int PAIRING_VARIANT_PASSKEY = 1;
    502 
    503     /**
    504      * The user will be prompted to confirm the passkey displayed on the screen or
    505      * an app will confirm the passkey for the user.
    506      */
    507     public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2;
    508 
    509     /**
    510      * The user will be prompted to accept or deny the incoming pairing request
    511      * @hide
    512      */
    513     public static final int PAIRING_VARIANT_CONSENT = 3;
    514 
    515     /**
    516      * The user will be prompted to enter the passkey displayed on remote device
    517      * This is used for Bluetooth 2.1 pairing.
    518      * @hide
    519      */
    520     public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4;
    521 
    522     /**
    523      * The user will be prompted to enter the PIN displayed on remote device.
    524      * This is used for Bluetooth 2.0 pairing.
    525      * @hide
    526      */
    527     public static final int PAIRING_VARIANT_DISPLAY_PIN = 5;
    528 
    529     /**
    530      * The user will be prompted to accept or deny the OOB pairing request
    531      * @hide
    532      */
    533     public static final int PAIRING_VARIANT_OOB_CONSENT = 6;
    534 
    535     /**
    536      * The user will be prompted to enter a 16 digit pin or
    537      * an app will enter a 16 digit pin for user.
    538      * @hide
    539      */
    540     public static final int PAIRING_VARIANT_PIN_16_DIGITS = 7;
    541 
    542     /**
    543      * Used as an extra field in {@link #ACTION_UUID} intents,
    544      * Contains the {@link android.os.ParcelUuid}s of the remote device which
    545      * is a parcelable version of {@link UUID}.
    546      */
    547     public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
    548 
    549     /** @hide */
    550     public static final String EXTRA_SDP_RECORD =
    551         "android.bluetooth.device.extra.SDP_RECORD";
    552 
    553     /** @hide */
    554     public static final String EXTRA_SDP_SEARCH_STATUS =
    555             "android.bluetooth.device.extra.SDP_SEARCH_STATUS";
    556     /**
    557      * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
    558      * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
    559      * @hide
    560      */
    561     public static final int ACCESS_UNKNOWN = 0;
    562 
    563     /**
    564      * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
    565      * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
    566      * @hide
    567      */
    568     public static final int ACCESS_ALLOWED = 1;
    569 
    570     /**
    571      * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
    572      * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
    573      * @hide
    574      */
    575     public static final int ACCESS_REJECTED = 2;
    576 
    577      /**
    578       * No preferrence of physical transport for GATT connections to remote dual-mode devices
    579       */
    580     public static final int TRANSPORT_AUTO = 0;
    581 
    582     /**
    583      * Prefer BR/EDR transport for GATT connections to remote dual-mode devices
    584      */
    585     public static final int TRANSPORT_BREDR = 1;
    586 
    587     /**
    588      * Prefer LE transport for GATT connections to remote dual-mode devices
    589      */
    590     public static final int TRANSPORT_LE = 2;
    591 
    592     /** @hide */
    593     public static final String EXTRA_MAS_INSTANCE =
    594         "android.bluetooth.device.extra.MAS_INSTANCE";
    595 
    596     /**
    597      * Lazy initialization. Guaranteed final after first object constructed, or
    598      * getService() called.
    599      * TODO: Unify implementation of sService amongst BluetoothFoo API's
    600      */
    601     private static IBluetooth sService;
    602 
    603     private final String mAddress;
    604 
    605     /*package*/ static IBluetooth getService() {
    606         synchronized (BluetoothDevice.class) {
    607             if (sService == null) {
    608                 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
    609                 sService = adapter.getBluetoothService(mStateChangeCallback);
    610             }
    611         }
    612         return sService;
    613     }
    614 
    615     static IBluetoothManagerCallback mStateChangeCallback = new IBluetoothManagerCallback.Stub() {
    616 
    617         public void onBluetoothServiceUp(IBluetooth bluetoothService)
    618                 throws RemoteException {
    619             synchronized (BluetoothDevice.class) {
    620                 if (sService == null) {
    621                     sService = bluetoothService;
    622                 }
    623             }
    624         }
    625 
    626         public void onBluetoothServiceDown()
    627             throws RemoteException {
    628             synchronized (BluetoothDevice.class) {
    629                 sService = null;
    630             }
    631         }
    632 
    633         public void onBrEdrDown()
    634         {
    635             if (DBG) Log.d(TAG, "onBrEdrDown: reached BLE ON state");
    636         }
    637     };
    638     /**
    639      * Create a new BluetoothDevice
    640      * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB",
    641      * and is validated in this constructor.
    642      * @param address valid Bluetooth MAC address
    643      * @throws RuntimeException Bluetooth is not available on this platform
    644      * @throws IllegalArgumentException address is invalid
    645      * @hide
    646      */
    647     /*package*/ BluetoothDevice(String address) {
    648         getService();  // ensures sService is initialized
    649         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
    650             throw new IllegalArgumentException(address + " is not a valid Bluetooth address");
    651         }
    652 
    653         mAddress = address;
    654     }
    655 
    656     @Override
    657     public boolean equals(Object o) {
    658         if (o instanceof BluetoothDevice) {
    659             return mAddress.equals(((BluetoothDevice)o).getAddress());
    660         }
    661         return false;
    662     }
    663 
    664     @Override
    665     public int hashCode() {
    666         return mAddress.hashCode();
    667     }
    668 
    669     /**
    670      * Returns a string representation of this BluetoothDevice.
    671      * <p>Currently this is the Bluetooth hardware address, for example
    672      * "00:11:22:AA:BB:CC". However, you should always use {@link #getAddress}
    673      * if you explicitly require the Bluetooth hardware address in case the
    674      * {@link #toString} representation changes in the future.
    675      * @return string representation of this BluetoothDevice
    676      */
    677     @Override
    678     public String toString() {
    679         return mAddress;
    680     }
    681 
    682     public int describeContents() {
    683         return 0;
    684     }
    685 
    686     public static final Parcelable.Creator<BluetoothDevice> CREATOR =
    687             new Parcelable.Creator<BluetoothDevice>() {
    688         public BluetoothDevice createFromParcel(Parcel in) {
    689             return new BluetoothDevice(in.readString());
    690         }
    691         public BluetoothDevice[] newArray(int size) {
    692             return new BluetoothDevice[size];
    693         }
    694     };
    695 
    696     public void writeToParcel(Parcel out, int flags) {
    697         out.writeString(mAddress);
    698     }
    699 
    700     /**
    701      * Returns the hardware address of this BluetoothDevice.
    702      * <p> For example, "00:11:22:AA:BB:CC".
    703      * @return Bluetooth hardware address as string
    704      */
    705     public String getAddress() {
    706         if (DBG) Log.d(TAG, "mAddress: " + mAddress);
    707         return mAddress;
    708     }
    709 
    710     /**
    711      * Get the friendly Bluetooth name of the remote device.
    712      *
    713      * <p>The local adapter will automatically retrieve remote names when
    714      * performing a device scan, and will cache them. This method just returns
    715      * the name for this device from the cache.
    716      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
    717      *
    718      * @return the Bluetooth name, or null if there was a problem.
    719      */
    720     @RequiresPermission(Manifest.permission.BLUETOOTH)
    721     public String getName() {
    722         if (sService == null) {
    723             Log.e(TAG, "BT not enabled. Cannot get Remote Device name");
    724             return null;
    725         }
    726         try {
    727             return sService.getRemoteName(this);
    728         } catch (RemoteException e) {Log.e(TAG, "", e);}
    729         return null;
    730     }
    731 
    732     /**
    733      * Get the Bluetooth device type of the remote device.
    734      *
    735      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
    736      *
    737      * @return the device type {@link #DEVICE_TYPE_CLASSIC}, {@link #DEVICE_TYPE_LE}
    738      *                         {@link #DEVICE_TYPE_DUAL}.
    739      *         {@link #DEVICE_TYPE_UNKNOWN} if it's not available
    740      */
    741     @RequiresPermission(Manifest.permission.BLUETOOTH)
    742     public int getType() {
    743         if (sService == null) {
    744             Log.e(TAG, "BT not enabled. Cannot get Remote Device type");
    745             return DEVICE_TYPE_UNKNOWN;
    746         }
    747         try {
    748             return sService.getRemoteType(this);
    749         } catch (RemoteException e) {Log.e(TAG, "", e);}
    750         return DEVICE_TYPE_UNKNOWN;
    751     }
    752 
    753     /**
    754      * Get the Bluetooth alias of the remote device.
    755      * <p>Alias is the locally modified name of a remote device.
    756      *
    757      * @return the Bluetooth alias, or null if no alias or there was a problem
    758      * @hide
    759      */
    760     public String getAlias() {
    761         if (sService == null) {
    762             Log.e(TAG, "BT not enabled. Cannot get Remote Device Alias");
    763             return null;
    764         }
    765         try {
    766             return sService.getRemoteAlias(this);
    767         } catch (RemoteException e) {Log.e(TAG, "", e);}
    768         return null;
    769     }
    770 
    771     /**
    772      * Set the Bluetooth alias of the remote device.
    773      * <p>Alias is the locally modified name of a remote device.
    774      * <p>This methoid overwrites the alias. The changed
    775      * alias is saved in the local storage so that the change
    776      * is preserved over power cycle.
    777      *
    778      * @return true on success, false on error
    779      * @hide
    780      */
    781     public boolean setAlias(String alias) {
    782         if (sService == null) {
    783             Log.e(TAG, "BT not enabled. Cannot set Remote Device name");
    784             return false;
    785         }
    786         try {
    787             return sService.setRemoteAlias(this, alias);
    788         } catch (RemoteException e) {Log.e(TAG, "", e);}
    789         return false;
    790     }
    791 
    792     /**
    793      * Get the Bluetooth alias of the remote device.
    794      * If Alias is null, get the Bluetooth name instead.
    795      * @see #getAlias()
    796      * @see #getName()
    797      *
    798      * @return the Bluetooth alias, or null if no alias or there was a problem
    799      * @hide
    800      */
    801     public String getAliasName() {
    802         String name = getAlias();
    803         if (name == null) {
    804             name = getName();
    805         }
    806         return name;
    807     }
    808 
    809     /**
    810      * Start the bonding (pairing) process with the remote device.
    811      * <p>This is an asynchronous call, it will return immediately. Register
    812      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
    813      * the bonding process completes, and its result.
    814      * <p>Android system services will handle the necessary user interactions
    815      * to confirm and complete the bonding process.
    816      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    817      *
    818      * @return false on immediate error, true if bonding will begin
    819      */
    820     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
    821     public boolean createBond() {
    822         if (sService == null) {
    823             Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device");
    824             return false;
    825         }
    826         try {
    827             Log.i(TAG, "createBond() for device " + getAddress() +
    828                     " called by pid: " + Process.myPid() +
    829                     " tid: " + Process.myTid());
    830             return sService.createBond(this, TRANSPORT_AUTO);
    831         } catch (RemoteException e) {Log.e(TAG, "", e);}
    832         return false;
    833     }
    834 
    835     /**
    836      * Start the bonding (pairing) process with the remote device using the
    837      * specified transport.
    838      *
    839      * <p>This is an asynchronous call, it will return immediately. Register
    840      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
    841      * the bonding process completes, and its result.
    842      * <p>Android system services will handle the necessary user interactions
    843      * to confirm and complete the bonding process.
    844      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    845      *
    846      * @param transport The transport to use for the pairing procedure.
    847      * @return false on immediate error, true if bonding will begin
    848      * @throws IllegalArgumentException if an invalid transport was specified
    849      * @hide
    850      */
    851     public boolean createBond(int transport) {
    852         if (sService == null) {
    853             Log.e(TAG, "BT not enabled. Cannot create bond to Remote Device");
    854             return false;
    855         }
    856         if (TRANSPORT_AUTO > transport || transport > TRANSPORT_LE)
    857         {
    858             throw new IllegalArgumentException(transport + " is not a valid Bluetooth transport");
    859         }
    860         try {
    861             Log.i(TAG, "createBond() for device " + getAddress() +
    862                     " called by pid: " + Process.myPid() +
    863                     " tid: " + Process.myTid());
    864             return sService.createBond(this, transport);
    865         } catch (RemoteException e) {Log.e(TAG, "", e);}
    866         return false;
    867     }
    868 
    869     /**
    870      * Start the bonding (pairing) process with the remote device using the
    871      * Out Of Band mechanism.
    872      *
    873      * <p>This is an asynchronous call, it will return immediately. Register
    874      * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
    875      * the bonding process completes, and its result.
    876      *
    877      * <p>Android system services will handle the necessary user interactions
    878      * to confirm and complete the bonding process.
    879      *
    880      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    881      *
    882      * @param transport - Transport to use
    883      * @param oobData - Out Of Band data
    884      * @return false on immediate error, true if bonding will begin
    885      *
    886      * @hide
    887      */
    888     public boolean createBondOutOfBand(int transport, OobData oobData) {
    889         try {
    890             return sService.createBondOutOfBand(this, transport, oobData);
    891         } catch (RemoteException e) {Log.e(TAG, "", e);}
    892         return false;
    893     }
    894 
    895     /**
    896      * Set the Out Of Band data for a remote device to be used later
    897      * in the pairing mechanism. Users can obtain this data through other
    898      * trusted channels
    899      *
    900      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    901      *
    902      * @param hash Simple Secure pairing hash
    903      * @param randomizer The random key obtained using OOB
    904      * @return false on error; true otherwise
    905      *
    906      * @hide
    907      */
    908     public boolean setDeviceOutOfBandData(byte[] hash, byte[] randomizer) {
    909       //TODO(BT)
    910       /*
    911       try {
    912         return sService.setDeviceOutOfBandData(this, hash, randomizer);
    913       } catch (RemoteException e) {Log.e(TAG, "", e);} */
    914       return false;
    915     }
    916 
    917     /**
    918      * Cancel an in-progress bonding request started with {@link #createBond}.
    919      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    920      *
    921      * @return true on success, false on error
    922      * @hide
    923      */
    924     public boolean cancelBondProcess() {
    925         if (sService == null) {
    926             Log.e(TAG, "BT not enabled. Cannot cancel Remote Device bond");
    927             return false;
    928         }
    929         try {
    930             Log.i(TAG, "cancelBondProcess() for device " + getAddress() +
    931                     " called by pid: " + Process.myPid() +
    932                     " tid: " + Process.myTid());
    933             return sService.cancelBondProcess(this);
    934         } catch (RemoteException e) {Log.e(TAG, "", e);}
    935         return false;
    936     }
    937 
    938     /**
    939      * Remove bond (pairing) with the remote device.
    940      * <p>Delete the link key associated with the remote device, and
    941      * immediately terminate connections to that device that require
    942      * authentication and encryption.
    943      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
    944      *
    945      * @return true on success, false on error
    946      * @hide
    947      */
    948     public boolean removeBond() {
    949         if (sService == null) {
    950             Log.e(TAG, "BT not enabled. Cannot remove Remote Device bond");
    951             return false;
    952         }
    953         try {
    954             Log.i(TAG, "removeBond() for device " + getAddress() +
    955                     " called by pid: " + Process.myPid() +
    956                     " tid: " + Process.myTid());
    957             return sService.removeBond(this);
    958         } catch (RemoteException e) {Log.e(TAG, "", e);}
    959         return false;
    960     }
    961 
    962     /**
    963      * Get the bond state of the remote device.
    964      * <p>Possible values for the bond state are:
    965      * {@link #BOND_NONE},
    966      * {@link #BOND_BONDING},
    967      * {@link #BOND_BONDED}.
    968      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
    969      *
    970      * @return the bond state
    971      */
    972     @RequiresPermission(Manifest.permission.BLUETOOTH)
    973     public int getBondState() {
    974         if (sService == null) {
    975             Log.e(TAG, "BT not enabled. Cannot get bond state");
    976             return BOND_NONE;
    977         }
    978         try {
    979             return sService.getBondState(this);
    980         } catch (RemoteException e) {Log.e(TAG, "", e);}
    981         catch (NullPointerException npe) {
    982             // Handle case where bluetooth service proxy
    983             // is already null.
    984             Log.e(TAG, "NullPointerException for getBondState() of device ("+
    985                 getAddress()+")", npe);
    986         }
    987         return BOND_NONE;
    988     }
    989 
    990     /**
    991      * Returns whether there is an open connection to this device.
    992      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
    993      *
    994      * @return True if there is at least one open connection to this device.
    995      * @hide
    996      */
    997     @SystemApi
    998     public boolean isConnected() {
    999         if (sService == null) {
   1000             // BT is not enabled, we cannot be connected.
   1001             return false;
   1002         }
   1003         try {
   1004             return sService.getConnectionState(this) != CONNECTION_STATE_DISCONNECTED;
   1005         } catch (RemoteException e) {
   1006             Log.e(TAG, "", e);
   1007             return false;
   1008         }
   1009     }
   1010 
   1011     /**
   1012      * Returns whether there is an open connection to this device
   1013      * that has been encrypted.
   1014      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
   1015      *
   1016      * @return True if there is at least one encrypted connection to this device.
   1017      * @hide
   1018      */
   1019     @SystemApi
   1020     public boolean isEncrypted() {
   1021         if (sService == null) {
   1022             // BT is not enabled, we cannot be connected.
   1023             return false;
   1024         }
   1025         try {
   1026             return sService.getConnectionState(this) > CONNECTION_STATE_CONNECTED;
   1027         } catch (RemoteException e) {
   1028             Log.e(TAG, "", e);
   1029             return false;
   1030         }
   1031     }
   1032 
   1033     /**
   1034      * Get the Bluetooth class of the remote device.
   1035      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
   1036      *
   1037      * @return Bluetooth class object, or null on error
   1038      */
   1039     @RequiresPermission(Manifest.permission.BLUETOOTH)
   1040     public BluetoothClass getBluetoothClass() {
   1041         if (sService == null) {
   1042             Log.e(TAG, "BT not enabled. Cannot get Bluetooth Class");
   1043             return null;
   1044         }
   1045         try {
   1046             int classInt = sService.getRemoteClass(this);
   1047             if (classInt == BluetoothClass.ERROR) return null;
   1048             return new BluetoothClass(classInt);
   1049         } catch (RemoteException e) {Log.e(TAG, "", e);}
   1050         return null;
   1051     }
   1052 
   1053     /**
   1054      * Returns the supported features (UUIDs) of the remote device.
   1055      *
   1056      * <p>This method does not start a service discovery procedure to retrieve the UUIDs
   1057      * from the remote device. Instead, the local cached copy of the service
   1058      * UUIDs are returned.
   1059      * <p>Use {@link #fetchUuidsWithSdp} if fresh UUIDs are desired.
   1060      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
   1061      *
   1062      * @return the supported features (UUIDs) of the remote device,
   1063      *         or null on error
   1064      */
   1065     @RequiresPermission(Manifest.permission.BLUETOOTH)
   1066      public ParcelUuid[] getUuids() {
   1067          if (sService == null || isBluetoothEnabled() == false) {
   1068             Log.e(TAG, "BT not enabled. Cannot get remote device Uuids");
   1069              return null;
   1070          }
   1071         try {
   1072             return sService.getRemoteUuids(this);
   1073         } catch (RemoteException e) {Log.e(TAG, "", e);}
   1074         return null;
   1075     }
   1076 
   1077      /**
   1078       * Perform a service discovery on the remote device to get the UUIDs supported.
   1079       *
   1080       * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent,
   1081       * with the UUIDs supported by the remote end. If there is an error
   1082       * in getting the SDP records or if the process takes a long time,
   1083       * {@link #ACTION_UUID} intent is sent with the UUIDs that is currently
   1084       * present in the cache. Clients should use the {@link #getUuids} to get UUIDs
   1085       * if service discovery is not to be performed.
   1086       * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
   1087       *
   1088       * @return False if the sanity check fails, True if the process
   1089       *               of initiating an ACL connection to the remote device
   1090       *               was started.
   1091       */
   1092      @RequiresPermission(Manifest.permission.BLUETOOTH)
   1093      public boolean fetchUuidsWithSdp() {
   1094         IBluetooth service = sService;
   1095         if (service == null || isBluetoothEnabled() == false) {
   1096             Log.e(TAG, "BT not enabled. Cannot fetchUuidsWithSdp");
   1097             return false;
   1098         }
   1099         try {
   1100             return service.fetchRemoteUuids(this);
   1101         } catch (RemoteException e) {Log.e(TAG, "", e);}
   1102             return false;
   1103     }
   1104 
   1105      /**
   1106       * Perform a service discovery on the remote device to get the SDP records associated
   1107       * with the specified UUID.
   1108       *
   1109       * <p>This API is asynchronous and {@link #ACTION_SDP_RECORD} intent is sent,
   1110       * with the SDP records found on the remote end. If there is an error
   1111       * in getting the SDP records or if the process takes a long time,
   1112       * {@link #ACTION_SDP_RECORD} intent is sent with an status value in
   1113       * {@link #EXTRA_SDP_SEARCH_STATUS} different from 0.
   1114       * Detailed status error codes can be found by members of the Bluetooth package in
   1115       * the AbstractionLayer class.
   1116       * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
   1117       * The SDP record data will be stored in the intent as {@link #EXTRA_SDP_RECORD}.
   1118       * The object type will match one of the SdpXxxRecord types, depending on the UUID searched
   1119       * for.
   1120       *
   1121       * @return False if the sanity check fails, True if the process
   1122       *               of initiating an ACL connection to the remote device
   1123       *               was started.
   1124       */
   1125      /** @hide */
   1126      public boolean sdpSearch(ParcelUuid uuid) {
   1127          if (sService == null) {
   1128              Log.e(TAG, "BT not enabled. Cannot query remote device sdp records");
   1129              return false;
   1130          }
   1131          try {
   1132              return sService.sdpSearch(this,uuid);
   1133          } catch (RemoteException e) {Log.e(TAG, "", e);}
   1134          return false;
   1135      }
   1136 
   1137     /**
   1138      * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
   1139      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
   1140      *
   1141      * @return true pin has been set
   1142      *         false for error
   1143      */
   1144     public boolean setPin(byte[] pin) {
   1145         if (sService == null) {
   1146             Log.e(TAG, "BT not enabled. Cannot set Remote Device pin");
   1147             return false;
   1148         }
   1149         try {
   1150             return sService.setPin(this, true, pin.length, pin);
   1151         } catch (RemoteException e) {Log.e(TAG, "", e);}
   1152         return false;
   1153     }
   1154 
   1155     /** @hide */
   1156     public boolean setPasskey(int passkey) {
   1157         //TODO(BT)
   1158         /*
   1159         try {
   1160             return sService.setPasskey(this, true, 4, passkey);
   1161         } catch (RemoteException e) {Log.e(TAG, "", e);}*/
   1162         return false;
   1163     }
   1164 
   1165     /**
   1166      * Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing.
   1167      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
   1168      *
   1169      * @return true confirmation has been sent out
   1170      *         false for error
   1171      */
   1172     @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
   1173     public boolean setPairingConfirmation(boolean confirm) {
   1174         if (sService == null) {
   1175             Log.e(TAG, "BT not enabled. Cannot set pairing confirmation");
   1176             return false;
   1177         }
   1178         try {
   1179             return sService.setPairingConfirmation(this, confirm);
   1180         } catch (RemoteException e) {Log.e(TAG, "", e);}
   1181         return false;
   1182     }
   1183 
   1184     /** @hide */
   1185     public boolean setRemoteOutOfBandData() {
   1186         // TODO(BT)
   1187         /*
   1188         try {
   1189           return sService.setRemoteOutOfBandData(this);
   1190       } catch (RemoteException e) {Log.e(TAG, "", e);}*/
   1191       return false;
   1192     }
   1193 
   1194     /** @hide */
   1195     public boolean cancelPairingUserInput() {
   1196         if (sService == null) {
   1197             Log.e(TAG, "BT not enabled. Cannot create pairing user input");
   1198             return false;
   1199         }
   1200         try {
   1201             return sService.cancelBondProcess(this);
   1202         } catch (RemoteException e) {Log.e(TAG, "", e);}
   1203         return false;
   1204     }
   1205 
   1206     /** @hide */
   1207     public boolean isBluetoothDock() {
   1208         // TODO(BT)
   1209         /*
   1210         try {
   1211             return sService.isBluetoothDock(this);
   1212         } catch (RemoteException e) {Log.e(TAG, "", e);}*/
   1213         return false;
   1214     }
   1215 
   1216      boolean isBluetoothEnabled() {
   1217          boolean ret = false;
   1218          BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
   1219          if (adapter != null && adapter.isEnabled() == true) {
   1220              ret = true;
   1221          }
   1222          return ret;
   1223      }
   1224 
   1225     /**
   1226      * Requires {@link android.Manifest.permission#BLUETOOTH}.
   1227      * @return Whether the phonebook access is allowed to this device. Can be
   1228      *         {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
   1229      * @hide
   1230      */
   1231     public int getPhonebookAccessPermission() {
   1232         if (sService == null) {
   1233             return ACCESS_UNKNOWN;
   1234         }
   1235         try {
   1236             return sService.getPhonebookAccessPermission(this);
   1237         } catch (RemoteException e) {
   1238             Log.e(TAG, "", e);
   1239         }
   1240         return ACCESS_UNKNOWN;
   1241     }
   1242 
   1243     /**
   1244      * Sets whether the phonebook access is allowed to this device.
   1245      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
   1246      * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or
   1247      *              {@link #ACCESS_REJECTED}.
   1248      * @return Whether the value has been successfully set.
   1249      * @hide
   1250      */
   1251     public boolean setPhonebookAccessPermission(int value) {
   1252         if (sService == null) {
   1253             return false;
   1254         }
   1255         try {
   1256             return sService.setPhonebookAccessPermission(this, value);
   1257         } catch (RemoteException e) {
   1258             Log.e(TAG, "", e);
   1259         }
   1260         return false;
   1261     }
   1262 
   1263     /**
   1264      * Requires {@link android.Manifest.permission#BLUETOOTH}.
   1265      * @return Whether the message access is allowed to this device. Can be
   1266      *         {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
   1267      * @hide
   1268      */
   1269     public int getMessageAccessPermission() {
   1270         if (sService == null) {
   1271             return ACCESS_UNKNOWN;
   1272         }
   1273         try {
   1274             return sService.getMessageAccessPermission(this);
   1275         } catch (RemoteException e) {
   1276             Log.e(TAG, "", e);
   1277         }
   1278         return ACCESS_UNKNOWN;
   1279     }
   1280 
   1281     /**
   1282      * Sets whether the message access is allowed to this device.
   1283      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
   1284      * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or
   1285      *              {@link #ACCESS_REJECTED}.
   1286      * @return Whether the value has been successfully set.
   1287      * @hide
   1288      */
   1289     public boolean setMessageAccessPermission(int value) {
   1290         if (sService == null) {
   1291             return false;
   1292         }
   1293         try {
   1294             return sService.setMessageAccessPermission(this, value);
   1295         } catch (RemoteException e) {
   1296             Log.e(TAG, "", e);
   1297         }
   1298         return false;
   1299     }
   1300 
   1301     /**
   1302      * Requires {@link android.Manifest.permission#BLUETOOTH}.
   1303      * @return Whether the Sim access is allowed to this device. Can be
   1304      *         {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
   1305      * @hide
   1306      */
   1307     public int getSimAccessPermission() {
   1308         if (sService == null) {
   1309             return ACCESS_UNKNOWN;
   1310         }
   1311         try {
   1312             return sService.getSimAccessPermission(this);
   1313         } catch (RemoteException e) {
   1314             Log.e(TAG, "", e);
   1315         }
   1316         return ACCESS_UNKNOWN;
   1317     }
   1318 
   1319     /**
   1320      * Sets whether the Sim access is allowed to this device.
   1321      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
   1322      * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or
   1323      *              {@link #ACCESS_REJECTED}.
   1324      * @return Whether the value has been successfully set.
   1325      * @hide
   1326      */
   1327     public boolean setSimAccessPermission(int value) {
   1328         if (sService == null) {
   1329             return false;
   1330         }
   1331         try {
   1332             return sService.setSimAccessPermission(this, value);
   1333         } catch (RemoteException e) {
   1334             Log.e(TAG, "", e);
   1335         }
   1336         return false;
   1337     }
   1338 
   1339     /**
   1340      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
   1341      * outgoing connection to this remote device on given channel.
   1342      * <p>The remote device will be authenticated and communication on this
   1343      * socket will be encrypted.
   1344      * <p> Use this socket only if an authenticated socket link is possible.
   1345      * Authentication refers to the authentication of the link key to
   1346      * prevent man-in-the-middle type of attacks.
   1347      * For example, for Bluetooth 2.1 devices, if any of the devices does not
   1348      * have an input and output capability or just has the ability to
   1349      * display a numeric key, a secure socket connection is not possible.
   1350      * In such a case, use {#link createInsecureRfcommSocket}.
   1351      * For more details, refer to the Security Model section 5.2 (vol 3) of
   1352      * Bluetooth Core Specification version 2.1 + EDR.
   1353      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
   1354      * connection.
   1355      * <p>Valid RFCOMM channels are in range 1 to 30.
   1356      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
   1357      *
   1358      * @param channel RFCOMM channel to connect to
   1359      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
   1360      * @throws IOException on error, for example Bluetooth not available, or
   1361      *                     insufficient permissions
   1362      * @hide
   1363      */
   1364     public BluetoothSocket createRfcommSocket(int channel) throws IOException {
   1365         if (isBluetoothEnabled() == false) {
   1366             Log.e(TAG, "Bluetooth is not enabled");
   1367             throw new IOException();
   1368         }
   1369         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel,
   1370                 null);
   1371     }
   1372 
   1373     /**
   1374      * Create an L2cap {@link BluetoothSocket} ready to start a secure
   1375      * outgoing connection to this remote device on given channel.
   1376      * <p>The remote device will be authenticated and communication on this
   1377      * socket will be encrypted.
   1378      * <p> Use this socket only if an authenticated socket link is possible.
   1379      * Authentication refers to the authentication of the link key to
   1380      * prevent man-in-the-middle type of attacks.
   1381      * For example, for Bluetooth 2.1 devices, if any of the devices does not
   1382      * have an input and output capability or just has the ability to
   1383      * display a numeric key, a secure socket connection is not possible.
   1384      * In such a case, use {#link createInsecureRfcommSocket}.
   1385      * For more details, refer to the Security Model section 5.2 (vol 3) of
   1386      * Bluetooth Core Specification version 2.1 + EDR.
   1387      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
   1388      * connection.
   1389      * <p>Valid L2CAP PSM channels are in range 1 to 2^16.
   1390      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
   1391      *
   1392      * @param channel L2cap PSM/channel to connect to
   1393      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
   1394      * @throws IOException on error, for example Bluetooth not available, or
   1395      *                     insufficient permissions
   1396      * @hide
   1397      */
   1398     public BluetoothSocket createL2capSocket(int channel) throws IOException {
   1399         return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, true, true, this, channel,
   1400                 null);
   1401     }
   1402 
   1403     /**
   1404      * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
   1405      * outgoing connection to this remote device using SDP lookup of uuid.
   1406      * <p>This is designed to be used with {@link
   1407      * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer
   1408      * Bluetooth applications.
   1409      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
   1410      * connection. This will also perform an SDP lookup of the given uuid to
   1411      * determine which channel to connect to.
   1412      * <p>The remote device will be authenticated and communication on this
   1413      * socket will be encrypted.
   1414      * <p> Use this socket only if an authenticated socket link is possible.
   1415      * Authentication refers to the authentication of the link key to
   1416      * prevent man-in-the-middle type of attacks.
   1417      * For example, for Bluetooth 2.1 devices, if any of the devices does not
   1418      * have an input and output capability or just has the ability to
   1419      * display a numeric key, a secure socket connection is not possible.
   1420      * In such a case, use {#link createInsecureRfcommSocketToServiceRecord}.
   1421      * For more details, refer to the Security Model section 5.2 (vol 3) of
   1422      * Bluetooth Core Specification version 2.1 + EDR.
   1423      * <p>Hint: If you are connecting to a Bluetooth serial board then try
   1424      * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
   1425      * However if you are connecting to an Android peer then please generate
   1426      * your own unique UUID.
   1427      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
   1428      *
   1429      * @param uuid service record uuid to lookup RFCOMM channel
   1430      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
   1431      * @throws IOException on error, for example Bluetooth not available, or
   1432      *                     insufficient permissions
   1433      */
   1434     @RequiresPermission(Manifest.permission.BLUETOOTH)
   1435     public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {
   1436         if (isBluetoothEnabled() == false) {
   1437             Log.e(TAG, "Bluetooth is not enabled");
   1438             throw new IOException();
   1439         }
   1440 
   1441         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1,
   1442                 new ParcelUuid(uuid));
   1443     }
   1444 
   1445     /**
   1446      * Create an RFCOMM {@link BluetoothSocket} socket ready to start an insecure
   1447      * outgoing connection to this remote device using SDP lookup of uuid.
   1448      * <p> The communication channel will not have an authenticated link key
   1449      * i.e it will be subject to man-in-the-middle attacks. For Bluetooth 2.1
   1450      * devices, the link key will be encrypted, as encryption is mandatory.
   1451      * For legacy devices (pre Bluetooth 2.1 devices) the link key will
   1452      * be not be encrypted. Use {@link #createRfcommSocketToServiceRecord} if an
   1453      * encrypted and authenticated communication channel is desired.
   1454      * <p>This is designed to be used with {@link
   1455      * BluetoothAdapter#listenUsingInsecureRfcommWithServiceRecord} for peer-peer
   1456      * Bluetooth applications.
   1457      * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
   1458      * connection. This will also perform an SDP lookup of the given uuid to
   1459      * determine which channel to connect to.
   1460      * <p>The remote device will be authenticated and communication on this
   1461      * socket will be encrypted.
   1462      * <p>Hint: If you are connecting to a Bluetooth serial board then try
   1463      * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
   1464      * However if you are connecting to an Android peer then please generate
   1465      * your own unique UUID.
   1466      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
   1467      *
   1468      * @param uuid service record uuid to lookup RFCOMM channel
   1469      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
   1470      * @throws IOException on error, for example Bluetooth not available, or
   1471      *                     insufficient permissions
   1472      */
   1473     @RequiresPermission(Manifest.permission.BLUETOOTH)
   1474     public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException {
   1475         if (isBluetoothEnabled() == false) {
   1476             Log.e(TAG, "Bluetooth is not enabled");
   1477             throw new IOException();
   1478         }
   1479         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1,
   1480                 new ParcelUuid(uuid));
   1481     }
   1482 
   1483     /**
   1484      * Construct an insecure RFCOMM socket ready to start an outgoing
   1485      * connection.
   1486      * Call #connect on the returned #BluetoothSocket to begin the connection.
   1487      * The remote device will not be authenticated and communication on this
   1488      * socket will not be encrypted.
   1489      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
   1490      *
   1491      * @param port    remote port
   1492      * @return An RFCOMM BluetoothSocket
   1493      * @throws IOException On error, for example Bluetooth not available, or
   1494      *                     insufficient permissions.
   1495      * @hide
   1496      */
   1497     public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
   1498 
   1499         if (isBluetoothEnabled() == false) {
   1500             Log.e(TAG, "Bluetooth is not enabled");
   1501             throw new IOException();
   1502         }
   1503         return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port,
   1504                 null);
   1505     }
   1506 
   1507     /**
   1508      * Construct a SCO socket ready to start an outgoing connection.
   1509      * Call #connect on the returned #BluetoothSocket to begin the connection.
   1510      * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
   1511      *
   1512      * @return a SCO BluetoothSocket
   1513      * @throws IOException on error, for example Bluetooth not available, or
   1514      *                     insufficient permissions.
   1515      * @hide
   1516      */
   1517     public BluetoothSocket createScoSocket() throws IOException {
   1518 
   1519         if (isBluetoothEnabled() == false) {
   1520             Log.e(TAG, "Bluetooth is not enabled");
   1521             throw new IOException();
   1522         }
   1523         return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null);
   1524     }
   1525 
   1526     /**
   1527      * Check that a pin is valid and convert to byte array.
   1528      *
   1529      * Bluetooth pin's are 1 to 16 bytes of UTF-8 characters.
   1530      * @param pin pin as java String
   1531      * @return the pin code as a UTF-8 byte array, or null if it is an invalid
   1532      *         Bluetooth pin.
   1533      * @hide
   1534      */
   1535     public static byte[] convertPinToBytes(String pin) {
   1536         if (pin == null) {
   1537             return null;
   1538         }
   1539         byte[] pinBytes;
   1540         try {
   1541             pinBytes = pin.getBytes("UTF-8");
   1542         } catch (UnsupportedEncodingException uee) {
   1543             Log.e(TAG, "UTF-8 not supported?!?");  // this should not happen
   1544             return null;
   1545         }
   1546         if (pinBytes.length <= 0 || pinBytes.length > 16) {
   1547             return null;
   1548         }
   1549         return pinBytes;
   1550     }
   1551 
   1552     /**
   1553      * Connect to GATT Server hosted by this device. Caller acts as GATT client.
   1554      * The callback is used to deliver results to Caller, such as connection status as well
   1555      * as any further GATT client operations.
   1556      * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
   1557      * GATT client operations.
   1558      * @param callback GATT callback handler that will receive asynchronous callbacks.
   1559      * @param autoConnect Whether to directly connect to the remote device (false)
   1560      *                    or to automatically connect as soon as the remote
   1561      *                    device becomes available (true).
   1562      * @throws IllegalArgumentException if callback is null
   1563      */
   1564     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
   1565                                      BluetoothGattCallback callback) {
   1566         return (connectGatt(context, autoConnect,callback, TRANSPORT_AUTO));
   1567     }
   1568 
   1569     /**
   1570      * Connect to GATT Server hosted by this device. Caller acts as GATT client.
   1571      * The callback is used to deliver results to Caller, such as connection status as well
   1572      * as any further GATT client operations.
   1573      * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
   1574      * GATT client operations.
   1575      * @param callback GATT callback handler that will receive asynchronous callbacks.
   1576      * @param autoConnect Whether to directly connect to the remote device (false)
   1577      *                    or to automatically connect as soon as the remote
   1578      *                    device becomes available (true).
   1579      * @param transport preferred transport for GATT connections to remote dual-mode devices
   1580      *             {@link BluetoothDevice#TRANSPORT_AUTO} or
   1581      *             {@link BluetoothDevice#TRANSPORT_BREDR} or {@link BluetoothDevice#TRANSPORT_LE}
   1582      * @throws IllegalArgumentException if callback is null
   1583      */
   1584     public BluetoothGatt connectGatt(Context context, boolean autoConnect,
   1585                                      BluetoothGattCallback callback, int transport) {
   1586         // TODO(Bluetooth) check whether platform support BLE
   1587         //     Do the check here or in GattServer?
   1588         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
   1589         IBluetoothManager managerService = adapter.getBluetoothManager();
   1590         try {
   1591             IBluetoothGatt iGatt = managerService.getBluetoothGatt();
   1592             if (iGatt == null) {
   1593                 // BLE is not supported
   1594                 return null;
   1595             }
   1596             BluetoothGatt gatt = new BluetoothGatt(context, iGatt, this, transport);
   1597             gatt.connect(autoConnect, callback);
   1598             return gatt;
   1599         } catch (RemoteException e) {Log.e(TAG, "", e);}
   1600         return null;
   1601     }
   1602 }
   1603