diff --git a/app/src/main/java/eu/darken/capod/common/bluetooth/BleScanner.kt b/app/src/main/java/eu/darken/capod/common/bluetooth/BleScanner.kt index ffadb4ba..bc1f931d 100644 --- a/app/src/main/java/eu/darken/capod/common/bluetooth/BleScanner.kt +++ b/app/src/main/java/eu/darken/capod/common/bluetooth/BleScanner.kt @@ -11,11 +11,15 @@ import eu.darken.capod.common.debug.autoreport.DebugSettings import eu.darken.capod.common.debug.logging.Logging.Priority.* import eu.darken.capod.common.debug.logging.log import eu.darken.capod.common.debug.logging.logTag +import eu.darken.capod.main.core.ScannerMode import eu.darken.capod.pods.core.apple.protocol.ProximityPairing import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.map +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch import javax.inject.Inject import javax.inject.Singleton @@ -28,7 +32,7 @@ class BleScanner @Inject constructor( fun scan( filter: Set = ProximityPairing.getBleScanFilter(), - mode: Int = ScanSettings.SCAN_MODE_LOW_LATENCY, + scannerMode: ScannerMode = ScannerMode.LOW_POWER, ): Flow> = callbackFlow { val adapter = bluetoothManager.adapter val scanner = bluetoothManager.scanner @@ -59,14 +63,36 @@ class BleScanner @Inject constructor( } val settings = ScanSettings.Builder().apply { - setScanMode(mode) + setScanMode( + when (scannerMode) { + ScannerMode.LOW_POWER -> ScanSettings.SCAN_MODE_LOW_POWER + ScannerMode.BALANCED -> ScanSettings.SCAN_MODE_BALANCED + ScannerMode.LOW_LATENCY -> ScanSettings.SCAN_MODE_LOW_LATENCY + } + ) if (adapter.isOffloadedScanBatchingSupported) { - setReportDelay(1000) + when (scannerMode) { + ScannerMode.LOW_POWER -> setReportDelay(5000) + ScannerMode.BALANCED -> setReportDelay(2500) + ScannerMode.LOW_LATENCY -> setReportDelay(500) + } } else { log(TAG, WARN) { "isOffloadedScanBatchingSupported=false" } } }.build() + val flushJob = launch { + while (isActive) { + // Can undercut the minimum setReportDelay(), e.g. 5000ms on a Pixel5@12 + adapter.bluetoothLeScanner.flushPendingScanResults(callback) + when (scannerMode) { + ScannerMode.LOW_POWER -> break + ScannerMode.BALANCED -> delay(2500) + ScannerMode.LOW_LATENCY -> delay(500) + } + } + } + if (adapter.isOffloadedFilteringSupported) { scanner.startScan(filter.toList(), settings, callback) log(TAG, VERBOSE) { "BleScanner started (filter=$filter, settings=$settings)" } @@ -77,8 +103,9 @@ class BleScanner @Inject constructor( } awaitClose { - log(TAG, INFO) { "BleScanner stopped" } + flushJob.cancel() scanner.stopScan(callback) + log(TAG, INFO) { "BleScanner stopped" } } } .map { origs -> diff --git a/app/src/main/java/eu/darken/capod/common/bluetooth/BluetoothManager2.kt b/app/src/main/java/eu/darken/capod/common/bluetooth/BluetoothManager2.kt index 47c6c69a..a8e5dd75 100644 --- a/app/src/main/java/eu/darken/capod/common/bluetooth/BluetoothManager2.kt +++ b/app/src/main/java/eu/darken/capod/common/bluetooth/BluetoothManager2.kt @@ -71,7 +71,7 @@ class BluetoothManager2 @Inject constructor( suspend fun getBluetoothProfile( profile: Int = BluetoothProfile.HEADSET ): BluetoothProfile2 = withContext(dispatcherProvider.IO) { - log(TAG) { "getBluetoothProfile(profile=$profile)" } + log(TAG, VERBOSE) { "getBluetoothProfile(profile=$profile)" } suspendCancellableCoroutine { val connectionState = AtomicBoolean(false) @@ -97,7 +97,7 @@ class BluetoothManager2 @Inject constructor( } private fun connectedDevicesForProfile(profile: Int): Flow> = callbackFlow { - log(TAG) { "connectedDevices(profile=$profile) starting" } + log(TAG, VERBOSE) { "connectedDevices(profile=$profile) starting" } trySend(getBluetoothProfile(profile).connectedDevices) val filter = IntentFilter().apply { diff --git a/app/src/main/java/eu/darken/capod/main/core/GeneralSettings.kt b/app/src/main/java/eu/darken/capod/main/core/GeneralSettings.kt index 09eef359..5812a757 100644 --- a/app/src/main/java/eu/darken/capod/main/core/GeneralSettings.kt +++ b/app/src/main/java/eu/darken/capod/main/core/GeneralSettings.kt @@ -29,7 +29,7 @@ class GeneralSettings @Inject constructor( val scannerMode = preferences.createFlowPreference( "core.scanner.mode", - ScannerMode.LOW_LATENCY, + ScannerMode.LOW_POWER, moshi ) diff --git a/app/src/main/java/eu/darken/capod/monitor/core/PodMonitor.kt b/app/src/main/java/eu/darken/capod/monitor/core/PodMonitor.kt index 4c2f2e0b..9a5897ad 100644 --- a/app/src/main/java/eu/darken/capod/monitor/core/PodMonitor.kt +++ b/app/src/main/java/eu/darken/capod/monitor/core/PodMonitor.kt @@ -1,6 +1,5 @@ package eu.darken.capod.monitor.core -import android.bluetooth.le.ScanSettings import eu.darken.capod.common.bluetooth.BleScanner import eu.darken.capod.common.bluetooth.BluetoothManager2 import eu.darken.capod.common.coroutine.AppScope @@ -10,7 +9,6 @@ import eu.darken.capod.common.debug.logging.log import eu.darken.capod.common.debug.logging.logTag import eu.darken.capod.common.flow.replayingShare import eu.darken.capod.main.core.GeneralSettings -import eu.darken.capod.main.core.ScannerMode import eu.darken.capod.pods.core.PodDevice import eu.darken.capod.pods.core.PodFactory import kotlinx.coroutines.CoroutineScope @@ -35,17 +33,10 @@ class PodMonitor @Inject constructor( private val cacheLock = Mutex() val devices: Flow> = generalSettings.scannerMode.flow - .flatMapLatest { - val mode = when (it) { - ScannerMode.LOW_POWER -> ScanSettings.SCAN_MODE_LOW_POWER - ScannerMode.BALANCED -> ScanSettings.SCAN_MODE_BALANCED - ScannerMode.LOW_LATENCY -> ScanSettings.SCAN_MODE_LOW_LATENCY - } + .flatMapLatest { scannerMode -> bluetoothManager.isBluetoothEnabled.flatMapLatest { isBluetoothEnabled -> if (isBluetoothEnabled) { - bleScanner.scan( - mode = mode - ) + bleScanner.scan(scannerMode = scannerMode) } else { log(TAG, WARN) { "Bluetooth is current disabled" } emptyFlow()