fixing conneciton state after a wifi disconnect

This commit is contained in:
2025-07-04 07:59:11 -04:00
parent 613686989e
commit c6e43a9f96
2 changed files with 66 additions and 35 deletions

View File

@@ -38,6 +38,8 @@ class WifiAwareManager(private val context: Context) {
private var subscribeDiscoverySession: SubscribeDiscoverySession? = null private var subscribeDiscoverySession: SubscribeDiscoverySession? = null
private val peerHandles = ConcurrentHashMap<String, PeerHandle>() private val peerHandles = ConcurrentHashMap<String, PeerHandle>()
private val peerRoomMapping = ConcurrentHashMap<String, String>() // PeerHandle.toString() -> roomName
private var currentRoom: String? = null
// Replace callbacks with Flows // Replace callbacks with Flows
private val _messageFlow = MutableSharedFlow<Triple<String, String, String>>() private val _messageFlow = MutableSharedFlow<Triple<String, String, String>>()
@@ -111,6 +113,7 @@ class WifiAwareManager(private val context: Context) {
} }
fun startHostMode(roomName: String) { fun startHostMode(roomName: String) {
currentRoom = roomName
val config = PublishConfig.Builder() val config = PublishConfig.Builder()
.setServiceName(SERVICE_NAME) .setServiceName(SERVICE_NAME)
.setServiceSpecificInfo(roomName.toByteArray()) .setServiceSpecificInfo(roomName.toByteArray())
@@ -196,6 +199,7 @@ class WifiAwareManager(private val context: Context) {
// Store peer handle for this room // Store peer handle for this room
peerHandles[roomName] = peerHandle peerHandles[roomName] = peerHandle
currentRoom = roomName
// Send connection request to host // Send connection request to host
Log.d(TAG, "Sending connection request to room: $roomName") Log.d(TAG, "Sending connection request to room: $roomName")
@@ -203,7 +207,8 @@ class WifiAwareManager(private val context: Context) {
// Update peer activity when discovered // Update peer activity when discovered
val peerId = peerHandle.toString() val peerId = peerHandle.toString()
lastPeerActivity[peerId] = System.currentTimeMillis() peerRoomMapping[peerId] = roomName
lastPeerActivity[roomName] = System.currentTimeMillis()
// Wait a bit for host to prepare, then connect // Wait a bit for host to prepare, then connect
coroutineScope.launch { coroutineScope.launch {
@@ -288,8 +293,19 @@ class WifiAwareManager(private val context: Context) {
override fun onLost(network: android.net.Network) { override fun onLost(network: android.net.Network) {
Log.d(TAG, "onLost: Network lost for room: $roomName") Log.d(TAG, "onLost: Network lost for room: $roomName")
// Clear peer handles when connection is lost // Check if we still have active keep-alive for this room
val lastActivity = lastPeerActivity[roomName]
val currentTime = System.currentTimeMillis()
if (lastActivity != null && (currentTime - lastActivity) < KEEP_ALIVE_TIMEOUT_MS) {
Log.d(TAG, "Network lost but keep-alive still active for room: $roomName - ignoring disconnect")
// Don't disconnect if keep-alive is still active
return
}
// Clear peer handles when connection is truly lost
peerHandles.remove(roomName) peerHandles.remove(roomName)
lastPeerActivity.remove(roomName)
coroutineScope.launch { coroutineScope.launch {
_connectionFlow.emit(Pair(roomName, false)) _connectionFlow.emit(Pair(roomName, false))
} }
@@ -358,8 +374,10 @@ class WifiAwareManager(private val context: Context) {
override fun onAvailable(network: android.net.Network) { override fun onAvailable(network: android.net.Network) {
Log.d(TAG, "Client connected") Log.d(TAG, "Client connected")
val peerId = peerHandle.toString() val peerId = peerHandle.toString()
peerHandles[peerId] = peerHandle val roomName = currentRoom ?: "host"
lastPeerActivity[peerId] = System.currentTimeMillis() peerHandles[roomName] = peerHandle
peerRoomMapping[peerId] = roomName
lastPeerActivity[roomName] = System.currentTimeMillis()
if (!isResumed) { if (!isResumed) {
isResumed = true isResumed = true
continuation.resume(Result.success(Unit)) continuation.resume(Result.success(Unit))
@@ -391,7 +409,11 @@ class WifiAwareManager(private val context: Context) {
try { try {
// Update peer activity on any message // Update peer activity on any message
val peerId = peerHandle.toString() val peerId = peerHandle.toString()
lastPeerActivity[peerId] = System.currentTimeMillis() val roomName = peerRoomMapping[peerId] ?: currentRoom
if (roomName != null) {
lastPeerActivity[roomName] = System.currentTimeMillis()
}
val messageStr = String(message) val messageStr = String(message)
val parts = messageStr.split("|", limit = 3) val parts = messageStr.split("|", limit = 3)
@@ -468,23 +490,23 @@ class WifiAwareManager(private val context: Context) {
var messagesSent = 0 var messagesSent = 0
if (publishDiscoverySession != null && peerHandles.isNotEmpty()) { if (publishDiscoverySession != null && peerHandles.isNotEmpty()) {
peerHandles.forEach { (peerId, peerHandle) -> peerHandles.forEach { (roomName, peerHandle) ->
try { try {
publishDiscoverySession?.sendMessage(peerHandle, messagesSent, message) publishDiscoverySession?.sendMessage(peerHandle, messagesSent, message)
messagesSent++ messagesSent++
Log.d(TAG, "Sent keep-alive to peer: $peerId") Log.d(TAG, "Sent keep-alive to room: $roomName")
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Failed to send keep-alive to peer: $peerId", e) Log.e(TAG, "Failed to send keep-alive to room: $roomName", e)
} }
} }
} else if (subscribeDiscoverySession != null && peerHandles.isNotEmpty()) { } else if (subscribeDiscoverySession != null && peerHandles.isNotEmpty()) {
peerHandles.forEach { (peerId, peerHandle) -> peerHandles.forEach { (roomName, peerHandle) ->
try { try {
subscribeDiscoverySession?.sendMessage(peerHandle, messagesSent, message) subscribeDiscoverySession?.sendMessage(peerHandle, messagesSent, message)
messagesSent++ messagesSent++
Log.d(TAG, "Sent keep-alive to peer: $peerId") Log.d(TAG, "Sent keep-alive to room: $roomName")
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "Failed to send keep-alive to peer: $peerId", e) Log.e(TAG, "Failed to send keep-alive to room: $roomName", e)
} }
} }
} }
@@ -493,7 +515,12 @@ class WifiAwareManager(private val context: Context) {
private fun handleKeepAlive(peerHandle: PeerHandle, shouldReply: Boolean) { private fun handleKeepAlive(peerHandle: PeerHandle, shouldReply: Boolean) {
// Update last activity for this peer // Update last activity for this peer
val peerId = peerHandle.toString() val peerId = peerHandle.toString()
lastPeerActivity[peerId] = System.currentTimeMillis() val roomName = peerRoomMapping[peerId] ?: currentRoom
if (roomName != null) {
lastPeerActivity[roomName] = System.currentTimeMillis()
Log.d(TAG, "Updated keep-alive activity for room: $roomName")
}
// Send acknowledgment if requested // Send acknowledgment if requested
if (shouldReply) { if (shouldReply) {
@@ -513,25 +540,26 @@ class WifiAwareManager(private val context: Context) {
private fun checkPeerActivity() { private fun checkPeerActivity() {
val currentTime = System.currentTimeMillis() val currentTime = System.currentTimeMillis()
val inactivePeers = mutableListOf<String>() val inactiveRooms = mutableListOf<String>()
lastPeerActivity.forEach { (peerId, lastActivity) -> lastPeerActivity.forEach { (roomName, lastActivity) ->
if (currentTime - lastActivity > KEEP_ALIVE_TIMEOUT_MS) { if (currentTime - lastActivity > KEEP_ALIVE_TIMEOUT_MS) {
Log.w(TAG, "Peer $peerId inactive for too long, considering disconnected") Log.w(TAG, "Room $roomName inactive for too long, considering disconnected")
inactivePeers.add(peerId) inactiveRooms.add(roomName)
} }
} }
// Remove inactive peers // Remove inactive rooms
inactivePeers.forEach { peerId -> inactiveRooms.forEach { roomName ->
lastPeerActivity.remove(peerId) lastPeerActivity.remove(roomName)
peerHandles.remove(peerId) peerHandles.remove(roomName)
}
// If all peers are disconnected, emit disconnection event // Clean up peer room mapping
if (peerHandles.isEmpty() && lastPeerActivity.isNotEmpty()) { peerRoomMapping.entries.removeIf { it.value == roomName }
// Emit disconnection event for this room
coroutineScope.launch { coroutineScope.launch {
_connectionFlow.emit(Pair("", false)) _connectionFlow.emit(Pair(roomName, false))
} }
} }
} }
@@ -547,6 +575,8 @@ class WifiAwareManager(private val context: Context) {
wifiAwareSession?.close() wifiAwareSession?.close()
wifiAwareSession = null wifiAwareSession = null
peerHandles.clear() peerHandles.clear()
peerRoomMapping.clear()
currentRoom = null
// Don't cancel the coroutine scope - we need it for future operations // Don't cancel the coroutine scope - we need it for future operations
Log.d(TAG, "WifiAwareManager stopped - session cleared for fresh start") Log.d(TAG, "WifiAwareManager stopped - session cleared for fresh start")
} }

View File

@@ -72,14 +72,7 @@ class ChatRepository @Inject constructor(
) )
addMessage(message) addMessage(message)
// If we're receiving messages, we must be connected // Don't change connection state based on messages - let WifiAwareManager handle it
if (_connectionState.value !is ConnectionState.Connected &&
_connectionState.value !is ConnectionState.Hosting) {
when (_connectionState.value) {
is ConnectionState.Hosting -> {} // Keep hosting state
else -> _connectionState.value = ConnectionState.Connected("Active")
}
}
} }
} catch (e: Exception) { } catch (e: Exception) {
android.util.Log.e("ChatRepository", "Error collecting message flow", e) android.util.Log.e("ChatRepository", "Error collecting message flow", e)
@@ -90,13 +83,21 @@ class ChatRepository @Inject constructor(
repositoryScope.launch { repositoryScope.launch {
try { try {
wifiAwareManager.connectionFlow.collect { (roomName, isConnected) -> wifiAwareManager.connectionFlow.collect { (roomName, isConnected) ->
android.util.Log.d("ChatRepository", "Connection flow update - room: $roomName, connected: $isConnected, current state: ${_connectionState.value}")
if (isConnected) { if (isConnected) {
currentRoomName = roomName currentRoomName = roomName
// Only change to connected if we're not already hosting
if (_connectionState.value !is ConnectionState.Hosting) {
_connectionState.value = ConnectionState.Connected(roomName) _connectionState.value = ConnectionState.Connected(roomName)
}
loadMessagesFromDatabase(roomName) loadMessagesFromDatabase(roomName)
} else { } else {
// Only disconnect if the room matches our current room
if (roomName.isEmpty() || roomName == currentRoomName) {
_connectionState.value = ConnectionState.Disconnected _connectionState.value = ConnectionState.Disconnected
} }
}
// Call the legacy callback if set // Call the legacy callback if set
connectionCallback?.invoke(roomName, isConnected) connectionCallback?.invoke(roomName, isConnected)
} }