I am creating an android app to receive sensor data. I am able to discover both paired devices on the phone as well as nearby available Bluetooth devices. The issue is when I click on one of the devices either from the paired list or the discovered device list I am not able to connect to the device.
The code:
package com.example.Pillwoah;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.io.IOException;
import java.util.Set;
import java.util.UUID;
public class MainActivity4 extends AppCompatActivity {
TextView phoneName, deviceList;
private BluetoothAdapter BA;
private Set<BluetoothDevice> pairedDevices;
private ArrayAdapter<String> BAarray, BANewArray;
private ListView DeviceList, NewDevice;
private BluetoothSocket BTSocket = null;
private BluetoothDevice device = null;
private static final UUID BTMODULEUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private final static int REQUEST_ENABLE_BT = 1;
private final static int REQUEST_COARSE_LOCATION = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main4);
Button mEnable = (Button) findViewById(R.id.enable);
Button mOff = (Button) findViewById(R.id.off);
Button mPaired = (Button) findViewById(R.id.paired);
Button mDiscover = (Button) findViewById(R.id.discover);
deviceList = findViewById(R.id.deviceTitle);
deviceList.setText(null);
phoneName = findViewById(R.id.name);
phoneName.setText(getLocalBtName());
BA = BluetoothAdapter.getDefaultAdapter();
BAarray = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1);
BANewArray = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1);
DeviceList = (ListView)findViewById(R.id.deviceListView);
DeviceList.setAdapter(BAarray);
DeviceList.setOnItemClickListener(DeviceClickListener);
NewDevice = (ListView)findViewById(R.id.newDeviceView);
NewDevice.setAdapter(BANewArray);
NewDevice.setOnItemClickListener(DeviceClickListener);
if (BA == null) {
Toast.makeText(this, "Bluetooth not supported", Toast.LENGTH_SHORT).show();
finish();
} else {
mEnable.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bluetoothOn(v);
}
});
mOff.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bluetoothOff(v);
}
});
mPaired.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
checkLocationPermission();
listPairedDevices(v);
}
});
mDiscover.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
checkLocationPermission();
discover(v);
}
});
}
};
protected void checkLocationPermission() {
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_COARSE_LOCATION);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case REQUEST_COARSE_LOCATION: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//discover(view); // --->
} else {
//TODO re-request
}
break;
}
}
}
public String getLocalBtName(){
if(BA == null){
BA = BluetoothAdapter.getDefaultAdapter();
}
String name = BA.getName();
if(name == null){
name = BA.getAddress();
}
return name;
}
private void bluetoothOn(View view){
if(!BA.isEnabled()){
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
Toast.makeText(getApplicationContext(), "Bluetooth turned on", Toast.LENGTH_SHORT).show();
}
else{
Toast.makeText(getApplicationContext(), "Bluetooth is already on", Toast.LENGTH_SHORT).show();
}
}
private void bluetoothOff(View view){
BA.disable();
BAarray.clear();
Toast.makeText(getApplicationContext(), "Bluetooth turned off", Toast.LENGTH_SHORT).show();
}
private void discover(View view) {
deviceList.setText("Available Devices");
if (BA.isDiscovering()) {
BA.cancelDiscovery();
deviceList.setText(null);
BANewArray.clear();
Toast.makeText(getApplicationContext(), "Discovery stopped", Toast.LENGTH_SHORT).show();
}
else {
if (BA.isEnabled()) {
Intent discoverIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 50);
startActivity(discoverIntent);
BANewArray.clear();
BAarray.clear();
BA.startDiscovery();
Toast.makeText(getApplicationContext(), "Discovery started", Toast.LENGTH_SHORT).show();
registerReceiver(BReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
}
else {
Toast.makeText(getApplicationContext(), "Bluetooth not on", Toast.LENGTH_SHORT).show();
}
}
}
private final BroadcastReceiver BReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(BluetoothDevice.ACTION_FOUND.equals(action)){
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
BANewArray.add(device.getName() + "\n" + device.getAddress());
BANewArray.notifyDataSetChanged();
}
}
};
private void listPairedDevices(View view){
deviceList.setText("Previously Connected Devices");
pairedDevices = BA.getBondedDevices();
if(BA.isEnabled()){
BANewArray.clear();
BAarray.clear();
for(BluetoothDevice device : pairedDevices)
BAarray.add(device.getName() + "\n" + device.getAddress());
Toast.makeText(getApplicationContext(), "Show paired devices", Toast.LENGTH_SHORT).show();
}
else{
Toast.makeText(getApplicationContext(), "Bluetooth not on", Toast.LENGTH_SHORT).show();
}
}
private AdapterView.OnItemClickListener DeviceClickListener = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) {
if(!BA.isEnabled()) {
Toast.makeText(getBaseContext(), "Bluetooth not on", Toast.LENGTH_SHORT).show();
return;
}
String info = ((TextView) v).getText().toString();
final String address = info.substring(info.length() - 17);
final String name = info.substring(0,info.length() - 17);
new Thread() {
public void run() {
device = BA.getRemoteDevice(address);
try {
BTSocket = device.createRfcommSocketToServiceRecord(BTMODULEUUID);
} catch (IOException e) {
Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show();
}
// Establish the Bluetooth socket connection.
try {
BTSocket.connect();
} catch (IOException e) {
try {
BTSocket.close();
} catch (IOException e2) {
//insert code to deal with this
Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show();
}
}
}
public void cancel() {
try {
BTSocket.close();
} catch (IOException e3) {
Toast.makeText(getBaseContext(), "Could not close the client socket", Toast.LENGTH_SHORT).show();
}
}
}.start();
}
};
}
Below is the snippet of code related to connecting via bluetooth to another device:
private AdapterView.OnItemClickListener DeviceClickListener = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) {
if(!BA.isEnabled()) {
Toast.makeText(getBaseContext(), "Bluetooth not on", Toast.LENGTH_SHORT).show();
return;
}
String info = ((TextView) v).getText().toString();
final String address = info.substring(info.length() - 17);
final String name = info.substring(0,info.length() - 17);
new Thread() {
public void run() {
device = BA.getRemoteDevice(address);
try {
BTSocket = device.createRfcommSocketToServiceRecord(BTMODULEUUID);
// this is a test message
Toast.makeText(getBaseContext(), "test", Toast.LENGTH_SHORT).show();
} catch (IOException e) {
Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show();
}
// Establish the Bluetooth socket connection.
try {
BTSocket.connect();
} catch (IOException e) {
try {
BTSocket.close();
} catch (IOException e2) {
//insert code to deal with this
Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show();
}
}
}
public void cancel() {
try {
BTSocket.close();
} catch (IOException e3) {
Toast.makeText(getBaseContext(), "Could not close the client socket", Toast.LENGTH_SHORT).show();
}
}
}.start();
}
};
This line is my declaration of UUID
private static final UUID BTMODULEUUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
I am not sure where things are going wrong. Can anyone give me any advice please?
Here is the stacktrace for the app:
2021-02-07 01:08:52.055 14096-14096/? I/xample.Pillwoa: Late-enabling -Xcheck:jni
2021-02-07 01:08:52.108 14096-14096/? E/xample.Pillwoa: Unknown bits set in runtime_flags: 0x8000
2021-02-07 01:08:52.118 14096-14096/? W/xample.Pillwoa: Core platform API violation: Ljava/lang/reflect/Field;->accessFlags:I from Landroid/os/Build; using reflection
2021-02-07 01:08:52.680 14096-14096/com.example.Pillwoah W/xample.Pillwoa: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (greylist, reflection, allowed)
2021-02-07 01:08:52.682 14096-14096/com.example.Pillwoah W/xample.Pillwoa: Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (greylist, reflection, allowed)
2021-02-07 01:09:11.787 14096-14135/com.example.Pillwoah I/Adreno-EGL: <qeglDrvAPI_eglInitialize:379>: EGL 1.4 QUALCOMM build: Nondeterministic_AU_msm8974_LA.BF.1.1.3_RB1__release_AU (I741a3d36ca)
OpenGL ES Shader Compiler Version: E031.29.00.00
Build Date: 04/04/16 Mon
Local Branch: mybranch19053788
Remote Branch: quic/LA.BF.1.1.3_rb1.12
Local Patches: NONE
Reconstruct Branch: NOTHING
2021-02-07 01:09:11.803 14096-14135/com.example.Pillwoah W/Adreno-EGL: <qeglDrvAPI_eglGetConfigAttrib:607>: EGL_BAD_ATTRIBUTE
2021-02-07 01:09:11.816 14096-14135/com.example.Pillwoah W/Adreno-EGL: <qeglDrvAPI_eglGetConfigAttrib:607>: EGL_BAD_ATTRIBUTE
2021-02-07 01:09:11.883 14096-14135/com.example.Pillwoah W/Gralloc3: mapper 3.x is not supported
2021-02-07 01:09:13.306 14096-14096/com.example.Pillwoah W/ActivityThread: handleWindowVisibility: no activity for token android.os.BinderProxy@7040693
2021-02-07 01:09:13.543 14096-14135/com.example.Pillwoah W/Adreno-EGL: <qeglDrvAPI_eglGetConfigAttrib:607>: EGL_BAD_ATTRIBUTE
2021-02-07 01:09:16.076 14096-14096/com.example.Pillwoah W/ActivityThread: handleWindowVisibility: no activity for token android.os.BinderProxy@6df2233
2021-02-07 01:09:16.353 14096-14135/com.example.Pillwoah W/Adreno-EGL: <qeglDrvAPI_eglGetConfigAttrib:607>: EGL_BAD_ATTRIBUTE
2021-02-07 01:09:17.785 14096-14135/com.example.Pillwoah W/Adreno-EGL: <qeglDrvAPI_eglGetConfigAttrib:607>: EGL_BAD_ATTRIBUTE
2021-02-07 01:09:20.683 14096-14135/com.example.Pillwoah W/Adreno-EGL: <qeglDrvAPI_eglGetConfigAttrib:607>: EGL_BAD_ATTRIBUTE
2021-02-07 01:09:21.770 14096-14322/com.example.Pillwoah E/AndroidRuntime: FATAL EXCEPTION: Thread-2
Process: com.example.Pillwoah, PID: 14096
java.lang.RuntimeException: Can't toast on a thread that has not called Looper.prepare()
at android.widget.Toast$TN.<init>(Toast.java:410)
at android.widget.Toast.<init>(Toast.java:124)
at android.widget.Toast.makeText(Toast.java:289)
at android.widget.Toast.makeText(Toast.java:279)
at com.example.Pillwoah.MainActivity4$6$1.run(MainActivity4.java:233)
2021-02-07 01:09:21.938 14096-14322/com.example.Pillwoah I/Process: Sending signal. PID: 14096 SIG: 9
Here is the updated portion of the code:
private AdapterView.OnItemClickListener DeviceClickListener = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) {
if(!BA.isEnabled()) {
Toast.makeText(getBaseContext(), "Bluetooth not on", Toast.LENGTH_SHORT).show();
return;
}
String info = ((TextView) v).getText().toString();
final String address = info.substring(info.length() - 17);
final String name = info.substring(0,info.length() - 17);
new Thread() {
public void run() {
device = BA.getRemoteDevice(address);
try {
BTSocket = device.createRfcommSocketToServiceRecord(BTMODULEUUID);
getMainLooper().prepare();
Toast.makeText(getBaseContext(), "test", Toast.LENGTH_SHORT).show();
getMainLooper().loop();
} catch (IOException e) {
getMainLooper().prepare();
Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show();
getMainLooper().loop();
}
// Establish the Bluetooth socket connection.
try {
BTSocket.connect();
getMainLooper().prepare();
Toast.makeText(getBaseContext(), "test 2", Toast.LENGTH_SHORT).show();
getMainLooper().loop();
} catch (IOException e) {
try {
BTSocket.close();
getMainLooper().prepare();
Toast.makeText(getBaseContext(), "test 3", Toast.LENGTH_SHORT).show();
getMainLooper().loop();
} catch (IOException e2) {
//insert code to deal with this
getMainLooper().prepare();
Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show();
getMainLooper().loop();
}
}
}
public void cancel() {
try {
BTSocket.close();
} catch (IOException e3) {
getMainLooper().prepare();
Toast.makeText(getBaseContext(), "Could not close the client socket", Toast.LENGTH_SHORT).show();
getMainLooper().loop();
}
}
}.start();
}
};