Fix wifi aware socket binding 2 (#536)

* Background persistence (#505)

* persistence step 1

* fix build

* messages in the background work, notifications not yet

* app state store

* DM icon shows up

* notification launches when app is closed!

* keep ui updated

* lifecycle fixes

* extensive logging, maybe revert later

* send nickname in announcement

* quit in notification

* setting in about sheet

* fix quit bitchat

* lifecycle fixes

* power mode based on background state

* stats for both direciotns

* fix graph persistence

* better counting

* count per device

* only compute when debug sheet is open? untested

* fix read receipts

* fix read receipts fully

* fix unread badge if messages have been read in focus

* foreground promotion fix

* fix app kill in notification

* adjust to new tor

* nice

* about sheet design

* bump version 1.6.0 (#524)

* Automated update of relay data - Sun Dec 14 06:06:53 UTC 2025

* bump targetSdk (#526)

* Automated update of relay data - Sun Dec 21 06:06:56 UTC 2025

* Automated update of relay data - Sun Dec 28 06:07:12 UTC 2025

* Prevent quit notification from reappearing (#530)

* shutdown sequence

* Prevent quit notification from reappearing

* Restrict force-finish broadcast

* Cancel quit shutdown on relaunch

* fix(wifi-aware): use bindSocket and scoped IPv6 instead of bindProcessToNetwork

* Merge branch 'upstream/main' into fix/wifi-aware-socket-binding

* Fix Wi-Fi Aware connectivity and UI integration post-merge

- Replace bindProcessToNetwork with bindSocket for VPN compatibility.
- Implement Scoped IPv6 address resolution (aware0) for mesh routing.
- Bridge Wi-Fi Aware incoming messages to AppStateStore for UI visibility.
- Fix syntax errors and variable name conflicts in Debug UI.

* Enhance Wi-Fi Aware robustness and debug UI display

- Clean up transport resources (sockets, server sockets, network callbacks) immediately on peer disconnection.
- Implement resolveScopedAddress to show scoped IPv6 (e.g., %aware0) in Debug UI.
- Fix Map type mismatch warning in ChatViewModel bridge.
- Filter self-ID from peer cleanup tables to prevent recursive self-removal.

* Share GossipSyncManager across transports to prevent redundant message synchronization

- Registered BluetoothMeshService's GossipSyncManager as a singleton in MeshServiceHolder.
- Modified WifiAwareMeshService to use the shared GossipSyncManager if available.
- Added background cleanup for peer mappings on socket disconnection.
- Fixed Kotlin type mismatch during nickname map merging.

* Restore VPN acquisition logic and improve peer cleanup

- Revert removal of NET_CAPABILITY_NOT_VPN to allow hardware handle acquisition while VPN is active.
- Refactor handlePeerDisconnection to more reliably cleanup initial and routed IDs.
- Switch cleanup logging to debug level to reduce log noise.

---------

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: aidenvalue <>
This commit is contained in:
callebtc
2026-01-03 23:39:54 +07:00
committed by GitHub
co-authored by GitHub Action aidenvalue <>
parent ecc7e93930
commit 463600a6c3
28 changed files with 2627 additions and 932 deletions
@@ -22,6 +22,8 @@ class MessageManager(private val state: ChatState) {
val currentMessages = state.getMessagesValue().toMutableList()
currentMessages.add(message)
state.setMessages(currentMessages)
// Reflect into process-wide store so snapshot replacements don't drop local outgoing messages
try { com.bitchat.android.services.AppStateStore.addPublicMessage(message) } catch (_: Exception) { }
}
// Log a system message into the main chat (visible to user)
@@ -52,6 +54,8 @@ class MessageManager(private val state: ChatState) {
channelMessageList.add(message)
currentChannelMessages[channel] = channelMessageList
state.setChannelMessages(currentChannelMessages)
// Reflect into process-wide store
try { com.bitchat.android.services.AppStateStore.addChannelMessage(channel, message) } catch (_: Exception) { }
// Update unread count if not currently viewing this channel
// Consider both classic channels (state.currentChannel) and geohash location channel selection
@@ -105,6 +109,8 @@ class MessageManager(private val state: ChatState) {
chatMessages.add(message)
currentPrivateChats[peerID] = chatMessages
state.setPrivateChats(currentPrivateChats)
// Reflect into process-wide store
try { com.bitchat.android.services.AppStateStore.addPrivateMessage(peerID, message) } catch (_: Exception) { }
// Mark as unread if not currently viewing this chat
if (state.getSelectedPrivateChatPeerValue() != peerID && message.sender != state.getNicknameValue()) {
@@ -124,6 +130,8 @@ class MessageManager(private val state: ChatState) {
chatMessages.add(message)
currentPrivateChats[peerID] = chatMessages
state.setPrivateChats(currentPrivateChats)
// Reflect into process-wide store
try { com.bitchat.android.services.AppStateStore.addPrivateMessage(peerID, message) } catch (_: Exception) { }
}
fun clearPrivateMessages(peerID: String) {
@@ -206,6 +214,21 @@ class MessageManager(private val state: ChatState) {
// MARK: - Delivery Status Updates
private fun statusPriority(status: DeliveryStatus?): Int = when (status) {
null -> 0
is DeliveryStatus.Sending -> 1
is DeliveryStatus.Sent -> 2
is DeliveryStatus.PartiallyDelivered -> 3
is DeliveryStatus.Delivered -> 4
is DeliveryStatus.Read -> 5
is DeliveryStatus.Failed -> 0 // treat as lowest for UI check marks ordering
}
private fun chooseStatus(old: DeliveryStatus?, new: DeliveryStatus): DeliveryStatus? {
// Never downgrade (e.g., Read -> Delivered). Keep the higher priority.
return if (statusPriority(new) >= statusPriority(old)) new else old
}
fun updateMessageDeliveryStatus(messageID: String, status: DeliveryStatus) {
// Update in private chats
val updatedPrivateChats = state.getPrivateChatsValue().toMutableMap()
@@ -215,22 +238,32 @@ class MessageManager(private val state: ChatState) {
val updatedMessages = messages.toMutableList()
val messageIndex = updatedMessages.indexOfFirst { it.id == messageID }
if (messageIndex >= 0) {
updatedMessages[messageIndex] = updatedMessages[messageIndex].copy(deliveryStatus = status)
updatedPrivateChats[peerID] = updatedMessages
updated = true
val current = updatedMessages[messageIndex].deliveryStatus
val finalStatus = chooseStatus(current, status)
if (finalStatus !== current) {
updatedMessages[messageIndex] = updatedMessages[messageIndex].copy(deliveryStatus = finalStatus)
updatedPrivateChats[peerID] = updatedMessages
updated = true
}
}
}
if (updated) {
state.setPrivateChats(updatedPrivateChats)
// Keep process-wide store in sync to prevent snapshot overwrites resetting status
try { com.bitchat.android.services.AppStateStore.updatePrivateMessageStatus(messageID, status) } catch (_: Exception) { }
}
// Update in main messages
val updatedMessages = state.getMessagesValue().toMutableList()
val messageIndex = updatedMessages.indexOfFirst { it.id == messageID }
if (messageIndex >= 0) {
updatedMessages[messageIndex] = updatedMessages[messageIndex].copy(deliveryStatus = status)
state.setMessages(updatedMessages)
val current = updatedMessages[messageIndex].deliveryStatus
val finalStatus = chooseStatus(current, status)
if (finalStatus !== current) {
updatedMessages[messageIndex] = updatedMessages[messageIndex].copy(deliveryStatus = finalStatus)
state.setMessages(updatedMessages)
}
}
// Update in channel messages
@@ -239,8 +272,12 @@ class MessageManager(private val state: ChatState) {
val channelMessagesList = messages.toMutableList()
val channelMessageIndex = channelMessagesList.indexOfFirst { it.id == messageID }
if (channelMessageIndex >= 0) {
channelMessagesList[channelMessageIndex] = channelMessagesList[channelMessageIndex].copy(deliveryStatus = status)
updatedChannelMessages[channel] = channelMessagesList
val current = channelMessagesList[channelMessageIndex].deliveryStatus
val finalStatus = chooseStatus(current, status)
if (finalStatus !== current) {
channelMessagesList[channelMessageIndex] = channelMessagesList[channelMessageIndex].copy(deliveryStatus = finalStatus)
updatedChannelMessages[channel] = channelMessagesList
}
}
}
state.setChannelMessages(updatedChannelMessages)