bluetoothLeScaner.startScan(scanCallback) isnt returning null

26 Views Asked by At

I am attempting to connect my phone to a bluetooth device. I am using an android 13 . In my scandevices file, I am coming across an issue on this line bluetoothLeScaner.startScan(scanCallback). I am getting that IllegalArgumentException: callback is null.

Menifest.xml

<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />

build.gradle:


android {
    namespace 'com.example.sensor'
    compileSdk 34

    kotlinOptions {
        jvmTarget = '17'
    }

    defaultConfig {
        applicationId "com.example.sensor"
        minSdk 31
        targetSdk 33 //33
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        vectorDrawables {
            useSupportLibrary true
        }
    }

stack trace

2024-03-12 13:36:00.288 25335-25335 PERMISSIONS             com.example.sensor                   D  Permission already granted: android.permission.BLUETOOTH
2024-03-12 13:36:00.289 25335-25335 PERMISSIONS             com.example.sensor                   D  Permission already granted: android.permission.BLUETOOTH_CONNECT
2024-03-12 13:36:00.290 25335-25335 PERMISSIONS             com.example.sensor                   D  Permission already granted: android.permission.ACCESS_COARSE_LOCATION
2024-03-12 13:36:00.290 25335-25335 PERMISSIONS             com.example.sensor                   D  Permission already granted: android.permission.ACCESS_FINE_LOCATION
2024-03-12 13:36:00.292 25335-25335 PERMISSIONS             com.example.sensor                   D  Permission already granted: android.permission.BLUETOOTH_ADMIN
2024-03-12 13:36:00.293 25335-25335 PERMISSIONS             com.example.sensor                   D  Permission already granted: android.permission.BLUETOOTH_SCAN
2024-03-12 13:36:00.294 25335-25335 PERMISSIONS             com.example.sensor                   D  Permission already granted: android.permission.BLUETOOTH_ADVERTISE
2024-03-12 13:36:00.294 25335-25335 PERMISSIONS             com.example.sensor                   D  All permissions are already granted


2024-03-12 13:36:00.299 25335-25335 BluetoothAdapter        com.example.sensor                   I  STATE_ON
2024-03-12 13:36:00.300 25335-25335 AndroidRuntime          com.example.sensor                   D  Shutting down VM
2024-03-12 13:36:00.304 25335-25335 AndroidRuntime          com.example.sensor                   E  FATAL EXCEPTION: main
                                                                                                    Process: com.example.sensor, PID: 25335
                                                                                                    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.sensor/com.example.sensor.MainActivity}: java.lang.IllegalArgumentException: callback is null
                                                                                                        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4169)
                                                                                                        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4325)
                                                                                                        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:101)
                                                                                                        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
                                                                                                        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
                                                                                                        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2574)
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:106)
                                                                                                        at android.os.Looper.loopOnce(Looper.java:226)
                                                                                                        at android.os.Looper.loop(Looper.java:313)
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:8779)
                                                                                                        at java.lang.reflect.Method.invoke(Native Method)
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:604)
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)
                                                                                                    Caused by: java.lang.IllegalArgumentException: callback is null
                                                                                                        at android.bluetooth.le.BluetoothLeScanner.startScan(BluetoothLeScanner.java:136)
                                                                                                        at com.example.sensor.data.ble.ScanDevices.run(ScanDevices.kt:40)
                                                                                                        at com.example.sensor.data.ble.ScanDevices.<init>(ScanDevices.kt:35)
                                                                                                        at com.example.sensor.MainActivity.onCreate(MainActivity.kt:62)
                                                                                                        at android.app.Activity.performCreate(Activity.java:8591)
                                                                                                        at android.app.Activity.performCreate(Activity.java:8570)
                                                                                                        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1384)
                                                                                                        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:4150)
                                                                                                        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4325) 
                                                                                                        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:101) 
                                                                                                        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
                                                                                                        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
                                                                                                        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2574) 
                                                                                                        at android.os.Handler.dispatchMessage(Handler.java:106) 
                                                                                                        at android.os.Looper.loopOnce(Looper.java:226) 
                                                                                                        at android.os.Looper.loop(Looper.java:313) 
                                                                                                        at android.app.ActivityThread.main(ActivityThread.java:8779) 
                                                                                                        at java.lang.reflect.Method.invoke(Native Method) 
                                                                                                        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:604) 
                                                                                                        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067) 
2024-03-12 13:36:00.334 25335-25335 Process                 com.example.sensor                   I  Sending signal. PID: 25335 SIG: 9

scandevice.kt


@SuppressLint("MissingPermission")

class ScanDevices(
    var bluetoothAdapter: BluetoothAdapter,
    val context: Context

):Thread() {
    val DEVICE_NAME = "WHEELSERV"
    private var isScanning = false
    private var bluetoothLeScaner = bluetoothAdapter.bluetoothLeScanner
    private var device: BluetoothDevice? = null
    private val latch = CountDownLatch(1);

    init {
            run()
    }

    override fun run() {
        bluetoothLeScaner.startScan(scanCallback)
        isScanning = true
        latch.await()
        val socket = device?.createL2capChannel(0)
        try {
            socket?.connect()
            Log.d("CREATION", "yay connected ")
        } catch (e: IOException) {
            println("didnt connect to device")

        }
    }

    val scanCallback = object : ScanCallback() {
        override fun onScanResult(
            callbackType: Int,
            result: ScanResult
        ) {
            super.onScanResult(callbackType, result)
            if (result.device.name == DEVICE_NAME) {//filter
                if (isScanning) {
                    isScanning = false
                    //bluetoothLeScaner.stopScan(scanCallback)
                    bluetoothAdapter.cancelDiscovery()
                    device = result.device
                    latch.countDown()
                }
            }
        }

    }
}

When debugging the code, I can see that bluetoothLeScanner is non-null. So then, I thought maybe it is an issue with permissions, so I tested it out in my MainActivity.kt. As you can see on the stack-trace and xml file, all permissions are setup, requested, and granted. I ran out of ideas on what the issue might be and would appreciate some advice on what I should test next.

1

There are 1 best solutions below

0
Michael On

In kotlin, init blocks and property initializers are executed in the order in which they appear.

We can illustrate this with the following simple example:

class Test : Thread() {
    init {
        run()
    }

    override fun run() {
        callback.onScanFailed(ScanCallback.SCAN_FAILED_INTERNAL_ERROR)
    }

    private val callback = object: ScanCallback() {
    }
}

Which is equivalent to the following Java code:

public final class Test extends Thread {
   private final ScanCallback callback;

   public void run() {
      this.callback.onScanFailed(ScanCallback.SCAN_FAILED_INTERNAL_ERROR);
   }

   public Test() {
      this.run();
      this.callback = new ScanCallback() {
      };
   }
}

As you can see, the callback is initialized after the call to run. So it's entirely possible to end up with a null callback when startScan is called in your case.

If you changed the code around like so:

class Test : Thread() {
    private val callback = object: ScanCallback() {
    }
    
    init {
        run()
    }

    override fun run() {
        callback.onScanFailed(ScanCallback.SCAN_FAILED_INTERNAL_ERROR)
    }
}

you'd instead get this:

public final class Test extends Thread {
   private final ScanCallback callback = new ScanCallback() {
   };

   public void run() {
      this.callback.onScanFailed(ScanCallback.SCAN_FAILED_INTERNAL_ERROR);
   }

   public Test() {
      this.run();
   }
}

which should work.

Although I'm not entirely sure why you see the need to spawn a new thread for the scanner(?). That seems unnecessary to me.