Using the Android SDK

Using the SDK

Initialize the SDK

To initialize the Voice SDK add the following in the onCreate function of your Application class.

To listen to Voice SDK logs, pass the class that implements the VoiceLogListener:

class MyApplication: Application(), VoiceLogListener {

   ...
   val voice = Voice.getInstance()

   override fun onCreate() {
      super.onCreate()
      voice.init(this, this)
      ...
   }

   override fun onLog(log: VoiceLog) {
      // Handle SDK logs
   }
   ...
}

The Voice SDK sends log information to the application.

Note: References to Voice in this document pertain to the voice object.

Register and Activate a Voice User

In order for the Voice SDK to function correctly, you need to add Voice user information to make and receive calls. Use the following for user data:

val userConfiguration = userConfiguration {
    accountId = "YOUR_ACCOUNT_ID"
    userId = "YOUR_USER_ID"
    msisdn = "YOUR_DEVICE_NUMBER"
    jwtToken = "YOUR_JWT_TOKEN"
    displayName = "YOUR_NAME"
    deviceId = "UNIQUE_DEVICE_IDENTIFIER"
}

Note:

*msisdn is optional.

*The deviceId is the device unique identifier, preferably FirebaseInstanceId. Please refer to Work with instance IDs and GUIDs for more information.

The Voice SDK also requires application information in the setup. Use the following for application data:

val sessionConfiguration = sessionConfiguration {
    applicationId = BuildConfig.APPLICATION_ID
    baseUrl = "VOICE_BASE_URL"
    pushToken = "YOUR_PUSH_TOKEN"
}

Note: The Voice URL is provided by the console when you request access to the Voice SDK.

Once you have the configurations ready, use them to activate the Voice SDK. For example:

configuration {
    userConfiguration = userConfig
    sessionConfiguration = sessionConfig
    failureListener = Configuration.FailureListener { exception ->
        Log.i(TAG, "Registration failed - $exception")
    }
    successListener = Configuration.SuccessListener {
        Log.i(TAG, "Registration succeeded")
    }
}
voice.activate(configuration)

Upon activation, the application is ready to make and receive calls.
To check if the user is registered and activated, use

voice.isActivated()

Note: Use the result of this function to determine whether or not the user requires activation.

SDK state

The Voice SDK allows you to get updates about sdk state. You can observe it using the following LiveData object:

voice.state.observe(lifecycleOwner) { state ->
   // Handle the state
}

Request runtime permissions

The Voice SDK requires access to READ_PHONE_STATE and RECORD_AUDIO permissions in order to successfully place and receive calls. To find out which permissions are not granted, call:

voice.setOnPermissionsListener { permissions ->
   ActivityCompat.requestPermissions(this, permissions, YOUR_REQUEST_CODE)
}

Note: The Voice SDK needs phone and mic permission in order to make and receive calls. If you have not enabled access to these required permissions, you will receive them once per application lifecycle. An application lifecycle is defined as the time that an application has started until it is removed or killed.

Place a call

In order to place a call, the Voice SDK requires the callee contact information. Use the VoiceContact object from the Voice SDK to create the callee information.

Once the contact object is ready you can place a call using the following:

voice.placeCall(activity, contact, object : CallCompletionHandler {
    override fun onSuccess(call: VoiceCall) {
        Log.d(TAG, "Outgoing call succeeded: $call")
        // Handle call
    }
    override fun onFailure(call: VoiceCall?, exception: VoiceException) {
        Log.e(TAG, "Outgoing call failed: $exception")
        // Handle exception
    }
})

Note: Passing activity is optional. This is required for the Voice SDK to prompt the user for permissions that are not granted while placing the call. When not provided, placing a call could fail with a PermissionNotGranted exception.

Mid-call features

The Voice SDK provides APIs to interact with an active VoiceCall. These actions are:

  • accept()
  • reject()
  • endAndAccept()
  • hangup()
  • mute()
  • unmute()
  • hold()
  • resume()

You can also query the state of incoming calls such as isIncoming, isPeerOnHold, isMuted, and callStartTime.

The Voice SDK allows a user to have a second incoming call while a call is in progress. Notifications happens via the VoiceCallUpdateListener. The Voice SDK provides functionality to end the ongoing call and accept an incoming call using the endAndAccept action. The default accept behavior is to put the ongoing call on hold and accept the incoming call.

Call updates

In order to receive call updates use addOnVoiceCallUpdateListener which takes the implementation of VoiceCallUpdateListener:

voice.addOnVoiceCallUpdateListener(this)

Once the listener is set up, call updates are received by the following callbacks:

override fun onCallAdded(call: VoiceCall) {
   // Call recently added
}

override fun onCallRemoved(call: VoiceCall) {
   // Call failed or finished.
}

override fun onCallUpdated(call: VoiceCall?) {
   // Call that's recently updated.
}

override fun onCallFailed(call: VoiceCall?, exception: Exception) {
   // Call that failed with an exception.
}

override fun onCallHoldUpdated(call: VoiceCall?) {
   // Call that has been moved on hold because of accepting another incoming call.
}

