feat: 5.0.0 (#35)
* draft: 临时提交 * feat: 实现扫描功能 * fix: 优化广播逻辑 * feat: 添加协程方法 * fix: 修改宏定义 * draft: 临时提交 * feat: 调整接口 * fix: 修改版本号 * feat: 4.1.1 * draft: 临时提交 * feat: 5.0.0-dev.2 * fix: 修复版本号错误 * draft: 临时提交 * fix: 修复连接断开异常 * fix: 修复问题 * fix: 优化代码 * fix: 优化 short UUID 格式化逻辑 * fix: 尝试实现 read_rssi 接口,当前此接口不可用,会报异常 * feat: 删除 getMaximumWriteLength 方法 * fix: 更新 CHANGELOG.md * feat: 5.0.0-dev.1 * fix: 更新依赖项 * feat: linux-5.0.0-dev.1 * fix: 更新 CHANGELOG.md * fix: 开始搜索设备时清空设备列表 * fix: 开始扫描时清空设备列表 * feat: 5.0.0-dev.2 * fix: 优化 MyGattService 和 MyGattCharacteristic * feat: 更新 interface 版本 -> 5.0.0-dev.4 * feat: 更新 interface 版本 -> 5.0.0-dev.4 * feat: 实现 flutter 部分 5.0.0 * fix: 移除 maximumWriteLength * fix: 移除 rssi * feat: 5.0.0-dev.1 * feat: 5.0.0-dev.2 * fix: 更新依赖项 * fix: 5.0.0-dev.4 * fix: 更新依赖项 * draft: 临时提交 * feat: 5.0.0-dev.5 * draft: 删除 MyCentralManager 和 MyPeripheralManager * fix: 更新依赖项 * fix: 更新依赖项 * feat: 适配新接口 * feat: 5.0.0-dev.6 * draft: 临时提交 * feat: 5.0.0-dev.7 * fix: 修改版本号 * feat: 5.0.0-dev.8 * feat: 5.0.0-dev.9 * fix: 修复 trimGATT 错误 * feat: 5.0.0-dev.6 * feat: 5.0.0-dev.3 * feat: 5.0.0-dev.4 * fix: 更新 pubspec.lock * feat: 5.0.0-dev.7 * feat: 5.0.0-dev.3 * fix: balabala * fix: balabala * draft: 5.0.0-dev.1 * fix: trim GATT when call the `writeCharacteristic` method. * fix: make difference of `trim` and `fragment`. * feat: 5.0.0-dev.1 * feat: 5.0.0-dev.1 * feat: 优化示例程序 * fix: 更新 README.md * fix: 修复插件引用 * draft: XXXX * feat: 增加调试信息 * fix: 更新 pubspec.lock * feat: 5.0.0-dev.4 * feat: 5.0.0-dev.3 * feat: 5.0.0 * feat: 5.0.0 * feat: 5.0.0 * feat: 5.0.0 * feat: 5.0.0 * feat: 5.0.0
This commit is contained in:
@ -6,16 +6,16 @@ import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
|
||||
|
||||
/** BluetoothLowEnergyAndroid */
|
||||
class BluetoothLowEnergyAndroid : FlutterPlugin, ActivityAware {
|
||||
private lateinit var centralManager: MyCentralManager
|
||||
private lateinit var peripheralManager: MyPeripheralManager
|
||||
private lateinit var mCentralManager: MyCentralManager
|
||||
private lateinit var mPeripheralManager: MyPeripheralManager
|
||||
|
||||
override fun onAttachedToEngine(binding: FlutterPlugin.FlutterPluginBinding) {
|
||||
val context = binding.applicationContext
|
||||
val binaryMessenger = binding.binaryMessenger
|
||||
centralManager = MyCentralManager(context, binaryMessenger)
|
||||
peripheralManager = MyPeripheralManager(context, binaryMessenger)
|
||||
MyCentralManagerHostApi.setUp(binaryMessenger, centralManager)
|
||||
MyPeripheralManagerHostApi.setUp(binaryMessenger, peripheralManager)
|
||||
mCentralManager = MyCentralManager(context, binaryMessenger)
|
||||
mPeripheralManager = MyPeripheralManager(context, binaryMessenger)
|
||||
MyCentralManagerHostApi.setUp(binaryMessenger, mCentralManager)
|
||||
MyPeripheralManagerHostApi.setUp(binaryMessenger, mPeripheralManager)
|
||||
}
|
||||
|
||||
override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
|
||||
@ -25,13 +25,13 @@ class BluetoothLowEnergyAndroid : FlutterPlugin, ActivityAware {
|
||||
}
|
||||
|
||||
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
|
||||
centralManager.onAttachedToActivity(binding)
|
||||
peripheralManager.onAttachedToActivity(binding)
|
||||
mCentralManager.onAttachedToActivity(binding)
|
||||
mPeripheralManager.onAttachedToActivity(binding)
|
||||
}
|
||||
|
||||
override fun onDetachedFromActivity() {
|
||||
centralManager.onDetachedFromActivity()
|
||||
peripheralManager.onDetachedFromActivity()
|
||||
mCentralManager.onDetachedFromActivity()
|
||||
mPeripheralManager.onDetachedFromActivity()
|
||||
}
|
||||
|
||||
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
|
||||
|
@ -3,14 +3,20 @@ package dev.yanshouwang.bluetooth_low_energy_android
|
||||
import android.bluetooth.le.AdvertiseCallback
|
||||
import android.bluetooth.le.AdvertiseSettings
|
||||
|
||||
class MyAdvertiseCallback(private val peripheralManager: MyPeripheralManager) : AdvertiseCallback() {
|
||||
class MyAdvertiseCallback(manager: MyPeripheralManager) : AdvertiseCallback() {
|
||||
private val mManager: MyPeripheralManager
|
||||
|
||||
init {
|
||||
mManager = manager
|
||||
}
|
||||
|
||||
override fun onStartSuccess(settingsInEffect: AdvertiseSettings) {
|
||||
super.onStartSuccess(settingsInEffect)
|
||||
peripheralManager.onStartSuccess(settingsInEffect)
|
||||
mManager.onStartSuccess(settingsInEffect)
|
||||
}
|
||||
|
||||
override fun onStartFailure(errorCode: Int) {
|
||||
super.onStartFailure(errorCode)
|
||||
peripheralManager.onStartFailure(errorCode)
|
||||
mManager.onStartFailure(errorCode)
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// Autogenerated from Pigeon (v12.0.1), do not edit directly.
|
||||
// Autogenerated from Pigeon (v15.0.2), do not edit directly.
|
||||
// See also: https://pub.dev/packages/pigeon
|
||||
|
||||
package dev.yanshouwang.bluetooth_low_energy_android
|
||||
@ -31,6 +31,9 @@ private fun wrapError(exception: Throwable): List<Any?> {
|
||||
}
|
||||
}
|
||||
|
||||
private fun createConnectionError(channelName: String): FlutterError {
|
||||
return FlutterError("channel-error", "Unable to establish connection on channel: '$channelName'.", "")}
|
||||
|
||||
/**
|
||||
* Error class for passing custom error details to Flutter via a thrown PlatformException.
|
||||
* @property code The error code.
|
||||
@ -82,84 +85,55 @@ enum class MyGattCharacteristicWriteTypeArgs(val raw: Int) {
|
||||
}
|
||||
}
|
||||
|
||||
/** Generated class from Pigeon that represents data sent in messages. */
|
||||
data class MyCentralManagerArgs (
|
||||
val stateNumberArgs: Long
|
||||
enum class MyGattCharacteristicNotifyStateArgs(val raw: Int) {
|
||||
NONE(0),
|
||||
NOTIFY(1),
|
||||
INDICATE(2);
|
||||
|
||||
) {
|
||||
companion object {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun fromList(list: List<Any?>): MyCentralManagerArgs {
|
||||
val stateNumberArgs = list[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
return MyCentralManagerArgs(stateNumberArgs)
|
||||
fun ofRaw(raw: Int): MyGattCharacteristicNotifyStateArgs? {
|
||||
return values().firstOrNull { it.raw == raw }
|
||||
}
|
||||
}
|
||||
fun toList(): List<Any?> {
|
||||
return listOf<Any?>(
|
||||
stateNumberArgs,
|
||||
)
|
||||
}
|
||||
|
||||
enum class MyGattStatusArgs(val raw: Int) {
|
||||
SUCCESS(0),
|
||||
READNOTPERMITTED(1),
|
||||
WRITENOTPERMITTED(2),
|
||||
REQUESTNOTSUPPORTED(3),
|
||||
INVALIDOFFSET(4),
|
||||
INSUFFICIENTAUTHENTICATION(5),
|
||||
INSUFFICIENTENCRYPTION(6),
|
||||
INVALIDATTRIBUTELENGTH(7),
|
||||
CONNECTIONCONGESTED(8),
|
||||
FAILURE(9);
|
||||
|
||||
companion object {
|
||||
fun ofRaw(raw: Int): MyGattStatusArgs? {
|
||||
return values().firstOrNull { it.raw == raw }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Generated class from Pigeon that represents data sent in messages. */
|
||||
data class MyPeripheralManagerArgs (
|
||||
val stateNumberArgs: Long
|
||||
data class MyManufacturerSpecificDataArgs (
|
||||
val idArgs: Long,
|
||||
val dataArgs: ByteArray
|
||||
|
||||
) {
|
||||
companion object {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun fromList(list: List<Any?>): MyPeripheralManagerArgs {
|
||||
val stateNumberArgs = list[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
return MyPeripheralManagerArgs(stateNumberArgs)
|
||||
fun fromList(list: List<Any?>): MyManufacturerSpecificDataArgs {
|
||||
val idArgs = list[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
val dataArgs = list[1] as ByteArray
|
||||
return MyManufacturerSpecificDataArgs(idArgs, dataArgs)
|
||||
}
|
||||
}
|
||||
fun toList(): List<Any?> {
|
||||
return listOf<Any?>(
|
||||
stateNumberArgs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Generated class from Pigeon that represents data sent in messages. */
|
||||
data class MyCentralArgs (
|
||||
val hashCodeArgs: Long,
|
||||
val uuidArgs: String
|
||||
|
||||
) {
|
||||
companion object {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun fromList(list: List<Any?>): MyCentralArgs {
|
||||
val hashCodeArgs = list[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
val uuidArgs = list[1] as String
|
||||
return MyCentralArgs(hashCodeArgs, uuidArgs)
|
||||
}
|
||||
}
|
||||
fun toList(): List<Any?> {
|
||||
return listOf<Any?>(
|
||||
hashCodeArgs,
|
||||
uuidArgs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Generated class from Pigeon that represents data sent in messages. */
|
||||
data class MyPeripheralArgs (
|
||||
val hashCodeArgs: Long,
|
||||
val uuidArgs: String
|
||||
|
||||
) {
|
||||
companion object {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun fromList(list: List<Any?>): MyPeripheralArgs {
|
||||
val hashCodeArgs = list[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
val uuidArgs = list[1] as String
|
||||
return MyPeripheralArgs(hashCodeArgs, uuidArgs)
|
||||
}
|
||||
}
|
||||
fun toList(): List<Any?> {
|
||||
return listOf<Any?>(
|
||||
hashCodeArgs,
|
||||
uuidArgs,
|
||||
idArgs,
|
||||
dataArgs,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -195,48 +169,64 @@ data class MyAdvertisementArgs (
|
||||
}
|
||||
|
||||
/** Generated class from Pigeon that represents data sent in messages. */
|
||||
data class MyManufacturerSpecificDataArgs (
|
||||
val idArgs: Long,
|
||||
val dataArgs: ByteArray
|
||||
data class MyCentralArgs (
|
||||
val addressArgs: String
|
||||
|
||||
) {
|
||||
companion object {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun fromList(list: List<Any?>): MyManufacturerSpecificDataArgs {
|
||||
val idArgs = list[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
val dataArgs = list[1] as ByteArray
|
||||
return MyManufacturerSpecificDataArgs(idArgs, dataArgs)
|
||||
fun fromList(list: List<Any?>): MyCentralArgs {
|
||||
val addressArgs = list[0] as String
|
||||
return MyCentralArgs(addressArgs)
|
||||
}
|
||||
}
|
||||
fun toList(): List<Any?> {
|
||||
return listOf<Any?>(
|
||||
idArgs,
|
||||
dataArgs,
|
||||
addressArgs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Generated class from Pigeon that represents data sent in messages. */
|
||||
data class MyGattServiceArgs (
|
||||
val hashCodeArgs: Long,
|
||||
val uuidArgs: String,
|
||||
val characteristicsArgs: List<MyGattCharacteristicArgs?>
|
||||
data class MyPeripheralArgs (
|
||||
val addressArgs: String
|
||||
|
||||
) {
|
||||
companion object {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun fromList(list: List<Any?>): MyGattServiceArgs {
|
||||
fun fromList(list: List<Any?>): MyPeripheralArgs {
|
||||
val addressArgs = list[0] as String
|
||||
return MyPeripheralArgs(addressArgs)
|
||||
}
|
||||
}
|
||||
fun toList(): List<Any?> {
|
||||
return listOf<Any?>(
|
||||
addressArgs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Generated class from Pigeon that represents data sent in messages. */
|
||||
data class MyGattDescriptorArgs (
|
||||
val hashCodeArgs: Long,
|
||||
val uuidArgs: String,
|
||||
val valueArgs: ByteArray? = null
|
||||
|
||||
) {
|
||||
companion object {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun fromList(list: List<Any?>): MyGattDescriptorArgs {
|
||||
val hashCodeArgs = list[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
val uuidArgs = list[1] as String
|
||||
val characteristicsArgs = list[2] as List<MyGattCharacteristicArgs?>
|
||||
return MyGattServiceArgs(hashCodeArgs, uuidArgs, characteristicsArgs)
|
||||
val valueArgs = list[2] as ByteArray?
|
||||
return MyGattDescriptorArgs(hashCodeArgs, uuidArgs, valueArgs)
|
||||
}
|
||||
}
|
||||
fun toList(): List<Any?> {
|
||||
return listOf<Any?>(
|
||||
hashCodeArgs,
|
||||
uuidArgs,
|
||||
characteristicsArgs,
|
||||
valueArgs,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -270,26 +260,26 @@ data class MyGattCharacteristicArgs (
|
||||
}
|
||||
|
||||
/** Generated class from Pigeon that represents data sent in messages. */
|
||||
data class MyGattDescriptorArgs (
|
||||
data class MyGattServiceArgs (
|
||||
val hashCodeArgs: Long,
|
||||
val uuidArgs: String,
|
||||
val valueArgs: ByteArray? = null
|
||||
val characteristicsArgs: List<MyGattCharacteristicArgs?>
|
||||
|
||||
) {
|
||||
companion object {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun fromList(list: List<Any?>): MyGattDescriptorArgs {
|
||||
fun fromList(list: List<Any?>): MyGattServiceArgs {
|
||||
val hashCodeArgs = list[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
val uuidArgs = list[1] as String
|
||||
val valueArgs = list[2] as ByteArray?
|
||||
return MyGattDescriptorArgs(hashCodeArgs, uuidArgs, valueArgs)
|
||||
val characteristicsArgs = list[2] as List<MyGattCharacteristicArgs?>
|
||||
return MyGattServiceArgs(hashCodeArgs, uuidArgs, characteristicsArgs)
|
||||
}
|
||||
}
|
||||
fun toList(): List<Any?> {
|
||||
return listOf<Any?>(
|
||||
hashCodeArgs,
|
||||
uuidArgs,
|
||||
valueArgs,
|
||||
characteristicsArgs,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -300,20 +290,15 @@ private object MyCentralManagerHostApiCodec : StandardMessageCodec() {
|
||||
return when (type) {
|
||||
128.toByte() -> {
|
||||
return (readValue(buffer) as? List<Any?>)?.let {
|
||||
MyCentralManagerArgs.fromList(it)
|
||||
MyGattCharacteristicArgs.fromList(it)
|
||||
}
|
||||
}
|
||||
129.toByte() -> {
|
||||
return (readValue(buffer) as? List<Any?>)?.let {
|
||||
MyGattCharacteristicArgs.fromList(it)
|
||||
}
|
||||
}
|
||||
130.toByte() -> {
|
||||
return (readValue(buffer) as? List<Any?>)?.let {
|
||||
MyGattDescriptorArgs.fromList(it)
|
||||
}
|
||||
}
|
||||
131.toByte() -> {
|
||||
130.toByte() -> {
|
||||
return (readValue(buffer) as? List<Any?>)?.let {
|
||||
MyGattServiceArgs.fromList(it)
|
||||
}
|
||||
@ -323,20 +308,16 @@ private object MyCentralManagerHostApiCodec : StandardMessageCodec() {
|
||||
}
|
||||
override fun writeValue(stream: ByteArrayOutputStream, value: Any?) {
|
||||
when (value) {
|
||||
is MyCentralManagerArgs -> {
|
||||
is MyGattCharacteristicArgs -> {
|
||||
stream.write(128)
|
||||
writeValue(stream, value.toList())
|
||||
}
|
||||
is MyGattCharacteristicArgs -> {
|
||||
is MyGattDescriptorArgs -> {
|
||||
stream.write(129)
|
||||
writeValue(stream, value.toList())
|
||||
}
|
||||
is MyGattDescriptorArgs -> {
|
||||
stream.write(130)
|
||||
writeValue(stream, value.toList())
|
||||
}
|
||||
is MyGattServiceArgs -> {
|
||||
stream.write(131)
|
||||
stream.write(130)
|
||||
writeValue(stream, value.toList())
|
||||
}
|
||||
else -> super.writeValue(stream, value)
|
||||
@ -346,20 +327,19 @@ private object MyCentralManagerHostApiCodec : StandardMessageCodec() {
|
||||
|
||||
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
|
||||
interface MyCentralManagerHostApi {
|
||||
fun setUp(callback: (Result<MyCentralManagerArgs>) -> Unit)
|
||||
fun setUp()
|
||||
fun startDiscovery(callback: (Result<Unit>) -> Unit)
|
||||
fun stopDiscovery()
|
||||
fun connect(peripheralHashCodeArgs: Long, callback: (Result<Unit>) -> Unit)
|
||||
fun disconnect(peripheralHashCodeArgs: Long, callback: (Result<Unit>) -> Unit)
|
||||
fun getMaximumWriteLength(peripheralHashCodeArgs: Long, typeNumberArgs: Long): Long
|
||||
fun readRSSI(peripheralHashCodeArgs: Long, callback: (Result<Long>) -> Unit)
|
||||
fun discoverGATT(peripheralHashCodeArgs: Long, callback: (Result<List<MyGattServiceArgs>>) -> Unit)
|
||||
fun requestMTU(peripheralHashCodeArgs: Long, mtuArgs: Long, callback: (Result<Long>) -> Unit)
|
||||
fun readCharacteristic(peripheralHashCodeArgs: Long, characteristicHashCodeArgs: Long, callback: (Result<ByteArray>) -> Unit)
|
||||
fun writeCharacteristic(peripheralHashCodeArgs: Long, characteristicHashCodeArgs: Long, valueArgs: ByteArray, typeNumberArgs: Long, callback: (Result<Unit>) -> Unit)
|
||||
fun notifyCharacteristic(peripheralHashCodeArgs: Long, characteristicHashCodeArgs: Long, stateArgs: Boolean, callback: (Result<Unit>) -> Unit)
|
||||
fun readDescriptor(peripheralHashCodeArgs: Long, descriptorHashCodeArgs: Long, callback: (Result<ByteArray>) -> Unit)
|
||||
fun writeDescriptor(peripheralHashCodeArgs: Long, descriptorHashCodeArgs: Long, valueArgs: ByteArray, callback: (Result<Unit>) -> Unit)
|
||||
fun connect(addressArgs: String, callback: (Result<Unit>) -> Unit)
|
||||
fun disconnect(addressArgs: String, callback: (Result<Unit>) -> Unit)
|
||||
fun requestMTU(addressArgs: String, mtuArgs: Long, callback: (Result<Long>) -> Unit)
|
||||
fun readRSSI(addressArgs: String, callback: (Result<Long>) -> Unit)
|
||||
fun discoverServices(addressArgs: String, callback: (Result<List<MyGattServiceArgs>>) -> Unit)
|
||||
fun readCharacteristic(addressArgs: String, hashCodeArgs: Long, callback: (Result<ByteArray>) -> Unit)
|
||||
fun writeCharacteristic(addressArgs: String, hashCodeArgs: Long, valueArgs: ByteArray, typeNumberArgs: Long, callback: (Result<Unit>) -> Unit)
|
||||
fun setCharacteristicNotifyState(addressArgs: String, hashCodeArgs: Long, stateNumberArgs: Long, callback: (Result<Unit>) -> Unit)
|
||||
fun readDescriptor(addressArgs: String, hashCodeArgs: Long, callback: (Result<ByteArray>) -> Unit)
|
||||
fun writeDescriptor(addressArgs: String, hashCodeArgs: Long, valueArgs: ByteArray, callback: (Result<Unit>) -> Unit)
|
||||
|
||||
companion object {
|
||||
/** The codec used by MyCentralManagerHostApi. */
|
||||
@ -373,15 +353,14 @@ interface MyCentralManagerHostApi {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.setUp", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { _, reply ->
|
||||
api.setUp() { result: Result<MyCentralManagerArgs> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
} else {
|
||||
val data = result.getOrNull()
|
||||
reply.reply(wrapResult(data))
|
||||
}
|
||||
var wrapped: List<Any?>
|
||||
try {
|
||||
api.setUp()
|
||||
wrapped = listOf<Any?>(null)
|
||||
} catch (exception: Throwable) {
|
||||
wrapped = wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
@ -426,8 +405,8 @@ interface MyCentralManagerHostApi {
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val peripheralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
api.connect(peripheralHashCodeArgsArg) { result: Result<Unit> ->
|
||||
val addressArgsArg = args[0] as String
|
||||
api.connect(addressArgsArg) { result: Result<Unit> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
@ -445,8 +424,8 @@ interface MyCentralManagerHostApi {
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val peripheralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
api.disconnect(peripheralHashCodeArgsArg) { result: Result<Unit> ->
|
||||
val addressArgsArg = args[0] as String
|
||||
api.disconnect(addressArgsArg) { result: Result<Unit> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
@ -460,19 +439,21 @@ interface MyCentralManagerHostApi {
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.getMaximumWriteLength", codec)
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.requestMTU", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val peripheralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
val typeNumberArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long }
|
||||
var wrapped: List<Any?>
|
||||
try {
|
||||
wrapped = listOf<Any?>(api.getMaximumWriteLength(peripheralHashCodeArgsArg, typeNumberArgsArg))
|
||||
} catch (exception: Throwable) {
|
||||
wrapped = wrapError(exception)
|
||||
val addressArgsArg = args[0] as String
|
||||
val mtuArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long }
|
||||
api.requestMTU(addressArgsArg, mtuArgsArg) { result: Result<Long> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
} else {
|
||||
val data = result.getOrNull()
|
||||
reply.reply(wrapResult(data))
|
||||
}
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
@ -483,8 +464,8 @@ interface MyCentralManagerHostApi {
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val peripheralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
api.readRSSI(peripheralHashCodeArgsArg) { result: Result<Long> ->
|
||||
val addressArgsArg = args[0] as String
|
||||
api.readRSSI(addressArgsArg) { result: Result<Long> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
@ -499,33 +480,12 @@ interface MyCentralManagerHostApi {
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.discoverGATT", codec)
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.discoverServices", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val peripheralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
api.discoverGATT(peripheralHashCodeArgsArg) { result: Result<List<MyGattServiceArgs>> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
} else {
|
||||
val data = result.getOrNull()
|
||||
reply.reply(wrapResult(data))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.requestMTU", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val peripheralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
val mtuArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long }
|
||||
api.requestMTU(peripheralHashCodeArgsArg, mtuArgsArg) { result: Result<Long> ->
|
||||
val addressArgsArg = args[0] as String
|
||||
api.discoverServices(addressArgsArg) { result: Result<List<MyGattServiceArgs>> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
@ -544,9 +504,9 @@ interface MyCentralManagerHostApi {
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val peripheralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
val characteristicHashCodeArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long }
|
||||
api.readCharacteristic(peripheralHashCodeArgsArg, characteristicHashCodeArgsArg) { result: Result<ByteArray> ->
|
||||
val addressArgsArg = args[0] as String
|
||||
val hashCodeArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long }
|
||||
api.readCharacteristic(addressArgsArg, hashCodeArgsArg) { result: Result<ByteArray> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
@ -565,11 +525,11 @@ interface MyCentralManagerHostApi {
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val peripheralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
val characteristicHashCodeArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long }
|
||||
val addressArgsArg = args[0] as String
|
||||
val hashCodeArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long }
|
||||
val valueArgsArg = args[2] as ByteArray
|
||||
val typeNumberArgsArg = args[3].let { if (it is Int) it.toLong() else it as Long }
|
||||
api.writeCharacteristic(peripheralHashCodeArgsArg, characteristicHashCodeArgsArg, valueArgsArg, typeNumberArgsArg) { result: Result<Unit> ->
|
||||
api.writeCharacteristic(addressArgsArg, hashCodeArgsArg, valueArgsArg, typeNumberArgsArg) { result: Result<Unit> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
@ -583,14 +543,14 @@ interface MyCentralManagerHostApi {
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.notifyCharacteristic", codec)
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerHostApi.setCharacteristicNotifyState", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val peripheralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
val characteristicHashCodeArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long }
|
||||
val stateArgsArg = args[2] as Boolean
|
||||
api.notifyCharacteristic(peripheralHashCodeArgsArg, characteristicHashCodeArgsArg, stateArgsArg) { result: Result<Unit> ->
|
||||
val addressArgsArg = args[0] as String
|
||||
val hashCodeArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long }
|
||||
val stateNumberArgsArg = args[2].let { if (it is Int) it.toLong() else it as Long }
|
||||
api.setCharacteristicNotifyState(addressArgsArg, hashCodeArgsArg, stateNumberArgsArg) { result: Result<Unit> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
@ -608,9 +568,9 @@ interface MyCentralManagerHostApi {
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val peripheralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
val descriptorHashCodeArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long }
|
||||
api.readDescriptor(peripheralHashCodeArgsArg, descriptorHashCodeArgsArg) { result: Result<ByteArray> ->
|
||||
val addressArgsArg = args[0] as String
|
||||
val hashCodeArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long }
|
||||
api.readDescriptor(addressArgsArg, hashCodeArgsArg) { result: Result<ByteArray> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
@ -629,10 +589,10 @@ interface MyCentralManagerHostApi {
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val peripheralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
val descriptorHashCodeArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long }
|
||||
val addressArgsArg = args[0] as String
|
||||
val hashCodeArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long }
|
||||
val valueArgsArg = args[2] as ByteArray
|
||||
api.writeDescriptor(peripheralHashCodeArgsArg, descriptorHashCodeArgsArg, valueArgsArg) { result: Result<Unit> ->
|
||||
api.writeDescriptor(addressArgsArg, hashCodeArgsArg, valueArgsArg) { result: Result<Unit> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
@ -658,21 +618,11 @@ private object MyCentralManagerFlutterApiCodec : StandardMessageCodec() {
|
||||
}
|
||||
}
|
||||
129.toByte() -> {
|
||||
return (readValue(buffer) as? List<Any?>)?.let {
|
||||
MyGattCharacteristicArgs.fromList(it)
|
||||
}
|
||||
}
|
||||
130.toByte() -> {
|
||||
return (readValue(buffer) as? List<Any?>)?.let {
|
||||
MyGattDescriptorArgs.fromList(it)
|
||||
}
|
||||
}
|
||||
131.toByte() -> {
|
||||
return (readValue(buffer) as? List<Any?>)?.let {
|
||||
MyManufacturerSpecificDataArgs.fromList(it)
|
||||
}
|
||||
}
|
||||
132.toByte() -> {
|
||||
130.toByte() -> {
|
||||
return (readValue(buffer) as? List<Any?>)?.let {
|
||||
MyPeripheralArgs.fromList(it)
|
||||
}
|
||||
@ -686,20 +636,12 @@ private object MyCentralManagerFlutterApiCodec : StandardMessageCodec() {
|
||||
stream.write(128)
|
||||
writeValue(stream, value.toList())
|
||||
}
|
||||
is MyGattCharacteristicArgs -> {
|
||||
is MyManufacturerSpecificDataArgs -> {
|
||||
stream.write(129)
|
||||
writeValue(stream, value.toList())
|
||||
}
|
||||
is MyGattDescriptorArgs -> {
|
||||
stream.write(130)
|
||||
writeValue(stream, value.toList())
|
||||
}
|
||||
is MyManufacturerSpecificDataArgs -> {
|
||||
stream.write(131)
|
||||
writeValue(stream, value.toList())
|
||||
}
|
||||
is MyPeripheralArgs -> {
|
||||
stream.write(132)
|
||||
stream.write(130)
|
||||
writeValue(stream, value.toList())
|
||||
}
|
||||
else -> super.writeValue(stream, value)
|
||||
@ -717,58 +659,77 @@ class MyCentralManagerFlutterApi(private val binaryMessenger: BinaryMessenger) {
|
||||
}
|
||||
}
|
||||
fun onStateChanged(stateNumberArgsArg: Long, callback: (Result<Unit>) -> Unit) {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onStateChanged", codec)
|
||||
val channelName = "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onStateChanged"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(listOf(stateNumberArgsArg)) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)));
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else {
|
||||
callback(Result.success(Unit));
|
||||
callback(Result.success(Unit))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(FlutterError("channel-error", "Unable to establish connection on channel.", "")));
|
||||
callback(Result.failure(createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
fun onDiscovered(peripheralArgsArg: MyPeripheralArgs, rssiArgsArg: Long, advertisementArgsArg: MyAdvertisementArgs, callback: (Result<Unit>) -> Unit) {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onDiscovered", codec)
|
||||
val channelName = "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onDiscovered"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(listOf(peripheralArgsArg, rssiArgsArg, advertisementArgsArg)) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)));
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else {
|
||||
callback(Result.success(Unit));
|
||||
callback(Result.success(Unit))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(FlutterError("channel-error", "Unable to establish connection on channel.", "")));
|
||||
callback(Result.failure(createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
fun onPeripheralStateChanged(peripheralArgsArg: MyPeripheralArgs, stateArgsArg: Boolean, callback: (Result<Unit>) -> Unit) {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onPeripheralStateChanged", codec)
|
||||
channel.send(listOf(peripheralArgsArg, stateArgsArg)) {
|
||||
fun onConnectionStateChanged(addressArgsArg: String, stateArgsArg: Boolean, callback: (Result<Unit>) -> Unit) {
|
||||
val channelName = "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onConnectionStateChanged"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(listOf(addressArgsArg, stateArgsArg)) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)));
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else {
|
||||
callback(Result.success(Unit));
|
||||
callback(Result.success(Unit))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(FlutterError("channel-error", "Unable to establish connection on channel.", "")));
|
||||
callback(Result.failure(createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
fun onCharacteristicValueChanged(characteristicArgsArg: MyGattCharacteristicArgs, valueArgsArg: ByteArray, callback: (Result<Unit>) -> Unit) {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onCharacteristicValueChanged", codec)
|
||||
channel.send(listOf(characteristicArgsArg, valueArgsArg)) {
|
||||
fun onMtuChanged(addressArgsArg: String, mtuArgsArg: Long, callback: (Result<Unit>) -> Unit) {
|
||||
val channelName = "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onMtuChanged"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(listOf(addressArgsArg, mtuArgsArg)) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)));
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else {
|
||||
callback(Result.success(Unit));
|
||||
callback(Result.success(Unit))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(FlutterError("channel-error", "Unable to establish connection on channel.", "")));
|
||||
callback(Result.failure(createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
fun onCharacteristicNotified(addressArgsArg: String, hashCodeArgsArg: Long, valueArgsArg: ByteArray, callback: (Result<Unit>) -> Unit) {
|
||||
val channelName = "dev.flutter.pigeon.bluetooth_low_energy_android.MyCentralManagerFlutterApi.onCharacteristicNotified"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(listOf(addressArgsArg, hashCodeArgsArg, valueArgsArg)) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else {
|
||||
callback(Result.success(Unit))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -802,11 +763,6 @@ private object MyPeripheralManagerHostApiCodec : StandardMessageCodec() {
|
||||
MyManufacturerSpecificDataArgs.fromList(it)
|
||||
}
|
||||
}
|
||||
133.toByte() -> {
|
||||
return (readValue(buffer) as? List<Any?>)?.let {
|
||||
MyPeripheralManagerArgs.fromList(it)
|
||||
}
|
||||
}
|
||||
else -> super.readValueOfType(type, buffer)
|
||||
}
|
||||
}
|
||||
@ -832,10 +788,6 @@ private object MyPeripheralManagerHostApiCodec : StandardMessageCodec() {
|
||||
stream.write(132)
|
||||
writeValue(stream, value.toList())
|
||||
}
|
||||
is MyPeripheralManagerArgs -> {
|
||||
stream.write(133)
|
||||
writeValue(stream, value.toList())
|
||||
}
|
||||
else -> super.writeValue(stream, value)
|
||||
}
|
||||
}
|
||||
@ -843,16 +795,14 @@ private object MyPeripheralManagerHostApiCodec : StandardMessageCodec() {
|
||||
|
||||
/** Generated interface from Pigeon that represents a handler of messages from Flutter. */
|
||||
interface MyPeripheralManagerHostApi {
|
||||
fun setUp(callback: (Result<MyPeripheralManagerArgs>) -> Unit)
|
||||
fun setUp()
|
||||
fun addService(serviceArgs: MyGattServiceArgs, callback: (Result<Unit>) -> Unit)
|
||||
fun removeService(serviceHashCodeArgs: Long)
|
||||
fun removeService(hashCodeArgs: Long)
|
||||
fun clearServices()
|
||||
fun startAdvertising(advertisementArgs: MyAdvertisementArgs, callback: (Result<Unit>) -> Unit)
|
||||
fun stopAdvertising()
|
||||
fun getMaximumWriteLength(centralHashCodeArgs: Long): Long
|
||||
fun sendReadCharacteristicReply(centralHashCodeArgs: Long, characteristicHashCodeArgs: Long, idArgs: Long, offsetArgs: Long, statusArgs: Boolean, valueArgs: ByteArray)
|
||||
fun sendWriteCharacteristicReply(centralHashCodeArgs: Long, characteristicHashCodeArgs: Long, idArgs: Long, offsetArgs: Long, statusArgs: Boolean)
|
||||
fun notifyCharacteristicValueChanged(centralHashCodeArgs: Long, characteristicHashCodeArgs: Long, valueArgs: ByteArray, callback: (Result<Unit>) -> Unit)
|
||||
fun sendResponse(addressArgs: String, idArgs: Long, statusNumberArgs: Long, offsetArgs: Long, valueArgs: ByteArray?)
|
||||
fun notifyCharacteristicChanged(hashCodeArgs: Long, valueArgs: ByteArray, confirmArgs: Boolean, addressArgs: String, callback: (Result<Unit>) -> Unit)
|
||||
|
||||
companion object {
|
||||
/** The codec used by MyPeripheralManagerHostApi. */
|
||||
@ -866,15 +816,14 @@ interface MyPeripheralManagerHostApi {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.setUp", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { _, reply ->
|
||||
api.setUp() { result: Result<MyPeripheralManagerArgs> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
} else {
|
||||
val data = result.getOrNull()
|
||||
reply.reply(wrapResult(data))
|
||||
}
|
||||
var wrapped: List<Any?>
|
||||
try {
|
||||
api.setUp()
|
||||
wrapped = listOf<Any?>(null)
|
||||
} catch (exception: Throwable) {
|
||||
wrapped = wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
@ -904,10 +853,10 @@ interface MyPeripheralManagerHostApi {
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val serviceHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
val hashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
var wrapped: List<Any?>
|
||||
try {
|
||||
api.removeService(serviceHashCodeArgsArg)
|
||||
api.removeService(hashCodeArgsArg)
|
||||
wrapped = listOf<Any?>(null)
|
||||
} catch (exception: Throwable) {
|
||||
wrapped = wrapError(exception)
|
||||
@ -972,37 +921,18 @@ interface MyPeripheralManagerHostApi {
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.getMaximumWriteLength", codec)
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.sendResponse", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val centralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
var wrapped: List<Any?>
|
||||
try {
|
||||
wrapped = listOf<Any?>(api.getMaximumWriteLength(centralHashCodeArgsArg))
|
||||
} catch (exception: Throwable) {
|
||||
wrapped = wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.sendReadCharacteristicReply", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val centralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
val characteristicHashCodeArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long }
|
||||
val idArgsArg = args[2].let { if (it is Int) it.toLong() else it as Long }
|
||||
val addressArgsArg = args[0] as String
|
||||
val idArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long }
|
||||
val statusNumberArgsArg = args[2].let { if (it is Int) it.toLong() else it as Long }
|
||||
val offsetArgsArg = args[3].let { if (it is Int) it.toLong() else it as Long }
|
||||
val statusArgsArg = args[4] as Boolean
|
||||
val valueArgsArg = args[5] as ByteArray
|
||||
val valueArgsArg = args[4] as ByteArray?
|
||||
var wrapped: List<Any?>
|
||||
try {
|
||||
api.sendReadCharacteristicReply(centralHashCodeArgsArg, characteristicHashCodeArgsArg, idArgsArg, offsetArgsArg, statusArgsArg, valueArgsArg)
|
||||
api.sendResponse(addressArgsArg, idArgsArg, statusNumberArgsArg, offsetArgsArg, valueArgsArg)
|
||||
wrapped = listOf<Any?>(null)
|
||||
} catch (exception: Throwable) {
|
||||
wrapped = wrapError(exception)
|
||||
@ -1014,37 +944,15 @@ interface MyPeripheralManagerHostApi {
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.sendWriteCharacteristicReply", codec)
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.notifyCharacteristicChanged", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val centralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
val characteristicHashCodeArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long }
|
||||
val idArgsArg = args[2].let { if (it is Int) it.toLong() else it as Long }
|
||||
val offsetArgsArg = args[3].let { if (it is Int) it.toLong() else it as Long }
|
||||
val statusArgsArg = args[4] as Boolean
|
||||
var wrapped: List<Any?>
|
||||
try {
|
||||
api.sendWriteCharacteristicReply(centralHashCodeArgsArg, characteristicHashCodeArgsArg, idArgsArg, offsetArgsArg, statusArgsArg)
|
||||
wrapped = listOf<Any?>(null)
|
||||
} catch (exception: Throwable) {
|
||||
wrapped = wrapError(exception)
|
||||
}
|
||||
reply.reply(wrapped)
|
||||
}
|
||||
} else {
|
||||
channel.setMessageHandler(null)
|
||||
}
|
||||
}
|
||||
run {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerHostApi.notifyCharacteristicValueChanged", codec)
|
||||
if (api != null) {
|
||||
channel.setMessageHandler { message, reply ->
|
||||
val args = message as List<Any?>
|
||||
val centralHashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
val characteristicHashCodeArgsArg = args[1].let { if (it is Int) it.toLong() else it as Long }
|
||||
val valueArgsArg = args[2] as ByteArray
|
||||
api.notifyCharacteristicValueChanged(centralHashCodeArgsArg, characteristicHashCodeArgsArg, valueArgsArg) { result: Result<Unit> ->
|
||||
val hashCodeArgsArg = args[0].let { if (it is Int) it.toLong() else it as Long }
|
||||
val valueArgsArg = args[1] as ByteArray
|
||||
val confirmArgsArg = args[2] as Boolean
|
||||
val addressArgsArg = args[3] as String
|
||||
api.notifyCharacteristicChanged(hashCodeArgsArg, valueArgsArg, confirmArgsArg, addressArgsArg) { result: Result<Unit> ->
|
||||
val error = result.exceptionOrNull()
|
||||
if (error != null) {
|
||||
reply.reply(wrapError(error))
|
||||
@ -1069,16 +977,6 @@ private object MyPeripheralManagerFlutterApiCodec : StandardMessageCodec() {
|
||||
MyCentralArgs.fromList(it)
|
||||
}
|
||||
}
|
||||
129.toByte() -> {
|
||||
return (readValue(buffer) as? List<Any?>)?.let {
|
||||
MyGattCharacteristicArgs.fromList(it)
|
||||
}
|
||||
}
|
||||
130.toByte() -> {
|
||||
return (readValue(buffer) as? List<Any?>)?.let {
|
||||
MyGattDescriptorArgs.fromList(it)
|
||||
}
|
||||
}
|
||||
else -> super.readValueOfType(type, buffer)
|
||||
}
|
||||
}
|
||||
@ -1088,14 +986,6 @@ private object MyPeripheralManagerFlutterApiCodec : StandardMessageCodec() {
|
||||
stream.write(128)
|
||||
writeValue(stream, value.toList())
|
||||
}
|
||||
is MyGattCharacteristicArgs -> {
|
||||
stream.write(129)
|
||||
writeValue(stream, value.toList())
|
||||
}
|
||||
is MyGattDescriptorArgs -> {
|
||||
stream.write(130)
|
||||
writeValue(stream, value.toList())
|
||||
}
|
||||
else -> super.writeValue(stream, value)
|
||||
}
|
||||
}
|
||||
@ -1111,58 +1001,107 @@ class MyPeripheralManagerFlutterApi(private val binaryMessenger: BinaryMessenger
|
||||
}
|
||||
}
|
||||
fun onStateChanged(stateNumberArgsArg: Long, callback: (Result<Unit>) -> Unit) {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onStateChanged", codec)
|
||||
val channelName = "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onStateChanged"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(listOf(stateNumberArgsArg)) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)));
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else {
|
||||
callback(Result.success(Unit));
|
||||
callback(Result.success(Unit))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(FlutterError("channel-error", "Unable to establish connection on channel.", "")));
|
||||
callback(Result.failure(createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
fun onReadCharacteristicCommandReceived(centralArgsArg: MyCentralArgs, characteristicArgsArg: MyGattCharacteristicArgs, idArgsArg: Long, offsetArgsArg: Long, callback: (Result<Unit>) -> Unit) {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onReadCharacteristicCommandReceived", codec)
|
||||
channel.send(listOf(centralArgsArg, characteristicArgsArg, idArgsArg, offsetArgsArg)) {
|
||||
fun onConnectionStateChanged(centralArgsArg: MyCentralArgs, stateArgsArg: Boolean, callback: (Result<Unit>) -> Unit) {
|
||||
val channelName = "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onConnectionStateChanged"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(listOf(centralArgsArg, stateArgsArg)) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)));
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else {
|
||||
callback(Result.success(Unit));
|
||||
callback(Result.success(Unit))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(FlutterError("channel-error", "Unable to establish connection on channel.", "")));
|
||||
callback(Result.failure(createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
fun onWriteCharacteristicCommandReceived(centralArgsArg: MyCentralArgs, characteristicArgsArg: MyGattCharacteristicArgs, idArgsArg: Long, offsetArgsArg: Long, valueArgsArg: ByteArray, callback: (Result<Unit>) -> Unit) {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onWriteCharacteristicCommandReceived", codec)
|
||||
channel.send(listOf(centralArgsArg, characteristicArgsArg, idArgsArg, offsetArgsArg, valueArgsArg)) {
|
||||
fun onMtuChanged(addressArgsArg: String, mtuArgsArg: Long, callback: (Result<Unit>) -> Unit) {
|
||||
val channelName = "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onMtuChanged"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(listOf(addressArgsArg, mtuArgsArg)) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)));
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else {
|
||||
callback(Result.success(Unit));
|
||||
callback(Result.success(Unit))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(FlutterError("channel-error", "Unable to establish connection on channel.", "")));
|
||||
callback(Result.failure(createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
fun onNotifyCharacteristicCommandReceived(centralArgsArg: MyCentralArgs, characteristicArgsArg: MyGattCharacteristicArgs, stateArgsArg: Boolean, callback: (Result<Unit>) -> Unit) {
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onNotifyCharacteristicCommandReceived", codec)
|
||||
channel.send(listOf(centralArgsArg, characteristicArgsArg, stateArgsArg)) {
|
||||
fun onCharacteristicReadRequest(addressArgsArg: String, hashCodeArgsArg: Long, idArgsArg: Long, offsetArgsArg: Long, callback: (Result<Unit>) -> Unit) {
|
||||
val channelName = "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onCharacteristicReadRequest"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(listOf(addressArgsArg, hashCodeArgsArg, idArgsArg, offsetArgsArg)) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)));
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else {
|
||||
callback(Result.success(Unit));
|
||||
callback(Result.success(Unit))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(FlutterError("channel-error", "Unable to establish connection on channel.", "")));
|
||||
callback(Result.failure(createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
fun onCharacteristicWriteRequest(addressArgsArg: String, hashCodeArgsArg: Long, idArgsArg: Long, offsetArgsArg: Long, valueArgsArg: ByteArray, preparedWriteArgsArg: Boolean, responseNeededArgsArg: Boolean, callback: (Result<Unit>) -> Unit) {
|
||||
val channelName = "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onCharacteristicWriteRequest"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(listOf(addressArgsArg, hashCodeArgsArg, idArgsArg, offsetArgsArg, valueArgsArg, preparedWriteArgsArg, responseNeededArgsArg)) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else {
|
||||
callback(Result.success(Unit))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
fun onExecuteWrite(addressArgsArg: String, idArgsArg: Long, executeArgsArg: Boolean, callback: (Result<Unit>) -> Unit) {
|
||||
val channelName = "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onExecuteWrite"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(listOf(addressArgsArg, idArgsArg, executeArgsArg)) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else {
|
||||
callback(Result.success(Unit))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
fun onCharacteristicNotifyStateChanged(addressArgsArg: String, hashCodeArgsArg: Long, stateNumberArgsArg: Long, callback: (Result<Unit>) -> Unit) {
|
||||
val channelName = "dev.flutter.pigeon.bluetooth_low_energy_android.MyPeripheralManagerFlutterApi.onCharacteristicNotifyStateChanged"
|
||||
val channel = BasicMessageChannel<Any?>(binaryMessenger, channelName, codec)
|
||||
channel.send(listOf(addressArgsArg, hashCodeArgsArg, stateNumberArgsArg)) {
|
||||
if (it is List<*>) {
|
||||
if (it.size > 1) {
|
||||
callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
|
||||
} else {
|
||||
callback(Result.success(Unit))
|
||||
}
|
||||
} else {
|
||||
callback(Result.failure(createConnectionError(channelName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,108 +2,54 @@ package dev.yanshouwang.bluetooth_low_energy_android
|
||||
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
import android.bluetooth.BluetoothDevice
|
||||
import android.bluetooth.BluetoothGatt
|
||||
import android.bluetooth.BluetoothGattCharacteristic
|
||||
import android.bluetooth.BluetoothGattDescriptor
|
||||
import android.bluetooth.BluetoothGattService
|
||||
import android.bluetooth.le.AdvertiseData
|
||||
import android.bluetooth.le.ScanRecord
|
||||
import android.bluetooth.le.ScanResult
|
||||
import android.os.ParcelUuid
|
||||
import android.util.SparseArray
|
||||
import java.util.UUID
|
||||
|
||||
val Any.TAG get() = this::class.java.simpleName as String
|
||||
|
||||
val BluetoothAdapter.stateArgs: MyBluetoothLowEnergyStateArgs
|
||||
get() = state.toBluetoothLowEnergyStateArgs()
|
||||
|
||||
fun Int.toBluetoothLowEnergyStateArgs(): MyBluetoothLowEnergyStateArgs {
|
||||
//region ToObj
|
||||
fun MyGattCharacteristicWriteTypeArgs.toType(): Int {
|
||||
return when (this) {
|
||||
BluetoothAdapter.STATE_ON -> MyBluetoothLowEnergyStateArgs.POWEREDON
|
||||
else -> MyBluetoothLowEnergyStateArgs.POWEREDOFF
|
||||
MyGattCharacteristicWriteTypeArgs.WITHRESPONSE -> BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
|
||||
MyGattCharacteristicWriteTypeArgs.WITHOUTRESPONSE -> BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE
|
||||
}
|
||||
}
|
||||
|
||||
fun BluetoothDevice.toPeripheralArgs(): MyPeripheralArgs {
|
||||
val hashCodeArgs = hashCode().toLong()
|
||||
val uuid = this.uuid.toString()
|
||||
return MyPeripheralArgs(hashCodeArgs, uuid)
|
||||
fun MyGattCharacteristicNotifyStateArgs.toValue(): ByteArray {
|
||||
return when (this) {
|
||||
MyGattCharacteristicNotifyStateArgs.NONE -> BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE
|
||||
MyGattCharacteristicNotifyStateArgs.NOTIFY -> BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
|
||||
MyGattCharacteristicNotifyStateArgs.INDICATE -> BluetoothGattDescriptor.ENABLE_INDICATION_VALUE
|
||||
}
|
||||
}
|
||||
|
||||
fun BluetoothDevice.toCentralArgs(): MyCentralArgs {
|
||||
val hashCodeArgs = hashCode().toLong()
|
||||
val uuid = this.uuid.toString()
|
||||
return MyCentralArgs(hashCodeArgs, uuid)
|
||||
fun MyGattStatusArgs.toStatus(): Int {
|
||||
return when (this) {
|
||||
MyGattStatusArgs.SUCCESS -> BluetoothGatt.GATT_SUCCESS
|
||||
MyGattStatusArgs.READNOTPERMITTED -> BluetoothGatt.GATT_READ_NOT_PERMITTED
|
||||
MyGattStatusArgs.WRITENOTPERMITTED -> BluetoothGatt.GATT_READ_NOT_PERMITTED
|
||||
MyGattStatusArgs.REQUESTNOTSUPPORTED -> BluetoothGatt.GATT_READ_NOT_PERMITTED
|
||||
MyGattStatusArgs.INVALIDOFFSET -> BluetoothGatt.GATT_INVALID_OFFSET
|
||||
MyGattStatusArgs.INSUFFICIENTAUTHENTICATION -> BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION
|
||||
MyGattStatusArgs.INSUFFICIENTENCRYPTION -> BluetoothGatt.GATT_INSUFFICIENT_ENCRYPTION
|
||||
MyGattStatusArgs.INVALIDATTRIBUTELENGTH -> BluetoothGatt.GATT_INVALID_ATTRIBUTE_LENGTH
|
||||
MyGattStatusArgs.CONNECTIONCONGESTED -> BluetoothGatt.GATT_CONNECTION_CONGESTED
|
||||
MyGattStatusArgs.FAILURE -> BluetoothGatt.GATT_FAILURE
|
||||
}
|
||||
}
|
||||
|
||||
val BluetoothDevice.uuid: UUID
|
||||
get() {
|
||||
val node = address.filter { char -> char != ':' }
|
||||
// We don't know the timestamp of the bluetooth device, use nil UUID as prefix.
|
||||
return UUID.fromString("00000000-0000-0000-0000-$node")
|
||||
}
|
||||
|
||||
val ScanResult.advertisementArgs: MyAdvertisementArgs
|
||||
get() {
|
||||
val record = scanRecord
|
||||
return if (record == null) {
|
||||
val nameArgs = null
|
||||
val serviceUUIDsArgs = emptyList<String?>()
|
||||
val serviceDataArgs = emptyMap<String?, ByteArray>()
|
||||
val manufacturerSpecificDataArgs = null
|
||||
MyAdvertisementArgs(nameArgs, serviceUUIDsArgs, serviceDataArgs, manufacturerSpecificDataArgs)
|
||||
} else {
|
||||
val nameArgs = record.deviceName
|
||||
val serviceUUIDsArgs = record.serviceUuids?.map { uuid -> uuid.toString() }
|
||||
?: emptyList()
|
||||
val pairs = record.serviceData.map { (uuid, value) ->
|
||||
val key = uuid.toString()
|
||||
return@map Pair(key, value)
|
||||
}.toTypedArray()
|
||||
val serviceDataArgs = mapOf<String?, ByteArray?>(*pairs)
|
||||
val manufacturerSpecificDataArgs = record.manufacturerSpecificData.toManufacturerSpecificDataArgs()
|
||||
MyAdvertisementArgs(nameArgs, serviceUUIDsArgs, serviceDataArgs, manufacturerSpecificDataArgs)
|
||||
}
|
||||
}
|
||||
|
||||
fun SparseArray<ByteArray>.toManufacturerSpecificDataArgs(): MyManufacturerSpecificDataArgs? {
|
||||
var index = 0
|
||||
val size = size()
|
||||
val itemsArgs = mutableListOf<MyManufacturerSpecificDataArgs>()
|
||||
while (index < size) {
|
||||
val idArgs = keyAt(index).toLong()
|
||||
val dataArgs = valueAt(index)
|
||||
val itemArgs = MyManufacturerSpecificDataArgs(idArgs, dataArgs)
|
||||
itemsArgs.add(itemArgs)
|
||||
index++
|
||||
}
|
||||
return itemsArgs.lastOrNull()
|
||||
}
|
||||
|
||||
val ScanRecord.rawValues: Map<Byte, ByteArray>
|
||||
get() {
|
||||
val rawValues = mutableMapOf<Byte, ByteArray>()
|
||||
var index = 0
|
||||
val size = bytes.size
|
||||
while (index < size) {
|
||||
val length = bytes[index++].toInt() and 0xff
|
||||
if (length == 0) {
|
||||
break
|
||||
}
|
||||
val end = index + length
|
||||
val type = bytes[index++]
|
||||
val value = bytes.slice(index until end).toByteArray()
|
||||
rawValues[type] = value
|
||||
index = end
|
||||
}
|
||||
return rawValues.toMap()
|
||||
}
|
||||
|
||||
fun MyAdvertisementArgs.toAdvertiseData(adapter: BluetoothAdapter): AdvertiseData {
|
||||
val advertiseDataBuilder = AdvertiseData.Builder()
|
||||
if (nameArgs == null) {
|
||||
advertiseDataBuilder.setIncludeDeviceName(false)
|
||||
} else {
|
||||
// TODO: There is an issue that Android will use the cached name before setName takes effect.
|
||||
// see https://stackoverflow.com/questions/8377558/change-the-android-bluetooth-device-name
|
||||
adapter.name = nameArgs
|
||||
advertiseDataBuilder.setIncludeDeviceName(true)
|
||||
}
|
||||
@ -124,48 +70,55 @@ fun MyAdvertisementArgs.toAdvertiseData(adapter: BluetoothAdapter): AdvertiseDat
|
||||
return advertiseDataBuilder.build()
|
||||
}
|
||||
|
||||
fun BluetoothGattService.toManufacturerSpecificDataArgs(characteristicsArgs: List<MyGattCharacteristicArgs>): MyGattServiceArgs {
|
||||
val hashCodeArgs = hashCode().toLong()
|
||||
val uuidArgs = this.uuid.toString()
|
||||
return MyGattServiceArgs(hashCodeArgs, uuidArgs, characteristicsArgs)
|
||||
fun MyGattDescriptorArgs.toDescriptor(): BluetoothGattDescriptor {
|
||||
val uuid = UUID.fromString(uuidArgs)
|
||||
val permissions =
|
||||
BluetoothGattDescriptor.PERMISSION_READ or BluetoothGattDescriptor.PERMISSION_WRITE
|
||||
return BluetoothGattDescriptor(uuid, permissions)
|
||||
}
|
||||
|
||||
fun BluetoothGattCharacteristic.toManufacturerSpecificDataArgs(descriptorsArgs: List<MyGattDescriptorArgs>): MyGattCharacteristicArgs {
|
||||
val hashCodeArgs = hashCode().toLong()
|
||||
val uuidArgs = this.uuid.toString()
|
||||
return MyGattCharacteristicArgs(hashCodeArgs, uuidArgs, propertyNumbersArgs, descriptorsArgs)
|
||||
fun MyGattCharacteristicArgs.toCharacteristic(): BluetoothGattCharacteristic {
|
||||
val uuid = UUID.fromString(uuidArgs)
|
||||
val properties = getProperties()
|
||||
val permissions = getPermissions()
|
||||
return BluetoothGattCharacteristic(uuid, properties, permissions)
|
||||
}
|
||||
|
||||
val BluetoothGattCharacteristic.propertyNumbersArgs: List<Long>
|
||||
get() {
|
||||
val numbersArgs = mutableListOf<Long>()
|
||||
if (properties and BluetoothGattCharacteristic.PROPERTY_READ != 0) {
|
||||
val number = MyGattCharacteristicPropertyArgs.READ.raw.toLong()
|
||||
numbersArgs.add(number)
|
||||
}
|
||||
if (properties and BluetoothGattCharacteristic.PROPERTY_WRITE != 0) {
|
||||
val number = MyGattCharacteristicPropertyArgs.WRITE.raw.toLong()
|
||||
numbersArgs.add(number)
|
||||
}
|
||||
if (properties and BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE != 0) {
|
||||
val number = MyGattCharacteristicPropertyArgs.WRITEWITHOUTRESPONSE.raw.toLong()
|
||||
numbersArgs.add(number)
|
||||
}
|
||||
if (properties and BluetoothGattCharacteristic.PROPERTY_NOTIFY != 0) {
|
||||
val number = MyGattCharacteristicPropertyArgs.NOTIFY.raw.toLong()
|
||||
numbersArgs.add(number)
|
||||
}
|
||||
if (properties and BluetoothGattCharacteristic.PROPERTY_INDICATE != 0) {
|
||||
val number = MyGattCharacteristicPropertyArgs.INDICATE.raw.toLong()
|
||||
numbersArgs.add(number)
|
||||
}
|
||||
return numbersArgs
|
||||
fun MyGattCharacteristicArgs.getProperties(): Int {
|
||||
val propertiesArgs = propertyNumbersArgs.filterNotNull().map { args ->
|
||||
val raw = args.toInt()
|
||||
MyGattCharacteristicPropertyArgs.ofRaw(raw)
|
||||
}
|
||||
val read = propertiesArgs.contains(MyGattCharacteristicPropertyArgs.READ)
|
||||
val write = propertiesArgs.contains(MyGattCharacteristicPropertyArgs.WRITE)
|
||||
val writeWithoutResponse =
|
||||
propertiesArgs.contains(MyGattCharacteristicPropertyArgs.WRITEWITHOUTRESPONSE)
|
||||
val notify = propertiesArgs.contains(MyGattCharacteristicPropertyArgs.NOTIFY)
|
||||
val indicate = propertiesArgs.contains(MyGattCharacteristicPropertyArgs.INDICATE)
|
||||
var properties = 0
|
||||
if (read) properties = properties or BluetoothGattCharacteristic.PROPERTY_READ
|
||||
if (write) properties = properties or BluetoothGattCharacteristic.PROPERTY_WRITE
|
||||
if (writeWithoutResponse) properties =
|
||||
properties or BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE
|
||||
if (notify) properties = properties or BluetoothGattCharacteristic.PROPERTY_NOTIFY
|
||||
if (indicate) properties = properties or BluetoothGattCharacteristic.PROPERTY_INDICATE
|
||||
return properties
|
||||
}
|
||||
|
||||
fun BluetoothGattDescriptor.toManufacturerSpecificDataArgs(): MyGattDescriptorArgs {
|
||||
val hashCodeArgs = hashCode().toLong()
|
||||
val uuidArgs = this.uuid.toString()
|
||||
return MyGattDescriptorArgs(hashCodeArgs, uuidArgs, null)
|
||||
fun MyGattCharacteristicArgs.getPermissions(): Int {
|
||||
val propertiesArgs = propertyNumbersArgs.filterNotNull().map { args ->
|
||||
val raw = args.toInt()
|
||||
MyGattCharacteristicPropertyArgs.ofRaw(raw)
|
||||
}
|
||||
val read = propertiesArgs.contains(MyGattCharacteristicPropertyArgs.READ)
|
||||
val write = propertiesArgs.contains(MyGattCharacteristicPropertyArgs.WRITE)
|
||||
val writeWithoutResponse =
|
||||
propertiesArgs.contains(MyGattCharacteristicPropertyArgs.WRITEWITHOUTRESPONSE)
|
||||
var permissions = 0
|
||||
if (read) permissions = permissions or BluetoothGattCharacteristic.PERMISSION_READ
|
||||
if (write || writeWithoutResponse) permissions =
|
||||
permissions or BluetoothGattCharacteristic.PERMISSION_WRITE
|
||||
return permissions
|
||||
}
|
||||
|
||||
fun MyGattServiceArgs.toService(): BluetoothGattService {
|
||||
@ -173,61 +126,142 @@ fun MyGattServiceArgs.toService(): BluetoothGattService {
|
||||
val serviceType = BluetoothGattService.SERVICE_TYPE_PRIMARY
|
||||
return BluetoothGattService(uuid, serviceType)
|
||||
}
|
||||
//endregion
|
||||
|
||||
fun MyGattCharacteristicArgs.toCharacteristic(): BluetoothGattCharacteristic {
|
||||
val uuid = UUID.fromString(uuidArgs)
|
||||
return BluetoothGattCharacteristic(uuid, properties, permissions)
|
||||
}
|
||||
|
||||
val MyGattCharacteristicArgs.properties: Int
|
||||
get() {
|
||||
val propertiesArgs = propertyNumbersArgs.filterNotNull().map { args ->
|
||||
val raw = args.toInt()
|
||||
MyGattCharacteristicPropertyArgs.ofRaw(raw)
|
||||
}
|
||||
val read = propertiesArgs.contains(MyGattCharacteristicPropertyArgs.READ)
|
||||
val write = propertiesArgs.contains(MyGattCharacteristicPropertyArgs.WRITE)
|
||||
val writeWithoutResponse = propertiesArgs.contains(MyGattCharacteristicPropertyArgs.WRITEWITHOUTRESPONSE)
|
||||
val notify = propertiesArgs.contains(MyGattCharacteristicPropertyArgs.NOTIFY)
|
||||
val indicate = propertiesArgs.contains(MyGattCharacteristicPropertyArgs.INDICATE)
|
||||
var properties = 0
|
||||
if (read) properties = properties or BluetoothGattCharacteristic.PROPERTY_READ
|
||||
if (write) properties = properties or BluetoothGattCharacteristic.PROPERTY_WRITE
|
||||
if (writeWithoutResponse) properties = properties or BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE
|
||||
if (notify) properties = properties or BluetoothGattCharacteristic.PROPERTY_NOTIFY
|
||||
if (indicate) properties = properties or BluetoothGattCharacteristic.PROPERTY_INDICATE
|
||||
return properties
|
||||
}
|
||||
|
||||
val MyGattCharacteristicArgs.permissions: Int
|
||||
get() {
|
||||
val propertiesArgs = propertyNumbersArgs.filterNotNull().map { args ->
|
||||
val raw = args.toInt()
|
||||
MyGattCharacteristicPropertyArgs.ofRaw(raw)
|
||||
}
|
||||
val read = propertiesArgs.contains(MyGattCharacteristicPropertyArgs.READ)
|
||||
val write = propertiesArgs.contains(MyGattCharacteristicPropertyArgs.WRITE)
|
||||
val writeWithoutResponse = propertiesArgs.contains(MyGattCharacteristicPropertyArgs.WRITEWITHOUTRESPONSE)
|
||||
var permissions = 0
|
||||
if (read) permissions = permissions or BluetoothGattCharacteristic.PERMISSION_READ
|
||||
if (write || writeWithoutResponse) permissions = permissions or BluetoothGattCharacteristic.PERMISSION_WRITE
|
||||
return permissions
|
||||
}
|
||||
|
||||
fun MyGattDescriptorArgs.toDescriptor(): BluetoothGattDescriptor {
|
||||
val uuid = UUID.fromString(uuidArgs)
|
||||
val permissions = BluetoothGattDescriptor.PERMISSION_READ or BluetoothGattDescriptor.PERMISSION_WRITE
|
||||
return BluetoothGattDescriptor(uuid, permissions)
|
||||
}
|
||||
|
||||
fun Long.toWriteTypeArgs(): MyGattCharacteristicWriteTypeArgs {
|
||||
val raw = toInt()
|
||||
return MyGattCharacteristicWriteTypeArgs.ofRaw(raw) ?: throw IllegalArgumentException()
|
||||
}
|
||||
|
||||
fun MyGattCharacteristicWriteTypeArgs.toType(): Int {
|
||||
//region ToArgs
|
||||
fun Int.toBluetoothLowEnergyStateArgs(): MyBluetoothLowEnergyStateArgs {
|
||||
return when (this) {
|
||||
MyGattCharacteristicWriteTypeArgs.WITHRESPONSE -> BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
|
||||
MyGattCharacteristicWriteTypeArgs.WITHOUTRESPONSE -> BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE
|
||||
BluetoothAdapter.STATE_ON -> MyBluetoothLowEnergyStateArgs.POWEREDON
|
||||
else -> MyBluetoothLowEnergyStateArgs.POWEREDOFF
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun SparseArray<ByteArray>.toManufacturerSpecificDataArgs(): MyManufacturerSpecificDataArgs? {
|
||||
var index = 0
|
||||
val size = size()
|
||||
val itemsArgs = mutableListOf<MyManufacturerSpecificDataArgs>()
|
||||
while (index < size) {
|
||||
val idArgs = keyAt(index).toLong()
|
||||
val dataArgs = valueAt(index)
|
||||
val itemArgs = MyManufacturerSpecificDataArgs(idArgs, dataArgs)
|
||||
itemsArgs.add(itemArgs)
|
||||
index++
|
||||
}
|
||||
return itemsArgs.lastOrNull()
|
||||
}
|
||||
|
||||
fun ScanResult.toAdvertisementArgs(): MyAdvertisementArgs {
|
||||
val record = scanRecord
|
||||
return if (record == null) {
|
||||
val nameArgs = null
|
||||
val serviceUUIDsArgs = emptyList<String?>()
|
||||
val serviceDataArgs = emptyMap<String?, ByteArray>()
|
||||
val manufacturerSpecificDataArgs = null
|
||||
MyAdvertisementArgs(
|
||||
nameArgs, serviceUUIDsArgs, serviceDataArgs, manufacturerSpecificDataArgs
|
||||
)
|
||||
} else {
|
||||
val nameArgs = record.deviceName
|
||||
val serviceUUIDsArgs = record.serviceUuids?.map { uuid -> uuid.toString() } ?: emptyList()
|
||||
val pairs = record.serviceData.map { (uuid, value) ->
|
||||
val key = uuid.toString()
|
||||
return@map Pair(key, value)
|
||||
}.toTypedArray()
|
||||
val serviceDataArgs = mapOf<String?, ByteArray?>(*pairs)
|
||||
val manufacturerSpecificDataArgs =
|
||||
record.manufacturerSpecificData.toManufacturerSpecificDataArgs()
|
||||
MyAdvertisementArgs(
|
||||
nameArgs, serviceUUIDsArgs, serviceDataArgs, manufacturerSpecificDataArgs
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun BluetoothDevice.toCentralArgs(): MyCentralArgs {
|
||||
val addressArgs = address
|
||||
return MyCentralArgs(addressArgs)
|
||||
}
|
||||
|
||||
fun BluetoothDevice.toPeripheralArgs(): MyPeripheralArgs {
|
||||
val addressArgs = address
|
||||
return MyPeripheralArgs(addressArgs)
|
||||
}
|
||||
|
||||
fun BluetoothGattService.toArgs(): MyGattServiceArgs {
|
||||
val hashCodeArgs = hashCode().toLong()
|
||||
val uuidArgs = this.uuid.toString()
|
||||
val characteristicsArgs = characteristics.map { it.toArgs() }
|
||||
return MyGattServiceArgs(hashCodeArgs, uuidArgs, characteristicsArgs)
|
||||
}
|
||||
|
||||
fun BluetoothGattCharacteristic.toArgs(): MyGattCharacteristicArgs {
|
||||
val hashCodeArgs = hashCode().toLong()
|
||||
val uuidArgs = this.uuid.toString()
|
||||
val propertyNumbersArgs = getPropertyNumbersArgs()
|
||||
val descriptorsArgs = descriptors.map { it.toArgs() }
|
||||
return MyGattCharacteristicArgs(hashCodeArgs, uuidArgs, propertyNumbersArgs, descriptorsArgs)
|
||||
}
|
||||
|
||||
fun BluetoothGattCharacteristic.getPropertyNumbersArgs(): List<Long> {
|
||||
val numbersArgs = mutableListOf<Long>()
|
||||
if (properties and BluetoothGattCharacteristic.PROPERTY_READ != 0) {
|
||||
val number = MyGattCharacteristicPropertyArgs.READ.raw.toLong()
|
||||
numbersArgs.add(number)
|
||||
}
|
||||
if (properties and BluetoothGattCharacteristic.PROPERTY_WRITE != 0) {
|
||||
val number = MyGattCharacteristicPropertyArgs.WRITE.raw.toLong()
|
||||
numbersArgs.add(number)
|
||||
}
|
||||
if (properties and BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE != 0) {
|
||||
val number = MyGattCharacteristicPropertyArgs.WRITEWITHOUTRESPONSE.raw.toLong()
|
||||
numbersArgs.add(number)
|
||||
}
|
||||
if (properties and BluetoothGattCharacteristic.PROPERTY_NOTIFY != 0) {
|
||||
val number = MyGattCharacteristicPropertyArgs.NOTIFY.raw.toLong()
|
||||
numbersArgs.add(number)
|
||||
}
|
||||
if (properties and BluetoothGattCharacteristic.PROPERTY_INDICATE != 0) {
|
||||
val number = MyGattCharacteristicPropertyArgs.INDICATE.raw.toLong()
|
||||
numbersArgs.add(number)
|
||||
}
|
||||
return numbersArgs
|
||||
}
|
||||
|
||||
fun BluetoothGattDescriptor.toArgs(): MyGattDescriptorArgs {
|
||||
val hashCodeArgs = hashCode().toLong()
|
||||
val uuidArgs = this.uuid.toString()
|
||||
return MyGattDescriptorArgs(hashCodeArgs, uuidArgs, null)
|
||||
}
|
||||
|
||||
fun ByteArray.toNotifyStateArgs(): MyGattCharacteristicNotifyStateArgs {
|
||||
return if (this contentEquals BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE) {
|
||||
MyGattCharacteristicNotifyStateArgs.NOTIFY
|
||||
} else if (this contentEquals BluetoothGattDescriptor.ENABLE_INDICATION_VALUE) {
|
||||
MyGattCharacteristicNotifyStateArgs.INDICATE
|
||||
} else if (this contentEquals BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE) {
|
||||
MyGattCharacteristicNotifyStateArgs.NONE
|
||||
} else {
|
||||
throw IllegalArgumentException()
|
||||
}
|
||||
}
|
||||
//endregion
|
||||
|
||||
val Any.TAG get() = this::class.java.simpleName as String
|
||||
|
||||
//val ScanRecord.rawValues: Map<Byte, ByteArray>
|
||||
// get() {
|
||||
// val rawValues = mutableMapOf<Byte, ByteArray>()
|
||||
// var index = 0
|
||||
// val size = bytes.size
|
||||
// while (index < size) {
|
||||
// val length = bytes[index++].toInt() and 0xff
|
||||
// if (length == 0) {
|
||||
// break
|
||||
// }
|
||||
// val end = index + length
|
||||
// val type = bytes[index++]
|
||||
// val value = bytes.slice(index until end).toByteArray()
|
||||
// rawValues[type] = value
|
||||
// index = end
|
||||
// }
|
||||
// return rawValues.toMap()
|
||||
// }
|
||||
|
@ -7,103 +7,131 @@ import android.bluetooth.BluetoothGattDescriptor
|
||||
import android.os.Build
|
||||
import java.util.concurrent.Executor
|
||||
|
||||
class MyBluetoothGattCallback(private val centralManager: MyCentralManager, private val executor: Executor) : BluetoothGattCallback() {
|
||||
class MyBluetoothGattCallback(manager: MyCentralManager, executor: Executor) :
|
||||
BluetoothGattCallback() {
|
||||
private val mManager: MyCentralManager
|
||||
private val mExecutor: Executor
|
||||
|
||||
init {
|
||||
mManager = manager
|
||||
mExecutor = executor
|
||||
}
|
||||
|
||||
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
|
||||
super.onConnectionStateChange(gatt, status, newState)
|
||||
executor.execute {
|
||||
centralManager.onConnectionStateChange(gatt, status, newState)
|
||||
mExecutor.execute {
|
||||
mManager.onConnectionStateChange(gatt, status, newState)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMtuChanged(gatt: BluetoothGatt, mtu: Int, status: Int) {
|
||||
super.onMtuChanged(gatt, mtu, status)
|
||||
executor.execute {
|
||||
centralManager.onMtuChanged(gatt, mtu, status)
|
||||
mExecutor.execute {
|
||||
mManager.onMtuChanged(gatt, mtu, status)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onReadRemoteRssi(gatt: BluetoothGatt, rssi: Int, status: Int) {
|
||||
super.onReadRemoteRssi(gatt, rssi, status)
|
||||
executor.execute {
|
||||
centralManager.onReadRemoteRssi(gatt, rssi, status)
|
||||
mExecutor.execute {
|
||||
mManager.onReadRemoteRssi(gatt, rssi, status)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
|
||||
super.onServicesDiscovered(gatt, status)
|
||||
executor.execute {
|
||||
centralManager.onServicesDiscovered(gatt, status)
|
||||
mExecutor.execute {
|
||||
mManager.onServicesDiscovered(gatt, status)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCharacteristicRead(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, value: ByteArray, status: Int) {
|
||||
override fun onCharacteristicRead(
|
||||
gatt: BluetoothGatt,
|
||||
characteristic: BluetoothGattCharacteristic,
|
||||
value: ByteArray,
|
||||
status: Int
|
||||
) {
|
||||
super.onCharacteristicRead(gatt, characteristic, value, status)
|
||||
executor.execute {
|
||||
centralManager.onCharacteristicRead(characteristic, status, value)
|
||||
mExecutor.execute {
|
||||
mManager.onCharacteristicRead(gatt, characteristic, status, value)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove this override when minSdkVersion >= 33
|
||||
override fun onCharacteristicRead(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
|
||||
override fun onCharacteristicRead(
|
||||
gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int
|
||||
) {
|
||||
super.onCharacteristicRead(gatt, characteristic, status)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
return
|
||||
}
|
||||
val value = characteristic.value
|
||||
executor.execute {
|
||||
centralManager.onCharacteristicRead(characteristic, status, value)
|
||||
mExecutor.execute {
|
||||
mManager.onCharacteristicRead(gatt, characteristic, status, value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCharacteristicWrite(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
|
||||
override fun onCharacteristicWrite(
|
||||
gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int
|
||||
) {
|
||||
super.onCharacteristicWrite(gatt, characteristic, status)
|
||||
executor.execute {
|
||||
centralManager.onCharacteristicWrite(characteristic, status)
|
||||
mExecutor.execute {
|
||||
mManager.onCharacteristicWrite(gatt, characteristic, status)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, value: ByteArray) {
|
||||
override fun onCharacteristicChanged(
|
||||
gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, value: ByteArray
|
||||
) {
|
||||
super.onCharacteristicChanged(gatt, characteristic, value)
|
||||
executor.execute {
|
||||
centralManager.onCharacteristicChanged(characteristic, value)
|
||||
mExecutor.execute {
|
||||
mManager.onCharacteristicChanged(gatt, characteristic, value)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove this override when minSdkVersion >= 33
|
||||
override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
|
||||
override fun onCharacteristicChanged(
|
||||
gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic
|
||||
) {
|
||||
super.onCharacteristicChanged(gatt, characteristic)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
return
|
||||
}
|
||||
val value = characteristic.value
|
||||
executor.execute {
|
||||
centralManager.onCharacteristicChanged(characteristic, value)
|
||||
mExecutor.execute {
|
||||
mManager.onCharacteristicChanged(gatt, characteristic, value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDescriptorRead(gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int, value: ByteArray) {
|
||||
override fun onDescriptorRead(
|
||||
gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int, value: ByteArray
|
||||
) {
|
||||
super.onDescriptorRead(gatt, descriptor, status, value)
|
||||
executor.execute {
|
||||
centralManager.onDescriptorRead(descriptor, status, value)
|
||||
mExecutor.execute {
|
||||
mManager.onDescriptorRead(gatt, descriptor, status, value)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove this override when minSdkVersion >= 33
|
||||
override fun onDescriptorRead(gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int) {
|
||||
override fun onDescriptorRead(
|
||||
gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int
|
||||
) {
|
||||
super.onDescriptorRead(gatt, descriptor, status)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
return
|
||||
}
|
||||
val value = descriptor.value
|
||||
executor.execute {
|
||||
centralManager.onDescriptorRead(descriptor, status, value)
|
||||
mExecutor.execute {
|
||||
mManager.onDescriptorRead(gatt, descriptor, status, value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDescriptorWrite(gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int) {
|
||||
override fun onDescriptorWrite(
|
||||
gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int
|
||||
) {
|
||||
super.onDescriptorWrite(gatt, descriptor, status)
|
||||
executor.execute {
|
||||
centralManager.onDescriptorWrite(descriptor, status)
|
||||
mExecutor.execute {
|
||||
mManager.onDescriptorWrite(gatt, descriptor, status)
|
||||
}
|
||||
}
|
||||
}
|
@ -7,67 +7,107 @@ import android.bluetooth.BluetoothGattServerCallback
|
||||
import android.bluetooth.BluetoothGattService
|
||||
import java.util.concurrent.Executor
|
||||
|
||||
class MyBluetoothGattServerCallback(private val peripheralManager: MyPeripheralManager, private val executor: Executor) : BluetoothGattServerCallback() {
|
||||
class MyBluetoothGattServerCallback(manager: MyPeripheralManager, executor: Executor) :
|
||||
BluetoothGattServerCallback() {
|
||||
private val mManager: MyPeripheralManager
|
||||
private val mExecutor: Executor
|
||||
|
||||
init {
|
||||
mManager = manager
|
||||
mExecutor = executor
|
||||
}
|
||||
|
||||
override fun onServiceAdded(status: Int, service: BluetoothGattService) {
|
||||
super.onServiceAdded(status, service)
|
||||
executor.execute {
|
||||
peripheralManager.onServiceAdded(status, service)
|
||||
mExecutor.execute {
|
||||
mManager.onServiceAdded(status, service)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onConnectionStateChange(device: BluetoothDevice, status: Int, newState: Int) {
|
||||
super.onConnectionStateChange(device, status, newState)
|
||||
executor.execute {
|
||||
peripheralManager.onConnectionStateChange(device, status, newState)
|
||||
mExecutor.execute {
|
||||
mManager.onConnectionStateChange(device, status, newState)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMtuChanged(device: BluetoothDevice, mtu: Int) {
|
||||
super.onMtuChanged(device, mtu)
|
||||
executor.execute {
|
||||
peripheralManager.onMtuChanged(device, mtu)
|
||||
mExecutor.execute {
|
||||
mManager.onMtuChanged(device, mtu)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCharacteristicReadRequest(device: BluetoothDevice, requestId: Int, offset: Int, characteristic: BluetoothGattCharacteristic) {
|
||||
override fun onCharacteristicReadRequest(
|
||||
device: BluetoothDevice,
|
||||
requestId: Int,
|
||||
offset: Int,
|
||||
characteristic: BluetoothGattCharacteristic
|
||||
) {
|
||||
super.onCharacteristicReadRequest(device, requestId, offset, characteristic)
|
||||
executor.execute {
|
||||
peripheralManager.onCharacteristicReadRequest(device, requestId, offset, characteristic)
|
||||
mExecutor.execute {
|
||||
mManager.onCharacteristicReadRequest(device, requestId, offset, characteristic)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCharacteristicWriteRequest(device: BluetoothDevice, requestId: Int, characteristic: BluetoothGattCharacteristic, preparedWrite: Boolean, responseNeeded: Boolean, offset: Int, value: ByteArray) {
|
||||
super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value)
|
||||
executor.execute {
|
||||
peripheralManager.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value)
|
||||
override fun onCharacteristicWriteRequest(
|
||||
device: BluetoothDevice,
|
||||
requestId: Int,
|
||||
characteristic: BluetoothGattCharacteristic,
|
||||
preparedWrite: Boolean,
|
||||
responseNeeded: Boolean,
|
||||
offset: Int,
|
||||
value: ByteArray
|
||||
) {
|
||||
super.onCharacteristicWriteRequest(
|
||||
device, requestId, characteristic, preparedWrite, responseNeeded, offset, value
|
||||
)
|
||||
mExecutor.execute {
|
||||
mManager.onCharacteristicWriteRequest(
|
||||
device, requestId, characteristic, preparedWrite, responseNeeded, offset, value
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onExecuteWrite(device: BluetoothDevice, requestId: Int, execute: Boolean) {
|
||||
super.onExecuteWrite(device, requestId, execute)
|
||||
executor.execute {
|
||||
peripheralManager.onExecuteWrite(device, requestId, execute)
|
||||
mExecutor.execute {
|
||||
mManager.onExecuteWrite(device, requestId, execute)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNotificationSent(device: BluetoothDevice, status: Int) {
|
||||
super.onNotificationSent(device, status)
|
||||
executor.execute {
|
||||
peripheralManager.onNotificationSent(device, status)
|
||||
mExecutor.execute {
|
||||
mManager.onNotificationSent(device, status)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDescriptorReadRequest(device: BluetoothDevice, requestId: Int, offset: Int, descriptor: BluetoothGattDescriptor) {
|
||||
override fun onDescriptorReadRequest(
|
||||
device: BluetoothDevice, requestId: Int, offset: Int, descriptor: BluetoothGattDescriptor
|
||||
) {
|
||||
super.onDescriptorReadRequest(device, requestId, offset, descriptor)
|
||||
executor.execute {
|
||||
peripheralManager.onDescriptorReadRequest(device, requestId, offset, descriptor)
|
||||
mExecutor.execute {
|
||||
mManager.onDescriptorReadRequest(device, requestId, offset, descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDescriptorWriteRequest(device: BluetoothDevice, requestId: Int, descriptor: BluetoothGattDescriptor, preparedWrite: Boolean, responseNeeded: Boolean, offset: Int, value: ByteArray) {
|
||||
super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value)
|
||||
executor.execute {
|
||||
peripheralManager.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value)
|
||||
override fun onDescriptorWriteRequest(
|
||||
device: BluetoothDevice,
|
||||
requestId: Int,
|
||||
descriptor: BluetoothGattDescriptor,
|
||||
preparedWrite: Boolean,
|
||||
responseNeeded: Boolean,
|
||||
offset: Int,
|
||||
value: ByteArray
|
||||
) {
|
||||
super.onDescriptorWriteRequest(
|
||||
device, requestId, descriptor, preparedWrite, responseNeeded, offset, value
|
||||
)
|
||||
mExecutor.execute {
|
||||
mManager.onDescriptorWriteRequest(
|
||||
device, requestId, descriptor, preparedWrite, responseNeeded, offset, value
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -2,62 +2,123 @@ package dev.yanshouwang.bluetooth_low_energy_android
|
||||
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
import android.bluetooth.BluetoothManager
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.PackageManager
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
|
||||
import io.flutter.plugin.common.PluginRegistry.RequestPermissionsResultListener
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.Executor
|
||||
|
||||
abstract class MyBluetoothLowEnergyManager(private val context: Context) {
|
||||
companion object {
|
||||
const val DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xff.toByte()
|
||||
const val REQUEST_CODE = 443
|
||||
typealias MyBluetoothLowEnergyState = MyBluetoothLowEnergyStateArgs
|
||||
|
||||
val HEART_RATE_MEASUREMENT_UUID: UUID = UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb")
|
||||
val CLIENT_CHARACTERISTIC_CONFIG_UUID: UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")
|
||||
abstract class MyBluetoothLowEnergyManager(context: Context) {
|
||||
companion object {
|
||||
val CLIENT_CHARACTERISTIC_CONFIG_UUID =
|
||||
UUID.fromString("00002902-0000-1000-8000-00805f9b34fb") as UUID
|
||||
}
|
||||
|
||||
private lateinit var binding: ActivityPluginBinding
|
||||
private val mContext: Context
|
||||
|
||||
protected val unsupported = !context.packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)
|
||||
protected val executor = ContextCompat.getMainExecutor(context) as Executor
|
||||
private val mRequestPermissionsResultListener: RequestPermissionsResultListener by lazy {
|
||||
MyRequestPermissionResultListener(this)
|
||||
}
|
||||
private val mBroadcastReceiver: BroadcastReceiver by lazy {
|
||||
MyBroadcastReceiver(this)
|
||||
}
|
||||
|
||||
protected val manager get() = ContextCompat.getSystemService(context, BluetoothManager::class.java) as BluetoothManager
|
||||
private var mRegistered: Boolean
|
||||
private lateinit var mBinding: ActivityPluginBinding
|
||||
|
||||
init {
|
||||
mContext = context
|
||||
mRegistered = false
|
||||
}
|
||||
|
||||
protected val executor get() = ContextCompat.getMainExecutor(mContext) as Executor
|
||||
protected val manager
|
||||
get() = ContextCompat.getSystemService(
|
||||
mContext, BluetoothManager::class.java
|
||||
) as BluetoothManager
|
||||
protected val adapter get() = manager.adapter as BluetoothAdapter
|
||||
|
||||
private val listener by lazy { MyRequestPermissionResultListener(this) }
|
||||
private val receiver by lazy { MyBroadcastReceiver(this) }
|
||||
protected fun initialize() {
|
||||
val hasFeature =
|
||||
mContext.packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)
|
||||
if (hasFeature) {
|
||||
val authorized = permissions.all { permission ->
|
||||
ActivityCompat.checkSelfPermission(
|
||||
mContext, permission
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
if (authorized) {
|
||||
mOnAuthorizationStateChanged(true)
|
||||
} else {
|
||||
val activity = mBinding.activity
|
||||
ActivityCompat.requestPermissions(activity, permissions, requestCode)
|
||||
}
|
||||
} else {
|
||||
val state = MyBluetoothLowEnergyState.UNSUPPORTED
|
||||
onStateChanged(state)
|
||||
}
|
||||
}
|
||||
|
||||
fun onAttachedToActivity(binding: ActivityPluginBinding) {
|
||||
binding.addRequestPermissionsResultListener(listener)
|
||||
this.binding = binding
|
||||
binding.addRequestPermissionsResultListener(mRequestPermissionsResultListener)
|
||||
mBinding = binding
|
||||
}
|
||||
|
||||
fun onDetachedFromActivity() {
|
||||
binding.removeRequestPermissionsResultListener(listener)
|
||||
mBinding.removeRequestPermissionsResultListener(mRequestPermissionsResultListener)
|
||||
}
|
||||
|
||||
protected fun authorize(permissions: Array<String>) {
|
||||
val activity = binding.activity
|
||||
ActivityCompat.requestPermissions(activity, permissions, REQUEST_CODE)
|
||||
fun onRequestPermissionsResult(
|
||||
requestCode: Int, permissions: Array<out String>, results: IntArray
|
||||
): Boolean {
|
||||
if (this.requestCode != requestCode) {
|
||||
return false
|
||||
}
|
||||
val authorized = results.all { r -> r == PackageManager.PERMISSION_GRANTED }
|
||||
mOnAuthorizationStateChanged(authorized)
|
||||
return true
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
protected open fun register() {
|
||||
fun onReceive(context: Context, intent: Intent) {
|
||||
val action = intent.action
|
||||
if (action != BluetoothAdapter.ACTION_STATE_CHANGED) {
|
||||
return
|
||||
}
|
||||
val extra = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF)
|
||||
val state = extra.toBluetoothLowEnergyStateArgs()
|
||||
onStateChanged(state)
|
||||
}
|
||||
|
||||
private fun mOnAuthorizationStateChanged(authorized: Boolean) {
|
||||
val state = if (authorized) {
|
||||
mRegisterReceiver()
|
||||
if (adapter.state == BluetoothAdapter.STATE_ON) MyBluetoothLowEnergyState.POWEREDON
|
||||
else MyBluetoothLowEnergyState.POWEREDOFF
|
||||
} else {
|
||||
MyBluetoothLowEnergyState.UNAUTHORIZED
|
||||
}
|
||||
onStateChanged(state)
|
||||
}
|
||||
|
||||
private fun mRegisterReceiver() {
|
||||
if (mRegistered) {
|
||||
return
|
||||
}
|
||||
val filter = IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)
|
||||
context.registerReceiver(receiver, filter)
|
||||
mContext.registerReceiver(mBroadcastReceiver, filter)
|
||||
mRegistered = true
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
protected open fun unregister() {
|
||||
context.unregisterReceiver(receiver)
|
||||
}
|
||||
abstract val permissions: Array<String>
|
||||
abstract val requestCode: Int
|
||||
abstract fun onStateChanged(state: MyBluetoothLowEnergyState)
|
||||
}
|
||||
|
||||
abstract fun onRequestPermissionsResult(requestCode: Int, results: IntArray): Boolean
|
||||
abstract fun onReceive(intent: Intent)
|
||||
}
|
@ -4,8 +4,14 @@ import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
|
||||
class MyBroadcastReceiver(private val bluetoothLowEnergyManager: MyBluetoothLowEnergyManager) : BroadcastReceiver() {
|
||||
class MyBroadcastReceiver(manager: MyBluetoothLowEnergyManager) : BroadcastReceiver() {
|
||||
private val mManager: MyBluetoothLowEnergyManager
|
||||
|
||||
init {
|
||||
mManager = manager
|
||||
}
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
bluetoothLowEnergyManager.onReceive(intent)
|
||||
mManager.onReceive(context, intent)
|
||||
}
|
||||
}
|
||||
|
@ -1,267 +1,224 @@
|
||||
package dev.yanshouwang.bluetooth_low_energy_android
|
||||
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
import android.bluetooth.BluetoothDevice
|
||||
import android.bluetooth.BluetoothGatt
|
||||
import android.bluetooth.BluetoothGattCallback
|
||||
import android.bluetooth.BluetoothGattCharacteristic
|
||||
import android.bluetooth.BluetoothGattDescriptor
|
||||
import android.bluetooth.BluetoothGattService
|
||||
import android.bluetooth.BluetoothProfile
|
||||
import android.bluetooth.BluetoothStatusCodes
|
||||
import android.bluetooth.le.BluetoothLeScanner
|
||||
import android.bluetooth.le.ScanCallback
|
||||
import android.bluetooth.le.ScanFilter
|
||||
import android.bluetooth.le.ScanResult
|
||||
import android.bluetooth.le.ScanSettings
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import io.flutter.plugin.common.BinaryMessenger
|
||||
|
||||
class MyCentralManager(private val context: Context, binaryMessenger: BinaryMessenger) : MyBluetoothLowEnergyManager(context), MyCentralManagerHostApi {
|
||||
private val scanner get() = adapter.bluetoothLeScanner
|
||||
|
||||
private val api = MyCentralManagerFlutterApi(binaryMessenger)
|
||||
private val scanCallback = MyScanCallback(this)
|
||||
private val bluetoothGattCallback = MyBluetoothGattCallback(this, executor)
|
||||
|
||||
private val devices = mutableMapOf<Long, BluetoothDevice>()
|
||||
private val bluetoothGATTs = mutableMapOf<Long, BluetoothGatt>()
|
||||
private val services = mutableMapOf<Long, BluetoothGattService>()
|
||||
private val characteristics = mutableMapOf<Long, BluetoothGattCharacteristic>()
|
||||
private val descriptors = mutableMapOf<Long, BluetoothGattDescriptor>()
|
||||
private val mtus = mutableMapOf<Long, Int>()
|
||||
|
||||
private val peripheralsArgs = mutableMapOf<Int, MyPeripheralArgs>()
|
||||
private val servicesArgsOfPeripherals = mutableMapOf<Long, List<MyGattServiceArgs>>()
|
||||
private val servicesArgs = mutableMapOf<Int, MyGattServiceArgs>()
|
||||
private val characteristicsArgs = mutableMapOf<Int, MyGattCharacteristicArgs>()
|
||||
private val descriptorsArgs = mutableMapOf<Int, MyGattDescriptorArgs>()
|
||||
|
||||
private var registered = false
|
||||
private var discovering = false
|
||||
|
||||
private var setUpCallback: ((Result<MyCentralManagerArgs>) -> Unit)? = null
|
||||
private var startDiscoveryCallback: ((Result<Unit>) -> Unit)? = null
|
||||
private val connectCallbacks = mutableMapOf<Long, (Result<Unit>) -> Unit>()
|
||||
private val disconnectCallbacks = mutableMapOf<Long, (Result<Unit>) -> Unit>()
|
||||
private val requestMtuCallbacks = mutableMapOf<Long, (Result<Long>) -> Unit>()
|
||||
private val readRssiCallbacks = mutableMapOf<Long, (Result<Long>) -> Unit>()
|
||||
private val discoverGattCallbacks = mutableMapOf<Long, (Result<List<MyGattServiceArgs>>) -> Unit>()
|
||||
private val readCharacteristicCallbacks = mutableMapOf<Long, (Result<ByteArray>) -> Unit>()
|
||||
private val writeCharacteristicCallbacks = mutableMapOf<Long, (Result<Unit>) -> Unit>()
|
||||
private val readDescriptorCallbacks = mutableMapOf<Long, (Result<ByteArray>) -> Unit>()
|
||||
private val writeDescriptorCallbacks = mutableMapOf<Long, (Result<Unit>) -> Unit>()
|
||||
|
||||
override fun setUp(callback: (Result<MyCentralManagerArgs>) -> Unit) {
|
||||
try {
|
||||
if (setUpCallback != null) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
tearDown()
|
||||
if (unsupported) {
|
||||
val stateNumberArgs = MyBluetoothLowEnergyStateArgs.UNSUPPORTED.raw.toLong()
|
||||
val args = MyCentralManagerArgs(stateNumberArgs)
|
||||
callback(Result.success(args))
|
||||
}
|
||||
val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
arrayOf(android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
} else {
|
||||
arrayOf(android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION)
|
||||
}
|
||||
authorize(permissions)
|
||||
setUpCallback = callback
|
||||
} catch (e: Throwable) {
|
||||
callback(Result.failure(e))
|
||||
}
|
||||
class MyCentralManager(context: Context, binaryMessenger: BinaryMessenger) :
|
||||
MyBluetoothLowEnergyManager(context), MyCentralManagerHostApi {
|
||||
companion object {
|
||||
const val REQUEST_CODE = 443
|
||||
}
|
||||
|
||||
private fun tearDown() {
|
||||
if (registered) {
|
||||
unregister()
|
||||
}
|
||||
if (discovering) {
|
||||
stopDiscovery()
|
||||
}
|
||||
for (gatt in bluetoothGATTs.values) {
|
||||
gatt.disconnect()
|
||||
}
|
||||
devices.clear()
|
||||
bluetoothGATTs.clear()
|
||||
services.clear()
|
||||
characteristics.clear()
|
||||
descriptors.clear()
|
||||
mtus.clear()
|
||||
peripheralsArgs.clear()
|
||||
servicesArgsOfPeripherals.clear()
|
||||
servicesArgs.clear()
|
||||
characteristicsArgs.clear()
|
||||
descriptorsArgs.clear()
|
||||
setUpCallback = null
|
||||
startDiscoveryCallback = null
|
||||
connectCallbacks.clear()
|
||||
disconnectCallbacks.clear()
|
||||
requestMtuCallbacks.clear()
|
||||
readRssiCallbacks.clear()
|
||||
discoverGattCallbacks.clear()
|
||||
readCharacteristicCallbacks.clear()
|
||||
writeCharacteristicCallbacks.clear()
|
||||
readDescriptorCallbacks.clear()
|
||||
writeDescriptorCallbacks.clear()
|
||||
private val mContext: Context
|
||||
private val mApi: MyCentralManagerFlutterApi
|
||||
|
||||
private val mScanCallback: ScanCallback by lazy {
|
||||
MyScanCallback(this)
|
||||
}
|
||||
private val mBluetoothGattCallback: BluetoothGattCallback by lazy {
|
||||
MyBluetoothGattCallback(this, executor)
|
||||
}
|
||||
|
||||
override fun register() {
|
||||
super.register()
|
||||
registered = true
|
||||
private var mDiscovering: Boolean
|
||||
|
||||
private val mDevices: MutableMap<String, BluetoothDevice>
|
||||
private val mGATTs: MutableMap<String, BluetoothGatt>
|
||||
private val mCharacteristics: MutableMap<String, Map<Long, BluetoothGattCharacteristic>>
|
||||
private val mDescriptors: MutableMap<String, Map<Long, BluetoothGattDescriptor>>
|
||||
|
||||
private var mStartDiscoveryCallback: ((Result<Unit>) -> Unit)?
|
||||
private val mConnectCallbacks: MutableMap<String, (Result<Unit>) -> Unit>
|
||||
private val mDisconnectCallbacks: MutableMap<String, (Result<Unit>) -> Unit>
|
||||
private val mRequestMtuCallbacks: MutableMap<String, (Result<Long>) -> Unit>
|
||||
private val mReadRssiCallbacks: MutableMap<String, (Result<Long>) -> Unit>
|
||||
private val mDiscoverServicesCallbacks: MutableMap<String, (Result<List<MyGattServiceArgs>>) -> Unit>
|
||||
private val mReadCharacteristicCallbacks: MutableMap<String, MutableMap<Long, (Result<ByteArray>) -> Unit>>
|
||||
private val mWriteCharacteristicCallbacks: MutableMap<String, MutableMap<Long, (Result<Unit>) -> Unit>>
|
||||
private val mReadDescriptorCallbacks: MutableMap<String, MutableMap<Long, (Result<ByteArray>) -> Unit>>
|
||||
private val mWriteDescriptorCallbacks: MutableMap<String, MutableMap<Long, (Result<Unit>) -> Unit>>
|
||||
|
||||
init {
|
||||
mContext = context
|
||||
mApi = MyCentralManagerFlutterApi(binaryMessenger)
|
||||
|
||||
mDiscovering = false
|
||||
|
||||
mDevices = mutableMapOf()
|
||||
mGATTs = mutableMapOf()
|
||||
mCharacteristics = mutableMapOf()
|
||||
mDescriptors = mutableMapOf()
|
||||
|
||||
mStartDiscoveryCallback = null
|
||||
mConnectCallbacks = mutableMapOf()
|
||||
mDisconnectCallbacks = mutableMapOf()
|
||||
mRequestMtuCallbacks = mutableMapOf()
|
||||
mReadRssiCallbacks = mutableMapOf()
|
||||
mDiscoverServicesCallbacks = mutableMapOf()
|
||||
mReadCharacteristicCallbacks = mutableMapOf()
|
||||
mWriteCharacteristicCallbacks = mutableMapOf()
|
||||
mReadDescriptorCallbacks = mutableMapOf()
|
||||
mWriteDescriptorCallbacks = mutableMapOf()
|
||||
}
|
||||
|
||||
override fun unregister() {
|
||||
super.unregister()
|
||||
registered = false
|
||||
private val mScanner: BluetoothLeScanner get() = adapter.bluetoothLeScanner
|
||||
|
||||
override val permissions: Array<String>
|
||||
get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
arrayOf(
|
||||
android.Manifest.permission.ACCESS_COARSE_LOCATION,
|
||||
android.Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
android.Manifest.permission.BLUETOOTH_SCAN,
|
||||
android.Manifest.permission.BLUETOOTH_CONNECT
|
||||
)
|
||||
} else {
|
||||
arrayOf(
|
||||
android.Manifest.permission.ACCESS_COARSE_LOCATION,
|
||||
android.Manifest.permission.ACCESS_FINE_LOCATION
|
||||
)
|
||||
}
|
||||
|
||||
override val requestCode: Int
|
||||
get() = REQUEST_CODE
|
||||
|
||||
override fun setUp() {
|
||||
mClearState()
|
||||
initialize()
|
||||
}
|
||||
|
||||
override fun startDiscovery(callback: (Result<Unit>) -> Unit) {
|
||||
try {
|
||||
if (startDiscoveryCallback != null) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
val filters = emptyList<ScanFilter>()
|
||||
val settings = ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build()
|
||||
scanner.startScan(filters, settings, scanCallback)
|
||||
executor.execute { onScanSucceed() }
|
||||
startDiscoveryCallback = callback
|
||||
val settings =
|
||||
ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build()
|
||||
mScanner.startScan(filters, settings, mScanCallback)
|
||||
mStartDiscoveryCallback = callback
|
||||
executor.execute {
|
||||
onScanSucceed()
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
callback(Result.failure(e))
|
||||
}
|
||||
}
|
||||
|
||||
override fun stopDiscovery() {
|
||||
scanner.stopScan(scanCallback)
|
||||
discovering = false
|
||||
mScanner.stopScan(mScanCallback)
|
||||
mDiscovering = false
|
||||
}
|
||||
|
||||
override fun connect(peripheralHashCodeArgs: Long, callback: (Result<Unit>) -> Unit) {
|
||||
override fun connect(addressArgs: String, callback: (Result<Unit>) -> Unit) {
|
||||
try {
|
||||
val unfinishedCallback = connectCallbacks[peripheralHashCodeArgs]
|
||||
if (unfinishedCallback != null) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
val device = devices[peripheralHashCodeArgs] as BluetoothDevice
|
||||
val device = mDevices[addressArgs] as BluetoothDevice
|
||||
val autoConnect = false
|
||||
// Add to bluetoothGATTs cache.
|
||||
bluetoothGATTs[peripheralHashCodeArgs] = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
mGATTs[addressArgs] = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
val transport = BluetoothDevice.TRANSPORT_LE
|
||||
device.connectGatt(context, autoConnect, bluetoothGattCallback, transport)
|
||||
device.connectGatt(mContext, autoConnect, mBluetoothGattCallback, transport)
|
||||
} else {
|
||||
device.connectGatt(context, autoConnect, bluetoothGattCallback)
|
||||
device.connectGatt(mContext, autoConnect, mBluetoothGattCallback)
|
||||
}
|
||||
connectCallbacks[peripheralHashCodeArgs] = callback
|
||||
mConnectCallbacks[addressArgs] = callback
|
||||
} catch (e: Throwable) {
|
||||
callback(Result.failure(e))
|
||||
}
|
||||
}
|
||||
|
||||
override fun disconnect(peripheralHashCodeArgs: Long, callback: (Result<Unit>) -> Unit) {
|
||||
override fun disconnect(addressArgs: String, callback: (Result<Unit>) -> Unit) {
|
||||
try {
|
||||
val unfinishedCallback = disconnectCallbacks[peripheralHashCodeArgs]
|
||||
if (unfinishedCallback != null) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
val gatt = bluetoothGATTs[peripheralHashCodeArgs] as BluetoothGatt
|
||||
val gatt = mGATTs[addressArgs] as BluetoothGatt
|
||||
gatt.disconnect()
|
||||
disconnectCallbacks[peripheralHashCodeArgs] = callback
|
||||
mDisconnectCallbacks[addressArgs] = callback
|
||||
} catch (e: Throwable) {
|
||||
callback(Result.failure(e))
|
||||
}
|
||||
}
|
||||
|
||||
override fun requestMTU(peripheralHashCodeArgs: Long, mtuArgs: Long, callback: (Result<Long>) -> Unit) {
|
||||
override fun requestMTU(addressArgs: String, mtuArgs: Long, callback: (Result<Long>) -> Unit) {
|
||||
try {
|
||||
val unfinishedCallback = requestMtuCallbacks[peripheralHashCodeArgs]
|
||||
if (unfinishedCallback != null) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
val gatt = bluetoothGATTs[peripheralHashCodeArgs] as BluetoothGatt
|
||||
val gatt = mGATTs[addressArgs] as BluetoothGatt
|
||||
val mtu = mtuArgs.toInt()
|
||||
val requesting = gatt.requestMtu(mtu)
|
||||
if (!requesting) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
requestMtuCallbacks[peripheralHashCodeArgs] = callback
|
||||
mRequestMtuCallbacks[addressArgs] = callback
|
||||
} catch (e: Throwable) {
|
||||
callback(Result.failure(e))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMaximumWriteLength(peripheralHashCodeArgs: Long, typeNumberArgs: Long): Long {
|
||||
val mtu = mtus[peripheralHashCodeArgs] ?: 23
|
||||
val maximumWriteLength = when (typeNumberArgs.toWriteTypeArgs()) {
|
||||
MyGattCharacteristicWriteTypeArgs.WITHRESPONSE -> 512
|
||||
MyGattCharacteristicWriteTypeArgs.WITHOUTRESPONSE -> (mtu - 3).coerceIn(20, 512)
|
||||
}
|
||||
return maximumWriteLength.toLong()
|
||||
}
|
||||
|
||||
override fun readRSSI(peripheralHashCodeArgs: Long, callback: (Result<Long>) -> Unit) {
|
||||
override fun readRSSI(addressArgs: String, callback: (Result<Long>) -> Unit) {
|
||||
try {
|
||||
val unfinishedCallback = readRssiCallbacks[peripheralHashCodeArgs]
|
||||
if (unfinishedCallback != null) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
val gatt = bluetoothGATTs[peripheralHashCodeArgs] as BluetoothGatt
|
||||
val gatt = mGATTs[addressArgs] as BluetoothGatt
|
||||
val reading = gatt.readRemoteRssi()
|
||||
if (!reading) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
readRssiCallbacks[peripheralHashCodeArgs] = callback
|
||||
mReadRssiCallbacks[addressArgs] = callback
|
||||
} catch (e: Throwable) {
|
||||
callback(Result.failure(e))
|
||||
}
|
||||
}
|
||||
|
||||
override fun discoverGATT(peripheralHashCodeArgs: Long, callback: (Result<List<MyGattServiceArgs>>) -> Unit) {
|
||||
override fun discoverServices(
|
||||
addressArgs: String, callback: (Result<List<MyGattServiceArgs>>) -> Unit
|
||||
) {
|
||||
try {
|
||||
val unfinishedCallback = discoverGattCallbacks[peripheralHashCodeArgs]
|
||||
if (unfinishedCallback != null) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
val gatt = bluetoothGATTs[peripheralHashCodeArgs] as BluetoothGatt
|
||||
val gatt = mGATTs[addressArgs] as BluetoothGatt
|
||||
val discovering = gatt.discoverServices()
|
||||
if (!discovering) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
discoverGattCallbacks[peripheralHashCodeArgs] = callback
|
||||
mDiscoverServicesCallbacks[addressArgs] = callback
|
||||
} catch (e: Throwable) {
|
||||
callback(Result.failure(e))
|
||||
}
|
||||
}
|
||||
|
||||
override fun readCharacteristic(peripheralHashCodeArgs: Long, characteristicHashCodeArgs: Long, callback: (Result<ByteArray>) -> Unit) {
|
||||
override fun readCharacteristic(
|
||||
addressArgs: String, hashCodeArgs: Long, callback: (Result<ByteArray>) -> Unit
|
||||
) {
|
||||
try {
|
||||
val unfinishedCallback = readCharacteristicCallbacks[characteristicHashCodeArgs]
|
||||
if (unfinishedCallback != null) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
val gatt = bluetoothGATTs[peripheralHashCodeArgs] as BluetoothGatt
|
||||
val characteristic = characteristics[characteristicHashCodeArgs] as BluetoothGattCharacteristic
|
||||
val gatt = mGATTs[addressArgs] as BluetoothGatt
|
||||
val characteristic =
|
||||
mRetrieveCharacteristic(addressArgs, hashCodeArgs) as BluetoothGattCharacteristic
|
||||
val reading = gatt.readCharacteristic(characteristic)
|
||||
if (!reading) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
readCharacteristicCallbacks[characteristicHashCodeArgs] = callback
|
||||
val callbacks = mReadCharacteristicCallbacks.getOrPut(addressArgs) { mutableMapOf() }
|
||||
callbacks[hashCodeArgs] = callback
|
||||
} catch (e: Throwable) {
|
||||
callback(Result.failure(e))
|
||||
}
|
||||
}
|
||||
|
||||
override fun writeCharacteristic(peripheralHashCodeArgs: Long, characteristicHashCodeArgs: Long, valueArgs: ByteArray, typeNumberArgs: Long, callback: (Result<Unit>) -> Unit) {
|
||||
override fun writeCharacteristic(
|
||||
addressArgs: String,
|
||||
hashCodeArgs: Long,
|
||||
valueArgs: ByteArray,
|
||||
typeNumberArgs: Long,
|
||||
callback: (Result<Unit>) -> Unit
|
||||
) {
|
||||
try {
|
||||
val unfinishedCallback = writeCharacteristicCallbacks[characteristicHashCodeArgs]
|
||||
if (unfinishedCallback != null) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
val gatt = bluetoothGATTs[peripheralHashCodeArgs] as BluetoothGatt
|
||||
val characteristic = characteristics[characteristicHashCodeArgs] as BluetoothGattCharacteristic
|
||||
val typeArgs = typeNumberArgs.toWriteTypeArgs()
|
||||
val gatt = mGATTs[addressArgs] as BluetoothGatt
|
||||
val characteristic =
|
||||
mRetrieveCharacteristic(addressArgs, hashCodeArgs) as BluetoothGattCharacteristic
|
||||
val typeRawArgs = typeNumberArgs.toInt()
|
||||
val typeArgs = MyGattCharacteristicWriteTypeArgs.ofRaw(typeRawArgs)
|
||||
?: throw IllegalArgumentException()
|
||||
val type = typeArgs.toType()
|
||||
val writing = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
val code = gatt.writeCharacteristic(characteristic, valueArgs, type)
|
||||
@ -275,80 +232,75 @@ class MyCentralManager(private val context: Context, binaryMessenger: BinaryMess
|
||||
if (!writing) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
writeCharacteristicCallbacks[characteristicHashCodeArgs] = callback
|
||||
val callbacks = mWriteCharacteristicCallbacks.getOrPut(addressArgs) { mutableMapOf() }
|
||||
callbacks[hashCodeArgs] = callback
|
||||
} catch (e: Throwable) {
|
||||
callback(Result.failure(e))
|
||||
}
|
||||
}
|
||||
|
||||
override fun notifyCharacteristic(peripheralHashCodeArgs: Long, characteristicHashCodeArgs: Long, stateArgs: Boolean, callback: (Result<Unit>) -> Unit) {
|
||||
override fun setCharacteristicNotifyState(
|
||||
addressArgs: String,
|
||||
hashCodeArgs: Long,
|
||||
stateNumberArgs: Long,
|
||||
callback: (Result<Unit>) -> Unit
|
||||
) {
|
||||
try {
|
||||
val gatt = bluetoothGATTs[peripheralHashCodeArgs] as BluetoothGatt
|
||||
val characteristic = characteristics[characteristicHashCodeArgs] as BluetoothGattCharacteristic
|
||||
val notifying = gatt.setCharacteristicNotification(characteristic, stateArgs)
|
||||
val gatt = mGATTs[addressArgs] as BluetoothGatt
|
||||
val characteristic =
|
||||
mRetrieveCharacteristic(addressArgs, hashCodeArgs) as BluetoothGattCharacteristic
|
||||
val stateRawArgs = stateNumberArgs.toInt()
|
||||
val stateArgs = MyGattCharacteristicNotifyStateArgs.ofRaw(stateRawArgs)
|
||||
?: throw IllegalArgumentException()
|
||||
val enable = stateArgs != MyGattCharacteristicNotifyStateArgs.NONE
|
||||
val notifying = gatt.setCharacteristicNotification(characteristic, enable)
|
||||
if (!notifying) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
// TODO: Seems the docs is not correct, this operation is necessary for all characteristics.
|
||||
// https://developer.android.com/guide/topics/connectivity/bluetooth/transfer-ble-data#notification
|
||||
// This is specific to Heart Rate Measurement.
|
||||
// if (characteristic.uuid == UUID_HEART_RATE_MEASUREMENT) {
|
||||
val descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_UUID)
|
||||
val descriptorHashCode = descriptor.hashCode()
|
||||
val descriptorArgs = descriptorsArgs[descriptorHashCode] as MyGattDescriptorArgs
|
||||
val descriptorHashCodeArgs = descriptorArgs.hashCodeArgs
|
||||
val unfinishedCallback = writeDescriptorCallbacks[descriptorHashCodeArgs]
|
||||
if (unfinishedCallback != null) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
val value = if (stateArgs) BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
|
||||
else BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE
|
||||
val writing = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
val code = gatt.writeDescriptor(descriptor, value)
|
||||
code == BluetoothStatusCodes.SUCCESS
|
||||
} else {
|
||||
// TODO: remove this when minSdkVersion >= 33
|
||||
descriptor.value = value
|
||||
gatt.writeDescriptor(descriptor)
|
||||
}
|
||||
if (!writing) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
writeDescriptorCallbacks[descriptorHashCodeArgs] = callback
|
||||
// } else {
|
||||
// callback(Result.success(Unit))
|
||||
// }
|
||||
//if (characteristic.uuid == UUID_HEART_RATE_MEASUREMENT) {
|
||||
val cccDescriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_UUID)
|
||||
val cccHashCodeArgs = cccDescriptor.hashCode().toLong()
|
||||
val valueArgs = stateArgs.toValue()
|
||||
writeDescriptor(addressArgs, cccHashCodeArgs, valueArgs, callback)
|
||||
//} else {
|
||||
// callback(Result.success(Unit))
|
||||
//}
|
||||
} catch (e: Throwable) {
|
||||
callback(Result.failure(e))
|
||||
}
|
||||
}
|
||||
|
||||
override fun readDescriptor(peripheralHashCodeArgs: Long, descriptorHashCodeArgs: Long, callback: (Result<ByteArray>) -> Unit) {
|
||||
override fun readDescriptor(
|
||||
addressArgs: String, hashCodeArgs: Long, callback: (Result<ByteArray>) -> Unit
|
||||
) {
|
||||
try {
|
||||
val unfinishedCallback = readDescriptorCallbacks[descriptorHashCodeArgs]
|
||||
if (unfinishedCallback != null) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
val gatt = bluetoothGATTs[peripheralHashCodeArgs] as BluetoothGatt
|
||||
val descriptor = descriptors[descriptorHashCodeArgs] as BluetoothGattDescriptor
|
||||
val gatt = mGATTs[addressArgs] as BluetoothGatt
|
||||
val descriptor =
|
||||
mRetrieveDescriptor(addressArgs, hashCodeArgs) as BluetoothGattDescriptor
|
||||
val reading = gatt.readDescriptor(descriptor)
|
||||
if (!reading) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
readDescriptorCallbacks[descriptorHashCodeArgs] = callback
|
||||
val callbacks = mReadDescriptorCallbacks.getOrPut(addressArgs) { mutableMapOf() }
|
||||
callbacks[hashCodeArgs] = callback
|
||||
} catch (e: Throwable) {
|
||||
callback(Result.failure(e))
|
||||
}
|
||||
}
|
||||
|
||||
override fun writeDescriptor(peripheralHashCodeArgs: Long, descriptorHashCodeArgs: Long, valueArgs: ByteArray, callback: (Result<Unit>) -> Unit) {
|
||||
override fun writeDescriptor(
|
||||
addressArgs: String,
|
||||
hashCodeArgs: Long,
|
||||
valueArgs: ByteArray,
|
||||
callback: (Result<Unit>) -> Unit
|
||||
) {
|
||||
try {
|
||||
val unfinishedCallback = writeDescriptorCallbacks[descriptorHashCodeArgs]
|
||||
if (unfinishedCallback != null) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
val gatt = bluetoothGATTs[peripheralHashCodeArgs] as BluetoothGatt
|
||||
val descriptor = descriptors[descriptorHashCodeArgs] as BluetoothGattDescriptor
|
||||
val gatt = mGATTs[addressArgs] as BluetoothGatt
|
||||
val descriptor =
|
||||
mRetrieveDescriptor(addressArgs, hashCodeArgs) as BluetoothGattDescriptor
|
||||
val writing = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
val code = gatt.writeDescriptor(descriptor, valueArgs)
|
||||
code == BluetoothStatusCodes.SUCCESS
|
||||
@ -360,51 +312,28 @@ class MyCentralManager(private val context: Context, binaryMessenger: BinaryMess
|
||||
if (!writing) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
writeDescriptorCallbacks[descriptorHashCodeArgs] = callback
|
||||
val callbacks = mWriteDescriptorCallbacks.getOrPut(addressArgs) { mutableMapOf() }
|
||||
callbacks[hashCodeArgs] = callback
|
||||
} catch (e: Throwable) {
|
||||
callback(Result.failure(e))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, results: IntArray): Boolean {
|
||||
if (requestCode != REQUEST_CODE) {
|
||||
return false
|
||||
}
|
||||
val authorized = results.all { r -> r == PackageManager.PERMISSION_GRANTED }
|
||||
val callback = setUpCallback ?: return false
|
||||
setUpCallback = null
|
||||
val stateArgs = if (authorized) adapter.stateArgs
|
||||
else MyBluetoothLowEnergyStateArgs.UNAUTHORIZED
|
||||
val stateNumberArgs = stateArgs.raw.toLong()
|
||||
val args = MyCentralManagerArgs(stateNumberArgs)
|
||||
callback(Result.success(args))
|
||||
if (authorized) {
|
||||
register()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onReceive(intent: Intent) {
|
||||
val action = intent.action
|
||||
if (action != BluetoothAdapter.ACTION_STATE_CHANGED) {
|
||||
return
|
||||
}
|
||||
val state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF)
|
||||
val stateArgs = state.toBluetoothLowEnergyStateArgs()
|
||||
val stateNumberArgs = stateArgs.raw.toLong()
|
||||
api.onStateChanged(stateNumberArgs) {}
|
||||
override fun onStateChanged(state: MyBluetoothLowEnergyState) {
|
||||
val stateNumberArgs = state.raw.toLong()
|
||||
mApi.onStateChanged(stateNumberArgs) {}
|
||||
}
|
||||
|
||||
private fun onScanSucceed() {
|
||||
discovering = true
|
||||
val callback = startDiscoveryCallback ?: return
|
||||
startDiscoveryCallback = null
|
||||
mDiscovering = true
|
||||
val callback = mStartDiscoveryCallback ?: return
|
||||
mStartDiscoveryCallback = null
|
||||
callback(Result.success(Unit))
|
||||
}
|
||||
|
||||
fun onScanFailed(errorCode: Int) {
|
||||
val callback = startDiscoveryCallback ?: return
|
||||
startDiscoveryCallback = null
|
||||
val callback = mStartDiscoveryCallback ?: return
|
||||
mStartDiscoveryCallback = null
|
||||
val error = IllegalStateException("Start discovery failed with error code: $errorCode")
|
||||
callback(Result.failure(error))
|
||||
}
|
||||
@ -412,82 +341,68 @@ class MyCentralManager(private val context: Context, binaryMessenger: BinaryMess
|
||||
fun onScanResult(result: ScanResult) {
|
||||
val device = result.device
|
||||
val peripheralArgs = device.toPeripheralArgs()
|
||||
val hashCode = device.hashCode()
|
||||
val hashCodeArgs = peripheralArgs.hashCodeArgs
|
||||
this.devices[hashCodeArgs] = device
|
||||
this.peripheralsArgs[hashCode] = peripheralArgs
|
||||
val addressArgs = peripheralArgs.addressArgs
|
||||
val rssiArgs = result.rssi.toLong()
|
||||
val advertisementArgs = result.advertisementArgs
|
||||
api.onDiscovered(peripheralArgs, rssiArgs, advertisementArgs) {}
|
||||
val advertisementArgs = result.toAdvertisementArgs()
|
||||
mDevices[addressArgs] = device
|
||||
mApi.onDiscovered(peripheralArgs, rssiArgs, advertisementArgs) {}
|
||||
}
|
||||
|
||||
fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
|
||||
val device = gatt.device
|
||||
val deviceHashCode = device.hashCode()
|
||||
val peripheralArgs = peripheralsArgs[deviceHashCode] as MyPeripheralArgs
|
||||
val peripheralHashCodeArgs = peripheralArgs.hashCodeArgs
|
||||
val addressArgs = device.address
|
||||
// check connection state.
|
||||
if (newState == BluetoothProfile.STATE_DISCONNECTED) {
|
||||
gatt.close()
|
||||
bluetoothGATTs.remove(peripheralHashCodeArgs)
|
||||
mtus.remove(peripheralHashCodeArgs)
|
||||
mGATTs.remove(addressArgs)
|
||||
mCharacteristics.remove(addressArgs)
|
||||
mDescriptors.remove(addressArgs)
|
||||
val error = IllegalStateException("GATT is disconnected with status: $status")
|
||||
val requestMtuCallback = requestMtuCallbacks.remove(peripheralHashCodeArgs)
|
||||
val requestMtuCallback = mRequestMtuCallbacks.remove(addressArgs)
|
||||
if (requestMtuCallback != null) {
|
||||
requestMtuCallback(Result.failure(error))
|
||||
}
|
||||
val readRssiCallback = readRssiCallbacks.remove(peripheralHashCodeArgs)
|
||||
val readRssiCallback = mReadRssiCallbacks.remove(addressArgs)
|
||||
if (readRssiCallback != null) {
|
||||
readRssiCallback(Result.failure(error))
|
||||
}
|
||||
val discoverGattCallback = discoverGattCallbacks.remove(peripheralHashCodeArgs)
|
||||
if (discoverGattCallback != null) {
|
||||
discoverGattCallback(Result.failure(error))
|
||||
val discoverServicesCallback = mDiscoverServicesCallbacks.remove(addressArgs)
|
||||
if (discoverServicesCallback != null) {
|
||||
discoverServicesCallback(Result.failure(error))
|
||||
}
|
||||
val servicesArgs = servicesArgsOfPeripherals.remove(peripheralHashCodeArgs)
|
||||
?: emptyList()
|
||||
for (serviceArgs in servicesArgs) {
|
||||
val serviceHashCodeArgs = serviceArgs.hashCodeArgs
|
||||
val service = services.remove(serviceHashCodeArgs) as BluetoothGattService
|
||||
val serviceHashCode = service.hashCode()
|
||||
this.servicesArgs.remove(serviceHashCode)
|
||||
val characteristicsArgs = serviceArgs.characteristicsArgs.filterNotNull()
|
||||
for (characteristicArgs in characteristicsArgs) {
|
||||
val characteristicHashCodeArgs = characteristicArgs.hashCodeArgs
|
||||
val characteristic = characteristics.remove(characteristicHashCodeArgs) as BluetoothGattCharacteristic
|
||||
val characteristicHashCode = characteristic.hashCode()
|
||||
this.characteristicsArgs.remove(characteristicHashCode)
|
||||
val readCharacteristicCallback = readCharacteristicCallbacks.remove(characteristicHashCodeArgs)
|
||||
val writeCharacteristicCallback = writeCharacteristicCallbacks.remove(characteristicHashCodeArgs)
|
||||
if (readCharacteristicCallback != null) {
|
||||
readCharacteristicCallback(Result.failure(error))
|
||||
}
|
||||
if (writeCharacteristicCallback != null) {
|
||||
writeCharacteristicCallback(Result.failure(error))
|
||||
}
|
||||
val descriptorsArgs = characteristicArgs.descriptorsArgs.filterNotNull()
|
||||
for (descriptorArgs in descriptorsArgs) {
|
||||
val descriptorHashCodeArgs = descriptorArgs.hashCodeArgs
|
||||
val descriptor = descriptors.remove(descriptorHashCodeArgs) as BluetoothGattDescriptor
|
||||
val descriptorHashCode = descriptor.hashCode()
|
||||
this.descriptorsArgs.remove(descriptorHashCode)
|
||||
val readDescriptorCallback = readDescriptorCallbacks.remove(descriptorHashCodeArgs)
|
||||
val writeDescriptorCallback = writeDescriptorCallbacks.remove(descriptorHashCodeArgs)
|
||||
if (readDescriptorCallback != null) {
|
||||
readDescriptorCallback(Result.failure(error))
|
||||
}
|
||||
if (writeDescriptorCallback != null) {
|
||||
writeDescriptorCallback(Result.failure(error))
|
||||
}
|
||||
}
|
||||
val readCharacteristicCallbacks = mReadCharacteristicCallbacks.remove(addressArgs)
|
||||
if (readCharacteristicCallbacks != null) {
|
||||
val callbacks = readCharacteristicCallbacks.values
|
||||
for (callback in callbacks) {
|
||||
callback(Result.failure(error))
|
||||
}
|
||||
}
|
||||
val writeCharacteristicCallbacks = mWriteCharacteristicCallbacks.remove(addressArgs)
|
||||
if (writeCharacteristicCallbacks != null) {
|
||||
val callbacks = writeCharacteristicCallbacks.values
|
||||
for (callback in callbacks) {
|
||||
callback(Result.failure(error))
|
||||
}
|
||||
}
|
||||
val readDescriptorCallbacks = mReadDescriptorCallbacks.remove(addressArgs)
|
||||
if (readDescriptorCallbacks != null) {
|
||||
val callbacks = readDescriptorCallbacks.values
|
||||
for (callback in callbacks) {
|
||||
callback(Result.failure(error))
|
||||
}
|
||||
}
|
||||
val writeDescriptorCallbacks = mWriteDescriptorCallbacks.remove(addressArgs)
|
||||
if (writeDescriptorCallbacks != null) {
|
||||
val callbacks = writeDescriptorCallbacks.values
|
||||
for (callback in callbacks) {
|
||||
callback(Result.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
val stateArgs = newState == BluetoothProfile.STATE_CONNECTED
|
||||
api.onPeripheralStateChanged(peripheralArgs, stateArgs) {}
|
||||
mApi.onConnectionStateChanged(addressArgs, stateArgs) {}
|
||||
// check connect & disconnect callbacks.
|
||||
val connectCallback = connectCallbacks.remove(peripheralHashCodeArgs)
|
||||
val disconnectCallback = disconnectCallbacks.remove(peripheralHashCodeArgs)
|
||||
val connectCallback = mConnectCallbacks.remove(addressArgs)
|
||||
if (connectCallback != null) {
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
connectCallback(Result.success(Unit))
|
||||
@ -496,6 +411,7 @@ class MyCentralManager(private val context: Context, binaryMessenger: BinaryMess
|
||||
connectCallback(Result.failure(error))
|
||||
}
|
||||
}
|
||||
val disconnectCallback = mDisconnectCallbacks.remove(addressArgs)
|
||||
if (disconnectCallback != null) {
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
disconnectCallback(Result.success(Unit))
|
||||
@ -508,75 +424,43 @@ class MyCentralManager(private val context: Context, binaryMessenger: BinaryMess
|
||||
|
||||
fun onMtuChanged(gatt: BluetoothGatt, mtu: Int, status: Int) {
|
||||
val device = gatt.device
|
||||
val hashCode = device.hashCode()
|
||||
val peripheralArgs = peripheralsArgs[hashCode] as MyPeripheralArgs
|
||||
val peripheralHashCodeArgs = peripheralArgs.hashCodeArgs
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
mtus[peripheralHashCodeArgs] = mtu
|
||||
}
|
||||
val callback = requestMtuCallbacks.remove(peripheralHashCodeArgs) ?: return
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
val addressArgs = device.address
|
||||
val result = if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
val mtuArgs = mtu.toLong()
|
||||
callback(Result.success(mtuArgs))
|
||||
mApi.onMtuChanged(addressArgs, mtuArgs) {}
|
||||
Result.success(mtuArgs)
|
||||
} else {
|
||||
val error = IllegalStateException("Request MTU failed with status: $status")
|
||||
callback(Result.failure(error))
|
||||
val error = IllegalStateException("Read RSSI failed with status: $status")
|
||||
Result.failure(error)
|
||||
}
|
||||
val callback = mRequestMtuCallbacks.remove(addressArgs) ?: return
|
||||
callback(result)
|
||||
}
|
||||
|
||||
fun onReadRemoteRssi(gatt: BluetoothGatt, rssi: Int, status: Int) {
|
||||
val device = gatt.device
|
||||
val hashCode = device.hashCode()
|
||||
val peripheralArgs = peripheralsArgs[hashCode] as MyPeripheralArgs
|
||||
val peripheralHashCodeArgs = peripheralArgs.hashCodeArgs
|
||||
val callback = readRssiCallbacks.remove(peripheralHashCodeArgs) ?: return
|
||||
val addressArgs = device.address
|
||||
val callback = mReadRssiCallbacks.remove(addressArgs) ?: return
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
val rssiArgs = rssi.toLong()
|
||||
callback(Result.success(rssiArgs))
|
||||
} else {
|
||||
val error = IllegalStateException("Read rssi failed with status: $status")
|
||||
val error = IllegalStateException("Read RSSI failed with status: $status")
|
||||
callback(Result.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
|
||||
val device = gatt.device
|
||||
val deviceHashCode = device.hashCode()
|
||||
val peripheralArgs = peripheralsArgs[deviceHashCode] as MyPeripheralArgs
|
||||
val peripheralHashCodeArgs = peripheralArgs.hashCodeArgs
|
||||
val callback = discoverGattCallbacks.remove(peripheralHashCodeArgs) ?: return
|
||||
val addressArgs = device.address
|
||||
val callback = mDiscoverServicesCallbacks.remove(addressArgs) ?: return
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
val services = gatt.services
|
||||
val servicesArgs = mutableListOf<MyGattServiceArgs>()
|
||||
for (service in services) {
|
||||
val characteristics = service.characteristics
|
||||
val characteristicsArgs = mutableListOf<MyGattCharacteristicArgs>()
|
||||
for (characteristic in characteristics) {
|
||||
val descriptors = characteristic.descriptors
|
||||
val descriptorsArgs = mutableListOf<MyGattDescriptorArgs>()
|
||||
for (descriptor in descriptors) {
|
||||
val descriptorArgs = descriptor.toManufacturerSpecificDataArgs()
|
||||
val descriptorHashCode = descriptor.hashCode()
|
||||
val descriptorHashCodeArgs = descriptorArgs.hashCodeArgs
|
||||
this.descriptors[descriptorHashCodeArgs] = descriptor
|
||||
this.descriptorsArgs[descriptorHashCode] = descriptorArgs
|
||||
descriptorsArgs.add(descriptorArgs)
|
||||
}
|
||||
val characteristicArgs = characteristic.toManufacturerSpecificDataArgs(descriptorsArgs)
|
||||
val characteristicHashCode = characteristic.hashCode()
|
||||
val characteristicHashCodeArgs = characteristicArgs.hashCodeArgs
|
||||
this.characteristics[characteristicHashCodeArgs] = characteristic
|
||||
this.characteristicsArgs[characteristicHashCode] = characteristicArgs
|
||||
characteristicsArgs.add(characteristicArgs)
|
||||
}
|
||||
val serviceArgs = service.toManufacturerSpecificDataArgs(characteristicsArgs)
|
||||
val serviceHashCode = service.hashCode()
|
||||
val serviceHashCodeArgs = serviceArgs.hashCodeArgs
|
||||
this.services[serviceHashCodeArgs] = service
|
||||
this.servicesArgs[serviceHashCode] = serviceArgs
|
||||
servicesArgs.add(serviceArgs)
|
||||
}
|
||||
servicesArgsOfPeripherals[peripheralHashCodeArgs] = servicesArgs
|
||||
val characteristics = services.flatMap { it.characteristics }
|
||||
val descriptors = characteristics.flatMap { it.descriptors }
|
||||
mCharacteristics[addressArgs] = characteristics.associateBy { it.hashCode().toLong() }
|
||||
mDescriptors[addressArgs] = descriptors.associateBy { it.hashCode().toLong() }
|
||||
val servicesArgs = services.map { it.toArgs() }
|
||||
callback(Result.success(servicesArgs))
|
||||
} else {
|
||||
val error = IllegalStateException("Discover GATT failed with status: $status")
|
||||
@ -584,11 +468,17 @@ class MyCentralManager(private val context: Context, binaryMessenger: BinaryMess
|
||||
}
|
||||
}
|
||||
|
||||
fun onCharacteristicRead(characteristic: BluetoothGattCharacteristic, status: Int, value: ByteArray) {
|
||||
val hashCode = characteristic.hashCode()
|
||||
val characteristicArgs = characteristicsArgs[hashCode] as MyGattCharacteristicArgs
|
||||
val characteristicHashCodeArgs = characteristicArgs.hashCodeArgs
|
||||
val callback = readCharacteristicCallbacks.remove(characteristicHashCodeArgs) ?: return
|
||||
fun onCharacteristicRead(
|
||||
gatt: BluetoothGatt,
|
||||
characteristic: BluetoothGattCharacteristic,
|
||||
status: Int,
|
||||
value: ByteArray
|
||||
) {
|
||||
val device = gatt.device
|
||||
val addressArgs = device.address
|
||||
val hashCodeArgs = characteristic.hashCode().toLong()
|
||||
val callbacks = mReadCharacteristicCallbacks[addressArgs] ?: return
|
||||
val callback = callbacks.remove(hashCodeArgs) ?: return
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
callback(Result.success(value))
|
||||
} else {
|
||||
@ -597,11 +487,14 @@ class MyCentralManager(private val context: Context, binaryMessenger: BinaryMess
|
||||
}
|
||||
}
|
||||
|
||||
fun onCharacteristicWrite(characteristic: BluetoothGattCharacteristic, status: Int) {
|
||||
val hashCode = characteristic.hashCode()
|
||||
val characteristicArgs = characteristicsArgs[hashCode] as MyGattCharacteristicArgs
|
||||
val characteristicHashCodeArgs = characteristicArgs.hashCodeArgs
|
||||
val callback = writeCharacteristicCallbacks.remove(characteristicHashCodeArgs) ?: return
|
||||
fun onCharacteristicWrite(
|
||||
gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int
|
||||
) {
|
||||
val device = gatt.device
|
||||
val addressArgs = device.address
|
||||
val hashCodeArgs = characteristic.hashCode().toLong()
|
||||
val callbacks = mWriteCharacteristicCallbacks[addressArgs] ?: return
|
||||
val callback = callbacks.remove(hashCodeArgs) ?: return
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
callback(Result.success(Unit))
|
||||
} else {
|
||||
@ -610,17 +503,23 @@ class MyCentralManager(private val context: Context, binaryMessenger: BinaryMess
|
||||
}
|
||||
}
|
||||
|
||||
fun onCharacteristicChanged(characteristic: BluetoothGattCharacteristic, value: ByteArray) {
|
||||
val hashCode = characteristic.hashCode()
|
||||
val characteristicArgs = characteristicsArgs[hashCode] as MyGattCharacteristicArgs
|
||||
api.onCharacteristicValueChanged(characteristicArgs, value) {}
|
||||
fun onCharacteristicChanged(
|
||||
gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, value: ByteArray
|
||||
) {
|
||||
val device = gatt.device
|
||||
val addressArgs = device.address
|
||||
val hashCodeArgs = characteristic.hashCode().toLong()
|
||||
mApi.onCharacteristicNotified(addressArgs, hashCodeArgs, value) {}
|
||||
}
|
||||
|
||||
fun onDescriptorRead(descriptor: BluetoothGattDescriptor, status: Int, value: ByteArray) {
|
||||
val hashCode = descriptor.hashCode()
|
||||
val descriptorArgs = descriptorsArgs[hashCode] as MyGattDescriptorArgs
|
||||
val descriptorHashCodeArgs = descriptorArgs.hashCodeArgs
|
||||
val callback = readDescriptorCallbacks.remove(descriptorHashCodeArgs) ?: return
|
||||
fun onDescriptorRead(
|
||||
gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int, value: ByteArray
|
||||
) {
|
||||
val device = gatt.device
|
||||
val addressArgs = device.address
|
||||
val hashCodeArgs = descriptor.hashCode().toLong()
|
||||
val callbacks = mReadDescriptorCallbacks[addressArgs] ?: return
|
||||
val callback = callbacks.remove(hashCodeArgs) ?: return
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
callback(Result.success(value))
|
||||
} else {
|
||||
@ -629,11 +528,12 @@ class MyCentralManager(private val context: Context, binaryMessenger: BinaryMess
|
||||
}
|
||||
}
|
||||
|
||||
fun onDescriptorWrite(descriptor: BluetoothGattDescriptor, status: Int) {
|
||||
val hashCode = descriptor.hashCode()
|
||||
val descriptorArgs = descriptorsArgs[hashCode] as MyGattDescriptorArgs
|
||||
val descriptorHashCodeArgs = descriptorArgs.hashCodeArgs
|
||||
val callback = writeDescriptorCallbacks.remove(descriptorHashCodeArgs) ?: return
|
||||
fun onDescriptorWrite(gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int) {
|
||||
val device = gatt.device
|
||||
val addressArgs = device.address
|
||||
val hashCodeArgs = descriptor.hashCode().toLong()
|
||||
val callbacks = mWriteDescriptorCallbacks[addressArgs] ?: return
|
||||
val callback = callbacks.remove(hashCodeArgs) ?: return
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
callback(Result.success(Unit))
|
||||
} else {
|
||||
@ -641,4 +541,42 @@ class MyCentralManager(private val context: Context, binaryMessenger: BinaryMess
|
||||
callback(Result.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
private fun mClearState() {
|
||||
if (mDiscovering) {
|
||||
stopDiscovery()
|
||||
}
|
||||
for (gatt in mGATTs.values) {
|
||||
gatt.disconnect()
|
||||
}
|
||||
mDevices.clear()
|
||||
mGATTs.clear()
|
||||
mCharacteristics.clear()
|
||||
mDescriptors.clear()
|
||||
|
||||
mStartDiscoveryCallback = null
|
||||
mConnectCallbacks.clear()
|
||||
mDisconnectCallbacks.clear()
|
||||
mRequestMtuCallbacks.clear()
|
||||
mReadRssiCallbacks.clear()
|
||||
mDiscoverServicesCallbacks.clear()
|
||||
mReadCharacteristicCallbacks.clear()
|
||||
mWriteCharacteristicCallbacks.clear()
|
||||
mReadDescriptorCallbacks.clear()
|
||||
mWriteDescriptorCallbacks.clear()
|
||||
}
|
||||
|
||||
private fun mRetrieveCharacteristic(
|
||||
addressArgs: String, hashCodeArgs: Long
|
||||
): BluetoothGattCharacteristic? {
|
||||
val characteristics = mCharacteristics[addressArgs] ?: return null
|
||||
return characteristics[hashCodeArgs]
|
||||
}
|
||||
|
||||
private fun mRetrieveDescriptor(
|
||||
addressArgs: String, hashCodeArgs: Long
|
||||
): BluetoothGattDescriptor? {
|
||||
val descriptors = mDescriptors[addressArgs] ?: return null
|
||||
return descriptors[hashCodeArgs]
|
||||
}
|
||||
}
|
||||
|
@ -1,123 +1,109 @@
|
||||
package dev.yanshouwang.bluetooth_low_energy_android
|
||||
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
import android.bluetooth.BluetoothDevice
|
||||
import android.bluetooth.BluetoothGatt
|
||||
import android.bluetooth.BluetoothGattCharacteristic
|
||||
import android.bluetooth.BluetoothGattDescriptor
|
||||
import android.bluetooth.BluetoothGattServer
|
||||
import android.bluetooth.BluetoothGattServerCallback
|
||||
import android.bluetooth.BluetoothGattService
|
||||
import android.bluetooth.BluetoothProfile
|
||||
import android.bluetooth.BluetoothStatusCodes
|
||||
import android.bluetooth.le.AdvertiseCallback
|
||||
import android.bluetooth.le.AdvertiseSettings
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import io.flutter.plugin.common.BinaryMessenger
|
||||
|
||||
class MyPeripheralManager(private val context: Context, binaryMessenger: BinaryMessenger) : MyBluetoothLowEnergyManager(context), MyPeripheralManagerHostApi {
|
||||
class MyPeripheralManager(context: Context, binaryMessenger: BinaryMessenger) :
|
||||
MyBluetoothLowEnergyManager(context), MyPeripheralManagerHostApi {
|
||||
companion object {
|
||||
const val REQUEST_CODE = 444
|
||||
}
|
||||
|
||||
private val advertiser get() = adapter.bluetoothLeAdvertiser
|
||||
|
||||
private val api = MyPeripheralManagerFlutterApi(binaryMessenger)
|
||||
private val bluetoothGattServerCallback = MyBluetoothGattServerCallback(this, executor)
|
||||
private val advertiseCallback = MyAdvertiseCallback(this)
|
||||
private val mContext: Context
|
||||
private val mApi: MyPeripheralManagerFlutterApi
|
||||
|
||||
private val devices = mutableMapOf<Long, BluetoothDevice>()
|
||||
private val services = mutableMapOf<Long, BluetoothGattService>()
|
||||
private val characteristics = mutableMapOf<Long, BluetoothGattCharacteristic>()
|
||||
private val descriptors = mutableMapOf<Long, BluetoothGattDescriptor>()
|
||||
private val mtus = mutableMapOf<Long, Int>()
|
||||
private val confirms = mutableMapOf<Long, Boolean>()
|
||||
private val preparedCharacteristics = mutableMapOf<Int, BluetoothGattCharacteristic>()
|
||||
private val preparedValues = mutableMapOf<Int, ByteArray>()
|
||||
private val values = mutableMapOf<Long, ByteArray>()
|
||||
|
||||
private val centralsArgs = mutableMapOf<Int, MyCentralArgs>()
|
||||
private val servicesArgs = mutableMapOf<Int, MyGattServiceArgs>()
|
||||
private val characteristicsArgs = mutableMapOf<Int, MyGattCharacteristicArgs>()
|
||||
private val descriptorsArgs = mutableMapOf<Int, MyGattDescriptorArgs>()
|
||||
|
||||
private lateinit var server: BluetoothGattServer
|
||||
private var registered = false
|
||||
private var advertising = false
|
||||
|
||||
private var setUpCallback: ((Result<MyPeripheralManagerArgs>) -> Unit)? = null
|
||||
private var addServiceCallback: ((Result<Unit>) -> Unit)? = null
|
||||
private var startAdvertisingCallback: ((Result<Unit>) -> Unit)? = null
|
||||
private val notifyCharacteristicValueChangedCallbacks = mutableMapOf<Long, (Result<Unit>) -> Unit>()
|
||||
|
||||
override fun setUp(callback: (Result<MyPeripheralManagerArgs>) -> Unit) {
|
||||
try {
|
||||
val unfinishedCallback = setUpCallback
|
||||
if (unfinishedCallback != null) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
tearDown()
|
||||
if (unsupported) {
|
||||
val stateNumberArgs = MyBluetoothLowEnergyStateArgs.UNSUPPORTED.raw.toLong()
|
||||
val args = MyPeripheralManagerArgs(stateNumberArgs)
|
||||
callback(Result.success(args))
|
||||
}
|
||||
val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
arrayOf(android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT)
|
||||
} else {
|
||||
arrayOf(android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION)
|
||||
}
|
||||
authorize(permissions)
|
||||
setUpCallback = callback
|
||||
} catch (e: Throwable) {
|
||||
callback(Result.failure(e))
|
||||
}
|
||||
private val bluetoothGattServerCallback: BluetoothGattServerCallback by lazy {
|
||||
MyBluetoothGattServerCallback(this, executor)
|
||||
}
|
||||
private val advertiseCallback: AdvertiseCallback by lazy {
|
||||
MyAdvertiseCallback(this)
|
||||
}
|
||||
|
||||
private fun tearDown() {
|
||||
if (registered) {
|
||||
unregister()
|
||||
}
|
||||
if (advertising) {
|
||||
stopAdvertising()
|
||||
}
|
||||
devices.clear()
|
||||
services.clear()
|
||||
characteristics.clear()
|
||||
descriptors.clear()
|
||||
mtus.clear()
|
||||
confirms.clear()
|
||||
preparedCharacteristics.clear()
|
||||
preparedValues.clear()
|
||||
values.clear()
|
||||
centralsArgs.clear()
|
||||
servicesArgs.clear()
|
||||
characteristicsArgs.clear()
|
||||
descriptorsArgs.clear()
|
||||
setUpCallback = null
|
||||
addServiceCallback = null
|
||||
startAdvertisingCallback = null
|
||||
notifyCharacteristicValueChangedCallbacks.clear()
|
||||
private lateinit var mServer: BluetoothGattServer
|
||||
private var mOpening = false
|
||||
private var mAdvertising = false
|
||||
|
||||
private val mServicesArgs: MutableMap<Int, MyGattServiceArgs>
|
||||
private val mCharacteristicsArgs: MutableMap<Int, MyGattCharacteristicArgs>
|
||||
private val mDescriptorsArgs: MutableMap<Int, MyGattDescriptorArgs>
|
||||
|
||||
private val mDevices: MutableMap<String, BluetoothDevice>
|
||||
private val mServices: MutableMap<Long, BluetoothGattService>
|
||||
private val mCharacteristics: MutableMap<Long, BluetoothGattCharacteristic>
|
||||
private val mDescriptors: MutableMap<Long, BluetoothGattDescriptor>
|
||||
|
||||
private var mSetUpCallback: ((Result<Unit>) -> Unit)?
|
||||
private var mAddServiceCallback: ((Result<Unit>) -> Unit)?
|
||||
private var mStartAdvertisingCallback: ((Result<Unit>) -> Unit)?
|
||||
private val mNotifyCharacteristicValueChangedCallbacks: MutableMap<String, (Result<Unit>) -> Unit>
|
||||
|
||||
init {
|
||||
mContext = context
|
||||
mApi = MyPeripheralManagerFlutterApi(binaryMessenger)
|
||||
|
||||
mServicesArgs = mutableMapOf()
|
||||
mCharacteristicsArgs = mutableMapOf()
|
||||
mDescriptorsArgs = mutableMapOf()
|
||||
|
||||
mDevices = mutableMapOf()
|
||||
mServices = mutableMapOf()
|
||||
mCharacteristics = mutableMapOf()
|
||||
mDescriptors = mutableMapOf()
|
||||
|
||||
mSetUpCallback = null
|
||||
mAddServiceCallback = null
|
||||
mStartAdvertisingCallback = null
|
||||
mNotifyCharacteristicValueChangedCallbacks = mutableMapOf()
|
||||
}
|
||||
|
||||
override fun register() {
|
||||
super.register()
|
||||
registered = true
|
||||
}
|
||||
override val permissions: Array<String>
|
||||
get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
arrayOf(
|
||||
android.Manifest.permission.ACCESS_COARSE_LOCATION,
|
||||
android.Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
android.Manifest.permission.BLUETOOTH_ADVERTISE,
|
||||
android.Manifest.permission.BLUETOOTH_CONNECT
|
||||
)
|
||||
} else {
|
||||
arrayOf(
|
||||
android.Manifest.permission.ACCESS_COARSE_LOCATION,
|
||||
android.Manifest.permission.ACCESS_FINE_LOCATION
|
||||
)
|
||||
}
|
||||
|
||||
override fun unregister() {
|
||||
super.unregister()
|
||||
registered = false
|
||||
override val requestCode: Int
|
||||
get() = REQUEST_CODE
|
||||
|
||||
override fun setUp() {
|
||||
mClearState()
|
||||
initialize()
|
||||
}
|
||||
|
||||
override fun addService(serviceArgs: MyGattServiceArgs, callback: (Result<Unit>) -> Unit) {
|
||||
try {
|
||||
val unfinishedCallback = addServiceCallback
|
||||
if (unfinishedCallback != null) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
val service = serviceArgs.toService()
|
||||
val characteristicsArgs = serviceArgs.characteristicsArgs.filterNotNull()
|
||||
for (characteristicArgs in characteristicsArgs) {
|
||||
val characteristic = characteristicArgs.toCharacteristic()
|
||||
val cccDescriptor = BluetoothGattDescriptor(CLIENT_CHARACTERISTIC_CONFIG_UUID, BluetoothGattDescriptor.PERMISSION_READ or BluetoothGattDescriptor.PERMISSION_WRITE)
|
||||
val cccDescriptor = BluetoothGattDescriptor(
|
||||
CLIENT_CHARACTERISTIC_CONFIG_UUID,
|
||||
BluetoothGattDescriptor.PERMISSION_READ or BluetoothGattDescriptor.PERMISSION_WRITE
|
||||
)
|
||||
val cccDescriptorAdded = characteristic.addDescriptor(cccDescriptor)
|
||||
if (!cccDescriptorAdded) {
|
||||
throw IllegalStateException()
|
||||
@ -129,89 +115,68 @@ class MyPeripheralManager(private val context: Context, binaryMessenger: BinaryM
|
||||
// Already added.
|
||||
continue
|
||||
}
|
||||
val descriptorHashCodeArgs = descriptorArgs.hashCodeArgs
|
||||
val descriptorHashCode = descriptor.hashCode()
|
||||
this.mDescriptorsArgs[descriptorHashCode] = descriptorArgs
|
||||
this.mDescriptors[descriptorHashCodeArgs] = descriptor
|
||||
val descriptorAdded = characteristic.addDescriptor(descriptor)
|
||||
if (!descriptorAdded) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
val descriptorHashCodeArgs = descriptorArgs.hashCodeArgs
|
||||
val descriptorHashCode = descriptor.hashCode()
|
||||
this.descriptorsArgs[descriptorHashCode] = descriptorArgs
|
||||
this.descriptors[descriptorHashCodeArgs] = descriptor
|
||||
}
|
||||
val characteristicHashCodeArgs = characteristicArgs.hashCodeArgs
|
||||
val characteristicHashCode = characteristic.hashCode()
|
||||
this.mCharacteristicsArgs[characteristicHashCode] = characteristicArgs
|
||||
this.mCharacteristics[characteristicHashCodeArgs] = characteristic
|
||||
val characteristicAdded = service.addCharacteristic(characteristic)
|
||||
if (!characteristicAdded) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
val characteristicHashCodeArgs = characteristicArgs.hashCodeArgs
|
||||
val characteristicHashCode = characteristic.hashCode()
|
||||
this.characteristicsArgs[characteristicHashCode] = characteristicArgs
|
||||
this.characteristics[characteristicHashCodeArgs] = characteristic
|
||||
}
|
||||
val adding = server.addService(service)
|
||||
if (!adding) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
val serviceHashCodeArgs = serviceArgs.hashCodeArgs
|
||||
val serviceHashCode = service.hashCode()
|
||||
this.servicesArgs[serviceHashCode] = serviceArgs
|
||||
this.services[serviceHashCodeArgs] = service
|
||||
addServiceCallback = callback
|
||||
this.mServicesArgs[serviceHashCode] = serviceArgs
|
||||
this.mServices[serviceHashCodeArgs] = service
|
||||
val adding = mServer.addService(service)
|
||||
if (!adding) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
mAddServiceCallback = callback
|
||||
} catch (e: Throwable) {
|
||||
freeService(serviceArgs)
|
||||
mClearService(serviceArgs)
|
||||
callback(Result.failure(e))
|
||||
}
|
||||
}
|
||||
|
||||
override fun removeService(serviceHashCodeArgs: Long) {
|
||||
val service = services[serviceHashCodeArgs] as BluetoothGattService
|
||||
val serviceHashCode = service.hashCode()
|
||||
val serviceArgs = servicesArgs[serviceHashCode] as MyGattServiceArgs
|
||||
val removed = server.removeService(service)
|
||||
override fun removeService(hashCodeArgs: Long) {
|
||||
val service = mServices[hashCodeArgs] as BluetoothGattService
|
||||
val hashCode = service.hashCode()
|
||||
val serviceArgs = mServicesArgs[hashCode] as MyGattServiceArgs
|
||||
val removed = mServer.removeService(service)
|
||||
if (!removed) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
freeService(serviceArgs)
|
||||
}
|
||||
|
||||
private fun freeService(serviceArgs: MyGattServiceArgs) {
|
||||
val characteristicsArgs = serviceArgs.characteristicsArgs.filterNotNull()
|
||||
for (characteristicArgs in characteristicsArgs) {
|
||||
val descriptorsArgs = characteristicArgs.descriptorsArgs.filterNotNull()
|
||||
for (descriptorArgs in descriptorsArgs) {
|
||||
val descriptorHashCodeArgs = descriptorArgs.hashCodeArgs
|
||||
val descriptor = this.descriptors.remove(descriptorHashCodeArgs) ?: continue
|
||||
val descriptorHashCode = descriptor.hashCode()
|
||||
this.descriptorsArgs.remove(descriptorHashCode)
|
||||
}
|
||||
val characteristicHashCodeArgs = characteristicArgs.hashCodeArgs
|
||||
val characteristic = this.characteristics.remove(characteristicHashCodeArgs) ?: continue
|
||||
this.confirms.remove(characteristicHashCodeArgs)
|
||||
val characteristicHashCode = characteristic.hashCode()
|
||||
this.characteristicsArgs.remove(characteristicHashCode)
|
||||
}
|
||||
val serviceHashCodeArgs = serviceArgs.hashCodeArgs
|
||||
val service = services.remove(serviceHashCodeArgs) ?: return
|
||||
val serviceHashCode = service.hashCode()
|
||||
servicesArgs.remove(serviceHashCode)
|
||||
mClearService(serviceArgs)
|
||||
}
|
||||
|
||||
override fun clearServices() {
|
||||
server.clearServices()
|
||||
val servicesArgs = this.servicesArgs.values
|
||||
mServer.clearServices()
|
||||
val servicesArgs = this.mServicesArgs.values
|
||||
for (serviceArgs in servicesArgs) {
|
||||
freeService(serviceArgs)
|
||||
mClearService(serviceArgs)
|
||||
}
|
||||
}
|
||||
|
||||
override fun startAdvertising(advertisementArgs: MyAdvertisementArgs, callback: (Result<Unit>) -> Unit) {
|
||||
override fun startAdvertising(
|
||||
advertisementArgs: MyAdvertisementArgs, callback: (Result<Unit>) -> Unit
|
||||
) {
|
||||
try {
|
||||
if (startAdvertisingCallback != null) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
val settings = AdvertiseSettings.Builder().setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED).setConnectable(true).build()
|
||||
val settings = AdvertiseSettings.Builder()
|
||||
.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED).setConnectable(true)
|
||||
.build()
|
||||
val advertiseData = advertisementArgs.toAdvertiseData(adapter)
|
||||
advertiser.startAdvertising(settings, advertiseData, advertiseCallback)
|
||||
startAdvertisingCallback = callback
|
||||
mStartAdvertisingCallback = callback
|
||||
} catch (e: Throwable) {
|
||||
callback(Result.failure(e))
|
||||
}
|
||||
@ -219,264 +184,259 @@ class MyPeripheralManager(private val context: Context, binaryMessenger: BinaryM
|
||||
|
||||
override fun stopAdvertising() {
|
||||
advertiser.stopAdvertising(advertiseCallback)
|
||||
advertising = false
|
||||
mAdvertising = false
|
||||
}
|
||||
|
||||
override fun getMaximumWriteLength(centralHashCodeArgs: Long): Long {
|
||||
val mtu = mtus[centralHashCodeArgs] ?: 23
|
||||
val maximumWriteLength = (mtu - 3).coerceIn(20, 512)
|
||||
return maximumWriteLength.toLong()
|
||||
}
|
||||
|
||||
override fun sendReadCharacteristicReply(centralHashCodeArgs: Long, characteristicHashCodeArgs: Long, idArgs: Long, offsetArgs: Long, statusArgs: Boolean, valueArgs: ByteArray) {
|
||||
val device = devices[centralHashCodeArgs] as BluetoothDevice
|
||||
override fun sendResponse(
|
||||
addressArgs: String,
|
||||
idArgs: Long,
|
||||
statusNumberArgs: Long,
|
||||
offsetArgs: Long,
|
||||
valueArgs: ByteArray?
|
||||
) {
|
||||
val device = mDevices[addressArgs] as BluetoothDevice
|
||||
val requestId = idArgs.toInt()
|
||||
val status = if (statusArgs) BluetoothGatt.GATT_SUCCESS
|
||||
else BluetoothGatt.GATT_FAILURE
|
||||
val statusRawArgs = statusNumberArgs.toInt()
|
||||
val statusArgs = MyGattStatusArgs.ofRaw(statusRawArgs) ?: throw IllegalArgumentException()
|
||||
val status = statusArgs.toStatus()
|
||||
val offset = offsetArgs.toInt()
|
||||
val sent = server.sendResponse(device, requestId, status, offset, valueArgs)
|
||||
val sent = mServer.sendResponse(device, requestId, status, offset, valueArgs)
|
||||
if (!sent) {
|
||||
throw IllegalStateException("Send read characteristic reply failed.")
|
||||
}
|
||||
}
|
||||
|
||||
override fun sendWriteCharacteristicReply(centralHashCodeArgs: Long, characteristicHashCodeArgs: Long, idArgs: Long, offsetArgs: Long, statusArgs: Boolean) {
|
||||
val device = devices[centralHashCodeArgs] as BluetoothDevice
|
||||
val requestId = idArgs.toInt()
|
||||
val status = if (statusArgs) BluetoothGatt.GATT_SUCCESS
|
||||
else BluetoothGatt.GATT_FAILURE
|
||||
val offset = offsetArgs.toInt()
|
||||
val value = values.remove(idArgs) as ByteArray
|
||||
val sent = server.sendResponse(device, requestId, status, offset, value)
|
||||
if (!sent) {
|
||||
throw IllegalStateException("Send write characteristic reply failed.")
|
||||
}
|
||||
}
|
||||
|
||||
override fun notifyCharacteristicValueChanged(centralHashCodeArgs: Long, characteristicHashCodeArgs: Long, valueArgs: ByteArray, callback: (Result<Unit>) -> Unit) {
|
||||
override fun notifyCharacteristicChanged(
|
||||
hashCodeArgs: Long,
|
||||
valueArgs: ByteArray,
|
||||
confirmArgs: Boolean,
|
||||
addressArgs: String,
|
||||
callback: (Result<Unit>) -> Unit
|
||||
) {
|
||||
try {
|
||||
val unfinishedCallback = notifyCharacteristicValueChangedCallbacks[centralHashCodeArgs]
|
||||
if (unfinishedCallback != null) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
val device = devices[centralHashCodeArgs] as BluetoothDevice
|
||||
val characteristic = characteristics[characteristicHashCodeArgs] as BluetoothGattCharacteristic
|
||||
val confirm = confirms[characteristicHashCodeArgs]
|
||||
?: throw IllegalStateException("The characteristic is not subscribed.")
|
||||
val device = mDevices[addressArgs] as BluetoothDevice
|
||||
val characteristic = mCharacteristics[hashCodeArgs] as BluetoothGattCharacteristic
|
||||
val notifying = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
val statusCode = server.notifyCharacteristicChanged(device, characteristic, confirm, valueArgs)
|
||||
val statusCode = mServer.notifyCharacteristicChanged(
|
||||
device, characteristic, confirmArgs, valueArgs
|
||||
)
|
||||
statusCode == BluetoothStatusCodes.SUCCESS
|
||||
} else {
|
||||
// TODO: remove this when minSdkVersion >= 33
|
||||
characteristic.value = valueArgs
|
||||
server.notifyCharacteristicChanged(device, characteristic, confirm)
|
||||
mServer.notifyCharacteristicChanged(device, characteristic, confirmArgs)
|
||||
}
|
||||
if (!notifying) {
|
||||
throw IllegalStateException()
|
||||
}
|
||||
notifyCharacteristicValueChangedCallbacks[centralHashCodeArgs] = callback
|
||||
mNotifyCharacteristicValueChangedCallbacks[addressArgs] = callback
|
||||
} catch (e: Throwable) {
|
||||
callback(Result.failure(e))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(requestCode: Int, results: IntArray): Boolean {
|
||||
if (requestCode != REQUEST_CODE) {
|
||||
return false
|
||||
override fun onStateChanged(state: MyBluetoothLowEnergyState) {
|
||||
when (state) {
|
||||
MyBluetoothLowEnergyStateArgs.POWEREDOFF -> mCloseGattServer()
|
||||
MyBluetoothLowEnergyStateArgs.POWEREDON -> mOpenGattServer()
|
||||
else -> {}
|
||||
}
|
||||
val authorized = results.all { r -> r == PackageManager.PERMISSION_GRANTED }
|
||||
val callback = setUpCallback ?: return false
|
||||
setUpCallback = null
|
||||
val stateArgs = if (authorized) adapter.stateArgs
|
||||
else MyBluetoothLowEnergyStateArgs.UNAUTHORIZED
|
||||
val stateNumberArgs = stateArgs.raw.toLong()
|
||||
val args = MyPeripheralManagerArgs(stateNumberArgs)
|
||||
if (stateArgs == MyBluetoothLowEnergyStateArgs.POWEREDON) {
|
||||
server = manager.openGattServer(context, bluetoothGattServerCallback)
|
||||
}
|
||||
callback(Result.success(args))
|
||||
if (authorized) {
|
||||
register()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onReceive(intent: Intent) {
|
||||
val action = intent.action
|
||||
if (action != BluetoothAdapter.ACTION_STATE_CHANGED) {
|
||||
return
|
||||
}
|
||||
val state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF)
|
||||
val stateArgs = state.toBluetoothLowEnergyStateArgs()
|
||||
if (stateArgs == MyBluetoothLowEnergyStateArgs.POWEREDON) {
|
||||
server = manager.openGattServer(context, bluetoothGattServerCallback)
|
||||
}
|
||||
val stateNumberArgs = stateArgs.raw.toLong()
|
||||
api.onStateChanged(stateNumberArgs) {}
|
||||
val stateNumberArgs = state.raw.toLong()
|
||||
mApi.onStateChanged(stateNumberArgs) {}
|
||||
}
|
||||
|
||||
fun onServiceAdded(status: Int, service: BluetoothGattService) {
|
||||
val callback = addServiceCallback ?: return
|
||||
addServiceCallback = null
|
||||
val callback = mAddServiceCallback ?: return
|
||||
mAddServiceCallback = null
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
callback(Result.success(Unit))
|
||||
} else {
|
||||
val hashCode = service.hashCode()
|
||||
val serviceArgs = servicesArgs[hashCode] as MyGattServiceArgs
|
||||
freeService(serviceArgs)
|
||||
val error = IllegalStateException("Read rssi failed with status: $status")
|
||||
callback(Result.failure(error))
|
||||
val hashCode = service.hashCode()
|
||||
val serviceArgs = mServicesArgs[hashCode] ?: return
|
||||
mClearService(serviceArgs)
|
||||
}
|
||||
}
|
||||
|
||||
fun onStartSuccess(settingsInEffect: AdvertiseSettings) {
|
||||
advertising = true
|
||||
val callback = startAdvertisingCallback ?: return
|
||||
startAdvertisingCallback = null
|
||||
mAdvertising = true
|
||||
val callback = mStartAdvertisingCallback ?: return
|
||||
mStartAdvertisingCallback = null
|
||||
callback(Result.success(Unit))
|
||||
}
|
||||
|
||||
fun onStartFailure(errorCode: Int) {
|
||||
val callback = startAdvertisingCallback ?: return
|
||||
startAdvertisingCallback = null
|
||||
val callback = mStartAdvertisingCallback ?: return
|
||||
mStartAdvertisingCallback = null
|
||||
val error = IllegalStateException("Start advertising failed with error code: $errorCode")
|
||||
callback(Result.failure(error))
|
||||
}
|
||||
|
||||
fun onConnectionStateChange(device: BluetoothDevice, status: Int, newState: Int) {
|
||||
val hashCode = device.hashCode()
|
||||
val centralArgs = centralsArgs.getOrPut(hashCode) { device.toCentralArgs() }
|
||||
val centralHashCodeArgs = centralArgs.hashCodeArgs
|
||||
devices[centralHashCodeArgs] = device
|
||||
val centralArgs = device.toCentralArgs()
|
||||
val addressArgs = centralArgs.addressArgs
|
||||
val stateArgs = newState == BluetoothProfile.STATE_CONNECTED
|
||||
mDevices[addressArgs] = device
|
||||
mApi.onConnectionStateChanged(centralArgs, stateArgs) {}
|
||||
}
|
||||
|
||||
fun onMtuChanged(device: BluetoothDevice, mtu: Int) {
|
||||
val hashCode = device.hashCode()
|
||||
val centralArgs = centralsArgs.getOrPut(hashCode) { device.toCentralArgs() }
|
||||
val centralHashCodeArgs = centralArgs.hashCodeArgs
|
||||
devices[centralHashCodeArgs] = device
|
||||
mtus[centralHashCodeArgs] = mtu
|
||||
val addressArgs = device.address
|
||||
val mtuArgs = mtu.toLong()
|
||||
mApi.onMtuChanged(addressArgs, mtuArgs) {}
|
||||
}
|
||||
|
||||
fun onCharacteristicReadRequest(device: BluetoothDevice, requestId: Int, offset: Int, characteristic: BluetoothGattCharacteristic) {
|
||||
val deviceHashCode = device.hashCode()
|
||||
val centralArgs = centralsArgs.getOrPut(deviceHashCode) { device.toCentralArgs() }
|
||||
val centralHashCodeArgs = centralArgs.hashCodeArgs
|
||||
devices[centralHashCodeArgs] = device
|
||||
val characteristicHashCode = characteristic.hashCode()
|
||||
val characteristicArgs = characteristicsArgs[characteristicHashCode] as MyGattCharacteristicArgs
|
||||
fun onCharacteristicReadRequest(
|
||||
device: BluetoothDevice,
|
||||
requestId: Int,
|
||||
offset: Int,
|
||||
characteristic: BluetoothGattCharacteristic
|
||||
) {
|
||||
val addressArgs = device.address
|
||||
val hashCode = characteristic.hashCode()
|
||||
val characteristicArgs = mCharacteristicsArgs[hashCode] ?: return
|
||||
val hashCodeArgs = characteristicArgs.hashCodeArgs
|
||||
val idArgs = requestId.toLong()
|
||||
val offsetArgs = offset.toLong()
|
||||
api.onReadCharacteristicCommandReceived(centralArgs, characteristicArgs, idArgs, offsetArgs) {}
|
||||
mApi.onCharacteristicReadRequest(addressArgs, hashCodeArgs, idArgs, offsetArgs) {}
|
||||
}
|
||||
|
||||
fun onCharacteristicWriteRequest(device: BluetoothDevice, requestId: Int, characteristic: BluetoothGattCharacteristic, preparedWrite: Boolean, responseNeeded: Boolean, offset: Int, value: ByteArray) {
|
||||
val deviceHashCode = device.hashCode()
|
||||
val centralArgs = centralsArgs.getOrPut(deviceHashCode) { device.toCentralArgs() }
|
||||
val centralHashCodeArgs = centralArgs.hashCodeArgs
|
||||
devices[centralHashCodeArgs] = device
|
||||
if (preparedWrite) {
|
||||
val preparedCharacteristic = preparedCharacteristics[deviceHashCode]
|
||||
if (preparedCharacteristic != null && preparedCharacteristic != characteristic) {
|
||||
val status = BluetoothGatt.GATT_CONNECTION_CONGESTED
|
||||
server.sendResponse(device, requestId, status, offset, value)
|
||||
return
|
||||
}
|
||||
val preparedValue = preparedValues[deviceHashCode]
|
||||
if (preparedValue == null) {
|
||||
preparedCharacteristics[deviceHashCode] = characteristic
|
||||
preparedValues[deviceHashCode] = value
|
||||
} else {
|
||||
preparedValues[deviceHashCode] = preparedValue.plus(value)
|
||||
}
|
||||
val status = BluetoothGatt.GATT_SUCCESS
|
||||
server.sendResponse(device, requestId, status, offset, value)
|
||||
} else {
|
||||
val characteristicHashCode = characteristic.hashCode()
|
||||
val characteristicArgs = characteristicsArgs[characteristicHashCode] as MyGattCharacteristicArgs
|
||||
val idArgs = requestId.toLong()
|
||||
val offsetArgs = offset.toLong()
|
||||
values[idArgs] = value
|
||||
api.onWriteCharacteristicCommandReceived(centralArgs, characteristicArgs, idArgs, offsetArgs, value) {}
|
||||
}
|
||||
fun onCharacteristicWriteRequest(
|
||||
device: BluetoothDevice,
|
||||
requestId: Int,
|
||||
characteristic: BluetoothGattCharacteristic,
|
||||
preparedWrite: Boolean,
|
||||
responseNeeded: Boolean,
|
||||
offset: Int,
|
||||
value: ByteArray
|
||||
) {
|
||||
val addressArgs = device.address
|
||||
val hashCode = characteristic.hashCode()
|
||||
val characteristicArgs = mCharacteristicsArgs[hashCode] ?: return
|
||||
val hashCodeArgs = characteristicArgs.hashCodeArgs
|
||||
val idArgs = requestId.toLong()
|
||||
val offsetArgs = offset.toLong()
|
||||
mApi.onCharacteristicWriteRequest(
|
||||
addressArgs, hashCodeArgs, idArgs, offsetArgs, value, preparedWrite, responseNeeded
|
||||
) {}
|
||||
}
|
||||
|
||||
fun onExecuteWrite(device: BluetoothDevice, requestId: Int, execute: Boolean) {
|
||||
val deviceHashCode = device.hashCode()
|
||||
val centralArgs = centralsArgs[deviceHashCode] as MyCentralArgs
|
||||
val characteristic = preparedCharacteristics.remove(deviceHashCode) as BluetoothGattCharacteristic
|
||||
val characteristicHashCode = characteristic.hashCode()
|
||||
val characteristicArgs = characteristicsArgs[characteristicHashCode] as MyGattCharacteristicArgs
|
||||
val value = preparedValues.remove(deviceHashCode) as ByteArray
|
||||
if (execute) {
|
||||
val idArgs = requestId.toLong()
|
||||
val offsetArgs = 0L
|
||||
values[idArgs] = value
|
||||
api.onWriteCharacteristicCommandReceived(centralArgs, characteristicArgs, idArgs, offsetArgs, value) {}
|
||||
} else {
|
||||
val status = BluetoothGatt.GATT_SUCCESS
|
||||
val offset = 0
|
||||
server.sendResponse(device, requestId, status, offset, value)
|
||||
}
|
||||
val addressArgs = device.address
|
||||
val idArgs = requestId.toLong()
|
||||
mApi.onExecuteWrite(addressArgs, idArgs, execute) {}
|
||||
}
|
||||
|
||||
fun onDescriptorReadRequest(device: BluetoothDevice, requestId: Int, offset: Int, descriptor: BluetoothGattDescriptor) {
|
||||
fun onDescriptorReadRequest(
|
||||
device: BluetoothDevice, requestId: Int, offset: Int, descriptor: BluetoothGattDescriptor
|
||||
) {
|
||||
val status = BluetoothGatt.GATT_SUCCESS
|
||||
val descriptorHashCode = descriptor.hashCode()
|
||||
val descriptorArgs = descriptorsArgs[descriptorHashCode] as MyGattDescriptorArgs
|
||||
val hashCode = descriptor.hashCode()
|
||||
val descriptorArgs = mDescriptorsArgs[hashCode] as MyGattDescriptorArgs
|
||||
val value = descriptorArgs.valueArgs
|
||||
val sent = server.sendResponse(device, requestId, status, offset, value)
|
||||
val sent = mServer.sendResponse(device, requestId, status, offset, value)
|
||||
if (!sent) {
|
||||
Log.e(TAG, "onDescriptorReadRequest: send response failed.")
|
||||
}
|
||||
}
|
||||
|
||||
fun onDescriptorWriteRequest(device: BluetoothDevice, requestId: Int, descriptor: BluetoothGattDescriptor, preparedWrite: Boolean, responseNeeded: Boolean, offset: Int, value: ByteArray) {
|
||||
val status = if (descriptor.uuid == CLIENT_CHARACTERISTIC_CONFIG_UUID) {
|
||||
val deviceHashCode = device.hashCode()
|
||||
val centralArgs = centralsArgs.getOrPut(deviceHashCode) { device.toCentralArgs() }
|
||||
val centralHashCodeArgs = centralArgs.hashCodeArgs
|
||||
devices[centralHashCodeArgs] = device
|
||||
fun onDescriptorWriteRequest(
|
||||
device: BluetoothDevice,
|
||||
requestId: Int,
|
||||
descriptor: BluetoothGattDescriptor,
|
||||
preparedWrite: Boolean,
|
||||
responseNeeded: Boolean,
|
||||
offset: Int,
|
||||
value: ByteArray
|
||||
) {
|
||||
if (descriptor.uuid == CLIENT_CHARACTERISTIC_CONFIG_UUID) {
|
||||
val addressArgs = device.address
|
||||
val characteristic = descriptor.characteristic
|
||||
val characteristicHashCode = characteristic.hashCode()
|
||||
val characteristicArgs = characteristicsArgs[characteristicHashCode] as MyGattCharacteristicArgs
|
||||
val characteristicHashCodeArgs = characteristicArgs.hashCodeArgs
|
||||
// TODO: what is 中缀?
|
||||
if (value contentEquals BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE) {
|
||||
confirms[characteristicHashCodeArgs] = false
|
||||
val stateArgs = true
|
||||
api.onNotifyCharacteristicCommandReceived(centralArgs, characteristicArgs, stateArgs) {}
|
||||
BluetoothGatt.GATT_SUCCESS
|
||||
} else if (value contentEquals BluetoothGattDescriptor.ENABLE_INDICATION_VALUE) {
|
||||
confirms[characteristicHashCodeArgs] = true
|
||||
val stateArgs = true
|
||||
api.onNotifyCharacteristicCommandReceived(centralArgs, characteristicArgs, stateArgs) {}
|
||||
BluetoothGatt.GATT_SUCCESS
|
||||
} else if (value contentEquals BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE) {
|
||||
confirms.remove(characteristicHashCodeArgs)
|
||||
val stateArgs = false
|
||||
api.onNotifyCharacteristicCommandReceived(centralArgs, characteristicArgs, stateArgs) {}
|
||||
BluetoothGatt.GATT_SUCCESS
|
||||
} else {
|
||||
BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED
|
||||
val hashCode = characteristic.hashCode()
|
||||
val characteristicArgs = mCharacteristicsArgs[hashCode] ?: return
|
||||
val hashCodeArgs = characteristicArgs.hashCodeArgs
|
||||
val stateArgs = value.toNotifyStateArgs()
|
||||
val stateNumberArgs = stateArgs.raw.toLong()
|
||||
mApi.onCharacteristicNotifyStateChanged(
|
||||
addressArgs, hashCodeArgs, stateNumberArgs
|
||||
) {}
|
||||
}
|
||||
if (responseNeeded) {
|
||||
val status = BluetoothGatt.GATT_SUCCESS
|
||||
val sent = mServer.sendResponse(device, requestId, status, offset, value)
|
||||
if (!sent) {
|
||||
Log.e(TAG, "onDescriptorReadRequest: send response failed.")
|
||||
}
|
||||
} else BluetoothGatt.GATT_SUCCESS
|
||||
val sent = server.sendResponse(device, requestId, status, offset, value)
|
||||
if (!sent) {
|
||||
Log.e(TAG, "onDescriptorReadRequest: send response failed.")
|
||||
}
|
||||
}
|
||||
|
||||
fun onNotificationSent(device: BluetoothDevice, status: Int) {
|
||||
val deviceHashCode = device.hashCode()
|
||||
val centralArgs = centralsArgs[deviceHashCode] as MyCentralArgs
|
||||
val centralHashCodeArgs = centralArgs.hashCodeArgs
|
||||
val callback = notifyCharacteristicValueChangedCallbacks.remove(centralHashCodeArgs)
|
||||
?: return
|
||||
val addressArgs = device.address
|
||||
val callback = mNotifyCharacteristicValueChangedCallbacks.remove(addressArgs) ?: return
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
callback(Result.success(Unit))
|
||||
} else {
|
||||
val error = IllegalStateException("Notify characteristic value changed failed with status: $status")
|
||||
val error =
|
||||
IllegalStateException("Notify characteristic value changed failed with status: $status")
|
||||
callback(Result.failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
private fun mClearState() {
|
||||
if (mAdvertising) {
|
||||
stopAdvertising()
|
||||
}
|
||||
|
||||
mServicesArgs.clear()
|
||||
mCharacteristicsArgs.clear()
|
||||
mDescriptorsArgs.clear()
|
||||
|
||||
mDevices.clear()
|
||||
mServices.clear()
|
||||
mCharacteristics.clear()
|
||||
mDescriptors.clear()
|
||||
|
||||
mSetUpCallback = null
|
||||
mAddServiceCallback = null
|
||||
mStartAdvertisingCallback = null
|
||||
mNotifyCharacteristicValueChangedCallbacks.clear()
|
||||
}
|
||||
|
||||
private fun mOpenGattServer() {
|
||||
if (mOpening) {
|
||||
return
|
||||
}
|
||||
mServer = manager.openGattServer(mContext, bluetoothGattServerCallback)
|
||||
mOpening = true
|
||||
}
|
||||
|
||||
private fun mCloseGattServer() {
|
||||
if (!mOpening) {
|
||||
return
|
||||
}
|
||||
mServer.close()
|
||||
mOpening = false
|
||||
}
|
||||
|
||||
private fun mClearService(serviceArgs: MyGattServiceArgs) {
|
||||
val characteristicsArgs = serviceArgs.characteristicsArgs.filterNotNull()
|
||||
for (characteristicArgs in characteristicsArgs) {
|
||||
val descriptorsArgs = characteristicArgs.descriptorsArgs.filterNotNull()
|
||||
for (descriptorArgs in descriptorsArgs) {
|
||||
val descriptorHashCodeArgs = descriptorArgs.hashCodeArgs
|
||||
val descriptor = mDescriptors.remove(descriptorHashCodeArgs) ?: continue
|
||||
val descriptorHashCode = descriptor.hashCode()
|
||||
mDescriptorsArgs.remove(descriptorHashCode)
|
||||
}
|
||||
val characteristicHashCodeArgs = characteristicArgs.hashCodeArgs
|
||||
val characteristic = mCharacteristics.remove(characteristicHashCodeArgs) ?: continue
|
||||
val characteristicHashCode = characteristic.hashCode()
|
||||
mCharacteristicsArgs.remove(characteristicHashCode)
|
||||
}
|
||||
val serviceHashCodeArgs = serviceArgs.hashCodeArgs
|
||||
val service = mServices.remove(serviceHashCodeArgs) ?: return
|
||||
val serviceHashCode = service.hashCode()
|
||||
mServicesArgs.remove(serviceHashCode)
|
||||
}
|
||||
}
|
@ -2,8 +2,17 @@ package dev.yanshouwang.bluetooth_low_energy_android
|
||||
|
||||
import io.flutter.plugin.common.PluginRegistry.RequestPermissionsResultListener
|
||||
|
||||
class MyRequestPermissionResultListener(private val bluetoothLowEnergyManager: MyBluetoothLowEnergyManager) : RequestPermissionsResultListener {
|
||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, results: IntArray): Boolean {
|
||||
return bluetoothLowEnergyManager.onRequestPermissionsResult(requestCode, results)
|
||||
class MyRequestPermissionResultListener(manager: MyBluetoothLowEnergyManager) :
|
||||
RequestPermissionsResultListener {
|
||||
private val mManager: MyBluetoothLowEnergyManager
|
||||
|
||||
init {
|
||||
mManager = manager
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int, permissions: Array<out String>, results: IntArray
|
||||
): Boolean {
|
||||
return mManager.onRequestPermissionsResult(requestCode, permissions, results)
|
||||
}
|
||||
}
|
@ -3,14 +3,20 @@ package dev.yanshouwang.bluetooth_low_energy_android
|
||||
import android.bluetooth.le.ScanCallback
|
||||
import android.bluetooth.le.ScanResult
|
||||
|
||||
class MyScanCallback(private val centralManager: MyCentralManager) : ScanCallback() {
|
||||
class MyScanCallback(manager: MyCentralManager) : ScanCallback() {
|
||||
private val mManager: MyCentralManager
|
||||
|
||||
init {
|
||||
mManager = manager
|
||||
}
|
||||
|
||||
override fun onScanFailed(errorCode: Int) {
|
||||
super.onScanFailed(errorCode)
|
||||
centralManager.onScanFailed(errorCode)
|
||||
mManager.onScanFailed(errorCode)
|
||||
}
|
||||
|
||||
override fun onScanResult(callbackType: Int, result: ScanResult) {
|
||||
super.onScanResult(callbackType, result)
|
||||
centralManager.onScanResult(result)
|
||||
mManager.onScanResult(result)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user