From f6cb73ff8950febca62a009ce002c18f690e0c1a Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Wed, 22 Oct 2025 04:09:00 +0200 Subject: [PATCH] wifi aware wip --- .../java/com/bitchat/android/MainActivity.kt | 39 +++++++++++++++++++ .../bitchat/android/services/MessageRouter.kt | 17 +++++++- .../wifi-aware/WifiAwareMeshServiceLatest.kt | 11 +++--- 3 files changed, 60 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/bitchat/android/MainActivity.kt b/app/src/main/java/com/bitchat/android/MainActivity.kt index 28d67280..36fbf4d1 100644 --- a/app/src/main/java/com/bitchat/android/MainActivity.kt +++ b/app/src/main/java/com/bitchat/android/MainActivity.kt @@ -120,6 +120,45 @@ class MainActivity : OrientationAwareActivity() { } } } + + // Bridge Wi‑Fi Aware callbacks into ChatViewModel (reusing BLE delegate methods) + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + com.bitchat.android.wifiaware.WifiAwareController.running.collect { running -> + val svc = com.bitchat.android.wifiaware.WifiAwareController.getService() + if (running && svc != null) { + svc.delegate = object : com.bitchat.android.wifiaware.WifiAwareMeshDelegate { + override fun didReceiveMessage(message: com.bitchat.android.model.BitchatMessage) { + chatViewModel.didReceiveMessage(message) + } + override fun didUpdatePeerList(peers: List) { + chatViewModel.didUpdatePeerList(peers) + } + override fun didReceiveChannelLeave(channel: String, fromPeer: String) { + chatViewModel.didReceiveChannelLeave(channel, fromPeer) + } + override fun didReceiveDeliveryAck(messageID: String, recipientPeerID: String) { + chatViewModel.didReceiveDeliveryAck(messageID, recipientPeerID) + } + override fun didReceiveReadReceipt(messageID: String, recipientPeerID: String) { + chatViewModel.didReceiveReadReceipt(messageID, recipientPeerID) + } + override fun decryptChannelMessage(encryptedContent: ByteArray, channel: String): String? { + return chatViewModel.decryptChannelMessage(encryptedContent, channel) + } + override fun getNickname(): String? { + return chatViewModel.getNickname() + } + override fun isFavorite(peerID: String): Boolean { + return try { + com.bitchat.android.favorites.FavoritesPersistenceService.shared.getFavoriteStatus(peerID)?.isMutual == true + } catch (_: Exception) { false } + } + } + } + } + } + } // Only start onboarding process if we're in the initial CHECKING state // This prevents restarting onboarding on configuration changes diff --git a/app/src/main/java/com/bitchat/android/services/MessageRouter.kt b/app/src/main/java/com/bitchat/android/services/MessageRouter.kt index 8166487e..53db2fa6 100644 --- a/app/src/main/java/com/bitchat/android/services/MessageRouter.kt +++ b/app/src/main/java/com/bitchat/android/services/MessageRouter.kt @@ -72,9 +72,15 @@ class MessageRouter private constructor( val hasMesh = mesh.getPeerInfo(toPeerID)?.isConnected == true val hasEstablished = mesh.hasEstablishedSession(toPeerID) + // Check Wi‑Fi Aware availability as a secondary transport + val aware = try { com.bitchat.android.wifiaware.WifiAwareController.getService() } catch (_: Exception) { null } + val hasAware = try { aware?.getPeerInfo(toPeerID)?.isConnected == true && aware.hasEstablishedSession(toPeerID) } catch (_: Exception) { false } if (hasMesh && hasEstablished) { Log.d(TAG, "Routing PM via mesh to ${toPeerID} msg_id=${messageID.take(8)}…") mesh.sendPrivateMessage(content, toPeerID, recipientNickname, messageID) + } else if (hasAware) { + Log.d(TAG, "Routing PM via Wi‑Fi Aware to ${toPeerID} msg_id=${messageID.take(8)}…") + aware?.sendPrivateMessage(content, toPeerID, recipientNickname, messageID) } else if (canSendViaNostr(toPeerID)) { Log.d(TAG, "Routing PM via Nostr to ${toPeerID.take(32)}… msg_id=${messageID.take(8)}…") nostr.sendPrivateMessage(content, toPeerID, recipientNickname, messageID) @@ -83,14 +89,21 @@ class MessageRouter private constructor( val q = outbox.getOrPut(toPeerID) { mutableListOf() } q.add(Triple(content, recipientNickname, messageID)) Log.d(TAG, "Initiating noise handshake after queueing PM for ${toPeerID.take(8)}…") - mesh.initiateNoiseHandshake(toPeerID) + if (hasMesh) mesh.initiateNoiseHandshake(toPeerID) else aware?.initiateNoiseHandshake(toPeerID) } } fun sendReadReceipt(receipt: ReadReceipt, toPeerID: String) { - if ((mesh.getPeerInfo(toPeerID)?.isConnected == true) && mesh.hasEstablishedSession(toPeerID)) { + val aware = try { com.bitchat.android.wifiaware.WifiAwareController.getService() } catch (_: Exception) { null } + val viaMesh = (mesh.getPeerInfo(toPeerID)?.isConnected == true) && mesh.hasEstablishedSession(toPeerID) + val viaAware = try { aware?.getPeerInfo(toPeerID)?.isConnected == true && aware.hasEstablishedSession(toPeerID) } catch (_: Exception) { false } + if (viaMesh) { Log.d(TAG, "Routing READ via mesh to ${toPeerID.take(8)}… id=${receipt.originalMessageID.take(8)}…") mesh.sendReadReceipt(receipt.originalMessageID, toPeerID, mesh.getPeerNicknames()[toPeerID] ?: mesh.myPeerID) + } else if (viaAware) { + Log.d(TAG, "Routing READ via Wi‑Fi Aware to ${toPeerID.take(8)}… id=${receipt.originalMessageID.take(8)}…") + val me = try { aware?.myPeerID } catch (_: Exception) { null } + aware?.sendReadReceipt(receipt.originalMessageID, toPeerID, me ?: "") } else { Log.d(TAG, "Routing READ via Nostr to ${toPeerID.take(8)}… id=${receipt.originalMessageID.take(8)}…") nostr.sendReadReceipt(receipt, toPeerID) diff --git a/app/src/main/java/com/bitchat/android/wifi-aware/WifiAwareMeshServiceLatest.kt b/app/src/main/java/com/bitchat/android/wifi-aware/WifiAwareMeshServiceLatest.kt index fccb81bc..7c3a728e 100644 --- a/app/src/main/java/com/bitchat/android/wifi-aware/WifiAwareMeshServiceLatest.kt +++ b/app/src/main/java/com/bitchat/android/wifi-aware/WifiAwareMeshServiceLatest.kt @@ -671,7 +671,7 @@ class WifiAwareMeshService(private val context: Context) { val cb = object : ConnectivityManager.NetworkCallback() { override fun onAvailable(network: Network) { - cm.bindProcessToNetwork(network) + // Do not bind process for Aware; use per-socket binding instead } override fun onCapabilitiesChanged(network: Network, nc: NetworkCapabilities) { if (peerSockets.containsKey(peerId)) return @@ -679,9 +679,11 @@ class WifiAwareMeshService(private val context: Context) { val addr = info.peerIpv6Addr as Inet6Address try { - val sock = network.socketFactory - .createSocket(addr, port) - .apply { keepAlive = true } + // Some devices deny bindSocket() (EPERM). Rely on scoped IPv6 to route correctly. + val sock = Socket() + sock.tcpNoDelay = true + sock.keepAlive = true + sock.connect(java.net.InetSocketAddress(addr, port), 7000) Log.d(TAG, "CLIENT: TCP connected to ${peerId.take(8)}… addr=$addr:$port") peerSockets[peerId] = sock @@ -696,7 +698,6 @@ class WifiAwareMeshService(private val context: Context) { } } override fun onLost(network: Network) { - cm.bindProcessToNetwork(null) networkCallbacks.remove(peerId) Log.d(TAG, "CLIENT: network lost for ${peerId.take(8)}…") }