Skip to content

Commit d28b6fc

Browse files
committed
fix(android): tear down surviving call legs on empty-metadata restart
If LMK kills only the main process, the Telecom call survives in the :callkeep_core process (kept alive by the system server binding). The old unconditional sticky-restart notification accidentally provided the last hang-up handle for that leg: Hang up on the orphan notification reached tearDownService. The empty-metadata guard removed that handle silently, leaving the device stuck in a zombie Telecom call (new incoming calls are treated as busy/call-waiting) with no UI to end it until the app is reopened. Call tearDownService() in the guard branch before stopping: the zombie leg is now cleaned up automatically instead of requiring a manual tap. It must run before stopForeground - while the service is still foreground, the startService toward the connection services is exempt from background-start restrictions (both communicate() implementations are also try/catch-guarded).
1 parent 97946fd commit d28b6fc

2 files changed

Lines changed: 10 additions & 1 deletion

File tree

webtrit_callkeep_android/android/src/main/kotlin/com/webtrit/callkeep/services/services/active_call/ActiveCallService.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,15 @@ class ActiveCallService : Service() {
8080
// process was killed. NotificationManager tracks active calls in its own static
8181
// list, so nothing will ever stop this orphaned instance - an ongoing notification
8282
// left here would be undismissable until the user force-stops the app.
83-
Log.w(TAG, "onStartCommand: no calls metadata (null-intent restart), stopping self")
83+
//
84+
// A call leg may have survived in :callkeep_core (Telecom keeps that process alive
85+
// via its own binding), and this restart is the last signal the main process gets
86+
// about it: tear the connection services down so the device is not left stuck in a
87+
// zombie Telecom call with no UI to end it. Must run before stopForeground - while
88+
// this service is still foreground the startService toward the connection services
89+
// is exempt from background-start restrictions.
90+
Log.w(TAG, "onStartCommand: no calls metadata (null-intent restart), tearing down and stopping self")
91+
CallkeepCore.instance.tearDownService()
8492
stopForeground(STOP_FOREGROUND_REMOVE)
8593
stopSelf()
8694
return START_NOT_STICKY

webtrit_callkeep_android/android/src/test/kotlin/com/webtrit/callkeep/services/services/active_call/ActiveCallServiceRestartTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import org.robolectric.annotation.Config
2929
* cannot be swiped away, and the Hang up action has no visible effect.
3030
*
3131
* The guard: after satisfying the startForeground contract, an instance with no calls
32+
* tears down the connection services (a call leg may have survived in :callkeep_core),
3233
* removes its notification and stops itself; the empty branch of hungUpCall does the same
3334
* on top of the existing tearDownService fallback.
3435
*/

0 commit comments

Comments
 (0)