Skip to content

Commit 499ad9d

Browse files
authored
Monitor bluetooth state before initiating connection (#580)
1 parent cb1a773 commit 499ad9d

2 files changed

Lines changed: 27 additions & 21 deletions

File tree

core/src/androidMain/kotlin/BluetoothDeviceAndroidPeripheral.kt

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,20 @@ import com.juul.kable.logs.Logging.DataProcessor.Operation
3434
import com.juul.kable.logs.detail
3535
import kotlinx.coroutines.CoroutineName
3636
import kotlinx.coroutines.CoroutineScope
37+
import kotlinx.coroutines.CoroutineStart.UNDISPATCHED
38+
import kotlinx.coroutines.Job
3739
import kotlinx.coroutines.SupervisorJob
3840
import kotlinx.coroutines.flow.Flow
3941
import kotlinx.coroutines.flow.MutableStateFlow
4042
import kotlinx.coroutines.flow.StateFlow
4143
import kotlinx.coroutines.flow.asStateFlow
44+
import kotlinx.coroutines.flow.collect
4245
import kotlinx.coroutines.flow.filter
4346
import kotlinx.coroutines.flow.launchIn
4447
import kotlinx.coroutines.flow.onEach
4548
import kotlinx.coroutines.flow.update
4649
import kotlinx.coroutines.job
50+
import kotlinx.coroutines.launch
4751
import kotlinx.coroutines.withContext
4852
import kotlin.coroutines.CoroutineContext
4953
import kotlin.coroutines.cancellation.CancellationException
@@ -106,6 +110,7 @@ internal class BluetoothDeviceAndroidPeripheral(
106110

107111
private suspend fun establishConnection(scope: CoroutineScope) {
108112
checkBluetoothAdapterState(expected = STATE_ON)
113+
bluetoothState.watchForDisablingIn(scope)
109114

110115
logger.info { message = "Connecting" }
111116
_state.value = State.Connecting.Bluetooth
@@ -141,21 +146,21 @@ internal class BluetoothDeviceAndroidPeripheral(
141146
logger.info { message = "Connected" }
142147
_state.value = State.Connected
143148

144-
bluetoothState.watchForDisablingIn(scope)
145149
state.watchForConnectionLossIn(scope)
146150
}
147151

148-
private fun Flow<Int>.watchForDisablingIn(scope: CoroutineScope) =
149-
filter { state -> state == STATE_TURNING_OFF || state == STATE_OFF }
150-
.onEach { state ->
151-
logger.debug {
152-
message = "Bluetooth disabled"
153-
detail("state", state)
152+
private fun Flow<Int>.watchForDisablingIn(scope: CoroutineScope): Job =
153+
scope.launch(start = UNDISPATCHED) {
154+
filter { state -> state == STATE_TURNING_OFF || state == STATE_OFF }
155+
.collect { state ->
156+
logger.debug {
157+
message = "Bluetooth disabled"
158+
detail("state", state)
159+
}
160+
closeConnection()
161+
throw BluetoothDisabledException()
154162
}
155-
closeConnection()
156-
throw BluetoothDisabledException()
157-
}
158-
.launchIn(scope)
163+
}
159164

160165
private fun Flow<State>.watchForConnectionLossIn(scope: CoroutineScope) =
161166
state

core/src/appleMain/kotlin/CBPeripheralCoreBluetoothPeripheral.kt

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ internal class CBPeripheralCoreBluetoothPeripheral(
138138
private suspend fun establishConnection(scope: CoroutineScope) {
139139
// Check CBCentral State since connecting can result in an API misuse message.
140140
centralManager.checkBluetoothState(CBManagerStatePoweredOn)
141+
centralManager.delegate.state.watchForDisablingIn(scope)
141142

142143
logger.info { message = "Connecting" }
143144
_state.value = State.Connecting.Bluetooth
@@ -169,21 +170,21 @@ internal class CBPeripheralCoreBluetoothPeripheral(
169170
logger.info { message = "Connected" }
170171
_state.value = State.Connected
171172

172-
centralManager.delegate.state.watchForDisablingIn(scope)
173173
centralManager.delegate.onDisconnected.watchForConnectionLossIn(scope)
174174
}
175175

176176
private fun Flow<CBManagerState>.watchForDisablingIn(scope: CoroutineScope) =
177-
filter { state -> state != CBManagerStatePoweredOn }
178-
.onEach { state ->
179-
logger.info {
180-
message = "Bluetooth unavailable"
181-
detail("state", state)
177+
scope.launch(start = UNDISPATCHED) {
178+
filter { state -> state != CBManagerStatePoweredOn }
179+
.collect { state ->
180+
logger.info {
181+
message = "Bluetooth unavailable"
182+
detail("state", state)
183+
}
184+
closeConnection()
185+
throw ConnectionLostException("$this $state")
182186
}
183-
closeConnection()
184-
throw ConnectionLostException("$this $state")
185-
}
186-
.launchIn(scope)
187+
}
187188

188189
private fun Flow<NSUUID>.watchForConnectionLossIn(scope: CoroutineScope) =
189190
filter { identifier -> identifier == cbPeripheral.identifier }

0 commit comments

Comments
 (0)