Using the SDK with your own UI

Though the Talk SDK includes a built-in UI, you can build and use your own UI if you prefer. The SDK also includes an API that encapsulates all its functionality.

This section describes how to use the SDK API with your own UI. To customize the look and feel of the SDK's built-in UI, see Customizing the look.

You need to create a SDK instance to access the API. See Creating a SDK instance in Getting started.

Topics covered:

Starting calls with your own permissions and call screens

You can build your own permissions and call screens and then use the SDK's API to add functionality to the UI.

Each Talk call has the following setup flow:

  1. Check for agent availability
  2. Check for permission to record audio
  3. Start the call

Use the SDK's API to perform each step in the setup flow.

In addition, your permissions screen should check for permission to access the device's microphone and get the user's permission if not yet granted. To learn more, see Permissions overview in the Android docs.

Check for agent availability

Determine if any agents are available for a Talk digital line. Hiding the call button when no agents are available is recommended to improve the user experience.

Use the API's lineStatus method to determine if any agents are available for a Talk digital line. For details, see Checking for agent availibility in Getting started.

Check for permission to record audio

After determining that agents are available but before starting the call, you must ensure that the user has granted permission to record audio.

Talk SDK requires the following dangerous permission:

  • android.permission.RECORD_AUDIO

To verify whether the permission is granted, use the API's arePermissionsGranted method.


