Integrate Hotline SDK (Using Gradle)

Pre Requisites : 
1. Hotline SDK clients require devices running Android 2.3 or higher
2. Hotline App Id and App Key from here: Where to find App ID and App Key
3. Android Studio and Gradle
If you have any queries during the integration, please send it to us - Submit a Query 

1. Add Hotline SDK to your app

Add the maven URL to the root build.gradle (project/build.gradle)     

allprojects {
    repositories {
        jcenter()
        maven { url "https://jitpack.io" }
    }
} 

Add the following dependency to your app module's build.gradle file (project/app/build.gradle):               

apply plugin: 'com.android.application'

android {
// ...
}

dependencies {
// ...
    compile 'com.github.freshdesk:hotline-android:1.2.+'
}

               

1.1 Android target version supported

Hotline SDK supports apps targeting Android version 5.0+. The SDK itself is compatible all the way down to Gingerbread (API Level 10). 


 
When app targets Android 7.0+
 


When FileProvider is not configured for Hotline SDK, the following error code is displayed
"Missing/Bad FileProvider for Hotline. Camera capture will fail in devices running Nougat or later versions of OS (error code 354)"

To fix this, please include the provider in the AndroidManifest.xml as below and specify the authority in strings.xml. Assuming, com.example.demoapp is the package name of your app, the declaration would be

AndroidManifest.xml
<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.example.demoapp.provider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/hotline_file_provider_paths" />
</provider>

Strings.xml

<string name="hotline_file_provider_authority">com.example.demoapp.provider</string>



When app targets Android 8.0+


   

When the app's target is Android 8.0 or later, and by extension  includes appcompat-v7 r26.0.0.+, you'll see the following errors

   


E/UncaughtException: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/freshdesk/hotline/activity/InterstitialActivity;
   


 Hotline SDK's activities extends ActionBarActivity to keep the SDK compatible with app's targeting older Android versions/appcompat-v7 revisions. It can be resolved by adding a proxy class (ActionBarActivity was replaced by AppCompatActivity and was proxied by lib itself since 24.2.0 of appcomapt-v7, until it was removed in 26.0.0) manually if you are building with support library 26.x.x. 
 

 
Add the following class in the appropriate package
 

 
package android.support.v7.app;

public class ActionBarActivity extends AppCompatActivity {
}



If your app targets 8.0, create a new Notification channel and pass the notification channel id to Hotline SDK as follows.


HotlineNotificationConfig notificationConfig = new HotlineNotificationConfig()
                .setNotificationChannelId("custom_notif_channel");


Where `custom_notif_channel` is the channel id of the notification channel


2. Initializing Hotline

Invoke Hotline.init() with your app id and app key before invoking/ attempting to use any other features of Hotline SDK.  

Note : We highly recommend invoking init() from your app's launcher/main activity's onCreate() function. Hotline SDK checks for presence of its components during init() and will warn about missing components when it detects the compoents are missing or their manifest entries are missing.


Don't forget to replace the YOUR-APP-ID and YOUR-APP-KEY in the following code snippet with the actual app ID and app key.    
import com.freshdesk.hotline.*;

public class MainActivity extends Activity {
  public void onCreate(Bundle savedInstance) {
    super.onCreate(savedInstance);
    setContentView(R.layout.mainview);

    HotlineConfig hlConfig=new HotlineConfig("YOUR-APP-ID","YOUR-APP-KEY");
    Hotline.getInstance(getApplicationContext()).init(hlConfig);
  }
}

 

2.1 Initialization Options

Enable or disable features like voice messaging (by specifying it in the config like below) before initialization.   

HotlineConfig hConfig=new HotlineConfig("<YOUR-APP-ID>","<YOUR-APP-KEY>");

hConfig.setVoiceMessagingEnabled(true);
hConfig.setCameraCaptureEnabled(true);
hConfig.setPictureMessagingEnabled(true);

Hotline.getInstance(getApplicationContext()).init(hConfig); 


3. User Information (Optional)

3.1 Updating User Information
You can send basic user information at any point to give you more context on the user when your support agents are messaging back and forth with them.         
//Get the user object for the current installation
HotlineUser hlUser=Hotline.getInstance(getApplicationContext()).getUser();

hlUser.setName("John Doe");
hlUser.setEmail("john.doe.1982@mail.com");
hlUser.setExternalId("john.doe");
hlUser.setPhone("+91", "9790987495");

