Create an example app

To create an example app using the Android mobile SDK, you need the following:

  • Admin 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, please ignore otherwise.

// Twilio VoIP SDK
api 'com.twilio:voice-android:6.1.1'
// Twilio Conversations SDK
api 'com.twilio:conversations-android:3.1.0'

Below 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. Follow the snippet below for reference.

android {
   compileOptions {
       sourceCompatibility 1.8
       targetCompatibility 1.8
   }
}

Get Company Key and Company Secret

  1. Sign into the Admin Portal using Admin credentials.

  2. Go to Settings > Developer Settings > Company Key & Secret Code.

  3. Retrieve the Company Key and Company Secret Code.

Getting Started

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"

    //We support Cobrowse feature from CCAI Platform SDK version 0.46.0 onwards and to     // We support Cobrowse feature from CCAI Platform SDK version 0.46.0 onwards
    //utilize it, requires to declare below CCAI Platform SDK dependency,  ignore otherwise.// Declare the following dependency to use it
    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's Application class's onCreate method.

::: caution Make sure that Ujet.init() is called in Application.onCreate(). because the Android SDK can be launched even if the host app is not running by the push notification and SMS link.

If Ujet.init() is not called and the Android SDK is launched, the Android SDK will not work properly and may cause a crash. :::

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.
             */

            //Also, server must implement a method that initiate async call to sign JWT auth token that returns the 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();
                    }
                });
        }
    }
}

Setup Push Notification

Prepare Firebase

You should prepare a Firebase project.

If you already have your project, you can use your own and skip this process.

  1. Create a Firebase project in the Firebase console.

  2. Download google-services.json from Settings > GENERAL in Firebase console.

  1. Get the Server Key from Settings > CLOUD MESSAGING in Firebase console.

Server Setup

  1. 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/paste your server key into the GCM KEY field and save it.

Android Client Setup

  1. Copy google-services.json into your app directory. (e.g PROJECT_ROOT/app/google-services.json)

    Retrieve FCM token. FCM token can be retrieved by the following source 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. Please read Set up an Android Client for the details.
    
    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);
        }
    }
    
  2. Implement UjetRequestListener.onRequestPushToken in your Application class.

    UjetRequestListener.onRequestPushToken should return FCM/GCM token.
    
    public class YourApplication extends Application implements UjetRequestListener {
        /**
         * Please return your FCM/GCM token
         */
        @Override
        public String onRequestPushToken() {
            return yourToken(); //You can retrieve your token using FirebaseMessaging.getInstance().getToken().addOnCompleteListener(task -> { }); as mentioned above.
        }
    }
    
  3. Handle the push notification:

    If you want CCAI Platform to handle processing it's own push messages, you can pass the data directly to UjetPushHandler.handle().Handle the push notification
    
    • The application will only process messages with the ujet_noti_type (also, noti_type for backwards compatibility) field set.

    • Otherwise, you can choose to only send messages with ujet_noti_type to UjetPushHandler.handle() for processing.

    Example push notification message looks like below.

    {
        "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).

  1. Go to Settings > Queue > Select any queue from the menu structure >

  2. Check Create direct access point

  3. Enter key in the text form

  4. Click Save.

You can also start the Android SDK with a specific ticket id to pass it to CRM. This ticket id will be opened when chat or call is connected.

String ticketId = "TICKET_ID";
UjetStartOptions ujetStartOptions = new UjetStartOptions.Builder()
        .setTicketId(ticketId)
        .build();

Ujet.start(ujetStartOptions);

Send Custom Data to 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 via the signed method, you will need to 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 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

::: caution This method is not recommended as it creates a potential vulnerability which could open your application to a man-in-the-middle attack. If you choose to use this method, we are not responsible for the security exposure and potential damage which may occur. :::

We encourage you to use the signed method described above to send custom data in your application.

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); // Please 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 and please use UjetCustomData.putObject("external_chat_transfer", hashMapObject) to set 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); // Please 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: string

  • agent: dictionary

    • name: string

    • avatar: string [url of agent avatar, optional]

  • transcript: array

    • sender: string ["end_user" or "agent"]

    • timestamp: string [ie "2021-03-15 12:00:00Z"]

    • content: array

      • type: 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]

    { "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" } ] } ] }

