@@ -93,12 +93,11 @@ class BleScannerHelper(
93
93
return callbackFlow {
94
94
val services = mutableSetOf<BluetoothGattService >()
95
95
val device = requireAdapter().getRemoteDevice(address)
96
+ var gatt: BluetoothGatt ? = null
96
97
97
98
val callback = object : BluetoothGattCallback () {
98
99
override fun onServicesDiscovered (gatt : BluetoothGatt , status : Int ) {
99
100
super .onServicesDiscovered(gatt, status)
100
- connections.put(gatt.device.address, gatt)
101
-
102
101
if (status == BluetoothGatt .GATT_SUCCESS ) {
103
102
Timber .tag(TAG_CONNECT ).d(" Services discovered. ${gatt.services.size} services for device $address " )
104
103
services.addAll(gatt.services.orEmpty())
@@ -129,49 +128,81 @@ class BleScannerHelper(
129
128
}
130
129
}
131
130
132
- override fun onConnectionStateChange (gatt : BluetoothGatt ? , status : Int , newState : Int ) {
131
+ override fun onConnectionStateChange (gatt : BluetoothGatt , status : Int , newState : Int ) {
133
132
super .onConnectionStateChange(gatt, status, newState)
134
133
checkStatus(newState, gatt, status)
135
134
}
136
135
137
- private fun checkStatus (newState : Int , gatt : BluetoothGatt ? , status : Int ) {
136
+ private fun checkStatus (newState : Int , gatt : BluetoothGatt , status : Int ) {
137
+ connections[address] = gatt
138
138
when (newState) {
139
139
BluetoothProfile .STATE_CONNECTING -> {
140
140
Timber .tag(TAG_CONNECT ).d(" Connecting to device $address " )
141
141
trySend(DeviceConnectResult .Connecting )
142
142
}
143
143
BluetoothProfile .STATE_CONNECTED -> {
144
144
Timber .tag(TAG_CONNECT ).d(" Connected to device $address " )
145
- trySend(DeviceConnectResult .Connected (gatt!! ))
145
+ trySend(DeviceConnectResult .Connected (gatt))
146
146
}
147
147
BluetoothProfile .STATE_DISCONNECTING -> {
148
148
Timber .tag(TAG_CONNECT ).d(" Disconnecting from device $address " )
149
149
trySend(DeviceConnectResult .Disconnecting )
150
+ gatt.close()
150
151
}
151
152
BluetoothProfile .STATE_DISCONNECTED -> {
152
153
Timber .tag(TAG_CONNECT ).d(" Disconnected from device $address " )
153
- if (status == 0x85 ) {
154
- Timber .tag(TAG_CONNECT ).e(" Error while connecting to device $address . Error code: $status " )
155
- trySend(DeviceConnectResult .MaxGattConnectionsReached )
156
- } else {
157
- trySend(DeviceConnectResult .Disconnected )
158
- }
154
+ handleDisconnect(status, gatt)
155
+ }
156
+ else -> {
157
+ Timber .tag(TAG_CONNECT ).e(" Error while connecting to device $address . Error code: $status " )
158
+ trySend(DeviceConnectResult .DisconnectedWithError .UnspecifiedConnectionError (gatt, status))
159
+ }
160
+ }
161
+ }
162
+
163
+ private fun handleDisconnect (status : Int , gatt : BluetoothGatt ) {
164
+ when (status) {
165
+ BluetoothGatt .GATT_SUCCESS -> {
166
+ trySend(DeviceConnectResult .Disconnected )
167
+ }
168
+ CONNECTION_FAILED_TO_ESTABLISH -> {
169
+ Timber .tag(TAG_CONNECT ).e(" Error while connecting to device $address . Error code: $status " )
170
+ trySend(DeviceConnectResult .DisconnectedWithError .ConnectionFailedToEstablish (gatt, status))
171
+ }
172
+ CONNECTION_FAILED_BEFORE_INITIALIZING -> {
173
+ Timber .tag(TAG_CONNECT ).e(" Error while connecting to device $address . Error code: $status " )
174
+ trySend(DeviceConnectResult .DisconnectedWithError .ConnectionFailedBeforeInitializing (gatt, status))
175
+ }
176
+ CONNECTION_TERMINATED -> {
177
+ Timber .tag(TAG_CONNECT ).e(" Error while connecting to device $address . Error code: $status " )
178
+ trySend(DeviceConnectResult .DisconnectedWithError .ConnectionTerminated (gatt, status))
179
+ }
180
+ BluetoothGatt .GATT_CONNECTION_TIMEOUT -> {
181
+ Timber .tag(TAG_CONNECT ).e(" Error while connecting to device $address . Error code: $status " )
182
+ trySend(DeviceConnectResult .DisconnectedWithError .ConnectionTimeout (gatt, status))
183
+ }
184
+ BluetoothGatt .GATT_FAILURE -> {
185
+ Timber .tag(TAG_CONNECT ).e(" Error while connecting to device $address . Error code: $status " )
186
+ trySend(DeviceConnectResult .DisconnectedWithError .ConnectionFailedTooManyClients (gatt, status))
159
187
}
160
188
else -> {
161
189
Timber .tag(TAG_CONNECT ).e(" Error while connecting to device $address . Error code: $status " )
162
- trySend(DeviceConnectResult .DisconnectedWithError (status))
163
- false
190
+ trySend(DeviceConnectResult .DisconnectedWithError .UnspecifiedConnectionError (gatt, status))
164
191
}
165
192
}
166
193
}
167
194
}
168
195
169
196
Timber .tag(TAG_CONNECT ).d(" Connecting to device $address " )
170
- connections[address] = device.connectGatt(appContext, false , callback)
197
+ gatt = device.connectGatt(appContext, false , callback, BluetoothDevice . TRANSPORT_LE )
171
198
172
199
awaitClose {
173
200
Timber .tag(TAG_CONNECT ).d(" Closing connection to device $address " )
174
- closeDeviceConnection(address)
201
+ if (requireBluetoothManager().getConnectionState(device, BluetoothProfile .GATT ) != BluetoothProfile .STATE_DISCONNECTED ) {
202
+ gatt.disconnect()
203
+ } else {
204
+ gatt.close()
205
+ }
175
206
}
176
207
}
177
208
}
@@ -229,8 +260,17 @@ class BleScannerHelper(
229
260
data class Connected (val gatt : BluetoothGatt ) : DeviceConnectResult
230
261
data object Disconnecting : DeviceConnectResult
231
262
data object Disconnected : DeviceConnectResult
232
- data class DisconnectedWithError (val errorCode : Int ) : DeviceConnectResult
233
- data object MaxGattConnectionsReached : DeviceConnectResult
263
+ sealed interface DisconnectedWithError : DeviceConnectResult {
264
+ val errorCode: Int
265
+ val gatt: BluetoothGatt
266
+
267
+ class UnspecifiedConnectionError (override val gatt : BluetoothGatt , override val errorCode : Int ) : DisconnectedWithError
268
+ class ConnectionTimeout (override val gatt : BluetoothGatt , override val errorCode : Int ) : DisconnectedWithError
269
+ class ConnectionTerminated (override val gatt : BluetoothGatt , override val errorCode : Int ) : DisconnectedWithError
270
+ class ConnectionFailedToEstablish (override val gatt : BluetoothGatt , override val errorCode : Int ) : DisconnectedWithError
271
+ class ConnectionFailedBeforeInitializing (override val gatt : BluetoothGatt , override val errorCode : Int ) : DisconnectedWithError
272
+ class ConnectionFailedTooManyClients (override val gatt : BluetoothGatt , override val errorCode : Int ) : DisconnectedWithError
273
+ }
234
274
}
235
275
236
276
fun isBluetoothEnabled (): Boolean {
@@ -306,10 +346,14 @@ class BleScannerHelper(
306
346
}
307
347
308
348
private fun tryToInitBluetoothScanner () {
309
- bluetoothAdapter = appContext.getSystemService( BluetoothManager :: class .java ).adapter
349
+ bluetoothAdapter = requireBluetoothManager( ).adapter
310
350
bluetoothScanner = bluetoothAdapter?.bluetoothLeScanner
311
351
}
312
352
353
+ private fun requireBluetoothManager (): BluetoothManager {
354
+ return appContext.getSystemService(BluetoothManager ::class .java)
355
+ }
356
+
313
357
private fun requireScanner (): BluetoothLeScanner {
314
358
if (bluetoothScanner == null ) {
315
359
tryToInitBluetoothScanner()
@@ -346,5 +390,8 @@ class BleScannerHelper(
346
390
companion object {
347
391
private const val TAG = " BleScannerHelper"
348
392
private const val TAG_CONNECT = " BleScannerHelperConnect"
393
+ private const val CONNECTION_FAILED_BEFORE_INITIALIZING = 0x85
394
+ private const val CONNECTION_FAILED_TO_ESTABLISH = 0x3E
395
+ private const val CONNECTION_TERMINATED = 0x16
349
396
}
350
397
}
0 commit comments