summaryrefslogtreecommitdiffstats
path: root/core/java/android/bluetooth/BluetoothDevice.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/bluetooth/BluetoothDevice.java')
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java943
1 files changed, 547 insertions, 396 deletions
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 951b4b0..6cb9770 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,515 +16,689 @@
package android.bluetooth;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ParcelUuid;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.util.Log;
+import java.io.IOException;
import java.io.UnsupportedEncodingException;
+import java.util.UUID;
/**
- * The Android Bluetooth API is not finalized, and *will* change. Use at your
- * own risk.
+ * Represents a remote Bluetooth device. A {@link BluetoothDevice} lets you
+ * create a connection with the repective device or query information about
+ * it, such as the name, address, class, and bonding state.
*
- * Manages the local Bluetooth device. Scan for devices, create bondings,
- * power up and down the adapter.
+ * <p>This class is really just a thin wrapper for a Bluetooth hardware
+ * address. Objects of this class are immutable. Operations on this class
+ * are performed on the remote Bluetooth hardware address, using the
+ * {@link BluetoothAdapter} that was used to create this {@link
+ * BluetoothDevice}.
*
- * @hide
+ * <p>To get a {@link BluetoothDevice}, use
+ * {@link BluetoothAdapter#getRemoteDevice(String)
+ * BluetoothAdapter.getRemoteDevice(String)} to create one representing a device
+ * of a known MAC address (which you can get through device discovery with
+ * {@link BluetoothAdapter}) or get one from the set of bonded devices
+ * returned by {@link BluetoothAdapter#getBondedDevices()
+ * BluetoothAdapter.getBondedDevices()}. You can then open a
+ * {@link BluetoothSocket} for communciation with the remote device, using
+ * {@link #createRfcommSocketToServiceRecord(UUID)}.
+ *
+ * <p class="note"><strong>Note:</strong>
+ * Requires the {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * {@see BluetoothAdapter}
+ * {@see BluetoothSocket}
*/
-public class BluetoothDevice {
-
- public static final int BLUETOOTH_STATE_OFF = 0;
- public static final int BLUETOOTH_STATE_TURNING_ON = 1;
- public static final int BLUETOOTH_STATE_ON = 2;
- public static final int BLUETOOTH_STATE_TURNING_OFF = 3;
-
- /** Inquiry scan and page scan are both off.
- * Device is neither discoverable nor connectable */
- public static final int SCAN_MODE_NONE = 0;
- /** Page scan is on, inquiry scan is off.
- * Device is connectable, but not discoverable */
- public static final int SCAN_MODE_CONNECTABLE = 1;
- /** Page scan and inquiry scan are on.
- * Device is connectable and discoverable */
- public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 3;
-
- public static final int RESULT_FAILURE = -1;
- public static final int RESULT_SUCCESS = 0;
-
- /** We do not have a link key for the remote device, and are therefore not
- * bonded */
- public static final int BOND_NOT_BONDED = 0;
- /** We have a link key for the remote device, and are probably bonded. */
- public static final int BOND_BONDED = 1;
- /** We are currently attempting bonding */
- public static final int BOND_BONDING = 2;
-
- //TODO: Unify these result codes in BluetoothResult or BluetoothError
- /** A bond attempt failed because pins did not match, or remote device did
- * not respond to pin request in time */
- public static final int UNBOND_REASON_AUTH_FAILED = 1;
- /** A bond attempt failed because the other side explicilty rejected
- * bonding */
- public static final int UNBOND_REASON_AUTH_REJECTED = 2;
- /** A bond attempt failed because we canceled the bonding process */
- public static final int UNBOND_REASON_AUTH_CANCELED = 3;
- /** A bond attempt failed because we could not contact the remote device */
- public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
- /** A bond attempt failed because a discovery is in progress */
- public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
- /** An existing bond was explicitly revoked */
- public static final int UNBOND_REASON_REMOVED = 6;
-
+public final class BluetoothDevice implements Parcelable {
private static final String TAG = "BluetoothDevice";
-
- private final IBluetoothDevice mService;
+
/**
- * @hide - hide this because it takes a parameter of type
- * IBluetoothDevice, which is a System private class.
- * Also note that Context.getSystemService is a factory that
- * returns a BlueToothDevice. That is the right way to get
- * a BluetoothDevice.
+ * Sentinel error value for this class. Guaranteed to not equal any other
+ * integer constant in this class. Provided as a convenience for functions
+ * that require a sentinel error value, for example:
+ * <p><code>Intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
+ * BluetoothDevice.ERROR)</code>
*/
- public BluetoothDevice(IBluetoothDevice service) {
- mService = service;
- }
+ public static final int ERROR = Integer.MIN_VALUE;
/**
- * Is Bluetooth currently turned on.
- *
- * @return true if Bluetooth enabled, false otherwise.
+ * Broadcast Action: Remote device discovered.
+ * <p>Sent when a remote device is found during discovery.
+ * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
+ * #EXTRA_CLASS}. Can contain the extra fields {@link #EXTRA_NAME} and/or
+ * {@link #EXTRA_RSSI} if they are available.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*/
- public boolean isEnabled() {
- try {
- return mService.isEnabled();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
+ // TODO: Change API to not broadcast RSSI if not available (incoming connection)
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_FOUND =
+ "android.bluetooth.device.action.FOUND";
/**
- * Get the current state of Bluetooth.
- *
- * @return One of BLUETOOTH_STATE_ or BluetoothError.ERROR.
+ * Broadcast Action: Remote device disappeared.
+ * <p>Sent when a remote device that was found in the last discovery is not
+ * found in the current discovery.
+ * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+ * @hide
*/
- public int getBluetoothState() {
- try {
- return mService.getBluetoothState();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return BluetoothError.ERROR;
- }
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_DISAPPEARED =
+ "android.bluetooth.device.action.DISAPPEARED";
/**
- * Enable the Bluetooth device.
- * Turn on the underlying hardware.
- * This is an asynchronous call,
- * BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION can be used to check if
- * and when the device is sucessfully enabled.
- * @return false if we cannot enable the Bluetooth device. True does not
- * imply the device was enabled, it only implies that so far there were no
- * problems.
+ * Broadcast Action: Bluetooth class of a remote device has changed.
+ * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
+ * #EXTRA_CLASS}.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+ * @see {@link BluetoothClass}
*/
- public boolean enable() {
- try {
- return mService.enable();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_CLASS_CHANGED =
+ "android.bluetooth.device.action.CLASS_CHANGED";
/**
- * Disable the Bluetooth device.
- * This turns off the underlying hardware.
- *
- * @return true if successful, false otherwise.
+ * Broadcast Action: Indicates a low level (ACL) connection has been
+ * established with a remote device.
+ * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
+ * <p>ACL connections are managed automatically by the Android Bluetooth
+ * stack.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*/
- public boolean disable() {
- try {
- return mService.disable(true);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_ACL_CONNECTED =
+ "android.bluetooth.device.action.ACL_CONNECTED";
- public String getAddress() {
- try {
- return mService.getAddress();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
+ /**
+ * Broadcast Action: Indicates that a low level (ACL) disconnection has
+ * been requested for a remote device, and it will soon be disconnected.
+ * <p>This is useful for graceful disconnection. Applications should use
+ * this intent as a hint to immediately terminate higher level connections
+ * (RFCOMM, L2CAP, or profile connections) to the remote device.
+ * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_ACL_DISCONNECT_REQUESTED =
+ "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED";
/**
- * Get the friendly Bluetooth name of this device.
- *
- * This name is visible to remote Bluetooth devices. Currently it is only
- * possible to retrieve the Bluetooth name when Bluetooth is enabled.
- *
- * @return the Bluetooth name, or null if there was a problem.
+ * Broadcast Action: Indicates a low level (ACL) disconnection from a
+ * remote device.
+ * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
+ * <p>ACL connections are managed automatically by the Android Bluetooth
+ * stack.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*/
- public String getName() {
- try {
- return mService.getName();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_ACL_DISCONNECTED =
+ "android.bluetooth.device.action.ACL_DISCONNECTED";
/**
- * Set the friendly Bluetooth name of this device.
- *
- * This name is visible to remote Bluetooth devices. The Bluetooth Service
- * is responsible for persisting this name.
- *
- * @param name the name to set
- * @return true, if the name was successfully set. False otherwise.
+ * Broadcast Action: Indicates the friendly name of a remote device has
+ * been retrieved for the first time, or changed since the last retrieval.
+ * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
+ * #EXTRA_NAME}.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*/
- public boolean setName(String name) {
- try {
- return mService.setName(name);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_NAME_CHANGED =
+ "android.bluetooth.device.action.NAME_CHANGED";
- public String getVersion() {
- try {
- return mService.getVersion();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
- public String getRevision() {
- try {
- return mService.getRevision();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
- public String getManufacturer() {
- try {
- return mService.getManufacturer();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
- public String getCompany() {
- try {
- return mService.getCompany();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
+ /**
+ * Broadcast Action: Indicates a change in the bond state of a remote
+ * device. For example, if a device is bonded (paired).
+ * <p>Always contains the extra fields {@link #EXTRA_DEVICE}, {@link
+ * #EXTRA_BOND_STATE} and {@link #EXTRA_PREVIOUS_BOND_STATE}.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+ */
+ // Note: When EXTRA_BOND_STATE is BOND_NONE then this will also
+ // contain a hidden extra field EXTRA_REASON with the result code.
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_BOND_STATE_CHANGED =
+ "android.bluetooth.device.action.BOND_STATE_CHANGED";
/**
- * Get the current scan mode.
- * Used to determine if the local device is connectable and/or discoverable
- * @return Scan mode, one of SCAN_MODE_* or an error code
+ * Used as a Parcelable {@link BluetoothDevice} extra field in every intent
+ * broadcast by this class. It contains the {@link BluetoothDevice} that
+ * the intent applies to.
*/
- public int getScanMode() {
- try {
- return mService.getScanMode();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return BluetoothError.ERROR_IPC;
- }
+ public static final String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
/**
- * Set the current scan mode.
- * Used to make the local device connectable and/or discoverable
- * @param scanMode One of SCAN_MODE_*
+ * Used as a String extra field in {@link #ACTION_NAME_CHANGED} and {@link
+ * #ACTION_FOUND} intents. It contains the friendly Bluetooth name.
*/
- public void setScanMode(int scanMode) {
- try {
- mService.setScanMode(scanMode);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- }
+ public static final String EXTRA_NAME = "android.bluetooth.device.extra.NAME";
- public int getDiscoverableTimeout() {
- try {
- return mService.getDiscoverableTimeout();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return -1;
- }
- public void setDiscoverableTimeout(int timeout) {
- try {
- mService.setDiscoverableTimeout(timeout);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
+ /**
+ * Used as an optional short extra field in {@link #ACTION_FOUND} intents.
+ * Contains the RSSI value of the remote device as reported by the
+ * Bluetooth hardware.
+ */
+ public static final String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI";
+
+ /**
+ * Used as an Parcelable {@link BluetoothClass} extra field in {@link
+ * #ACTION_FOUND} and {@link #ACTION_CLASS_CHANGED} intents.
+ */
+ public static final String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS";
+
+ /**
+ * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
+ * Contains the bond state of the remote device.
+ * <p>Possible values are:
+ * {@link #BOND_NONE},
+ * {@link #BOND_BONDING},
+ * {@link #BOND_BONDED}.
+ */
+ public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE";
+ /**
+ * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
+ * Contains the previous bond state of the remote device.
+ * <p>Possible values are:
+ * {@link #BOND_NONE},
+ * {@link #BOND_BONDING},
+ * {@link #BOND_BONDED}.
+ */
+ public static final String EXTRA_PREVIOUS_BOND_STATE =
+ "android.bluetooth.device.extra.PREVIOUS_BOND_STATE";
+ /**
+ * Indicates the remote device is not bonded (paired).
+ * <p>There is no shared link key with the remote device, so communication
+ * (if it is allowed at all) will be unauthenticated and unencrypted.
+ */
+ public static final int BOND_NONE = 10;
+ /**
+ * Indicates bonding (pairing) is in progress with the remote device.
+ */
+ public static final int BOND_BONDING = 11;
+ /**
+ * Indicates the remote device is bonded (paired).
+ * <p>A shared link keys exists locally for the remote device, so
+ * communication can be authenticated and encrypted.
+ * <p><i>Being bonded (paired) with a remote device does not necessarily
+ * mean the device is currently connected. It just means that the ponding
+ * procedure was compeleted at some earlier time, and the link key is still
+ * stored locally, ready to use on the next connection.
+ * </i>
+ */
+ public static final int BOND_BONDED = 12;
+
+ /** @hide */
+ public static final String EXTRA_REASON = "android.bluetooth.device.extra.REASON";
+ /** @hide */
+ public static final String EXTRA_PAIRING_VARIANT =
+ "android.bluetooth.device.extra.PAIRING_VARIANT";
+ /** @hide */
+ public static final String EXTRA_PASSKEY = "android.bluetooth.device.extra.PASSKEY";
+
+ /**
+ * Broadcast Action: This intent is used to broadcast the {@link UUID}
+ * wrapped as a {@link android.os.ParcelUuid} of the remote device after it
+ * has been fetched. This intent is sent only when the UUIDs of the remote
+ * device are requested to be fetched using Service Discovery Protocol
+ * <p> Always contains the extra field {@link #EXTRA_DEVICE}
+ * <p> Always contains the extra filed {@link #EXTRA_UUID}
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_UUID =
+ "android.bleutooth.device.action.UUID";
+
+ /**
+ * Broadcast Action: Indicates a failure to retrieve the name of a remote
+ * device.
+ * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+ * @hide
+ */
+ //TODO: is this actually useful?
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_NAME_FAILED =
+ "android.bluetooth.device.action.NAME_FAILED";
+
+ /** @hide */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_PAIRING_REQUEST =
+ "android.bluetooth.device.action.PAIRING_REQUEST";
+ /** @hide */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_PAIRING_CANCEL =
+ "android.bluetooth.device.action.PAIRING_CANCEL";
+
+ /** A bond attempt succeeded
+ * @hide */
+ public static final int BOND_SUCCESS = 0;
+ /** A bond attempt failed because pins did not match, or remote device did
+ * not respond to pin request in time
+ * @hide */
+ public static final int UNBOND_REASON_AUTH_FAILED = 1;
+ /** A bond attempt failed because the other side explicilty rejected
+ * bonding
+ * @hide */
+ public static final int UNBOND_REASON_AUTH_REJECTED = 2;
+ /** A bond attempt failed because we canceled the bonding process
+ * @hide */
+ public static final int UNBOND_REASON_AUTH_CANCELED = 3;
+ /** A bond attempt failed because we could not contact the remote device
+ * @hide */
+ public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
+ /** A bond attempt failed because a discovery is in progress
+ * @hide */
+ public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
+ /** A bond attempt failed because of authentication timeout
+ * @hide */
+ public static final int UNBOND_REASON_AUTH_TIMEOUT = 6;
+ /** A bond attempt failed because of repeated attempts
+ * @hide */
+ public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7;
+ /** A bond attempt failed because we received an Authentication Cancel
+ * by remote end
+ * @hide */
+ public static final int UNBOND_REASON_REMOTE_AUTH_CANCELED = 8;
+ /** An existing bond was explicitly revoked
+ * @hide */
+ public static final int UNBOND_REASON_REMOVED = 9;
+
+ /** The user will be prompted to enter a pin
+ * @hide */
+ public static final int PAIRING_VARIANT_PIN = 0;
+ /** The user will be prompted to enter a passkey
+ * @hide */
+ public static final int PAIRING_VARIANT_PASSKEY = 1;
+ /** The user will be prompted to confirm the passkey displayed on the screen
+ * @hide */
+ public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2;
+ /** The user will be prompted to accept or deny the incoming pairing request
+ * @hide */
+ public static final int PAIRING_VARIANT_CONSENT = 3;
+ /** The user will be prompted to enter the passkey displayed on remote device
+ * @hide */
+ public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4;
+
+ /**
+ * Used as an extra field in {@link #ACTION_UUID} intents,
+ * Contains the {@link android.os.ParcelUuid}s of the remote device which
+ * is a parcelable version of {@link UUID}.
+ * @hide
+ */
+ public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
+
+ /**
+ * Lazy initialization. Guaranteed final after first object constructed, or
+ * getService() called.
+ * TODO: Unify implementation of sService amongst BluetoothFoo API's
+ */
+ private static IBluetooth sService;
+
+ private final String mAddress;
+
+ /*package*/ static IBluetooth getService() {
+ synchronized (BluetoothDevice.class) {
+ if (sService == null) {
+ IBinder b = ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE);
+ if (b == null) {
+ throw new RuntimeException("Bluetooth service not available");
+ }
+ sService = IBluetooth.Stub.asInterface(b);
+ }
+ }
+ return sService;
}
- public boolean startDiscovery() {
- return startDiscovery(true);
+ /**
+ * Create a new BluetoothDevice
+ * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB",
+ * and is validated in this constructor.
+ * @param address valid Bluetooth MAC address
+ * @throws RuntimeException Bluetooth is not available on this platform
+ * @throws IllegalArgumentException address is invalid
+ * @hide
+ */
+ /*package*/ BluetoothDevice(String address) {
+ getService(); // ensures sService is initialized
+ if (!BluetoothAdapter.checkBluetoothAddress(address)) {
+ throw new IllegalArgumentException(address + " is not a valid Bluetooth address");
+ }
+
+ mAddress = address;
}
- public boolean startDiscovery(boolean resolveNames) {
- try {
- return mService.startDiscovery(resolveNames);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof BluetoothDevice) {
+ return mAddress.equals(((BluetoothDevice)o).getAddress());
+ }
return false;
}
- public void cancelDiscovery() {
- try {
- mService.cancelDiscovery();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
+ @Override
+ public int hashCode() {
+ return mAddress.hashCode();
}
- public boolean isDiscovering() {
- try {
- return mService.isDiscovering();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
+ /**
+ * Returns a string representation of this BluetoothDevice.
+ * <p>Currently this is the Bluetooth hardware address, for example
+ * "00:11:22:AA:BB:CC". However, you should always use {@link #getAddress}
+ * if you explicitly require the Bluetooth hardware address in case the
+ * {@link #toString} representation changes in the future.
+ * @return string representation of this BluetoothDevice
+ */
+ @Override
+ public String toString() {
+ return mAddress;
}
- public boolean startPeriodicDiscovery() {
- try {
- return mService.startPeriodicDiscovery();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
+ public int describeContents() {
+ return 0;
}
- public boolean stopPeriodicDiscovery() {
- try {
- return mService.stopPeriodicDiscovery();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
- }
- public boolean isPeriodicDiscovery() {
- try {
- return mService.isPeriodicDiscovery();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
+
+ public static final Parcelable.Creator<BluetoothDevice> CREATOR =
+ new Parcelable.Creator<BluetoothDevice>() {
+ public BluetoothDevice createFromParcel(Parcel in) {
+ return new BluetoothDevice(in.readString());
+ }
+ public BluetoothDevice[] newArray(int size) {
+ return new BluetoothDevice[size];
+ }
+ };
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mAddress);
}
- public String[] listRemoteDevices() {
- try {
- return mService.listRemoteDevices();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
+ /**
+ * Returns the hardware address of this BluetoothDevice.
+ * <p> For example, "00:11:22:AA:BB:CC".
+ * @return Bluetooth hardware address as string
+ */
+ public String getAddress() {
+ return mAddress;
}
/**
- * List remote devices that have a low level (ACL) connection.
- *
- * RFCOMM, SDP and L2CAP are all built on ACL connections. Devices can have
- * an ACL connection even when not paired - this is common for SDP queries
- * or for in-progress pairing requests.
+ * Get the friendly Bluetooth name of the remote device.
*
- * In most cases you probably want to test if a higher level protocol is
- * connected, rather than testing ACL connections.
+ * <p>The local adapter will automatically retrieve remote names when
+ * performing a device scan, and will cache them. This method just returns
+ * the name for this device from the cache.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*
- * @return bluetooth hardware addresses of remote devices with a current
- * ACL connection. Array size is 0 if no devices have a
- * connection. Null on error.
+ * @return the Bluetooth name, or null if there was a problem.
*/
- public String[] listAclConnections() {
+ public String getName() {
try {
- return mService.listAclConnections();
+ return sService.getRemoteName(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
}
/**
- * Check if a specified remote device has a low level (ACL) connection.
- *
- * RFCOMM, SDP and L2CAP are all built on ACL connections. Devices can have
- * an ACL connection even when not paired - this is common for SDP queries
- * or for in-progress pairing requests.
- *
- * In most cases you probably want to test if a higher level protocol is
- * connected, rather than testing ACL connections.
+ * Start the bonding (pairing) process with the remote device.
+ * <p>This is an asynchronous call, it will return immediately. Register
+ * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
+ * the bonding process completes, and its result.
+ * <p>Android system services will handle the necessary user interactions
+ * to confirm and complete the bonding process.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
*
- * @param address the Bluetooth hardware address you want to check.
- * @return true if there is an ACL connection, false otherwise and on
- * error.
+ * @return false on immediate error, true if bonding will begin
+ * @hide
*/
- public boolean isAclConnected(String address) {
+ public boolean createBond() {
try {
- return mService.isAclConnected(address);
+ return sService.createBond(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
/**
- * Perform a low level (ACL) disconnection of a remote device.
+ * Cancel an in-progress bonding request started with {@link #createBond}.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
*
- * This forcably disconnects the ACL layer connection to a remote device,
- * which will cause all RFCOMM, SDP and L2CAP connections to this remote
- * device to close.
- *
- * @param address the Bluetooth hardware address you want to disconnect.
- * @return true if the device was disconnected, false otherwise and on
- * error.
+ * @return true on sucess, false on error
+ * @hide
*/
- public boolean disconnectRemoteDeviceAcl(String address) {
+ public boolean cancelBondProcess() {
try {
- return mService.disconnectRemoteDeviceAcl(address);
+ return sService.cancelBondProcess(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
/**
- * Create a bonding with a remote bluetooth device.
- *
- * This is an asynchronous call. The result of this bonding attempt can be
- * observed through BluetoothIntent.BOND_STATE_CHANGED_ACTION intents.
+ * Remove bond (pairing) with the remote device.
+ * <p>Delete the link key associated with the remote device, and
+ * immediately terminate connections to that device that require
+ * authentication and encryption.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
*
- * @param address the remote device Bluetooth address.
- * @return false If there was an immediate problem creating the bonding,
- * true otherwise.
+ * @return true on sucess, false on error
+ * @hide
*/
- public boolean createBond(String address) {
+ public boolean removeBond() {
try {
- return mService.createBond(address);
+ return sService.removeBond(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
/**
- * Cancel an in-progress bonding request started with createBond.
+ * Get the bond state of the remote device.
+ * <p>Possible values for the bond state are:
+ * {@link #BOND_NONE},
+ * {@link #BOND_BONDING},
+ * {@link #BOND_BONDED}.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
+ *
+ * @return the bond state
*/
- public boolean cancelBondProcess(String address) {
+ public int getBondState() {
try {
- return mService.cancelBondProcess(address);
+ return sService.getBondState(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
+ return BOND_NONE;
}
/**
- * Remove an already exisiting bonding (delete the link key).
+ * Get the Bluetooth class of the remote device.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
+ *
+ * @return Bluetooth class object, or null on error
*/
- public boolean removeBond(String address) {
+ public BluetoothClass getBluetoothClass() {
try {
- return mService.removeBond(address);
+ int classInt = sService.getRemoteClass(mAddress);
+ if (classInt == BluetoothClass.ERROR) return null;
+ return new BluetoothClass(classInt);
} catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
+ return null;
}
/**
- * List remote devices that are bonded (paired) to the local device.
- *
- * Bonding (pairing) is the process by which the user enters a pin code for
- * the device, which generates a shared link key, allowing for
- * authentication and encryption of future connections. In Android we
- * require bonding before RFCOMM or SCO connections can be made to a remote
- * device.
- *
- * This function lists which remote devices we have a link key for. It does
- * not cause any RF transmission, and does not check if the remote device
- * still has it's link key with us. If the other side no longer has its
- * link key then the RFCOMM or SCO connection attempt will result in an
- * error.
- *
- * This function does not check if the remote device is in range.
- *
- * Remote devices that have an in-progress bonding attempt are not
- * returned.
- *
- * @return bluetooth hardware addresses of remote devices that are
- * bonded. Array size is 0 if no devices are bonded. Null on error.
+ * Get trust state of a remote device.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
+ * @hide
*/
- public String[] listBonds() {
+ public boolean getTrustState() {
try {
- return mService.listBonds();
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
+ return sService.getTrustState(mAddress);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ return false;
}
/**
- * Get the bonding state of a remote device.
- *
- * Result is one of:
- * BluetoothError.*
- * BOND_*
- *
- * @param address Bluetooth hardware address of the remote device to check.
- * @return Result code
+ * Set trust state for a remote device.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
+ * @param value the trust state value (true or false)
+ * @hide
*/
- public int getBondState(String address) {
+ public boolean setTrust(boolean value) {
try {
- return mService.getBondState(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return BluetoothError.ERROR_IPC;
+ return sService.setTrust(mAddress, value);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ return false;
}
- public String getRemoteName(String address) {
+ /** @hide */
+ public ParcelUuid[] getUuids() {
try {
- return mService.getRemoteName(address);
+ return sService.getRemoteUuids(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
}
- public String getRemoteVersion(String address) {
- try {
- return mService.getRemoteVersion(address);
+ /**
+ * Perform a SDP query on the remote device to get the UUIDs
+ * supported. This API is asynchronous and an Intent is sent,
+ * with the UUIDs supported by the remote end. If there is an error
+ * in getting the SDP records or if the process takes a long time,
+ * an Intent is sent with the UUIDs that is currently present in the
+ * cache. Clients should use the {@link getUuids} to get UUIDs
+ * is SDP is not to be performed.
+ *
+ * @return False if the sanity check fails, True if the process
+ * of initiating an ACL connection to the remote device
+ * was started.
+ * @hide
+ */
+ public boolean fetchUuidsWithSdp() {
+ try {
+ return sService.fetchRemoteUuids(mAddress, null, null);
} catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
+ return false;
}
- public String getRemoteRevision(String address) {
+
+ /** @hide */
+ public int getServiceChannel(ParcelUuid uuid) {
+ try {
+ return sService.getRemoteServiceChannel(mAddress, uuid);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return BluetoothDevice.ERROR;
+ }
+
+ /** @hide */
+ public boolean setPin(byte[] pin) {
try {
- return mService.getRemoteRevision(address);
+ return sService.setPin(mAddress, pin);
} catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
+ return false;
}
- public String getRemoteManufacturer(String address) {
+
+ /** @hide */
+ public boolean setPasskey(int passkey) {
try {
- return mService.getRemoteManufacturer(address);
+ return sService.setPasskey(mAddress, passkey);
} catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
+ return false;
}
- public String getRemoteCompany(String address) {
+
+ /** @hide */
+ public boolean setPairingConfirmation(boolean confirm) {
try {
- return mService.getRemoteCompany(address);
+ return sService.setPairingConfirmation(mAddress, confirm);
} catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
+ return false;
}
- /**
- * Returns the RFCOMM channel associated with the 16-byte UUID on
- * the remote Bluetooth address.
- *
- * Performs a SDP ServiceSearchAttributeRequest transaction. The provided
- * uuid is verified in the returned record. If there was a problem, or the
- * specified uuid does not exist, -1 is returned.
- */
- public boolean getRemoteServiceChannel(String address, short uuid16,
- IBluetoothDeviceCallback callback) {
+ /** @hide */
+ public boolean cancelPairingUserInput() {
try {
- return mService.getRemoteServiceChannel(address, uuid16, callback);
+ return sService.cancelPairingUserInput(mAddress);
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
/**
- * Get the major, minor and servics classes of a remote device.
- * These classes are encoded as a 32-bit integer. See BluetoothClass.
- * @param address remote device
- * @return 32-bit class suitable for use with BluetoothClass, or
- * BluetoothClass.ERROR on error
+ * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
+ * outgoing connection to this remote device on given channel.
+ * <p>The remote device will be authenticated and communication on this
+ * socket will be encrypted.
+ * <p>Use {@link BluetoothSocket#connect} to intiate the outgoing
+ * connection.
+ * <p>Valid RFCOMM channels are in range 1 to 30.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
+ *
+ * @param channel RFCOMM channel to connect to
+ * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
+ * @throws IOException on error, for example Bluetooth not available, or
+ * insufficient permissions
+ * @hide
*/
- public int getRemoteClass(String address) {
- try {
- return mService.getRemoteClass(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return BluetoothClass.ERROR;
+ public BluetoothSocket createRfcommSocket(int channel) throws IOException {
+ return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel,
+ null);
}
- public byte[] getRemoteFeatures(String address) {
- try {
- return mService.getRemoteFeatures(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
- public String lastSeen(String address) {
- try {
- return mService.lastSeen(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
- }
- public String lastUsed(String address) {
- try {
- return mService.lastUsed(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return null;
+ /**
+ * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
+ * outgoing connection to this remote device using SDP lookup of uuid.
+ * <p>This is designed to be used with {@link
+ * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer
+ * Bluetooth applications.
+ * <p>Use {@link BluetoothSocket#connect} to intiate the outgoing
+ * connection. This will also perform an SDP lookup of the given uuid to
+ * determine which channel to connect to.
+ * <p>The remote device will be authenticated and communication on this
+ * socket will be encrypted.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
+ *
+ * @param uuid service record uuid to lookup RFCOMM channel
+ * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
+ * @throws IOException on error, for example Bluetooth not available, or
+ * insufficient permissions
+ */
+ public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {
+ return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1,
+ new ParcelUuid(uuid));
}
- public boolean setPin(String address, byte[] pin) {
- try {
- return mService.setPin(address, pin);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
+ /**
+ * Construct an insecure RFCOMM socket ready to start an outgoing
+ * connection.
+ * Call #connect on the returned #BluetoothSocket to begin the connection.
+ * The remote device will not be authenticated and communication on this
+ * socket will not be encrypted.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ *
+ * @param port remote port
+ * @return An RFCOMM BluetoothSocket
+ * @throws IOException On error, for example Bluetooth not available, or
+ * insufficient permissions.
+ * @hide
+ */
+ public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
+ return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port,
+ null);
}
- public boolean cancelPin(String address) {
- try {
- return mService.cancelPin(address);
- } catch (RemoteException e) {Log.e(TAG, "", e);}
- return false;
+
+ /**
+ * Construct a SCO socket ready to start an outgoing connection.
+ * Call #connect on the returned #BluetoothSocket to begin the connection.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+ *
+ * @return a SCO BluetoothSocket
+ * @throws IOException on error, for example Bluetooth not available, or
+ * insufficient permissions.
+ * @hide
+ */
+ public BluetoothSocket createScoSocket() throws IOException {
+ return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null);
}
/**
@@ -534,6 +708,7 @@ public class BluetoothDevice {
* @param pin pin as java String
* @return the pin code as a UTF8 byte array, or null if it is an invalid
* Bluetooth pin.
+ * @hide
*/
public static byte[] convertPinToBytes(String pin) {
if (pin == null) {
@@ -552,28 +727,4 @@ public class BluetoothDevice {
return pinBytes;
}
- private static final int ADDRESS_LENGTH = 17;
- /** Sanity check a bluetooth address, such as "00:43:A8:23:10:F0" */
- public static boolean checkBluetoothAddress(String address) {
- if (address == null || address.length() != ADDRESS_LENGTH) {
- return false;
- }
- for (int i = 0; i < ADDRESS_LENGTH; i++) {
- char c = address.charAt(i);
- switch (i % 3) {
- case 0:
- case 1:
- if (Character.digit(c, 16) != -1) {
- break; // hex character, OK
- }
- return false;
- case 2:
- if (c == ':') {
- break; // OK
- }
- return false;
- }
- }
- return true;
- }
}