Skip to content

Commit 62922c2

Browse files
fix(android): respond to descriptor write (#76)
Signed-off-by: Berend Sliedrecht <[email protected]>
1 parent 852913a commit 62922c2

File tree

14 files changed

+756
-496
lines changed

14 files changed

+756
-496
lines changed
Lines changed: 5 additions & 227 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,12 @@
11
package com.reactnativebledidcomm
22

3-
import android.annotation.SuppressLint
4-
import android.bluetooth.*
5-
import android.bluetooth.le.AdvertiseCallback
6-
import android.bluetooth.le.ScanCallback
7-
import android.bluetooth.le.ScanResult
8-
import android.util.Log
93
import androidx.annotation.RequiresPermission
104
import com.facebook.react.bridge.*
11-
import com.facebook.react.modules.core.DeviceEventManagerModule
125
import com.reactnativebledidcomm.central.CentralManager
136
import com.reactnativebledidcomm.central.CentralManagerException
147
import com.reactnativebledidcomm.peripheral.PeripheralManager
158
import com.reactnativebledidcomm.peripheral.PeripheralManagerException
16-
import java.util.*
9+
import java.util.UUID
1710

1811
class BleDidcommModule(private val context: ReactApplicationContext) :
1912
ReactContextBaseJavaModule(context) {
@@ -44,7 +37,7 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
4437
promise: Promise,
4538
) {
4639
try {
47-
this.peripheralManager = PeripheralManager(context, gattServerCallback)
40+
this.peripheralManager = PeripheralManager(context)
4841
promise.resolve(null)
4942
} catch (e: Exception) {
5043
promise.reject("error", e)
@@ -127,7 +120,7 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
127120
try {
128121
val centralManager =
129122
this.centralManager ?: throw CentralManagerException.NotStarted()
130-
centralManager.scan(bluetoothScanCallback)
123+
centralManager.scan()
131124
promise.resolve(null)
132125
} catch (e: Exception) {
133126
promise.reject("error", e)
@@ -140,7 +133,7 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
140133
try {
141134
val peripheralManager =
142135
this.peripheralManager ?: throw PeripheralManagerException.NotStarted()
143-
peripheralManager.advertise(deviceAdvertiseCallback)
136+
peripheralManager.advertise()
144137
promise.resolve(null)
145138
} catch (e: Exception) {
146139
promise.reject("error", e)
@@ -153,7 +146,7 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
153146
try {
154147
val centralManager =
155148
this.centralManager ?: throw CentralManagerException.NotStarted()
156-
centralManager.connect(peripheralId, gattClientCallback)
149+
centralManager.connect(peripheralId)
157150
promise.resolve(null)
158151
} catch (e: Exception) {
159152
promise.reject("error", e)
@@ -193,219 +186,4 @@ class BleDidcommModule(private val context: ReactApplicationContext) :
193186
@ReactMethod
194187
fun removeListeners(@Suppress("UNUSED_PARAMETER") count: Int) {
195188
}
196-
197-
private fun sendEvent(event: BleDidcommEvent, params: WritableMap?) {
198-
this.context
199-
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
200-
.emit(event.token, params)
201-
}
202-
203-
private val gattClientCallback = object : BluetoothGattCallback() {
204-
var message: ByteArray = byteArrayOf()
205-
206-
// Triggered when client receives an indication
207-
override fun onCharacteristicChanged(
208-
gatt: BluetoothGatt,
209-
characteristic: BluetoothGattCharacteristic,
210-
) {
211-
super.onCharacteristicChanged(gatt, characteristic)
212-
val msg = characteristic.value
213-
if (msg.toString(Charsets.UTF_8) == "EOM") {
214-
val params = Arguments.createMap().apply {
215-
putString("message", message.toString(Charsets.UTF_8))
216-
}
217-
sendEvent(BleDidcommEvent.OnReceivedNotification, params)
218-
message = byteArrayOf()
219-
} else {
220-
message += msg
221-
}
222-
}
223-
224-
// Triggered when the client is ready to send the next message
225-
override fun onCharacteristicWrite(
226-
gatt: BluetoothGatt,
227-
characteristic: BluetoothGattCharacteristic,
228-
status: Int,
229-
) {
230-
super.onCharacteristicWrite(gatt, characteristic, status)
231-
if (status == BluetoothGatt.GATT_SUCCESS) {
232-
centralManager?.isPeripheralReady = true
233-
}
234-
}
235-
236-
// Triggered when the MTU has been changed.
237-
@SuppressLint("MissingPermission")
238-
override fun onMtuChanged(gatt: BluetoothGatt, mtu: Int, status: Int) {
239-
super.onMtuChanged(gatt, mtu, status)
240-
if (status != BluetoothGatt.GATT_SUCCESS) {
241-
Log.e(Constants.TAG, "error occurred while requesting MTU. Status $status")
242-
return
243-
}
244-
centralManager?.connectedMtu = mtu
245-
gatt.discoverServices()
246-
}
247-
248-
// Triggered when client discovered services
249-
@SuppressLint("MissingPermission")
250-
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
251-
super.onServicesDiscovered(gatt, status)
252-
val service = gatt.getService(centralManager?.serviceUUID)
253-
254-
centralManager?.writeCharacteristic =
255-
service.getCharacteristic(centralManager?.writeCharacteristicUUID)
256-
257-
centralManager?.indicationCharacteristic =
258-
service.getCharacteristic(centralManager?.indicationCharacteristicUUID)
259-
260-
val indicationCharacteristic = centralManager?.indicationCharacteristic ?: return
261-
gatt.setCharacteristicNotification(indicationCharacteristic, true)
262-
val descriptor = indicationCharacteristic.getDescriptor(UUID.fromString(Constants.CCC_DESCRIPTOR_UUID))
263-
descriptor?.value = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE
264-
gatt.writeDescriptor(descriptor)
265-
}
266-
267-
// Triggered when the connection state is updated
268-
@SuppressLint("MissingPermission")
269-
override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int, newState: Int) {
270-
super.onConnectionStateChange(gatt, status, newState)
271-
val params = Arguments.createMap().apply {
272-
putString("identifier", gatt.device.address)
273-
}
274-
if (newState == BluetoothProfile.STATE_CONNECTED) {
275-
gatt.requestMtu(512)
276-
centralManager?.stopScan()
277-
sendEvent(BleDidcommEvent.OnConnectedPeripheral, params)
278-
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
279-
sendEvent(BleDidcommEvent.OnDisconnectedPeripheral, params)
280-
centralManager?.connectedPeripheral = null
281-
}
282-
}
283-
}
284-
285-
private val bluetoothScanCallback = object : ScanCallback() {
286-
override fun onScanResult(callbackType: Int, result: ScanResult?) {
287-
super.onScanResult(callbackType, result)
288-
val device = result?.device ?: return
289-
centralManager?.discoveredPeripherals?.add(device)
290-
val params = Arguments.createMap().apply {
291-
putString("identifier", device.address)
292-
}
293-
sendEvent(BleDidcommEvent.OnDiscoverPeripheral, params)
294-
}
295-
}
296-
297-
private val gattServerCallback = object : BluetoothGattServerCallback() {
298-
var message: ByteArray = byteArrayOf()
299-
300-
// Triggered when the mtu is updated for the peripheral
301-
override fun onMtuChanged(device: BluetoothDevice, mtu: Int) {
302-
super.onMtuChanged(device, mtu)
303-
peripheralManager?.connectedMtu = mtu
304-
}
305-
306-
// Triggered the peripheral received a write request.
307-
// It appends it to a buffer and when "EOM" is received, it will emit a React Native event
308-
@SuppressLint("MissingPermission")
309-
override fun onCharacteristicWriteRequest(
310-
device: BluetoothDevice,
311-
requestId: Int,
312-
characteristic: BluetoothGattCharacteristic?,
313-
preparedWrite: Boolean,
314-
responseNeeded: Boolean,
315-
offset: Int,
316-
value: ByteArray,
317-
) {
318-
super.onCharacteristicWriteRequest(
319-
device,
320-
requestId,
321-
characteristic,
322-
preparedWrite,
323-
responseNeeded,
324-
offset,
325-
value,
326-
)
327-
328-
if ("EOM" == value.toString(Charsets.UTF_8)) {
329-
val params = Arguments.createMap().apply {
330-
putString("message", message.toString(Charsets.UTF_8))
331-
}
332-
sendEvent(BleDidcommEvent.OnReceivedWriteWithoutResponse, params)
333-
message = byteArrayOf()
334-
} else {
335-
message += value
336-
}
337-
338-
if (responseNeeded) {
339-
peripheralManager?.gattServer?.sendResponse(
340-
device,
341-
requestId,
342-
BluetoothGatt.GATT_SUCCESS,
343-
offset,
344-
value,
345-
)
346-
}
347-
}
348-
349-
override fun onDescriptorWriteRequest(
350-
device: BluetoothDevice,
351-
requestId: Int,
352-
descriptor: BluetoothGattDescriptor,
353-
preparedWrite: Boolean,
354-
responseNeeded: Boolean,
355-
offset: Int,
356-
value: ByteArray,
357-
) {
358-
super.onDescriptorWriteRequest(
359-
device,
360-
requestId,
361-
descriptor,
362-
preparedWrite,
363-
responseNeeded,
364-
offset,
365-
value,
366-
)
367-
val params = Arguments.createMap().apply {
368-
putString("identifier", device.address)
369-
}
370-
sendEvent(BleDidcommEvent.OnConnectedCentral, params)
371-
}
372-
373-
// Triggered when the peripheral is ready to send again
374-
override fun onNotificationSent(device: BluetoothDevice?, status: Int) {
375-
super.onNotificationSent(device, status)
376-
if (status == BluetoothGatt.GATT_SUCCESS) {
377-
peripheralManager?.isConnectedClientReady = true
378-
}
379-
}
380-
381-
// TODO: can we do this without this function?
382-
@SuppressLint("MissingPermission")
383-
override fun onExecuteWrite(device: BluetoothDevice?, requestId: Int, execute: Boolean) {
384-
super.onExecuteWrite(device, requestId, execute)
385-
peripheralManager?.gattServer?.sendResponse(
386-
device,
387-
requestId,
388-
BluetoothGatt.GATT_SUCCESS,
389-
0,
390-
null,
391-
)
392-
}
393-
394-
// Triggered when the connection state is updated for the peripheral
395-
@SuppressLint("MissingPermission")
396-
override fun onConnectionStateChange(device: BluetoothDevice, status: Int, newState: Int) {
397-
super.onConnectionStateChange(device, status, newState)
398-
if (newState == BluetoothProfile.STATE_CONNECTED) {
399-
peripheralManager?.connectedClient = device
400-
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
401-
peripheralManager?.connectedClient = null
402-
val params = Arguments.createMap().apply {
403-
putString("identifier", device.address)
404-
}
405-
sendEvent(BleDidcommEvent.OnDisconnectedCentral, params)
406-
}
407-
}
408-
}
409-
410-
private val deviceAdvertiseCallback = object : AdvertiseCallback() {}
411189
}

0 commit comments

Comments
 (0)