//Call updateUser so that the user information is synced with Hotline's servers
Hotline.getInstance(getApplicationContext()).updateUser(hlUser);

  

3.2 Updating User Properties (Meta Data)


You can capture and send additional metadata about the user and the events in the app, all of which also becomes a way to segment your users to later push messages to them.  

/* Set any custom metadata to give agents more context, and for segmentation for marketing or pro-active messaging */
Map<String, String> userMeta = new HashMap<String, String>();
userMeta.put("userLoginType", "Facebook");
userMeta.put("city", "SpringField");
userMeta.put("age", "22");
userMeta.put("userType", "premium");
userMeta.put("numTransactions", "5");
userMeta.put("usedWishlistFeature", "yes");
                                
//Call updateUserProperties to sync the user properties with Hotline's servers
Hotline.getInstance(getApplicationContext()).updateUserProperties(userMeta);

   


3.3 Clear User Data

Clear user data at logout or when deemed appropriate based on user action in the app by invoking the clearUserData API. 
Hotline.clearUserData(getApplicationContext())

 4. Launching the Support Experience

Use the snippets below to launch into the FAQ or Conversation based support experience from a call to action in your app. Your call to action or entry point could be an on-screen button or a menu item.  
4.1 Conversations
In response to a specific UI events like a menu selection or button on click event, invoke the showConversations() API to launch the Conversation Flow. If the app has multiple channels configured, the user will see the channel list. Channel list is ordered as specified in the Dashboard (link to channel list in dashboard) when there are no messages. When messages are present, the order is based on most recently used first

Note : Only Message Channels with visibility set to "Visible to all users" will be displayed when using showConversations() API

// Launching Conversation List from click of a button in your app's screen
myConversationsButton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View view) {
        Hotline.showConversations(getApplicationContext());
    }
}); 


 

4.1.1 Conversation Options - Filtering message channels 

 

To filter and display only Message Channels tagged with a specific term, use the filterByTags API in ConversationOptions instance passed to showConversations() API as below.


Note :  Message Channels with visibility set to "Visible in filtered view of conversations by tags" which are normally not visible when using showConversations() API, will also be displayed when tagged and the specific tag is passed to filterByTags API of ConversationOptions instance passed to showConversations() API


Eg: To link and display only specific Message Channels from say orders page in your app, those specific Message Channels can be tagged with the term "order_queries    


List<String> tags = new ArrayList<>();
tags.add("order_queries");

ConversationOptions convOptions = new ConversationOptions()
    .filterByTags(tags, "Order Queries");

Hotline.showConversations(MainActivity.this, convOptions);



4.2. FAQ

In response to specific UI events like a menu selection or button on click event, invoke the showFAQs() API to launch the FAQ screen.
By default the FAQ Categories is displayed as a grid with a “Contact Us” button at the bottom. For customising this, check the FAQ Options.
// Launching FAQ from click of a button in your app's screen
myFAQButton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View view) {
        Hotline.showFAQs(getApplicationContext());
    }
});


4.2.1 FAQ Options

Customizations to the FAQ Flow can be achieved by specifying the relevant options in the FaqOptions instance passed to the showFAQs() API.  
 

Eg.    

// Launching FAQ from click of a button in your app's screen
myFAQButton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View view) {

        FaqOptions faqOptions = new FaqOptions()
            .showFaqCategoriesAsGrid(true)
            .showContactUsOnAppBar(true)
            .showContactUsOnFaqScreens(false)
            .showContactUsOnFaqNotHelpful(false);

        Hotline.showFAQs(MainActivity.this, faqOptions);
    }
});

  

 

4.2.2 Filter FAQ Categories by tags

 

To filter and display only FAQ Categories tagged with a specific term, use the filterByTags API with Filter Type as Category in FAQOptions instance passed to showFAQs() API as below.

Eg: To display FAQ Categories related to specific user type, those specific FAQ Categories can be tagged with the term "premium" 


List<String> tags = new ArrayList<>();
tags.add("premium");

FaqOptions faqOptions = new FaqOptions()
    .filterByTags(tags, "FAQs", FaqOptions.FilterType.CATEGORY);//tags, filtered screen title, type

Hotline.showFAQs(MainActivity.this, faqOptions);



4.2.3 Filter FAQs by tags

To filter and display only FAQs tagged with a specific term, use the filterByTags API with Filter Type as Article in FAQOptions instance passed to showFAQs() API as below. 

