VoIP applications can integrate their calls into the system call log. This lets users see their VoIP call history centrally in the system dialer app and return calls directly from the dialer app. This guide describes the required changes to VoIP calling apps, system dialer apps, and managing unified call history settings.
Changes for the calling app
To integrate your VoIP app with the system call log, follow these steps.
Register callback intent filter
Register the system-protected intent TelecomManager.ACTION_CALL_BACK.
Once this intent filter is properly registered, any calls your app adds using
CallsManager.addCall or other related Telecom APIs will be automatically
logged by the system. The system uses this registered intent to later send a
callback to your app when a user selects a VoIP call log entry in the dialer
to return the call.
<!-- Activity to handle the callback intent from the system dialer --> <activity android:name=".VoipCallActivity" android:exported="true"> <!-- Register callback intent --> <intent-filter> <action android:name="android.telecom.action.CALL_BACK" /> </intent-filter> </activity>
Exclude call logging
Once the callback is registered, all calls are logged to the system
dialer. To exclude calls on a per-call basis, set the isLogExcluded
boolean to true within CallAttributesCompat.
CallAttributesCompat( displayName = displayName, address = address, isLogExcluded = excludeCallLogging, // to exclude call from logging direction = if (isIncoming) { CallAttributesCompat.DIRECTION_INCOMING } else { CallAttributesCompat.DIRECTION_OUTGOING }, callType = CallAttributesCompat.CALL_TYPE_AUDIO_CALL, callCapabilities = ( CallAttributesCompat.SUPPORTS_SET_INACTIVE or CallAttributesCompat.SUPPORTS_STREAM or CallAttributesCompat.SUPPORTS_TRANSFER ), )
Handle callbacks
Calls added through CallsManager.addCall get a unique UUID through
CallControlScope.getCallId.
// check the intent action for CALL_BACK if (intent.action == TelecomManager.ACTION_CALL_BACK) { launchCall( // fetching stored call details for the UUID to initiate callback callDetails = getCallDetails( uuid = intent.getStringExtra(TelecomManager.EXTRA_UUID) ) ) }
Verify call log entries
The system call log maintains a finite number of entries and eventually
purges old call records. Because the app stores a mapping of UUIDs to call
details for callback handling, it should periodically check which UUIDs are
still present in the system call log. If a UUID is no longer in the system
log, the user cannot initiate a callback for that call, and the app can
safely remove the mapping from its local storage. This practice helps
optimize storage.
To get the current list of UUIDs attributed to the app within the system
log, use CallLog.Calls.CONTENT_VOIP_URI.
Changes for the dialer app
Follow these steps to enable the dialer app to display VoIP call logs and initiate callbacks to VoIP apps.
Display VoIP call logs in the dialer app
By default, VoIP apps call logs don't appear in the dialer app. To display the integrated call logs in the dialer app, do the following:
On Android 16.1 (API level 36.1), append the query parameter
include_voip_callsto theCallLog.Callscontent provider to display VoIP call logs:CallLog.Calls.CONTENT_URI.buildUpon() .appendQueryParameter("include_voip_calls", "true") .build()
On Android 17 (API level 37) and higher, use the following formalized content provider and parameter key:
Initiate callbacks from dialer app
To initiate a callback from a dialer, use TelecomManager.placeCall. The
platform uses the unique CallLog.Calls._ID of the call log entry to launch
the correct VoIP app. This launch includes a
TelecomManager.ACTION_CALL_BACK intent, which is a system-defined action
for initiating a return call. This intent contains the call's UUID in
intent extra TelecomManager.EXTRA_UUID, allowing the VoIP app to identify
which specific call is being called back.
// Uri generated with unique ID of the call log entry to launch the respective VoIP app for callback val address = ContentUris.withAppendedId(CallLog.Calls.CONTENT_URI, callId) // extra information required to initiate callback val extras = Bundle() telecomManager.placeCall(address, extras)
Manage unified call history settings
Starting in Android 17 (API level 37), users can view and toggle unified call history on a per-app basis in system settings (typically under Settings > Calling accounts > Integrated call logs or directly within their default dialer app). Both third-party calling apps and dialer apps can interact with these settings.
Navigate users to settings
To open unified call history settings, start an activity with the
TelecomManager.ACTION_CONFIGURE_CALL_LOG_INTEGRATION intent action:
val intent = Intent(TelecomManager.ACTION_CONFIGURE_CALL_LOG_INTEGRATION) startActivity(intent)
When a user turns off unified call history for an app in system settings, the
system immediately and permanently purges all existing call log entries for that
package from the native call log provider (CallLog.Calls). Future calls
initiated by or received for that app won't be recorded in the system dialer.
Listen for preference changes
To stay synchronized when a user enables or disables unified call history for
your calling app in system settings or the dialer, register a broadcast receiver
for the TelecomManager.ACTION_VOIP_CALL_LOG_PREFERENCE
(android.telecom.action.VOIP_CALL_LOG_PREFERENCE) broadcast intent:
val receiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (intent.action == TelecomManager.ACTION_VOIP_CALL_LOG_PREFERENCE) { // Status of the Unified Call History of the app val isEnabled = intent.getBooleanExtra( TelecomManager.EXTRA_VOIP_CALL_LOG_PREFERENCE_STATUS, true ) } } }
When the user flips the toggle, the platform broadcasts this intent to your
app containing the updated boolean state in the
TelecomManager.EXTRA_VOIP_CALL_LOG_PREFERENCE_STATUS extra. Instead of
waiting for periodic verification against CallLog.Calls, your app can listen
to this broadcast. When unified call history is disabled (in other words, set to
false), your app can update its internal state or perform cleanup such as
clearing locally cached call mappings used for callback handling.