When it is not longer needed:

voice.removeOnVoiceCallUpdateListener(this)

Receive a call

The application needs to receive push notifications via FCM. If you are not using FCM on your project refer to this Firebase topic.

The application receives a push notification via the FirebaseMessagingService object as an indication of an incoming call. Once the application receives the push notification, it needs to check if the notification is for an incoming call. Use:

val isVoiceNotification = voice.isVoiceNotification(data)

If the notification is for an incoming call, it is passed along with its context to the Voice SDK. To process an incoming call the Voice SDK starts a Foreground Service which requires a notification to be displayed by the application. The notification is displayed for a very short time and may display text such as Incoming call. This notification can be replaced by another notification with Accept and Reject actions as soon as updates are received.

If you wish to present a view as soon as the incoming call is connected, use:

voice.setOnCallActionListener {
    when (it) {
        CallAction.PRESENT_INCOMING_CALL -> // Show Incoming Call Notification and UI
        CallAction.MUTE_INCOMING_CALL -> // Mute Incoming Call Notification
    }
}

Note: Set the CallActionListener before the receiveCall in order to present your notification or view.

Once the notification is ready, use the following:

voice.receiveCall(data, notification, object : CallCompletionHandler {
    override fun onSuccess(call: VoiceCall) {
        // Handle incoming call
    }
    override fun onFailure(call: VoiceCall?, exception: VoiceException) {
        // Handle failure
    }
})

Update contact information

For any active call, you can update the contact information by using the following:

val contact = VoiceContact("CONTACT_ID", "CONTACT_NAME", "CONTACT_AVATAR_URL", "CONTACT_PHONE_NUMBER")
voice.updateContact(call.uuid, contact)

Audio control

The Voice SDK allows you to switch your audio output during a call by using the following:

voice.setVoiceAudioOption(audioOption)

In order to receive audio updates use addOnVoiceCallAudioOptionListener which takes the implementation of VoiceCallAudioOptionListener:

voice.addOnVoiceCallAudioOptionListener(this)

Once the listener is set up, call updates are received by the following callbacks:

override fun onAudioChanged(audioOption: VoiceCallAudioOption) {
    // Handle audio option
}

And when it is no longer needed:

voice.removeOnVoiceCallAudioOptionListener(this)

The SDK allows you to easily toggle between audio options. It follows the following:
VoiceCallAudioOption.EARPIECE to VoiceCallAudioOption.SPEAKER,
VoiceCallAudioOption.SPEAKER to VoiceCallAudioOption.EARPIECE,
VoiceCallAudioOption.BLUETOOTH to VoiceCallAudioOption.EARPIECE

To toggle between audio options use:

voice.toggleAudioOption()

Note: audioOption is of the type VoiceCallAudioOption which consists of the values of BLUETOOTH, SPEAKER, and EARPIECE.

Update push notification token and phone number

After registration the push token and phone number that are provided during activation can be reconfigured.

To update the push token, add the following to the class which extends FirebaseMessagingService:

override fun onNewToken(token: String) {
    super.onNewToken(token)
    ...
    voice.updatePushToken(token, object: CompletionHandler {
        override fun onSuccess() {
            // Handle success
        }
        
        override fun onFailure(e: ExceptionType) { 
            // Handle failure
        }
    })
}

To update the phone number, use the following:

voice.updatePhoneNumber(number, object : CompletionHandler {
    override fun onSuccess() {
        // Handle success
    }
    override fun onFailure(e: ExceptionType) {
        // Handle faailure
    }
})

Unregister and Deactivate Voice User

To deactivate or unregister a user, use the following method:

voice.deactivate(object : CompletionHandler {
    override fun onSuccess() {
        // Handle success
    }
    override fun onFailure(e: ExceptionType) {
        // Handle failure
    }
})

Proguard Rules

If minifyEnabled is set to true in your application:

  • Add the following in your proguard-rules.pro file:
#noinspection ShrinkerUnresolvedReference
-keep class com.eght.voice.sdk.** { *; }
-keep class com.eght.sip.** { *; }
-keep class com.eght.call.** { *; }
  • If the compiler complains about META-INF/* file collision after adding the proguard rules, you must add the following to your app-level build.gradle:
android {

   ...

   packagingOptions {
      pickFirst  '**'
   }
}

Shared Preferences

In order to persist data, it is recommended that the Voice SDK is excluded from allowBackup. If your application needs the attribute android:allowBackup="true" in your AndroidManifest.xml file, we recommend doing the following:

  • Create an xml file under the xml resource directory. We'll call it backup_rules.xml:
    <?xml version="1.0" encoding="utf-8"?>
    <full-backup-content>
      <exclude domain="sharedpref" path="voice-sdk-preferences.xml"/>
    </full-backup-content>
    
  • Add the following attribute to your AndroidManifest.xml:
    <application
      ...
      android:fullBackupContent="@xml/backup_rules">
      ...
    </application>
    

    Note: If you have android:allowBackup="false", you do not need to add this file nor add the fullBackupContent attribute.


Did this page help you?