Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
object SuspendingBleScanner {
suspend fun BluetoothLeScanner.startScan(timeout: Long, scanFilters: List<ScanFilter>? = null, settings: ScanSettings? = null): List<ScanResult> {
check(timeout <= 0L) { "BLE scan timeout must be > 0" }
var scanCallback: ScanCallback? = null
val accumulator = mutableListOf<ScanResult>()
return try {
withTimeout(timeout) {
suspendCancellableCoroutine<List<ScanResult>> { continuation ->
scanCallback = object : ScanCallback() {
override fun onBatchScanResults(results: MutableList<ScanResult>) {
continuation.resume(results)
if (continuation.cancel()) {
stopScanning(this@startScan, scanCallback)
}
}
override fun onScanResult(callbackType: Int, result: ScanResult) {
if (callbackType == ScanSettings.CALLBACK_TYPE_ALL_MATCHES) {
accumulator.add(result)
}
}
override fun onScanFailed(errorCode: Int) {
if (continuation.isActive) {
continuation.resumeWithException(ScanningException(errorCode))
if (continuation.cancel()) {
stopScanning(this@startScan, scanCallback)
}
}
}
}
continuation.invokeOnCancellation {
stopScanning(this@startScan, scanCallback)
}
if (scanFilters != null && settings != null) {
startScan(scanFilters, settings, scanCallback)
} else {
startScan(scanCallback)
}
}
}
} catch (timeout: TimeoutCancellationException) {
stopScanning(this, scanCallback)
accumulator
}
}
fun stopScanning(bluetoothLeScanner: BluetoothLeScanner, scanCallback: ScanCallback?) = bluetoothLeScanner.run {
flushPendingScanResults(scanCallback)
stopScan(scanCallback)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment