In this document
- The Basics
- Bluetooth Permissions
- Setting Up Bluetooth
- Finding Devices
- Connecting Devices
- Managing a Connection
- Working with Profiles
Key classes
Related samples
The Android platform includes support for the Bluetooth network stack, which allows a device to wirelessly exchange data with other Bluetooth devices. The application framework provides access to the Bluetooth functionality through the Android Bluetooth APIs. These APIs let applications wirelessly connect to other Bluetooth devices, enabling point-to-point and multipoint wireless features.
Using the Bluetooth APIs, an Android application can perform the following:
- Scan for other Bluetooth devices
- Query the local Bluetooth adapter for paired Bluetooth devices
- Establish RFCOMM channels
- Connect to other devices through service discovery
- Transfer data to and from other devices
- Manage multiple connections
This document describes how to use Classic Bluetooth . Classic Bluetooth is the right choice for more battery-intensive operations such as streaming and communicating between Android devices. For Bluetooth devices with low power requirements, Android 4.3 (API Level 18) introduces API support for Bluetooth Low Energy. To learn more, see Bluetooth Low Energy .
The Basics
This document describes how to use the Android Bluetooth APIs to accomplish the four major tasks necessary to communicate using Bluetooth: setting up Bluetooth, finding devices that are either paired or available in the local area, connecting devices, and transferring data between devices.
All of the Bluetooth APIs are available in the
android.bluetooth
package. Here's a summary of the classes and interfaces you will need to create Bluetooth
connections:
-
BluetoothAdapter
-
Represents the local Bluetooth adapter (Bluetooth radio). The
BluetoothAdapter
is the entry-point for all Bluetooth interaction. Using this, you can discover other Bluetooth devices, query a list of bonded (paired) devices, instantiate aBluetoothDevice
using a known MAC address, and create aBluetoothServerSocket
to listen for communications from other devices. -
BluetoothDevice
-
Represents a remote Bluetooth device. Use this to request a connection
with a remote device through a
BluetoothSocket
or query information about the device such as its name, address, class, and bonding state. -
BluetoothSocket
-
Represents the interface for a Bluetooth socket (similar to a TCP
Socket
). This is the connection point that allows an application to exchange data with another Bluetooth device via InputStream and OutputStream. -
BluetoothServerSocket
-
Represents an open server socket that listens for incoming requests
(similar to a TCP
ServerSocket
). In order to connect two Android devices, one device must open a server socket with this class. When a remote Bluetooth device makes a connection request to the this device, theBluetoothServerSocket
will return a connectedBluetoothSocket
when the connection is accepted. -
BluetoothClass
- Describes the general characteristics and capabilities of a Bluetooth device. This is a read-only set of properties that define the device's major and minor device classes and its services. However, this does not reliably describe all Bluetooth profiles and services supported by the device, but is useful as a hint to the device type.
-
BluetoothProfile
- An interface that represents a Bluetooth profile. A Bluetooth profile is a wireless interface specification for Bluetooth-based communication between devices. An example is the Hands-Free profile. For more discussion of profiles, see Working with Profiles
-
BluetoothHeadset
- Provides support for Bluetooth headsets to be used with mobile phones. This includes both Bluetooth Headset and Hands-Free (v1.5) profiles.
-
BluetoothA2dp
- Defines how high quality audio can be streamed from one device to another over a Bluetooth connection. "A2DP" stands for Advanced Audio Distribution Profile.
-
BluetoothHealth
- Represents a Health Device Profile proxy that controls the Bluetooth service.
-
BluetoothHealthCallback
-
An abstract class that you use to implement
BluetoothHealth
callbacks. You must extend this class and implement the callback methods to receive updates about changes in the application’s registration state and Bluetooth channel state. -
BluetoothHealthAppConfiguration
- Represents an application configuration that the Bluetooth Health third-party application registers to communicate with a remote Bluetooth health device.
-
BluetoothProfile.ServiceListener
-
An interface that notifies
BluetoothProfile
IPC clients when they have been connected to or disconnected from the service (that is, the internal service that runs a particular profile).
Bluetooth Permissions
In order to use Bluetooth features in your application, you must declare
the Bluetooth permission
BLUETOOTH
.
You need this permission to perform any Bluetooth communication,
such as requesting a connection, accepting a connection, and transferring data.
If you want your app to initiate device discovery or manipulate Bluetooth
settings, you must also declare the
BLUETOOTH_ADMIN
permission. Most applications need this permission solely for the
ability to discover local Bluetooth devices. The other abilities granted by this
permission should not be used, unless the application is a "power manager" that
will modify Bluetooth settings upon user request.
Note:
If you
use
BLUETOOTH_ADMIN
permission, then you must
also have the
BLUETOOTH
permission.
Declare the Bluetooth permission(s) in your application manifest file. For example:
<manifest ... > <uses-permission android:name="android.permission.BLUETOOTH" /> ... </manifest>
See the <uses-permission> reference for more information about declaring application permissions.
Setting Up Bluetooth
Before your application can communicate over Bluetooth, you need to verify that Bluetooth is supported on the device, and if so, ensure that it is enabled.
If Bluetooth is not supported, then you should gracefully disable any
Bluetooth features. If Bluetooth is supported, but disabled, then you can request that the
user enable Bluetooth without leaving your application. This setup is
accomplished in two steps, using the
BluetoothAdapter
.
-
Get the
BluetoothAdapter
The
BluetoothAdapter
is required for any and all Bluetooth activity. To get theBluetoothAdapter
, call the staticgetDefaultAdapter()
method. This returns aBluetoothAdapter
that represents the device's own Bluetooth adapter (the Bluetooth radio). There's one Bluetooth adapter for the entire system, and your application can interact with it using this object. IfgetDefaultAdapter()
returns null, then the device does not support Bluetooth and your story ends here. For example:BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (mBluetoothAdapter == null) { // Device does not support Bluetooth }
-
Enable Bluetooth
Next, you need to ensure that Bluetooth is enabled. Call
isEnabled()
to check whether Bluetooth is currently enable. If this method returns false, then Bluetooth is disabled. To request that Bluetooth be enabled, callstartActivityForResult()
with theACTION_REQUEST_ENABLE
action Intent. This will issue a request to enable Bluetooth through the system settings (without stopping your application). For example:if (!mBluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); }
A dialog will appear requesting user permission to enable Bluetooth, as shown in Figure 1. If the user responds "Yes," the system will begin to enable Bluetooth and focus will return to your application once the process completes (or fails).
The
REQUEST_ENABLE_BT
constant passed tostartActivityForResult()
is a locally defined integer (which must be greater than 0), that the system passes back to you in youronActivityResult()
implementation as therequestCode
parameter.If enabling Bluetooth succeeds, your activity receives the
RESULT_OK
result code in theonActivityResult()
callback. If Bluetooth was not enabled due to an error (or the user responded "No") then the result code isRESULT_CANCELED
.
Optionally, your application can also listen for the
ACTION_STATE_CHANGED
broadcast Intent, which
the system will broadcast whenever the Bluetooth state has changed. This broadcast contains
the extra fields
EXTRA_STATE
and
EXTRA_PREVIOUS_STATE
, containing the new and old
Bluetooth states, respectively. Possible values for these extra fields are
STATE_TURNING_ON
,
STATE_ON
,
STATE_TURNING_OFF
, and
STATE_OFF
. Listening for this
broadcast can be useful to detect changes made to the Bluetooth state while your
app is running.
Tip: Enabling discoverability will automatically enable Bluetooth. If you plan to consistently enable device discoverability before performing Bluetooth activity, you can skip step 2 above. Read about enabling discoverability , below.
Finding Devices
Using the
BluetoothAdapter
, you can find remote Bluetooth
devices either through device discovery or by querying the list of paired (bonded)
devices.
Device discovery is a scanning procedure that searches the local area for Bluetooth enabled devices and then requesting some information about each one (this is sometimes referred to as "discovering," "inquiring" or "scanning"). However, a Bluetooth device within the local area will respond to a discovery request only if it is currently enabled to be discoverable. If a device is discoverable, it will respond to the discovery request by sharing some information, such as the device name, class, and its unique MAC address. Using this information, the device performing discovery can then choose to initiate a connection to the discovered device.
Once a connection is made with a remote device for the first time, a pairing request is automatically presented to the user. When a device is paired, the basic information about that device (such as the device name, class, and MAC address) is saved and can be read using the Bluetooth APIs. Using the known MAC address for a remote device, a connection can be initiated with it at any time without performing discovery (assuming the device is within range).
Remember there is a difference between being paired and being connected. To be paired means that two devices are aware of each other's existence, have a shared link-key that can be used for authentication, and are capable of establishing an encrypted connection with each other. To be connected means that the devices currently share an RFCOMM channel and are able to transmit data with each other. The current Android Bluetooth API's require devices to be paired before an RFCOMM connection can be established. (Pairing is automatically performed when you initiate an encrypted connection with the Bluetooth APIs.)
The following sections describe how to find devices that have been paired, or discover new devices using device discovery.
Note: Android-powered devices are not discoverable by default. A user can make the device discoverable for a limited time through the system settings, or an application can request that the user enable discoverability without leaving the application. How to enable discoverability is discussed below.
Querying paired devices
Before performing device discovery, its worth querying the set
of paired devices to see if the desired device is already known. To do so,
call
getBondedDevices()
. This
will return a Set of
BluetoothDevice
s representing
paired devices. For example, you can query all paired devices and then
show the name of each device to the user, using an ArrayAdapter:
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices(); // If there are paired devices if (pairedDevices.size() > 0) { // Loop through paired devices for (BluetoothDevice device : pairedDevices) { // Add the name and address to an array adapter to show in a ListView mArrayAdapter.add(device.getName() + "\n" + device.getAddress()); } }
All that's needed from the
BluetoothDevice
object
in order to initiate a connection is the MAC address. In this example, it's saved
as a part of an ArrayAdapter that's shown to the user. The MAC address can later
be extracted in order to initiate the connection. You can learn more about creating
a connection in the section about
Connecting Devices
.
Discovering devices
To start discovering devices, simply call
startDiscovery()
. The
process is asynchronous and the method will immediately return with a boolean
indicating whether discovery has successfully started. The discovery process
usually involves an inquiry scan of about 12 seconds, followed by a page scan of
each found device to retrieve its Bluetooth name.
Your application must register a BroadcastReceiver for the
ACTION_FOUND
Intent in
order to receive information about each
device discovered. For each device, the system will broadcast the
ACTION_FOUND
Intent. This
Intent carries the extra fields
EXTRA_DEVICE
and
EXTRA_CLASS
, containing a
BluetoothDevice
and a
BluetoothClass
, respectively. For example, here's how you can
register to handle the broadcast when devices are discovered:
// Create a BroadcastReceiver for ACTION_FOUND private final BroadcastReceiver mReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); // When discovery finds a device if (BluetoothDevice.ACTION_FOUND.equals(action)) { // Get the BluetoothDevice object from the Intent BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // Add the name and address to an array adapter to show in a ListView mArrayAdapter.add(device.getName() + "\n" + device.getAddress()); } } }; // Register the BroadcastReceiver IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy
All that's needed from the
BluetoothDevice
object
in order to initiate a
connection is the MAC address. In this example, it's saved as a part of an
ArrayAdapter that's shown to the user. The MAC address can later be extracted in
order to initiate the connection. You can learn more about creating a connection
in the section about
Connecting Devices
.
Caution:
Performing device discovery is
a heavy procedure for the Bluetooth
adapter and will consume a lot of its resources. Once you have found a device to
connect, be certain that you always stop discovery with
cancelDiscovery()
before
attempting a connection. Also, if you
already hold a connection with a device, then performing discovery can
significantly reduce the bandwidth available for the connection, so you should
not perform discovery while connected.
Enabling discoverability
If you would like to make the local device discoverable to other devices,
call
startActivityForResult(Intent, int)
with the
ACTION_REQUEST_DISCOVERABLE
action
Intent. This will issue a request to enable discoverable mode through the system
settings (without stopping your application). By default, the device will become
discoverable for 120 seconds. You can define a different duration by adding the
EXTRA_DISCOVERABLE_DURATION
Intent
extra. The maximum duration an app can set is 3600 seconds, and a value of 0
means the device is always discoverable. Any value below 0 or above 3600 is
automatically set to 120 secs). For example, this snippet sets the duration to
300:
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); startActivity(discoverableIntent);
A dialog will be displayed, requesting user permission to make the device
discoverable, as shown in Figure 2. If the user responds "Yes," then the device
will become discoverable for the specified amount of time. Your activity will
then receive a call to the
onActivityResult())
callback, with the result code equal to the duration that the device
is discoverable. If the user responded "No" or if an error occurred, the result code will
be
RESULT_CANCELED
.
Note: If Bluetooth has not been enabled on the device, then enabling device discoverability will automatically enable Bluetooth.
The device will silently remain in discoverable mode for the allotted time.
If you would like to be notified when the discoverable mode has changed, you can
register a BroadcastReceiver for the
ACTION_SCAN_MODE_CHANGED
Intent. This will contain the extra fields
EXTRA_SCAN_MODE
and
EXTRA_PREVIOUS_SCAN_MODE
, which tell you the
new and old scan mode, respectively. Possible values for each are
SCAN_MODE_CONNECTABLE_DISCOVERABLE
,
SCAN_MODE_CONNECTABLE
, or
SCAN_MODE_NONE
,
which indicate that the device is either in discoverable mode, not in
discoverable mode but still able to receive connections, or not in discoverable
mode and unable to receive connections, respectively.
You do not need to enable device discoverability if you will be initiating the connection to a remote device. Enabling discoverability is only necessary when you want your application to host a server socket that will accept incoming connections, because the remote devices must be able to discover the device before it can initiate the connection.
Connecting Devices
In order to create a connection between your application on two devices, you
must implement both the server-side and client-side mechanisms, because one
device must open a server socket and the other one must initiate the connection
(using the server device's MAC address to initiate a connection). The server and
client are considered connected to each other when they each have a connected
BluetoothSocket
on the same RFCOMM channel. At this
point, each device can obtain input and output streams and data transfer can
begin, which is discussed in the section about
Managing a Connection
. This section describes how
to initiate the connection between two devices.
The server device and the client device each obtain the required
BluetoothSocket
in different ways. The server will receive it
when an incoming connection is accepted. The client will receive it when it
opens an RFCOMM channel to the server.
One implementation technique is to automatically prepare each device as a server, so that each one has a server socket open and listening for connections. Then either device can initiate a connection with the other and become the client. Alternatively, one device can explicitly "host" the connection and open a server socket on demand and the other device can simply initiate the connection.
Note: If the two devices have not been previously paired, then the Android framework will automatically show a pairing request notification or dialog to the user during the connection procedure, as shown in Figure 3. So when attempting to connect devices, your application does not need to be concerned about whether or not the devices are paired. Your RFCOMM connection attempt will block until the user has successfully paired, or will fail if the user rejects pairing, or if pairing fails or times out.
Connecting as a server
When you want to connect two devices, one must act as a server by holding an
open
BluetoothServerSocket
. The purpose of the server
socket is to listen for incoming connection requests and when one is accepted,
provide a connected
BluetoothSocket
. When the
BluetoothSocket
is acquired from the
BluetoothServerSocket
,
the
BluetoothServerSocket
can (and should) be
discarded, unless you want to accept more connections.
About UUID
A Universally Unique Identifier (UUID) is a standardized 128-bit format for a string
ID used to uniquely identify information. The point of a UUID is that it's big
enough that you can select any random and it won't clash. In this case, it's
used to uniquely identify your application's Bluetooth service. To get a UUID to
use with your application, you can use one of the many random UUID generators on
the web, then initialize a
UUID
with
fromString(String)
.
Here's the basic procedure to set up a server socket and accept a connection:
-
Get a
BluetoothServerSocket
by calling thelistenUsingRfcommWithServiceRecord(String, UUID)
.The string is an identifiable name of your service, which the system will automatically write to a new Service Discovery Protocol (SDP) database entry on the device (the name is arbitrary and can simply be your application name). The UUID is also included in the SDP entry and will be the basis for the connection agreement with the client device. That is, when the client attempts to connect with this device, it will carry a UUID that uniquely identifies the service with which it wants to connect. These UUIDs must match in order for the connection to be accepted (in the next step).
-
Start listening for connection requests by calling
accept()
.This is a blocking call. It will return when either a connection has been accepted or an exception has occurred. A connection is accepted only when a remote device has sent a connection request with a UUID matching the one registered with this listening server socket. When successful,
accept()
will return a connectedBluetoothSocket
. -
Unless you want to accept additional connections, call
close()
.This releases the server socket and all its resources, but does not close the connected
BluetoothSocket
that's been returned byaccept()
. Unlike TCP/IP, RFCOMM only allows one connected client per channel at a time, so in most cases it makes sense to callclose()
on theBluetoothServerSocket
immediately after accepting a connected socket.
The
accept()
call should not
be executed in the main activity UI thread because it is a blocking call and
will prevent any other interaction with the application. It usually makes
sense to do all work with a
BluetoothServerSocket
or
BluetoothSocket
in a new
thread managed by your application. To abort a blocked call such as
accept()
, call
close()
on the
BluetoothServerSocket
(or
BluetoothSocket
) from another thread and the blocked call will
immediately return. Note that all methods on a
BluetoothServerSocket
or
BluetoothSocket
are thread-safe.
Example
Here's a simplified thread for the server component that accepts incoming connections:
private class AcceptThread extends Thread { private final BluetoothServerSocket mmServerSocket; public AcceptThread() { // Use a temporary object that is later assigned to mmServerSocket, // because mmServerSocket is final BluetoothServerSocket tmp = null; try { // MY_UUID is the app's UUID string, also used by the client code tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID); } catch (IOException e) { } mmServerSocket = tmp; } public void run() { BluetoothSocket socket = null; // Keep listening until exception occurs or a socket is returned while (true) { try { socket = mmServerSocket.accept(); } catch (IOException e) { break; } // If a connection was accepted if (socket != null) { // Do work to manage the connection (in a separate thread) manageConnectedSocket(socket); mmServerSocket.close(); break; } } } /** Will cancel the listening socket, and cause the thread to finish */ public void cancel() { try { mmServerSocket.close(); } catch (IOException e) { } } }
In this example, only one incoming connection is desired, so as soon as a
connection is accepted and the
BluetoothSocket
is
acquired, the application
sends the acquired
BluetoothSocket
to a separate
thread, closes the
BluetoothServerSocket
and breaks the loop.
Note that when
accept()
returns the
BluetoothSocket
, the socket is already
connected, so you should
not
call
connect()
(as you do from the
client-side).
manageConnectedSocket()
is a fictional method in the application
that will
initiate the thread for transferring data, which is discussed in the section
about
Managing a Connection
.
You should usually close your
BluetoothServerSocket
as soon as you are done listening for incoming connections. In this example,
close()
is called as soon
as the
BluetoothSocket
is acquired. You may also want
to provide a public method in your thread that can close the private
BluetoothSocket
in the event that you need to stop listening on the
server socket.
Connecting as a client
In order to initiate a connection with a remote device (a device holding an
open
server socket), you must first obtain a
BluetoothDevice
object that represents the remote device.
(Getting a
BluetoothDevice
is covered in the above
section about
Finding Devices
.) You must then use the
BluetoothDevice
to acquire a
BluetoothSocket
and initiate the connection.
Here's the basic procedure:
-
Using the
BluetoothDevice
, get aBluetoothSocket
by callingcreateRfcommSocketToServiceRecord(UUID)
.This initializes a
BluetoothSocket
that will connect to theBluetoothDevice
. The UUID passed here must match the UUID used by the server device when it opened itsBluetoothServerSocket
(withlistenUsingRfcommWithServiceRecord(String, UUID)
). Using the same UUID is simply a matter of hard-coding the UUID string into your application and then referencing it from both the server and client code. -
Initiate the connection by calling
connect()
.Upon this call, the system will perform an SDP lookup on the remote device in order to match the UUID. If the lookup is successful and the remote device accepts the connection, it will share the RFCOMM channel to use during the connection and
connect()
will return. This method is a blocking call. If, for any reason, the connection fails or theconnect()
method times out (after about 12 seconds), then it will throw an exception.Because
connect()
is a blocking call, this connection procedure should always be performed in a thread separate from the main activity thread.Note: You should always ensure that the device is not performing device discovery when you call
connect()
. If discovery is in progress, then the connection attempt will be significantly slowed and is more likely to fail.
Example
Here is a basic example of a thread that initiates a Bluetooth connection:
private class ConnectThread extends Thread { private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; public ConnectThread(BluetoothDevice device) { // Use a temporary object that is later assigned to mmSocket, // because mmSocket is final BluetoothSocket tmp = null; mmDevice = device; // Get a BluetoothSocket to connect with the given BluetoothDevice try { // MY_UUID is the app's UUID string, also used by the server code tmp = device.createRfcommSocketToServiceRecord(MY_UUID); } catch (IOException e) { } mmSocket = tmp; } public void run() { // Cancel discovery because it will slow down the connection mBluetoothAdapter.cancelDiscovery(); try { // Connect the device through the socket. This will block // until it succeeds or throws an exception mmSocket.connect(); } catch (IOException connectException) { // Unable to connect; close the socket and get out try { mmSocket.close(); } catch (IOException closeException) { } return; } // Do work to manage the connection (in a separate thread) manageConnectedSocket(mmSocket); } /** Will cancel an in-progress connection, and close the socket */ public void cancel() { try { mmSocket.close(); } catch (IOException e) { } } }
Notice that
cancelDiscovery()
is called
before the connection is made. You should always do this before connecting and it is safe
to call without actually checking whether it is running or not (but if you do want to
check, call
isDiscovering()
).
manageConnectedSocket()
is a fictional method in the application
that will initiate the thread for transferring data, which is discussed in the section
about
Managing a Connection
.
When you're done with your
BluetoothSocket
, always
call
close()
to clean up.
Doing so will immediately close the connected socket and clean up all internal
resources.
Managing a Connection
When you have successfully connected two (or more) devices, each one will
have a connected
BluetoothSocket
. This is where the fun
begins because you can share data between devices. Using the
BluetoothSocket
, the general procedure to transfer arbitrary data is
simple:
-
Get the
InputStream
andOutputStream
that handle transmissions through the socket, viagetInputStream()
andgetOutputStream()
, respectively. -
Read and write data to the streams with
read(byte[])
andwrite(byte[])
.
That's it.
There are, of course, implementation details to consider. First and foremost,
you should use a dedicated thread for all stream reading and writing. This is
important because both
read(byte[])
and
write(byte[])
methods are blocking calls.
read(byte[])
will block until there is something to read
from the stream.
write(byte[])
does not usually
block, but can block for flow control if the remote device is not calling
read(byte[])
quickly enough and the intermediate buffers are full.
So, your main loop in the thread should be dedicated to reading from the
InputStream
. A separate public method in the thread can be used to initiate
writes to the
OutputStream
.
Example
Here's an example of how this might look:
private class ConnectedThread extends Thread { private final BluetoothSocket mmSocket; private final InputStream mmInStream; private final OutputStream mmOutStream; public ConnectedThread(BluetoothSocket socket) { mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; // Get the input and output streams, using temp objects because // member streams are final try { tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); } catch (IOException e) { } mmInStream = tmpIn; mmOutStream = tmpOut; } public void run() { byte[] buffer = new byte[1024]; // buffer store for the stream int bytes; // bytes returned from read() // Keep listening to the InputStream until an exception occurs while (true) { try { // Read from the InputStream bytes = mmInStream.read(buffer); // Send the obtained bytes to the UI activity mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer) .sendToTarget(); } catch (IOException e) { break; } } } /* Call this from the main activity to send data to the remote device */ public void write(byte[] bytes) { try { mmOutStream.write(bytes); } catch (IOException e) { } } /* Call this from the main activity to shutdown the connection */ public void cancel() { try { mmSocket.close(); } catch (IOException e) { } } }
The constructor acquires the necessary streams and once executed, the thread
will wait for data to come through the InputStream. When
read(byte[])
returns with
bytes from the stream, the data is sent to the main activity using a member
Handler from the parent class. Then it goes back and waits for more bytes from
the stream.
Sending outgoing data is as simple as calling the thread's
write()
method from the main activity and passing in the bytes to
be sent. This method then simply calls
write(byte[])
to send the data to the remote device.
The thread's
cancel()
method is important so that the connection
can be
terminated at any time by closing the
BluetoothSocket
.
This should always be called when you're done using the Bluetooth
connection.
For a demonstration of using the Bluetooth APIs, see the Bluetooth Chat sample app .
Working with Profiles
Starting in Android 3.0, the Bluetooth API includes support for working with Bluetooth profiles. A Bluetooth profile is a wireless interface specification for Bluetooth-based communication between devices. An example is the Hands-Free profile. For a mobile phone to connect to a wireless headset, both devices must support the Hands-Free profile.
You can implement the interface
BluetoothProfile
to write
your own classes to support a particular Bluetooth profile. The Android
Bluetooth API provides implementations for the following Bluetooth
profiles:
-
Headset
. The Headset profile provides support for
Bluetooth headsets to be used with mobile phones. Android provides the
BluetoothHeadset
class, which is a proxy for controlling the Bluetooth Headset Service via interprocess communication ( IPC ). This includes both Bluetooth Headset and Hands-Free (v1.5) profiles. TheBluetoothHeadset
class includes support for AT commands. For more discussion of this topic, see Vendor-specific AT commands -
A2DP
. The Advanced Audio Distribution Profile (A2DP)
profile defines how high quality audio can be streamed from one device to
another over a Bluetooth connection. Android provides the
BluetoothA2dp
class, which is a proxy for controlling the Bluetooth A2DP Service via IPC. - Health Device . Android 4.0 (API level 14) introduces support for the Bluetooth Health Device Profile (HDP). This lets you create applications that use Bluetooth to communicate with health devices that support Bluetooth, such as heart-rate monitors, blood meters, thermometers, scales, and so on. For a list of supported devices and their corresponding device data specialization codes, refer to Bluetooth Assigned Numbers at www.bluetooth.org . Note that these values are also referenced in the ISO/IEEE 11073-20601 [7] specification as MDC_DEV_SPEC_PROFILE_* in the Nomenclature Codes Annex. For more discussion of HDP, see Health Device Profile .
Here are the basic steps for working with a profile:
- Get the default adapter, as described in Setting Up Bluetooth .
-
Use
getProfileProxy()
to establish a connection to the profile proxy object associated with the profile. In the example below, the profile proxy object is an instance ofBluetoothHeadset
. -
Set up a
BluetoothProfile.ServiceListener
. This listener notifiesBluetoothProfile
IPC clients when they have been connected to or disconnected from the service. -
In
onServiceConnected()
, get a handle to the profile proxy object. - Once you have the profile proxy object, you can use it to monitor the state of the connection and perform other operations that are relevant to that profile.
For example, this code snippet shows how to connect to a
BluetoothHeadset
proxy object so that you can control the
Headset profile:
BluetoothHeadset mBluetoothHeadset; // Get the default adapter BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); // Establish connection to the proxy. mBluetoothAdapter.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET); private BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() { public void onServiceConnected(int profile, BluetoothProfile proxy) { if (profile == BluetoothProfile.HEADSET) { mBluetoothHeadset = (BluetoothHeadset) proxy; } } public void onServiceDisconnected(int profile) { if (profile == BluetoothProfile.HEADSET) { mBluetoothHeadset = null; } } }; // ... call functions on mBluetoothHeadset // Close proxy connection after use. mBluetoothAdapter.closeProfileProxy(mBluetoothHeadset);
Vendor-specific AT commands
Starting in Android 3.0, applications can register to receive system
broadcasts of pre-defined vendor-specific AT commands sent by headsets (such as
a Plantronics +XEVENT command). For example, an application could receive
broadcasts that indicate a connected device's battery level and could notify the
user or take other action as needed. Create a broadcast receiver for the
ACTION_VENDOR_SPECIFIC_HEADSET_EVENT
intent
to handle vendor-specific AT commands for the headset.
Health Device Profile
Android 4.0 (API level 14) introduces support for the Bluetooth Health Device
Profile (HDP). This lets you create applications that use Bluetooth to
communicate with health devices that support Bluetooth, such as heart-rate
monitors, blood meters, thermometers, and scales. The Bluetooth Health API
includes the classes
BluetoothHealth
,
BluetoothHealthCallback
, and
BluetoothHealthAppConfiguration
, which are described in
The Basics
.
In using the Bluetooth Health API, it's helpful to understand these key HDP concepts:
Concept | Description |
---|---|
Source | A role defined in HDP. A source is a health device that transmits medical data (weight scale, glucose meter, thermometer, etc.) to a smart device such as an Android phone or tablet. |
Sink |
A role defined in HDP. In HDP, a
sink
is the smart device that
receives the medical data. In an Android HDP application, the sink is
represented by a
BluetoothHealthAppConfiguration
object.
|
Registration | Refers to registering a sink for a particular health device. |
Connection | Refers to opening a channel between a health device and a smart device such as an Android phone or tablet. |
Creating an HDP Application
Here are the basic steps involved in creating an Android HDP application:
-
Get a reference to the
BluetoothHealth
proxy object.Similar to regular headset and A2DP profile devices, you must call
getProfileProxy()
with aBluetoothProfile.ServiceListener
and theHEALTH
profile type to establish a connection with the profile proxy object. -
Create a
BluetoothHealthCallback
and register an application configuration (BluetoothHealthAppConfiguration
) that acts as a health sink. - Establish a connection to a health device. Some devices will initiate the connection. It is unnecessary to carry out this step for those devices.
-
When connected successfully to a health device, read/write to the health
device using the file descriptor.
The received data needs to be interpreted using a health manager which implements the IEEE 11073-xxxxx specifications.
- When done, close the health channel and unregister the application. The channel also closes when there is extended inactivity.
For a complete code sample that illustrates these steps, see Bluetooth HDP (Health Device Profile) .