boolean permissionsGranted = talk.arePermissionsGranted();if(permissionsGranted) {    // fine to start a call} else {    // request permission}


val permissionsGranted = talk.arePermissionsGranted()if (permissionsGranted) {    // fine to start the call} else {    // request permission}

If the permission is granted, you can start the call. See Start the call. Otherwise, your application has to obtain the permission from the user. To learn more, see Request App Permissions in the Android docs.

Start the call

Once you're sure that an agent is available and your application has the required permissions, you can start a call to an agent.

  1. Create CallData.


    CallData callData = CallDataBuilder.create("your digital line name")    .recordingConsentAnswer(null)    .build();


    val callData = CallData(digitalLine = "your digital line name", recordingConsentAnswer = null)

    The CallDataBuilder.create method requires a digital line nickname. RecordingConsentAnswer is an optional property.

  2. Create the call.


    TalkListenableFuture<TalkCallResult> job = TalkJavaCompat.createCall(talk, callData);job.addListener(new TalkJavaCompatListener<TalkCallResult>() {    @Override    public void onSuccess(@NotNull TalkCallResult result) {        handleTalkCallResult(result);    }
        @Override    public void onError(@NotNull Throwable throwable) {


    yourCoroutineScope.launch {    val callResult = talk.createCall(callData)    handleTalkCallResult(callResult)}
  3. Handle the result.

    The talk.createCall() method returns TalkCallResult, which is a Kotlin sealed class that contains one of the following states:

    • TalkCallResult.Failure.DigitalLineNotFound - The digital line nickname does not exist in the account
    • TalkCallResult.Failure.Unknown - Creating the call failed due to an unknown error
    • TalkCallResult.Success - Creating the call was successful and a call to an agent was established. See Managing calls with your own call screen

    If the TalkCallResult is TalkCallResult.Failure.DigitalLineNotFound or TalkCallResult.Failure.Unknown, the call was not established and you should inform the user about the error.

Managing calls with your own call screen

After starting a call successfully (when TalkCallResult is TalkCallResult.Success), you can perform the following actions to manage the call:

Listening to call status changes

You can listen to changes in the call status by using the statusChanges property of TalkCallResult.Success. It's called every time the status changes and can be one of the following values:

  • CALL_CONNECTED - the call is connected
  • CALL_DISCONNECTED - the call is disconnected, either by an user or agent
  • CALL_DISCONNECTED_CONNECTION_ERROR - the call is disconnected due to connection issues
  • CALL_FAILED - the call failed to connect
  • CALL_RECONNECTING - the call is not connected and trying to reconnect again
  • CALL_RECONNECTED - the call reconnected after being disconnected



if (result instanceof TalkCallResult.Success) {    TalkCallResult.Success success = (TalkCallResult.Success) result;    success.getStatusChanges().observe(this, new Observer<CallStatus>() {        @Override        public void onChanged(CallStatus callStatus) {            // do something with callStatus        }    });}


if (result is TalkCallResult.Success) {    yourCoroutineScope.launch {        result.statusChanges.collect { callStatus ->            // do something with callStatus        }    }}

Muting or unmuting the call

You can mute or unmute the call.

You can check the current state of muting with the talkCall.isMuted() method. You can change the mute state with talkCall.mute(boolean).


boolean muted = success.getTalkCall().isMuted();success.getTalkCall().mute(!muted);


val muted = result.talkCall.isMuted()result.talkCall.mute(!muted)

Changing the audio output of the call

You can change the audio output of the call from a headset to the device's built-in speakers. By default, the audio is played through a wireless Bluetooth headset when detected or a phone headset when a Bluetooth headset is not found.

To change the audio output, use talkCall.changeAudioOutput(AudioOutput).

AudioOutput is an enum that can be one of the following:

  • AudioOutput.SPEAKERS - the audio is routed through the built-in device speakers
  • AudioOutput.HEADSET - the audio is routed through the device headset
  • AudioOutput.BLUETOOTH - the audio is routed through the external Bluetooth headset

Before setting desired audio output on your call you need to subscribe to updates for supported audio devices. Not all AudioOutput types are supported on all devices (device must support Bluetooth) or in every scenarios (Bluetooth needs to be turned on and the device must be activated).

To minimize the effort required by you, the Talk SDK exposes a stream of supported audio devices. Your application needs to listen to this stream and update your UI options properly based on the values received.

TalkCallResult.Success contains the property availableAudioDevices, which is either of type Flow<List<AudioDevice>> for Kotlin or LiveData<List<AudioDevice>> for Java.

AudioDevice describes the available audio device. In addition to AudioOutput, it may contain additional properties specific for the given type. All descendants of AudioOutput contain a boolean flag indicating whether it's the currently active audio device.

AudioDevice can be one of following items:

  • AudioDevice.Speakers, which has the following properties:
    • isActive: Whether the speakers actively used to play audio or not
    • audioOutput: Enum representing this state. Used to change the active audio output
  • AudioDevice.Headset, which has the following properties:
    • isActive: Whether the speakers actively used to play audio or not
    • audioOutput: Enum representing this state. Used to change the active audio output
  • AudioDevice.BluetoothHeadset, which has the following properties:
    • deviceName: Name of the Bluetooth device or null if the name could not be retrieved
    • isActive: Whether the speakers actively used to play audio or not
    • audioOutput: Enum representing this state. Used to change the active audio output

To retrieve the current state of the audio output, you can use one of following approaches:

  1. Use the talkCall.getAudioOutput() method, which returns the currently used audio output at the moment the method is called.
  2. Use the talkCallResult.availableAudioDevices stream, which is updated any time the active AudioDevice changes or the Bluetooth device changes to another one.

Zendesk recommends using the second approach because it always provides up-to-date data. Use the first approach only when you need data synchronously.

Example - Listening for available audio devices


success.getAvailableAudioDevices().observe(this, new Observer<List<AudioDevice>>() {    @Override    public void onChanged(List<AudioDevice> audioDevices) {        AudioDevice activeAudioDevice = null;        for (AudioDevice audioDevice : audioDevices) {            if (audioDevice.isActive()) {                activeAudioDevice = audioDevice;                break;            }        }        // display available audio devices    }});


yourCoroutineScope.launch {    success.availableAudioDevices.collect { availableAudioDevices ->        val activeDevice = devices.find { it.isActive }        // display available audio devices    }}

Example - Changing audio output





Disconnecting the call

To disconnect the call, use talkCall.disconnect().





Shortly after calling disconnect(), the statusChanges property discussed above will specify CallStatus.DISCONNECTED.

Using your own call screen only

The user must have granted permission to record audio before a call can start. You can use the SDK's built-in permissions screen to handle permissions and use your own call screen to start and manage the call.

To use your own call screen only, pass an Intent to use it into talk.startCallSetupFlow instead of a null value. Your Intent must lead to an Activity.

After permissions are checked and the consent screen is finished, the SDK will run the Intent instead of the built-in call screen.

  1. Create the Activity in your application and register it in AndroidManifest.xml.


    public class CustomCallScreenJavaActivity extends AppCompatActivity {
        @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);    }}


    class CustomCallScreenActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)    }}
  2. In onCreate, extract the RecordingConsentAnswer from the permissions screen.


    RecordingConsentAnswer recordingAnswer = CallSetupIntentContract.getRecordingAnswer(getIntent());


    val recordingAnswer = CallSetupIntentContract.getRecordingAnswer(intent)
  3. With the received RecordingConsentAnswer object, create the call using the SDK API. See Start the call.

  4. Start the SDK's built-in permissions screen with an intent to your Activity:


    talk.startCallSetupFlow(this, "your digital line name", new Intent(this, CustomCallScreenJavaActivity.class));


    talk.startCallSetupFlow(    context = this,    digitalLine = "your digital line name",    successIntent = Intent(this,

After the call starts successfully, you can manage the call with your call screen. See Managing calls with your own call screen.

Using your own permissions screen only

You can use your own permissions and consent screens and then use the SDK's built-in call screen.

In this case, your application is responsible for checking and requesting permission to access the microphone as well as to record audio. See Check for permission to record audio. If the call is started without the required permissions, the SDK will throw a runtime exception.

Use the talk.startCallScreen method to start the SDK call screen.


talk.startCallScreen(this, "your digital line name", null);


talk.startCallScreen(    context = this,    digitalLine = "your digital line name",    recordingConsentAnswer = null)

The startCallScreen method has three required arguments:

  • context - the Android Context, used for starting a new screen
  • digitalLine - nickname of the digital line configured in your account
  • recordingConsentAnswer - the consent for recording the call. One of "OPTED_IN", "OPTED_OUT", or null. When null, the default account setting for the recording is used

Note: For this release, the recording consent is not supported by the system, but the SDK API supports it. For an initial integration of Talk SDK, we recommend setting recordingConsentAnswer to null.