Skip to main content

Bluetooth Chat Application - Android Tutorial

In this tutorial, we will see about how to design an Android layout for chat application using Chat Bubbles and the main part is chat via Bluetooth.

Main objective of this post is to give an idea about how to allow two-way text chat over Bluetooth in android.

Bubbles:

Chat bubbles are background image that expands horizontally and vertically as required based on the message posted. Bubbles are Nine-patch Images.

Image

Nine-patch Image

In creating Android chat bubbles, nine-patch image plays a crucial role. Nine-patch image is a bitmap which stretches to fit the content posted in the View where it is applied as a background.


A NinePatch drawable is a standard PNG image that includes an extra 1-pixel-wide border. It must be saved with the extension .9.png, and saved into the res/drawable/ directory of your project. The border is used to define the stretchable and static areas of the image. You indicate a stretchable section by drawing one (or more) 1-pixel-wide black line(s) in the left and top part of the border (the other border pixels should be fully transparent or white). You can have as many stretchable sections as you want: their relative size stays the same, so the largest sections always remain the largest.

We can use the draw9patch tool provided with the Android-sdk to create a nine-patch image. There are lots of free online tools available to generate these images. Of course, we can use Photoshop and create ourselves.

Download these bubble images






Create new Project

1. Get Bluetooth Service
We need the Android Bluetooth service for this tutorial to work. In order to use Bluetooth service, declare BLUETOOTH permission in manifest file. 

<uses-permission android:name="android.permission.BLUETOOTH" />

Now to initiate device discovery and to access Bluetooth setting declare BLUETOOTH_ADMIN permission.

<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

2. Bluetooth Adapter Class

Now to check whether Bluetooth is supported on device or not, we use object of BluetoothAdapter class. 

BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 

If this method returns null, then it means that Bluetooth is not supported on the device and so we will close the application.

To know more about BluetoothAdapter class please refer following link:

3. isEnable() Method

To check Bluetooth is enabled or not, we will use isEnabled() method on object of BluetoothAdapter class. 

If Bluetooth is disabled then we request the user to enable it. And we perform this action by calling startActivityForResult() with REQUEST_ENABLE_BT action. This will open dialog to enable Bluetooth on the device. 

Intent enableIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);

Image

If the user clicks Allow then the onActivityResult() method receives RESULT_OK and if the user clicks Deny (or due to internal problem in device), RESULT_CANCELED is received. If returned value RESULT_OK is received then we will initiate the chat service.

4. Discover Bluetooth

Now in android, device is not discoverable by default. To make device discoverable, call startActivityForResult() with BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE action. By default device is discoverable for 120 seconds. To set discoverable duration, add EXTRA_DISCOVERABLE_DURATION in intent extra. The maximum value for duration is 360 seconds. 


Intent discoverableIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(
BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);

This will open dialog to enable discoverable mode.

5. Bluetooth Connection

To start the chat, we first need to establish connection with the desired device. And before starting scanning for available devices, we usually get paired devices first in the list.


BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();

Above code will return a set of BluetoothDevice objects. The object of BluetoothDevice class gives required information about remote device which is used to establish connection (Explained later). 

To start scanning, call the startDiscovery() method of BluetoothAdapter class. The activity which starts scanning must register receiver 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.

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) {
newDevicesArrayAdapter.add(device.getName() + "\n"
+ device.getAddress());
}
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED
.equals(action)) {
setProgressBarIndeterminateVisibility(false);
setTitle(R.string.select_device);
if (newDevicesArrayAdapter.getCount() == 0) {
String noDevices = getResources().getText(
R.string.none_found).toString();
newDevicesArrayAdapter.add(noDevices);
}
}
}
};

To know more about BroadcastReceiver please refer following link:

To register receiver:


IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(discoveryFinishReceiver, filter);

6. Pairing devices

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. Both are connected when BluetoothSocket is connected on the same RFCOMM channel. During connection procedure android framework automatically shows pairing dialog.

Connection as Server:
Make object of BluetoothServerSocket by calling the listenUsingRfcommWithServiceRecord().
Listening for connection requests by calling accept().
Release server socket by calling close().

// runs while listening for incoming connections
private class AcceptThread extends Thread {
private final BluetoothServerSocket serverSocket;
private String socketType;

public AcceptThread(boolean secure) {
BluetoothServerSocket tmp = null;
socketType = secure ? "Secure" : "Insecure";

try {
if (secure) {
tmp = bluetoothAdapter.listenUsingRfcommWithServiceRecord(
NAME_SECURE, MY_UUID_SECURE);
} else {
tmp = bluetoothAdapter
.listenUsingInsecureRfcommWithServiceRecord(
NAME_INSECURE, MY_UUID_INSECURE);
}
} catch (IOException e) {
}
serverSocket = tmp;
}

public void run() {
setName("AcceptThread" + socketType);

BluetoothSocket socket = null;

while (state != STATE_CONNECTED) {
try {
socket = serverSocket.accept();
} catch (IOException e) {
break;
}

// If a connection was accepted
if (socket != null) {
synchronized (ChatService.this) {
switch (state) {
case STATE_LISTEN:
case STATE_CONNECTING:
// start the connected thread.
connected(socket, socket.getRemoteDevice(),
socketType);
break;
case STATE_NONE:
case STATE_CONNECTED:
// Either not ready or already connected. Terminate
// new socket.
try {
socket.close();
} catch (IOException e) {
}
break;
}
}
}
}
}

public void cancel() {
try {
serverSocket.close();
} catch (IOException e) {
}
}
}

