From a1f8817fceb9f957919125657b0036ecaa0d4d9a Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 3 Apr 2026 17:31:06 +0000 Subject: [PATCH] fix: stop call ringing when Ended state is missed due to StateFlow conflation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The state collector in CallController was blocking on showIncomingCallNotification() which downloads the caller's profile picture over the network. Because StateFlow is conflated, if the call ended (peer hangup, reject, timeout) while the collector was suspended, the Ended→Idle transition would cause the Ended emission to be lost. Since cleanup/stopRinging only ran in the Ended handler, the ringtone and vibration would continue indefinitely. Two fixes: 1. Launch showIncomingCallNotification in a separate coroutine so the collector is never blocked by network I/O. 2. Add a safety-net Idle handler that stops ringing, ringback tone, and cancels the call notification. https://claude.ai/code/session_01NfyLNgR4d8yjnxaQJ6FUt5 --- .../amethyst/service/call/CallController.kt | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallController.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallController.kt index 638ef64f9..c1f63332f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallController.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallController.kt @@ -155,7 +155,13 @@ class CallController( when (state) { is CallState.IncomingCall -> { withContext(Dispatchers.IO) { audioManager.startRinging() } - showIncomingCallNotification(state.callerPubKey) + // Launch notification in a separate coroutine so that + // long-running network I/O (profile picture download) + // does not block the state collector. StateFlow is + // conflated — if the collector is suspended when the + // state transitions Ended → Idle, the Ended emission + // is lost and cleanup/stopRinging never runs. + scope.launch { showIncomingCallNotification(state.callerPubKey) } } is CallState.Offering -> { @@ -178,7 +184,14 @@ class CallController( cleanup() } - else -> {} + is CallState.Idle -> { + // Safety net: ensure ringing and notifications are + // stopped even if the Ended state was missed due to + // StateFlow conflation. + audioManager.stopRinging() + audioManager.stopRingbackTone() + NotificationUtils.cancelCallNotification(context) + } } } }