Android communicate with Arduino + HC-06 Bluetooth Module, part II

It's my old post "Android example to communicate with Bluetooth device, HC-06 Bluetooth Module", to make a Android phone communicate with Arduino + HC-06 Bluetooth Module. In the example, the first byte always lost.

After more test, I found that the first byte not lost. Because the byte stream sent from Arduino not in sync with Android side, and the bytes may be separated in different slot received in Android ThreadConnected, and the old slot covered by the new slot.

To show it, I modify it not to clear the TextView.


MainActivity.java
/*
Android Example to connect to and communicate with Bluetooth
In this exercise, the target is a Arduino Due + HC-06 (Bluetooth Module)

Ref:
- Make BlueTooth connection between Android devices
http://android-er.blogspot.com/2014/12/make-bluetooth-connection-between.html
- Bluetooth communication between Android devices
http://android-er.blogspot.com/2014/12/bluetooth-communication-between-android.html
*/
package com.example.androidbtcontrol;

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.support.v7.app.ActionBarActivity;
import android.view.View;
import android.widget.AdapterView;
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;

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

public class MainActivity extends ActionBarActivity {

private static final int REQUEST_ENABLE_BT = 1;

BluetoothAdapter bluetoothAdapter;

ArrayList<BluetoothDevice> pairedDeviceArrayList;

TextView textInfo, textStatus, textByteCnt;
ListView listViewPairedDevice;
LinearLayout inputPane;
EditText inputField;
Button btnSend, btnClear;

ArrayAdapter<BluetoothDevice> pairedDeviceAdapter;
private UUID myUUID;
private final String UUID_STRING_WELL_KNOWN_SPP =
"00001101-0000-1000-8000-00805F9B34FB";

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);
textByteCnt = (TextView)findViewById(R.id.textbyteCnt);
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 View.OnClickListener(){

@Override
public void onClick(View v) {
if(myThreadConnected!=null){
byte[] bytesToSend = inputField.getText().toString().getBytes();
myThreadConnected.write(bytesToSend);
byte[] NewLine = "\n".getBytes();
myThreadConnected.write(NewLine);
}
}});

btnClear = (Button)findViewById(R.id.clear);
btnClear.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
textStatus.setText("");
textByteCnt.setText("");
}
});

if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)){
Toast.makeText(this,
"FEATURE_BLUETOOTH NOT support",
Toast.LENGTH_LONG).show();
finish();
return;
}

//using the well-known SPP UUID
myUUID = UUID.fromString(UUID_STRING_WELL_KNOWN_SPP);

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 AdapterView.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();
}
}
}

//Called in ThreadConnectBTdevice once connect successed
//to start ThreadConnected
private void startThreadConnected(BluetoothSocket socket){

myThreadConnected = new ThreadConnected(socket);
myThreadConnected.start();
}

/*
ThreadConnectBTdevice:
Background Thread to handle BlueTooth connecting
*/
private class ThreadConnectBTdevice extends Thread {

private BluetoothSocket bluetoothSocket = null;
private final BluetoothDevice bluetoothDevice;


private 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("");
textByteCnt.setText("");
Toast.makeText(MainActivity.this, msgconnected, Toast.LENGTH_LONG).show();

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();
}

}

}

/*
ThreadConnected:
Background Thread to handle Bluetooth data communication
after connected
*/
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;

String strRx = "";

while (true) {
try {
bytes = connectedInputStream.read(buffer);
final String strReceived = new String(buffer, 0, bytes);
final String strByteCnt = String.valueOf(bytes) + " bytes received.\n";

runOnUiThread(new Runnable(){

@Override
public void run() {
textStatus.append(strReceived);
textByteCnt.append(strByteCnt);
}});

} 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();
}
}
}

}


layout/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:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:orientation="horizontal"
tools:context=".MainActivity">

<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical">
<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/textbyteCnt"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"/>
<TextView
android:id="@+id/status"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"/>
</LinearLayout>

<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical">

<TextView
android:id="@+id/info"
android:textStyle="bold|italic"
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"/>
<Button
android:id="@+id/clear"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Clear"/>

</LinearLayout>

</LinearLayout>

</LinearLayout>


Have to modify AndroidManifest.xml to uses-permission of "android.permission.BLUETOOTH". Refer the exmple "Android example to communicate with Bluetooth device, HC-06 Bluetooth Module".

download filesDownload the files (Android Studio Format) .

download filesDownload and try APK.


For the Arduino side, refer to : Arduino-er - Connect Arduino Due with HC-06 (Bluetooth Module).


This Android App can be used to talk with PC, with FTDI USB-to-Serial adapter connected to HC-06. Refer to the next post "Android Bluetooth connect PC (running Windows10) via HC-06 BT Module and FTDI US-to-Serial adapter".

more:
- Android Bluetooth Terminal to login Raspberry Pi + HC-06