diff options
author | Scott Main <smain@google.com> | 2009-12-09 18:06:58 -0800 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2009-12-09 18:06:58 -0800 |
commit | 0ee7706c59ad6e54235a82af52df6e639fa48e81 (patch) | |
tree | f912ade53ed788636c02b5f58bad225a2f38ae93 /docs/html/guide | |
parent | 0df59b47d9936ca2751faf99569f3b3007cadfbd (diff) | |
parent | ed2a70d6495b3f1928e36ad2b00ee4d33b2c0379 (diff) | |
download | frameworks_base-0ee7706c59ad6e54235a82af52df6e639fa48e81.zip frameworks_base-0ee7706c59ad6e54235a82af52df6e639fa48e81.tar.gz frameworks_base-0ee7706c59ad6e54235a82af52df6e639fa48e81.tar.bz2 |
am ed2a70d6: docs: add the Bluetooth developer guide, and make some revisions to the BT javadocs
Merge commit 'ed2a70d6495b3f1928e36ad2b00ee4d33b2c0379' into eclair-plus-aosp
* commit 'ed2a70d6495b3f1928e36ad2b00ee4d33b2c0379':
docs: add the Bluetooth developer guide,
Diffstat (limited to 'docs/html/guide')
-rw-r--r-- | docs/html/guide/guide_toc.cs | 4 | ||||
-rw-r--r-- | docs/html/guide/topics/wireless/bluetooth.jd | 818 |
2 files changed, 817 insertions, 5 deletions
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs index c28cde1..6c6e0e7 100644 --- a/docs/html/guide/guide_toc.cs +++ b/docs/html/guide/guide_toc.cs @@ -191,13 +191,15 @@ <div><a style="color:gray;">Wireless Controls</a></div> <ul> <li><a style="color:gray;">Wi-Fi</a></li> - <li><a style="color:gray;">Bluetooth</a></li> </ul> </li> --> <!--<li><a style="color:gray;">Localization</a></li> --> <li><a href="<?cs var:toroot ?>guide/topics/appwidgets/index.html"> <span class="en">App Widgets</span> </a></li> + <li><a href="<?cs var:toroot?>guide/topics/wireless/bluetooth.html"> + <span class="en">Bluetooth</span> + </a> <span class="new">new!</span></li> </ul> </li> diff --git a/docs/html/guide/topics/wireless/bluetooth.jd b/docs/html/guide/topics/wireless/bluetooth.jd index 710cd4c..21881eb 100644 --- a/docs/html/guide/topics/wireless/bluetooth.jd +++ b/docs/html/guide/topics/wireless/bluetooth.jd @@ -1,18 +1,828 @@ page.title=Bluetooth -parent.title=Wireless Controls -parent.link=index.html @jd:body <div id="qv-wrapper"> <div id="qv"> + <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>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> </div> </div> -TODO
\ No newline at end of file +<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 add 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="#ManagingConnection">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> + +<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> + +<div class="figure" style="width:200px"> +<img src="{@docRoot}images/bt_pairing_request.png" /> +<strong>Figure 3:</strong> The Bluetooth pairing dialog. +</div> + +<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. 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-inner"> +<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="#ManagingConnection">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="#ManagingConnection">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> + + |