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:
iAMD
2023-12-31 00:53:48 +08:00
committed by GitHub
parent cfe0eda4a3
commit 87fe3e2447
137 changed files with 14108 additions and 8393 deletions

View File

@ -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) {

View File

@ -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)
}
}

View File

@ -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)))
}
}
}

View File

@ -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()
// }

View File

@ -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)
}
}
}

View File

@ -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
)
}
}
}

View File

@ -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)
}

View File

@ -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)
}
}

View File

@ -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]
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}