My aim is to connect to already paired bluetooth devices. I have got all the paired devices names and I am displaying them in a listview. When I click on any of the device name from the listview it should connect to that device if its within the range.
Whenever I try to connect to the device by calling mmSocket.connect() I get this system error in my log cat shown below and then it calls mmSocket.close():
06-22 17:40:50.617: W/System.err(25986): java.io.IOException: read failed, socket might closed or timeout, read ret: -1
06-22 17:40:50.618: W/System.err(25986): at android.bluetooth.BluetoothSocket.readAll(BluetoothSocket.java:510)
06-22 17:40:50.619: W/System.err(25986): at android.bluetooth.BluetoothSocket.readInt(BluetoothSocket.java:521)
06-22 17:40:50.619: W/System.err(25986): at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:320)
06-22 17:40:50.619: W/System.err(25986): at ik.learning.bluetooth.MainActivity$ConnectThread.run(MainActivity.java:233)
I am not sure why is this happening can some one help me out here. Below is my code:
public class MainActivity extends Activity implements OnItemClickListener{
ArrayAdapter<String> listAdapter;
Button connectNew;
ListView listView;
BluetoothAdapter btAdapter;
Set<BluetoothDevice> devicesArray;
IntentFilter filter;
BroadcastReceiver receiver;
ArrayList<String> pairedDevices;
ArrayList<BluetoothDevice> devices;
public static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
protected static final int SUCCESS_CONNECT = 0;
protected static final int MESSAGE_READ = 1;
Handler mHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
if(btAdapter == null){
Toast.makeText(this, "No bluetooth detected", Toast.LENGTH_LONG).show();
finish();
} else {
if(!btAdapter.isEnabled()){
turnOnBluetooth();
}
getPairedDevices();
startDiscovery();
}
mHandler = new Handler(){
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch(msg.what){
case SUCCESS_CONNECT:
ConnectedThread connectedThread = new ConnectedThread((BluetoothSocket) msg.obj);
Toast.makeText(getApplicationContext(), "Connected", Toast.LENGTH_SHORT).show();
String s = "Successfully connected";
connectedThread.write(s.getBytes());
break;
case MESSAGE_READ:
byte[] readBuff = (byte[]) msg.obj;
String string = new String(readBuff);
Toast.makeText(getApplicationContext(), string, Toast.LENGTH_SHORT).show();
break;
}
}
};
}
private void startDiscovery() {
// TODO Auto-generated method stub
btAdapter.cancelDiscovery();
btAdapter.startDiscovery();
}
private void turnOnBluetooth() {
// TODO Auto-generated method stub
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, 1);
}
private void getPairedDevices() {
// TODO Auto-generated method stub
devicesArray = btAdapter.getBondedDevices();
if(devicesArray.size() > 0){
for(BluetoothDevice device : devicesArray){
//listAdapter.add(device.getName()+"\n"+device.getAddress());
pairedDevices.add(device.getName());//+"\n"+device.getAddress());
}
}
}
private void init() {
connectNew = (Button) findViewById(R.id.btnConnectNew);
listView = (ListView) findViewById(R.id.bluetoothlistView);
listView.setOnItemClickListener(this);
listAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1, 0);
listView.setAdapter(listAdapter);
btAdapter = BluetoothAdapter.getDefaultAdapter();
pairedDevices = new ArrayList<String>();
filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
devices = new ArrayList<BluetoothDevice>();
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String action = intent.getAction();
if(BluetoothDevice.ACTION_FOUND.equals(action)){
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
devices.add(device);
String s = "";
for(int i = 0; i< pairedDevices.size(); i++){
if(device.getName().equals(pairedDevices.get(i))){
s = "PAIRED";
break;
}
}
listAdapter.add(device.getName()+" ("+s+") "+"\n"+device.getAddress());
}
else if(BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)){
}
else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){
}
else if(BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)){
if(btAdapter.getState() == btAdapter.STATE_OFF){
turnOnBluetooth();
}
}
}
};
registerReceiver(receiver, filter);
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
registerReceiver(receiver, filter);
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(receiver, filter);
filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(receiver, filter);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_CANCELED){
Toast.makeText(getApplicationContext(), "Bluetooth must be enabled to continue", Toast.LENGTH_SHORT).show();
}
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
unregisterReceiver(receiver);
}
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
// TODO Auto-generated method stub
if(btAdapter.isDiscovering()){
btAdapter.cancelDiscovery();
}
if(listAdapter.getItem(arg2).contains("PAIRED")){
//Object[] o = devicesArray.toArray();
BluetoothDevice selectedDevice = devices.get(arg2);
ConnectThread connect = new ConnectThread(selectedDevice);
connect.start();
Toast.makeText(getApplicationContext(), "Devices Paired", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "Devices Not Paired", Toast.LENGTH_SHORT).show();
}
}
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to mmSocket,
// because mmSocket is final
BluetoothSocket tmp = null;
mmDevice = device;
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
// MY_UUID is the app's UUID string, also used by the server code
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) { }
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it will slow down the connection
btAdapter.cancelDiscovery();
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
Log.d("ConnectThread","try connect");
//mHandler.obtainMessage(SUCCESS_CONNECT, mmSocket).sendToTarget();
mmSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and get out
connectException.printStackTrace();
Log.d("ConnectThread","catch connect: "+connectException);
try {
Log.d("ConnectThread","try soccet close");
mmSocket.close();
} catch (IOException closeException) {
Log.d("ConnectThread","catch close: "+connectException);
}
return;
}
// Do work to manage the connection (in a separate thread)
Log.d("ConnectThread","before manage connected socket");
//manageConnectedSocket(mmSocket);
mHandler.obtainMessage(SUCCESS_CONNECT, mmSocket).sendToTarget();
}
/*private void manageConnectedSocket(BluetoothSocket mmSocket2) {
// TODO Auto-generated method stub
}*/
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
buffer = new byte[1024]; // buffer store for the stream
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI activity
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);
} catch (IOException e) { }
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
}
After onClick List Item you get the Bluetooth Name, using that name you can get Bluetooth Device object by calling BluetoothAdapter.getDefaultAdapter().getRemoteDevice(bluetoothDevice.getAddress());
Here is a sample code to connect to Bluetooth device..
//global variable
BluetoothSocket mBSocket;
// inside run() function
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(mBluetoothAdapter.isEnabled()) {
try {
for(BluetoothDevice bt: mBluetoothAdapter.getBondedDevices()) {
if(bt.getName().equalsIgnoreCase(selectedDevice.getName())) {
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(bt.getAddress());
mBluetoothAdapter.cancelDiscovery();
mBSocket = device.createRfcommSocketToServiceRecord(SPP_UUID);
mBSocket.connect();
return mBSocket;
}
}
} catch(IOException e) {
if(mBSocket != null) {
try {
mBSocket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
mBSocket = null;
}
e.printStackTrace();
return null;
}
}
return null;
Hope it helps.
Related
I'm stuck and can't find a way to restart or reconnect the Bluetooth service in my app. The app has 3 fragments, tabs managed by FragmentPagerAdapter.
In the first fragment you can discover, associate and communicate with the BT device. In the second and third card it is necessary to interact with the device, it is not possible to get the connection or keep the service connected.
Here it goes the first fragment:
public class Conexiones extends Fragment implements ServiceConnection, SerialListener {
public BluetoothAdapter BTAdapter;
private ListView listView; // detectados
private ArrayList<String> mDeviceList;
public Button conectar, actualizar;
private ArrayAdapter m_DiscoveredPeersAdapter;
BluetoothDevice bdDevice;
BluetoothClass dbClass;
ArrayList<BluetoothDevice> listaBTDevices = null;
View view;
public SerialSocket socket;
public SerialService service;
public Conexiones(){
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
view = inflater.inflate(R.layout.fragment_conexiones, container, false );
BTAdapter = BluetoothAdapter.getDefaultAdapter();
listView = (ListView) this.view.findViewById(R.id.listView);
mDeviceList = new ArrayList<>();
m_DiscoveredPeersAdapter = new ArrayAdapter(getActivity(), android.R.layout.simple_list_item_1, mDeviceList);
listView.setAdapter(m_DiscoveredPeersAdapter);
listItemClicked = new ListItemClicked();
clicked = new ButtonClicked();
checkBTPermissions();
listaBTDevices = new ArrayList<BluetoothDevice>();
m_DiscoveredPeersAdapter.notifyDataSetChanged();
if (BTAdapter == null || !BTAdapter.isEnabled()) {
Intent turnOn = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(turnOn, 1);
}
int MY_PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION = 1;
ActivityCompat.requestPermissions(activity,
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
MY_PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION);
if (BTAdapter.isEnabled()){
BTAdapter.startDiscovery();
Log.e("mio", "dp de star discovery");
}
else{
Intent turnOn = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(turnOn, 1);
Log.e("mio", "no weisa");
}
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
activity.registerReceiver(mReceiver, filter);
return view;
}
#Override
public void onStart() {
Log.e("mio", "dentro de on start ");
dataInicialRecibida=false;
super.onStart();
//getPairedDevices();
this.conectar.setOnClickListener(clicked);
this.actualizar.setOnClickListener(clicked);
listView.setOnItemClickListener(listItemClicked);
MainActivity activity = (MainActivity) getActivity();
texto.setText("sistema listo");
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.i("BT", "recibe");
if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
//discovery starts, we can show progress dialog or perform other tasks
Log.i("BT", "empezamos BT");
}
if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
//discovery starts, we can show progress dialog or perform other tasks
Log.i("BT", "terminiamos BT");
try {
Method getUuidsMethod = BluetoothAdapter.class.getDeclaredMethod("getUuids", null);
ParcelUuid[] uuids = (ParcelUuid[]) getUuidsMethod.invoke(BTAdapter, null);
if(uuids != null) {
for (ParcelUuid uuid : uuids) {
Log.d(TAG, "UUID: " + uuid.getUuid().toString());
miu=uuid.getUuid().toString();
}
}else{
Log.d(TAG, "Uuids not found, be sure to enable Bluetooth!");
}
}catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
//discovery starts, we can show progress dialog or perform other tasks
Log.i("BT", "state changed BT");
}
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// mDeviceList.add(device.getName() + "\n" + device.getAddress());
// DeviceItem newDevice = new DeviceItem(device.getName(), device.getAddress(), "false");
Log.i("BTN", device.getName() + "\n" + device.getAddress());
// mDeviceList.notifyDataSetChanged();
if(listaBTDevices.size()<1) // this checks if the size of bluetooth device is 0,then add the
{
Log.i("mio", "lista devices menor a 1");// device to the arraylist.
m_DiscoveredPeersAdapter.add(device.getName()+"\n"+device.getAddress());
listaBTDevices.add(device);
m_DiscoveredPeersAdapter.notifyDataSetChanged();
}
else
{
Log.i("mio", "lista devices maor o igual a 1");
boolean flag = true; // flag to indicate that particular device is already in the arlist or not
for(int i = 0; i<listaBTDevices.size();i++)
{
if(device.getAddress().equals(listaBTDevices.get(i).getAddress()))
{
flag = false;
}
}
if(flag == true)
{
m_DiscoveredPeersAdapter.add(device.getName()+"\n"+device.getAddress());
listaBTDevices.add(device);
m_DiscoveredPeersAdapter.notifyDataSetChanged();
}
}
}
listView.setAdapter(new ArrayAdapter<String>(context,
android.R.layout.simple_list_item_1, mDeviceList));
}
};
#RequiresApi(api = Build.VERSION_CODES.M)
private void checkBTPermissions() {
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP){
int permissionCheck =getActivity().checkSelfPermission("Manifest.permission.ACCESS_FINE_LOCATION");
permissionCheck += getActivity().checkSelfPermission("Manifest.permission.ACCESS_COARSE_LOCATION");
if (permissionCheck != 0) {
this.requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, 1001); //Any number
}
}else{
Log.d(TAG, "checkBTPermissions: No need to check permissions. SDK version < LOLLIPOP.");
}
}
#Override
public void onDestroy() {
MainActivity activity = (MainActivity) getActivity();
activity.unregisterReceiver(mReceiver);
super.onDestroy();
Log.e("mio", "on destroy ");
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK){
Log.d(TAG, "caso okookok.");
BTAdapter.startDiscovery();
}else{
Log.d(TAG, "cas no ok.");
}
}
#Override
public void onStop() {
super.onStop();
Log.e("mio", "on stop");
MainActivity activity = (MainActivity) getActivity();
activity.unregisterReceiver(mReceiver);
}
#Override
public void onServiceConnected(ComponentName name, IBinder binder) {
service = ((SerialService.SerialBinder) binder).getService();
Log.e("mio", "on service conectado conexiones ");
if(initialStart && isResumed()) {
initialStart = false;
getActivity().runOnUiThread(this::connect);
}
}
#Override
public void onServiceDisconnected(ComponentName name) {
service = null;
texto.setText("desconectado BT");
Log.e("mio", "desconectado BT conexiones");
}
#Override
public void onSerialConnect() {
texto.setText("conexion BT");
Log.e("mio", "conectado BT conexiones");
}
#Override
public void onSerialConnectError(Exception e) {
texto.setText("error conexion BT");
Log.e("mio", "onSerialConnectError");
}
#Override
public void onSerialRead(byte[] data) {
receive(data);
texto.setText("leyendo BT");
Log.e("mio", "leyendo BT ");
}
private void receive(byte[] data) {
receiveText+=new String(data);
receiveText="";
}
#Override
public void onSerialIoError(Exception e) {
texto.setText("error conexion BT");
}
class ButtonClicked implements View.OnClickListener
{
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.button:
listaBTDevices.clear();
m_DiscoveredPeersAdapter.clear();
startSearching();
texto.setText("buscando dispositivos BT");
break;
case R.id.button3:
break;
}
}
}
class ListItemClicked implements AdapterView.OnItemClickListener
{
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
bdDevice = listaBTDevices.get(position);
//bdClass = arrayListBluetoothDevices.get(position);
Log.i("Log", "The dvice : "+bdDevice.toString());
connect();
}
}
private boolean isNetworkAvailable() {
ConnectivityManager connectivityManager = (ConnectivityManager) service.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
private void getPairedDevices() {
// Set<BluetoothDevice> pairedDevice = BTAdapter.getBondedDevices();
// if(pairedDevice.size()>0)
{
// for(BluetoothDevice device : pairedDevice)
{
// arrayListpaired.add(device.getName()+"\n"+device.getAddress());
// arrayListPairedBluetoothDevices.add(device);
}
}
// adapter.notifyDataSetChanged();
}
public void send(String str) {
try {
SpannableStringBuilder spn = new SpannableStringBuilder(str+'\n');
byte[] data = (str).getBytes();
socket.write(data);
} catch (Exception e) {
onSerialIoError(e);
}
}
#SuppressWarnings("deprecation")
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// getActivity().bindService(new Intent(getActivity(), SerialService.class), this, Context.BIND_AUTO_CREATE);
}
private void connect() {
try {
BTAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothDevice device = BTAdapter .getRemoteDevice(bdDevice.getAddress());
String deviceName = device.getName() != null ? device.getName() : device.getAddress();
socket = new SerialSocket();
service.connect(this, "Connected to " + deviceName);
socket.connect(getContext(), service, device);
MainActivity activity = (MainActivity) getActivity();
activity.setidEquipo(bdDevice.getAddress());
// conexión ok, cambiar color letras boton
} catch (Exception e) {
//onSerialConnectError(e);
Log.i("mio", "error del connect "+e);
// sino hay conexión mantener boton con letras naranjas
}
}
private void startSearching() {
Log.i("Log", "in the start searching method");
MainActivity activity = (MainActivity) getActivity();
IntentFilter intentFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
activity.registerReceiver(mReceiver, intentFilter);
BTAdapter.startDiscovery();
}
private void onBluetooth() {
if(!BTAdapter.isEnabled())
{
BTAdapter.enable();
Log.i("Log", "Bluetooth is Enabled");
}
}
private void offBluetooth() {
if(BTAdapter.isEnabled())
{
BTAdapter.disable();
}
}
}
The serial service:
public class SerialService extends Service implements SerialListener {
class SerialBinder extends Binder {
SerialService getService() { return SerialService.this; }
}
private enum QueueType {Connect, ConnectError, Read, IoError}
private class QueueItem {
QueueType type;
byte[] data;
Exception e;
QueueItem(QueueType type, byte[] data, Exception e) { this.type=type; this.data=data; this.e=e; }
}
private final Handler mainLooper;
private final IBinder binder;
private final Queue<QueueItem> queue1, queue2;
private SerialListener listener;
private boolean connected;
private String notificationMsg;
public SerialService() {
mainLooper = new Handler(Looper.getMainLooper());
binder = new SerialBinder();
queue1 = new LinkedList<>();
queue2 = new LinkedList<>();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return binder;
}
public void connect(SerialListener listener, String notificationMsg) {
this.listener = listener;
connected = true;
this.notificationMsg = notificationMsg;
}
public void disconnect() {
listener = null;
connected = false;
notificationMsg = null;
}
public void attach(SerialListener listener) {
if(Looper.getMainLooper().getThread() != Thread.currentThread())
throw new IllegalArgumentException("not in main thread");
cancelNotification();
// use synchronized() to prevent new items in queue2
// new items will not be added to queue1 because mainLooper.post and attach() run in main thread
if(connected) {
synchronized (this) {
this.listener = listener;
}
}
for(QueueItem item : queue1) {
switch(item.type) {
case Connect: listener.onSerialConnect (); break;
case ConnectError: listener.onSerialConnectError (item.e); break;
case Read: listener.onSerialRead (item.data); break;
case IoError: listener.onSerialIoError (item.e); break;
}
}
for(QueueItem item : queue2) {
switch(item.type) {
case Connect: listener.onSerialConnect (); break;
case ConnectError: listener.onSerialConnectError (item.e); break;
case Read: listener.onSerialRead (item.data); break;
case IoError: listener.onSerialIoError (item.e); break;
}
}
queue1.clear();
queue2.clear();
}
public void detach() {
if(connected)
createNotification();
// items already in event queue (posted before detach() to mainLooper) will end up in queue1
// items occurring later, will be moved directly to queue2
// detach() and mainLooper.post run in the main thread, so all items are caught
listener = null;
}
public void onSerialConnect() {
Log.i("mio", "dentro on serial connect ");
if(connected) {
Log.i("mio", "dentro de connected ");
synchronized (this) {
if (listener != null) {
mainLooper.post(() -> {
if (listener != null) {
listener.onSerialConnect();
} else {
queue1.add(new QueueItem(QueueType.Connect, null, null));
}
});
} else {
queue2.add(new QueueItem(QueueType.Connect, null, null));
}
}
}
}
public void onSerialConnectError(Exception e) {
if(connected) {
synchronized (this) {
if (listener != null) {
mainLooper.post(() -> {
if (listener != null) {
listener.onSerialConnectError(e);
} else {
queue1.add(new QueueItem(QueueType.ConnectError, null, e));
cancelNotification();
disconnect();
}
});
} else {
queue2.add(new QueueItem(QueueType.ConnectError, null, e));
cancelNotification();
disconnect();
}
}
}
}
public void onSerialRead(byte[] data) {
if(connected) {
synchronized (this) {
if (listener != null) {
mainLooper.post(() -> {
if (listener != null) {
listener.onSerialRead(data);
} else {
queue1.add(new QueueItem(QueueType.Read, data, null));
}
});
} else {
queue2.add(new QueueItem(QueueType.Read, data, null));
}
}
}
}
public void onSerialIoError(Exception e) {
if(connected) {
synchronized (this) {
if (listener != null) {
mainLooper.post(() -> {
if (listener != null) {
listener.onSerialIoError(e);
} else {
queue1.add(new QueueItem(QueueType.IoError, null, e));
cancelNotification();
disconnect();
}
});
} else {
queue2.add(new QueueItem(QueueType.IoError, null, e));
cancelNotification();
disconnect();
}
}
}
}
}
The serial socket class:
class SerialSocket implements Runnable {
private static final UUID BLUETOOTH_SPP = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private final BroadcastReceiver disconnectBroadcastReceiver;
private Context context;
private SerialListener listener;
private BluetoothDevice device;
private BluetoothSocket socket;
private boolean connected;
SerialSocket() {
disconnectBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(listener != null)
listener.onSerialIoError(new IOException("background disconnect"));
disconnect(); // disconnect now, else would be queued until UI re-attached
}
};
}
/**
* connect-success and most connect-errors are returned asynchronously to listener
*/
void connect(Context context, SerialListener listener, BluetoothDevice device) throws IOException {
if(connected || socket != null)
throw new IOException("already connected");
this.context = context;
this.listener = listener;
this.device = device;
context.registerReceiver(disconnectBroadcastReceiver, new IntentFilter(Constants.INTENT_ACTION_DISCONNECT));
Executors.newSingleThreadExecutor().submit(this);
}
void disconnect() {
listener = null; // ignore remaining data and errors
// connected = false; // run loop will reset connected
if(socket != null) {
try {
socket.close();
} catch (Exception ignored) {
}
socket = null;
}
try {
context.unregisterReceiver(disconnectBroadcastReceiver);
} catch (Exception ignored) {
}
}
void write(byte[] data) throws IOException {
if (!connected)
throw new IOException("not connected");
socket.getOutputStream().write(data);
}
#Override
public void run() { // connect & read
try {
socket = device.createRfcommSocketToServiceRecord(BLUETOOTH_SPP);
socket.connect();
if(listener != null)
listener.onSerialConnect();
} catch (Exception e) {
if(listener != null)
listener.onSerialConnectError(e);
try {
socket.close();
} catch (Exception ignored) {
}
socket = null;
return;
}
connected = true;
try {
byte[] buffer = new byte[1024];
int len;
//noinspection InfiniteLoopStatement
while (true) {
len = socket.getInputStream().read(buffer);
byte[] data = Arrays.copyOf(buffer, len);
if(listener != null)
listener.onSerialRead(data);
}
} catch (Exception e) {
connected = false;
if (listener != null)
listener.onSerialIoError(e);
try {
socket.close();
} catch (Exception ignored) {
}
socket = null;
}
}
}
And the second fragment whereas I need to keep connection or connect to the same device already connected in fragment ("conexiones"):
public class Identificacion extends Fragment implements ServiceConnection, SerialListener {
private String deviceAddress;
private String newline = "\r\n";
private String receiveText;
private enum Connected { False, Pending, True }
private String sendText;
private SerialSocket socket;
private SerialService service;
private boolean initialStart = true;
private Connected connected = Connected.False;
// constructor requerido vacio
public Identificacion(){
}
#Override
public void onCreate(Bundle savedInstanceState) {
Log.e("mio", "dentro on creata identificacion");
super.onCreate(savedInstanceState);
setRetainInstance(true);
// deviceAddress = getArguments().getString("device");
}
#SuppressWarnings("deprecation") // onAttach(context) was added with API 23. onAttach(activity) works for all API versions
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
getActivity().bindService(new Intent(getActivity(), SerialService.class), this, Context.BIND_AUTO_CREATE);
}
#Override
public void onDetach() {
try { getActivity().unbindService(this); } catch(Exception ignored) {}
super.onDetach();
}
#Override
public void onResume() {
super.onResume();
/* if(initialStart && service !=null) {
initialStart = false;
getActivity().runOnUiThread(this::connect);
} */
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
view = inflater.inflate(R.layout.fragment_identificacion, container, false );
return view;
}
private void addListenerOnButton() {
bt12.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
EditText txtView = (EditText) aux1;
EditText txtView2 = (EditText) aux2;
TextView txtView3 = (TextView) aux3;
if (pin2 != null && pin2.length() == largo && pin4 != null && pin4.length() == largo){
//consultar BD si exta bien la pass, caso si:
Log.e("mio", "dentro de pin y pass con formato " + pin2);
pin=pin2;
String aenvio=(String)pin2+";"+pin4;
// enviar pin por BT
connect();
send(aenvio);
}
}
});
}// fin add listener button
private void connect() {
try {
MainActivity activity = (MainActivity) getActivity();
String par3= activity.getidEquipo();
deviceAddress=par3;
Log.e("mio", "connect identif valor deviceAddress "+deviceAddress);
//deviceAddress = getArguments().getString("device");
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(deviceAddress);
String deviceName = device.getName() != null ? device.getName() : device.getAddress();
// status("connecting...");
Log.e("mio", "connect identif deviceName "+deviceName);
connected = Connected.Pending;
onAttach(activity);
// socket =
//socket = new SerialSocket();
getActivity().bindService(new Intent(getActivity(), SerialService.class ), this, Context.BIND_ADJUST_WITH_ACTIVITY );
service.connect(this, "Connected to " + deviceName);
socket.connect(getContext(), service, device);
connected = Connected.True;
Log.e("mio", "connect identif salida "+deviceName);
} catch (Exception e) {
onSerialConnectError(e);
}
}
private void send(String str) {
if(connected != Connected.True) {
Toast.makeText(getActivity(), "not connected", Toast.LENGTH_SHORT).show();
Log.e("mio", "dentro send no conectado "+str);
// return;
}
try {
connect();
// SpannableStringBuilder spn = new SpannableStringBuilder(str+'\n');
Log.e("mio", "send conectado "+str);
// spn.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.colorSendText)), 0, spn.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
Toast.makeText(getActivity(), "enviando login a esp", Toast.LENGTH_SHORT).show();
sendText=str; // poner aca el string de user;pass a enviar al esp32 app
byte[] data = (str + newline).getBytes();
socket.write(data);
} catch (Exception e) {
onSerialIoError(e);
}
}
private void receive(byte[] data) {
receiveText+=(new String(data));
}
#Override
public void onServiceConnected(ComponentName name, IBinder binder) {
service = ((SerialService.SerialBinder) binder).getService();
if(initialStart && isResumed()) {
initialStart = false;
getActivity().runOnUiThread(this::connect);
}
}
#Override
public void onServiceDisconnected(ComponentName name) {
service = null;
}
#Override
public void onSerialRead(byte[] data) {
Log.e("mio", "serial leer data ");
receive(data);
}
#Override
public void onSerialIoError(Exception e) {
Log.e("mio", "serial io error, desconectar ");
disconnect();
}
}
Managing code when you are using Bluetooth or system-related task is too hard because it creates a tightly coupled code eventually turn into the buggy code. So you can use this and this libraries to do your task neat and cleanly. Please check the example app for my suggested first and second libraries. If you face any struck in implementation let me know.
Run service from an activity or from the App class.
upd:
Or use singleton as a main point to communicate with the BluetoothHelper
I solved this of my way, by keeping the bluetooth socket static.
I've setted the 'boolean' object {TRUE, PENDING, FALSE}, in service and handled this object with service listener in others activities.
in the activities i unbind the service but do not disconnect socket, but as i don't disconnect from socket when change activities, there's a memory leak, but for me isn't a problem.
result:
the socket keeps connected and i can access the device from all activities, and the error handling (discconect, bluetooth off) happens thanks to listener
Create a service running in a different process not the main app process. Communicate with main app and service using broadcast receivers. This makes sure you can be anywhere in main app but you can still interact with Ble service
solved moving all the bluetooth code: broadcast receiver, service instance and socket instance, to the main activity, then in the fragments the service is attached (bind service) or (if null) started again.
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
Log.e("mio", "dentro de is visible to user identif ");
// connect();
if(service != null){
service.attach(this);
Log.e("mio", "caso attach ");
}
else{
Log.e("mio", "caso start service 1 ");
getActivity().startService(new Intent(getActivity(), SerialService.class)); // prevents service destroy on unbind from recreated activity caused by orientation change
// service.attach(this);
}
This solves the problem nice and easy, so the service is available when user see data in the fragment, and communication is well received and sent.
I have used BluetoothSPP Library:
https://github.com/akexorcist/Android-BluetoothSPPLibrary
The arduino connecting successfully to the android studio application, but I can't receive the data, I will import both of my codes and please some one tell me if I did something wrong, from what I read and understood , bluetooth.setOnDataReceivedListener is the function to receive and you should place bluetooth.print(data) on the arduino part in order to
Android:
public class MainActivity extends AppCompatActivity {
final String ON = "1";
final String OFF = "0";
BluetoothSocket socket;
private BluetoothAdapter mAdapter;
BluetoothSPP bluetooth;
private BluetoothDevice remoteDevice;
TextView text;
private BluetoothServerSocket mmServerSocket;
String TAG = "TEST: ";
Button connect;
Button on;
Button off;
private OnDataReceivedListener mDataReceivedListener = null;
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == BluetoothState.REQUEST_CONNECT_DEVICE) {
if (resultCode == Activity.RESULT_OK)
bluetooth.connect(data);
} else if (requestCode == BluetoothState.REQUEST_ENABLE_BT) {
if (resultCode == Activity.RESULT_OK) {
bluetooth.setupService();
} else {
Toast.makeText(getApplicationContext()
, "Bluetooth was not enabled."
, Toast.LENGTH_SHORT).show();
finish();
}
}
}
public void setOnDataReceivedListener (OnDataReceivedListener listener) {
if (mDataReceivedListener == null)
mDataReceivedListener = listener;
}
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket, String socketType) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the BluetoothSocket input and output streams
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
}
public void onStart() {
super.onStart();
if (!bluetooth.isBluetoothEnabled()) {
bluetooth.enable();
} else {
if (!bluetooth.isServiceAvailable()) {
bluetooth.setupService();
bluetooth.startService(BluetoothState.DEVICE_OTHER);
}
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bluetooth = new BluetoothSPP(this);
text = (TextView) findViewById(R.id.textView2);
connect = (Button) findViewById(R.id.connect);
on = (Button) findViewById(R.id.on);
off = (Button) findViewById(R.id.off);
BluetoothSocket socket = null;
mAdapter = BluetoothAdapter.getDefaultAdapter();
if (!bluetooth.isBluetoothAvailable()) {
Toast.makeText(getApplicationContext(), "Bluetooth is not available", Toast.LENGTH_SHORT).show();
finish();
}
bluetooth.setOnDataReceivedListener(new BluetoothSPP.OnDataReceivedListener() {
public void onDataReceived(byte[] data, String message) {
Log.d(TAG, "Start Reading");
/*Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();*/
Log.i("Check", "Message : " + message);
}
});
bluetooth.setBluetoothConnectionListener(new BluetoothSPP.BluetoothConnectionListener() {
public void onDeviceConnected(String name, String address) {
connect.setText("Connected to " + name);
}
public void onDeviceDisconnected() {
connect.setText("Connection lost");
}
public void onDeviceConnectionFailed() {
connect.setText("Unable to connect");
}
});
connect.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (bluetooth.getServiceState() == BluetoothState.STATE_CONNECTED) {
bluetooth.disconnect();
} else {
Intent intent = new Intent(getApplicationContext(), DeviceList.class);
startActivityForResult(intent, BluetoothState.REQUEST_CONNECT_DEVICE);
}
}
});
on.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "Its on");
bluetooth.send(ON, true);
}
});
off.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d(TAG, "Its off");
bluetooth.send(OFF, true);
}
});
}
arduino part:
The Arduino code looks right.
Try first a Bluetooth serial monitor on your Android to check if the data is really being sent and received.
Then make sure in your Android code you connect to the module first then try to receive the data.
I'm making a OBDII reader app and would like to see the (in this case) voltage on text rather than in the Logcat which is what I currently see. You can see in the code below where I read the voltage in my while loop. Is it possible to update the textView everytime the loop runs?
Any help is appreciated!
.java
public class BTHandler {
public static final int STATE_NONE = 0; // we're doing nothing
public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
public static final int STATE_CONNECTED = 3; // now connected to a remote device
private final BluetoothAdapter mAdapter;
private final Handler mHandler;
BluetoothAdapter mBluetoothAdapter;
UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private String status;
private BluetoothDevice mmDevice;
private ConnectedThread mConnectedThread;
private ConnectThread mConnectThread;
private int pPlatform = Constants.SPA;
private boolean connectionStatus = false;
public BTHandler(Context context, Handler handler) { // Konstruktor
mAdapter = BluetoothAdapter.getDefaultAdapter();
mHandler = handler;
}
public void write(String s) {
mConnectedThread.sendRawCommand(s);
Log.v("write", "write");
}
public void close() {
try {
mConnectedThread.cancel();
} catch (NullPointerException e) {
}
}
public void connect(String deviceAddress) {
mConnectThread = new ConnectThread(deviceAddress);
mConnectThread.start();
}
private void guiHandler(int what, int arg1, String obj) {
Message msg = mHandler.obtainMessage();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.sendToTarget();
}
private class ConnectThread extends Thread {
private final BluetoothDevice mmDevice;
BluetoothSocket tmp = null;
private BluetoothSocket mmSocket;
public ConnectThread(String deviceAddress) {
mmDevice = mAdapter.getRemoteDevice(deviceAddress);
try {
// MY_UUID is the app's UUID string, also used by the server code
tmp = mmDevice.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
}
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it will slow down the connection
mAdapter.cancelDiscovery();
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mmSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and get out
try {
mmSocket.close();
} catch (IOException closeException) {
}
guiHandler(Constants.TOAST, Constants.SHORT, "Connection Failed");
return;
}
// Do work to manage the connection (in a separate thread)
guiHandler(Constants.CONNECTION_STATUS, Constants.STATE_CONNECTED, "");
mConnectedThread = new ConnectedThread(mmSocket);
mConnectedThread.start();
}
}
private class ConnectedThread extends Thread {
private final InputStream mmInStream;
private final OutputStream mmOutStream;
private BluetoothSocket mmSocket;
private ObdMultiCommand multiCommand;
public ConnectedThread(BluetoothSocket socket) {
connectionStatus = true;
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
switch (pPlatform) {
case Constants.SPA:
multiCommand = new ObdMultiCommand();
multiCommand.add(new OdbRawCommand(SPA.VOLTAGE));
break;
}
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.v("e", "e");
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
OBDcmds();
ModuleVoltageCommand voltageCommand = new ModuleVoltageCommand();
//TextView textView = (TextView) findViewById(R.id.textView);
while (!Thread.currentThread().isInterrupted()) {
try {
voltageCommand.run(mmInStream, mmOutStream);
voltageCommand.getFormattedResult();
Log.d("Log", "Voltage:" + voltageCommand.getFormattedResult());
textView.setText(voltageCommand.getFormattedResult());
} catch (Exception e) {
e.printStackTrace();
}
}
}
// CALL this to MainActivity
public void sendRawCommand(String s) {
try {
} catch (Exception e) {
Log.v("sendRawCommand", "e");
}
}
/*
// Call this from the main activity to send data to the remote device
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
*/
private void OBDcmds() { // execute commands
try {
new EchoOffCommand().run(mmInStream, mmOutStream);
new LineFeedOffCommand().run(mmInStream, mmOutStream);
new TimeoutCommand(100).run(mmInStream, mmOutStream);
new SelectProtocolCommand(ObdProtocols.AUTO).run(mmInStream, mmOutStream);
//ISO_15765_4_CAN
} catch (Exception e) {
Log.v("OBDcmds", "e");
// handle errors
}
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
connectionStatus = false;
mmSocket.close();
guiHandler(Constants.CONNECTION_STATUS, Constants.STATE_NOT_CONNECTED, "");
} catch (IOException e) {
}
}
}
}
.xml
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="178dp"
android:text="Medium Text"
android:textAppearance="?android:attr/textAppearanceMedium" />
MainActivity
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Button b1;
BluetoothAdapter mAdapter;
BTHandler btHandler;
private Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case Constants.MESSAGE_STATE_CHANGE:
switch (msg.arg1) {
case BTHandler.STATE_CONNECTED:
setContentView(R.layout.activity_connected);
Toast.makeText(getApplicationContext(), R.string.title_connected_to, Toast.LENGTH_SHORT).show();
Log.v("Log", "Connected");
break;
case BTHandler.STATE_NONE:
Toast.makeText(getApplicationContext(), R.string.title_not_connected, Toast.LENGTH_SHORT).show();
break;
}
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView = (TextView) findViewById(R.id.textView);
btHandler = new BTHandler(MainActivity.this, mHandler);
b1 = (Button) findViewById(R.id.connect);
b1.setOnClickListener(this);
mAdapter = BluetoothAdapter.getDefaultAdapter();
if (mAdapter == null) {
Toast.makeText(getApplicationContext(), R.string.device_not_supported, Toast.LENGTH_LONG).show();
finish();
} else {
if (!mAdapter.isEnabled()) {
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, 1);
}
}
}
public void onClick(View v) {
int id = v.getId();
//String voltage = ("ATRV");
switch (id) {
case R.id.connect:
onConnect(); //Operation
Log.v("Log", "Pressed onClick");
break;
case R.id.getValue:
btHandler.write(SPA.VOLTAGE);
Log.v("getValue","" + SPA.VOLTAGE);
break;
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_CANCELED) {
Toast.makeText(getApplicationContext(), R.string.enable_bluetooth, Toast.LENGTH_SHORT).show();
finish();
}
}
private void onConnect() {
ArrayList deviceStrs = new ArrayList();
final ArrayList<String> devices = new ArrayList();
BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapter();
Set pairedDevices = mAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
for (Object device : pairedDevices) {
BluetoothDevice bdevice = (BluetoothDevice) device;
deviceStrs.add(bdevice.getName() + "\n" + bdevice.getAddress());
devices.add(bdevice.getAddress());
}
}
// show list
final AlertDialog.Builder alertDialog = new AlertDialog.Builder(this);
ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.select_dialog_singlechoice,
deviceStrs.toArray(new String[deviceStrs.size()]));
alertDialog.setSingleChoiceItems(adapter, -1, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
int position = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
String deviceAddress = devices.get(position);
btHandler.connect(deviceAddress);
}
});
alertDialog.setTitle("Paired devices");
alertDialog.show();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
Your object extends the Thread so I assume that it would be started like this
ConnectedThread ct = new ConnectedThread(socket);
ct.start();
In Android you can't update View from non-UI thread. You would need to create a Handler and pass the data to it. In you Handler implementation you would be able to call the setText() method to update your TextView.
See this link for more details about communication with UT thread.
For the updated post
I personally don't like the idea to change the layout of the Activity in the Handler implementation - I would go for Fragments usage.
Anyway after calling the setContentView(R.layout.activity_connected) in your Handler you need to call the findViewById again to find the TextView in your activity_connected layout:
case BTHandler.STATE_CONNECTED:
setContentView(R.layout.activity_connected);
Toast.makeText(getApplicationContext(), R.string.title_connected_to, Toast.LENGTH_SHORT).show();
Log.v("Log", "Connected");
TextView tv = (TextView)findViewById(R.id.textView);
tv.setText("Connected");
break;
Code snippet update
ConnectedThread#run()
public void run() {
OBDcmds();
ModuleVoltageCommand voltageCommand = new ModuleVoltageCommand();
//TextView textView = (TextView) findViewById(R.id.textView);
while (!Thread.currentThread().isInterrupted()) {
try {
voltageCommand.run(mmInStream, mmOutStream);
Log.d("Log", "Voltage:" + voltageCommand.getFormattedResult());
guiHandler(Constants.VOLTAGE_STATUS, 0, voltageCommand.getFormattedResult())
} catch (Exception e) {
e.printStackTrace();
}
}
}
Handler implementation
private Handler mHandler = new Handler() {
TextView textView = null;
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case Constants.MESSAGE_STATE_CHANGE:
switch (msg.arg1) {
case BTHandler.STATE_CONNECTED:
setContentView(R.layout.activity_connected);
Toast.makeText(getApplicationContext(), R.string.title_connected_to, Toast.LENGTH_SHORT).show();
Log.v("Log", "Connected");
textView = (TextView)findViewById(R.id.textView);
break;
case BTHandler.STATE_NONE:
Toast.makeText(getApplicationContext(), R.string.title_not_connected, Toast.LENGTH_SHORT).show();
break;
}
break;
case Constants.VOLTAGE_STATUS:
if(msg.obj != null && textView != null){
textView.setText((String)msg.obj)
}
break;
}
}
};
Use textView.setText(voltageCommand.getFormattedResult())
First, you need to map your textView to the resource ID.
TextView textView = (TextView) findViewById(R.id.textView);
you can place the above line after setContentView("your layout");
Now, you can use this textView and set the data as shown below,
textView.setText(voltageCommand.getFormattedResult());
This is about Android app development basics, you should read the tutorials at developer.android.com.
You can access the TextView with
TextView textView = (TextView) findViewbyId(R.id.textView);.
Then change your text with
textView.setText("new message");
HTH
I am trying to setup a Bluetooth connection between an Android device and an rPi. However I am getting an unresolved symbol error on socket in the testouput function. However, socket works just fine further down the code. I am not sure what I am doing wrong here. Thanks!
ArrayAdapter<String> listAdapter;
ListView listView;
BluetoothAdapter btAdapter;
Set<BluetoothDevice> devicesArray;
ArrayList<String> pairedDevices;
ArrayList<BluetoothDevice> devices;
public static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
protected static final int SUCCESS_CONNECT = 0;
protected static final int MESSAGE_READ = 1;
IntentFilter filter;
BroadcastReceiver receiver;
String tag = "debugging";
Handler mHandler = new Handler(){
#Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
Log.i(tag, "in handler");
super.handleMessage(msg);
switch(msg.what){
case SUCCESS_CONNECT:
// DO something
ConnectedThread connectedThread = new ConnectedThread((BluetoothSocket)msg.obj);
Toast.makeText(getApplicationContext(), "CONNECT", 0).show();
String s = "successfully connected";
connectedThread.write(s.getBytes());
Log.i(tag, "connected");
break;
case MESSAGE_READ:
byte[] readBuf = (byte[])msg.obj;
String string = new String(readBuf);
Toast.makeText(getApplicationContext(), string, 0).show();
break;
}
}
};
#Override
public void testoutput(String str){
final BluetoothSocket mmSocket;
mmSocket = socket;
byte[] toSend=str.getBytes();
OutputStream mmOutStream = socket.getOutputStream();
mmOutStream.write(toSend);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.bluetooth);
init();
if(btAdapter==null){
Toast.makeText(getApplicationContext(), "No bluetooth detected", 0).show();
finish();
}
else{
if(!btAdapter.isEnabled()){
turnOnBT();
}
getPairedDevices();
startDiscovery();
}
}
private void startDiscovery() {
// TODO Auto-generated method stub
btAdapter.cancelDiscovery();
btAdapter.startDiscovery();
}
private void turnOnBT() {
// TODO Auto-generated method stub
Intent intent =new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, 1);
}
private void getPairedDevices() {
// TODO Auto-generated method stub
devicesArray = btAdapter.getBondedDevices();
if(devicesArray.size()>0){
for(BluetoothDevice device:devicesArray){
pairedDevices.add(device.getName());
}
}
}
private void init() {
// TODO Auto-generated method stub
listView=(ListView)findViewById(R.id.listView);
listView.setOnItemClickListener(this);
listAdapter= new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,0);
listView.setAdapter(listAdapter);
btAdapter = BluetoothAdapter.getDefaultAdapter();
pairedDevices = new ArrayList<String>();
filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
devices = new ArrayList<BluetoothDevice>();
receiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String action = intent.getAction();
if(BluetoothDevice.ACTION_FOUND.equals(action)){
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
devices.add(device);
String s = "";
for(int a = 0; a < pairedDevices.size(); a++){
if(device.getName().equals(pairedDevices.get(a))){
//append
s = "(Paired)";
break;
}
}
listAdapter.add(device.getName()+" "+s+" "+"\n"+device.getAddress());
}
else if(BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)){
// run some code
}
else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){
// run some code
}
else if(BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)){
if(btAdapter.getState() == btAdapter.STATE_OFF){
turnOnBT();
}
}
}
};
registerReceiver(receiver, filter);
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
registerReceiver(receiver, filter);
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(receiver, filter);
filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(receiver, filter);
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
unregisterReceiver(receiver);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_CANCELED){
Toast.makeText(getApplicationContext(), "Bluetooth must be enabled to continue", Toast.LENGTH_SHORT).show();
finish();
}
}
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// TODO Auto-generated method stub
if(btAdapter.isDiscovering()){
btAdapter.cancelDiscovery();
}
if(listAdapter.getItem(arg2).contains("Paired")){
BluetoothDevice selectedDevice = devices.get(arg2);
ConnectThread connect = new ConnectThread(selectedDevice);
connect.start();
Log.i(tag, "in click listener");
}
else{
Toast.makeText(getApplicationContext(), "device is not paired", 0).show();
}
}
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to mmSocket,
// because mmSocket is final
BluetoothSocket tmp = null;
mmDevice = device;
Log.i(tag, "construct");
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
// MY_UUID is the app's UUID string, also used by the server code
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
Log.i(tag, "get socket failed");
}
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it will slow down the connection
btAdapter.cancelDiscovery();
Log.i(tag, "connect - run");
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mmSocket.connect();
Log.i(tag, "connect - succeeded");
} catch (IOException connectException) { Log.i(tag, "connect failed");
// Unable to connect; close the socket and get out
try {
mmSocket.close();
} catch (IOException closeException) { }
return;
}
// Do work to manage the connection (in a separate thread)
mHandler.obtainMessage(SUCCESS_CONNECT, mmSocket).sendToTarget();
}
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
buffer = new byte[1024];
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI activity
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);
} catch (IOException e) { }
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
I am trying to get my Android phone (NexusOne) to connect to two bluetooth chips simultaneously. I have read various responses on the internet concluding that this may or may not be able to be done. People who have gotten it working say it works by establishing multiple RFcomm connections, like two connect threads in parallel. I am not sure how to go about doing this. I have my connect code which will only connect to one chip at the moment. Ideas?
package com.example.connect;
public class ConnectThread extends Activity {
static BluetoothSocket mmSocket;
static BluetoothSocket mmSocket2;
static BluetoothDevice mmDevice;
static BluetoothDevice mmDevice2;
static InputStream mmInputStream;
static OutputStream mmOutputStream;
static BluetoothAdapter mBluetoothAdapter;
static BluetoothAdapter mBluetoothAdapter2;
TextView myLabel;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_connect_thread);
Button button = (Button)this.findViewById(R.id.button1);
myLabel = (TextView)findViewById(R.id.textView1);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(ConnectThread.this, "Connection in progress", Toast.LENGTH_SHORT).show();
myLabel.setText("Connection in progress");
try
{
findBT2();
openBT2();
findBT();
openBT();
}
catch (IOException ex) { }
}
});}
void findBT2()
{
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(mBluetoothAdapter == null)
{
myLabel.setText("No bluetooth adapter available");
}
if(!mBluetoothAdapter.isEnabled())
{
Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBluetooth, 0);
}
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
if(pairedDevices.size() > 0)
{
for(BluetoothDevice device2 : pairedDevices)
{
if(device2.getName().equals("H-C-2010-06-01"))
{
mmDevice2 = device2;
myLabel.setText("Bluetooth Device Found");
break;
}
}
if(pairedDevices.size()==0){myLabel.setText("Please Pair devices");}
}
}
public int openBT2() throws IOException
{
UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb"); //Standard SerialPortService ID
mmSocket2 = mmDevice2.createRfcommSocketToServiceRecord(uuid);
mmSocket2.connect();
mmOutputStream = mmSocket2.getOutputStream();
mmInputStream = mmSocket2.getInputStream();
return 1;
}
void findBT()
{
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(mBluetoothAdapter == null)
{
myLabel.setText("No bluetooth adapter available");
}
if(!mBluetoothAdapter.isEnabled())
{
Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBluetooth, 0);
}
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
if(pairedDevices.size() > 0)
{
for(BluetoothDevice device : pairedDevices)
{
if(device.getName().equals("HC-05"))
{
mmDevice = device;
myLabel.setText("Bluetooth Device Found");
break;
}
}
if(pairedDevices.size()==0){myLabel.setText("Please Pair devices");}
}
}
public int openBT() throws IOException
{
UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb"); //Standard SerialPortService ID
mmSocket = mmDevice.createRfcommSocketToServiceRecord(uuid);
mmSocket.connect();
mmOutputStream = mmSocket.getOutputStream();
mmInputStream = mmSocket.getInputStream();
return 1;
}
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(action))
{ myLabel.setText("CONNECTED");}
}
void closeBT() throws IOException
{
mmOutputStream.close();
mmInputStream.close();
mmSocket.close();
myLabel.setText("Bluetooth Closed");
}
}
UPDATE: I got a double connection by instead of trying to connect to each chip separately, just pulling up a list of paired devices and connecting to each one at a time. This worked to connect to both however still no data showing...
public class Main_Activity extends Activity implements OnItemClickListener {
ArrayAdapter<String> listAdapter;
ListView listView;
static TextView MyLabel;
BluetoothAdapter btAdapter;
Set<BluetoothDevice> devicesArray;
ArrayList<String> pairedDevices;
ArrayList<BluetoothDevice> devices;
public static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
protected static final int SUCCESS_CONNECT = 0;
protected static final int MESSAGE_READ = 1;
IntentFilter filter;
BroadcastReceiver receiver;
String tag = "debugging";
Handler mHandler = new Handler(){
#Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
Log.i(tag, "in handler");
super.handleMessage(msg);
switch(msg.what){
case SUCCESS_CONNECT:
// DO something
ConnectedThread connectedThread = new ConnectedThread((BluetoothSocket)msg.obj);
Toast.makeText(getApplicationContext(), "CONNECT", 0).show();
String s = "successfully connected";
connectedThread.write(s.getBytes());
Log.i(tag, "connected");
break;
case MESSAGE_READ:
byte[] readBuf = (byte[])msg.obj;
String string = new String(readBuf);
Toast.makeText(getApplicationContext(), string, 0).show();
MyLabel.setText(string);
break;
}
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
MyLabel = (TextView)findViewById(R.id.Receive);
init();
if(btAdapter==null){
Toast.makeText(getApplicationContext(), "No bluetooth detected", 0).show();
finish();
}
else{
if(!btAdapter.isEnabled()){
turnOnBT();
}
getPairedDevices();
startDiscovery();
}
}
private void startDiscovery() {
// TODO Auto-generated method stub
btAdapter.cancelDiscovery();
btAdapter.startDiscovery();
}
private void turnOnBT() {
// TODO Auto-generated method stub
Intent intent =new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, 1);
}
private void getPairedDevices() {
// TODO Auto-generated method stub
devicesArray = btAdapter.getBondedDevices();
if(devicesArray.size()>0){
for(BluetoothDevice device:devicesArray){
pairedDevices.add(device.getName());
}
}
}
private void init() {
// TODO Auto-generated method stub
listView=(ListView)findViewById(R.id.listView);
listView.setOnItemClickListener(this);
listAdapter= new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,0);
listView.setAdapter(listAdapter);
btAdapter = BluetoothAdapter.getDefaultAdapter();
pairedDevices = new ArrayList<String>();
filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
devices = new ArrayList<BluetoothDevice>();
receiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String action = intent.getAction();
if(BluetoothDevice.ACTION_FOUND.equals(action)){
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
devices.add(device);
String s = "";
for(int a = 0; a < pairedDevices.size(); a++){
if(device.getName().equals(pairedDevices.get(a))){
//append
s = "(Paired)";
break;
}
}
listAdapter.add(device.getName()+" "+s+" "+"\n"+device.getAddress());
}
else if(BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)){
// run some code
}
else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){
// run some code
}
else if(BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)){
if(btAdapter.getState() == btAdapter.STATE_OFF){
turnOnBT();
}
}
}
};
registerReceiver(receiver, filter);
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
registerReceiver(receiver, filter);
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(receiver, filter);
filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(receiver, filter);
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
unregisterReceiver(receiver);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_CANCELED){
Toast.makeText(getApplicationContext(), "Bluetooth must be enabled to continue", Toast.LENGTH_SHORT).show();
finish();
}
}
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// TODO Auto-generated method stub
if(btAdapter.isDiscovering()){
btAdapter.cancelDiscovery();
}
if(listAdapter.getItem(arg2).contains("Paired")){
BluetoothDevice selectedDevice = devices.get(arg2);
ConnectThread connect = new ConnectThread(selectedDevice);
connect.start();
Log.i(tag, "in click listener");
}
else{
Toast.makeText(getApplicationContext(), "device is not paired", 0).show();
}
}
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to mmSocket,
// because mmSocket is final
BluetoothSocket tmp = null;
mmDevice = device;
Log.i(tag, "construct");
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
// MY_UUID is the app's UUID string, also used by the server code
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
Log.i(tag, "get socket failed");
}
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it will slow down the connection
btAdapter.cancelDiscovery();
Log.i(tag, "connect - run");
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mmSocket.connect();
Log.i(tag, "connect - succeeded");
} catch (IOException connectException) { Log.i(tag, "connect failed");
// Unable to connect; close the socket and get out
try {
mmSocket.close();
} catch (IOException closeException) { }
return;
}
// Do work to manage the connection (in a separate thread)
mHandler.obtainMessage(SUCCESS_CONNECT, mmSocket).sendToTarget();
}
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
Toast.makeText(Main_Activity.this, "running", Toast.LENGTH_SHORT).show();
byte[] buffer; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
buffer = new byte[5000];
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI activity
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);
} catch (IOException e) { }
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
}