@@ -60,50 +60,49 @@ class CentralManager(private val context: ReactContext) {
6060 var characteristicWriteUUID: UUID ? = null
6161 var characteristicIndicationUUID: UUID ? = null
6262
63+ private val scanSettings = ScanSettings
64+ .Builder ()
65+ .setScanMode(ScanSettings .SCAN_MODE_BALANCED )
66+ .setReportDelay(0 )
67+ .build()
68+
6369 fun setService (
6470 serviceUUID : UUID ,
6571 writeCharacteristicUUID : UUID ,
6672 indicationCharacteristicUUID : UUID ,
6773 ) {
6874 this .serviceUUID = serviceUUID
69- this . characteristicWriteUUID = writeCharacteristicUUID
70- this . characteristicIndicationUUID = indicationCharacteristicUUID
75+ characteristicWriteUUID = writeCharacteristicUUID
76+ characteristicIndicationUUID = indicationCharacteristicUUID
7177 }
7278
7379 @SuppressLint(" MissingPermission" )
7480 fun shutdownCentral () {
7581 try {
76- this .stopScan()
77- this .connectedGatt?.disconnect( )
78- this .connectedGatt?.close()
79- } catch (e : CentralManagerException . NotScanning ) {
80- // Not Scanning
81- } catch (e : Exception ) {
82- // Error we don't care about
82+ characteristicIndication?. let {
83+ unsubscribeFromCharacteristic(it )
84+ }
85+ stopScan()
86+ connectedGatt?.disconnect()
87+ connectedGatt?.close()
88+ } catch (_ : Exception ) {
8389 } finally {
84- this . serviceUUID = null
85- this . characteristicWriteUUID = null
86- this . characteristicIndicationUUID = null
87- this . connectedGatt = null
88- this . discoveredPeripherals.clear()
90+ serviceUUID = null
91+ characteristicWriteUUID = null
92+ characteristicIndicationUUID = null
93+ connectedGatt = null
94+ discoveredPeripherals.clear()
8995 }
9096 }
9197
9298 @RequiresPermission(value = " android.permission.BLUETOOTH_SCAN" )
9399 fun scan () {
94- val serviceUUID = this .serviceUUID
95- ? : throw CentralManagerException .NoService ()
96-
97- val settings = ScanSettings
98- .Builder ()
99- .setScanMode(ScanSettings .SCAN_MODE_BALANCED )
100- .setReportDelay(0 )
101- .build()
100+ val serviceUUID = serviceUUID ? : throw CentralManagerException .NoService ()
102101
103102 val filter = ScanFilter .Builder ().setServiceUuid(ParcelUuid (serviceUUID)).build()
104103 val filters = listOf (filter)
105104
106- bleScanner.startScan(filters, settings , scanCallback)
105+ bleScanner.startScan(filters, scanSettings , scanCallback)
107106 }
108107
109108 @RequiresPermission(value = " android.permission.BLUETOOTH_SCAN" )
@@ -123,6 +122,10 @@ class CentralManager(private val context: ReactContext) {
123122 @RequiresPermission(value = " android.permission.BLUETOOTH_CONNECT" )
124123 fun write (message : ByteArray ) {
125124 Log .d(Constants .TAG , " [CENTRAL]: Sending message of ${message.size} bytes." )
125+ val chunkSize =
126+ min(connectedMtu - Constants .NUMBER_OF_BYTES_FOR_DATA_HEADER , message.count())
127+ Log .d(Constants .TAG , " [CENTRAL]: Using a chunk size of $chunkSize . Sending ${message.size / chunkSize + 1 } messages." )
128+
126129 if (isSending) throw CentralManagerException .AlreadySending ()
127130 val characteristic =
128131 characteristicWrite ? : throw CentralManagerException .NoCharacteristicFound ()
@@ -138,29 +141,31 @@ class CentralManager(private val context: ReactContext) {
138141
139142 Thread {
140143 isSending = true
141- val chunkSize =
142- min(connectedMtu - Constants .NUMBER_OF_BYTES_FOR_DATA_HEADER , message.count())
144+
143145 for (chunkIndexStart in 0 .. message.count() step chunkSize) {
144146 val chunkIndexEnd = min(chunkIndexStart + chunkSize, message.count()) - 1
145147 val chunkedMessage = message.sliceArray(IntRange (chunkIndexStart, chunkIndexEnd))
148+ if (chunkedMessage.isEmpty()) {
149+ continue
150+ }
146151 characteristic.value = chunkedMessage
147152 while (! isPeripheralReady) {
148153 Thread .sleep(20 )
149154 }
150155 Log .d(
151156 Constants .TAG ,
152- " [CENTRAL]: Sending chunked message of ${chunkedMessage.size} bytes."
157+ " [CENTRAL]: Sending chunked message of ${chunkedMessage.size} bytes." ,
153158 )
154159 val didSend = connectedPeripheral.writeCharacteristic(characteristic)
155160 if (didSend) {
156161 Log .d(
157162 Constants .TAG ,
158- " [CENTRAL]: Send the message"
163+ " [CENTRAL]: Sent the message" ,
159164 )
160165 } else {
161166 Log .d(
162167 Constants .TAG ,
163- " [CENTRAL]: Did not send the message"
168+ " [CENTRAL]: Did not sent the message" ,
164169 )
165170 }
166171 isPeripheralReady = false
@@ -176,17 +181,11 @@ class CentralManager(private val context: ReactContext) {
176181 }
177182
178183 @SuppressLint(" MissingPermission" )
179- private fun subscribeToIndication (
180- characteristic : BluetoothGattCharacteristic ,
181- gatt : BluetoothGatt
182- ) {
184+ private fun subscribeToIndications (characteristic : BluetoothGattCharacteristic , gatt : BluetoothGatt ) {
183185 val cccdUuid = UUID .fromString(Constants .CCC_DESCRIPTOR_UUID )
184186 characteristic.getDescriptor(cccdUuid)?.let { cccDescriptor ->
185187 if (! gatt.setCharacteristicNotification(characteristic, true )) {
186- Log .e(
187- Constants .TAG ,
188- " [CENTRAL]: Could not set notifications for characteristic ${characteristic.uuid} "
189- )
188+ Log .e(Constants .TAG , " [CENTRAL]: setNotification(true) failed for ${characteristic.uuid} " )
190189 return
191190 }
192191 cccDescriptor.value = BluetoothGattDescriptor .ENABLE_INDICATION_VALUE
@@ -201,10 +200,7 @@ class CentralManager(private val context: ReactContext) {
201200 val cccdUuid = UUID .fromString(Constants .CCC_DESCRIPTOR_UUID )
202201 characteristic.getDescriptor(cccdUuid)?.let { cccDescriptor ->
203202 if (! gatt.setCharacteristicNotification(characteristic, false )) {
204- Log .e(
205- Constants .TAG ,
206- " [CENTRAL]: Could not unsubscribe from characteristic ${characteristic.uuid} "
207- )
203+ Log .e(Constants .TAG , " [CENTRAL]: setNotification(false) failed for ${characteristic.uuid} " )
208204 return
209205 }
210206 cccDescriptor.value = BluetoothGattDescriptor .DISABLE_NOTIFICATION_VALUE
@@ -220,17 +216,16 @@ class CentralManager(private val context: ReactContext) {
220216 override fun onConnectionStateChange (gatt : BluetoothGatt , status : Int , newState : Int ) {
221217 Log .d(
222218 Constants .TAG ,
223- " [CENTRAL]: Connection state has been changed to $newState with status $status "
219+ " [CENTRAL]: Connection state has been changed to $newState with status $status " ,
224220 )
225221
226222 if (status == BluetoothGatt .GATT_SUCCESS ) {
227223 val params = Arguments .createMap().apply {
228224 putString(" identifier" , gatt.device.address)
229225 }
230226 if (newState == BluetoothProfile .STATE_CONNECTED ) {
231- gatt.requestMtu( 512 )
227+ gatt.discoverServices( )
232228 stopScan()
233- sendEvent(BleDidcommEvent .OnConnectedPeripheral , params)
234229 } else if (newState == BluetoothProfile .STATE_DISCONNECTED ) {
235230 sendEvent(BleDidcommEvent .OnDisconnectedPeripheral , params)
236231 gatt.close()
@@ -266,20 +261,11 @@ class CentralManager(private val context: ReactContext) {
266261 return
267262 }
268263
269- gatt.setCharacteristicNotification(characteristicIndication, true )
270- val descriptor =
271- characteristicIndication?.getDescriptor(UUID .fromString(Constants .CCC_DESCRIPTOR_UUID ))
272- ? : run {
273- Log .d(
274- Constants .TAG ,
275- " [CENTRAL]: Indication Descriptor not found. Make sure CCC is set on the descriptor. Task of the peripheral"
276- )
277- gatt.disconnect()
278- return
279- }
280-
281- descriptor.value = BluetoothGattDescriptor .ENABLE_INDICATION_VALUE
282- gatt.writeDescriptor(descriptor)
264+ characteristicIndication?.let {
265+ subscribeToIndications(it, gatt)
266+ } ? : run {
267+ Log .e(Constants .TAG , " [CENTRAL]: characteristic not found $characteristicIndicationUUID " )
268+ }
283269 }
284270
285271 // Triggered when the client is ready to send the next message
@@ -301,7 +287,7 @@ class CentralManager(private val context: ReactContext) {
301287 ) {
302288 Log .d(
303289 Constants .TAG ,
304- " [CENTRAL]: Received an indication of ${characteristic.value.size} bytes."
290+ " [CENTRAL]: Received an indication of ${characteristic.value.size} bytes." ,
305291 )
306292
307293 if (characteristic.uuid == characteristicIndicationUUID) {
@@ -320,13 +306,19 @@ class CentralManager(private val context: ReactContext) {
320306 }
321307 }
322308
309+ @SuppressLint(" MissingPermission" )
323310 override fun onDescriptorWrite (
324311 gatt : BluetoothGatt ,
325312 descriptor : BluetoothGattDescriptor ,
326- status : Int
313+ status : Int ,
327314 ) {
328315 super .onDescriptorWrite(gatt, descriptor, status)
329316 Log .d(Constants .TAG , " [CENTRAL]: Descriptor write. Connection is ready" )
317+ gatt.requestMtu(512 )
318+ val params = Arguments .createMap().apply {
319+ putString(" identifier" , gatt.device.address)
320+ }
321+ sendEvent(BleDidcommEvent .OnConnectedPeripheral , params)
330322 }
331323
332324 // Triggered when the MTU has been changed.
@@ -339,7 +331,6 @@ class CentralManager(private val context: ReactContext) {
339331 return
340332 }
341333 connectedMtu = mtu
342- gatt.discoverServices()
343334 }
344335 }
345336
@@ -348,7 +339,6 @@ class CentralManager(private val context: ReactContext) {
348339 override fun onScanResult (callbackType : Int , result : ScanResult ) {
349340 val name = result.scanRecord?.deviceName ? : result.device.name ? : result.device.address
350341 Log .d(Constants .TAG , " [CENTRAL]: Found item $name " )
351- super .onScanResult(callbackType, result)
352342
353343 discoveredPeripherals.add(result.device)
354344 val params = Arguments .createMap().apply {
@@ -358,40 +348,3 @@ class CentralManager(private val context: ReactContext) {
358348 }
359349 }
360350}
361-
362-
363-
364-
365-
366-
367-
368-
369-
370-
371-
372-
373-
374-
375-
376-
377-
378-
379-
380-
381-
382-
383-
384-
385-
386-
387-
388-
389-
390-
391-
392-
393-
394-
395-
396-
397-
0 commit comments