Note : FAQs also inherit the tags from the parent FAQ Category.


Eg: To link to FAQs related to payment failure, those specific FAQs can be tagged with the term "payment_failure" and can be linked to from Payments page in the app   

List<String> tags = new ArrayList<>();
tags.add("payment_failure");

FaqOptions faqOptions = new FaqOptions()
    .filterByTags(tags, "payment_failure", FaqOptions.FilterType.ARTICLE);//tags, filtered screen title, type

Hotline.showFAQs(MainActivity.this, faqOptions);

    


4.2.4 Filter Message Channels displayed on clicking "Contact Us" in FAQs by tags

To filter and display only Message Channels tagged with a specific term when user clicks "Contact Us"in FAQ screens, use the filterContactUsByTags API in FAQOptions instance passed to showFAQs() API as below.


Note : The default behaviour for "Contact Us" from within FAQ flow is same as invoking showConversations() i.e it will display all channels that are marked "Visible to all users", except when filtering of channels is enabled by passing tags to filterContactUsByTags API


Eg: To display Message Channels related to specific section of FAQ show, those specific Message Channels can be tagged with the term "payment_failure"   

List<String> tags = new ArrayList<>();
tags.add("payment_failure");

FaqOptions faqOptions = new FaqOptions()
    .filterContactUsByTags(tags, "Payments"); //tags, filtered screen title

Hotline.showFAQs(MainActivity.this, faqOptions);



5. Displaying unread message count (Optional)

5.1 Unread message count across "All Conversations" :

If you would like to obtain the number of unread messages for the user, use the getUnreadCountAsync API        

protected void onResume() {
    Hotline.getInstance(getApplicationContext()).getUnreadCountAsync(new UnreadCountCallback() {
        @Override
        public void onResult(HotlineCallbackStatus hotlineCallbackStatus, int unreadCount) {
            //Assuming "badgeTextView" is a text view to show the count on
            badgeTextView.setText(Integer.toString(unreadCount));
        }
    });
}

       

5.2 Unread message count across "Conversations Filtered By Tags" :

If you would like to obtain the number of unread messages for the user across specific conversations filtered by tags, use the getUnreadCountAsync API

protected void onResume() {
    List<String> tags = new ArrayList<>();
    tags.add("premium"); //Tags to filter conversations by
    Hotline.getInstance(getApplicationContext()).getUnreadCountAsync(new UnreadCountCallback() {
        @Override
        public void onResult(HotlineCallbackStatus hotlineCallbackStatus, int unreadCount) {
            //Assuming "badgeTextView" is a text view to show the count on
            badgeTextView.setText(Integer.toString(unreadCount));
        }
    }, tags);
}



6. Proguard Configuration (If Proguard is enabled in your app)

Holtine Android SDK from version 1.0.1 is configured out of the box to support proguard. Proguard will automatically pickup the config for the SDK, no manual configuration is necessary.

Some exceptions to the automatic configuration noted below: 

- If target OS version is not Marshmallow (API Level 23), please include the following in the app's proguard-rules.pro

-dontwarn com.freshdesk.hotline.**

 

- If you are integrating Hotline SDK version 1.1.12 with proguard enabled and custom font support is not required, please include the following in the app's proguard-rules.pro

-dontwarn uk.co.chrishenx.calligraphy.**


This is no longer required as of version 1.0.13 onwards



7. Push Notifications

Prerequisites: 

-  / GCM Implemented in you app
- Device running Play Services
- FCM Server Key or GCM Server API Key 
Steps to get push notifications working with Hotline
Step 1 : Sending the device registration token to Hotline
Step 2 : Handling messages

7.1 Connecting Hotline with GCM/FCM
Option 1: FCM
If you haven’t already integrated FCM, do so by following the instructions here
After following FCM steps for integration, follow these 2 steps to connect Hotline and FCM
Step 1. Send Registration Token
In the app’s implementation of  FirebaseInstanceIdService, send the token to Hotline as follows 
@Override
public void onTokenRefresh() {
    String token = FirebaseInstanceId.getInstance().getToken();
    Hotline.getInstance(this).updateGcmRegistrationToken(token);
}

  

Step 2 : Handle FCM Message
In the app’s implementation of  FirebaseMessagingService, pass the RemoteMessage object to Hotline if it is a Hotline notification. 
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    if (Hotline.isHotlineNotification(remoteMessage)) {
        Hotline.getInstance(this).handleFcmMessage(remoteMessage);
    } else {
        //Handle notifications with data payload for your app
    }
}

 


