Improve error handling and disconnection events (#60)

* Improve Android error handling

* Improve cleanup after disconnection on Apple

* Update changelog
This commit is contained in:
Foti Dim
2024-07-05 11:02:33 +02:00
committed by GitHub
parent 0070f5c002
commit 9cd2faee66
5 changed files with 85 additions and 30 deletions
@@ -298,14 +298,14 @@ fun Short.toByteArray(byteOrder: ByteOrder = ByteOrder.LITTLE_ENDIAN): ByteArray
fun unknownCharacteristicError(char: String) =
FlutterError("IllegalArgument", "Unknown error", null)
// Future result classes
class BleCharacteristicFuture(
val deviceId: String,
val characteristicId: String,
val serviceId: String,
val result: (Result<ByteArray>) -> Unit,
val DeviceDisconnectedError: FlutterError = FlutterError(
"DeviceDisconnected",
"Device Disconnected",
null
)
// Future result classes
class DiscoverServicesFuture(
val deviceId: String,
val result: (Result<List<UniversalBleService>>) -> Unit,
@@ -316,6 +316,13 @@ class MtuResultFuture(
val result: (Result<Long>) -> Unit,
)
class ReadResultFuture(
val deviceId: String,
val characteristicId: String,
val serviceId: String,
val result: (Result<ByteArray>) -> Unit,
)
class WriteResultFuture(
val deviceId: String,
val characteristicId: String,
@@ -323,7 +330,7 @@ class WriteResultFuture(
val result: (Result<Unit>) -> Unit,
)
class CharacteristicSubscriptionFuture(
class SubscriptionResultFuture(
val deviceId: String,
val characteristicId: String,
val serviceId: String,
@@ -37,12 +37,11 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
private lateinit var context: Context
private var activity: Activity? = null
private lateinit var bluetoothManager: BluetoothManager
private val mtuResultFutureList = mutableListOf<MtuResultFuture>()
private val bleCharacteristicFutureList = mutableListOf<BleCharacteristicFuture>()
private val discoverServicesFutureList = mutableListOf<DiscoverServicesFuture>()
private val characteristicSubscriptionFutureList =
mutableListOf<CharacteristicSubscriptionFuture>()
private val mtuResultFutureList = mutableListOf<MtuResultFuture>()
private val readResultFutureList = mutableListOf<ReadResultFuture>()
private val writeResultFutureList = mutableListOf<WriteResultFuture>()
private val subscriptionResultFutureList = mutableListOf<SubscriptionResultFuture>()
private val cachedServicesMap = mutableMapOf<String, List<String>>()
private val devicesStateMap = mutableMapOf<String, Int>()
private var bluetoothEnableRequestFuture: ((Result<Boolean>) -> Unit)? = null
@@ -240,8 +239,8 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
)
if (gatt.setNotifiable(gattCharacteristic, bleInputProperty)) {
characteristicSubscriptionFutureList.add(
CharacteristicSubscriptionFuture(
subscriptionResultFutureList.add(
SubscriptionResultFuture(
gatt.device.address,
gattCharacteristic.uuid.toString(),
gattCharacteristic.service.uuid.toString(),
@@ -296,8 +295,8 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
return
}
bleCharacteristicFutureList.add(
BleCharacteristicFuture(
readResultFutureList.add(
ReadResultFuture(
gatt.device.address,
gattCharacteristic.uuid.toString(),
gattCharacteristic.service.uuid.toString(),
@@ -325,12 +324,12 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
value: ByteArray,
status: Int,
) {
bleCharacteristicFutureList.filter {
readResultFutureList.filter {
it.deviceId == gatt.device.address &&
it.characteristicId == characteristic.uuid.toString() &&
it.serviceId == characteristic.service.uuid.toString()
}.forEach {
bleCharacteristicFutureList.remove(it)
readResultFutureList.remove(it)
if (status == BluetoothGatt.GATT_SUCCESS) {
it.result(Result.success(value))
} else {
@@ -641,14 +640,45 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
private fun cleanConnection(gatt: BluetoothGatt) {
knownGatts.remove(gatt)
gatt.disconnect()
bleCharacteristicFutureList.removeAll {
it.deviceId == gatt.device.address
readResultFutureList.removeAll {
if (it.deviceId == gatt.device.address) {
it.result(Result.failure(DeviceDisconnectedError))
true
} else {
false
}
}
writeResultFutureList.removeAll {
if (it.deviceId == gatt.device.address) {
it.result(Result.failure(DeviceDisconnectedError))
true
} else {
false
}
}
subscriptionResultFutureList.removeAll {
if (it.deviceId == gatt.device.address) {
it.result(Result.failure(DeviceDisconnectedError))
true
} else {
false
}
}
mtuResultFutureList.removeAll {
it.deviceId == gatt.device.address
if (it.deviceId == gatt.device.address) {
it.result(Result.failure(DeviceDisconnectedError))
true
} else {
false
}
}
discoverServicesFutureList.removeAll {
it.deviceId == gatt.device.address
if (it.deviceId == gatt.device.address) {
it.result(Result.failure(DeviceDisconnectedError))
true
} else {
false
}
}
}
@@ -752,10 +782,7 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
devicesStateMap[gatt.device.address] = newState
if (status != BluetoothGatt.GATT_SUCCESS) {
Log.e(TAG, "Failed to update connected state: $status")
return
}
Log.d(TAG, "onConnectionStateChange-> Status: ${status}, NewState: $newState")
if (newState == BluetoothGatt.STATE_CONNECTED) {
mainThreadHandler?.post {
@@ -771,8 +798,6 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
) {}
}
}
}
override fun onCharacteristicChanged(
@@ -811,12 +836,12 @@ class UniversalBlePlugin : UniversalBlePlatformChannel, BluetoothGattCallback(),
service: String,
status: Int,
) {
characteristicSubscriptionFutureList.filter {
subscriptionResultFutureList.filter {
it.deviceId == deviceId &&
it.characteristicId == characteristic &&
it.serviceId == service
}.forEach {
characteristicSubscriptionFutureList.remove(it)
subscriptionResultFutureList.remove(it)
val error: String? = status.parseGattErrorCode()
if (error != null) {
it.result(