diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 5924865cc4faa..42d87f4118c26 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -370,9 +370,17 @@ public final class BluetoothAdapter { } /** - * Turn on the local Bluetooth adapter. + * Turn on the local Bluetooth adapter—do not use without explicit + * user action to turn on Bluetooth. *
This powers on the underlying Bluetooth hardware, and starts all * Bluetooth system services. + *
Bluetooth should never be enabled without + * direct user consent. If you want to turn on Bluetooth in order + * to create a wireless connection, you should use the {@link + * #ACTION_REQUEST_ENABLE} Intent, which will raise a dialog that requests + * user permission to turn on Bluetooth. The {@link #enable()} method is + * provided only for applications that include a user interface for changing + * system settings, such as a "power manager" app.
*This is an asynchronous call: it will return immediately, and * clients should listen for {@link #ACTION_STATE_CHANGED} * to be notified of subsequent adapter state changes. If this call returns @@ -382,7 +390,8 @@ public final class BluetoothAdapter { * #STATE_ON}. If this call returns false then there was an * immediate problem that will prevent the adapter from being turned on - * such as Airplane mode, or the adapter is already turned on. - *
Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} + *
Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN} + * permission * * @return true to indicate adapter startup has begun, or false on * immediate error @@ -395,9 +404,14 @@ public final class BluetoothAdapter { } /** - * Turn off the local Bluetooth adapter. + * Turn off the local Bluetooth adapter—do not use without explicit + * user action to turn off Bluetooth. *
This gracefully shuts down all Bluetooth connections, stops Bluetooth * system services, and powers down the underlying Bluetooth hardware. + *
Bluetooth should never be disbled without + * direct user consent. The {@link #disable()} method is + * provided only for applications that include a user interface for changing + * system settings, such as a "power manager" app.
*This is an asynchronous call: it will return immediately, and * clients should listen for {@link #ACTION_STATE_CHANGED} * to be notified of subsequent adapter state changes. If this call returns @@ -407,7 +421,8 @@ public final class BluetoothAdapter { * #STATE_ON}. If this call returns false then there was an * immediate problem that will prevent the adapter from being turned off - * such as the adapter already being turned off. - *
Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} + *
Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN} + * permission * * @return true to indicate adapter shutdown has begun, or false on * immediate error diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java index bc067130584ef..c7fea9e1dad02 100644 --- a/core/java/android/bluetooth/BluetoothClass.java +++ b/core/java/android/bluetooth/BluetoothClass.java @@ -25,10 +25,6 @@ import android.os.Parcelable; * specify the general device type such as a phone, a computer, or * headset, and whether it's capable of services such as audio or telephony. * - *
The Bluetooth class is useful as a hint to roughly describe a device (for example to - * show an icon in the UI), but does not reliably describe which Bluetooth - * profiles or services are actually supported by a device. - * *
Every Bluetooth class is composed of zero or more service classes, and * exactly one device class. The device class is further broken down into major * and minor device class components. diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs index c28cde106834a..6c6e0e76793ec 100644 --- a/docs/html/guide/guide_toc.cs +++ b/docs/html/guide/guide_toc.cs @@ -191,13 +191,15 @@
-->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:
+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.
+ +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:
+ +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}.
+ +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.
+ +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. Note: If you +use {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission, then must +also have the {@link android.Manifest.permission#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.
+ + +
+Figure 1: The enabling Bluetooth dialog.
+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 {@link android.bluetooth.BluetoothAdapter}.
+ + +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:
+
+BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+if (mBluetoothAdapter == null) {
+ // Device does not support Bluetooth
+}
+
+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:
+
+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).
+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}.
+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.
+ +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.
+ + +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.
+ +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.
+ + +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:
+
+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 {@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 Connecting Devices.
+ + +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.
+ +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:
+
+// 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 {@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 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 +{@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.
+ +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:
++Intent discoverableIntent = new +Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); +discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); +startActivity(discoverableIntent); ++ +
+Figure 2: The enabling discoverability dialog.
+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.
+ +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 {@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.
+ +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.
+ + + +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 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 {@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.
+ +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.
+ +
+Figure 3: The Bluetooth pairing dialog.
+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. 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.
+ + +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.
+ +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)}.
+Here's the basic procedure to set up a server socket and accept a +connection:
+ +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).
+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}.
+This releases the server socket and all its resources, but does not 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.
+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.
+ +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 = 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) { }
+ }
+}
+
+
+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.
+ +Note that when {@link android.bluetooth.BluetoothServerSocket#accept()} +returns the {@link android.bluetooth.BluetoothSocket}, the socket is already +connected, so you should not call {@link +android.bluetooth.BluetoothSocket#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 {@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.
+ + +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 Finding Devices.) You must then use the +{@link android.bluetooth.BluetoothDevice} to acquire a {@link +android.bluetooth.BluetoothSocket} and initiate the connection.
+ +Here's the basic procedure:
+ +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.
+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.
+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.
+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.
+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
+ 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) { }
+ }
+}
+
+
+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()}).
+ +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 {@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.
+ + +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:
+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 {@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}.
+ +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 {@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.
+ +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 {@link
+java.io.OutputStream#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 {@link android.bluetooth.BluetoothSocket}.
+This should always be called when you're done using the Bluetooth
+connection.