fix(ble): implement scanning for unbonded devices in common connections ui (#4779)

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
James Rich 2026-03-13 11:33:30 -05:00 committed by GitHub
parent afe1356430
commit 5cc1e94a13
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 83 additions and 10 deletions

View file

@ -22,15 +22,24 @@ import no.nordicsemi.kotlin.ble.client.android.CentralManager
import no.nordicsemi.kotlin.ble.client.distinctByPeripheral
import org.koin.core.annotation.Single
import kotlin.time.Duration
import kotlin.uuid.ExperimentalUuidApi
import kotlin.uuid.Uuid
/**
* An Android implementation of [BleScanner] using Nordic's [CentralManager].
*
* @param centralManager The Nordic [CentralManager] to use for scanning.
*/
@OptIn(ExperimentalUuidApi::class)
@Single
class AndroidBleScanner(private val centralManager: CentralManager) : BleScanner {
override fun scan(timeout: Duration): Flow<BleDevice> =
centralManager.scan(timeout).distinctByPeripheral().map { AndroidBleDevice(it.peripheral) }
override fun scan(timeout: Duration, serviceUuid: Uuid?): Flow<BleDevice> = centralManager
.scan(timeout = timeout) {
if (serviceUuid != null) {
ServiceUuid(serviceUuid)
}
}
.distinctByPeripheral()
.map { AndroidBleDevice(it.peripheral) }
}

View file

@ -27,5 +27,5 @@ interface BleScanner {
* @param timeout The duration of the scan.
* @return A [Flow] of discovered [BleDevice]s.
*/
fun scan(timeout: Duration): Flow<BleDevice>
fun scan(timeout: Duration, serviceUuid: kotlin.uuid.Uuid? = null): Flow<BleDevice>
}

View file

@ -45,7 +45,7 @@ class BleScannerTest {
fun `scan returns peripherals`() = runTest(testDispatcher) {
val mockEnvironment = MockAndroidEnvironment.Api31(isBluetoothEnabled = true)
val centralManager = CentralManager.mock(mockEnvironment, backgroundScope)
val scanner = BleScanner(centralManager)
val scanner = AndroidBleScanner(centralManager)
val peripheral =
PeripheralSpec.simulatePeripheral(
@ -70,7 +70,7 @@ class BleScannerTest {
fun `scan with filter returns only matching peripherals`() = runTest(testDispatcher) {
val mockEnvironment = MockAndroidEnvironment.Api31(isBluetoothEnabled = true)
val centralManager = CentralManager.mock(mockEnvironment, backgroundScope)
val scanner = BleScanner(centralManager)
val scanner = AndroidBleScanner(centralManager)
val targetUuid = Uuid.parse("4FAFC201-1FB5-459E-8FCC-C5C9C331914B")
@ -92,7 +92,7 @@ class BleScannerTest {
centralManager.simulatePeripherals(listOf(matchingPeripheral, nonMatchingPeripheral))
val scannedDevices = mutableListOf<no.nordicsemi.kotlin.ble.client.android.Peripheral>()
val job = launch { scanner.scan(5.seconds) { ServiceUuid(targetUuid) }.toList(scannedDevices) }
val job = launch { scanner.scan(5.seconds, targetUuid).toList(scannedDevices) }
// Needs time to scan in mock environment
advanceUntilIdle()