We support markdown on the text type and supported formats are listed down.

  • Bold

  • Italics

  • Underline

  • Line breaks

  • Bullet list

  • Numbered list

  • Links

Custom Data Format

JSON encoded to JWT

The JSON should include iat and exp to validate JWT. And the object of custom data is value of 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"
        }
    }
}

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

SDK Configuration

You can set several options before starting the Android SDK. Please take a look UjetOption class. Fallback Phone Number and Network Sensitivity described below works only Enable PSTN Fallback toggle is ON in the Portal under Settings > Developer Settings > MMA > Edit pop-up. When Enable PSTN Fallback toggle is OFF, we do not fallback to PSTN, please check Fallback section below for more details and we use default network sensitivity (0.85) for checking network connection.

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 will be 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 it's true, the app will handle all uncaught SDK exceptions at runtime by Thread.setDefaultUncaughtExceptionHandler. But if the same exception occurs twice, the app will crash. Boolean. true
Network Sensitivity The sensitivity for checking the network state. Double between 0 and 1. 0 is the least sensitive and 1 is the most sensitive. A value of 1 will always fallback to a PSTN call. If used, we recommend starting out with a value of .97. 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 it's true then the SDK applies a dark mode theme when the user turns on dark mode, ignores otherwise. Boolean. false
Single Channel Enabled Config option to show or bypass channel selection screen for a single channel. If it's true then the SDK shows a single channel selection screen instead of auto selecting the channel in case of only one channel 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 end user to minimize it. Boolean. false
Agent Icon Border Enabled Config option to show agent icon with circular border or remove the border. Boolean. false
Static Font Size In Picker View Config option to auto adjust picker item text size or disable it. Boolean. false
Hide Media Attachment In Chat Config option to show or hide media attachment icon in chat UI. Boolean. false
Ignore READ_PHONE_STATE Permission If set to true then the SDK will not request the READ_PHONE_STATE permission. This permission is required for In App IVR Call to work so we do not recommend to set this flag to true. In case, you do not want to use In App IVR Call then you can set this flag to true to avoid requesting this permission and also your application need to explicitly remove android.permission.READ_PHONE_STATE permission for CCAI Platform SDK. 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 logging with your account into https://cobrowse.io/dashboard/settings. There you can find a section called License Key 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")
        .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. Please 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 via a VoIP provider but one could not 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

App will require below permissions and request to user when required.

Permission Description
CAMERA Used for smart action to take photos and record videos
MICROPHONE Allows app to use VoIP call via 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 set UjetEventListener to receive application event notifications (optional).

Available event types and descriptions are listed below.

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 listed below.

  • 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

1. Check for an existing session.

Before starting a session, use the below 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

Please use the below 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 mentioned below. Otherwise set callback to null.

Ujet.disconnect(new UjetResponseCallback() {
    @Override
    public void onFinished() {
        //onFinished() will be 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 below 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.

  1. Language selected from the splash screen within the app.

  2. Default language selected using UjetOptions. You can set the default language using setDefaultLanguage("en") in UjetOptions. See Default Language in the SDK configuration section for more details.

  3. Device language selected in the device (using Settings > General > Language) will be used, when it is supported by the app.

  4. 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.

  5. 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 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 does not match with the icon uploaded into the app then the Android SDK will use the default icon.

Configure the Surveys Thank You icon

You can customize / override icon in survey thank you page by uploading icon into drawable folder of your app and ensure to use ujet_survey_thank_you_icon as icon name.

Customize (Optional)

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 shown below.

<resources>
    <!-- Do not include the below tags if you do not want to customize any of these keys and instead prefer to use CCAI Platform default values. -->

    <!-- 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.

  1. 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>
    
  2. 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 below screenshot.

    <style name="Ujet">
        <!-- Do not include the below tags if you do not want to customize any of these keys and instead prefer to use CCAI Platform default values. -->
        <!-- 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.