Skip to main content
Keep calls alive when users navigate away from your app. Background handling ensures the call continues running when users press the home button, switch to another app, or lock their device.

Overview

When a user leaves your call activity, Android may terminate it to free resources. The SDK provides CometChatOngoingCallService - a foreground service that:
  • Keeps the call session active in the background
  • Shows an ongoing notification in the status bar
  • Allows users to return to the call with a single tap
  • Provides a hangup action directly from the notification

When to Use

ScenarioSolution
User stays in call activityNo action needed
User enters Picture-in-PicturePiP Mode handles this
User presses HOME during callUse OngoingCallService
User switches to another appUse OngoingCallService
Receiving calls when app is killedVoIP Calling handles this
Background Handling is different from VoIP Calling. VoIP handles receiving calls when the app is not running. Background Handling keeps an active call alive when the user leaves the app.

Implementation

Step 1: Add Manifest Permissions

Add the required permissions and service declaration to your AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- Required for foreground service -->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

</manifest>

Step 2: Start Service on Session Join

Start the ongoing call service when the user successfully joins a call session:
import com.cometchat.calls.services.CometChatOngoingCallService
import com.cometchat.calls.utils.OngoingNotification

class CallActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_call)

        val callSession = CallSession.getInstance()

        callSession.addSessionStatusListener(this, object : SessionStatusListener() {
            override fun onSessionJoined() {
                // Start the foreground service to keep call alive in background
                CometChatOngoingCallService.launch(this@CallActivity)
            }

            override fun onSessionLeft() {
                // Stop the service when call ends
                CometChatOngoingCallService.abort(this@CallActivity)
                finish()
            }

            override fun onConnectionClosed() {
                CometChatOngoingCallService.abort(this@CallActivity)
            }
        })

        // Join the session...
    }

    override fun onDestroy() {
        // Always stop the service when activity is destroyed
        CometChatOngoingCallService.abort(this)
        super.onDestroy()
    }
}

Custom Notification

Customize the ongoing call notification to match your app’s branding:
import com.cometchat.calls.utils.OngoingNotification

private fun buildCustomNotification(): Notification {
    val channelId = "CometChat_Call_Ongoing_Conference"
    
    // Intent to return to call when notification is tapped
    val intent = Intent(this, CallActivity::class.java).apply {
        flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
    }
    val pendingIntent = PendingIntent.getActivity(
        this, 0, intent,
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
    )

    return NotificationCompat.Builder(this, channelId)
        .setSmallIcon(R.drawable.ic_call)
        .setContentTitle("Ongoing Call")
        .setContentText("Tap to return to your call")
        .setPriority(NotificationCompat.PRIORITY_HIGH)
        .setContentIntent(pendingIntent)
        .setOngoing(true)
        .setAutoCancel(false)
        .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
        .build()
}

// Use custom notification before launching service
callSession.addSessionStatusListener(this, object : SessionStatusListener() {
    override fun onSessionJoined() {
        OngoingNotification.buildOngoingConferenceNotification(buildCustomNotification())
        CometChatOngoingCallService.launch(this@CallActivity)
    }
})
The notification channel ID must be CometChat_Call_Ongoing_Conference to work with the SDK’s service.

Complete Example

class CallActivity : AppCompatActivity() {

    private lateinit var callSession: CallSession

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_call)

        callSession = CallSession.getInstance()
        
        setupSessionListener()
        joinCall()
    }

    private fun setupSessionListener() {
        callSession.addSessionStatusListener(this, object : SessionStatusListener() {
            override fun onSessionJoined() {
                // Build custom notification (optional)
                OngoingNotification.buildOngoingConferenceNotification(buildCustomNotification())
                
                // Start foreground service
                CometChatOngoingCallService.launch(this@CallActivity)
            }

            override fun onSessionLeft() {
                CometChatOngoingCallService.abort(this@CallActivity)
                finish()
            }

            override fun onConnectionClosed() {
                CometChatOngoingCallService.abort(this@CallActivity)
            }
        })
    }

    private fun joinCall() {
        val sessionId = intent.getStringExtra("SESSION_ID") ?: return
        val container = findViewById<FrameLayout>(R.id.callContainer)

        val sessionSettings = CometChatCalls.SessionSettingsBuilder()
            .setTitle("My Call")
            .build()

        CometChatCalls.joinSession(
            sessionId = sessionId,
            sessionSettings = sessionSettings,
            view = container,
            context = this,
            listener = object : CometChatCalls.CallbackListener<CallSession>() {
                override fun onSuccess(session: CallSession) {
                    Log.d(TAG, "Joined call successfully")
                }

                override fun onError(e: CometChatException) {
                    Log.e(TAG, "Failed to join: ${e.message}")
                    finish()
                }
            }
        )
    }

    private fun buildCustomNotification(): Notification {
        val channelId = "CometChat_Call_Ongoing_Conference"
        
        val intent = Intent(this, CallActivity::class.java).apply {
            flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
        }
        val pendingIntent = PendingIntent.getActivity(
            this, 0, intent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )

        return NotificationCompat.Builder(this, channelId)
            .setSmallIcon(R.drawable.ic_call)
            .setContentTitle("Ongoing Call")
            .setContentText("Tap to return to your call")
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setContentIntent(pendingIntent)
            .setOngoing(true)
            .setAutoCancel(false)
            .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
            .build()
    }

    override fun onDestroy() {
        CometChatOngoingCallService.abort(this)
        super.onDestroy()
    }

    companion object {
        private const val TAG = "CallActivity"
    }
}

API Reference

CometChatOngoingCallService

MethodDescription
launch(context)Starts the foreground service with an ongoing notification
abort(context)Stops the foreground service and removes the notification

OngoingNotification

MethodDescription
buildOngoingConferenceNotification(notification)Sets a custom notification to display. Call before launch()
createNotificationChannel(activity)Creates the notification channel (called automatically)