847 lines
38 KiB
Plaintext
847 lines
38 KiB
Plaintext
page.title=Bluetooth
|
|
@jd:body
|
|
|
|
<div id="qv-wrapper">
|
|
<div id="qv">
|
|
|
|
<h2>Quickview</h2>
|
|
<ul>
|
|
<li>Android's bluetooth APIs allow your application to perform wireless data transactions with
|
|
other devices</li>
|
|
</ul>
|
|
|
|
<h2>In this document</h2>
|
|
<ol>
|
|
<li><a href="#TheBasics">The Basics</a></li>
|
|
<li><a href="#Permissions">Bluetooth Permissions</a></li>
|
|
<li><a href="#SettingUp">Setting Up Bluetooth</a></li>
|
|
<li><a href="#FindingDevices">Finding Devices</a>
|
|
<ol>
|
|
<li><a href="#QueryingPairedDevices">Querying paired devices</a></li>
|
|
<li><a href="#DiscoveringDevices">Discovering devices</a>
|
|
<ol><li><a href="#EnablingDiscoverability">Enabling
|
|
discoverability</a></li></ol>
|
|
</li>
|
|
</ol>
|
|
</li>
|
|
<li><a href="#ConnectingDevices">Connecting Devices</a>
|
|
<ol>
|
|
<li><a href="#ConnectingAsAServer">Connecting as a server</a></li>
|
|
<li><a href="#ConnectingAsAClient">Connecting as a client</a></li>
|
|
</ol>
|
|
</li>
|
|
<li><a href="#ManagingAConnection">Managing a Connection</a></li>
|
|
</ol>
|
|
|
|
<h2>Key classes</h2>
|
|
<ol>
|
|
<li>{@link android.bluetooth.BluetoothAdapter}</li>
|
|
<li>{@link android.bluetooth.BluetoothDevice}</li>
|
|
<li>{@link android.bluetooth.BluetoothSocket}</li>
|
|
<li>{@link android.bluetooth.BluetoothServerSocket}</li>
|
|
</ol>
|
|
|
|
<h2>Related samples</h2>
|
|
<ol>
|
|
<li><a href="{@docRoot}resources/samples/BluetoothChat/index.html">Bluetooth Chat</a></li>
|
|
</ol>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<p>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.</p>
|
|
|
|
<p>Using the Bluetooth APIs, an Android application can perform the
|
|
following:</p>
|
|
<ul>
|
|
<li>Scan for other Bluetooth devices</li>
|
|
<li>Query the local Bluetooth adapter for paired Bluetooth devices</li>
|
|
<li>Establish RFCOMM channels</li>
|
|
<li>Connect to other devices through service discovery</li>
|
|
<li>Transfer data to and from other devices</li>
|
|
<li>Manage multiple connections</li>
|
|
</ul>
|
|
|
|
|
|
<h2 id="TheBasics">The Basics</h2>
|
|
|
|
<p>This document describes how to us 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.</p>
|
|
|
|
<p>All of the Bluetooth APIs are available in the {@link android.bluetooth}
|
|
package. Here's a summary of the classes you will need to create Bluetooth
|
|
connections:</p>
|
|
|
|
<dl>
|
|
<dt>{@link android.bluetooth.BluetoothAdapter}</dt>
|
|
<dd>Represents the local Bluetooth adapter (Bluetooth radio). The
|
|
{@link android.bluetooth.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 a {@link android.bluetooth.BluetoothDevice} using a known
|
|
MAC address, and create a {@link android.bluetooth.BluetoothServerSocket} to
|
|
listen for communications
|
|
from other devices.</dd>
|
|
|
|
<dt>{@link android.bluetooth.BluetoothDevice}</dt>
|
|
<dd>Represents a remote Bluetooth device. Use this to request a connection
|
|
with a remote device through a {@link android.bluetooth.BluetoothSocket} or
|
|
query information about the
|
|
device such as its name, address, class, and bonding state.</dd>
|
|
|
|
<dt>{@link android.bluetooth.BluetoothSocket}</dt>
|
|
<dd>Represents the interface for a Bluetooth socket (similar to a TCP
|
|
{@link java.net.Socket}). This is the connection point that allows
|
|
an application to exchange data with another Bluetooth device via InputStream
|
|
and OutputStream.</dd>
|
|
|
|
<dt>{@link android.bluetooth.BluetoothServerSocket}</dt>
|
|
<dd>Represents an open server socket that listens for incoming requests
|
|
(similar to a TCP {@link java.net.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, the
|
|
{@link android.bluetooth.BluetoothServerSocket} will return a connected {@link
|
|
android.bluetooth.BluetoothSocket} when the
|
|
connection is accepted.</dd>
|
|
|
|
<dt>{@link android.bluetooth.BluetoothClass}</dt>
|
|
<dd>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.</dd>
|
|
</dl>
|
|
|
|
|
|
|
|
|
|
<h2 id="Permissions">Bluetooth Permissions</h2>
|
|
|
|
<p>In order to use Bluetooth features in your application, you need to declare
|
|
at least one of two Bluetooth permissions: {@link
|
|
android.Manifest.permission#BLUETOOTH} and {@link
|
|
android.Manifest.permission#BLUETOOTH_ADMIN}.</p>
|
|
|
|
<p>You must request the {@link android.Manifest.permission#BLUETOOTH} permission
|
|
in order to perform any Bluetooth communication, such as requesting a
|
|
connection, accepting a connection, and transferring data.</p>
|
|
|
|
<p>You must request the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
|
|
permission in order to initiate device discovery or manipulate Bluetooth
|
|
settings. 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. <strong>Note:</strong> If you
|
|
use {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission, then must
|
|
also have the {@link android.Manifest.permission#BLUETOOTH} permission.</p>
|
|
|
|
<p>Declare the Bluetooth permission(s) in your application manifest file. For
|
|
example:</p>
|
|
|
|
<pre>
|
|
<manifest ... >
|
|
<uses-permission android:name="android.permission.BLUETOOTH" />
|
|
...
|
|
</manifest>
|
|
</pre>
|
|
|
|
<p>See the <a
|
|
href="{@docRoot}guide/topics/manifest/uses-permission-element.html"><uses-permission></a>
|
|
reference for more information about declaring application permissions.</p>
|
|
|
|
|
|
<h2 id="SettingUp">Setting Up Bluetooth</h2>
|
|
|
|
<div class="figure" style="width:200px">
|
|
<img src="{@docRoot}images/bt_enable_request.png" />
|
|
<strong>Figure 1:</strong> The enabling Bluetooth dialog.
|
|
</div>
|
|
|
|
<p>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.</p>
|
|
|
|
<p>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 {@link android.bluetooth.BluetoothAdapter}.</p>
|
|
|
|
|
|
<ol>
|
|
<li>Get the {@link android.bluetooth.BluetoothAdapter}
|
|
<p>The {@link android.bluetooth.BluetoothAdapter} is required for any and all Bluetooth
|
|
activity. To get the {@link android.bluetooth.BluetoothAdapter}, call the static {@link
|
|
android.bluetooth.BluetoothAdapter#getDefaultAdapter()} method. This returns a
|
|
{@link android.bluetooth.BluetoothAdapter} 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. If
|
|
{@link android.bluetooth.BluetoothAdapter#getDefaultAdapter()} returns null,
|
|
then the device does not support Bluetooth and your story ends here. For example:</p>
|
|
<pre>
|
|
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
|
if (mBluetoothAdapter == null) {
|
|
// Device does not support Bluetooth
|
|
}
|
|
</pre>
|
|
</li>
|
|
|
|
<li>Enable Bluetooth
|
|
<p>Next, you need to ensure that Bluetooth is enabled. Call {@link
|
|
android.bluetooth.BluetoothAdapter#isEnabled()} to check whether Bluetooth is
|
|
currently enable. If this method returns false, then Bluetooth is disabled. To
|
|
request that Bluetooth be enabled, call {@link
|
|
android.app.Activity#startActivityForResult(Intent,int) startActivityForResult()}
|
|
with the {@link android.bluetooth.BluetoothAdapter#ACTION_REQUEST_ENABLE} action Intent.
|
|
This will issue a request to enable Bluetooth through the system settings (without
|
|
stopping your application). For example:</p>
|
|
<pre>
|
|
if (!mBluetoothAdapter.isEnabled()) {
|
|
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
|
|
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
|
|
}
|
|
</pre>
|
|
|
|
<p>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).</p>
|
|
<p>If enabling Bluetooth succeeds, your Activity will receive the {@link
|
|
android.app.Activity#RESULT_OK} result code in the {@link
|
|
android.app.Activity#onActivityResult(int,int,Intent) onActivityResult()}
|
|
callback. If Bluetooth was not enabled
|
|
due to an error (or the user responded "No") then the result code will be {@link
|
|
android.app.Activity#RESULT_CANCELED}.</p>
|
|
</li>
|
|
</ol>
|
|
|
|
<p>Optionally, your application can also listen for the
|
|
{@link android.bluetooth.BluetoothAdapter#ACTION_STATE_CHANGED} broadcast Intent, which
|
|
the system will broadcast whenever the Bluetooth state has changed. This broadcast contains
|
|
the extra fields {@link android.bluetooth.BluetoothAdapter#EXTRA_STATE} and {@link
|
|
android.bluetooth.BluetoothAdapter#EXTRA_PREVIOUS_STATE}, containing the new and old
|
|
Bluetooth states, respectively. Possible values for these extra fields are
|
|
{@link android.bluetooth.BluetoothAdapter#STATE_TURNING_ON}, {@link
|
|
android.bluetooth.BluetoothAdapter#STATE_ON}, {@link
|
|
android.bluetooth.BluetoothAdapter#STATE_TURNING_OFF}, and {@link
|
|
android.bluetooth.BluetoothAdapter#STATE_OFF}. Listening for this
|
|
broadcast can be useful to detect changes made to the Bluetooth state while your
|
|
app is running.</p>
|
|
|
|
<p class="note"><strong>Tip:</strong> 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 <a href="#EnablingDiscoverability">enabling discoverability</a>,
|
|
below.</p>
|
|
|
|
|
|
<h2 id="FindingDevices">Finding Devices</h2>
|
|
|
|
<p>Using the {@link android.bluetooth.BluetoothAdapter}, you can find remote Bluetooth
|
|
devices either through device discovery or by querying the list of paired (bonded)
|
|
devices.</p>
|
|
|
|
<p>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.</p>
|
|
|
|
<p>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).</p>
|
|
|
|
<p>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.)</p>
|
|
|
|
<p>The following sections describe how to find devices that have been paired, or
|
|
discover new devices using device discovery.</p>
|
|
|
|
<p class="note"><strong>Note:</strong> 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 <a href="#EnablingDiscoverability">enable discoverability</a>
|
|
is discussed below.</p>
|
|
|
|
|
|
<h3 id="QueryingPairedDevices">Querying paired devices</h3>
|
|
|
|
<p>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 {@link android.bluetooth.BluetoothAdapter#getBondedDevices()}. This
|
|
will return a Set of {@link android.bluetooth.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:</p>
|
|
<pre>
|
|
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());
|
|
}
|
|
}
|
|
</pre>
|
|
|
|
<p>All that's needed from the {@link android.bluetooth.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 <a href="#ConnectingDevices">Connecting Devices</a>.</p>
|
|
|
|
|
|
<h3 id="DiscoveringDevices">Discovering devices</h3>
|
|
|
|
<p>To start discovering devices, simply call {@link
|
|
android.bluetooth.BluetoothAdapter#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.</p>
|
|
|
|
<p>Your application must register a BroadcastReceiver for the
|
|
{@link android.bluetooth.BluetoothDevice#ACTION_FOUND} Intent in
|
|
order to receive information about each
|
|
device discovered. For each device, the system will broadcast the
|
|
{@link android.bluetooth.BluetoothDevice#ACTION_FOUND} Intent. This
|
|
Intent carries the extra fields
|
|
{@link android.bluetooth.BluetoothDevice#EXTRA_DEVICE} and
|
|
{@link android.bluetooth.BluetoothDevice#EXTRA_CLASS}, containing a
|
|
{@link android.bluetooth.BluetoothDevice} and a {@link
|
|
android.bluetooth.BluetoothClass}, respectively. For example, here's how you can
|
|
register to handle the broadcast when devices are discovered:</p>
|
|
<pre>
|
|
// 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
|
|
</pre>
|
|
|
|
<p>All that's needed from the {@link android.bluetooth.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 <a href="#ConnectingDevices">Connecting Devices</a>.</p>
|
|
|
|
<p class="caution"><strong>Caution:</strong> 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
|
|
{@link android.bluetooth.BluetoothAdapter#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.</p>
|
|
|
|
<h4 id="EnablingDiscoverability">Enabling discoverability</h4>
|
|
|
|
<p>If you would like to make the local device discoverable to other devices,
|
|
call {@link android.app.Activity#startActivityForResult(Intent,int)} with the
|
|
{@link android.bluetooth.BluetoothAdapter#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
|
|
{@link android.bluetooth.BluetoothAdapter#EXTRA_DISCOVERABLE_DURATION} Intent extra
|
|
(maximum duration is 300 seconds). For example:</p>
|
|
<pre>
|
|
Intent discoverableIntent = new
|
|
Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
|
|
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
|
|
startActivity(discoverableIntent);
|
|
</pre>
|
|
|
|
<div class="figure" style="width:200px">
|
|
<img src="{@docRoot}images/bt_enable_discoverable.png" />
|
|
<strong>Figure 2:</strong> The enabling discoverability dialog.
|
|
</div>
|
|
|
|
<p>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 {@link android.app.Activity#onActivityResult(int,int,Intent)
|
|
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 Activity.RESULT_CANCELLED.</p>
|
|
|
|
<p class="note"><strong>Note:</strong> If Bluetooth has not been enabled on the device,
|
|
then enabling device discoverability will automatically enable Bluetooth.</p>
|
|
|
|
<p>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 {@link
|
|
android.bluetooth.BluetoothAdapter#ACTION_SCAN_MODE_CHANGED}
|
|
Intent. This will contain the extra fields {@link
|
|
android.bluetooth.BluetoothAdapter#EXTRA_SCAN_MODE} and
|
|
{@link android.bluetooth.BluetoothAdapter#EXTRA_PREVIOUS_SCAN_MODE}, which tell you the
|
|
new and old scan mode, respectively. Possible values for each are
|
|
{@link android.bluetooth.BluetoothAdapter#SCAN_MODE_CONNECTABLE_DISCOVERABLE},
|
|
{@link android.bluetooth.BluetoothAdapter#SCAN_MODE_CONNECTABLE}, or {@link
|
|
android.bluetooth.BluetoothAdapter#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.</p>
|
|
|
|
<p>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.</p>
|
|
|
|
|
|
|
|
<h2 id="ConnectingDevices">Connecting Devices</h2>
|
|
|
|
<p>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
|
|
{@link android.bluetooth.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 <a
|
|
href="#ManagingAConnection">Managing a Connection</a>. This section describes how
|
|
to initiate the connection between two devices.</p>
|
|
|
|
<p>The server device and the client device each obtain the required {@link
|
|
android.bluetooth.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.</p>
|
|
|
|
<div class="figure" style="width:200px">
|
|
<img src="{@docRoot}images/bt_pairing_request.png" />
|
|
<strong>Figure 3:</strong> The Bluetooth pairing dialog.
|
|
</div>
|
|
|
|
<p>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.</p>
|
|
|
|
<p class="note"><strong>Note:</strong> 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. </p>
|
|
|
|
|
|
<h3 id="ConnectingAsAServer">Connecting as a server</h3>
|
|
|
|
<p>When you want to connect two devices, one must act as a server by holding an
|
|
open {@link android.bluetooth.BluetoothServerSocket}. The purpose of the server
|
|
socket is to listen for incoming connection requests and when one is accepted,
|
|
provide a connected {@link android.bluetooth.BluetoothSocket}. When the {@link
|
|
android.bluetooth.BluetoothSocket} is acquired from the {@link
|
|
android.bluetooth.BluetoothServerSocket},
|
|
the {@link android.bluetooth.BluetoothServerSocket} can (and should) be
|
|
discarded, unless you want to accept more connections.</p>
|
|
|
|
<div class="sidebox-wrapper">
|
|
<div class="sidebox">
|
|
<h2>About UUID</h2>
|
|
|
|
<p>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 {@link java.util.UUID} with {@link
|
|
java.util.UUID#fromString(String)}.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<p>Here's the basic procedure to set up a server socket and accept a
|
|
connection:</p>
|
|
|
|
<ol>
|
|
<li>Get a {@link android.bluetooth.BluetoothServerSocket} by calling the
|
|
{@link
|
|
android.bluetooth.BluetoothAdapter#listenUsingRfcommWithServiceRecord(String,
|
|
UUID)}.
|
|
<p>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).</p>
|
|
</li>
|
|
|
|
<li>Start listening for connection requests by calling
|
|
{@link android.bluetooth.BluetoothServerSocket#accept()}.
|
|
<p>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, {@link
|
|
android.bluetooth.BluetoothServerSocket#accept()} will
|
|
return a connected {@link android.bluetooth.BluetoothSocket}.</p>
|
|
</li>
|
|
|
|
<li>Unless you want to accept additional connections, call
|
|
{@link android.bluetooth.BluetoothServerSocket#close()}.
|
|
<p>This releases the server socket and all its resources, but does <em>not</em> close the
|
|
connected {@link android.bluetooth.BluetoothSocket} that's been returned by {@link
|
|
android.bluetooth.BluetoothServerSocket#accept()}. Unlike TCP/IP, RFCOMM only allows one
|
|
connected client per channel at a time, so in most cases it makes sense to call {@link
|
|
android.bluetooth.BluetoothServerSocket#close()} on the {@link
|
|
android.bluetooth.BluetoothServerSocket} immediately after accepting a connected
|
|
socket.</p>
|
|
</li>
|
|
</ol>
|
|
|
|
<p>The {@link android.bluetooth.BluetoothServerSocket#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 {@link android.bluetooth.BluetoothServerSocket} or {@link
|
|
android.bluetooth.BluetoothSocket} in a new
|
|
thread managed by your application. To abort a blocked call such as {@link
|
|
android.bluetooth.BluetoothServerSocket#accept()}, call {@link
|
|
android.bluetooth.BluetoothServerSocket#close()} on the {@link
|
|
android.bluetooth.BluetoothServerSocket} (or {@link
|
|
android.bluetooth.BluetoothSocket}) from another thread and the blocked call will
|
|
immediately return. Note that all methods on a {@link
|
|
android.bluetooth.BluetoothServerSocket} or {@link android.bluetooth.BluetoothSocket}
|
|
are thread-safe.</p>
|
|
|
|
<h4>Example</h4>
|
|
|
|
<p>Here's a simplified thread for the server component that accepts incoming
|
|
connections:</p>
|
|
<pre>
|
|
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 = mAdapter.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) { }
|
|
}
|
|
}
|
|
</pre>
|
|
|
|
<p>In this example, only one incoming connection is desired, so as soon as a
|
|
connection is accepted and the {@link android.bluetooth.BluetoothSocket} is
|
|
acquired, the application
|
|
sends the acquired {@link android.bluetooth.BluetoothSocket} to a separate
|
|
thread, closes the
|
|
{@link android.bluetooth.BluetoothServerSocket} and breaks the loop.</p>
|
|
|
|
<p>Note that when {@link android.bluetooth.BluetoothServerSocket#accept()}
|
|
returns the {@link android.bluetooth.BluetoothSocket}, the socket is already
|
|
connected, so you should <em>not</em> call {@link
|
|
android.bluetooth.BluetoothSocket#connect()} (as you do from the
|
|
client-side).</p>
|
|
|
|
<p><code>manageConnectedSocket()</code> is a fictional method in the application
|
|
that will
|
|
initiate the thread for transferring data, which is discussed in the section
|
|
about <a href="#ManagingAConnection">Managing a Connection</a>.</p>
|
|
|
|
<p>You should usually close your {@link android.bluetooth.BluetoothServerSocket}
|
|
as soon as you are done listening for incoming connections. In this example, {@link
|
|
android.bluetooth.BluetoothServerSocket#close()} is called as soon
|
|
as the {@link android.bluetooth.BluetoothSocket} is acquired. You may also want
|
|
to provide a public method in your thread that can close the private {@link
|
|
android.bluetooth.BluetoothSocket} in the event that you need to stop listening on the
|
|
server socket.</p>
|
|
|
|
|
|
<h3 id="ConnectingAsAClient">Connecting as a client</h3>
|
|
|
|
<p>In order to initiate a connection with a remote device (a device holding an
|
|
open
|
|
server socket), you must first obtain a {@link
|
|
android.bluetooth.BluetoothDevice} object that represents the remote device.
|
|
(Getting a {@link android.bluetooth.BluetoothDevice} is covered in the above
|
|
section about <a
|
|
href="#FindingDevices">Finding Devices</a>.) You must then use the
|
|
{@link android.bluetooth.BluetoothDevice} to acquire a {@link
|
|
android.bluetooth.BluetoothSocket} and initiate the connection.</p>
|
|
|
|
<p>Here's the basic procedure:</p>
|
|
|
|
<ol>
|
|
<li>Using the {@link android.bluetooth.BluetoothDevice}, get a {@link
|
|
android.bluetooth.BluetoothSocket} by calling {@link
|
|
android.bluetooth.BluetoothDevice#createRfcommSocketToServiceRecord(UUID)}.
|
|
<p>This initializes a {@link android.bluetooth.BluetoothSocket} that will
|
|
connect to the {@link android.bluetooth.BluetoothDevice}. The UUID passed here
|
|
must match the UUID used by the server device when it opened its
|
|
{@link android.bluetooth.BluetoothServerSocket} (with {@link
|
|
android.bluetooth.BluetoothAdapter#listenUsingRfcommWithServiceRecord(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.</p>
|
|
</li>
|
|
|
|
<li>Initiate the connection by calling {@link
|
|
android.bluetooth.BluetoothSocket#connect()}.
|
|
<p>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 {@link
|
|
android.bluetooth.BluetoothSocket#connect()} will return. This method is a
|
|
blocking call. If, for
|
|
any reason, the connection fails or the {@link
|
|
android.bluetooth.BluetoothSocket#connect()} method times out (after about
|
|
12 seconds), then it will throw an exception.</p>
|
|
<p>Because {@link
|
|
android.bluetooth.BluetoothSocket#connect()} is a blocking call, this connection
|
|
procedure should always be performed in a thread separate from the main Activity
|
|
thread.</p>
|
|
<p class="note">Note: You should always ensure that the device is not performing
|
|
device discovery when you call {@link
|
|
android.bluetooth.BluetoothSocket#connect()}. If discovery is in progress, then
|
|
the
|
|
connection attempt will be significantly slowed and is more likely to fail.</p>
|
|
</li>
|
|
</ol>
|
|
|
|
<h4>Example</h4>
|
|
|
|
<p>Here is a basic example of a thread that initiates a Bluetooth
|
|
connection:</p>
|
|
<pre>
|
|
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
|
|
mAdapter.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) { }
|
|
}
|
|
}
|
|
</pre>
|
|
|
|
<p>Notice that {@link android.bluetooth.BluetoothAdapter#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 {@link android.bluetooth.BluetoothAdapter#isDiscovering()}).</p>
|
|
|
|
<p><code>manageConnectedSocket()</code> is a fictional method in the application
|
|
that will initiate the thread for transferring data, which is discussed in the section
|
|
about <a href="#ManagingAConnection">Managing a Connection</a>.</p>
|
|
|
|
<p>When you're done with your {@link android.bluetooth.BluetoothSocket}, always
|
|
call {@link android.bluetooth.BluetoothSocket#close()} to clean up.
|
|
Doing so will immediately close the connected socket and clean up all internal
|
|
resources.</p>
|
|
|
|
|
|
<h2 id="ManagingAConnection">Managing a Connection</h2>
|
|
|
|
<p>When you have successfully connected two (or more) devices, each one will
|
|
have a connected {@link android.bluetooth.BluetoothSocket}. This is where the fun
|
|
begins because you can share data between devices. Using the {@link
|
|
android.bluetooth.BluetoothSocket}, the general procedure to transfer arbitrary data is
|
|
simple:</p>
|
|
<ol>
|
|
<li>Get the {@link java.io.InputStream} and {@link java.io.OutputStream} that
|
|
handle transmissions through the socket, via {@link
|
|
android.bluetooth.BluetoothSocket#getInputStream()} and
|
|
{@link android.bluetooth.BluetoothSocket#getOutputStream}, respectively.</li>
|
|
|
|
<li>Read and write data to the streams with {@link
|
|
java.io.InputStream#read(byte[])} and {@link java.io.OutputStream#write(byte[])}.</li>
|
|
</ol>
|
|
|
|
<p>That's it.</p>
|
|
|
|
<p>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 {@link java.io.InputStream#read(byte[])} and {@link
|
|
java.io.OutputStream#write(byte[])} methods are blocking calls. {@link
|
|
java.io.InputStream#read(byte[])} will block until there is something to read
|
|
from the stream. {@link java.io.OutputStream#write(byte[])} does not usually
|
|
block, but can block for flow control if the remote device is not calling {@link
|
|
java.io.InputStream#read(byte[])} quickly enough and the intermediate buffers are full.
|
|
So, your main loop in the thread should be dedicated to reading from the {@link
|
|
java.io.InputStream}. A separate public method in the thread can be used to initiate
|
|
writes to the {@link java.io.OutputStream}.</p>
|
|
|
|
<h4>Example</h4>
|
|
|
|
<p>Here's an example of how this might look:</p>
|
|
<pre>
|
|
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) { }
|
|
}
|
|
}
|
|
</pre>
|
|
|
|
<p>The constructor acquires the necessary streams and once executed, the thread
|
|
will wait for data to come through the InputStream. When {@link
|
|
java.io.InputStream#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.</p>
|
|
|
|
<p>Sending outgoing data is as simple as calling the thread's
|
|
<code>write()</code> method from the main Activity and passing in the bytes to
|
|
be sent. This method then simply calls {@link
|
|
java.io.OutputStream#write(byte[])} to send the data to the remote device.</p>
|
|
|
|
<p>The thread's <code>cancel()</code> method is important so that the connection
|
|
can be
|
|
terminated at any time by closing the {@link android.bluetooth.BluetoothSocket}.
|
|
This should always be called when you're done using the Bluetooth
|
|
connection.</p>
|
|
|
|
<div class="special">
|
|
<p>For a complete demonstration using the Bluetooth APIs, see the <a
|
|
href="{@docRoot}resources/samples/BluetoothChat/index.html">Bluetooth Chat sample app</a>.</p>
|
|
</div>
|