Bluetooth
The Androidplatform includes support for the Bluetoothnetwork stack, which allows a deviceto wirelessly exchange data with otherBluetooth devices. The applicationframework provides access to the Bluetoothfunctionality through the AndroidBluetooth APIs. These APIs let applicationswirelessly connect to otherBluetooth devices, enabling point-to-point andmultipoint wireless features.
UsingtheBluetooth APIs, an Android application can perform the following:
- Scan for other Bluetooth devices
- Query the local Bluetooth adapter for paired Bluetooth devices
- Establish RFCOMM channels
- Connect to other devices through service discovery
- Transfer data to and from other devices
- Manage multiple connections
All of theBluetooth APIs are available in the android.bluetooth package. Here's asummary of the classesand interfaces you will need to create Bluetoothconnections:
Four major tasksnecessary to communicate using Bluetooth: settingup Bluetooth, finding devices that are eitherpaired or available in the localarea, connecting devices, and transferring databetween devices.
Representsthelocal Bluetooth adapter (Bluetooth radio). The BluetoothAdapter is the entry-point for all Bluetoothinteraction. Usingthis, you can discover other Bluetooth devices, query a listof bonded (paired)devices, instantiate a BluetoothDevice using a known MAC address, and createa BluetoothServerSocket to listen for communications fromother devices.
Representsaremote Bluetooth device. Use this to request a connection with a remotedevicethrough a BluetoothSocket or query information about the devicesuch as its name,address, class, and bonding state.
Representstheinterface for a Bluetooth socket (similar to a TCP Socket). This is the connection point that allowsan applicationto exchange data with another Bluetooth device via InputStreamand OutputStream.
Representsanopen server socket that listens for incoming requests (similar to a TCP ServerSocket). In order to connect two Android devices,one devicemust open a server socket with this class. When a remote Bluetoothdevice makesa connection request to the this device, the BluetoothServerSocket will return a connected BluetoothSocket when the connection is accepted.
Describesthegeneral characteristics and capabilities of a Bluetooth device. This isaread-only set of properties that define the device's major and minordeviceclasses and its services. However, this does not reliably describeallBluetooth profiles and services supported by the device, but is useful asahint to the device type.
An interfacethatrepresents a Bluetooth profile. A Bluetooth profile is awirelessinterface specification for Bluetooth-based communication betweendevices. Anexample is the Hands-Free profile. For more discussion of profiles,see Working with Profiles
Providessupportfor Bluetooth headsets to be used with mobile phones. This includesbothBluetooth Headset and Hands-Free (v1.5) profiles.
Defines howhighquality audio can be streamed from one device to another over aBluetoothconnection. "A2DP" stands for Advanced Audio DistributionProfile.
BluetoothProfile.ServiceListener
An interfacethatnotifies BluetoothProfile IPC clients when they have beenconnected to or disconnectedfrom the service (that is, the internal servicethat runs a particular profile).
BluetoothPermissions
Inorder to useBluetooth features in your application, you need to declare atleast one of twoBluetooth permissions: BLUETOOTH and BLUETOOTH_ADMIN.
Declare theBluetooth permission(s) in your applicationmanifest file. For example:
<manifest ... >
<uses-permissionandroid:name="android.permission.BLUETOOTH"/>
...
</manifest>
SettingUpBluetooth
1. Get the BluetoothAdapter
BluetoothAdapter mBluetoothAdapter =BluetoothAdapter.getDefaultAdapter();
if(mBluetoothAdapter==null){
// Devicedoes not support Bluetooth
}
2. EnableBluetooth
if(!mBluetoothAdapter.isEnabled()){
Intent enableBtIntent =newIntent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
Finding Devices
Using the BluetoothAdapter, you can find remoteBluetooth deviceseither through device discovery or by querying the list ofpaired (bonded)devices.
Note: Android-powereddevices are notdiscoverable by default. A user can make the device discoverablefor a limitedtime through the system settings, or an application can requestthat the userenable discoverability without leaving the application. How to enablediscoverability is discussed below.
Querying paireddevices
Beforeperforming devicediscovery, its worth querying the set of paired devices tosee if the desireddevice is already known. To do so, call getBondedDevices(). This will return aSet ofBluetoothDevices representing paireddevices. For example, youcan query all paired devices and then show the name ofeach device to the user,using an ArrayAdapter:
Set<BluetoothDevice> pairedDevices =mBluetoothAdapter.getBondedDevices();
// If there are paired devices
if(pairedDevices.size()>0){
// Loopthrough 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 neededfrom the BluetoothDevice object in order toinitiate a connectionis the MAC address. In this example, it's saved as a partof an ArrayAdapterthat's shown to the user. The MAC address can later beextracted in order toinitiate the connection.
Discoveringdevices
// Create a BroadcastReceiver forACTION_FOUND
privatefinalBroadcastReceiver mReceiver =newBroadcastReceiver(){
publicvoid 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 =newIntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter);// Don't forget to unregister duringonDestroy
Enablingdiscoverability
IntentdiscoverableIntent =new
Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,300);
startActivity(discoverableIntent);
Note: If Bluetooth has notbeen enabled on thedevice, then enabling device discoverability willautomatically enableBluetooth.
You do not needto enable device discoverability if you will be initiatingthe connection to aremote device. Enabling discoverability is only necessarywhen you want yourapplication to host a server socket that will accept incomingconnections,because the remote devices must be able to discover the devicebefore it caninitiate the connection.
ConnectingDevices
In order tocreate a connection between your application on two devices,you must implementboth the server-side and client-side mechanisms, because onedevice must open aserver socket and the other one must initiate the connection(using the serverdevice's MAC address to initiate a connection).
The server deviceand the client device each obtain the required BluetoothSocket in different ways. Theserver willreceive it when an incoming connection is accepted. The client willreceive itwhen it opens an RFCOMM channel to the server.
Note: If the two deviceshave not beenpreviously paired, then the Android framework will automaticallyshow a pairingrequest notification or dialog to the user during the connectionprocedure, asshown in Figure 3. So when attempting to connect devices, yourapplication doesnot need to be concerned about whether or not the devices arepaired. YourRFCOMM connection attempt will block until the user hassuccessfully paired, orwill fail if the user rejects pairing, or if pairingfails or times out.
Connecting as aserver
When you want toconnect two devices, one must act as a server by holdingan open BluetoothServerSocket. The purpose of theserver socket is tolisten for incoming connection requests and when one isaccepted, provide aconnected BluetoothSocket. When the BluetoothSocket is acquired from theBluetoothServerSocket, the BluetoothServerSocket can (and should) bediscarded, unless youwant to accept more connections.
Here's the basicprocedure to set up a server socket and accept aconnection:
1.Get a BluetoothServerSocket by calling the listenUsingRfcommWithServiceRecord(String,UUID).
2.Startlistening for connectionrequests by calling accept().
3.Unlessyou want toaccept additional connections, call close().
The accept() call should not beexecuted in the mainActivity UI thread because it is a blocking call and willprevent any otherinteraction with the application. It usually makes sense to doall work with a BluetoothServerSocket or BluetoothSocket in a new threadmanaged by yourapplication. To abort a blocked call such as accept(), call close() on the BluetoothServerSocket (orBluetoothSocket) from another threadand the blocked call willimmediately return. Note that all methods on a BluetoothServerSocket or BluetoothSocket are thread-safe.
Example
Here's a simplifiedthread for the server component thataccepts incoming connections:
privateclassAcceptThreadextendsThread{
privatefinalBluetoothServerSocket mmServerSocket;
publicAcceptThread(){
// Use a temporary object that is later assigned to mmServerSocket,
// because mmServerSocket is final
BluetoothServerSocket tmp =null;
try{
// MY_UUID is the app's UUID string, also used by the client code
tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
}catch(IOException e){}
mmServerSocket = tmp;
}
publicvoid 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, andcause the thread to finish */
publicvoid cancel(){
try{
mmServerSocket.close();
}catch(IOException e){}
}
}
Connecting as aclient
Here's the basicprocedure:
1.Using the BluetoothDevice, get a BluetoothSocket by calling createRfcommSocketToServiceRecord(UUID).
2. Initiate the connection by calling connect().
Note: You shouldalways ensure that the device is not performing devicediscovery when you call connect(). If discovery is inprogress, then theconnection attempt will be significantly slowed and is morelikely to fail.
Example
Here is a basicexample of a thread that initiates aBluetooth connection:
privateclassConnectThreadextendsThread{
privatefinalBluetoothSocket mmSocket;
privatefinalBluetoothDevice mmDevice;
publicConnectThread(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 connectwith 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;
}
publicvoid run(){
// Cancel discovery because it will slow down the connection
mBluetoothAdapter.cancelDiscovery();
try{
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mmSocket.connect();
}catch(IOException connectException){
// Unable to connect; close the socket and get out
try{
mmSocket.close();
}catch(IOException closeException){}
return;
}
// Do work to manage the connection (ina separate thread)
manageConnectedSocket(mmSocket);
}
/** Will cancel an in-progress connection,and close the socket */
publicvoid cancel(){
try{
mmSocket.close();
}catch(IOException e){}
}
}
ManagingaConnection
Whenyou havesuccessfully connected two (or more) devices, each one will have aconnected BluetoothSocket. This is where the fun begins because youcan share databetween devices. Using theBluetoothSocket, the general procedure to transferarbitrary data issimple:
1.Get the InputStream and OutputStream that handle transmissions through thesocket, via getInputStream() and getOutputStream(), respectively.
2.Read and writedata to the streams with read(byte[]) and write(byte[]).
Example
Here's anexample of how this might look:
privateclassConnectedThreadextendsThread{
privatefinalBluetoothSocket mmSocket;
privatefinalInputStream mmInStream;
privatefinalOutputStream mmOutStream;
publicConnectedThread(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;
}
publicvoid run(){
byte[] buffer =newbyte[1024]; // bufferstore 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;
}
}
}
/* Callthis from the main Activity to send data to the remote device */
publicvoid write(byte[] bytes){
try{
mmOutStream.write(bytes);
}catch(IOException e){}
}
/* Callthis from the main Activity to shutdown the connection */
publicvoid cancel(){
try{
mmSocket.close();
}catch(IOException e){}
}
}
Representsthelocal Bluetooth adapter (Bluetooth radio). The BluetoothAdapter is the entry-point for all Bluetoothinteraction. Usingthis, you can discover other Bluetooth devices, query a listof bonded (paired)devices, instantiate a BluetoothDevice using a known MAC address, and createa BluetoothServerSocket to listen for communications fromother devices.
Representsaremote Bluetooth device. Use this to request a connection with a remotedevicethrough a BluetoothSocket or query information about the devicesuch as its name,address, class, and bonding state.
Representstheinterface for a Bluetooth socket (similar to a TCP Socket). This is the connection point that allowsan applicationto exchange data with another Bluetooth device via InputStreamand OutputStream.
Representsanopen server socket that listens for incoming requests (similar to a TCP ServerSocket). In order to connect two Android devices,one devicemust open a server socket with this class. When a remote Bluetoothdevice makesa connection request to the this device, the BluetoothServerSocket will return a connected BluetoothSocket when the connection is accepted.
Describesthegeneral characteristics and capabilities of a Bluetooth device. This isaread-only set of properties that define the device's major and minordeviceclasses and its services. However, this does not reliably describeallBluetooth profiles and services supported by the device, but is useful asahint to the device type.
An interfacethatrepresents a Bluetooth profile. A Bluetooth profile is awirelessinterface specification for Bluetooth-based communication betweendevices. Anexample is the Hands-Free profile. For more discussion of profiles,see Working with Profiles
Providessupportfor Bluetooth headsets to be used with mobile phones. This includesbothBluetooth Headset and Hands-Free (v1.5) profiles.
Defines howhighquality audio can be streamed from one device to another over aBluetoothconnection. "A2DP" stands for Advanced Audio DistributionProfile.
BluetoothProfile.ServiceListener
An interfacethatnotifies BluetoothProfile IPC clients when they have beenconnected to ordisconnected from the service (that is, the internal servicethat runs aparticular profile).
To get a BluetoothAdapter representing the localBluetooth adapter, call the static getDefaultAdapter() method. Fundamentally, this is your startingpointfor all Bluetooth actions. Once you have the local adapter, you can get aset ofBluetoothDevice objects representingall paired deviceswith getBondedDevices();start device discovery with startDiscovery();or create a BluetoothServerSocket to listen forincoming connection requestswith listenUsingRfcommWithServiceRecord(String,UUID).
Note:Most methodsrequire the BLUETOOTH permissionand some also require the BLUETOOTH_ADMIN permission.
To get a BluetoothDevice, use BluetoothAdapter.getRemoteDevice(String) to create onerepresenting a device of aknown MAC address (which you can get through devicediscovery withBluetoothAdapter)or get one from the set of bonded devicesreturned by BluetoothAdapter.getBondedDevices().You can then open a BluetoothSocket forcommunication with the remote device,using createRfcommSocketToServiceRecord(UUID).
Note:Requires the BLUETOOTH permission.
The interface for Bluetooth Sockets is similar to that of TCP sockets: Socket and ServerSocket. On the server side, usea BluetoothServerSocket to create a listeningserver socket. When a connection isaccepted by the BluetoothServerSocket, it will return a new BluetoothSocket to manage the connection.On the client side, use a single BluetoothSocket to both initiate anoutgoing connection and to manage theconnection.
To create a BluetoothSocket for connecting to a knowndevice, use BluetoothDevice.createRfcommSocketToServiceRecord(). Then call connect() to attempt a connection to the remotedevice. This call willblock until a connection is established or the connectionfails.
BluetoothSocket is threadsafe. In particular, close() will alwaysimmediately abort ongoing operations andclose the socket.
Note:Requires the BLUETOOTH permission.
On the server side, use a BluetoothServerSocket to create a listeningserver socket. When a connection isaccepted by the BluetoothServerSocket, it will return a new BluetoothSocket to manage the connection.On the client side, use a single BluetoothSocket to both initiate anoutgoing connection and to manage theconnection.
To create alistening BluetoothServerSocket that's readyfor incoming connections, use BluetoothAdapter.listenUsingRfcommWithServiceRecord().Then call accept() to listen forincoming connection requests. This callwill block until a connection isestablished, at which point, it will return a BluetoothSocket to manage theconnection. Once the BluetoothSocket is acquired,it's a good idea to call close() on the BluetoothServerSocket when it's nolonger needed for acceptingconnections. Closing the BluetoothServerSocket will not closethereturned BluetoothSocket.
BluetoothServerSocket is threadsafe. In particular, close() will alwaysimmediately abort ongoing operations andclose the server socket.
Note:Requires the BLUETOOTH permission.