Option 2 : GCM

Please update the Hotline SDK with your GCM registration token once it becomes available.”

Step 1. Send Registration Token
In the app’s implementation of InstanceIDListenerService’s onTokenRefresh() method or the GcmRegistrationService
Hotline.getInstance(context).updateGcmRegistrationToken(token);

 

Step 2: Handle GCM Message
In the app’s implementation of GCMListenerService’s onMessageReceived, pass the instance of the Bundle received as a parameter in onMessageReceived to Hotline if it is a Hotline notification.
@Override
protected void onMessageReceived(String from, Bundle data) {
    if(Hotline.isHotlineNotification(data)) {
        Hotline.getInstance(this).handleGcmMessage(data);
        return;
    } else {
        // Your application code goes here to handle other kinds of messages
    }
}

   

7.2 Customizing Notifications

Hotline SDK supports customizing the following for notifications.

1. Notification Icon (Small Icon and Large Icon) - App icon is used as the default for small icon if not set explicitly

2. Notification Sound - Enable or disable notification tone. Default is disabled.

3. Notification Deeplink Behaviour - If deeplink is present in a notification, whether clicking on the notifications should take the user to the deeplink target or the messages screen. From version 1.0.1, defaults to launching the deeplink target when clicking on the notification

4. Notification Priority - Priority for notifications. Default is NotificationCompat.PRIORITY_DEFAULT. 
Do note, priority is used to determine whether to auto expand notifications. If there are other notifications with higher priority, the picture message notifications won’t expand by default.

5. Activity to launch on up navigation from the messages screen launched from notification. The messages screen will have no activity to navigate up to in the backstack when its launched from notification. Specify the activity class name to be launched.   


6. For specifying the accent color of the circle behind the small icon in notification 


<color name="hotline_notification_accent_color">@color/red</color>

 

HotlineNotificationConfig notificationConfig = new HotlineNotificationConfig()
    .setNotificationSoundEnabled(true)
    .setSmallIcon(R.drawable.ic_notif_small_icon)
    .setLargeIcon(R.drawable.ic_notif_large_icon)
    .launchDeepLinkTargetOnNotificationClick(true)
    .launchActivityOnFinish(MainActivity.class.getName())
    .setPriority(NotificationCompat.PRIORITY_HIGH);

Hotline.getInstance(getApplicationContext()).setNotificationConfig(notificationConfig);


8. Send message on behalf of user


The app can send a message on behalf of the user using the sendMessage() API. 

Note: This API would silently send a message and not launch the Hotline SDK UI


Eg: To send a message on a channel tagged "premium", the API can be invoked as below

String tag = "premium";
String msgText = "User has trouble with order #1234";
HotlineMessage hotlineMessage = new HotlineMessage().setTag(tag).setMessage(msgText);
Hotline.sendMessage(getContext(), hotlineMessage);



9. PERMISSIONS


9.1 Dynamic Permissions Model
Hotline SDK is built with support for the Run Time / Dynamic Permissions Model introduced in Marshmallow as long as the app is built with targetSdk as Marshmallow or later.
9.2 Negating Unused Permissions - Android Manifest
Hotline requires the following permissions for voice messaging. 

- android.permission.RECORD_AUDIO

- android.permission.WRITE_EXTERNAL_STORAGE

If the app doesn’t require the voice messaging features, the permissions can be removed by specifying the permission along with tools:node="remove" in your app’s manifest 

<uses-permission android:name="android.permission.RECORD_AUDIO" tools:node="remove" />


9. Checklist for launch 


  1. Ensure you are initializing the SDK in the onCreate of the main / launcher activity
  2. Check that you have push notifications working right from your first launch, and have the right notification icons configured
  3. Ensure the App name is set right for your notifications
  4. Negate the audio recording permissions in your manifest if you are not using voice messaging
  5. See our Theming and Customization document here to make sure you are matching the experience with the rest of your app
  6. Configure your default channel name and welcome message right even if you aren't using other channels
  7. Capture the unique user identifier, email, phone number, or any other unique customer identifiers with the SDK to ensure smooth use of APIs, as well as for best use of our "Smart Plugs" feature on the dashboard.
  8. Ensure the push notifications are working for new installs as well as upgrades from your previous versions.