Sunday, December 28, 2014

Bluetooth communication between Android devices

This exercise implement bi-direction Bluetooth communication between Android devices. After connection made in last post "Make BlueTooth connection between Android devices", start another thread, ThreadConnected, to handle read and write once BluetoothSocket established. If any case make the connection lost, the program will not re-connect, so you have to quit and re-start it.


please notice that it is just a exercise to study bluetooth, not a completed example.


AndroidBlueToothBeCOnnected:

MainActivity.java
package com.example.androidbluetoothbeconnected;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;

import android.support.v7.app.ActionBarActivity;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {
 
 private static final int REQUEST_ENABLE_BT = 1;
 
 BluetoothAdapter bluetoothAdapter;
 
 private UUID myUUID;
 private String myName;
 
 LinearLayout inputPane;
 EditText inputField;
 Button btnSend;

 TextView textInfo, textStatus;
 
 ThreadBeConnected myThreadBeConnected;
 ThreadConnected myThreadConnected;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  textInfo = (TextView)findViewById(R.id.info);
  textStatus = (TextView)findViewById(R.id.status);
  
  inputPane = (LinearLayout)findViewById(R.id.inputpane);
  inputField = (EditText)findViewById(R.id.input);
  btnSend = (Button)findViewById(R.id.send);
  btnSend.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View v) {
    if(myThreadConnected!=null){
     byte[] bytesToSend = inputField.getText().toString().getBytes();
     myThreadConnected.write(bytesToSend);
    }
   }});
  
  if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)){
   Toast.makeText(this, 
    "FEATURE_BLUETOOTH NOT support", 
    Toast.LENGTH_LONG).show();
            finish();
            return;
  }

  //generate UUID on web: http://www.famkruithof.net/uuid/uuidgen
  //have to match the UUID on the another device of the BT connection
  myUUID = UUID.fromString("ec79da00-853f-11e4-b4a9-0800200c9a66");
  myName = myUUID.toString();
  
  bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
  if (bluetoothAdapter == null) {
   Toast.makeText(this, 
    "Bluetooth is not supported on this hardware platform", 
    Toast.LENGTH_LONG).show();
            finish();
            return;
  }
  
  String stInfo = bluetoothAdapter.getName() + "\n" +
      bluetoothAdapter.getAddress();
  textInfo.setText(stInfo);
 }
 
 @Override
 protected void onStart() {
  super.onStart();
  
  //Turn ON BlueTooth if it is OFF
  if (!bluetoothAdapter.isEnabled()) {
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
        }
  
  setup();
 }
 
 private void setup() {
  textStatus.setText("setup()");
  myThreadBeConnected = new ThreadBeConnected();
  myThreadBeConnected.start();
 }
 
 @Override
 protected void onDestroy() {
  super.onDestroy();
  
  if(myThreadBeConnected!=null){
   myThreadBeConnected.cancel();
  }
 }

 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  
  if(requestCode==REQUEST_ENABLE_BT){
   if(resultCode == Activity.RESULT_OK){
    setup();
   }else{
    Toast.makeText(this, 
     "BlueTooth NOT enabled", 
     Toast.LENGTH_SHORT).show();
             finish();
   }
  } 
 }


 private class ThreadBeConnected extends Thread {
  
  private BluetoothServerSocket bluetoothServerSocket = null;
  
  public ThreadBeConnected() {
   try {
    bluetoothServerSocket = 
      bluetoothAdapter.listenUsingRfcommWithServiceRecord(myName, myUUID);
    
    textStatus.setText("Waiting\n" 
     + "bluetoothServerSocket :\n"
     + bluetoothServerSocket);
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }

  @Override
  public void run() {
   BluetoothSocket bluetoothSocket = null;
   
   if(bluetoothServerSocket!=null){
    try {
     bluetoothSocket = bluetoothServerSocket.accept();
     
     BluetoothDevice remoteDevice = bluetoothSocket.getRemoteDevice();
     
     final String strConnected = "Connected:\n" +
       remoteDevice.getName() + "\n" +
       remoteDevice.getAddress();
     
     //connected
     runOnUiThread(new Runnable(){

      @Override
      public void run() {
       textStatus.setText(strConnected);
       inputPane.setVisibility(View.VISIBLE);
      }});
     
     startThreadConnected(bluetoothSocket);
     
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
     
     final String eMessage = e.getMessage();
     runOnUiThread(new Runnable(){

      @Override
      public void run() {
       textStatus.setText("something wrong: \n" + eMessage);
      }});
    }
   }else{
    runOnUiThread(new Runnable(){

     @Override
     public void run() {
      textStatus.setText("bluetoothServerSocket == null");
     }});
   }
  }
  
  public void cancel() {
   
   Toast.makeText(getApplicationContext(), 
    "close bluetoothServerSocket", 
    Toast.LENGTH_LONG).show();
   
   try {
    bluetoothServerSocket.close();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
        }
 }
 
private void startThreadConnected(BluetoothSocket socket){
  
  myThreadConnected = new ThreadConnected(socket);
  myThreadConnected.start();
 }
 
 private class ThreadConnected extends Thread {
  private final BluetoothSocket connectedBluetoothSocket;
        private final InputStream connectedInputStream;
        private final OutputStream connectedOutputStream;
  
  public ThreadConnected(BluetoothSocket socket) {
   connectedBluetoothSocket = socket;
   InputStream in = null;
            OutputStream out = null;
            
            try {
    in = socket.getInputStream();
    out = socket.getOutputStream();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
            
            connectedInputStream = in;
            connectedOutputStream = out;
  }

  @Override
  public void run() {
   byte[] buffer = new byte[1024];
            int bytes;
            
            while (true) {
             try {
     bytes = connectedInputStream.read(buffer);
     
     String strReceived = new String(buffer, 0, bytes);
     final String msgReceived = String.valueOf(bytes) + 
       " bytes received:\n" 
       + strReceived;

     runOnUiThread(new Runnable(){

      @Override
      public void run() {
       textStatus.setText(msgReceived);
      }});
     
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
     
     final String msgConnectionLost = "Connection lost:\n"
       + e.getMessage();
     runOnUiThread(new Runnable(){

      @Override
      public void run() {
       textStatus.setText(msgConnectionLost);
      }});
    }
            }
  }
  
  public void write(byte[] buffer) {
   try {
    connectedOutputStream.write(buffer);
    connectedOutputStream.flush();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
        }
  
  public void cancel() {
   try {
    connectedBluetoothSocket.close();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }

 }
}

activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.example.androidbluetoothbeconnected.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    
    <TextView
        android:id="@+id/info"
        android:textStyle="bold|italic"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <TextView
        android:id="@+id/status"
        android:textSize="28sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    
    <LinearLayout
        android:id="@+id/inputpane"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:visibility="gone">
        
        <EditText
            android:id="@+id/input"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
        <Button
            android:id="@+id/send"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Sent"/>
        
    </LinearLayout>

</LinearLayout>

download filesDownload the files.

AndroidBlueTooth:

MainActivity.java
package com.example.androidbluetooth;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Set;
import java.util.UUID;

import android.support.v7.app.ActionBarActivity;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {
 
 private static final int REQUEST_ENABLE_BT = 1;
 
 BluetoothAdapter bluetoothAdapter;
 
 ArrayList<BluetoothDevice> pairedDeviceArrayList;
 
 TextView textInfo, textStatus;
 ListView listViewPairedDevice;
 ArrayAdapter<BluetoothDevice> pairedDeviceAdapter;
 private UUID myUUID;
 
 LinearLayout inputPane;
 EditText inputField;
 Button btnSend;
 
 ThreadConnectBTdevice myThreadConnectBTdevice;
 ThreadConnected myThreadConnected;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  textInfo = (TextView)findViewById(R.id.info);
  textStatus = (TextView)findViewById(R.id.status);
  listViewPairedDevice = (ListView)findViewById(R.id.pairedlist);
  
  inputPane = (LinearLayout)findViewById(R.id.inputpane);
  inputField = (EditText)findViewById(R.id.input);
  btnSend = (Button)findViewById(R.id.send);
  btnSend.setOnClickListener(new OnClickListener(){

   @Override
   public void onClick(View v) {
    if(myThreadConnected!=null){
     byte[] bytesToSend = inputField.getText().toString().getBytes();
     myThreadConnected.write(bytesToSend);
    }
   }});
  
  if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)){
   Toast.makeText(this, 
    "FEATURE_BLUETOOTH NOT support", 
    Toast.LENGTH_LONG).show();
            finish();
            return;
  }

  //generate UUID on web: http://www.famkruithof.net/uuid/uuidgen
  //have to match the UUID on the another device of the BT connection
  myUUID = UUID.fromString("ec79da00-853f-11e4-b4a9-0800200c9a66");
  
  bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
  if (bluetoothAdapter == null) {
   Toast.makeText(this, 
    "Bluetooth is not supported on this hardware platform", 
    Toast.LENGTH_LONG).show();
            finish();
            return;
  }
  
  String stInfo = bluetoothAdapter.getName() + "\n" +
    bluetoothAdapter.getAddress();
  textInfo.setText(stInfo);
 }

 @Override
 protected void onStart() {
  super.onStart();
  
  //Turn ON BlueTooth if it is OFF
  if (!bluetoothAdapter.isEnabled()) {
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
        }
  
  setup();
 }
 
 private void setup() {
  Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();
  if (pairedDevices.size() > 0) {
   pairedDeviceArrayList = new ArrayList<BluetoothDevice>();
   
   for (BluetoothDevice device : pairedDevices) {
    pairedDeviceArrayList.add(device);
            }
   
   pairedDeviceAdapter = new ArrayAdapter<BluetoothDevice>(this,
                 android.R.layout.simple_list_item_1, pairedDeviceArrayList);
   listViewPairedDevice.setAdapter(pairedDeviceAdapter);
   
   listViewPairedDevice.setOnItemClickListener(new OnItemClickListener(){

    @Override
    public void onItemClick(AdapterView<?> parent, View view,
      int position, long id) {
     BluetoothDevice device = 
       (BluetoothDevice)parent.getItemAtPosition(position);
      Toast.makeText(MainActivity.this, 
       "Name: " + device.getName() + "\n"
       + "Address: " + device.getAddress() + "\n"
       + "BondState: " + device.getBondState() + "\n"
       + "BluetoothClass: " + device.getBluetoothClass() + "\n"
       + "Class: " + device.getClass(),
       Toast.LENGTH_LONG).show();
      
      textStatus.setText("start ThreadConnectBTdevice");
      myThreadConnectBTdevice = new ThreadConnectBTdevice(device);
      myThreadConnectBTdevice.start();
    }});
  }
 }

 @Override
 protected void onDestroy() {
  super.onDestroy();
  
  if(myThreadConnectBTdevice!=null){
   myThreadConnectBTdevice.cancel();
  }
 }

 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  
  if(requestCode==REQUEST_ENABLE_BT){
   if(resultCode == Activity.RESULT_OK){
    setup();
   }else{
    Toast.makeText(this, 
     "BlueTooth NOT enabled", 
     Toast.LENGTH_SHORT).show();
             finish();
   }
  } 
 }
 
 private class ThreadConnectBTdevice extends Thread {
  private BluetoothSocket bluetoothSocket = null;
        private final BluetoothDevice bluetoothDevice;
        
        
        public ThreadConnectBTdevice(BluetoothDevice device) {
         bluetoothDevice = device;

         try {
    bluetoothSocket = device.createRfcommSocketToServiceRecord(myUUID);
    textStatus.setText("bluetoothSocket: \n" + bluetoothSocket);
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
        }

  @Override
  public void run() {
   boolean success = false;
   try {
    bluetoothSocket.connect();
    success = true;
   } catch (IOException e) {
    e.printStackTrace();
    
    final String eMessage = e.getMessage();
    runOnUiThread(new Runnable(){

     @Override
     public void run() {
      textStatus.setText("something wrong bluetoothSocket.connect(): \n" + eMessage);
     }});
    
    try {
     bluetoothSocket.close();
    } catch (IOException e1) {
     // TODO Auto-generated catch block
     e1.printStackTrace();
    }
   }
   
   if(success){
    //connect successful
    final String msgconnected = "connect successful:\n"
     + "BluetoothSocket: " + bluetoothSocket + "\n"
     + "BluetoothDevice: " + bluetoothDevice;
    
    runOnUiThread(new Runnable(){

     @Override
     public void run() {
      textStatus.setText(msgconnected);
      
      listViewPairedDevice.setVisibility(View.GONE);
      inputPane.setVisibility(View.VISIBLE);
     }});
    
    startThreadConnected(bluetoothSocket);
   }else{
    //fail
   }
  }
  
  public void cancel() {
   
   Toast.makeText(getApplicationContext(), 
     "close bluetoothSocket", 
     Toast.LENGTH_LONG).show();
   
   try {
    bluetoothSocket.close();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   
        }
 }
 
 private void startThreadConnected(BluetoothSocket socket){
  
  myThreadConnected = new ThreadConnected(socket);
  myThreadConnected.start();
 }
 
 private class ThreadConnected extends Thread {
  private final BluetoothSocket connectedBluetoothSocket;
        private final InputStream connectedInputStream;
        private final OutputStream connectedOutputStream;
  
  public ThreadConnected(BluetoothSocket socket) {
   connectedBluetoothSocket = socket;
   InputStream in = null;
            OutputStream out = null;
            
            try {
    in = socket.getInputStream();
    out = socket.getOutputStream();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
            
            connectedInputStream = in;
            connectedOutputStream = out;
  }

  @Override
  public void run() {
   byte[] buffer = new byte[1024];
            int bytes;
            
            while (true) {
             try {
     bytes = connectedInputStream.read(buffer);
     String strReceived = new String(buffer, 0, bytes);
     final String msgReceived = String.valueOf(bytes) + 
       " bytes received:\n" 
       + strReceived;
     
     runOnUiThread(new Runnable(){

      @Override
      public void run() {
       textStatus.setText(msgReceived);
      }});
     
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
     
     final String msgConnectionLost = "Connection lost:\n"
       + e.getMessage();
     runOnUiThread(new Runnable(){

      @Override
      public void run() {
       textStatus.setText(msgConnectionLost);
      }});
    }
            }
  }
  
  public void write(byte[] buffer) {
   try {
    connectedOutputStream.write(buffer);
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
        }
  
  public void cancel() {
   try {
    connectedBluetoothSocket.close();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }

 }
 
}

activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.example.androidbluetooth.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:autoLink="web"
        android:text="http://android-er.blogspot.com/"
        android:textStyle="bold" />
    
    <TextView
        android:id="@+id/info"
        android:textStyle="bold|italic"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <TextView
        android:id="@+id/status"
        android:textSize="28sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    
    <ListView 
        android:id="@+id/pairedlist"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    
    <LinearLayout
        android:id="@+id/inputpane"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:visibility="gone">
        
        <EditText
            android:id="@+id/input"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
        <Button
            android:id="@+id/send"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Sent"/>
        
    </LinearLayout>

</LinearLayout>


download filesDownload the files.


Remark: both side have to modify AndroidManifest.xml to add permission of "android.permission.BLUETOOTH".


Related:
- Android example to communicate with Bluetooth device, HC-06 Bluetooth Module

3 comments:

Dalal said...

could you please put a complete exercise with explanation of the code

Anonymous said...

very nice and useful.
thank you.

shravan.jakkani03 said...

your post is very useful. Is there any chance to maintain Bluetooth connection throughtout multiple activities.