89cf5e14d4
The previous approach used a detached CoroutineScope in CallActivity.onDestroy to publish hangup/reject events. This was unreliable: the process could be killed before the coroutine completed, leaving the remote peer's phone ringing. Fix: CallForegroundService now owns hangup signaling via two paths: 1. onTaskRemoved() — fires when user swipes app from Recents. Uses runBlocking with 3-second timeout to synchronously publish hangup before the service is killed. 2. onDestroy() — fires when the service is stopped for any other reason. Same runBlocking pattern as a safety net. Changes: - AndroidManifest: stopWithTask="false" so onTaskRemoved fires instead of the service being silently killed. - CallForegroundService: added onTaskRemoved(), onDestroy(), and publishHangupBlocking() helper. - CallActivity.onDestroy: removed fire-and-forget CoroutineScope. Session resource cleanup (close()) still happens here; signaling hangup is delegated to the foreground service. - CallSessionBridge.clear(): converted fire-and-forget hangup to runBlocking with 3-second timeout for account-switch safety. The three-layer hangup guarantee is now: 1. CallForegroundService.onTaskRemoved/onDestroy — synchronous, reliable (runBlocking). 2. CallManager ringing watchdog (65s) — if nothing else fires. 3. Remote peer's own timeout — last resort. https://claude.ai/code/session_019yNnDjGKmJb19gadmojq54