I have been trying to build an Android App with the capability of connecting to a bluetooth device called ESP32 on BLE mode. I have found some posts helping me in these regards but I also have to debug lots of stuff. I ask runtime permissions on first start of my App so I don't know why this part of Code for some reason produces this error?
MyBtEngine.java:
package com.example.myapplication;
import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.util.Log;
import androidx.core.app.ActivityCompat;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
public class MyBtEngine {
static final int BT_STATE_NONE = 0;
static final int BT_STATE_CONNECTING = 1;
static final int BT_STATE_CONNECTED = 2;
//uid for all 3rd party devices (not android)
private static final UUID UUID_BT_DEVICE = UUID.fromString("55072829-bc9e-4c53-938a-74a6d4c78776");
private static final String BT_DEVICE_MAC = "78:E3:6D:09:63:38";//put your device MAC !!!!
private Context cont;
private BtWaitConnThread mWaitConnThread = null;
private BtWorkThread mWorkThread = null;
private final BluetoothAdapter mAdapter;
private int mState;
MyBtEngine(Context context) {
mAdapter = BluetoothAdapter.getDefaultAdapter();
mState = BT_STATE_NONE;
cont = context;
}
synchronized void start() throws IOException {
if (mAdapter == null) {
return;
}
BluetoothDevice device;
try {
device = mAdapter.getRemoteDevice(BT_DEVICE_MAC);
} catch (Exception e) {
return;
}
if (mWaitConnThread != null) {
mWaitConnThread.cancel();
mWaitConnThread = null;
}
if (mWorkThread != null) {
mWorkThread.cancel();
mWorkThread = null;
}
mWaitConnThread = new BtWaitConnThread(device);
mWaitConnThread.start();
setState(BT_STATE_CONNECTING);
}
public synchronized void stop() {
if (mWaitConnThread != null) {
mWaitConnThread.cancel();
mWaitConnThread = null;
}
if (mWorkThread != null) {
mWorkThread.cancel();
mWorkThread = null;
}
setState(BT_STATE_NONE);
}
private synchronized void setState(int state) {
Log.e("MyBtEngine", "setState() " + mState + " -> " + state);
mState = state;
}
synchronized int getState() {
return mState;
}
public boolean writeBt(byte[] out) {
BtWorkThread r; // temp obj , just to keep write function not to destroyed if mWorkThread finish
synchronized (this) {
if ((mWorkThread == null) || (mState != BT_STATE_CONNECTED)) {
return false;
}
r = mWorkThread;
}
r.write(out);
return true;
}
private synchronized void startWorker(BluetoothSocket socket, BluetoothDevice device) {
if (mWaitConnThread != null) {
mWaitConnThread.cancel();
mWaitConnThread = null;
}
if (mWorkThread != null) {
mWorkThread.cancel();
mWorkThread = null;
}
mWorkThread = new BtWorkThread(socket);
mWorkThread.start();
setState(BT_STATE_CONNECTED);
}
private class BtWaitConnThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
private BtWaitConnThread(BluetoothDevice device) throws IOException {
mmDevice = device;
BluetoothSocket tmp = null;
if (ActivityCompat.checkSelfPermission(cont,
Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
new PermissionCheck().checkPermission(cont);
}
}
tmp = device.createRfcommSocketToServiceRecord(UUID_BT_DEVICE);
mmSocket = tmp;
}
public void run() {
if (ActivityCompat.checkSelfPermission(cont,
Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
new PermissionCheck().checkPermission(cont);
}
}
mAdapter.cancelDiscovery();
try {
mmSocket.connect();
} catch (IOException e) {
try {
mmSocket.close();
} catch (IOException e2) { }
setState(BT_STATE_NONE);
return;
}
synchronized (MyBtEngine.this) {
mWaitConnThread = null;//set itself to null because thread exit soon
}
startWorker(mmSocket, mmDevice);
}
private void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
private class BtWorkThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
private BtWorkThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
while (true) {
try {
int charFromEsp = mmInStream.read();//TODO: add code here for handling input from ESP
} catch (IOException e) {
try {
MyBtEngine.this.start();//restart from beginning
} catch (IOException ex) {
ex.printStackTrace();
}
return; // exit worker thread
}
}
}
public boolean write(byte[] buffer) {
try {
mmOutStream.write(buffer);
} catch (IOException e) { return false; }
return true;
}
private void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
public int returnState(){
return mState;
}
}
causing the error:
java.lang.SecurityException: Need android.permission.BLUETOOTH_SCAN permission for android.content.AttributionSource@efdade4f: AdapterService cancelDiscovery
at android.os.Parcel.createExceptionOrNull(Parcel.java:2456)
at android.os.Parcel.createException(Parcel.java:2440)
at android.os.Parcel.readException(Parcel.java:2423)
at android.os.Parcel.readException(Parcel.java:2365)
at android.bluetooth.IBluetooth$Stub$Proxy.cancelDiscovery(IBluetooth.java:3247)
at android.bluetooth.BluetoothAdapter.cancelDiscovery(BluetoothAdapter.java:1874)
at com.example.myapplication.MyBtEngine$BtWaitConnThread.run(MyBtEngine.java:135)
It seems to happen on line 135 which is the line where my Adapter is trying to connect for the first time
I tried asking for the permissions for the one part, where it didn't connecting yet. But it doesn't even ask for it of course in other words its alreay permitted. still it throws this exact issue!