@@ -128,11 +128,13 @@ class BluetoothConnectionManager(
128128
129129 try {
130130 isActive = true
131- setupGattServer()
132131
133132 // Start power manager and services
134133 connectionScope.launch {
135134 powerManager.start()
135+
136+ // Setup GATT server after power manager is ready
137+ setupGattServer()
136138 delay(500 ) // Ensure GATT server is ready
137139
138140 startAdvertising()
@@ -146,13 +148,14 @@ class BluetoothConnectionManager(
146148
147149 startPeriodicCleanup()
148150
149- Log .i(TAG , " Power-optimized Bluetooth services started successfully (CLIENT ONLY) " )
151+ Log .i(TAG , " Power-optimized Bluetooth services started successfully" )
150152 }
151153
152154 return true
153155
154156 } catch (e: Exception ) {
155157 Log .e(TAG , " Failed to start Bluetooth services: ${e.message} " )
158+ isActive = false
156159 return false
157160 }
158161 }
@@ -355,6 +358,12 @@ class BluetoothConnectionManager(
355358
356359 val serverCallback = object : BluetoothGattServerCallback () {
357360 override fun onConnectionStateChange (device : BluetoothDevice , status : Int , newState : Int ) {
361+ // Guard against callbacks after service shutdown
362+ if (! isActive) {
363+ Log .d(TAG , " Server: Ignoring connection state change after shutdown" )
364+ return
365+ }
366+
358367 when (newState) {
359368 BluetoothProfile .STATE_CONNECTED -> {
360369 Log .d(TAG , " Server: Device connected ${device.address} " )
@@ -371,6 +380,20 @@ class BluetoothConnectionManager(
371380 }
372381 }
373382
383+ override fun onServiceAdded (status : Int , service : BluetoothGattService ) {
384+ // Guard against callbacks after service shutdown
385+ if (! isActive) {
386+ Log .d(TAG , " Server: Ignoring service added callback after shutdown" )
387+ return
388+ }
389+
390+ if (status == BluetoothGatt .GATT_SUCCESS ) {
391+ Log .d(TAG , " Server: Service added successfully: ${service.uuid} " )
392+ } else {
393+ Log .e(TAG , " Server: Failed to add service: ${service.uuid} , status: $status " )
394+ }
395+ }
396+
374397 override fun onCharacteristicWriteRequest (
375398 device : BluetoothDevice ,
376399 requestId : Int ,
@@ -380,6 +403,12 @@ class BluetoothConnectionManager(
380403 offset : Int ,
381404 value : ByteArray
382405 ) {
406+ // Guard against callbacks after service shutdown
407+ if (! isActive) {
408+ Log .d(TAG , " Server: Ignoring characteristic write after shutdown" )
409+ return
410+ }
411+
383412 if (characteristic.uuid == CHARACTERISTIC_UUID ) {
384413 val packet = BitchatPacket .fromBinaryData(value)
385414 if (packet != null ) {
@@ -402,13 +431,21 @@ class BluetoothConnectionManager(
402431 offset : Int ,
403432 value : ByteArray
404433 ) {
434+ // Guard against callbacks after service shutdown
435+ if (! isActive) {
436+ Log .d(TAG , " Server: Ignoring descriptor write after shutdown" )
437+ return
438+ }
439+
405440 if (BluetoothGattDescriptor .ENABLE_NOTIFICATION_VALUE .contentEquals(value)) {
406441 Log .d(TAG , " Device ${device.address} subscribed to notifications" )
407442 subscribedDevices.add(device)
408443
409444 connectionScope.launch {
410445 delay(100 )
411- delegate?.onDeviceConnected(device)
446+ if (isActive) { // Check if still active
447+ delegate?.onDeviceConnected(device)
448+ }
412449 }
413450 }
414451
@@ -418,34 +455,51 @@ class BluetoothConnectionManager(
418455 }
419456 }
420457
421- // Clean up existing server
422- gattServer?.close()
423-
424- gattServer = bluetoothManager.openGattServer(context, serverCallback)
425-
426- // Create characteristic with notification support
427- characteristic = BluetoothGattCharacteristic (
428- CHARACTERISTIC_UUID ,
429- BluetoothGattCharacteristic .PROPERTY_READ or
430- BluetoothGattCharacteristic .PROPERTY_WRITE or
431- BluetoothGattCharacteristic .PROPERTY_WRITE_NO_RESPONSE or
432- BluetoothGattCharacteristic .PROPERTY_NOTIFY ,
433- BluetoothGattCharacteristic .PERMISSION_READ or
434- BluetoothGattCharacteristic .PERMISSION_WRITE
435- )
436-
437- val descriptor = BluetoothGattDescriptor (
438- UUID .fromString(" 00002902-0000-1000-8000-00805f9b34fb" ),
439- BluetoothGattDescriptor .PERMISSION_READ or BluetoothGattDescriptor .PERMISSION_WRITE
440- )
441- characteristic?.addDescriptor(descriptor)
442-
443- val service = BluetoothGattService (SERVICE_UUID , BluetoothGattService .SERVICE_TYPE_PRIMARY )
444- service.addCharacteristic(characteristic)
445-
446- gattServer?.addService(service)
458+ // Proper cleanup sequencing to prevent race conditions
459+ gattServer?.let { server ->
460+ Log .d(TAG , " Cleaning up existing GATT server" )
461+ connectionScope.launch {
462+ // Give time for pending callbacks to complete
463+ delay(100 )
464+ server.close()
465+ }
466+ }
447467
448- Log .i(TAG , " GATT server setup complete" )
468+ // Create new server after cleanup delay
469+ connectionScope.launch {
470+ delay(200 ) // Allow previous server to fully close
471+
472+ if (! isActive) {
473+ Log .d(TAG , " Service inactive, skipping GATT server creation" )
474+ return @launch
475+ }
476+
477+ gattServer = bluetoothManager.openGattServer(context, serverCallback)
478+
479+ // Create characteristic with notification support
480+ characteristic = BluetoothGattCharacteristic (
481+ CHARACTERISTIC_UUID ,
482+ BluetoothGattCharacteristic .PROPERTY_READ or
483+ BluetoothGattCharacteristic .PROPERTY_WRITE or
484+ BluetoothGattCharacteristic .PROPERTY_WRITE_NO_RESPONSE or
485+ BluetoothGattCharacteristic .PROPERTY_NOTIFY ,
486+ BluetoothGattCharacteristic .PERMISSION_READ or
487+ BluetoothGattCharacteristic .PERMISSION_WRITE
488+ )
489+
490+ val descriptor = BluetoothGattDescriptor (
491+ UUID .fromString(" 00002902-0000-1000-8000-00805f9b34fb" ),
492+ BluetoothGattDescriptor .PERMISSION_READ or BluetoothGattDescriptor .PERMISSION_WRITE
493+ )
494+ characteristic?.addDescriptor(descriptor)
495+
496+ val service = BluetoothGattService (SERVICE_UUID , BluetoothGattService .SERVICE_TYPE_PRIMARY )
497+ service.addCharacteristic(characteristic)
498+
499+ gattServer?.addService(service)
500+
501+ Log .i(TAG , " GATT server setup complete" )
502+ }
449503 }
450504
451505 @Suppress(" DEPRECATION" )
0 commit comments