0

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();
    }
};
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Romko Smuk
  • 57
  • 10
  • Tell us what happens when you run the code. (So far, you have only told us that it doesn't work. That's not going to help us help you.) – Stephen C Feb 07 '21 at 03:46
  • Well the app downloads on my phone and when I turn the Bluetooth on within the app the Bluetooth turns on. When I want a list of already paired devices the list is displayed. Also when I turn on the discoverability other Bluetooth devices show up on the list. When I click on the device from either list because I have 2 the above function is initiated but I am not able to connect to that device. Just nothing happens. – Romko Smuk Feb 07 '21 at 04:35
  • So ... you are not seeing any of those Toast message? And what would you expect to see if was working correctly? Can you show us the code that would make that observation. The code (as written) starts a thread to establish a connection, but there is nothing there to tell anything else *when* the connection has been established. – Stephen C Feb 07 '21 at 04:53
  • I am not seeing the toast messages from the above code. I am expecting the phone to be paired/connected to the desired Bluetooth device once it is selected. – Romko Smuk Feb 07 '21 at 05:16
  • Please answer these questions - *"And what would you expect to **see** if was working correctly? Can you show us **the code that would make that observation**. The code (as written) starts a thread to establish a connection, but there is nothing there to tell anything else when the connection has been established. "* – Stephen C Feb 07 '21 at 05:22
  • Also, note that you need to put all of this information into the Question. Use the [EDIT button](https://stackoverflow.com/posts/66083924/edit). – Stephen C Feb 07 '21 at 05:25
  • I added a toast message in the first try{ as shown above in code and what happens is the app crashes so maybe the issue is my UUID? – Romko Smuk Feb 07 '21 at 05:33
  • There is insufficient information to answer that. Please change the code to log the exceptions that occur, and then put the stacktrace into the question. When all of the information is **in the question** I will attempt to answer it. – Stephen C Feb 07 '21 at 05:35
  • I added the stacktrace – Romko Smuk Feb 07 '21 at 06:20
  • That stacktrace is no help. What we need to see is the stacktrace for the exception that caused you to caught prior to trying to make the toast; i.e. the one that describes the error that is (we assume) related to the cause of your problems. Read https://stackoverflow.com/questions/4341363/android-print-full-exception-backtrace-to-log – Stephen C Feb 07 '21 at 06:46

1 Answers1

0

After creating a handler in the main thread, the program creates a looper object, but the sub-thread does not. Therefore, you need to execute Looper.prepare() before using the Toast, and then execute Looper.loop(); after using the Toast.

 {
Looper.prepare();
Toast.makeText(getBaseContext(), "test", Toast.LENGTH_SHORT).show();
Looper.loop();
}
Sunshine
  • 61
  • 2
  • This addresses the (secondary) "why did the toast throw an exception" problem. I am **hoping** that the OP will figure out how to log the (apparent) original exception that he is catching and "toasting". – Stephen C Feb 07 '21 at 06:50
  • You can print the Bluetooth status (no connection, waiting to connect, connecting, connected) to see which step is wrong. – Sunshine Feb 07 '21 at 07:04
  • Put that all of that in the answer, not the comments. It is more readable. (Comments are for comments, not answers.) Use the [EDIT button](https://stackoverflow.com/posts/66085257/edit). – Stephen C Feb 07 '21 at 07:15
  • I was able to print out the "test" message after adding those looper changes which made the toasting work. @stephen Will using the log exception show anything different in the stackframe? Or is the stackframe configured differently where I wont be able to see the changes? – Romko Smuk Feb 07 '21 at 08:30
  • https://stackoverflow.com/questions/66096305/not-able-to-pair-a-bluetooth-device-in-android-studio I was able to post another question about the issues and I received an answer in this link. After modifying the code I was able to pair and connect to the device but since it uses only BLE implementation I had to rewrite the code – Romko Smuk Feb 18 '21 at 02:23