This article provides a step-by-step tutorial to integrate a self-managed
ConnectionService into a VoIP Android application based on the Voximplant Android SDK.
ConnectionService resolves the situation of multiple calls from various applications that also use the ConnectionService API, such as switching between calls on hold or answering an incoming call when you're already on a call. It also allows answering or declining calls on wearable devices.
Manifest declarations and permissions
To integrate a self-managed
ConnectionService, declare the
MANAGE_OWN_CALLS permission in the AndroidManifest.xml file.
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
ConnectionService, declare the service itself and the BIND_TELECOM_CONNECTION_SERVICE permission in the AndroidManifest.xml file.
<service android:name=".services.CallConnectionService" android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"> <intent-filter> <action android:name="android.telecom.ConnectionService" /> </intent-filter> </service>
TelecomManager and PhoneAccount
TelecomManager uses a registered
PhoneAccount to place a phone/VoIP call. To build a
PhoneAccount, the app should provide a valid
PhoneAccountHandle which refers to the connection service implementation that
Telecom will use to interact with the app.
PhoneAccountHandle consists of a component name of the associated connection service and a string identifier that is unique among
PhoneAccountHandles with the same component name. See
PhoneAccountHandler on the Android Developers site.
For a self-managed
PhoneAccount.CAPABILITY_SELF_MANAGED to indicate that this
PhoneAccount is responsible for managing its own
Create and manage a call connection
Android Telecom Connection
Connection represents a phone call or connection to a remote endpoint that carries voice and/or video traffic.
By that definition, creating a new Android Telecom Connection for each Voximplant call (
ICall) is required. This way the Voximplant
ICall interface manages a VoIP call and Telecom Connection registers this call in the telecom subsystem.
Connection must be specified with the following parameters:
You can also use additional features such as putting a call on hold or muting with
connectionCapabilities. Find the full list of features on the Android Developers site.
Make an outgoing call
To create an outgoing call, check that a
PhoneAccount is registered and then use the
ConnectionService must contain
EXTRA_PHONE_ACCOUNT_HANDLE in the Bundle extra to specify the
PhoneAccountHandle associated with it.
If the app can place an outgoing call, the telecom subsystem calls the
onCreateOutgoingConnection() method to where the app must return a new
Connection to represent a new outgoing call.
It is important to call
Connection.setActive() once the outgoing call is connected. It notifies the telecom subsystem that the call is in progress.
Receive an incoming call
When the app receives an incoming call via the Voximplant SDK (
IClientIncomingCallListener.onIncomingCall()), it is necessary to check the
PhoneAccount registration in the system. To register a new incoming call, use the
The telecom subsystem binds to the app's
ConnectionService and requests a new
Connection instance for the incoming call using the
ConnectionService.onCreateIncomingConnection() API. Upon receiving this event, the application needs to create a
For a self-managed connection service, the
Connection will trigger the
Connection.onShowIncomingCallUi() event to let the application know when to display the incoming call UI. Showing a notification with full-screen intent is recommended.
The user may accept and reject the incoming call from the incoming call notification or wearable devices:
If the user answers or rejects the call from the notification, it should be handled by the application via PendingIntent.
If the user answers or rejects the call from a wearable device, the
Connectionwill inform you about this action by triggering the
To answer the call, you need the
ICall.answer() API. Establish the call connection using the Voximplant Android SDK and update the
Connection state to active once the call is connected (
To reject the call, you need the
ICall.reject() API. The Voximplant Android SDK triggers the
ICallListener.onCallDisconnected() event as soon as the call is ended. The application must set the
Connection status to disconnected and destroy the
Manage ongoing call
The Voximplant Android SDK provides the following capabilities for an ongoing call:
Put the call on hold
Change the audio device
Mute and audio device changing capabilities are fully managed by the Voximplant Android SDK and do not require any
Connection API call.
However, to put the call on hold, the application
Connection state should be changed via the
Connection.setOnHold() API. Please be sure to change the
Connection state only if
ICall.hold() is completed successfully.
1) On devices running Android API level 28 or higher, when an incoming PSTN call is answered by the user, the VoIP ongoing call is put on hold by
TelecomManager and can be resumed after the PSTN call ends.
- 2) On devices running Android API level 27 or lower, only one app can maintain an ongoing call at any given time. This constraint means that the ongoing call will be terminated.
End ongoing call
Either a user or a remote party can end an ongoing call.
If the user ends the call, the application should call
ICall.hangup() API, so the Voximplant Android SDK triggers the
If the remote party ends the call, the Voximplant Android SDK informs the application by triggering the
After receiving the
ICallListener.onCallDisconnected() event you need to:
- Change the
Connectionstatus to disconnected via
- Destroy the
Connection.destroy()API to destroy the Connection object.
DisconnectCause describes the cause of a disconnected call. It always includes a code describing the generic cause of the disconnect. Optionally, it may include a label and/or description to be displayed to the user. The
ConnectionService provides localized versions of the label and description. It may also contain a disconnect reason used for the logs, and not intended for the user.
DisconnectCause on the Android Developers site for more information.