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
@@ -0,0 +1,66 @@
package com.bitchat.android.service
import android.content.Context
import com.bitchat.android.mesh.BluetoothMeshService
/**
* Process-wide holder to share a single BluetoothMeshService instance
* between the foreground service and UI (MainActivity/ViewModels).
*/
object MeshServiceHolder {
private const val TAG = "MeshServiceHolder"
@Volatile
var sharedGossipSyncManager: com.bitchat.android.sync.GossipSyncManager? = null
private set
fun setGossipManager(mgr: com.bitchat.android.sync.GossipSyncManager) { sharedGossipSyncManager = mgr }
@Volatile
var meshService: BluetoothMeshService? = null
private set
@Synchronized
fun getOrCreate(context: Context): BluetoothMeshService {
val existing = meshService
if (existing != null) {
// If the existing instance is healthy, reuse it; otherwise, replace it.
return try {
if (existing.isReusable()) {
android.util.Log.d(TAG, "Reusing existing BluetoothMeshService instance")
existing
} else {
android.util.Log.w(TAG, "Existing BluetoothMeshService not reusable; replacing with a fresh instance")
// Best-effort stop before replacing
try { existing.stopServices() } catch (e: Exception) {
android.util.Log.w(TAG, "Error while stopping non-reusable instance: ${e.message}")
}
val created = BluetoothMeshService(context.applicationContext)
android.util.Log.i(TAG, "Created new BluetoothMeshService (replacement)")
meshService = created
created
}
} catch (e: Exception) {
android.util.Log.e(TAG, "Error checking service reusability; creating new instance: ${e.message}")
val created = BluetoothMeshService(context.applicationContext)
meshService = created
created
}
}
val created = BluetoothMeshService(context.applicationContext)
android.util.Log.i(TAG, "Created new BluetoothMeshService (no existing instance)")
meshService = created
return created
}
@Synchronized
fun attach(service: BluetoothMeshService) {
android.util.Log.d(TAG, "Attaching BluetoothMeshService to holder")
meshService = service
}
@Synchronized
fun clear() {
android.util.Log.d(TAG, "Clearing BluetoothMeshService from holder")
meshService = null
}
}