mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 22:05:26 +00:00
fix null pointer
This commit is contained in:
@@ -128,11 +128,13 @@ class BluetoothConnectionManager(
|
||||
|
||||
try {
|
||||
isActive = true
|
||||
setupGattServer()
|
||||
|
||||
// Start power manager and services
|
||||
connectionScope.launch {
|
||||
powerManager.start()
|
||||
|
||||
// Setup GATT server after power manager is ready
|
||||
setupGattServer()
|
||||
delay(500) // Ensure GATT server is ready
|
||||
|
||||
startAdvertising()
|
||||
@@ -146,13 +148,14 @@ class BluetoothConnectionManager(
|
||||
|
||||
startPeriodicCleanup()
|
||||
|
||||
Log.i(TAG, "Power-optimized Bluetooth services started successfully (CLIENT ONLY)")
|
||||
Log.i(TAG, "Power-optimized Bluetooth services started successfully")
|
||||
}
|
||||
|
||||
return true
|
||||
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to start Bluetooth services: ${e.message}")
|
||||
isActive = false
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -355,6 +358,12 @@ class BluetoothConnectionManager(
|
||||
|
||||
val serverCallback = object : BluetoothGattServerCallback() {
|
||||
override fun onConnectionStateChange(device: BluetoothDevice, status: Int, newState: Int) {
|
||||
// Guard against callbacks after service shutdown
|
||||
if (!isActive) {
|
||||
Log.d(TAG, "Server: Ignoring connection state change after shutdown")
|
||||
return
|
||||
}
|
||||
|
||||
when (newState) {
|
||||
BluetoothProfile.STATE_CONNECTED -> {
|
||||
Log.d(TAG, "Server: Device connected ${device.address}")
|
||||
@@ -371,6 +380,20 @@ class BluetoothConnectionManager(
|
||||
}
|
||||
}
|
||||
|
||||
override fun onServiceAdded(status: Int, service: BluetoothGattService) {
|
||||
// Guard against callbacks after service shutdown
|
||||
if (!isActive) {
|
||||
Log.d(TAG, "Server: Ignoring service added callback after shutdown")
|
||||
return
|
||||
}
|
||||
|
||||
if (status == BluetoothGatt.GATT_SUCCESS) {
|
||||
Log.d(TAG, "Server: Service added successfully: ${service.uuid}")
|
||||
} else {
|
||||
Log.e(TAG, "Server: Failed to add service: ${service.uuid}, status: $status")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCharacteristicWriteRequest(
|
||||
device: BluetoothDevice,
|
||||
requestId: Int,
|
||||
@@ -380,6 +403,12 @@ class BluetoothConnectionManager(
|
||||
offset: Int,
|
||||
value: ByteArray
|
||||
) {
|
||||
// Guard against callbacks after service shutdown
|
||||
if (!isActive) {
|
||||
Log.d(TAG, "Server: Ignoring characteristic write after shutdown")
|
||||
return
|
||||
}
|
||||
|
||||
if (characteristic.uuid == CHARACTERISTIC_UUID) {
|
||||
val packet = BitchatPacket.fromBinaryData(value)
|
||||
if (packet != null) {
|
||||
@@ -402,13 +431,21 @@ class BluetoothConnectionManager(
|
||||
offset: Int,
|
||||
value: ByteArray
|
||||
) {
|
||||
// Guard against callbacks after service shutdown
|
||||
if (!isActive) {
|
||||
Log.d(TAG, "Server: Ignoring descriptor write after shutdown")
|
||||
return
|
||||
}
|
||||
|
||||
if (BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE.contentEquals(value)) {
|
||||
Log.d(TAG, "Device ${device.address} subscribed to notifications")
|
||||
subscribedDevices.add(device)
|
||||
|
||||
connectionScope.launch {
|
||||
delay(100)
|
||||
delegate?.onDeviceConnected(device)
|
||||
if (isActive) { // Check if still active
|
||||
delegate?.onDeviceConnected(device)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,34 +455,51 @@ class BluetoothConnectionManager(
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up existing server
|
||||
gattServer?.close()
|
||||
// Proper cleanup sequencing to prevent race conditions
|
||||
gattServer?.let { server ->
|
||||
Log.d(TAG, "Cleaning up existing GATT server")
|
||||
connectionScope.launch {
|
||||
// Give time for pending callbacks to complete
|
||||
delay(100)
|
||||
server.close()
|
||||
}
|
||||
}
|
||||
|
||||
gattServer = bluetoothManager.openGattServer(context, serverCallback)
|
||||
// Create new server after cleanup delay
|
||||
connectionScope.launch {
|
||||
delay(200) // Allow previous server to fully close
|
||||
|
||||
// Create characteristic with notification support
|
||||
characteristic = BluetoothGattCharacteristic(
|
||||
CHARACTERISTIC_UUID,
|
||||
BluetoothGattCharacteristic.PROPERTY_READ or
|
||||
BluetoothGattCharacteristic.PROPERTY_WRITE or
|
||||
BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE or
|
||||
BluetoothGattCharacteristic.PROPERTY_NOTIFY,
|
||||
BluetoothGattCharacteristic.PERMISSION_READ or
|
||||
BluetoothGattCharacteristic.PERMISSION_WRITE
|
||||
)
|
||||
if (!isActive) {
|
||||
Log.d(TAG, "Service inactive, skipping GATT server creation")
|
||||
return@launch
|
||||
}
|
||||
|
||||
val descriptor = BluetoothGattDescriptor(
|
||||
UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"),
|
||||
BluetoothGattDescriptor.PERMISSION_READ or BluetoothGattDescriptor.PERMISSION_WRITE
|
||||
)
|
||||
characteristic?.addDescriptor(descriptor)
|
||||
gattServer = bluetoothManager.openGattServer(context, serverCallback)
|
||||
|
||||
val service = BluetoothGattService(SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY)
|
||||
service.addCharacteristic(characteristic)
|
||||
// Create characteristic with notification support
|
||||
characteristic = BluetoothGattCharacteristic(
|
||||
CHARACTERISTIC_UUID,
|
||||
BluetoothGattCharacteristic.PROPERTY_READ or
|
||||
BluetoothGattCharacteristic.PROPERTY_WRITE or
|
||||
BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE or
|
||||
BluetoothGattCharacteristic.PROPERTY_NOTIFY,
|
||||
BluetoothGattCharacteristic.PERMISSION_READ or
|
||||
BluetoothGattCharacteristic.PERMISSION_WRITE
|
||||
)
|
||||
|
||||
gattServer?.addService(service)
|
||||
val descriptor = BluetoothGattDescriptor(
|
||||
UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"),
|
||||
BluetoothGattDescriptor.PERMISSION_READ or BluetoothGattDescriptor.PERMISSION_WRITE
|
||||
)
|
||||
characteristic?.addDescriptor(descriptor)
|
||||
|
||||
Log.i(TAG, "GATT server setup complete")
|
||||
val service = BluetoothGattService(SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY)
|
||||
service.addCharacteristic(characteristic)
|
||||
|
||||
gattServer?.addService(service)
|
||||
|
||||
Log.i(TAG, "GATT server setup complete")
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
|
||||
@@ -47,6 +47,9 @@ class BluetoothMeshService(private val context: Context) {
|
||||
internal val connectionManager = BluetoothConnectionManager(context, myPeerID) // Made internal for access
|
||||
private val packetProcessor = PacketProcessor(myPeerID)
|
||||
|
||||
// Service state management
|
||||
private var isActive = false
|
||||
|
||||
// Delegate for message callbacks (maintains same interface)
|
||||
var delegate: BluetoothMeshDelegate? = null
|
||||
|
||||
@@ -98,7 +101,10 @@ class BluetoothMeshService(private val context: Context) {
|
||||
|
||||
// SecurityManager delegate for key exchange notifications
|
||||
securityManager.delegate = object : SecurityManagerDelegate {
|
||||
override fun onKeyExchangeCompleted(peerID: String) {
|
||||
override fun onKeyExchangeCompleted(peerID: String, peerPublicKeyData: ByteArray) {
|
||||
// Notify delegate about key exchange completion so it can register peer fingerprint
|
||||
delegate?.registerPeerPublicKey(peerID, peerPublicKeyData)
|
||||
|
||||
// Send announcement and cached messages after key exchange
|
||||
serviceScope.launch {
|
||||
delay(100)
|
||||
@@ -276,15 +282,24 @@ class BluetoothMeshService(private val context: Context) {
|
||||
* Start the mesh service
|
||||
*/
|
||||
fun startServices() {
|
||||
// Prevent double starts
|
||||
if (isActive) {
|
||||
Log.w(TAG, "Mesh service already active, ignoring duplicate start request")
|
||||
return
|
||||
}
|
||||
|
||||
Log.i(TAG, "Starting Bluetooth mesh service with peer ID: $myPeerID")
|
||||
|
||||
if (connectionManager.startServices()) {
|
||||
isActive = true
|
||||
Log.i(TAG, "Bluetooth services started successfully")
|
||||
|
||||
// Send initial announcements after services are ready
|
||||
serviceScope.launch {
|
||||
delay(1000)
|
||||
sendBroadcastAnnounce()
|
||||
if (isActive) { // Check if still active
|
||||
sendBroadcastAnnounce()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Failed to start Bluetooth services")
|
||||
@@ -295,7 +310,13 @@ class BluetoothMeshService(private val context: Context) {
|
||||
* Stop all mesh services
|
||||
*/
|
||||
fun stopServices() {
|
||||
if (!isActive) {
|
||||
Log.w(TAG, "Mesh service not active, ignoring stop request")
|
||||
return
|
||||
}
|
||||
|
||||
Log.i(TAG, "Stopping Bluetooth mesh service")
|
||||
isActive = false
|
||||
|
||||
// Send leave announcement
|
||||
sendLeaveAnnouncement()
|
||||
@@ -547,4 +568,5 @@ interface BluetoothMeshDelegate {
|
||||
fun decryptChannelMessage(encryptedContent: ByteArray, channel: String): String?
|
||||
fun getNickname(): String?
|
||||
fun isFavorite(peerID: String): Boolean
|
||||
fun registerPeerPublicKey(peerID: String, publicKeyData: ByteArray)
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ class SecurityManager(private val encryptionService: EncryptionService, private
|
||||
Log.d(TAG, "Successfully processed key exchange from $peerID")
|
||||
|
||||
// Notify delegate
|
||||
delegate?.onKeyExchangeCompleted(peerID)
|
||||
delegate?.onKeyExchangeCompleted(peerID, packet.payload)
|
||||
|
||||
return true
|
||||
|
||||
@@ -315,5 +315,5 @@ class SecurityManager(private val encryptionService: EncryptionService, private
|
||||
* Delegate interface for security manager callbacks
|
||||
*/
|
||||
interface SecurityManagerDelegate {
|
||||
fun onKeyExchangeCompleted(peerID: String)
|
||||
fun onKeyExchangeCompleted(peerID: String, peerPublicKeyData: ByteArray)
|
||||
}
|
||||
|
||||
@@ -253,10 +253,6 @@ class ChatViewModel(application: Application) : AndroidViewModel(application), B
|
||||
privateChatManager.toggleFavorite(peerID)
|
||||
}
|
||||
|
||||
fun registerPeerPublicKey(peerID: String, publicKeyData: ByteArray) {
|
||||
privateChatManager.registerPeerPublicKey(peerID, publicKeyData)
|
||||
}
|
||||
|
||||
// MARK: - Debug and Troubleshooting
|
||||
|
||||
fun getDebugStatus(): String {
|
||||
@@ -341,6 +337,10 @@ class ChatViewModel(application: Application) : AndroidViewModel(application), B
|
||||
return meshDelegateHandler.isFavorite(peerID)
|
||||
}
|
||||
|
||||
override fun registerPeerPublicKey(peerID: String, publicKeyData: ByteArray) {
|
||||
privateChatManager.registerPeerPublicKey(peerID, publicKeyData)
|
||||
}
|
||||
|
||||
// MARK: - Emergency Clear
|
||||
|
||||
fun panicClearAllData() {
|
||||
|
||||
@@ -154,4 +154,8 @@ class MeshDelegateHandler(
|
||||
override fun isFavorite(peerID: String): Boolean {
|
||||
return privateChatManager.isFavorite(peerID)
|
||||
}
|
||||
|
||||
override fun registerPeerPublicKey(peerID: String, publicKeyData: ByteArray) {
|
||||
privateChatManager.registerPeerPublicKey(peerID, publicKeyData)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user