Skip to content

Commit

Permalink
fix(android): fix concurrency issue in timeoutmap(#419)
Browse files Browse the repository at this point in the history
  • Loading branch information
Anders Hausding committed Aug 8, 2023
1 parent 948c887 commit f4f5064
Showing 1 changed file with 29 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.capacitorjs.community.plugins.bluetoothle

import android.annotation.SuppressLint
import android.bluetooth.*
import android.content.BroadcastReceiver
import android.content.Context
Expand All @@ -10,12 +11,32 @@ import android.os.Handler
import android.os.Looper
import com.getcapacitor.Logger
import java.util.*
import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.atomic.AtomicReference

class CallbackResponse(
val success: Boolean,
val value: String,
)

class WriteTimeout(
val key: String,
val handler: Handler
)

fun <T> ConcurrentLinkedQueue<T>.popFirstMatch(predicate: (T) -> Boolean): T? {
val removed = AtomicReference<T>()
this.removeIf { item ->
if (removed.get() == null && predicate(item)) {
removed.set(item)
true
} else {
false
}
}
return removed.get()
}

class Device(
private val context: Context,
bluetoothAdapter: BluetoothAdapter,
Expand All @@ -35,7 +56,7 @@ class Device(
private var device: BluetoothDevice = bluetoothAdapter.getRemoteDevice(address)
private var bluetoothGatt: BluetoothGatt? = null
private var callbackMap = HashMap<String, ((CallbackResponse) -> Unit)>()
private var timeoutMap = HashMap<String, Handler>()
private val timeoutQueue = ConcurrentLinkedQueue<WriteTimeout>()
private var bondStateReceiver: BroadcastReceiver? = null
private var currentMtu = -1

Expand Down Expand Up @@ -120,7 +141,7 @@ class Device(
super.onCharacteristicWrite(gatt, characteristic, status)
val key = "write|${characteristic.service.uuid}|${characteristic.uuid}"
if (status == BluetoothGatt.GATT_SUCCESS) {
resolve(key, "Characteristic successfully written.")
resolve(key, "Characteristic successfully written.")// ${characteristic.value.toHex()}")
} else {
reject(key, "Writing characteristic failed.")
}
Expand Down Expand Up @@ -395,7 +416,7 @@ class Device(
reject(key, "Writing characteristic failed.")
return
}
setTimeout(key, "Write timeout.", timeout)
setTimeout(key, "Write timeout. for $value", timeout)
}

fun setNotifications(
Expand Down Expand Up @@ -510,28 +531,27 @@ class Device(
private fun resolve(key: String, value: String) {
if (callbackMap.containsKey(key)) {
Logger.debug(TAG, "resolve: $key $value")

timeoutQueue.popFirstMatch { it.key == key }?.handler?.removeCallbacksAndMessages(null)
callbackMap[key]?.invoke(CallbackResponse(true, value))
callbackMap.remove(key)
timeoutMap[key]?.removeCallbacksAndMessages(null)
timeoutMap.remove(key)
}
}

private fun reject(key: String, value: String) {
if (callbackMap.containsKey(key)) {
Logger.debug(TAG, "reject: $key $value")
timeoutQueue.popFirstMatch { it.key == key }?.handler?.removeCallbacksAndMessages(null)
callbackMap[key]?.invoke(CallbackResponse(false, value))
callbackMap.remove(key)
timeoutMap[key]?.removeCallbacksAndMessages(null)
timeoutMap.remove(key)
}
}

private fun setTimeout(
key: String, message: String, timeout: Long
) {
val handler = Handler(Looper.getMainLooper())
timeoutMap[key] = handler
timeoutQueue.add(WriteTimeout(key, handler))
handler.postDelayed({
reject(key, message)
}, timeout)
Expand All @@ -544,7 +564,7 @@ class Device(
timeout: Long,
) {
val handler = Handler(Looper.getMainLooper())
timeoutMap[key] = handler
timeoutQueue.add(WriteTimeout(key, handler))
handler.postDelayed({
connectionState = STATE_DISCONNECTED
gatt?.disconnect()
Expand Down

0 comments on commit f4f5064

Please sign in to comment.