This page explains how to use the Android SDK.
Create an example app
To create an example app using the Android mobile SDK, you need the following:
CCAI Platform portal Company Key and Company Secret.
Android 5.0 (API level 21, Lollipop) or later.
Firebase Cloud Messaging or Google Cloud Messaging for the push notification.
App migrated to AndroidX.
Twilio SDK upgrade requirements
Requires Twilio SDK to be following specific versions if the Android SDK is integrated using our package directly, otherwise this can be ignored.
// Twilio VoIP SDK
api 'com.twilio:voice-android:6.1.1'
// Twilio Conversations SDK
api 'com.twilio:conversations-android:3.1.0'
In addition, Proguard rules are already included in the Android SDK to ensure that the Twilio Programmable Voice library is not removed by ProGuard and can be used to troubleshoot in case ProGuard accidentally removes the library.
-keep class com.twilio.** { *; }
-keep class tvo.webrtc.** { *; }
-dontwarn tvo.webrtc.**
-keep class com.twilio.voice.** { *; }
-keepattributes InnerClasses
To support latest Twilio versions, starting with the Android SDK version 0.34.0, SDK is no longer binary compatible with applications that target Java 7. In order to use this and future releases, developers must upgrade their applications to target Java 8. See the following code example:
android {
compileOptions {
sourceCompatibility 1.8
targetCompatibility 1.8
}
}
Get company key and company secret
Sign into the Admin Portal using Admin credentials.
Go to Settings > Developer Settings > Company Key & Secret Code.
Retrieve the Company Key and Company Secret Code.
Installation
Add the Android SDK repository to your Gradle setting for the root project.
build.gradle (Project)
allprojects {
repositories {
google()
jcenter()
maven {
url "https://sdk.ujet.co/android/"
}
}
}
build.gradle (module: app)
dependencies {
// Replace x.y.z with latest version of CCAI Platform SDK
def ujetSdkVersion = "x.y.z"
implementation "co.ujet.android:ujet-android:$ujetSdkVersion"
// CCAI Platform supports co-browse for Web SDK version 0.46.0 or
// higher.
// To use co-browse, declare the following dependency.
implementation "co.ujet.android:cobrowse:$ujetVersion"
}
Setup company settings
Enter your company settings as metadata in AndroidManifest.xml file.
AndroidManifest.xml
<application>
// ...
<!-- Company Settings -->
<meta-data android:name="co.ujet.android.subdomain" android:value="@string/ujet_subdomain"/>
<meta-data android:name="co.ujet.android.companyKey" android:value="@string/ujet_company_key"/>
<meta-data android:name="co.ujet.android.companyName" android:value="@string/ujet_company_name"/>
// ...
</application>
strings.xml
<resources>
<string name="ujet_subdomain">YOUR_SUBDOMAIN</string>
<string name="ujet_company_key">YOUR_COMPANY_KEY</string>
<string name="ujet_company_name">YOUR_COMPANY_NAME</string>
</resources>
JWT Signing
An end user information must be signed as JWT in your server for security purposes.
The example app contains APIManager for testing and you need to put UJET_COMPANY_SECRET in mock/APIManager.java. APIManager must implement a method that initiate async call to sign JWT auth token that returns the token.
In production, you must implement the signing process on your server.
public class APIManager {
public static final String UJET_COMPANY_SECRET = "Please input your UJET_COMPANY_SECRET from Ujet developer admin page";
// ...
}
Initialize SDK
Initialize the SDK in Android Application class onCreate
method.
public class ExampleApplication extends Application implements UjetRequestListener {
@Override
public void onCreate() {
super.onCreate();
Ujet.init(this);
}
// ...
}
End-user authentication
The end user is the consumer who contacts your customer support team through the application.
In order to authenticate the end user in the application, we introduce a JWT signing mechanism.
The Android SDK asks to sign the payload when it needs authentication. If the signing is successful, the application exchanges the signed JWT to the end user's auth token.
In ExampleApplication
you should implement the UjetRequestListener
interface for signing the auth token and for custom data.
public class ExampleApplication extends Application implements UjetRequestListener {
@Override
public void onCreate() {
super.onCreate();
Ujet.init(this);
}
@Override
public void onSignPayloadRequest(Map<String, Object> payload, UjetPayloadType ujetPayloadType, UjetTokenCallback tokenCallback) {
if (ujetPayloadType == UjetPayloadType.AuthToken) {
// In production, you should implement this on your server.
// The server must implement a method that initiates an asynchronous call
to sign and return a JWT auth token.
APIManager.getHttpManager()
.getAuthToken(payload, UjetPayloadType.AuthToken, new UjetTokenCallback() {
@Override
public void onSuccess(@Nullable final String authToken) {
tokenCallback.onToken(authToken);
}
@Override
public void onFailure(@Nullable final String authToken) {
tokenCallback.onError();
}
});
}
}
}
For more information, see end user authentication.
Set up push notifications
This section outlines how to enable mobile push notifications.
Prepare Firebase
You should prepare a Firebase project.
If you already have your project, you can use your own and skip this process.
Create a Firebase project in the Firebase console.
Download google-services.json from Settings > GENERAL in Firebase console.
- Get the Server Key from Settings > CLOUD MESSAGING in Firebase console.
Server setup
- Sign into the CCAI Platform portal with an Admin account.
Multiple Mobile App Feature | Path | Action |
---|---|---|
Enabled | Go to Settings → Developer Settings → Mobile Apps and tap on Edit icon for activated mobile app. | Copy/paste your server key into the FCM KEY field and save it. |
Disabled | Go to Settings → Developer Settings → Push Notification. | Copy and paste your server key into the GCM KEY field, and then save it. |
Android client setup
Copy
google-services.json
into your app directory, for example,PROJECT_ROOT/app/google-services.json
.Get the
FCM
token using the following code:FirebaseMessaging.getInstance().getToken() .addOnCompleteListener(task -> { if (!task.isSuccessful() || task.getResult() == null) { Log.w("FCM", "Couldn't get FCM token"); return; } String token = task.getResult(); Log.i("FCM", "FCM token: " + token); });
FirebaseMessagingService
is called, which is registered in Manifest if the token is refreshed. For more information, see Set up a Firebase Cloud Messaging client app on Android.public class YourFirebaseMessagingService extends FirebaseMessagingService { /** * There are two scenarios when onNewToken is called: * 1) When a new token is generated on initial app startup * 2) Whenever an existing token is changed * Under #2, there are three scenarios when the existing token is changed: * A) App is restored to a new device * B) User uninstalls/re-installs the app * C) User clears app data */ @Override public void onNewToken(String token) { Log.i("FCM", "FCM token updated: " + token); } }
Implement
UjetRequestListener.onRequestPushToken
in your Application class.UjetRequestListener.onRequestPushToken
should return theFCM/GCM
token.public class YourApplication extends Application implements UjetRequestListener { /** * Return your FCM/GCM token */ @Override public String onRequestPushToken() { return yourToken(); // As shown in the previous step, you can get your token using FirebaseMessaging.getInstance().getToken().addOnCompleteListener(task -> { }) } }
Handle the push notification. If you want Contact Center AI Platform (CCAI Platform) to handle processing its own push messages, you can pass the data directly to
UjetPushHandler.handle()
.The application only processes messages with the
ujet_noti_type
(ornoti_type
, for backwards compatibility) field set.Otherwise, you can choose to only send messages with
ujet_noti_type
toUjetPushHandler.handle()
for processing.
The following is an example of a push notification message:
{ "call_id" : 12345, "ujet_noti_type" : "connect_call", "noti_type" : "connect_call", "call_type" : "ScheduledCall", "fail_reason" : "none", "fail_details" : "none" }
Handle FCM message
public class YourFirebaseMessagingService extends FirebaseMessagingService {
private UjetPushHandler ujetPushHandler;
@Override
public void onCreate() {
super.onCreate();
this.ujetPushHandler = new UjetPushHandler(this);
}
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
if (ujetPushHandler.handle(remoteMessage)) {
// Handled by CCAI Platform
} else {
// Handle your push notification message in here
}
}
}
Handle GCM message
public class YourGcmListenerService extends GcmListenerService {
private UjetPushHandler ujetPushHandler;
@Override
public void onCreate() {
super.onCreate();
this.ujetPushHandler = new UjetPushHandler(this);
}
@Override
public void onMessageReceived(String s, Bundle bundle) {
if (ujetPushHandler.handle(bundle)) {
// Handled by CCAI Platform
} else {
// Handle your message
}
}
}
Handle GCM message in GcmReceiver (Old way)
public class YourGcmReceiver extends WakefulBroadcastReceiver {
private UjetPushHandler ujetPushHandler;
@Override
public void onReceive(Context context, Intent intent) {
ujetPushHandler = new UjetPushHandler(context);
if (ujetPushHandler.handle(intent.getExtras())) {
// Handled by CCAI Platform
} else {
// Handle your message
}
}
}
Start the application
Add the following line where you want to start the application (without any parameters):
Ujet.start(new UjetStartOptions.Builder().build());
You can also start the Android SDK without the splash screen.
UjetStartOptions ujetStartOptions = new UjetStartOptions.Builder()
.setSkipSplashEnabled(true)
.build();
Ujet.start(ujetStartOptions);
You can also start the Android SDK from a specific point in the menu with this key using a Direct Access Point:
String menuKey = "MENU_KEY";
UjetStartOptions ujetStartOptions = new UjetStartOptions.Builder()
.setMenuKey(menuKey)
.build();
Ujet.start(ujetStartOptions);
The menuKey
can be created with a Direct Access Point in the CCAI Platform portal
(with Admin role).
Go to Settings > Queue.
Select any queue from the menu structure.
Check Create direct access point.
Enter key in the text form.
Click Save.
You can also start the Android SDK with a specific ticket ID to pass it to the CRM. This ticket ID will be opened when a chat or call is connected.
String ticketId = "TICKET_ID";
UjetStartOptions ujetStartOptions = new UjetStartOptions.Builder()
.setTicketId(ticketId)
.build();
Ujet.start(ujetStartOptions);
Send custom data to your CRM
Custom data can be sent to support agents and will appear in the support ticket for the incoming call/chat.
There are two methods to send custom data:
Signed method: Predefined data signing with JWT.
Unsigned method: Predefined data with plain JSON (not recommended).
Using the signed method to send custom data
To send custom data using the signed method, implement a signing method.
First, retrieve custom data to your host app then send them to your server for signing. On your server, you can add additional data by using a defined form. Sign them with your company secret, and then return them by JWT.
public class ExampleApplication extends Application implements UjetRequestListener {
@Override
public void onCreate() {
super.onCreate();
Ujet.init(this);
}
@Override
public void onSignPayloadRequest(Map<String, Object> payload, UjetPayloadType ujetPayloadType, UjetTokenCallback tokenCallback) {
// ...
if (ujetPayloadType == UjetPayloadType.CustomData) {
/**
* These codes are for providing signed custom data.
* Add some data from app, and add more sensitive data from server and sign it.
*/
UjetCustomData appCustomData = new UjetCustomData();
appCustomData.put("model", "Model", "MODEL1234");
appCustomData.put("customor_id", "Customor ID", 12345);
appCustomData.put("temperature", "Temperature", 70.5f);
appCustomData.put("purchase_date", "Purchase Date", new Date());
appCustomData.put("battery", "Battery", "52%");
appCustomData.put("location", "Location", "San Francisco, CA, United States");
appCustomData.putURL("dashboard_url", "Dashboard URL", "https://internal.dashboard.com/12345");
payload.put("custom_data", appCustomData.getData());
tokenCallback.onToken(APIManager.getHttpManager().getSignedCustomData(payload));
}
// ...
}
}
Using unsigned method to send custom data
Google recommends that you to use the signed method to send custom data in your application. For more information, see Using the signed method to send custom data.
You can send unsigned data by starting the Android SDK with start options to set
custom data using UjetStartOptions.Builder#setUnsignedCustomData
and
UjetTokenCallback
should call onToken(null)
.
HashMap<String, Object> jsonData = new HashMap<>();
// Convert json string into hashmap object and store it in jsonData
UjetCustomData customData = new UjetCustomData();
customData.putObject("external_chat_transfer", jsonData); // Use `external_chat_transfer` key to send chat transcript data
UjetStartOptions ujetStartOptions = new UjetStartOptions.Builder()
.setUnsignedCustomData(customData)
.build();
Ujet.start(ujetStartOptions);
Using unsigned custom data to send external chat transcript
You can send the external chat transcript to CCAI Platform using
unsigned custom data when it's started. Use
UjetCustomData.putObject("external_chat_transfer", hashMapObject)
to set the
transcript data in JSON format as follows:
HashMap<String, Object> jsonData = new HashMap<>();
// Convert json string into hashmap object and store it in jsonData
UjetCustomData customData = new UjetCustomData();
customData.putObject("external_chat_transfer", jsonData); // Use `external_chat_transfer` key to send chat transcript data
UjetStartOptions ujetStartOptions = new UjetStartOptions.Builder()
.setUnsignedCustomData(customData)
.build();
Ujet.start(ujetStartOptions);
JSON format:
greeting_override
: stringagent
: dictionaryname
: stringavatar
: string [url of agent avatar, optional]
transcript
: arraysender
: string ["end_user" or "agent"]timestamp
: string [ie "2021-03-15 12:00:00Z"]content
: arraytype
: string [one of text, media]text
: string [required for text type]media
: dictionary [required for media type]type
: string [one of image, video]url
: string [public URL pointing at media file]
JSON example:
{
"greeting_override": "Please hold while we connect you with a human agent.",
"agent": {
"name": "Name",
"avatar": "avatar url"
},
"transcript": [
{
"sender": "agent",
"timestamp": "2021-03-15 12:00:15Z",
"content": [
{
"type": "text",
"text": "**Suggestions shown:**\n\n* Help with batch or delivery\n* Help with metrics or order feedback\n* Help with Instant Cashout"
}
]
},
{
"sender": "end_user",
"timestamp": "2021-03-15 12:00:16Z",
"content": [
{
"type": "text",
"text": "Help with batch or delivery"
}
]
}
]
}
You can use Markdown on the text type. The following formats are supported:
Bold
Italics
Underline
Line breaks
Bullet list
Numbered list
Links
Custom data format
This section shows the format of the custom data that can be passed in the JWT.
JSON encoded to JWT
The JSON should include iat and exp to validate JWT. The object of
the custom data is the value of the custom_data
key.
{
"iat" : 1537399656,
"exp" : 1537400256,
"custom_data" : {
"location" : {
"label" : "Location",
"value" : "1000 Stockton St, San Francisco, CA, United States",
"type" : "string"
},
"dashboard_url" : {
"label" : "Dashboard URL",
"value" : "http://(company_name)/dashboard/device_user_ID",
"type" : "url"
},
"contact_date" : {
"label" : "Contact Date",
"value" : 1537399655992,
"type" : "date"
},
"membership_number" : {
"label" : "Membership Number",
"value" : 62303,
"type" : "number"
},
"model" : {
"label" : "Model",
"value" : "iPhone",
"type" : "string"
},
"os_version" : {
"label" : "OS Version",
"value" : "12.0",
"type" : "string"
},
"last_transaction_id" : {
"label" : "Last Transaction ID",
"value" : "243324DE-01A1-4F71-BABC-3572B77AC487",
"type" : "string"
},
"battery" : {
"label" : "Battery",
"value" : "-100%",
"type" : "string"
},
"bluetooth" : {
"label" : "Bluetooth",
"value" : "Bluetooth not supported",
"type" : "string"
},
"wifi" : {
"label" : "Wi-Fi",
"value" : "Wi-Fi not connected",
"type" : "string"
},
"ssn" : {
"invisible_to_agent" : true,
"label" : "Social Security Number",
"value" : "102-186-1837",
"type" : "string"
}
}
}
The key is a unique identifier for the data. The type is the type of the value.
string
- JSON string
number
- integer, float
date
- UTC Unix timestamp format with 13 digits. (contains milliseconds)
url
- HTTP URL format
The label is the display name on the CRM page.
Prevent the display of custom data
You can use the invisible_to_agent
property with a custom data object to
prevent signed or unsigned custom data from being displayed in the agent
adapter. In the previous example, the end-user's social security number is not
shown in the agent adapter because "invisible_to_agent" : true
is included in
the ssn
object.
When you include the "invisible_to_agent" : true
property with a custom data object,
you can expect the following behavior:
- The custom data is included in the session metadata file.
- The custom data is not included in CRM records.
For more information, see View session data in the agent adapter.
Reserved data properties
You can send reserved data properties to CCAI Platform as signed custom data when a session begins. For more information, see Send reserved data properties.
The following is an example of reserved data properties in custom data:
{ "custom_data": { "reserved_verified_customer": { "label": "Verified Customer", "value": "VERIFIED_CUSTOMER_BOOLEAN": , "type": "boolean" }, "reserved_bad_actor": { "label": "Bad Actor", "value": "VERIFIED_BAD_ACTOR_BOOLEAN": , "type": "boolean" }, "reserved_repeat_customer": { "label": "Repeat Customer", "value": "REPEAT_CUSTOMER_BOOLEAN": , "type": "boolean" } } }
Replace the following:
VERIFIED_CUSTOMER_BOOLEAN
: True if you consider this end-user to be a legitimate customer.VERIFIED_BAD_ACTOR_BOOLEAN
: True if you consider this end-user to potentially be a bad actor.REPEAT_CUSTOMER_BOOLEAN
: True if you have determined that this end-user has contacted your contact center before.
SDK configuration
You can configure several options before starting the Android SDK. See the
UjetOption
class. The Fallback Phone Number and Network Sensitivity options
described in the following table only work when the Enable PSTN Fallback
toggle is on in the CCAI Platform portal at Settings > Developer Settings >
MMA > Edit. When the Enable PSTN Fallback toggle is off, we don't fallback
to PSTN. CCAI Platform uses default network sensitivity (0.85) for
checking network connections.
Option | Description | Value | Default value |
---|---|---|---|
Log Level | Log level to be printed in Logcat. | Integer. Same with Log level for Android Log. (Min: 2, Max: 7) | 5 (Log.Warn) |
Default Language | The default language code. | String. An ISO 639 language code. (e.g. en for English) | null |
Fallback Phone Number | The phone number is used as the fallback when the internet is not available or the representative phone number for the company doesn't exist from Admin portal. | String. Phone number. | null |
Uncaught Exception Handler Enabled | Enable the uncaught exception handler. If true , the app handles all uncaught SDK exceptions at runtime by using Thread.setDefaultUncaughtExceptionHandler . However, if the same exception occurs twice, the app crashes. |
Boolean. | true |
Network Sensitivity | The sensitivity for checking the network state. | Double between 0 and 1 , where 0 is the least sensitive and 1 is the most sensitive. A value of 1 will always fall back to a PSTN call. If used, we recommend starting out with a value of .97 . The value from the Portal under Settings > Developer Settings > Mobile Apps > Fallback phone number threshold overrides this value. |
0.85 |
Dark Mode Enabled | Enable the dark mode theme. If true , the SDK applies a dark mode theme when the user turns on dark mode, and otherwise ignores the action. |
Boolean. | false |
Single Channel Enabled | Config option to either show or bypass channel selection screen for a single channel. If true , the SDK shows a single channel selection screen instead of automatically selecting the channel even if only one channel is enabled in the menu queue. |
Boolean. | false |
Auto Minimize Call View | Config option to automatically minimize the initial call screen UI by default or wait for the user to minimize it. | Boolean. | false |
Agent Icon Border Enabled | Config option to show or remove a circular border around the agent icon. | Boolean. | false |
Static Font Size In Picker View | Config option to automatically adjust or disable the picker item text size. | Boolean. | false |
Hide Media Attachment In Chat | Config option to show or hide the media attachment icon in chat UI. | Boolean. | false |
Ignore READ_PHONE_STATE Permission |
If set to true then the SDK doesn't request the READ_PHONE_STATE permission. If you don't want to use in-app IVR calls, set this flag to true to avoid requesting this permission and also your application needs to explicitly remove android.permission.READ_PHONE_STATE permission for CCAI Platform SDK. Note that we don't recommend setting this to true , because this permission is required for in-app IVR calls to work. |
Boolean | false |
Cobrowse.io License Key (if applicable) | Config option to set up the Cobrowse.io library. You can find your Cobrowse License Key by signing in to https://cobrowse.io/dashboard/settings and going to the License Key section. |
String | null |
UjetOption ujetOption = new UjetOption.Builder()
.setLogLevel(Log.INFO)
.setDefaultLanguage("en")
.setFallbackPhoneNumber("+18001112222")
.setUncaughtExceptionHandlerEnabled(false)
.setNetworkSensitivity(0)
.setDarkModeEnabled(true)
.setShowSingleChannelEnabled(true)
.setAutoMinimizeCallView(true)
.setShowAgentIconBorderEnabled(true)
.setStaticFontSizeInPickerView(true)
.setHideMediaAttachmentInChat(true)
.setIgnoreReadPhoneStatePermission(true)
.setCobrowseLicenseKey("COBROWSE_IO_LICENSE_KEY_HERE")
.setCobrowseURL("COBROWSE_IO_API_URL_HERE")
.setCustomChatHeaderTitle("CHAT_HEADER_TITLE_TEXT")
.setUjetStylesOptions(
new UjetStylesOptions.Builder()
.setChatQuickReplyButtonsStyle(QuickReplyButtonsStyle.INDIVIDUAL)
.setChatStyles(new ChatStyles(...)) // See `Content Cards Theme` item
.build() )
.setBlockChatTerminationByEndUser(true)
.setHideStatusBar(true)
.setLoadingSpinnerDrawableRes(R.drawable.RESOURCE_NAME)
.setLandscapeOrientationDisabled(true)
.build();
//The following customizes various attributes in chat UI
ChatStyles chatStyles = new ChatStyles();
chatStyles.setBackButton(new BackButtonStyle(false, "ujet_agent_sample")); //customizes back button styles
chatStyles.setHeader(...); //customizes chat header styles
chatStyles.setAgentMessageBubbles(...); //customizes agent messages styles
chatStyles.setConsumerMessageBubbles(...); //customizes consumer messages styles
chatStyles.setSystemMessages(...); //customizes system messages styles
chatStyles.setEndChatButton(...); //customizes end chat button styles
chatStyles.setTimeStamps(...); //customizes timestamp styles
chatStyles.setUserInputBar(...); //customizes user input bar styles
UjetOption ujetOption = new UjetOption.Builder()
.setUjetStylesOptions(
new UjetStylesOptions.Builder()
.setChatStyles(chatStyles)
.build()
)
//The following customizes various attributes in chat UI using json file. Store json file in assets folder
//and create a method to read json file contents and convert it into json string.
String chatStylesFromJson = parseJsonContentsFromAssetsFolder();
UjetOption ujetOption = new UjetOption.Builder()
.setUjetStylesOptions(
new UjetStylesOptions.Builder()
.setChatStyles(chatStylesFromJson)
.build()
)
Fallback
You can use UjetErrorListener
for the fallback of unexpected errors. If
you don't set this listener or return false, the Android SDK will
handle the error.
The Android SDK will redirect users to the dialer with a fallback number only when Enable PSTN Fallback toggle is ON in the at Settings > Developer Settings > MMA > Edit pop-up, exit the SDK otherwise.
Error Type | Error Code | Trigger |
---|---|---|
NETWORK_ERROR | 1 | The network is not available. Note that this error is not triggered when network is not available during chat or call or rate screen. |
AUTHENTICATION_ERROR | 100 | An unexpected error occurred during the authentication. |
AUTHENTICATION_JWT_ERROR | 101 | An unexpected error occurred during the JWT validation (eg. parsing error). |
VOIP_CONNECTION_ERROR | 1000 | Failed to establish a connection to the VoIP provider. It is handled through the callback of VoIP SDK. |
VOIP_LIBRARY_NOT_FOUND | 1001 | A call is expected to be connected using a VoIP provider but one couldn't be found. This could happen when a developer integrated the wrong SDK or didn't add VoIP provider library in their dependencies. |
CHAT_LIBRARY_NOT_FOUND | 1100 | Occurs when couldn't find chat library. This could happen when a developer integrated the wrong SDK or didn't add Twilio Chat library in their dependencies. |
Ujet.setUjetEventListener(new UjetEventListener() {
@Override
public void onEvent(UjetEventType eventType, HashMap<String, Object> eventData) {
// eventType specifies the event type and eventData holds the data related to the event.
// You can parse the eventData and here we are just logging the event type and event data.
Log.i("CCAI Platform Event Type", eventType.getValue());
StringBuilder builder = new StringBuilder();
for (Map.Entry<String, Object> entry : eventData.entrySet()) {
builder.append(entry.getKey()).append(" : ").append(entry.getValue()).append("\n");
}
Log.i("CCAI Platform Event Data", builder.toString());
}
});
App permissions
The app requires the following permissions and requests these permissions of user when required.
Permission | Description |
---|---|
CAMERA | Used for smart action to take photos and record videos |
MICROPHONE | Allows app to use VoIP call through Twilio |
STORAGE | Allows app to save photos and videos |
Deep linking setup (optional)
If you want to use smart actions for an IVR (PSTN) call, you need to set up deep linking in your project.
Deep linking format is a unique URI such as:
ujet:// <package_name>/smartchannel.
Also, you have to set this link or any URL which will redirect to this link in Admin Portal (Settings > Operation Management > Enable Send SMS to Download App).
You will need to add an intent filter that contains the deep link in your manifest.
<activity android:name="co.ujet.android.activity.UjetActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:host="<package_name>"
android:scheme="ujet"
android:path="/smartchannel" />
</intent-filter>
</activity>
Event Notifications
You can optionally set UjetEventListener
to receive application event notifications.
Available event types and descriptions are listed here.
Ujet.setUjetEventListener(new UjetEventListener() {
@Override
public void onEvent(UjetEventType eventType, HashMap<String, Object> eventData) {
// eventType specifies the event type and eventData holds the data related to the event.
// You can parse the eventData and here we are just logging the event type and event data.
Log.i("CCAI Platform Event Type", eventType.getValue());
StringBuilder builder = new StringBuilder();
for (Map.Entry<String, Object> entry : eventData.entrySet()) {
builder.append(entry.getKey()).append(" : ").append(entry.getValue()).append("\n");
}
Log.i("CCAI Platform Event Data", builder.toString());
}
});
UjetEventType | Description |
---|---|
EmailClicked | This event triggers when user clicks on email channel. |
EmailSubmitted | This event triggers when user send email. |
SessionPaused | This event triggers when user user minimized chat/call session. |
SessionResumed | This event triggers when user switched back to chat/call session from background. |
SessionCreated | This event triggers when chat or call is created. |
SessionEnded | This event triggers when chat or call is ended. |
SdkTerminated | This event triggers when the SDK is closed (including SDK closed unexpectedly). |
Data included in the event are outlined.
EmailClicked
- Queue Menu Data (as mentioned in below).
EmailSubmitted
Queue Menu Data
Email Submitted Data
SessionPaused
- Session Data
SessionResumed
- Session Data
SessionCreated
Queue Menu Data
Session Created Data
SessionEnded
Queue Menu Data
Session Created Data
Session Ended Data
SdkTerminated
- SDK Terminated Data
Queue Menu Data
Key | Type | Description |
---|---|---|
event_name | String | Contains event name. Example, "Email Clicked". |
application | String | Contains application name. Example, "Android". |
app_id | String | Contains app identifier which is same as Context.getPackageName(). |
app_version | String | Contains app version name and version code. Example, "0.32.0 (123)". |
sdk_version | String | Contains the SDK version. Example, "0.32.0". |
timestamp | String | Contains timestamp in UTC (in yyyy-MM-dd'T'HH:mm:ss'Z' format). |
device_model | String | Contains user device model. Example, "Google Pixel". |
device_version | String | Contains user device version. Example, "10, Q, SDK 29". |
company | String | Contains company name. Example, "Company". |
menu_name | String | Contains name of the leaf node (user last menu selection). Example, "Sub Menu". |
menu_id | String | Contains id of the leaf node (user last menu selection). Example, "123". |
menu_path | String | Contains the full sequence of menus selected by user. Example, "Parent / Child / Sub Menu". |
menu_key | String | Contains DAP key and it is optional. Example, "special_user_menu". |
Email Submitted Data
Key | Type | Description |
---|---|---|
has_attachments | Boolean | Returns True if email has any attachments, False otherwise. |
Session Data
Key | Type | Description |
---|---|---|
event_name | String | Contains event name. Example, "Email Clicked". |
type | String | Contains session type. Example, "chat" or "call". |
timestamp | String | Contains timestamp in UTC (in yyyy-MM-dd'T'HH:mm:ss'Z' format). |
Session Created Data
Key | Type | Description |
---|---|---|
session_id | String | Contains session id. Example, "100". |
type | String | Contains session type. Example, "chat" or "call". |
end_user_identifier | String | Contains end user identifier. Example, "John". |
messages_end_user | String | Contains end user messages count and only included for chat session. Example, "3". |
messages_agent | String | Contains agent messages count and only included for chat session. Example, "3". |
Session Ended Data
Key | Type | Description |
---|---|---|
agent_name | String | Contains agent name. Example, "John". |
ended_by | String | Contains who ended the session details. Possible values are "agent" (when agent ends the session) or "end_user" (when end user ends the session) or "timeout" (when chat is timed out) or "dismissed" (when chat is dismissed). |
duration | String | Contains session duration in seconds and only included for call session. Example, "30 seconds". |
SDK Terminated Data
Key | Type | Description |
---|---|---|
event_name | String | Contains event name. Example, "Email Clicked". |
Incoming call behavior changes
Beginning with Android 10 version devices, incoming call will not be received directly to end users when host app is in the background. Instead, we use notifications to alert users to incoming call (even when phone is locked) giving them the option to accept or decline the call.
We show the same notifications when host app in background and locked the screen before incoming call is arrived. This behavior change is to comply with Google's recent restrictions to start activities when app is in background. Behavior is not affected when host app in foreground or running on lower than Android 10 version devices.
Customize SDK session
This section outlines how the SDK can be further customized.
Check for an existing session
Before starting a session, use the described method to check if there is any existing or in progress session. And, if it exists then you can prompt the end user to resume or cancel it.
This is especially important when a user is changed.
if (Ujet.getStatus() != UjetStatus.None) {
// Display alert to cancel login or resume existing session
}
Disconnect the session
Refer to the method if you want to disconnect any session in progress.
Before using this method, ensure to check if such a session exists using
Ujet.getStatus(). If you want to perform an action(s) after the SDK
disconnects the session, for example, showing a message or closing the
app, then you can use response callback onFinished()
as covered in the next
section, otherwise set callback to null.
Ujet.disconnect(new UjetResponseCallback() {
@Override
public void onFinished() {
// `onFinished()` is triggered after CCAI Platform disconnects the session.
finish(); // Finishes the activity.
}
});
Clear end user data from cache
You are responsible for clearing the cache when end user related data has been updated or changed from your app. For example, if the end user has signed out, then invoke the method to remove the cache for that user so that a new session is initiated for the new end user upon the next start of SDK.
Ujet.clearUserData();
Language preference
The Android SDK will use the following priority order to determine the language.
Language selected from the splash screen within the app.
Default language selected using
UjetOptions
. You can set the default language usingsetDefaultLanguage("en")
inUjetOptions
. See Default Language in the SDK configuration section for more details.Device language selected in the device (using Settings > General > Language) will be used, when it is supported by the app.
Closest dialect of device language will be used when the app does not support the device language but supports its closest parent dialect. For example, if the user selected Spanish Cuba as the language in the device and the app does not support Spanish Cuba but supports parent dialect Spanish, then Spanish language will be used.
English will be used as the default language, when the device language is not supported by the app.
Configure external deflection link icons
Customize the icon in the External Deflection Link channel by uploading the icon into a drawable folder of your app and ensure you use the same icon name while creating the external deflection link in the CCAI Platform portal at Settings > Chat > External Deflection Links > View links > Add Deflection Link.
If the icon name in the CCAI Platform portal doesn't match the icon uploaded into the app then the Android SDK will uses the default icon.
Configure the surveys Thank You icon
You can customize or override the icon in survey thank you page by uploading an
icon into the drawable folder of your app and use the filename
ujet_survey_thank_you_icon
as icon name.
Customize (Optional)
This section outlines how to customize specific values within the SDK.
Strings
You can customize strings used in the application by overriding keys for each string in strings.xml.
<resources>
<!--Greeting title and message in splash screen-->
<string name="ujet_greeting_title">Customer Support</string>
<string name="ujet_greeting_description">runs on UJET</string>
</resources>
Text size customization
Customize title, description and picker text size used in the application by overriding following keys in dimens.xml.
Customizable text sizes are outlined:
<resources>
<!-- Don't include the following tags if you don't want to customize any of these keys and prefer to use the CCAI Platform default values instead. -->
<!-- You can customize title text size by updating value here. -->
<dimen name="ujet_title">10sp</dimen>
<!-- You can customize description text size by updating value here. -->
<dimen name="ujet_description">10sp</dimen>
<!-- You can customize picker text size by updating value here. -->
<dimen name="ujet_picker_item_text_size">10sp</dimen>
</resources>
Theme
Customize the theme and background with the following steps. Step 1 is for theme and step 2 is for background.
Customize the theme by overriding keys for each style item in style.xml. For example,
<!--Default style applies to both Light and Dark Mode Themes--> <style name="Ujet"> <item name="ujet_typeFace">ProximaNova-Reg.otf</item> <item name="ujet_colorPrimary">@color/primaryDefault</item> <item name="ujet_colorPrimaryDark">@color/primaryDarkDefault</item> <item name="ujet_buttonRadius">10dp</item> <item name="ujet_companyLogo">@drawable/your_company_logo_default</item> <!-- You can customize the avatar in waiting UI before call or chat is connected by using the following option. --> <item name="ujet_defaultAvatar">@drawable/your_default_avatar</item> </style> <!--This is optional and can be used to update style in Light Mode Theme only--> <style name="Ujet.Light"> <item name="ujet_typeFace">ProximaNova-Reg.otf</item> <item name="ujet_colorPrimary">@color/primaryLightMode</item> <item name="ujet_colorPrimaryDark">@color/primaryDarkLightMode</item> <item name="ujet_buttonRadius">10dp</item> <item name="ujet_companyLogo">@drawable/your_company_logo_light_mode</item> <!-- You can customize the avatar in waiting UI before call or chat is connected by using the following option. --> <item name="ujet_defaultAvatar">@drawable/your_default_avatar</item> </style> <!--This is optional and can be used to update style in Dark Mode Theme only--> <style name="Ujet.Dark"> <item name="ujet_typeFace">ProximaNova-Reg.otf</item> <item name="ujet_colorPrimary">@color/primaryDarkMode</item> <item name="ujet_colorPrimaryDark">@color/primaryDarkForDarkMode</item> <item name="ujet_buttonRadius">10dp</item> <item name="ujet_companyLogo">@drawable/your_company_logo</item> <!-- You can customize the avatar in waiting UI before call or chat is connected by using the following option. --> <item name="ujet_defaultAvatar">@drawable/your_default_avatar</item> </style>
You can customize background color in the application by overriding keys for each style item in style.xml. Customizable background color is shown in the screenshot.
<style name="Ujet"> <!-- Don't include the following tags if you don't want to customize any of these keys and prefer to use the CCAI Platform default values instead. --> <!-- You can customize light mode theme background color by updating value here in hex. --> <item name="ujet_colorBackground">@color/backgroundDefault</item> <!-- You can customize dark mode theme background color by updating value here in hex. --> <item name="ujet_colorBackgroundDark">@color/backgroundDefaultDark</item> </style>
Customize the chat header title
There are options available to customize the chat header title text in chat in your UI.
You can customize the chat header title text by using the following options:
<item name="ujet_chatCustomHeaderTextColor">@color/chatHeaderTextLightMode</item>
<item name="ujet_chatCustomHeaderTextColowDark">@color/chatHeaderTextDarkMode</item>
<item name="ujet_chatCustomHeaderTextSize">16sp</item>
<item name="ujet_chatCustomHeaderTextStyle">bold</item>
You can customize Virtual Agent quick replies in the chat UI by using the following options:
<item name="ujet_colorChatQuickReplyButtonBackground">@color/chatQuickReplyButtonBackgroundLightMode</item>
<item name="ujet_colorChatQuickReplyButtonBackgroundDark">@color/chatQuickReplyButtonBackgroundDarkMode</item>
<item name="ujet_colorChatQuickReplyButtonPressedBackground">@color/chatQuickReplyButtonPressedBackgroundLightMode</item>
<item name="ujet_colorChatQuickReplyButtonPressedBackgroundDark">@color/chatQuickReplyButtonPressedBackgroundDarkMode</item>
<item name="ujet_colorChatQuickReplyButtonText">@color/chatQuickReplyButtonTextLightMode</item>
<item name="ujet_colorChatQuickReplyButtonTextDark">@color/chatQuickReplyButtonTextDarkMode</item>
<item name="ujet_colorChatQuickReplyButtonPressedText">@color/chatQuickReplyButtonPressedTextLightMode</item>
<item name="ujet_colorChatQuickReplyButtonPressedTextDark">@color/chatQuickReplyButtonPressedTextDarkMode</item>
<item name="ujet_colorChatQuickReplyButtonStroke">@color/chatQuickReplyButtonStrokeLightMode</item>
<item name="ujet_colorChatQuickReplyButtonStrokeDark">@color/chatQuickReplyButtonStrokeDarkMode</item>
<item name="ujet_chatQuickReplyButtonTypeFace">Kreon-Regular.ttf</item>
<item name="ujet_chatQuickReplyButtonStrokeWidth">3dp</item>
<item name="ujet_chatQuickReplyButtonCornerRadius">3dp</item>
<item name="ujet_chatQuickReplyButtonVerticalMargin">0dp</item>
<item name="ujet_chatQuickReplyButtonHorizontalPadding">10dp</item>
<item name="ujet_chatQuickReplyButtonVerticalPadding">1dp</item>
<item name="ujet_chatQuickReplyButtonAlignment">right</item>
Content cards
You can add customization for content cards along with chat customization. You
can do this either by using the JSON file (refer to the content_card property
in the app/src/main/assets/json/ujet_styles.json
file) or by using the
ContentCardStyle
class.
ChatStyles(
...
contentCard = ContentCardStyle(
backgroundColor = "color_reference",
cornerRadius = 8,
font = FontStyle(
colorReference = "color_reference",
size = 16,
style = "bold|italic",
family = "Roboto-Black.ttf",
),
border = BorderStyle(
color = "color_reference",
width = 2,
),
title = TextStyle(
FontStyle(
colorReference = "color_reference",
size = 18,
style = "bold|italic",
family = "Roboto-Black.ttf",
)
),
subtitle = TextStyle(
FontStyle(
colorReference = "color_reference",
size = 16,
style = "bold|italic",
family = "Roboto-Black.ttf",
)
),
body = TextStyle(
FontStyle(
colorReference = "color_reference",
size = 16,
style = "bold|italic",
family = "Roboto-Black.ttf",
)
)
)
)
Surveys
You can change the icon on the survey thank you page by uploading an icon to your app's drawable folder.
Make sure you use ujet_survey_thank_you_icon
as the icon name.