Firstly, take a glance at Bluetooth technology defining on
Wikipedia:
Bluetooth is a wireless technology standard for exchanging data over short distances (using short-wavelength UHF radio waves in the ISM band from 2.4 to 2.485 GHz[4]) from fixed and mobile devices, and building personal area networks (PANs). Invented by telecom vendor Ericsson in 1994,[5] it was originally conceived as a wireless alternative to RS-232 data cables. It can connect several devices, overcoming problems of synchronization.
According to this, we can "build" a local are network (LAN) by connecting devices over Bluetooth. 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 so we absolutely able to transferring data to other devices in the network circle.
Now, in this tutorial, I will note some important works to make a simple chat application which allows two Android devices to carry out two-way text chat over Bluetooth. If you only need full application code, please go to end of this post!
Requesting Bluetooth permissions
In order to use Bluetooth service, please add
BLUETOOTH
permission to your
AndroidManifest.xml. Moreover, because we need to discover available devices nearby later,
BLUETOOTH_ADMIN
permission should be required, too:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
Checking if device supports Bluetooth
Now to check whether Bluetooth is supported on device or not, we use object of
BluetoothAdapter
class. If
getDefaultAdapter()
return null, your device not supports Bluetooth. This is the "check code":
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {
Toast.makeText(this, "Bluetooth is not available!", Toast.LENGTH_SHORT).show();
finish(); //automatic close app if Bluetooth service is not available!
}
Check if Bluetooth is Enabled
The 2nd important works is check if your device is enabled Bluetooth. If not, request to turn it on:
if (!bluetoothAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BLUETOOTH);
}
You should put this code in
onStart()
to ensure that your app always check the connection when it launched! The "enabling request" dialog may be like this:
Discovering Bluetooth devices
In android, available devices is not discoverable by default. To scanning them, use
startDiscovery()
method of
BluetoothAdapter
class. The activity which starts scanning must register a
BroadCastReceiver
with
BluetoothDevice.ACTION_FOUND
action. After completing discovery, system will broadcast
BluetoothDevice.ACTION_FOUND
Intent
. This
Intent
contains extra fields
EXTRA_DEVICE
and
EXTRA_CLASS
, representing a
BluetoothDevice
and a BluetoothClass, respectively. In this application, I will add detected devices to an
ArrayAdapter
and show by
ListView
:
if (bluetoothAdapter.isDiscovering()) {
bluetoothAdapter.cancelDiscovery();
}
bluetoothAdapter.startDiscovery();
// Register for broadcasts when a device is discovered
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(discoveryFinishReceiver, filter);
// Register for broadcasts when discovery has finished
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(discoveryFinishReceiver, filter);
The
BroadcastReceiver
variable seem like this:
private final BroadcastReceiver discoveryFinishReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
discoveredDevicesAdapter.add(device.getName() + "\n" + device.getAddress());
}
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
if (discoveredDevicesAdapter.getCount() == 0) {
discoveredDevicesAdapter.add(getString(R.string.none_found));
}
}
}
};
Listing paired devices
Moreover, your devices can be connected to some other devices before, so you can listing them by call
getBondedDevices()
:
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
// If there are paired devices, add each one to the ArrayAdapter
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
pairedDevicesAdapter.add(device.getName() + "\n" + device.getAddress());
}
} else {
pairedDevicesAdapter.add(getString(R.string.none_paired));
}
In this sample application, I show a
Dialog
which contains 2
ListViews
of paired devices and discovered devices and this result look like this:
Connecting to a device
To connect two devices, we must implement server side and client side mechanism. One device shall open the server socket and another should initiate the connection (the remain device is a client device).
With connection as server:
- Initializing an instance of
BluetoothServerSocket
by calling the listenUsingRfcommWithServiceRecord()
method.
- Listening for connection requests by calling
accept()
- Release server socket by calling
close()
private class AcceptThread extends Thread {
private final BluetoothServerSocket serverSocket;
public AcceptThread() {
BluetoothServerSocket tmp = null;
try {
tmp = bluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord(APP_NAME, MY_UUID);
} catch (IOException ex) {
ex.printStackTrace();
}
serverSocket = tmp;
}
public void run() {
setName("AcceptThread");
BluetoothSocket socket;
while (state != STATE_CONNECTED) {
try {
socket = serverSocket.accept();
} catch (IOException e) {
break;
}
// If a connection was accepted
if (socket != null) {
synchronized (ChatController.this) {
switch (state) {
case STATE_LISTEN:
case STATE_CONNECTING:
// start the connected thread.
connected(socket, socket.getRemoteDevice());
break;
case STATE_NONE:
case STATE_CONNECTED:
// Either not ready or already connected. Terminate
// new socket.
try {
socket.close();
} catch (IOException e) {
}
break;
}
}
}
}
}
As connected as a client:
- Create an instance of
BluetoothSocket
by calling createRfcommSocketToServiceRecord(UUID)
on BluetoothDevice
object.
- Initializing the connection by calling
connect()
.
private class ConnectThread extends Thread {
private final BluetoothSocket socket;
private final BluetoothDevice device;
public ConnectThread(BluetoothDevice device) {
this.device = device;
BluetoothSocket tmp = null;
try {
tmp = device.createInsecureRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
e.printStackTrace();
}
socket = tmp;
}
public void run() {
setName("ConnectThread");
// Always cancel discovery because it will slow down a connection
bluetoothAdapter.cancelDiscovery();
// Make a connection to the BluetoothSocket
try {
socket.connect();
} catch (IOException e) {
try {
socket.close();
} catch (IOException e2) {
}
connectionFailed();
return;
}
// Reset the ConnectThread because we're done
synchronized (ChatController.this) {
connectThread = null;
}
// Start the connected thread
connected(socket, device);
}
public void cancel() {
try {
socket.close();
} catch (IOException e) {
}
}
}
This is definition of
My_UUID
constant:
private static final UUID MY_UUID = UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66");
Read and write data (text messages)
Of course, after establishing connection successfully, we'll do the most important work of a chat application: send/receive text messages. Now, each device has a connected
BluetoothSocket
, both of them can read and write data to the streams using
read(byte[])
and
write(byte[])
:
private class ReadWriteThread extends Thread {
private final BluetoothSocket bluetoothSocket;
private final InputStream inputStream;
private final OutputStream outputStream;
public ReadWriteThread(BluetoothSocket socket) {
this.bluetoothSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
}
inputStream = tmpIn;
outputStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[1024];
int bytes;
// Keep listening to the InputStream
while (true) {
try {
// Read from the InputStream
bytes = inputStream.read(buffer);
// Send the obtained bytes to the UI Activity
handler.obtainMessage(MainActivity.MESSAGE_READ, bytes, -1,
buffer).sendToTarget();
} catch (IOException e) {
connectionLost();
// Start the service over to restart listening mode
ChatController.this.start();
break;
}
}
}
// write to OutputStream
public void write(byte[] buffer) {
try {
outputStream.write(buffer);
handler.obtainMessage(MainActivity.MESSAGE_WRITE, -1, -1,
buffer).sendToTarget();
} catch (IOException e) {
}
}
public void cancel() {
try {
bluetoothSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
NOTE
: In my sample project, I put
AcceptThread
,
ConnectThread
and
ReadWriteThread
classes into a class named
ChatController
.
Application output
Some screenshots of this simple chat app:
|
When you have connected to a dive |
|
Sending/receiving messages with connected device |
|
When user close app on other device, the connection was lost |
Conclusions
I have presented some important works in developing a simple bluetooth chat application, hope this is helpful with your work! To make a better chat messages interface, please a glance in "
Design Chat bubble UI" post. Moreover, visit these official document pages to deep understanding about Bluetooth connection in Android:
Share