XYOracleNetwork/sdk-ble-android

View on GitHub
ble-android-library/src/main/kotlin/network/xyo/ble/generic/gatt/peripheral/XYBluetoothGattCallback.kt

Summary

Maintainability
F
3 days
Test Coverage
package network.xyo.ble.generic.gatt.peripheral

import android.annotation.TargetApi
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCallback
import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothGattDescriptor
import android.os.Build
import java.util.HashMap
import kotlinx.coroutines.launch
import network.xyo.base.XYBase

// This class is just a callback broadcast version of the standard BluetoothGattCallback

open class XYBluetoothGattCallback : BluetoothGattCallback() {
    private val gattListeners = HashMap<String, BluetoothGattCallback>()
    private val _lock = Any()

    fun addListener(key: String, listener: BluetoothGattCallback) {
        synchronized(_lock) {
            gattListeners[key] = listener
        }
    }

    fun removeListener(key: String) {
        synchronized(_lock) {
            gattListeners.remove(key)
        }
    }

    override fun onCharacteristicChanged(
        gatt: BluetoothGatt?,
        characteristic: BluetoothGattCharacteristic?
    ) {
        super.onCharacteristicChanged(gatt, characteristic)
        log.info("onCharacteristicChanged: $characteristic")

        // there is a possible race condition when getting the value from a characteristic that is
        // changing quickly, so there is a flag to change this. If blockNotificationCallback is set to true,
        // all of the notifications callbacks will be blocking, preventing the race condition
        // https://bugs.chromium.org/p/chromium/issues/detail?id=647673&desc=2
        synchronized(_lock) {
            for ((key, listener) in gattListeners) {
                log.info("onCharacteristicChanged: $key")
                if (blockNotificationCallback) {
                    listener.onCharacteristicChanged(gatt, characteristic)
                } else {
                    ble.launch {
                        listener.onCharacteristicChanged(gatt, characteristic)
                    }
                }
            }
        }
    }

    override fun onCharacteristicRead(
        gatt: BluetoothGatt?,
        characteristic: BluetoothGattCharacteristic?,
        status: Int
    ) {
        super.onCharacteristicRead(gatt, characteristic, status)
        log.info("onCharacteristicRead: $characteristic : $status")
        synchronized(_lock) {
            for ((_, listener) in gattListeners) {
                ble.launch {
                    listener.onCharacteristicRead(gatt, characteristic, status)
                }
            }
        }
    }

    override fun onCharacteristicWrite(
        gatt: BluetoothGatt?,
        characteristic: BluetoothGattCharacteristic?,
        status: Int
    ) {
        super.onCharacteristicWrite(gatt, characteristic, status)
        synchronized(_lock) {
            for ((_, listener) in gattListeners) {
                ble.launch {
                    listener.onCharacteristicWrite(gatt, characteristic, status)
                }
            }
        }
    }

    override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
        super.onConnectionStateChange(gatt, status, newState)
        synchronized(_lock) {
            for ((_, listener) in gattListeners) {
                ble.launch {
                    listener.onConnectionStateChange(gatt, status, newState)
                }
            }
        }
    }

    override fun onDescriptorRead(
        gatt: BluetoothGatt?,
        descriptor: BluetoothGattDescriptor?,
        status: Int
    ) {
        super.onDescriptorRead(gatt, descriptor, status)
        synchronized(_lock) {
            for ((_, listener) in gattListeners) {
                ble.launch {
                    listener.onDescriptorRead(gatt, descriptor, status)
                }
            }
        }
    }

    override fun onDescriptorWrite(
        gatt: BluetoothGatt?,
        descriptor: BluetoothGattDescriptor?,
        status: Int
    ) {
        super.onDescriptorWrite(gatt, descriptor, status)
        log.info("onDescriptorWrite: $descriptor : $status")
        synchronized(_lock) {
            for ((_, listener) in gattListeners) {
                ble.launch {
                    listener.onDescriptorWrite(gatt, descriptor, status)
                }
            }
        }
    }

    override fun onMtuChanged(gatt: BluetoothGatt?, mtu: Int, status: Int) {
        super.onMtuChanged(gatt, mtu, status)
        log.info("onMtuChanged: $mtu : $status")
        synchronized(_lock) {
            for ((_, listener) in gattListeners) {
                ble.launch {
                    listener.onMtuChanged(gatt, mtu, status)
                }
            }
        }
    }

    @TargetApi(Build.VERSION_CODES.O)
    override fun onPhyRead(gatt: BluetoothGatt?, txPhy: Int, rxPhy: Int, status: Int) {
        super.onPhyRead(gatt, txPhy, rxPhy, status)
        log.info("onPhyRead: $txPhy : $rxPhy : $status")

        synchronized(_lock) {
            for ((_, listener) in gattListeners) {
                ble.launch {
                    listener.onPhyRead(gatt, txPhy, rxPhy, status)
                }
            }
        }
    }

    @TargetApi(Build.VERSION_CODES.O)
    override fun onPhyUpdate(gatt: BluetoothGatt?, txPhy: Int, rxPhy: Int, status: Int) {
        super.onPhyUpdate(gatt, txPhy, rxPhy, status)
        log.info("onPhyUpdate: $txPhy : $rxPhy : $status")
        synchronized(_lock) {
            for ((_, listener) in gattListeners) {
                ble.launch {
                    listener.onPhyUpdate(gatt, txPhy, rxPhy, status)
                }
            }
        }
    }

    override fun onReadRemoteRssi(gatt: BluetoothGatt?, rssi: Int, status: Int) {
        super.onReadRemoteRssi(gatt, rssi, status)
        log.info("onReadRemoteRssi: $rssi : $status")
        // AT:this@XYBluetoothGatt.rssi = rssi
        // AT:onDetect(null)
        synchronized(_lock) {
            for ((_, listener) in gattListeners) {
                ble.launch {
                    listener.onReadRemoteRssi(gatt, rssi, status)
                }
            }
        }
    }

    override fun onReliableWriteCompleted(gatt: BluetoothGatt?, status: Int) {
        super.onReliableWriteCompleted(gatt, status)
        log.info("onReliableWriteCompleted: $status")
        synchronized(_lock) {
            for ((_, listener) in gattListeners) {
                ble.launch {
                    listener.onReliableWriteCompleted(gatt, status)
                }
            }
        }
    }

    override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
        super.onServicesDiscovered(gatt, status)
        log.info("onServicesDiscovered: $status")
        synchronized(_lock) {
            for ((_, listener) in gattListeners) {
                ble.launch {
                    listener.onServicesDiscovered(gatt, status)
                }
            }
        }
    }

    companion object : XYBase() {
        var blockNotificationCallback = false
    }
}