To know more about BluetoothSocket please refer following link:

Connection as Client:
Create object of BluetoothSocket by calling createRfcommSocketToServiceRecord(UUID) on BluetoothDevice object.
Initiate connection by calling connect().

// runs while attempting to make an outgoing connection
private class ConnectThread extends Thread {
private final BluetoothSocket socket;
private final BluetoothDevice device;
private String socketType;

public ConnectThread(BluetoothDevice device, boolean secure) {
this.device = device;
BluetoothSocket tmp = null;
socketType = secure ? "Secure" : "Insecure";

try {
if (secure) {
tmp = device
.createRfcommSocketToServiceRecord(MY_UUID_SECURE);
} else {
tmp = device
.createInsecureRfcommSocketToServiceRecord(MY_UUID_INSECURE);
}
} catch (IOException e) {
}
socket = tmp;
}

public void run() {
setName("ConnectThread" + socketType);

// 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 (ChatService.this) {
connectThread = null;
}

// Start the connected thread
connected(socket, device, socketType);
}

public void cancel() {
try {
socket.close();
} catch (IOException e) {
}
}
}

7. Read and Write Data

1. After establishing connection successfully, each device has connected BluetoothSocket.
2. Now one can Read and write data to the streams using read(byte[]) and write(byte[]).

// runs during a connection with a remote device
private class ConnectedThread extends Thread {
private final BluetoothSocket bluetoothSocket;
private final InputStream inputStream;
private final OutputStream outputStream;

public ConnectedThread(BluetoothSocket socket, String socketType) {
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
ChatService.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) {
}
}
}
__________________________________________________
Source Code for BluetoothChat.zip and for apk to check it

Comments

  1. I have implemented your project in Android Studio. It works perfectly. Many Thanks.
    It took me a long time to find a really working source code. There is so much trash on the internet that it supposedly works. It does not.
    I intend to use your project as a basis for my other specific project.

    ReplyDelete
    Replies
    1. bro how you implemented that project please tell me....
      you may forward to this mail ajaygajula574@gmail.com

      Delete
    2. bro send me that project source code on bhargandemangesh100@gmail.com

      Delete
    3. Buddy please please send me source code
      And tell me how to implement
      Please

      Delete
    4. Buddy please send me the source code and tell me how you implemented it
      Kum.aniket@gmail.com

      Delete
    5. buddy pls send your code at ritikjalal4567@gmail.com

      Delete
  2. in which this all code you have type how did you run

    ReplyDelete

Post a Comment

Popular posts from this blog

Get Phone Number from Contact List - Android Tutorial

When you create an application to send sms or an application to make calls, getting a destination number from the contacts list is a common task. In this Android tip, I am going to show the code to fetch a number from the contacts list. Now let me tell you how to achieve the goal. First, you need to create an Intent object for the PICK_ACTION action. To open the contacts list, the table that contains the contacts information must be specified as a parameter of the constructor of the Intent class. You can refer to the table using ContactsContract.Contacts.CONTENT_URI. Then call the startActivityForResult () method passing the Intent object and request code to open the contacts list. After a contact is selected from the contacts list, to get the result, you need to override the onActivityResult(int reqCode, int resultCode, Intent data) method of the activity. You can call the getData() method of the data parameter to get the table or uri that contains the selected contact. From the t

Spinner with Search on DropDown - Android Tutorial

If you have more values on Dropdown of Spinner its hard to select the last item by making a long scroll. To overcome this issue Android introduced a component called  AutoCompleteTextView Yes it is!!! Then why Spinner with Search? There may be some requirement even though gave much knowledge about it. There is a simple and good library that helps us to achieve this -  SearchableSpinner Gradle dependencies {     ...     implementation 'com.toptoche.searchablespinner:searchablespinnerlibrary:1.3.1' } Usage Now replace your Normal Android Spinner on XML with the following < com.toptoche.searchablespinnerlibrary.SearchableSpinner     android:id="@+id/id_city"     android:layout_width="match_parent"     android:layout_height="wrap_content"     android:background="@android:color/transparent"     android:padding="5dp" /> ___________________________________________________________

Set Focus on Spinner when select Item on Vertical Scroll - Android Tutorial

We may face an issue on Spinner lies on long vertical scroll, (i.e.) when selected and item from dropdown the focus moves to top of scroll. To avoid this please follow this piece of code spinner.setFocusableInTouchMode( true ); spinner.setOnFocusChangeListener( new View.OnFocusChangeListener() {     @Override     public void onFocusChange(View v, boolean hasFocus) {         if (hasFocus) {             if (spinner.getWindowToken() != null ) {                 spinner.performClick();             }         }     } });   _______________________________________________________________________________ Happy Coding...