Bluetooth enables point to point & multipoint communication between bluetooth enabled devices. Android framework includes APIs for connection with other bluetooth enabled device and exchange data with connected device.
Android framework supports both Classic as well as Low Energy bluetooth and provides APIs for both. Classic bluetooth is used in app when both devices share a connection for longer periods & have large data to exchange. It drains the device battery being responsible for such intensive tasks. Low Energy bluetooth as name suggests consumes less power unlike classic bluetooth . It's application areas are very specific which suit intermittent burst data transfers.
We will first cover classic bluetooth communication APIs and then low energy bluetooth communication.
In a point to point communication of bluetooth devices, one devices acts as a master & other as a slave. The master devices scans for available bluetooth enabled devices in vicinity. Slave devices is put in discoverable mode so that master can find it during scan. Once master device finds a device after scan, it initiates a connection. The connection is performed in 2 steps. First step is a pairing which generates a bond between two devices and confirms the identity of the devices. The pairing mechanism varies as per type of device & bluetooth version it supports. After a successful pairing between two devices, a connection is established through sockets. Let's dive into the code now.
For any bluetooth application you need to add these two permissions to your application's AndroidManifest.xml
We will use the Android bluetooth API to connect to device using sockets. The communication will be over the socket streams.
For a master device, we will create the socket connection to the other bluetooth device. Then it will continuously listen for the data from the socket stream inside a thread. It can write to connected stream outside this thread. The connection is a blocking call and bluetooth device discovery being a heavy process, may slow down the connection. So it is a good practice to cancel the device discovery before trying to connect to other device. Note that the bluetooth socket connection is a blocking call and returns only if a connection is successful or if an exception occurs while connecting to device.
The BluetoothConnection will create the socket connection to other device, once instantiated and start listening to the data from connected device.
For a slave device, we need to put the device in discoverable mode so a master can connect to it. When the master device requests a connection, slave accepts the connection and streams to read from/write to are obtained from sockets.
For our device to be a slave Bluetooth device, put it in discoverable mode using following.
Android framework supports both Classic as well as Low Energy bluetooth and provides APIs for both. Classic bluetooth is used in app when both devices share a connection for longer periods & have large data to exchange. It drains the device battery being responsible for such intensive tasks. Low Energy bluetooth as name suggests consumes less power unlike classic bluetooth . It's application areas are very specific which suit intermittent burst data transfers.
We will first cover classic bluetooth communication APIs and then low energy bluetooth communication.
In a point to point communication of bluetooth devices, one devices acts as a master & other as a slave. The master devices scans for available bluetooth enabled devices in vicinity. Slave devices is put in discoverable mode so that master can find it during scan. Once master device finds a device after scan, it initiates a connection. The connection is performed in 2 steps. First step is a pairing which generates a bond between two devices and confirms the identity of the devices. The pairing mechanism varies as per type of device & bluetooth version it supports. After a successful pairing between two devices, a connection is established through sockets. Let's dive into the code now.
For any bluetooth application you need to add these two permissions to your application's AndroidManifest.xml
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH" />
We will use the Android bluetooth API to connect to device using sockets. The communication will be over the socket streams.
For a master device, we will create the socket connection to the other bluetooth device. Then it will continuously listen for the data from the socket stream inside a thread. It can write to connected stream outside this thread. The connection is a blocking call and bluetooth device discovery being a heavy process, may slow down the connection. So it is a good practice to cancel the device discovery before trying to connect to other device. Note that the bluetooth socket connection is a blocking call and returns only if a connection is successful or if an exception occurs while connecting to device.
The BluetoothConnection will create the socket connection to other device, once instantiated and start listening to the data from connected device.
private class BluetoothConnection extends Thread { private final BluetoothSocket mmSocket; private final InputStream mmInStream; private final OutputStream mmOutStream; byte[] buffer; // Unique UUID for this application, you may use different private static final UUID MY_UUID = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66"); public BluetoothConnection(BluetoothDevice device) { BluetoothSocket tmp = null; // Get a BluetoothSocket for a connection with the given BluetoothDevice try { tmp = device.createRfcommSocketToServiceRecord(MY_UUID); } catch (IOException e) { e.printStackTrace(); } mmSocket = tmp; //now make the socket connection in separate thread to avoid FC Thread connectionThread = new Thread(new Runnable() { @Override public void run() { // Always cancel discovery because it will slow down a connection mAdapter.cancelDiscovery(); // Make a connection to the BluetoothSocket try { // This is a blocking call and will only return on a // successful connection or an exception mmSocket.connect(); } catch (IOException e) { //connection to device failed so close the socket try { mmSocket.close(); } catch (IOException e2) { e2.printStackTrace(); } } } }); connectionThread.start(); InputStream tmpIn = null; OutputStream tmpOut = null; // Get the BluetoothSocket input and output streams try { tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); buffer = new byte[1024]; } catch (IOException e) { e.printStackTrace(); } mmInStream = tmpIn; mmOutStream = tmpOut; } public void run() { // Keep listening to the InputStream while connected while (true) { try { //read the data from socket stream mmInStream.read(buffer); // Send the obtained bytes to the UI Activity } catch (IOException e) { //an exception here marks connection loss //send message to UI Activity break; } } } public void write(byte[] buffer) { try { //write the data to socket stream mmOutStream.write(buffer); } catch (IOException e) { e.printStackTrace(); } } public void cancel() { try { mmSocket.close(); } catch (IOException e) { e.printStackTrace(); } } }
For a slave device, we need to put the device in discoverable mode so a master can connect to it. When the master device requests a connection, slave accepts the connection and streams to read from/write to are obtained from sockets.
For our device to be a slave Bluetooth device, put it in discoverable mode using following.
//Making the host device discoverable startActivityForResult(new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE), DISCOVERY_REQUEST_BLUETOOTH);An instance BluetoothServerSocket listens for incoming requests upon discoverable mode is initiated successfully. This instance is obtained by calling the listenUsingRfcommWithServiceRecord method on the Bluetooth adapter. With this instance of BluetoothServerSocket, phone listens for incoming requests from remote devices through the start() method. Since listening is a blocking process we must use separate thread for the same.
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == DISCOVERY_REQUEST_BLUETOOTH) { boolean isDiscoverable = resultCode > 0; if (isDiscoverable) { UUID uuid = UUID.fromString(MY_UUID); String serverName = "BTserver"; final BluetoothServerSocket bluetoothServer = bluetoothAdapter.listenUsingRfcommWithServiceRecord(serverName, uuid); Thread listenThread = new Thread(new Runnable() { public void run() { try { BluetoothSocket serverSocket = bluetoothServer.accept(); } catch (IOException e) { Log.d("BLUETOOTH", e.getMessage()); } } }); listenThread.start(); } } }