fix: add event dedup, back button handling, and wake lock for calls

- Deduplicate signaling events via processedEventIds set in
  CallManager to prevent duplicate processing from multiple relays
- BackHandler on CallScreen calls hangup() before navigating back
- KeepScreenOn composable adds FLAG_KEEP_SCREEN_ON during calls
  and clears it on dispose

https://claude.ai/code/session_017hZm7yu7CzmcQgZGSaqSXS
This commit is contained in:
Claude
2026-04-02 00:46:44 +00:00
parent b04d052507
commit 073e9f052a
2 changed files with 26 additions and 1 deletions
@@ -20,6 +20,8 @@
*/
package com.vitorpamplona.amethyst.ui.call
import android.view.WindowManager
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@@ -40,6 +42,7 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
@@ -50,6 +53,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -73,7 +77,13 @@ fun CallScreen(
) {
val callState by callManager.state.collectAsState()
val scope = rememberCoroutineScope()
val context = androidx.compose.ui.platform.LocalContext.current
val context = LocalContext.current
BackHandler(enabled = callState !is CallState.Idle && callState !is CallState.Ended) {
scope.launch { callManager.hangup() }
}
KeepScreenOn()
when (val state = callState) {
is CallState.Idle -> {
@@ -363,3 +373,15 @@ private fun formatDuration(seconds: Long): String {
val secs = seconds % 60
return "%02d:%02d".format(mins, secs)
}
@Composable
private fun KeepScreenOn() {
val context = LocalContext.current
DisposableEffect(Unit) {
val window = (context as? android.app.Activity)?.window
window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
onDispose {
window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
}
}
@@ -56,6 +56,7 @@ class CallManager(
private var timeoutJob: Job? = null
private var resetJob: Job? = null
private val processedEventIds = mutableSetOf<String>()
companion object {
const val CALL_TIMEOUT_MS = 60_000L // 60 seconds ringing timeout
@@ -198,6 +199,7 @@ class CallManager(
fun onSignalingEvent(event: Event) {
if (isEventTooOld(event)) return
if (!processedEventIds.add(event.id)) return
when (event) {
is CallOfferEvent -> onIncomingCallEvent(event)
@@ -234,6 +236,7 @@ class CallManager(
cancelTimeout()
resetJob?.cancel()
resetJob = null
processedEventIds.clear()
}
private fun transitionToEnded(