androidkotlin-coroutines

how to received the BroadcastReceiver message in suspendCancellableCoroutine


I wrote the below code for implement bond bluetooth device and obtain bluetooth device bond state, but I can't receive the BroadcastReceiver message, the Log.e("Bluetooth", "onReceive") never log!

@SuppressLint("MissingPermission")
suspend fun Context.obtainBluetoothDeviceBondState(): Boolean {
    return suspendCancellableCoroutine { continuation ->
        val receiver = object : BroadcastReceiver() {
            override fun onReceive(context: Context?, intent: Intent?) {
                Log.e("Bluetooth", "onReceive")
                if (BluetoothDevice.ACTION_BOND_STATE_CHANGED == intent?.action) {
                    val device = intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)
                    val bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE)
                    if (macAddress == device?.address) {
                        when (bondState) {
                            BluetoothDevice.BOND_BONDED -> {
                                Log.e("Bluetooth", "bond bluetooth device success")
                                unregisterReceiver(this)
                                continuation.resume(true)
                            }

                            BluetoothDevice.BOND_NONE -> {
                                Log.e("Bluetooth", "bond bluetooth device failed")
                                unregisterReceiver(this)
                                continuation.resume(false)
                            }
                        }
                    }
                }
            }
        }

        continuation.invokeOnCancellation {
            Log.e("Bluetooth", "unregisterReceiver")
            unregisterReceiver(receiver)
        }

        Log.e("Bluetooth", "registerReceiver")
        ContextCompat.registerReceiver(
            this, receiver, IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED), ContextCompat.RECEIVER_NOT_EXPORTED
        )

        val bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
        if (!bluetoothManager.adapter.bondBluetoothDevice(macAddress)) {
            continuation.resume(false)
        }
    }
}

@SuppressLint("MissingPermission")
fun BluetoothAdapter.bondBluetoothDevice(macAddress: String) = getRemoteDevice(macAddress).createBond()

The kotlin version is 1.9.24, the kotlin coroutine jvm version and the kotlin coroutine android version is just 1.6.4

I don't know why i don't receive BroadcastReceiver message. Could anyone have an idea?


Solution

  • To ensure your BroadcastReceiver can receive system events, register it using the ContextCompat.RECEIVER_EXPORTED flag instead of ContextCompat.RECEIVER_NOT_EXPORTED. This allows the receiver to listen for broadcasts from other apps and the Android system.

    use

    ContextCompat.registerReceiver(this, receiver, IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED), ContextCompat.RECEIVER_EXPORTED)
    

    instead of

    ContextCompat.registerReceiver(this, receiver, IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED), ContextCompat.RECEIVER_NOT_EXPORTED)