Companion Device Manager

Native Android ==> Bluetooth module

For devices running at least Android 8.0 it is possible to scan for a BluetoothPeripheral using the OS Companion Device Manager. The Companion Device Manager will scan for BluetoothDevices that match a BluetoothPeripheral and allow the end user to select the desired BluetoothDevice from a System presented dialog. More information on the Companion Device Manager can be found in Android documentation here and here.

val deviceFilter: BluetoothLeDeviceFilter = BluetoothLeDeviceFilter.Builder()
  // Match only Bluetooth devices whose name matches the pattern.
  .setNamePattern(bluetoothPeripheral.regexPattern)
  // Match only Bluetooth devices whose service UUID matches this pattern.
  .addServiceUuid(ParcelUuid(bluetoothPeripheral.getBroadcastingService()))
  .build()

val pairingRequest: AssociationRequest = AssociationRequest.Builder()
  // Find only devices that match this request filter.
  .addDeviceFilter(deviceFilter)
  // Stop scanning as soon as one device matching the filter is found.
  .setSingleDevice(true)
  .build()

val deviceManager =
  requireContext().getSystemService(Context.COMPANION_DEVICE_SERVICE)

deviceManager.associate(pairingRequest,
  object : CompanionDeviceManager.Callback() {
    // Called when a device is found. Launch the IntentSender so the user
    // can select the device they want to pair with.
    override fun onDeviceFound(chooserLauncher: IntentSender) {
      startIntentSenderForResult(
        chooserLauncher,
        SELECT_DEVICE_REQUEST_CODE, null, 0, 0, 0
      )
    }

    override fun onFailure(error: CharSequence?) {
      // Handle the failure.
    }
  },
  null
)

To collect the device that the end user has selected override your activity's onActivityResult. After collected enqueue a PairRequest or ReadRequest with the selected BluetoothDevice and BluetoothPeripheral

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
  when (requestCode) {
    SELECT_DEVICE_REQUEST_CODE -> when (resultCode) {
      Activity.RESULT_OK -> {
        // The user chose to pair the app with a Bluetooth device.
        val scanResult: ScanResult? =
          data?.getParcelableExtra(CompanionDeviceManager.EXTRA_DEVICE)
        val device: BluetoothDevice = scanResult?.bluetoothDevice
        viewLifecycleScope.launch {
          try {
            val pairResult = PairRequest(bluetoothPeripheral, device).enqueue()
            Log.i("Bluetooth", "Pair Success with $device.address")
          } catch (e: ValidicBluetoothExceptiion) {
            Log.e("Bluetooth", e)
          }
        }
      }
      else -> super.onActivityResult(requestCode, resultCode, data)
    }
  }

Special Considerations

Most supported Bluetooth devices function similarly and you can follow the instructions on this page to work with them using Companion Device Manager.

However, a few of our supported devices have additional requirements and/or considerations that you need to be aware of. Those are covered in Bluetooth Behavior.