CompanionDeviceManager instability in Android

515 Views Asked by At

Did anyone have a successful experience on working with CompanionDeviceManager on Android? Especially, with the devices with Bluetooth Classic support. I've been testing a pretty simple app which tries to connect some device using Bluetooth Classic and I keep getting different strange errors. The problems I'm facing:

  • The internals of CompanionDeviceManager can crash with some nullpointer
  • The API uses onActivityResult mechanism and often I just get this callback with unsuccessful result (!Activity.RESULT_OK)
  • But most importantly, it takes way too long to discover a device

So, am I doing something wrong? Or this API is quite unstable?

2

There are 2 best solutions below

0
On

Make sure that your bluetooth device filter is of type BluetoothDeviceFilter, which is for Bluetooth Classic devices, unlike BluetoothLeDeviceFilter which is for Bluetooth Low Energy devices.

Code sample:

   val companionDeviceManager = context.getSystemService(CompanionDeviceManager::class.java)

    val classicBluetoothDeviceFilter = BluetoothDeviceFilter.Builder()
                .build()

    val leBluetoothDeviceFilter = BluetoothLeDeviceFilter.Builder()
                .build()

    val pairingRequest = AssociationRequest.Builder()
        .addDeviceFilter(classicBluetoothDeviceFilter)
        .addDeviceFilter(leBluetoothDeviceFilter)
        .build()

    bluetoothObserver?.onFindingDevice()

    companionDeviceManager?.associate(
        pairingRequest,
        object : CompanionDeviceManager.Callback() {/* callbacks here */},
        Handler(Looper.getMainLooper())
    )

Then when you attempt to check if the device is paired/unpaired via ActivityResult API, do note that you'll be receiving Parcelable Extra of type ScanResult when it's a Bluetooth LE device, and a Parcelable Extra of type BluetoothDevice when it's a Bluetooth Classic device:

 registerForActivityResult(
        ActivityResultContracts.StartIntentSenderForResult()
    ) { activityResult ->
        if (activityResult.resultCode == Activity.RESULT_OK) {
            val leBluetoothDevice = IntentCompat.getParcelableExtra(activityResult.data ?: Intent(), CompanionDeviceManager.EXTRA_DEVICE, ScanResult::class.java)
            val classicBluetoothDevice = IntentCompat.getParcelableExtra(activityResult.data ?: Intent(), CompanionDeviceManager.EXTRA_DEVICE, BluetoothDevice::class.java)
            val bluetoothDevice = leBluetoothDevice?.device ?: classicBluetoothDevice

            if (bluetoothDevice?.bondState == BluetoothDevice.BOND_BONDED) {
                // device is paired and can be connected
            } else {
                // device is not paired, start pairing process
            }

        }
    }
0
On

Yes, Companion Device Pairing can be made to work reliably on BLE devices -- at least as reliably as the alternative pairing (BLE bonding) mechanisms on Android, which have their own issues. The Starfield watch app uses this to pair Android phones with the watch.

I am not surprised that this is not as well tested on Bluetooth Classic, as it appears to be designed for Bluetooth LE watches in particular. For your specific issues, you would need to post code so that we can help with specifics.