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 @@

Wireless Controls
-->
  • App Widgets
  • +
  • + Bluetooth + new!
  • diff --git a/docs/html/guide/topics/wireless/bluetooth.jd b/docs/html/guide/topics/wireless/bluetooth.jd index 710cd4c16847f..21881eb36da04 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
    +

    Key Classes

    +
      +
    1. {@link android.bluetooth.BluetoothAdapter}
    2. +
    3. {@link android.bluetooth.BluetoothDevice}
    4. +
    5. {@link android.bluetooth.BluetoothSocket}
    6. +
    7. {@link android.bluetooth.BluetoothServerSocket}
    8. +

    In this document

      - +
    1. The Basics
    2. +
    3. Bluetooth Permissions
    4. +
    5. Setting Up Bluetooth
    6. +
    7. Finding Devices +
        +
      1. Querying paired devices
      2. +
      3. Discovering devices +
        1. Enabling + discoverability
        +
      4. +
      +
    8. +
    9. Connecting Devices +
        +
      1. Connecting as a server
      2. +
      3. Connecting as a client
      4. +
      +
    10. +
    11. Managing a Connection
    -TODO \ No newline at end of file +

    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:

    + + + +

    The Basics

    + +

    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:

    + +
    +
    {@link android.bluetooth.BluetoothAdapter}
    +
    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.
    + +
    {@link android.bluetooth.BluetoothDevice}
    +
    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.
    + +
    {@link android.bluetooth.BluetoothSocket}
    +
    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.
    + +
    {@link android.bluetooth.BluetoothServerSocket}
    +
    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.
    + +
    {@link android.bluetooth.BluetoothClass}
    +
    Describes the general characteristics and capabilities of a Bluetooth +device. This is a read-only set of properties that define the device's major and +minor device classes and its services. However, this does not reliably describe +all Bluetooth profiles and services supported by the device, but is useful as a +hint to the device type.
    +
    + + + + +

    Bluetooth Permissions

    + +

    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.

    + + +

    Setting Up Bluetooth

    + +
    + +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}.

    + + +
      +
    1. Get 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
      +}
      +
      +
    2. + +
    3. Enable 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}.

      +
    4. +
    + +

    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.

    + + +

    Finding Devices

    + +

    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.

    + + +

    Querying paired devices

    + +

    Before performing device discovery, its worth querying the set +of paired devices to see if the desired device is already known. To do so, +call {@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.

    + + +

    Discovering 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.

    + +

    Enabling discoverability

    + +

    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.

    + + + +

    Connecting Devices

    + +

    In order to create a connection between your application on two devices, you +must implement both the server-side and client-side mechanisms, because one +device must open a server socket and the other one must initiate the connection +(using the server device's MAC address to initiate a connection). The server and +client are considered connected to each other when they each have a connected +{@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.

    + + +

    Connecting as a server

    + +

    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.

    + + + +

    Here's the basic procedure to set up a server socket and accept a +connection:

    + +
      +
    1. Get a {@link android.bluetooth.BluetoothServerSocket} by calling the +{@link +android.bluetooth.BluetoothAdapter#listenUsingRfcommWithServiceRecord(String, +UUID)}. +

      The string is an identifiable name of your service, which the system will +automatically write to a new Service Discovery Protocol (SDP) database entry on +the device (the name is arbitrary and can simply be your application name). The +UUID is also included in the SDP entry and will be the basis for the connection +agreement with the client device. That is, when the client attempts to connect +with this device, it will carry a UUID that uniquely identifies the service with +which it wants to connect. These UUIDs must match in order for the connection to +be accepted (in the next step).

      +
    2. + +
    3. Start listening for connection requests by calling +{@link android.bluetooth.BluetoothServerSocket#accept()}. +

      This is a blocking call. It will return when either a connection has been +accepted or an exception has occurred. A connection is accepted only when a +remote device has sent a connection request with a UUID matching the one +registered with this listening server socket. When successful, {@link +android.bluetooth.BluetoothServerSocket#accept()} will +return a connected {@link android.bluetooth.BluetoothSocket}.

      +
    4. + +
    5. Unless you want to accept additional connections, call +{@link android.bluetooth.BluetoothServerSocket#close()}. +

      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.

      +
    6. +
    + +

    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.

    + +

    Example

    + +

    Here's a simplified thread for the server component that accepts incoming +connections:

    +
    +private class AcceptThread extends Thread {
    +    private final BluetoothServerSocket mmServerSocket;
    +
    +    public AcceptThread() {
    +        // Use a temporary object that is later assigned to mmServerSocket,
    +        // because mmServerSocket is final
    +        BluetoothServerSocket tmp = null;
    +        try {
    +            // MY_UUID is the app's UUID string, also used by the client code
    +            tmp = 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.

    + + +

    Connecting as a client

    + +

    In order to initiate a connection with a remote device (a device holding an +open +server socket), you must first obtain a {@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:

    + +
      +
    1. Using the {@link android.bluetooth.BluetoothDevice}, get a {@link +android.bluetooth.BluetoothSocket} by calling {@link +android.bluetooth.BluetoothDevice#createRfcommSocketToServiceRecord(UUID)}. +

      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.

      +
    2. + +
    3. Initiate the connection by calling {@link +android.bluetooth.BluetoothSocket#connect()}. +

      Upon this call, the system will perform an SDP lookup on the remote device in +order to match the UUID. If the lookup is successful and the remote device +accepts the connection, it will share the RFCOMM channel to use during the +connection and {@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.

      +
    4. +
    + +

    Example

    + +

    Here is a basic example of a thread that initiates a Bluetooth +connection:

    +
    +private class ConnectThread extends Thread {
    +    private final BluetoothSocket mmSocket;
    +    private final BluetoothDevice mmDevice;
    +
    +    public ConnectThread(BluetoothDevice device) {
    +        // Use a temporary object that is later assigned to mmSocket,
    +        // because mmSocket is final
    +        BluetoothSocket tmp = null;
    +        mmDevice = device;
    +
    +        // Get a BluetoothSocket to connect with the given BluetoothDevice
    +        try {
    +            // MY_UUID is the app's UUID string, also used by the server code
    +            tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
    +        } catch (IOException e) { }
    +        mmSocket = tmp;
    +    }
    +
    +    public void run() {
    +        // Cancel discovery because it will slow down the connection
    +        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.

    + + +

    Managing a Connection

    + +

    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:

    +
      +
    1. 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.
    2. + +
    3. Read and write data to the streams with {@link +java.io.InputStream#read(byte[])} and {@link java.io.OutputStream#write(byte[])}.
    4. +
    + +

    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}.

    + +

    Example

    + +

    Here's an example of how this might look:

    +
    +private class ConnectedThread extends Thread {
    +    private final BluetoothSocket mmSocket;
    +    private final InputStream mmInStream;
    +    private final OutputStream mmOutStream;
    +
    +    public ConnectedThread(BluetoothSocket socket) {
    +        mmSocket = socket;
    +        InputStream tmpIn = null;
    +        OutputStream tmpOut = null;
    +
    +        // Get the input and output streams, using temp objects because
    +        // member streams are final
    +        try {
    +            tmpIn = socket.getInputStream();
    +            tmpOut = socket.getOutputStream();
    +        } catch (IOException e) { }
    +
    +        mmInStream = tmpIn;
    +        mmOutStream = tmpOut;
    +    }
    +
    +    public void run() {
    +        byte[] buffer = new byte[1024];  // buffer store for the stream
    +        int bytes; // bytes returned from read()
    +
    +        // Keep listening to the InputStream until an exception occurs
    +        while (true) {
    +            try {
    +                // Read from the InputStream
    +                bytes = mmInStream.read(buffer);
    +                // Send the obtained bytes to the UI Activity
    +                mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
    +                        .sendToTarget();
    +            } catch (IOException e) {
    +                break;
    +            }
    +        }
    +    }
    +
    +    /* Call this from the main Activity to send data to the remote device */
    +    public void write(byte[] bytes) {
    +        try {
    +            mmOutStream.write(bytes);
    +        } catch (IOException e) { }
    +    }
    +
    +    /* Call this from the main Activity to shutdown the connection */
    +    public void cancel() {
    +        try {
    +            mmSocket.close();
    +        } catch (IOException e) { }
    +    }
    +}
    +
    + +

    The constructor acquires the necessary streams and once executed, the thread +will wait for data to come through the InputStream. When {@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.

    + +