This commit is contained in:
callebtc
2025-10-22 04:58:05 +02:00
parent 13d4c5145e
commit 1296e117ba
6 changed files with 79 additions and 32 deletions
@@ -73,6 +73,8 @@ class MainActivity : OrientationAwareActivity() {
permissionManager = PermissionManager(this)
// Initialize core mesh service first
meshService = BluetoothMeshService(this)
// Expose BLE mesh to WiFi Aware controller for cross-transport relays
try { com.bitchat.android.wifiaware.WifiAwareController.setBleMeshService(meshService) } catch (_: Exception) { }
bluetoothStatusManager = BluetoothStatusManager(
activity = this,
context = this,
@@ -347,6 +349,12 @@ class MainActivity : OrientationAwareActivity() {
bluetoothStatusManager.logBluetoothStatus()
mainViewModel.updateBluetoothStatus(bluetoothStatusManager.checkBluetoothStatus())
val bleRequired = try { com.bitchat.android.ui.debug.DebugPreferenceManager.getBleEnabled(true) } catch (_: Exception) { true }
if (!bleRequired) {
// Skip BLE checks entirely when BLE is disabled in debug settings
checkLocationAndProceed()
return
}
when (mainViewModel.bluetoothStatus.value) {
BluetoothStatus.ENABLED -> {
// Bluetooth is enabled, check location services next
@@ -513,8 +521,9 @@ class MainActivity : OrientationAwareActivity() {
else -> BatteryOptimizationStatus.ENABLED
}
val bleRequired2 = try { com.bitchat.android.ui.debug.DebugPreferenceManager.getBleEnabled(true) } catch (_: Exception) { true }
when {
currentBluetoothStatus != BluetoothStatus.ENABLED -> {
bleRequired2 && currentBluetoothStatus != BluetoothStatus.ENABLED -> {
// Bluetooth still disabled, but now we have permissions to enable it
Log.d("MainActivity", "Permissions granted, but Bluetooth still disabled. Showing Bluetooth enable screen.")
mainViewModel.updateBluetoothStatus(currentBluetoothStatus)
@@ -249,11 +249,16 @@ class BluetoothMeshService(private val context: Context) {
override fun sendPacket(packet: BitchatPacket) {
// Sign the packet before broadcasting
val signedPacket = signPacketBeforeBroadcast(packet)
connectionManager.broadcastPacket(RoutedPacket(signedPacket))
val routed = RoutedPacket(signedPacket)
connectionManager.broadcastPacket(routed)
// Cross-transport relay to WiFi Aware if available
try { com.bitchat.android.wifiaware.WifiAwareController.getService()?.broadcastRoutedPacket(routed) } catch (_: Exception) { }
}
override fun relayPacket(routed: RoutedPacket) {
connectionManager.broadcastPacket(routed)
// Cross-transport relay to WiFi Aware if available
try { com.bitchat.android.wifiaware.WifiAwareController.getService()?.broadcastRoutedPacket(routed) } catch (_: Exception) { }
}
override fun getBroadcastRecipient(): ByteArray {
@@ -210,6 +210,7 @@ class MediaSendingManager(
Log.d(TAG, "📤 Calling meshService.sendFilePrivate to $toPeerID")
meshService.sendFilePrivate(toPeerID, filePacket)
try { com.bitchat.android.wifiaware.WifiAwareController.getService()?.sendFilePrivate(toPeerID, filePacket) } catch (_: Exception) {}
Log.d(TAG, "✅ File send completed successfully")
}
@@ -264,6 +265,7 @@ class MediaSendingManager(
Log.d(TAG, "📤 Calling meshService.sendFileBroadcast")
meshService.sendFileBroadcast(filePacket)
try { com.bitchat.android.wifiaware.WifiAwareController.getService()?.sendFileBroadcast(filePacket) } catch (_: Exception) {}
Log.d(TAG, "✅ File broadcast completed successfully")
}
@@ -576,16 +576,21 @@ private fun PeerItem(
tint = Color.Gray
)
} else {
val wifiAwarePeers by com.bitchat.android.wifiaware.WifiAwareController.connectedPeers.collectAsState()
val isWifiAware = wifiAwarePeers.containsKey(peerID)
val awareConnected by com.bitchat.android.wifiaware.WifiAwareController.connectedPeers.collectAsState()
val awareDiscovered by com.bitchat.android.wifiaware.WifiAwareController.discoveredPeers.collectAsState()
val isWifiDirect = awareConnected.containsKey(peerID)
val isBleDirect = isDirect
val icon = when {
isWifiAware -> Icons.Filled.Wifi
isDirect -> Icons.Outlined.SettingsInputAntenna
isWifiDirect -> Icons.Filled.Wifi
isBleDirect -> Icons.Outlined.SettingsInputAntenna
// Routed: show Route icon; optionally prefer WiFi Aware if discovered there
awareDiscovered.contains(peerID) -> Icons.Filled.WifiTethering
else -> Icons.Filled.Route
}
val cd = when {
isWifiAware -> "Direct WiFi Aware"
isDirect -> "Direct Bluetooth"
isWifiDirect -> "Direct WiFi Aware"
isBleDirect -> "Direct Bluetooth"
awareDiscovered.contains(peerID) -> "Routed over WiFi"
else -> "Routed"
}
Icon(
@@ -51,7 +51,7 @@ object WifiAwareController {
try {
val s = service
if (s != null) {
_connectedPeers.value = s.getDeviceAddressToPeerMapping().entries.associate { (ip, peer) -> peer to ip }
_connectedPeers.value = s.getDeviceAddressToPeerMapping() // peerID -> ip
_knownPeers.value = s.getPeerNicknames()
_discoveredPeers.value = s.getDiscoveredPeerIds()
} else {
@@ -108,4 +108,9 @@ object WifiAwareController {
}
fun getService(): WifiAwareMeshService? = service
// Optional bridge to BLE mesh for cross-transport relaying
@Volatile private var bleMesh: com.bitchat.android.mesh.BluetoothMeshService? = null
fun setBleMeshService(svc: com.bitchat.android.mesh.BluetoothMeshService) { bleMesh = svc }
fun getBleMeshService(): com.bitchat.android.mesh.BluetoothMeshService? = bleMesh
}
@@ -172,24 +172,39 @@ class WifiAwareMeshService(private val context: Context) {
* Broadcasts routed packet to currently connected peers.
*/
private fun broadcastPacket(routed: RoutedPacket) {
routed.packet.toBinaryData()?.let {
routed.packet.toBinaryData()?.let { data ->
Log.d(TAG, "TX: packet type=${routed.packet.type} broadcast (ttl=${routed.packet.ttl})")
broadcastRaw(it)
serviceScope.launch { broadcastRaw(data) }
// Cross-transport relay (optional): also broadcast via BLE if available
try { com.bitchat.android.wifiaware.WifiAwareController.getBleMeshService()?.connectionManager?.broadcastPacket(routed) } catch (_: Exception) { }
}
}
// Expose a public method so BLE can forward relays to WiFi Aware
fun broadcastRoutedPacket(routed: RoutedPacket) {
broadcastPacket(routed)
}
/**
* Send packet to connected peer.
*/
private fun sendPacketToPeer(peerID: String, packet: BitchatPacket) {
val sock = peerSockets[peerID] ?: return
try {
val data = packet.toBinaryData() ?: return
sock.getOutputStream().write(data)
Log.d(TAG, "TX: packet type=${packet.type}${peerID.take(8)}… (bytes=${data.size})")
} catch (e: IOException) {
Log.e(TAG, "TX: write to ${peerID.take(8)}… failed: ${e.message}")
val data = packet.toBinaryData() ?: return
serviceScope.launch {
val sock = peerSockets[peerID]
if (sock == null) {
Log.w(TAG, "TX: no socket for ${peerID.take(8)}")
return@launch
}
try {
sock.getOutputStream().write(data)
Log.d(TAG, "TX: packet type=${packet.type}${peerID.take(8)}… (bytes=${data.size})")
} catch (e: IOException) {
Log.e(TAG, "TX: write to ${peerID.take(8)}… failed: ${e.message}")
}
}
// Cross-transport relay to BLE when unicast target is connected there too
try { com.bitchat.android.wifiaware.WifiAwareController.getBleMeshService()?.connectionManager?.sendPacketToPeer(peerID, packet) } catch (_: Exception) { }
}
/**
@@ -279,17 +294,19 @@ class WifiAwareMeshService(private val context: Context) {
override fun hasNoiseSession(peerID: String) =
encryptionService.hasEstablishedSession(peerID)
override fun initiateNoiseHandshake(peerID: String) {
val hs = encryptionService.initiateHandshake(peerID) ?: return
val packet = BitchatPacket(
version = 1u,
type = MessageType.NOISE_HANDSHAKE.value,
senderID = hexStringToByteArray(myPeerID),
recipientID = hexStringToByteArray(peerID),
timestamp = System.currentTimeMillis().toULong(),
payload = hs,
ttl = MAX_TTL
)
broadcastPacket(RoutedPacket(signPacketBeforeBroadcast(packet)))
serviceScope.launch {
val hs = encryptionService.initiateHandshake(peerID) ?: return@launch
val packet = BitchatPacket(
version = 1u,
type = MessageType.NOISE_HANDSHAKE.value,
senderID = hexStringToByteArray(myPeerID),
recipientID = hexStringToByteArray(peerID),
timestamp = System.currentTimeMillis().toULong(),
payload = hs,
ttl = MAX_TTL
)
broadcastPacket(RoutedPacket(signPacketBeforeBroadcast(packet)))
}
}
override fun processNoiseHandshakeMessage(payload: ByteArray, peerID: String): ByteArray? =
try { encryptionService.processHandshakeMessage(payload, peerID) } catch (_: Exception) { null }
@@ -593,8 +610,10 @@ class WifiAwareMeshService(private val context: Context) {
// Kick off Noise handshake for this logical peer
if (myPeerID < peerId) {
messageHandler.delegate?.initiateNoiseHandshake(peerId)
Log.d(TAG, "SERVER: initiating Noise handshake to ${peerId.take(8)}")
Log.d(TAG, "SERVER: initiating Noise handshake to ${peerId.take(8)} (lower ID)")
}
// Ensure fast presence even before handshake settles
serviceScope.launch { delay(150); sendBroadcastAnnounce() }
} catch (ioe: IOException) {
Log.e(TAG, "SERVER: accept failed for ${peerId.take(8)}", ioe)
}
@@ -707,10 +726,12 @@ class WifiAwareMeshService(private val context: Context) {
listenerExec.execute { listenToPeer(sock, peerId) }
handleServerKeepAlive(sock, peerId, peerHandle)
// Kick off Noise handshake for this logical peer
if (myPeerID > peerId) {
if (myPeerID < peerId) {
messageHandler.delegate?.initiateNoiseHandshake(peerId)
Log.d(TAG, "CLIENT: initiating Noise handshake to ${peerId.take(8)}")
Log.d(TAG, "CLIENT: initiating Noise handshake to ${peerId.take(8)} (lower ID)")
}
// Ensure fast presence even before handshake settles
serviceScope.launch { delay(150); sendBroadcastAnnounce() }
} catch (ioe: IOException) {
Log.e(TAG, "CLIENT: socket connect failed to ${peerId.take(8)}", ioe)
}