Bluetooth chat messenger Android App
In this video it shows the demo and code for creating a Bluetooth based chat message Android App. This App would be useful to communicate between Android devices in the absence of any network/ internet. It just uses Bluetooth to send and receive messages.
I hope you like this video. For any questions, suggestions or appreciation please contact us at: https://programmerworld.co/contact/ or email at: programmerworld1990@gmail.com
Details:
Code:
package com.programmerworld.bluetoothchatapp;
// How to make Bluetooth based chat messenger Android App?
import android.app.Activity;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.Manifest;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationCompat;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Set;
import java.util.UUID;
public class MainActivity extends Activity {
private static final String APP_NAME = "BTChat";
private static final UUID MY_UUID = UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66");
private static final String CHANNEL_ID = "BluetoothChatNotifications";
private BluetoothAdapter bluetoothAdapter;
private BluetoothDevice remoteDevice;
private BluetoothSocket bluetoothSocket;
private Handler handler;
private ConnectedThread connectedThread;
private AcceptThread acceptThread;
private TextView status;
private EditText messageBox;
private Button sendButton, discoverButton;
private ListView chatList;
private ArrayAdapter<String> chatAdapter;
private NotificationManager notificationManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.POST_NOTIFICATIONS}, 1);
}
}
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
createNotificationChannel();
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED ||
checkSelfPermission(Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{
Manifest.permission.BLUETOOTH_CONNECT,
Manifest.permission.BLUETOOTH_SCAN
}, 1);
}
}
status = findViewById(R.id.status);
messageBox = findViewById(R.id.messageBox);
sendButton = findViewById(R.id.sendButton);
discoverButton = findViewById(R.id.discoverButton);
chatList = findViewById(R.id.chatList);
chatAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1);
chatList.setAdapter(chatAdapter);
handler = new Handler(Looper.getMainLooper(), msg -> {
if (msg.what == 1) {
String receivedMessage = (String) msg.obj;
chatAdapter.add(receivedMessage);
showNotification("New Message", receivedMessage);
}
return true;
});
acceptThread = new AcceptThread();
acceptThread.start();
discoverButton.setOnClickListener(v -> {
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
});
sendButton.setOnClickListener(v -> {
if (connectedThread != null) {
String message = messageBox.getText().toString();
connectedThread.write(message.getBytes());
chatAdapter.add("Me: " + message);
messageBox.setText("");
}
});
Button connectButton = findViewById(R.id.connectButton);
connectButton.setOnClickListener(v -> selectDevice());
}
private class AcceptThread extends Thread {
private BluetoothServerSocket serverSocket = null;
public AcceptThread() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
return;
}
}
try {
serverSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord(APP_NAME, MY_UUID);
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
BluetoothSocket socket;
while (true) {
try {
if (serverSocket != null) {
socket = serverSocket.accept();
if (socket != null) {
manageConnectedSocket(socket);
serverSocket.close();
break;
}
}
} catch (IOException e) {
break;
}
}
}
}
private void manageConnectedSocket(BluetoothSocket socket) {
connectedThread = new ConnectedThread(socket);
connectedThread.start();
}
private class ConnectedThread extends Thread {
private final InputStream inputStream;
private final OutputStream outputStream;
public ConnectedThread(BluetoothSocket socket) {
bluetoothSocket = socket;
InputStream tempIn = null;
OutputStream tempOut = null;
try {
tempIn = socket.getInputStream();
tempOut = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
inputStream = tempIn;
outputStream = tempOut;
}
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while (true) {
try {
bytes = inputStream.read(buffer);
String receivedMessage = new String(buffer, 0, bytes);
handler.obtainMessage(1, "Friend: " + receivedMessage).sendToTarget();
} catch (IOException e) {
break;
}
}
}
public void write(byte[] bytes) {
try {
outputStream.write(bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private class ConnectThread extends Thread {
private BluetoothSocket socket;
private final BluetoothDevice device;
public ConnectThread(BluetoothDevice device) {
this.device = device;
BluetoothSocket temp = null;
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (checkSelfPermission(Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
return;
}
}
temp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
e.printStackTrace();
}
socket = temp;
}
public void run() {
if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
bluetoothAdapter.cancelDiscovery(); // Speed up connection
try {
socket.connect();
manageConnectedSocket(socket); // Start chat
} catch (IOException e) {
try {
socket.close();
} catch (IOException closeException) {
closeException.printStackTrace();
}
return;
}
}
}
private void selectDevice() {
if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {
return;
}
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
if(device.getName().contains("Redmi")){
remoteDevice = device; // Automatically select the first paired device
Toast.makeText(this, "Connecting to " + device.getName(), Toast.LENGTH_LONG).show();
break;
}
}
if (remoteDevice != null) {
new ConnectThread(remoteDevice).start();
}
}
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "Bluetooth Chat Notifications";
String description = "Notifications for new Bluetooth messages";
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
// NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
private void showNotification(String title, String message) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle(title)
.setContentText(message)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true);
notificationManager.notify(1, builder.build());
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.BluetoothChatApp"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Bluetooth Chat"
android:textSize="20sp"
android:textStyle="bold"
android:layout_gravity="center_horizontal"/>
<Button
android:id="@+id/discoverButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Make Discoverable" />
<Button
android:id="@+id/connectButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Connect" />
<ListView
android:id="@+id/chatList"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:divider="@android:color/darker_gray"
android:dividerHeight="1dp"/>
<EditText
android:id="@+id/messageBox"
android:layout_width="match_parent"
android:layout_height="60dp"
android:hint="Type a message" />
<Button
android:id="@+id/sendButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Send" />
</LinearLayout>
Screenshots:




