Usage

This is the technical documentation which describes how to implement the Clever Dialer SDK into your application. For non-technical information about the SDK and its feature set look here: overview

General

The Clever Dialer SDK comes with a very flexible, configurable feature set. The hosting app can decide which features should be supported and available to the user. In order to enable the user to adjust the state of the supported SDK (core) features according to his wishes, it contains a dynamically created settings page, too. As the main goal of the SDK is detecting phone calls and providing contact details upon / during (pre-call) and after (post-call) a phone call, it requires a set of permissions, which the user has to grant at runtime during the SDKs onboarding process. To figure out, if the user already did so the hosting application can query the current SDK status at any time. To enable the hosting application to bring its own functionality into the process, the SDK propagates events to the hosting app, which partially have to be handled. Doing so, the hosting app is able to react on user click events and provide a great, consistent user experience. Furthermore, the Clever Dialer SDK can help the hosting application to collect app reviews, boost the reputation in the store listing and grow organically. The integration of the Clever Dialer SDK can be tested easily.

Integration

Setting Value
minSdkVersion 24
targetSdkVersion 34
compileSdkVersion 34

If the hosting application is built using Gradle, the Clever Dialer SDK can be pulled directly from our Maven repository.

implementation('de.validio.cdand:cdand-sdk:1.12.1:<classifier>@aar') {
    transitive = true
}

The <classifier> has to be replaced with your partnerId, which is provided by us and tells the SDK which hosting application it is being integrated into. To make sure transitive dependencies are being loaded, the flag transitive has to be set to true.

Furthermore, our Maven repository has to be added to your build.gradle.

allprojects {
    repositories {
        maven {
            credentials {
                username "$mavenUser"
                password "$mavenPassword"
            }
            url "https://nexus.validio.de/content/repositories/partner-releases/"
        }
    }
}

TIP

The values for $mavenUser and $mavenPassword are best kept separate from your source and should be set in ~/.gradle/gradle.properties.

If the hosting project is not using Java 8+, Java version has to be set to 8 in build.gradle:

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

API credentials

All web service requests are directed to the Clever Dialer production environment hosted under https://ws.cleverdialer.com/api/1.4 by default.

Therefore, at least, your credentials to our production environment have to be added to a file named src\main\res\values\config.xml.

<string name="cd_sdk_partner_id" translatable="false"></string>
<string name="cd_sdk_secret" translatable="false"></string>

During app development, it can be helpful to point to our dev or staging environment. In order to do this, the URL of the desired environment has to be added to a file named src\<build_type>\res\values\config.xml as shown in the following example.

<string name="cd_sdk_ws_base_url" translatable="false">
    https://ws.dev.cleverdialer.com/api/1.4
</string>

The corresponding authentication credentials cd_sdk_partner_id and cd_sdk_secret must be stored inside said config.xml file as well.

ProGuard

If the hosting application project uses ProGuard, it does not have to manually update the ProGuard file, as the Clever Dialer SDK embeds its own ProGuard file. As the SDKs ProGuard rules are specified by using the consumerProguardFiles property inside the defaultConfig block of the SDKs build.gradle file, they will automatically be appended to the ProGuard configuration file of the hosting app.

Onboarding process

In order to detect phone calls and work correctly, the Clever Dialer SDK requires a set of permissions. The permissions are declared in the AndroidManifest of the SDK and therefore do not need to be entered into the Manifest of the hosting application. Starting with Android 6.0 (API level 23), the user is requested to grant permissions at runtime.

Required permissions

The user must at least grant the permissions READ_PHONE_STATE and PROCESS_OUTGOING_CALLS at runtime for the caller identification to work. Starting with Android 9 (API level 28) the permission READ_CALL_LOG is required, too. The permission SYSTEM_ALERT_WINDOW has to be granted, to enable the hosting application to draw the Pre-Call Overlay on top of all other apps.

<uses-permission android:name="android.permission.INTERNET" />

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

<uses-permission android:name="android.permission.READ_PHONE_STATE" />

<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />

<uses-permission-sdk-23 android:name="android.permission.READ_CALL_LOG" />

Since the Clever Dialer SDK communicates with the hosting app through events, an additional permission must be added to the AndroidManifest.xml of the hosting application. This enables the hosting app to register for these events. The <classifier> - usually the cd_sdk_partner_id in capitals - must be added as well.

<!-- receive SdkEvents -->
<uses-permission android:name="de.validio.cdand.sdk.SDK_EVENT_PERMISSION_<classifier>"/>

If the Clever Dialer SDK should not show an overlay for phone numbers, which are stored in the users address book, it requires the READ_CONTACTS permission in order to get access to the users address book. The hosting application can decide, if it wants to support this feature. If it does, it has to declare the permission in its AndroidManifest.

<uses-permission android:name="android.permission.READ_CONTACTS" />

If the Clever Dialer SDK should send notifications to the user, whenever a Post-Call Overlay is shown, the hosting application has to make sure, to request the permission POST_NOTIFICATIONS if the app is installed on a device running Android 13. The hosting application can decide, if it wants to support this feature. If it does, it has to declare the permission in its AndroidManifest and is responsible to ask the user to grant it.

<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

Implementation

The hosting application could either implement its own logic to ask the user to accept the usage of the SDK and request all these required permissions, or it could just use the default onboarding process provided by Clever Dialer SDK. Using the default onboarding process, the hosting application can decide when and how often a user should be asked to activate the SDK (if he does not do it at first attempt).

To use the default onboarding process, the hosting application just has to call the static method:

CleverDialerSdk.enableOnboardingProcess(Context context, boolean isCdSdkUsageAccepted);

DANGER

It is important, that the hosting application passes the right value for isCdSdkUsageAccepted. Otherwise users, who already accepted the usage of Clever Dialer SDK, would be asked again.

If the hosting application did or does not use the default onboarding process until now, it has to care about a flag / SharedPreference, which indicates that the user accepted the usage of the Clever Dialer SDK. It is important to pass this value as param isCdSdkUsageAccepted when enableOnboardingProcess() is called. Otherwise users, who already accepted the usage of the SDK, would be asked again.

A good place to call enableOnboardingProcess() would be the onStart()-method of the hosting apps MainActivity.java:

@Override
protected void onStart() {
    super.onStart();
    CleverDialerSdk.enableOnboardingProcess(
            this, isCdSdkUsageAccepted, new Frequency(7, 3, 90));
}

IMPORTANT

If the default onboarding process is used, the hosting application has to react to some events, too.

By calling enableOnboardingProcess(), the hosting app tells the SDK, that it is responsible for onboarding from now on. Whenever this method is called, the SDK will check if the usage was accepted and if each mandatory permission was granted. If any approval is missing, the SDK will start to ask the user to agree. If the user denies this by clicking the negative button in the onboarding overlays, the decision will be postponed. When the user will be asked again is defined by the frequency, in order to prevent annoying him. This frequency takes three values into account:

  • intervalDays: Amount of days which have to be passed before the user is asked again
  • limit: Amount of times the user will be asked, before the requests are paused for revivalDays.
  • revivalDays: Amount of days which have to be passed to reactivate the onboarding process.

This means:
If the user chooses NOT NOW in the overlay he will be asked again in intervalDays days. If he postpones each time, he will only be asked a maximum of limit times. If he postpones again after that, the onboarding process will be paused for the amount of revivalDays days. After that time has passed, the process will be repeated. The hosting app can specify these values by passing an object of type Frequency.java to enableOnboardingProcess().

TIP

As shown in the code above, the hosting application defined some hard coded values to specify the onboarding frequency. However, it is best practice, to make these values configurable at runtime e.g. via Firebase Remote Config. This way, the frequency rule could easily be changed on the fly in order to find out the values, which produce the best results.

If the hosting application calls enableOnboardingProcess() without passing a frequency object, the default frequency will be used:

default frequency example above
intervalDays 3 7
limit 3 3
revivalDays 45 90

The onboarding process is started in its own (translucent) Activity. When it finishes, the user automatically returns to the Activity which called enableOnboardingProcess(). Therefore, the calling Activity can monitore the current state of the onboarding process in its onResume()- method:

@Override
protected void onResume() {
    super.onResume();

    if (!CleverDialerSdk.getStatus(this).isOnboarding()) {
        // Onboarding finished. The hosting application can
        // e.g. show other dialogs now.
    }
}

Starting with Clever Dialer SDK version 1.11.0 calling enableOnboardingProcess() will also init a mechanism, which will periodically send a local notification to the user, in order to remind him to fulfill the required setup steps. This notification will be created depending on the current permission state of the running device and respect the discussed onboarding frequency. It will be delivered in an interval of intervalDays days and be paused during revivalDays. In order to get this process working, the hosting app has to request and hold the permission POST_NOTIFICATIONS.

If in a later version of the hosting app, the application should be changed to implement its own onboarding process, it has to signal, that the SDK is not responsible for onboarding anymore. This can be done by calling:

CleverDialerSdk.disableOnboardingProcess(Context context);

After calling this static method, the SDK will stop onboarding and will not request the permissions anymore. The hosting application will have to handle the activation / deactivation of all SDK features by it self.

Configuration

The Clever Dialer SDK comes with a very flexible, configurable feature set. The hosting app can decide, which features should be supported and available to the user.

Implementation

In order to configure the SDK, the hosting application must instantiate a Config.Builder and call the support-methods for the desired features. Passing true to these methods means, that a feature should be supported and available to the user. By passing false the feature will be shut off and will not be present in the hosting app. The resulting configuration has to be passed to the static method CleverDialerSdk.configure(Context context, Config config).

A good place to configure the SDK, is the onCreate()-method of the hosting apps class App.java:

public class App extends MultiDexApplication {
    @Override
    public void onCreate() {
        super.onCreate();

        Config config = new Config.Builder()
                    // TODO Call support-methods to declare, which
                    //  features should be available in the hosting app

                    // Passing true to these methods means, that a feature
                    // should be supported and available to the user.
                    .supportCallerId(true)

                    // By passing false the feature will be shut off and
                    // will not be present in the hosting app.
                    .supportAddressBookAccess(false)

                    .supportSpamProtection(isProUser)
                    .supportBookingLinks(isBetaTester)
                    .supportNotifications(areNotificationsEnabled)
                    
                    .writeLogs(BuildConfig.DEBUG)
                    // ...
                    .build();

        CleverDialerSdk.configure(this, config);
    }
}

Options

The class Config.Builder provides support-methods for all configurable features of the SDK. They are listed and discussed in this section.

Spam protection

By default, the SDK will show warnings upon / during (pre-call) and after (post-call) a phone call, if the given phone number is identified as a known spam number. If the hosting app does not want to support this feature, it has to call supportSpamProtection(false).

Default: true (-> supported)

Caller ID

By default, the SDK will show Pre-Call- and Post-Call Overlays with contact details, whenever a (partner) directory entry was found for a given phone number. If the hosting app does not want to support this feature, it has to call supportCallerId(false).

Default: true (-> supported)

Alternative suggestions

By default, the SDK will show a Post-Call Overlay with alternative suggestions, if the user tried to call an identified business, but the phone call was not answered and alternatives have been found. If the hosting application does not want to support this feature, it has to call supportAlternativeSuggestions(false).

Default: true (-> supported)

If the hosting application wants to support this feature, it can optionally pass some params, in order to specify the behavior of the feature and the corresponding overlay. For example it can decide, if it wants to include a "more"-button in the overlay (at the end of the alternative suggestions list). Furthermore, it can decide to deactivate the restricted mode, which means, that the alternatives suggestions will be shown independently of the call type and no longer be limited to unsuccessful outgoing calls. Therefore, this will increase the impressions of alternative suggestion overlays a lot.

Config.Alternatives.Params params = new Config.Alternatives.Params();
params.includeMoreButton(true);             // default is `false`
params.restrictToUnsuccessfulCalls(false);  // default is `true`

Config.Builder builder = new Config.Builder()
        .supportAlternativeSuggestions(true, params);

Online booking call interceptor

By default, the SDK will not intercept phone calls. However, if the hosting app wants to support the call-interceptor feature in order to promote online booking options for business directory entries, it has to call supportOnlineBookingCallInterceptor(true).

Default: false (-> unsupported)

Notifications

Whenever a Post-Call Overlay is shown, the Clever Dialer SDK will send a notification to the user, too. By clicking the notification, the user can reopen the Post-Call Overlay. If the hosting app does not want to support this feature, it has to call supportNotifications(false).

Default: true (-> supported)

WARNING

If the hosting application wants to support this feature (which it does per default), it has to make sure, that the permission POST_NOTIFICATIONS is requested, if the app is installed on a device running Android 13 (API level 33). The Clever Dialer SDK does not request this permission. In order to provide a consistent user experience, the hosting application should consider to mark notifications as unsupported, as long as the user did not enable notifications (by granting the required permission) in this case.

Address book access

By default, the SDK will enable the user to grant access to his address book. If the user does not want to see any overlays for phone numbers, which are stored in his address book, he has to grant access to his address book. If the hosting app does not want to support this feature, it has to call supportAddressBookAccess(false). Doing so, the user will not be able to deactivate overlays even if the phone number is stored in his address book.

Default: true (-> supported)

WARNING

If the hosting application wants to support this feature (which it does per default), it has to declare the permission READ_CONTACTS in its AndroidManifest.

Rate-button

By default, the SDK will not collect ratings for directory entries. If the hosting app wants to support this feature, it has to call supportRateButton(true). Doing so, the Post-Call Overlay will contain a button, which allows the user to rate a contact, if the given contact allows it.

Default: false (-> unsupported)

By default, the SDK will show a hint in the Pre-Call Overlay and a clickable booking link in the Post-Call Overlay and alternative suggestions, if the given contact supports online booking. If the hosting app should not support online booking, call supportBookingLinks(false).

Default: true (-> supported)

Profile-button

By default, the Post-Call Overlay will contain a button, which enables the user to open the profile belonging to the given contact. If the hosting application does not want to provide this feature, it has to call supportProfileButton(false).

Default: true (-> supported)

Share-button

By default, the Post-Call Overlay will contain the share button to enable the user to forward the contact / directory data found by the SDK. If the hosting application does not want to provide this feature, it has to mark it as unsupported by calling supportProfileSharing(false).

Default: true (-> supported)

Write logs

The hosting application can decide, if the Clever Dialer SDK should write debugging output to the log to review it with logcat. Logging is deactivated by default. If it should be activated during development, writeLogs(true) has to be called.

Default: false (-> no logging)

Rules

There are three rules, which have to be followed, in order to configure the Clever Dialer SDK correctly. An infringement will cause a ConfigurationException to be thrown.

Spam protection and / or Caller ID

At least spam protection or caller ID (or both) have to be supported by the hosting application.

Alternative suggestions requires Caller ID

If the hosting app wants to provide alternative suggestions, it has to support caller ID, too.

Online booking call interceptor requires Caller ID

If the hosting app wants to provide the online booking call interceptor feature, it has to support caller ID, too.

Settings page

The Clever Dialer SDK contains a default settings page, which can optionally be used by the hosting app. The settings page is created dynamically and will provide settings according to the chosen configuration. It enables the user to activate / deactivate the supported (core) features of the SDK according to his wishes.

User settings

Depending on the configuration which the hosting application set, the settings page will or will not contain the following entries:

Spam protection

The user can decide, if he wants to be warned against untrustworthy numbers that are considered spam.

<CheckBoxPreference
    android:key="@string/cd_sdk_pref_spam_protection_enabled"
    android:defaultValue="@bool/cd_sdk_default_enable_spam_protection" />

Default: true (-> enabled)

Caller ID

The user can decide, if the SDK should try to identify phone numbers and display contact details during / after the call.

<CheckBoxPreference
    android:key="@string/cd_sdk_pref_caller_id_enabled"
    android:defaultValue="@bool/cd_sdk_default_enable_caller_id" />

Default: true (-> enabled)

Alternative suggestions

The user can decide, if the SDK should display alternative suggestions after a phone call with a business.

<CheckBoxPreference
    android:key="@string/cd_sdk_pref_alternative_suggestions_enabled"
    android:defaultValue="@bool/cd_sdk_default_enable_alternative_suggestions" />

Default: true (-> enabled)

Online booking call interceptor

The user can decide, if the SDK should show the call interceptor screen, when he tries to place a phone call to a business, which supports online booking.

<CheckBoxPreference
    android:key="@string/cd_sdk_pref_online_booking_call_interceptor_enabled"
    android:defaultValue="@bool/cd_sdk_default_enable_online_booking_call_interceptor" />

Default: true (-> enabled)

Address book access

Determines, if the sdk should access the local address book of the user. If so, it does not show additional information for a phone number during / after a call if the number is stored in the local address book.

<CheckBoxPreference
    android:key="@string/cd_sdk_pref_address_book_access_enabled"
    android:defaultValue="@bool/cd_sdk_default_enable_address_book_access" />

Default: false (-> disabled)

WARNING

If the user wants to activate this feature (which means, that he does not want to see overlays, if the given phone number is stored in his address book), he has to grant the permission READ_CONTACTS. Therefore the hosting application has to add the permission to its AndroidManifest.

Notifications

The user can decide, if the SDK should send a notification as soon as the call has been ended and further details for the phone number have been found.

<CheckBoxPreference
    android:key="@string/cd_sdk_pref_notifications_enabled"
    android:defaultValue="@bool/cd_sdk_default_enable_notifications" />

Default: true (-> enabled)

Default values

As shown above, the Clever Dialer SDK defines the default_enable state for all the listed preferences. However, the hosting application is able to override these values. The default values will define the behavior of the core features, as long as the user does not change the settings himself.

To override the default values, (and therefore the default behavior) of the core features, the following entries can be added to the file src\main\res\values\config.xml which has already been created to add the SDK credentials:

<!-- Declare the default enabled state for the (supported) core features.
Can be changed by the user at runtime within the default settings page. -->
<bool name="cd_sdk_default_enable_spam_protection">true</bool>
<bool name="cd_sdk_default_enable_caller_id">true</bool>
<bool name="cd_sdk_default_enable_alternative_suggestions">true</bool>
<bool name="cd_sdk_default_enable_address_book_access">false</bool>
<bool name="cd_sdk_default_enable_notifications">true</bool>
<bool name="cd_sdk_default_enable_online_booking_call_interceptor">true</bool>

Implementation

The hosting application has two options:
1.) It could either add each of the listed preferences as a TwoStatePreference (for example CheckBoxPreference) to its PreferenceScreen and implement the logic behind (e.g. it should care about requesting the permission READ_CONTACTS, if the user wants to deactivate overlays for contacts, which are stored locally).
2.) It could just use the default settings page, which is included in the Clever Dialer SDK.

To use the default settings page, the Activity CdSdkSettingsActivity.java has to be added to AndroidManifest.xml of the hosting application:

<activity
    android:name="de.validio.cdand.sdk.controller.activity.CdSdkSettingsActivity" />

Now, the hosting application can decide, when to open / show this screen. For example, the hosting app could add a MenuItem to its NavigationView or an entry to its PreferenceScreen and open the SDKs settings page, when the user clicks this item.

To open the settings, the Activity can be started by simply calling the static method:

CleverDialerSdk.openSettingsActivity(Context context, boolean isCdSdkUsageAccepted);

DANGER

It is important, that the hosting application passes the right value for isCdSdkUsageAccepted when the settings page is opened. Otherwise users, who already accepted the usage of Clever Dialer SDK, would be asked again.

The default settings page includes an element, where the user can activate the SDK and will ask him to do so, if he did not do it yet. If the hosting application did or does not use the default onboarding process until now, it has to care about a flag / SharedPreference, which indicates if the user accepted the usage of the Clever Dialer SDK. It is important to pass this value as param isCdSdkUsageAccepted when openSettingsActivity() is called. Otherwise users, who already accepted the usage of Clever Dialer SDK, would be asked again.

The default settings page can be changed and styled easily:

  • If the hosting application wants to change the title in the Toolbar of the settings page, it just has to add android:label="@string/title" to the activity-tag in the AndroidManifest-entry.
  • If the hosting application wants to change the style of the settings page, it could override the file cd_sdk_preferences_screen.xml. For example, instead of CheckBoxPreference another type of TwoStatePreference (e.g. SwitchPreference) could be used.
  • The texts for android:title or android:summary, referenced in cd_sdk_preferences_screen.xml, could be changed, as well.
  • By default the settings page will use the colors of the standard AppTheme. To individualize the page, a different theme can be defined in the src\main\res\values\styles.xml. By setting the colors colorPrimary, colorPrimaryDark and colorAccent the displayed colors can be adjusted. Adding the created theme to the activity-tag in the AndroidManifest.xml will set the preferred style for the screen.

If the hosting application uses the default settings page of the Clever Dialer SDK, it has to handle the corresponding click events. Furthermore, as the user is able to start the onboarding process from within the settings page, the hosting application has to handle the onbording process click events, too.

Status reporting

If the hosting application uses the default onboarding process and the default settings page, it can query the current SDK status at any time. Therefore it just has to call the static method CleverDialerSdk.getStatus(Context context), which will provide an object of type Status, to describe the current state of the SDK.

Description of the class Status:

Value Method & description
boolean
isOnboarding()

Returns a boolean-flag, which indicates, whether the SDK is showing the onboarding overlays at the moment, or not.
boolean
isCdSdkUsageAccepted()

Returns a boolean-flag, which explains, whether the user accepted the usage of the SDK, or not. Will be true, if he did so.
boolean
arePermissionsGranted()

Returns a boolean-flag, which explains, whether the user granted the mandatory permissions, which are required by the SDK to work correctly, or not. As the permission READ_CONTACTS is optional, this permission is not taken into account here. Furthermore, the permission SYSTEM_ALERT_WINDOW is ignored here, too, as the SDK will for example be able to show Post-Call Overlays, even without this permission.
Set<CoreFeatureState>
getCoreFeatureStates()

Returns a Set of CoreFeatureState dependend on the SDK features, which are supported by the hosting application. Features which are not supported, will not be listed here. A CoreFeature is a SDK feature, which can be supported by the hosting application and enabled / disabled by the user via the default settings page at runtime.

Description of the class CoreFeatureState:

Value Method & description
Label
getName()

Returns the name of the feature.
boolean
isActive()

Returns a boolean-flag to describe, whether this feature is acitve or not. A feature will be active, if the user accepted the usage of the SDK, granted all mandatory permissions and did not disable it in the default settings page.

The Status-object will enable the hosting application, to find out if a user accepted the usage of the SDK and if he granted all mandatory permissions. Furthermore it will get insights in the current state of the SDKs CoreFeatures. As mentioned in the table above, a CoreFeature is a SDK feature, which can be supported by the hosting app and be enabled / disabled by the user at runtime via the default settings page. There are six features, which match this requirements: SPAM_PROTECTION, CALLER_ID, ALTERNATIVES, ADDRESS_BOOK_ACCESS, CALL_INTERCEPTOR_ONLINE_BOOKING, NOTIFICATIONS. The Set of CoreFeatureStates will contain an entry for each of these features, as long as it is supported by the hosting application. If the user accepted the usage of the SDK (isCdSdkUsageAccepted()) and granted all the mandatory permissions (arePermissionsGranted()) but the feature is still inactive, this proves that the user deactivated it via the settings page.

Example usage:

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // ...
        Status status = CleverDialerSdk.getStatus(this);

        if (status.isCdSdkUsageAccepted() && status.arePermissionsGranted()) {
            // The user accepted the usage of the SDK and granted all mandatory
            // permissions. Analyze the current state of the features, to find
            // out, if a feature has been disabled by the user.
            for (CoreFeatureState feature : status.getCoreFeatureStates()) {
                Log.d(TAG, feature.getName() + " is active " + feature.isActive());
            }
        }
    }
}

Online booking call interceptor

The hosting app can decide to support the call-interceptor feature in order to promote online booking options for business directory entries. Doing so, the Clever Dialer SDK can be triggered to show a screen which will enable the user to choose the online booking option, whenever he tries to start a phone call to a business - which supports this feature - within the hosting application. The default settings page will contain a checkbox to enable the user to activate / deactivate this feature.

As the call-interceptor for online booking is marked as unsupported by default, the partner app has to configure the Clever Dialer SDK accordingly, in order to use the feature:

    Config config = new Config.Builder()
                .supportCallerId(true)
                .supportOnlineBookingCallInterceptor(true)
                // ...
                .build();

    CleverDialerSdk.configure(this, config);

Afterwards, whenever the hosting application wants to show the call interceptor for online booking screen, it just has to call the static method CleverDialerSdk.interceptOrDial(context, phoneNumber) and pass in the phone number which the user wants to call:

CleverDialerSdk.interceptOrDial(context, phoneNumber);

Whenever this method is called, the Clever Dialer SDK will start a request to the Clever Dialer Webservice in order to load data for the given phone number. If the response proves that the number belongs to a business that supports online booking, the SDK will show the call interceptor screen and ask the user to book online (if he did not deactivate this feature in the default settings page). Otherwise it will hand over the phone number to the default dialer app to enable the user to place the phone call.

DANGER

As a call to CleverDialerSdk.interceptOrDial(context, phoneNumber) will cause a request to Clever Dialer Webservice - which means that data will be transferred to the server - the user has to accept the usage of the SDK upfront. If the hosting application does not use the default onboarding process of the Clever Dialer SDK, it has to make sure, that the method is only called, if the user has accepted the usage of the SDK.

if (isCdSdkUsageAccepted) {
    CleverDialerSdk.interceptOrDial(context, phoneNumber);
} else {
    // TODO Ask the user to accept the usage of the SDK or start the
    //  phone call directly
}

If the hosting application wants to support the call-interceptor for online booking, it has to be able to handle the corresponding click events.

Events

On many occasions, the Clever Dialer SDK sends events to the hosting app. Such an event, which is represented by the class SdkEvent, is being triggered for example when an overlay is being shown or a user action is being registered. Some of these events are mandatory and must be handled by the hosting app. Others are optional and for reporting purpose only.

Event model

A SdkEvent always contains values of type Category and Action. In most of the cases a value of type Label is available, too. The combination of these three values describes, what caused the event to be fired. Dependent on the trigger of the event, further relevant variables are set, which enable the hosting app to extract all the important information to react accordingly.

Methods of the class SdkEvent:

Value Method & description
Category
getCategory()

Returns the Category.
Action
getAction()

Returns the Action.
Label
getLabel()

Returns the Label if available, otherwise null.
String
getPhoneNumber()

Returns the phone number which caused the overlay impression. May be null for optional reporting events and events which do not require this field.
String
getRelevantPhoneNumber()

Returns the phone number, which is relevant in the current context and belongs to the contact which the user selected in an overlay. As a contact can have more than one number, or the user might select an alternative suggestion, relevantPhoneNumber may differ from the phone number returned by getPhoneNumber(). May be null, if the selected contact does not have a phone number.
List<String>
getRawContacts()

Returns the list of contacts (raw representation according to the partner API), which were shown in the overlay. May be null for optional reporting events or if no raw contact exists (e.g. spam call).
int
getContactIndex()

Returns the list index of the contact, which is relevant in the present context.
String
getRelevantRawContact()

Returns the relevant raw contact (the contact that caused the overlay impression or if a field of an [alternative] contact has been selected, the associated contact). May be null.

For a regular Pre- or Post-Call Overlay (PRECALL_OVERLAY, POSTCALL_OVERLAY) and the CALL_INTERCEPTOR_ONLINE_BOOKING the list of raw contacts will just contain one element and the index will be 0, as these overlays always just display one contact at a time. In case of an overlay, which was shown in order to warn the user against a spam call (PRECALL_SPAM_OVERLAY, POSTCALL_SPAM_OVERLAY), the list of contacts will be null, as no raw contact exists. In case of an overlay, which shows alternative suggestions (POSTCALL_ALTERNATIVES_OVERLAY), the list of (raw) contacts will contain all the contacts, which have been displayed to the user. The first element is always the original contact, which was found for the given phone number, followed by the alternative suggestions.

DANGER

The raw contact is the raw representation of a contact according to the partner API and its version used by the Clever Dialer Webservice. Therefore it might change if the partner API changes. The hosting app must be prepared and robust to deal with those changes and stay compatible.

Example

When a Post-Call Overlay with three alternative suggestions (maximum) is shown after an outgoing phone call, the SdkEvent reported to the hosting application will contain the following information:

Method Value
getCategory()
POSTCALL_ALTERNATIVES_OVERLAY
getAction()
OUTGOING_CALL
getLabel()
The <partnerId> in capitals.
getPhoneNumber()
The phone number which caused the overlay impression.
getRelevantPhoneNumber()
Equal to getPhoneNumber(), as no contact has been selected inside of the overlay.
getRawContacts()
The list of four (raw) contacts which have been displayed to the user. The first element is always the original contact, which was found for the given phone number, followed by the alternative suggestions.
getContactIndex()
As the original contact is always the first in the list and the user did not interact with the list yet, the index will be 0.
getRelevantRawContact()
Will retrieve the original contact which was found for the given phone number and shown on top of the overlay.

Now, if the user clicks on the phone number of the second alternative suggestion, in order to call this contact, the SdkEvent reported to the hosting application will look like this:

Method Value
getCategory()
POSTCALL_ALTERNATIVES_OVERLAY
getAction()
CLICK
getLabel()
NUMBER
getPhoneNumber()
The phone number which caused the overlay impression.
getRelevantPhoneNumber()
The phone number of the second alternative suggestion, which the user selected to call now.
getRawContacts()
The list of four (raw) contacts which have been displayed to the user.
getContactIndex()
As the user selected the second alternative suggestion, the index will be 2.
getRelevantRawContact()
Will retrieve the raw contact of the second alternative suggestion.

Event handling

To be able to listen to and react on these events, the class AbstractCdSdkBroadcastReceiver must be extended by the hosting application. This class provides abstract methods, which are called, whenever an action takes place, which has to be handled by the hosting app.

public class SampleCdSdkBroadcastReceiver extends AbstractCdSdkBroadcastReceiver {
    // TODO Implement abstract methods to react on events …
}

Furthermore, this implementation of AbstractCdSdkBroadcastReceiver must be registered in the AndroidManifest.xml of the hosting application.

<receiver android:name=".receiver.SampleCdSdkBroadcastReceiver"
          android:exported="false">
    <intent-filter>
        <action android:name="de.validio.cdand.sdk.SDK_EVENT"/>
    </intent-filter>
</receiver>

Apart from that, the permission de.validio.cdand.sdk.SDK_EVENT_PERMISSION_<classifier> must be added to AndroidManifest.xml as described under permissions.

<!-- receive SdkEvents (e.g. tracking) -->
<uses-permission android:name="de.validio.cdand.sdk.SDK_EVENT_PERMISSION_<classifier>"/>

Now, the hosting application is ready to receive SdkEvents.

Mandatory events

Most of the mandatory events, which must be handled by the hosting application, are triggered by a click in an overlay. In this case, the Category describes the overlay, which was shown to the user and can therefore have one of the values ACTIVATION_OVERLAY, POSTCALL_OVERLAY, POSTCALL_SPAM_OVERLAY, POSTCALL_ALTERNATIVES_OVERLAY, APP_REVIEW_OVERLAY or CALL_INTERCEPTOR_ONLINE_BOOKING. The Action will have the value CLICK. The Label transfers the information, which field has been clicked. The class AbstractCdSdkBroadcastReceiver provides (abstract) methods for all these (click) events. By implementing it, the hosting application can decide, how to react. Some of them are already implemented by the Clever Dialer SDK itself and therefore provide a suitable default solution. Others have to be implemented by the hosting app in order to provide a feasible reaction to the given event.

DANGER

The hosting application might want to parse the raw contact (contained in the SdkEvent), in order to extract certain properties to handle some of the following (click) events correctly. If so, the code has to be robust against changes in the partner API, as the raw contact depends on the version of the partner API which is used by the Clever Dialer Webservice and might change over time. As the declared Clever Dialer SDK default solutions do not need the raw contact, they can always be safely used as a fallback:

String rawContact = event.getRelevantRawContact();

try {
    // TODO Parse the given raw contact to proceed
} catch (Exception e) {
    // Could not parse the given raw contact
    // TODO Use the declared default solution
}

1.) Onboarding process click events

The following events can occur, if the hosting application uses the default onboarding process or the default SDK settings page. The hosting app has to make sure, that they are handled correctly.

1.1.) onUsageAccepted(Context context, SdkEvent event)

This method will be called, when the user accepts the usage of the Clever Dialer SDK by clicking the positive button in the activation overlay.

SdkEvent states:

Category Action Label
ACTIVATION_OVERLAY CLICK ACCEPT

Example implementation:

public class SampleCdSdkBroadcastReceiver extends AbstractCdSdkBroadcastReceiver {
    @Override
    protected void onUsageAccepted(Context context, SdkEvent event) {
        // TODO Activate all caller ID functionality if it has been deactivated
        //  upfront
    }  
}

TIP

This is the right place, to (re-)activate all caller ID functionality, if it has been deactivated upfront.

1.2.) onInfoLinkClicked(Context context, SdkEvent event)

This method will be called, when the user clicks on an (info)-link, inside of the (activation) overlays of the Clever Dialer SDK. The SdkEvent Label will transfer the information, which topic the user is interested in (according to the current step within the onboarding / activation process). As a reaction, the hosting app should provide detailed information.

SdkEvent states:

Category Action Label
DYNAMIC_INFORMATION_LINK CLICK ACTIVATION
DYNAMIC_INFORMATION_LINK CLICK SYSTEM_ALERT_WINDOW_PERMISSION
DYNAMIC_INFORMATION_LINK CLICK DEVICE_SETTINGS

Example implementation:

public class SampleCdSdkBroadcastReceiver extends AbstractCdSdkBroadcastReceiver {
    @Override
    protected void onInfoLinkClicked(Context context, SdkEvent event) {
        switch (event.getLabel()) {
            case ACTIVATION:
                // The user is about to activate the SDK.
                // Now he wants to get more information about the features.
                // TODO Open a page where the SDK-features are described
                break;
            case SYSTEM_ALERT_WINDOW_PERMISSION:
                // The user needs additional information to grant the
                // SYSTEM_ALERT_WINDOW-permission.
                // TODO E.g. show FAQs
                break;
            case DEVICE_SETTINGS:
                // The user is running a "huawei", "samsung" or "xiaomi"
                // device. On these devices, additional settings are
                // required in order to make the SDK work correctly.
                // TODO Show instructions for those settings
                break;
            default:
                super.onInfoLinkClicked(context, event);
                break;
        }
    }   
}

TIP

The SDK provides default webpages (powered by Clever Dialer) for all these cases which contain all the relevant information to enable the user to proceed without any hazzle. These webpages can easily be opened by calling super.onInfoLinkClicked(context, event) which will open the corresponding link in the browser app.

The hosting application can either implement its own logic or just rely on the default implementation to handle this event. If the hosting app does not override this method, the browser app will be opened to show a matching webpage (powered by Clever Dialer) for each of the cases to enable the user to find the relevant information he needs. The webpages are styled in the hosting applications corporate design and will show the partner logo in the top. The links to those webpages are shown in the following table.

Label Description & Link
ACTIVATION
The user is about to activate the SDK and wants to get more information about the features.
https://www.cleverdialer.app/client/demo/features
SYSTEM_ALERT_WINDOW_PERMISSION
The user needs additional information to grant the SYSTEM_ALERT_WINDOW-permission.
https://www.cleverdialer.app/client/demo/precall
DEVICE_SETTINGS
The user is running a "huawei", "samsung" or "xiaomi" device. On these devices, additional settings are required in order to make the SDK work correctly. He needs some instructions.
https://www.cleverdialer.app/client/demo/huawei

TIP

To open these webpages in the corresponding partner design (showing the partner logo on the top), the path segment "demo" has to be replaced with your <partnerId>.

2.) Settings page click events

If the hosting application uses the default settings page, it will receive an event, whenever the user clicks an element within the settings page. Most of them are for reporting purpose only. But at least one of them, has to be handled:

onTroubleshootingClicked(Context context, SdkEvent event)

The user is able to request help by clicking on the TROUBLESHOOTING element within the settings. The hosting app should handle this click by showing some instructions or give the user the chance to send an email to the support.

SdkEvent states:

Category Action Label
SETTINGS CLICK TROUBLESHOOTING

Example implementation:

public class SampleCdSdkBroadcastReceiver extends AbstractCdSdkBroadcastReceiver {
    @Override
    protected void onTroubleshootingClicked(Context context, SdkEvent event) {
        // TODO The user needs help. Let him send an email to the support or
        // show some instructions or FAQs in order to solve his problems.
    }
}

TIP

If the hosting app does not override this method, the Clever Dialer SDK will open the link https://www.cleverdialer.app/client/demo/troubleshooting in the browser app. The corresponding webpage is powered by Clever Dialer and will show the partner logo on the top.

3.) Overlay click events

Whenever the user clicks an element within the overlays of the Clever Dialer SDK, the event will be propagated to the hosting app and can be handled easily.

3.1.) onSettingsClicked(Context context, SdkEvent event)

When the user clicks the settings-button within one of the overlays, the SDKs settings screen needs to be opened within the hosting app.

SdkEvent states:

Category Action Label
POSTCALL_OVERLAY CLICK SETTINGS
POSTCALL_SPAM_OVERLAY CLICK SETTINGS
POSTCALL_ALTERNATIVES_OVERLAY CLICK SETTINGS

Example implementation:
If the hosting application uses the default settings page, which is included in the Clever Dialer SDK, this method could be implemented as simple as this:

public class SampleCdSdkBroadcastReceiver extends AbstractCdSdkBroadcastReceiver {
    @Override
    protected void onSettingsClicked(Context context, SdkEvent event) {
        CleverDialerSdk.openSettingsActivity(context, isCdSdkUsageAccepted);
    }    
}

3.2.) onBookingClicked(Context context, SdkEvent event)

If the hosting app supports online booking this method is called, when the user clicks on the booking link within an overlay. As a reaction to this event, the hosting application could for example open the browser app and start the corresponding online booking process. Furthermore, this method will be called, if the hosting app supports the call interceptor for online booking and the user chooses to book online by clicking the corresponding button contained in this screen.

SdkEvent states:

Category Action Label
POSTCALL_OVERLAY CLICK BOOKING_LINK
POSTCALL_ALTERNATIVES_OVERLAY CLICK BOOKING_LINK
CALL_INTERCEPTOR_ONLINE_BOOKING CLICK BOOKING_LINK

As The POSTCALL_SPAM_OVERLAY does not contain a booking link, the Category can only be POSTCALL_OVERLAY, POSTCALL_ALTERNATIVES_OVERLAY, or CALL_INTERCEPTOR_ONLINE_BOOKING.
If the Category is POSTCALL_OVERLAY, or CALL_INTERCEPTOR_ONLINE_BOOKING, a call to event.getRelevantRawContact() will retrieve the raw representation of the contact, which was shown in the overlay / screen.
If the Category is POSTCALL_ALTERNATIVES_OVERLAY, this could mean, that the user clicked on the booking link of the original contact entry in the top of the overlay, or the user has chosen one of the alternative suggestions. A call to event.getContactIndex() will clarify and event.getRelevantRawContact() will again retrieve the corresponding raw contact.

Example implementation:

public class SampleCdSdkBroadcastReceiver extends AbstractCdSdkBroadcastReceiver {
    @Override
    protected void onBookingClicked(Context context, SdkEvent event) {
        // A contact's booking link has been clicked. Get the associated contact,
        // which is transferred in `SdkEvent`, parse it and extract the relevant
        // data to proceed.

        // As both, the `POSTCALL_OVERLAY` and `POSTCALL_ALTERNATIVES_OVERLAY`
        // contain booking links, this method might have been called, because
        // the user clicked the booking link of an alternative suggestion.
        // If it is relevant for the hosting application, to know, in which type
        // of overlay this click occurred (for example for tracking purpose),
        // event.getCategory() will retrieve this information.

        // If the category is of type `POSTCALL_ALTERNATIVES_OVERLAY`,
        // `event.getContactIndex()` will point out, which contact has been
        // selected to start the online booking process.

        String rawContact = event.getRelevantRawContact();

        // TODO Parse the given rawContact, extract relevant data and start
        //  the booking process
    }
}

TIP

If the hosting application does not override this method, it can rely on the default implementation of the Clever Dialer SDK, which will open the booking link in the browser app.

3.3.) onRateClicked(Context context, SdkEvent event)

If the hosting app enabled the rate-feature for contacts, this method will be called, when the user clicks the rate-button within an overlay. As a reaction to this event, the hosting application should start its rating process for the given contact.

SdkEvent states:

Category Action Label
POSTCALL_OVERLAY CLICK RATE
POSTCALL_ALTERNATIVES_OVERLAY CLICK RATE

As the POSTCALL_SPAM_OVERLAY does not contain a rate-button, the Category can only be POSTCALL_OVERLAY or POSTCALL_ALTERNATIVES_OVERLAY.
If the Category is POSTCALL_OVERLAY, a call to event.getRelevantRawContact() will retrieve the raw representation of the contact, which was shown in the overlay.
If the Category is POSTCALL_ALTERNATIVES_OVERLAY, this could mean, that the user clicked on the rate-button of the original contact entry in the top of the overlay, or the user has chosen one of the alternative suggestions. A call to event.getContactIndex() will clarify and event.getRelevantRawContact() will again retrieve the corresponding raw contact.

Example implementation:

public class SampleCdSdkBroadcastReceiver extends AbstractCdSdkBroadcastReceiver {
    @Override
    protected void onRateClicked(Context context, SdkEvent event) {
        String rawContact = event.getRelevantRawContact();
        // TODO Parse the given rawContact, extract relevant data and start the
        //  rating process
    }
}

3.4.) onAddressClicked(Context context, SdkEvent event)

This method will be called, when the user clicks an address within an overlay. As a reaction to this event, the hosting application should e.g. show a map for the corresponding location.

SdkEvent states:

Category Action Label
POSTCALL_OVERLAY CLICK ADDRESS
POSTCALL_ALTERNATIVES_OVERLAY CLICK ADDRESS

The POSTCALL_SPAM_OVERLAY can contain the address field to show the origin (country and eventually city) of the phone number. However, the field is not clickable in this case. Therefore the Category of the click event can only be POSTCALL_OVERLAY or POSTCALL_ALTERNATIVES_OVERLAY.
If the Category is POSTCALL_OVERLAY, a call to event.getRelevantRawContact() will retrieve the raw representation of the contact, which was shown in the overlay.
If the Category is POSTCALL_ALTERNATIVES_OVERLAY, this could mean, that the user clicked on the address of the original contact entry in the top of the overlay, or the user has chosen one of the alternative suggestions. A call to event.getContactIndex() will clarify and event.getRelevantRawContact() will again retrieve the corresponding raw contact.

Example implementation:

public class SampleCdSdkBroadcastReceiver extends AbstractCdSdkBroadcastReceiver {
    @Override
    protected void onAddressClicked(Context context, SdkEvent event) {
        String rawContact = event.getRelevantRawContact();
        // TODO Parse the given rawContact, extract the address and e.g. show a
        //  map for the location
    }
}

TIP

Instead of overriding this method and implementing its own logic, the hosting application could just rely on the default solution provided by the Clever Dialer SDK, which will open maps for the given address.

3.5.) onWebsiteClicked(Context context, SdkEvent event)

This method will be called, when the user clicks the contacts website link within an overlay. As a reaction to this event, the hosting application should e.g. open the browser app for the given link.

SdkEvent states:

Category Action Label
POSTCALL_OVERLAY CLICK WEBSITE
POSTCALL_ALTERNATIVES_OVERLAY CLICK WEBSITE

As the POSTCALL_SPAM_OVERLAY does not contain a weblink, the Category can only be POSTCALL_OVERLAY or POSTCALL_ALTERNATIVES_OVERLAY.
If the Category is POSTCALL_OVERLAY, a call to event.getRelevantRawContact() will retrieve the raw representation of the contact, which was shown in the overlay.
If the Category is POSTCALL_ALTERNATIVES_OVERLAY, this could mean, that the user clicked on the website link of the original contact entry in the top of the overlay, or the user has chosen one of the alternative suggestions. A call to event.getContactIndex() will clarify and event.getRelevantRawContact() will again retrieve the corresponding raw contact.

Example implementation:

public class SampleCdSdkBroadcastReceiver extends AbstractCdSdkBroadcastReceiver {
    @Override
    protected void onWebsiteClicked(Context context, SdkEvent event) {
        String rawContact = event.getRelevantRawContact();
        // TODO Parse the given rawContact, extract the weblink and e.g. open
        //  browser app
    }
}

TIP

Instead of overriding this method and implementing its own logic, the hosting application could just rely on the default solution provided by the Clever Dialer SDK, which will open the browser app for the given link.

3.6.) onPhoneReceiverClicked(Context context, SdkEvent event)

This method will be called, when the user clicks on a phone number within an overlay or chooses to start a phone call within the call interceptor for online booking screen. As a reaction to this event, the hosting application should for example start a phone call or at least hand over the phone number to the default dialer app.

SdkEvent states:

Category Action Label
POSTCALL_OVERLAY CLICK NUMBER
POSTCALL_SPAM_OVERLAY CLICK NUMBER
POSTCALL_ALTERNATIVES_OVERLAY CLICK NUMBER
CALL_INTERCEPTOR_ONLINE_BOOKING CLICK CALL

As each type of overlay is triggered by a phone call, there is always an underlying phone number. Therefore the Category can be POSTCALL_OVERLAY, POSTCALL_SPAM_OVERLAY, POSTCALL_ALTERNATIVES_OVERLAY or CALL_INTERCEPTOR_ONLINE_BOOKING (if supported by the hosting app). However, the phone number, which triggered the overlay might differ from the phone number, which the user selected to call now (for example, when the user selected the phone number of an alternative suggestion).
To get access to the phone number, which the user wants to call, the hosting application can safely call event.getRelevantPhoneNumber().
If the hosting application wants to know, which contact this phone number belongs to, it has to take the Category into account: If the Category is POSTCALL_SPAM_OVERLAY, there is no contact. Therefore the method event.getRelevantRawContact() will return null.
If the Category is POSTCALL_OVERLAY or CALL_INTERCEPTOR_ONLINE_BOOKING, the method event.getRelevantRawContact() will return the corresponding contact, as this type of overlay / screen only contains one contact.
If the Category is POSTCALL_ALTERNATIVES_OVERLAY, a call to event.getContactIndex() will clarify which contact the phone number belongs to and event.getRelevantRawContact() will again retrieve the corresponding raw contact.

Example implementation:

public class SampleCdSdkBroadcastReceiver extends AbstractCdSdkBroadcastReceiver {
    @Override
    protected void onPhoneReceiverClicked(Context context, SdkEvent event) {
        String phoneNumber = event.getRelevantPhoneNumber();
        // TODO Start a phone call or open the default dialer app for the given
        //  phone number
    }
}

TIP

Instead of overriding this method and implementing its own logic, the hosting application could just rely on the default solution provided by the Clever Dialer SDK, which will open the default dialer app for the given phone number or show the call interceptor for online booking screen, (if relevant and supported by the partner app).

3.7.) onProfileClicked(Context context, SdkEvent event)

This method will be called, when the user clicks the profile-button in one of the overlays. As a reaction to this event, the hosting application should open the profile page of the current contact entry.

SdkEvent states:

Category Action Label
POSTCALL_OVERLAY CLICK PROFILE
POSTCALL_ALTERNATIVES_OVERLAY CLICK PROFILE

As the POSTCALL_SPAM_OVERLAY does not contain a profile-button, the Category can only be POSTCALL_OVERLAY or POSTCALL_ALTERNATIVES_OVERLAY.
If the Category is POSTCALL_OVERLAY, a call to event.getRelevantRawContact() will retrieve the raw representation of the contact, which was shown in the overlay.
If the Category is POSTCALL_ALTERNATIVES_OVERLAY, this could mean, that the user clicked on the profile-button of the original contact entry in the top of the overlay, or the user has chosen one of the alternative suggestions. A call to event.getContactIndex() will clarify and event.getRelevantRawContact() will again retrieve the corresponding raw contact.

Example implementation:

public class SampleCdSdkBroadcastReceiver extends AbstractCdSdkBroadcastReceiver {
    @Override
    protected void onProfileClicked(Context context, SdkEvent event) {
        String rawContact = event.getRelevantRawContact();
        // TODO Open the profile page of the given contact
    }
}

3.8.) onSaveClicked(Context context, SdkEvent event)

This method will be called, when the user clicks the save-button in one of the overlays. As a reaction to this event, the hosting application should store the given contact to the address book or at least open the contacts app and pre-fill the available address book entry fields with the given contact data.

SdkEvent states:

Category Action Label
POSTCALL_OVERLAY CLICK SAVE
POSTCALL_SPAM_OVERLAY CLICK SAVE
POSTCALL_ALTERNATIVES_OVERLAY CLICK SAVE

As each type of overlay, which is shown after a phone call, does contain a save-button, the Category can be POSTCALL_OVERLAY, POSTCALL_ALTERNATIVES_OVERLAY or POSTCALL_SPAM_OVERLAY.
If the Category is POSTCALL_SPAM_OVERLAY, there is no contact. Therefore the method event.getRelevantRawContact() will return null. Use event.getPhoneNumber() in this case, to get access to at least the phone number, which triggered this overlay.
If the Category is POSTCALL_OVERLAY, the method event.getRelevantRawContact() will return the corresponding contact.
If the Category is POSTCALL_ALTERNATIVES_OVERLAY, this could mean, that the user clicked on the save-button of the original contact entry in the top of the overlay, or the user has chosen one of the alternative suggestions. A call to event.getContactIndex() will clarify and event.getRelevantRawContact() will again retrieve the corresponding raw contact.

Example implementation:

public class SampleCdSdkBroadcastReceiver extends AbstractCdSdkBroadcastReceiver {
    @Override
    protected void onSaveClicked(Context context, SdkEvent event) {
        String rawContact = event.getRelevantRawContact();
        
        if (StringUtils.isNotBlank(rawContact)) {
            // TODO Save the available contact details to the users address book
        } else {
            String phoneNumber = event.getRelevantPhoneNumber();
            // TODO As no rawContact is available, save at least the phone number
        }
    }
}

TIP

Instead of overriding this method and implementing its own logic, the hosting application could just rely on the default solution provided by the Clever Dialer SDK, which will open the default contacts app to insert or edit a contact. Depending on the available contact information, the corresponding fields will be pre-filled.

3.9.) onMoreAlternativesClicked(Context context, SdkEvent event)

This method will be called, when the user clicks the more-button at the end of the alternative suggestions list. As none of the other overlays contains this button, the Category always is POSTCALL_ALTERNATIVES_OVERLAY. The hosting app has to implement its own logic to handle this click event and could for example open its own nearby search screen for the given contact category (event.getRelevantRawContact() will retrieve the corresponding raw contact of the original contact entry which was shown in the top of the overlay).

Example implementation:

public class SampleCdSdkBroadcastReceiver extends AbstractCdSdkBroadcastReceiver {
    @Override
    protected void onMoreAlternativesClicked(Context context, SdkEvent event) {
        String rawContact = event.getRelevantRawContact();
        // TODO Open the hosting application and start a nearby search for the
        //  given contact / business category
    }
}

3.10.) onShareClicked(Context context, SdkEvent event)

This method will be called, when the user clicks the share-button in one of the overlays. As a reaction to this event, the hosting application should enable the user to forward the given (contact) details.

SdkEvent states:

Category Action Label
POSTCALL_OVERLAY CLICK SHARE
POSTCALL_SPAM_OVERLAY CLICK SHARE
POSTCALL_ALTERNATIVES_OVERLAY CLICK SHARE

As each type of overlay, which is shown after a phone call, can contain a share-button, the Category can be POSTCALL_OVERLAY, POSTCALL_ALTERNATIVES_OVERLAY or POSTCALL_SPAM_OVERLAY.
If the Category is POSTCALL_SPAM_OVERLAY, there is no contact. Therefore the method event.getRelevantRawContact() will return null. Use event.getPhoneNumber() in this case, to get access to at least the phone number, which triggered this overlay.
If the Category is POSTCALL_OVERLAY, the method event.getRelevantRawContact() will return the corresponding contact.
If the Category is POSTCALL_ALTERNATIVES_OVERLAY, this could mean, that the user clicked on the share-button of the original contact entry in the top of the overlay, or the user has chosen one of the alternative suggestions. A call to event.getContactIndex() will clarify and event.getRelevantRawContact() will again retrieve the corresponding raw contact.

Example implementation:

public class SampleCdSdkBroadcastReceiver extends AbstractCdSdkBroadcastReceiver {
    @Override
    protected void onShareClicked(Context context, SdkEvent event) {
        if (POSTCALL_SPAM_OVERLAY.equals(event.getCategory())) {
            String phoneNumber = event.getPhoneNumber();
          // TODO Share a spam-warning for the given number
        } else {
            String rawContact = event.getRelevantRawContact();
          // TODO Use the given rawContact to share the desired details
        }
    }
}

TIP

Instead of overriding this method and implementing its own logic, the hosting application could just rely on the default solution provided by the Clever Dialer SDK, which will open the native share dialog and enable the user to forward a predefined text message (including the directory profile link and brand name or in case of a spam-warning the link to the corresponding Clever Dialer detail page).

4.) App review click events

If the hosting application uses the app-review feature of the Clever Dialer SDK, it will be notified whenever the user clicks on a button inside of the associated overlays.

TIP

A complete implementation example of the following two methods can be found here.

4.1.) onAppReviewClicked(Context context, SdkEvent event)

As described here, the user will be able to click the REVIEW-button, when he already decided, that the hosting application is GOOD. This is the right time, to enable him, to leave an app review on Google Play Store / HUAWEI AppGallery.

SdkEvent states:

Category Action Label
APP_REVIEW_OVERLAY CLICK REVIEW

Example implementation:

public class SampleCdSdkBroadcastReceiver extends AbstractCdSdkBroadcastReceiver {
    @Override
    protected void onAppReviewClicked(Context context, SdkEvent event) {
        // TODO The user wants to create an app review. Open up the store page
        //  (Google Play Store / HUAWEI AppGallery).
    }
}

4.2.) onFeedbackClicked(Context context, SdkEvent event)

As described here, the user will be able to click the FEEDBACK-button, when he already decided, that the hosting application is BAD. In order to prevent him, to write a bad app review on Google Play Store, the user gets the possibility, to send his feedback to the support team.

SdkEvent states:

Category Action Label
APP_REVIEW_OVERLAY CLICK FEEDBACK

Example implementation:

public class SampleCdSdkBroadcastReceiver extends AbstractCdSdkBroadcastReceiver {
    @Override
    protected void onFeedbackClicked(Context context, SdkEvent event) {
        // TODO The user wants to send feedback to the support team.
    }
}

5.) onAppRecommendationClicked(Context context, SdkEvent event)

As described here, the Clever Dialer SDK provides an overlay to ask the user to recommend / share the hosting app. A click on the positive button (label SHARE) will (per default) show the native share dialog to enable the user to easily share a predefined text message which includes the link to the hosting applications Play Store page. The hosting app is able to react on this event and override the named action.

SdkEvent states:

Category Action Label
APP_RECOMMENDATION_OVERLAY CLICK SHARE

Example implementation:

public class SampleCdSdkBroadcastReceiver extends AbstractCdSdkBroadcastReceiver {
    @Override
    protected void onAppRecommendationClicked(Context context, SdkEvent event) {
      // TODO The user wants to recommend / share the hosting application.
    }
}

TIP

Instead of overriding this method and implementing its own logic, the hosting application could just rely on the default solution provided by the Clever Dialer SDK, which will open the native share dialog to enable the user to easily forward a predefined text message which includes the link to the hosting applications Play Store page.

Optional events

In addition to the mandatory events, there are optional events, which are mainly used for reporting purpose only. The hosting application can ignore these events totally. However, if the hosting app is interested in these events, too, it can override onOptionalEvent(Context context, SdkEvent event) in its implementation of AbstractCdSdkBroadcastReceiver. To get insights in the event, the hosting application can evaluate Category, Action and Label. Depending on the event, additional values will be set, as described in the section event model.

Example implementation:

public class SampleCdSdkBroadcastReceiver extends AbstractCdSdkBroadcastReceiver {
    @Override
    protected void onOptionalEvent(Context context, SdkEvent event) {
        // TODO Evaluate event.getCategory(), event.getAction() and event.getLabel()
        //  to get insights in the given event
    }
}

In the following section, the possible optional events are listed.

Overlay impressions

Whenever an overlay is shown, the Clever Dialer SDK sends an event, to inform the hosting app. The Category describes the overlay, which was shown. When it was shown on start of the phone call, the Category can be of type PRECALL_OVERLAY or PRECALL_SPAM_OVERLAY. After the phone call, the overlay is of type POSTCALL_OVERLAY, POSTCALL_SPAM_OVERLAY or POSTCALL_ALTERNATIVES_OVERLAY. The Action will transfer information about the call type. At start of the phone call, it can be of type INCOMING_CALL or OUTGOING_CALL. When the phone call is finished, it can be of type MISSED_CALL, too. A MISSED_CALL is an INCOMING_CALL, which was not answered by the user. The Label can be <partnerId> in capital letters or SPAM, depending on the data, which was shown in the overlay.

Category Action Label
PRECALL_OVERLAY INCOMING_CALL
OUTGOING_CALL
<partnerId>
PRECALL_SPAM_OVERLAY INCOMING_CALL
OUTGOING_CALL
SPAM
POSTCALL_OVERLAY INCOMING_CALL
OUTGOING_CALL
MISSED_CALL
<partnerId>
POSTCALL_SPAM_OVERLAY INCOMING_CALL
OUTGOING_CALL
MISSED_CALL
SPAM
POSTCALL_ALTERNATIVES_OVERLAY INCOMING_CALL
OUTGOING_CALL
MISSED_CALL
<partnerId>

First overlay impression

Whenever the Clever Dialer SDK shows an overlay of type POSTCALL_OVERLAY, POSTCALL_SPAM_OVERLAY or POSTCALL_ALTERNATIVES_OVERLAY for the first time, it will additionally show a hint to the user, to describe the overlay and its purpose. The hosting app will be notified about this hint impression.

Category Action Label
POSTCALL_OVERLAY
POSTCALL_SPAM_OVERLAY
POSTCALL_ALTERNATIVES_OVERLAY
SHOW_HINT null

Online booking call interceptor impression

Whenever a call interceptor for online booking is shown, the Clever Dialer SDK sends an event, to inform the hosting app about this screen impression.

Category Action Label
CALL_INTERCEPTOR_ONLINE_BOOKING OPENED null

Notification events

Whenever the Clever Dialer SDK finds details for a phone number, it will send a notification to the user, when the phone call is ended and an overlay is shown. The user can deactivate these notifications in the default settings page. When a notification is clicked, the associated overlay will be opened.

Category Action Label
NOTIFICATION SENT <partnerId>
SPAM
ALTERNATIVES
NOTIFICATION OPENED <partnerId>
SPAM
ALTERNATIVES

Furthermore, if the hosting app uses the default onboarding process, the Clever Dialer SDK will periodically send a notification to the user in order to remind him to fulfill the required onboarding steps. Delivery and clicks are reported as shown below:

Category Action Label
NOTIFICATION SENT ACTIVATION
NOTIFICATION OPENED ACTIVATION

Handled click events

There are some click events, which are handled by the Clever Dialer SDK automatically. However, the hosting application will be notified as well.

Category Action Label
ACTIVATION_OVERLAY CLICK POSTPONE

This event will be fired, when the user postponed the onboarding process by clicking the negative button in the corresponding ACTIVATION_OVERLAY. The user will be re-asked again in the defined frequency.

Category Action Label
POSTCALL_OVERLAY CLICK ALTERNATIVES

By clicking the SHOW_ALTERNATIVE-button in a POSTCALL_OVERLAY, the user is able to open the POSTCALL_ALTERNATIVES_OVERLAY.

Category Action Label
POSTCALL_SPAM_OVERLAY CLICK PROFILE

When the user clicks the more details-button in the POSTCALL_SPAM_OVERLAY, the Clever Dialer website will be opened to show more details about the given spam phone number.

Category Action Label
APP_REVIEW_OVERLAY OPENED
APP_REVIEW_OVERLAY CLICK GOOD
BAD
POSTPONE

If the hosting application uses the app-review feature of the Clever Dialer SDK, it will be notified whenever the associated overlay is shown (OPENED) or the user clicks on a button inside it. There are three click-events, which are for reporting purpose only. The hosting app can observe, but it does not need to handle them.

Category Action Label
APP_RECOMMENDATION_OVERLAY OPENED
APP_RECOMMENDATION_OVERLAY CLICK POSTPONE

If the hosting application uses the app-recommendation feature of the Clever Dialer SDK, it will be notified whenever the associated overlay is shown (OPENED) or the user clicks on a button inside it. The click on the negative button (POSTPONE) closes the overlay and is propagated for reporting purpose only.

Expected obstacles

In some circumstances, the Clever Dialer SDK is not able to show any overlays. Basically, if the caller suppressed his phone number, the users phone was not connected to the internet and no cached data was available or the SDK did not find any data about the phone number, the hosting app will be notified about it. If the user decided, that he does not want to see an overlay, when a phone number is stored in his address book, the SDK sends an event with the Label LOCAL_KNOWN, when a phone call to or from such a contact takes place.

Category Action Label
PRECALL_OVERLAY INCOMING_CALL SUPPRESSED_NUM
PRECALL_OVERLAY INCOMING_CALL
OUTGOING_CALL
NO_CONNECTION
PRECALL_OVERLAY INCOMING_CALL
OUTGOING_CALL
NO_DETAILS
PRECALL_OVERLAY INCOMING_CALL
OUTGOING_CALL
LOCAL_KNOWN
POSTCALL_OVERLAY INCOMING_CALL
OUTGOING_CALL
MISSED_CALL
NO_CONNECTION
POSTCALL_OVERLAY INCOMING_CALL
OUTGOING_CALL
MISSED_CALL
NO_DETAILS
POSTCALL_OVERLAY INCOMING_CALL
OUTGOING_CALL
MISSED_CALL
LOCAL_KNOWN

Settings page events

If the hosting application uses the default settings page of the Clever Dialer SDK, it will be notified whenever the user clicks an element inside the settings page.

Category Action Label
SETTINGS ACTIVATED
DEACTIVATED
UPDATE
SPAM_PROTECTION
SETTINGS ACTIVATED
DEACTIVATED
CALLER_ID
SETTINGS ACTIVATED
DEACTIVATED
ALTERNATIVES
SETTINGS ACTIVATED
DEACTIVATED
CALL_INTERCEPTOR_ONLINE_BOOKING
SETTINGS ACTIVATED
DEACTIVATED
ADDRESS_BOOK_ACCESS
SETTINGS ACTIVATED
DEACTIVATED
NOTIFICATIONS

Collect app reviews

The Clever Dialer SDK can help the hosting application to collect app reviews and boost the reputation in the store listing. Therefore, the Clever Dialer SDK contains a set of overlays, which can be triggered by the hosting app at any time, to ask the user to rate / review the app.

To trigger the overlay which asks the user to review the app, the hosting application just has to call the static method CleverDialerSdk.showAppReviewOverlay(Context context) and pass a context of type Activity. The SDK will show the desired overlay immediately.

CleverDialerSdk.showAppReviewOverlay(context);

Via the app menu

A very common way is to let the user decide for himself if and when he wants to create an app review. Therefore the hosting application could for example add a "review"-MenuItem to its NavigationView and call the described method, when the user clicks on it:

public class MainActivity extends Activity implements OnNavigationItemSelectedListener {
    // ...
    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        if (item.getItemId() == R.id.review) {
            CleverDialerSdk.showAppReviewOverlay(this);
        }
        // ...
        return true;
    }
}

On app start

Allowing the user to rate the app via the app menu is a first step. However, a much more effective way would be, to ask the user directly, whenever certain criterias are met. To achieve this, the hosting application could take several values into account and declare a rule to define, when and which users should be asked to review the app. For example, the hosting app could store the date, when the user launched the app for the first time and increase a counter, whenever he launches the app. And necessarily it should remember, if the user already rated / reviewed the app. Based on these values, the application could easily decide, if the user should be asked for an app review, whenever he opens the app:

public class MainActivity extends Activity implements OnNavigationItemSelectedListener {
    @Override
    protected void onResume() {
        super.onResume();

        if (!CleverDialerSdk.getStatus(this).isOnboarding()
            && isTimeToAskForAppReview(this)) {
            askForAppReview(this);
        }
    }

    public static boolean isTimeToAskForAppReview(Context context) {
        SharedPreferences prefs = getDefaultSharedPreferences(context);

        if (!prefs.contains(PREF_KEY_APP_REVIEWED)) {
            // The user did not review the app yet.
            if (prefs.getInt(PREF_KEY_LAUNCH_COUNT, 0) >= 10) {
                // He opened the app at least 10 times.
                long firstLaunch = prefs.getLong(PREF_KEY_FIRST_LAUNCH, 0);
                // If he uses the app since at least 14 days, we can ask for a review.
                if (now().isAfter(new DateTime(firstLaunch).plusDays(14))) {
                    // We must not overdo it. Means: When we asked the user to review
                    // the app, we should wait another 14 days, before we ask him again.
                    long lastReq = prefs.getLong(PREF_KEY_LAST_APP_REVIEW_REQUEST, 0);
                    return now().isAfter(new DateTime(lastReq).plusDays(14));
                }
            }
        }

        return false;
    }

    public static void askForAppReview(Context context) {
        // In order to make sure, that we do not ask this user again, until the
        // defined time span has passed, we have to store the current date.
        getDefaultSharedPreferences(context)
                .edit().putLong(PREF_KEY_LAST_APP_REVIEW_REQUEST, now().getMillis())
                .commit();

        CleverDialerSdk.showAppReviewOverlay(context);
    }
}

TIP

As shown in the code above, the hosting application defined some hard coded values, which are used to decide, if a user should be asked for an app review, or not. It is best practice, to make these values configurable e.g. via Firebase Remote Config. This way, the rule could easily be changed on the fly in order to find out the values, which work best to collect as many good app ratings, as possible.

After a spam warning

Asking loyal users on app start to rate the app is great. However, the most powerful and effective way to collect a bunch of positive app reviews is, to ask these users after they had a positive user experience. And according to experience, being warned against a known spam caller, is such a very strong, positive event. Users, who had just been warned against a spam call, are certainly willing to give a good 5-star app rating. If the hosting application wants to ask a user, after he has been warned against a spam call, it just has to override the method onOptionalEvent(Context context, SdkEvent event) of the class AbstractCdSdkBroadcastReceiver.java (which is described here). By evaluating the reported SdkEvent, the hosting application could react and tell the SDK, to ask for an app review, after the spam-warning is closed by the user.

public class SampleCdSdkBroadcastReceiver extends AbstractCdSdkBroadcastReceiver {
    @Override
    protected void onOptionalEvent(Context context, SdkEvent event) {
        if (POSTCALL_SPAM_OVERLAY.equals(event.getCategory())
            && MISSED_CALL.equals(event.getAction())
            && MainActivity.isTimeToAskForAppReview(context)) {
            // The user just has been warned against a spam call and did not answer
            // it (MISSED_CALL). He had a good user experience and is certainly
            // willing to leave a good app review.

            // Save the date and call CleverDialerSdk.showAppReviewOverlay(context)
            // to tell the SDK that it should ask for an app review, when the user
            // closes the overlay.
            MainActivity.askForAppReview(context);
        }
    }
}

TIP

Beside Firebase Remote Config, the hosting application should consider to use Firebase A/B Testing. This way, it could easily find out, if users, who already have had for example two or three spam warnings, are more willing to give a good rating, than users, who only had been warned once.

Event handling

Now that the hosting application created three entry points for the Clever Dialer SDK to ask for app reviews, it has to handle the possible click events, which can occur within the involved overlays. As described here, the first overlay will ask the user for a general choice between GOOD and BAD. The clicks on the corresponding buttons will be reported as optional events. Much more important are the events, when the user is in the second step, where he is able to click the FEEDBACK or REVIEW button. These clicks have to be handled by the hosting application. The SDK provides appropriate methods in SdkEventHandler.java for both of them:

public class SampleCdSdkBroadcastReceiver extends AbstractCdSdkBroadcastReceiver {
    @Override
    protected void onFeedbackClicked(Context context, SdkEvent event) {
        deactivateAppReviewOverlay(context);
        // Open the e-mail client to enable the user to send feedback to the
        // suppport team.
        SdkEventHandler.openMailClient(context, recipient, subject, message);
    }

    @Override
    protected void onAppReviewClicked(Context context, SdkEvent event) {
        deactivateAppReviewOverlay(context);
        // CAUTION: The SdkEventHandler currently does only support
        // `Google Play Store`. However, if the partner app is listed in
        // `AppGallery`, too, the app has to care about sending the user to
        // the right store.
        SdkEventHandler.openPlayStorePage(context);
    }

    private void deactivateAppReviewOverlay(Context context) {
        // The user has clicked the FEEDBACK or REVIEW button, this means,
        // that he made his decision. It is really important to prevent asking
        // him again. Therefore the hosting application could save a value to
        // its SharedPreferences and take it into account, when it has to
        // decide if it wants to ask for app review, the next time.
        getDefaultSharedPreferences(context)
                .edit().putBoolean(MainActivity.PREF_KEY_APP_REVIEWED, true)
                .commit();
    }
}

TIP

More information about the Clever Dialer SDK event system can be found in events.

Ask for recommendation

The Clever Dialer SDK can help the hosting application to grow organically by asking the user for recommendation. For this, it contains an overlay, which can be triggered by the hosting app at any time, to ask the user to take action.

To trigger the overlay which asks the user to recommend the app, the hosting application just has to call the static method CleverDialerSdk.showAppRecommendationOverlay(Context context) and pass a context.

CleverDialerSdk.showAppRecommendationOverlay(context);

As the user is most likely to recommend the hosting application right after he had a positive experience, it would be a good chance to ask him, when he has been warned against spam. To do so, the hosting app just has to override the method onOptionalEvent(Context context, SdkEvent event) of the class AbstractCdSdkBroadcastReceiver.java (which is described here). By evaluating the reported SdkEvent, the hosting application could react on the spam-warning event and tell the SDK, to ask for an app recommendation, after the spam-warning is closed by the user.

public class SampleCdSdkBroadcastReceiver extends AbstractCdSdkBroadcastReceiver { 
    @Override 
    protected void onOptionalEvent(Context context, SdkEvent event) {
        if (POSTCALL_SPAM_OVERLAY.equals(event.getCategory())
            && MISSED_CALL.equals(event.getAction())) {
            CleverDialerSdk.showAppRecommendationOverlay(context);
        }
    }
}

Clicks on the buttons contained in this overlay are reported to the hosting application and by default handled by the Clever Dialer SDK. By default, a click on the positive (SHARE) button will open the native share dialog to enable the user to easily forward a predefined text message which includes the link to the hosting applications Play Store page. However, the hosting app is able to change this behavior by overriding the associated callback.

public class SampleCdSdkBroadcastReceiver extends AbstractCdSdkBroadcastReceiver {
    @Override
    protected void onAppRecommendationClicked(Context context, SdkEvent event) {
      // TODO The user wants to recommend / share the hosting application.
      // (By default, `SdkEventHandler.shareAppRecommendation(context)` gets called)
    }
}

TIP

Instead of overriding this method, the hosting application is also able to reuse the underlying functionality to provide a consistent user experience throughout the whole application. For this it could just call the static method SdkEventHandler.shareAppRecommendation(Context context) in each place, where it wants to provide a standardized functionality of sharing a predefined app recommendation text message. This method is internally called in the Clever Dialer SDK default implementation of onAppRecommendationClicked(Context context, SdkEvent event), too.

To enable the user to share an app recommendation at any time, the hosting application could for example add an associated MenuItem to its NavigationView. Since the user already expresses his interest by clicking on the item, it is not necessary to show the overlay in this case. However, the Clever Dialer SDK standardized functionality of sharing a predefined app recommendation text message (including the link to the hosting applications Play Store page) could be provided by calling SdkEventHandler.shareAppRecommendation(Context context) as easy as this:

public class MainActivity extends Activity implements OnNavigationItemSelectedListener {
    // ...
    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        if (item.getItemId() == R.id.recommend) {
            SdkEventHandler.shareAppRecommendation(this);
        }
        // ...
        return true;
    }
}

Testing

The integration of the Clever Dialer SDK can be tested by using the class CdSdkTestingActivity.java. This Activity provides an UI, which enables the tester to easily open Pre- and Post-Call Overlays. A set of mocked contacts is included, too.

To use this test interface, the Activity CdSdkTestingActivity.java has to be added to the AndroidManifest.xml of the hosting application:

<activity android:name="de.validio.cdand.sdk.controller.activity.CdSdkTestingActivity" />

Now, the hosting application can decide, when to open / show this screen. The Activity can be started by simply calling the static method:

CleverDialerSdk.openTestingActivity(Context context);

TIP

For example, the hosting application could add this screen only in a debug version of the app. Alternatively, it could open up this screen, when some secret user-input was detected (e.g. the settings page has been opened 7 times within 10 sec).

Full working example

top-level build.gradle

allprojects {
    repositories {
        maven {
            credentials {
                username "$mavenUser"
                password "$mavenPassword"
            }
            url "https://nexus.validio.de/content/repositories/partner-releases/"
        }
    }
}

module-level build.gradle

dependencies {
    // ...

    implementation('de.validio.cdand:cdand-sdk:1.12.1:<classifier>@aar') {
        transitive = true
    }

    implementation "joda-time:joda-time:2.12.5"
    implementation "org.apache.commons:commons-lang3:3.12.0"

    configurations.implementation {
      exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk8'
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="de.validio.cdand.sdk.demo">

    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
  
    <uses-permission android:name="de.validio.cdand.sdk.SDK_EVENT_PERMISSION_<classifier>" />

    <application
        android:name=".App"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:exported="true"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity android:name="de.validio.cdand.sdk.controller.activity.CdSdkTestingActivity" />

        <activity android:name="de.validio.cdand.sdk.controller.activity.CdSdkSettingsActivity" />

        <receiver
            android:name=".CdSdkBroadcastReceiver"
            android:exported="false">
            <intent-filter>
                <action android:name="de.validio.cdand.sdk.SDK_EVENT" />
            </intent-filter>
        </receiver>
    </application>
</manifest>

src\main\res\values\config.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="cd_sdk_partner_id" translatable="false">your_partner_id</string>
    <string name="cd_sdk_secret" translatable="false">your_api_secret</string>

    <!-- Declare the default enabled state for the (supported) core features.
    Can be changed by the user at runtime within the default settings page. -->
    <bool name="cd_sdk_default_enable_spam_protection">true</bool>
    <bool name="cd_sdk_default_enable_caller_id">true</bool>
    <bool name="cd_sdk_default_enable_alternative_suggestions">true</bool>
    <bool name="cd_sdk_default_enable_address_book_access">false</bool>
    <bool name="cd_sdk_default_enable_notifications">true</bool>
    <bool name="cd_sdk_default_enable_online_booking_call_interceptor">true</bool>
</resources>

App.java

public class App extends MultiDexApplication {
    @Override
    public void onCreate() {
        super.onCreate();

        // Tell the Clever Dialer SDK, which features should be supported
        // and available for the user within the hosting app.
        configureCdSdk();
    }

    private void configureCdSdk() {
        // The `POSTCALL_ALTERNATIVES_OVERLAY` should include a more-button at
        // the end of the alternative suggestions list and must not be limited
        // to unsuccessful outgoing calls:
        Config.Alternatives.Params params = new Config.Alternatives.Params();
        params.includeMoreButton(true);
        params.restrictToUnsuccessfulCalls(false);

        Config config = new Config.Builder()
                .supportCallerId(true)
                .supportSpamProtection(true)
                .supportAlternativeSuggestions(true, params)
                .supportAddressBookAccess(true)
                .supportNotifications(true)
                .supportBookingLinks(true)
                .supportProfileButton(true)
                .supportRateButton(true)
                .supportOnlineBookingCallInterceptor(true)
                .supportProfileSharing(true)
                .writeLogs(BuildConfig.DEBUG)
                .build();

        CleverDialerSdk.configure(this, config);
    }
}

MainActivity.java

public class MainActivity extends Activity
        implements NavigationView.OnNavigationItemSelectedListener {
    private DrawerLayout mDrawerLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mDrawerLayout = findViewById(R.id.drawer_layout);
        NavigationView navigationView = findViewById(R.id.nav_view);
        navigationView.setNavigationItemSelectedListener(this);

        navigationView.getMenu().findItem(R.id.testing)
                      .setVisible("debug".equals(BuildConfig.BUILD_TYPE));
    }

    @Override
    protected void onStart() {
        super.onStart();

        AppReviewHelper.appLaunched(this);

        CleverDialerSdk.enableOnboardingProcess(this, isCdSdkUsageAccepted());
    }

    @Override
    protected void onResume() {
        super.onResume();

        if (!CleverDialerSdk.getStatus(this).isOnboarding()
            && AppReviewHelper.isTimeToAskForAppReview(this)) {
            AppReviewHelper.askForAppReview(this);
        }
    }

    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        if (item.getItemId() == R.id.settings) {
            CleverDialerSdk.openSettingsActivity(this, isCdSdkUsageAccepted());
        } else if (item.getItemId() == R.id.testing) {
            CleverDialerSdk.openTestingActivity(this);
        } else if (item.getItemId() == R.id.recommend) {
            CleverDialerSdk.showAppRecommendationOverlay(this);
        } else if (item.getItemId() == R.id.review) {
            AppReviewHelper.askForAppReview(this);
        }

        mDrawerLayout.closeDrawers();
        return true;
    }

    private boolean isCdSdkUsageAccepted() {
        SharedPreferences preferences = getDefaultSharedPreferences(this);
        // If the hosting application did or does not use the default onboarding
        // process until now, it has to care about a flag / SharedPreference, which
        // indicates that the user accepted the usage of the Clever Dialer SDK.
        // It is important to pass this value as param isCdSdkUsageAccepted when
        // enableOnboardingProcess() is called. Otherwise users, who already accepted
        // the usage of the SDK, would be asked again.
        return preferences.getBoolean(PREF_KEY_CD_SDK_USAGE_ACCEPTED, false);
    }
}

AppReviewHelper.java

public class AppReviewHelper {
    private static final String PREF_KEY_FIRST_LAUNCH = "firstLaunch";
    private static final String PREF_KEY_LAUNCH_COUNT = "launchCount";
    private static final String PREF_KEY_APP_REVIEWED = "appReviewed";
    private static final String PREF_KEY_LAST_APP_REVIEW_REQUEST = "lastAppReview";

    public static void appLaunched(Context context) {
        SharedPreferences prefs = getDefaultSharedPreferences(context);

        if (!prefs.contains(PREF_KEY_FIRST_LAUNCH)) {
            prefs.edit().putLong(PREF_KEY_FIRST_LAUNCH, now().getMillis()).commit();
        }

        int launchCount = prefs.getInt(PREF_KEY_LAUNCH_COUNT, 0) + 1;
        prefs.edit().putInt(PREF_KEY_LAUNCH_COUNT, launchCount).commit();
    }

    public static boolean isTimeToAskForAppReview(Context context) {
        SharedPreferences prefs = getDefaultSharedPreferences(context);

        if (!prefs.contains(PREF_KEY_APP_REVIEWED)) {
            // The user did not review the app yet.
            if (prefs.getInt(PREF_KEY_LAUNCH_COUNT, 0) >= 10) {
                // He opened the app at least 10 times.
                long firstLaunch = prefs.getLong(PREF_KEY_FIRST_LAUNCH, 0);
                // If he uses the app since at least 14 days, we can ask him
                // for a review.
                if (now().isAfter(new DateTime(firstLaunch).plusDays(14))) {
                    // We must not overdo it. Means: When we asked the user to review
                    // the app, we should wait another 14 days, before we ask him again.
                    long lastReq = prefs.getLong(PREF_KEY_LAST_APP_REVIEW_REQUEST, 0);
                    return now().isAfter(new DateTime(lastReq).plusDays(14));
                }
            }
        }

        return false;
    }

    public static void askForAppReview(Context context) {
        // In order to make sure, that we do not ask this user again, until
        // the defined time span has passed, we have to store the current date.
        getDefaultSharedPreferences(context)
                .edit().putLong(PREF_KEY_LAST_APP_REVIEW_REQUEST, now().getMillis())
                .commit();

        CleverDialerSdk.showAppReviewOverlay(context);
    }

    public static void deactivateAppReview(Context context) {
        // It is really important to remember, that the user already made
        // his decision, in order to prevent asking him again.
        getDefaultSharedPreferences(context)
                .edit().putBoolean(PREF_KEY_APP_REVIEWED, true).commit();
    }
}

CdSdkBroadcastReceiver.java

public class CdSdkBroadcastReceiver extends AbstractCdSdkBroadcastReceiver {
    @Override
    protected void onUsageAccepted(Context context, SdkEvent sdkEvent) {
        // The user accepted the usage of the Clever Dialer SDK by clicking
        // the positive button in the activation overlay. As long as the
        // hosting application does not have to setup anything special, there
        // is nothing to do here.
    }

    @Override
    protected void onProfileClicked(Context context, SdkEvent sdkEvent) {
        // The user clicked the profile button in an overlay. He wants to
        // open the profile page for the given contact.
        try {
            String rawContact = sdkEvent.getRelevantRawContact();
            // TODO Parse the given raw contact to proceed
        } catch (Exception e) {
            // Could not parse the given raw contact.
            // There is no default implementation for this event. The hosting
            // app should be able to deal with it or mark this feature as
            // unsupported.
        }
    }

    @Override
    protected void onRateClicked(Context context, SdkEvent sdkEvent) {
        // The user clicked the rate button in an overlay.
        // He wants to rate the given contact.
        try {
            String rawContact = sdkEvent.getRelevantRawContact();
            // TODO Parse the given raw contact to proceed
        } catch (Exception e) {
            // Could not parse the given raw contact.
            // There is no default implementation for this event. The hosting
            // app should be able to deal with it or mark this feature as
            // unsupported.
        }
    }

    @Override
    protected void onMoreAlternativesClicked(Context context, SdkEvent sdkEvent) {
        // The user clicked the more-button at the end of the alternative
        // suggestion list. He wants to get more results.
        try {
            String rawContact = sdkEvent.getRelevantRawContact();
            // TODO Parse the given raw contact and open the apps search
            //  screen for the given contact category
        } catch (Exception e) {
            // Could not parse the given raw contact.
            // There is no default implementation for this event. The hosting
            // app should be able to deal with it or mark this feature as
            // unsupported.
        }
    }

    @Override
    protected void onSettingsClicked(Context context, SdkEvent sdkEvent) {
        // The clicked the settings button in an overlay.
        // The easiest way to manage this, is to use the SDKs default settings page.
        CleverDialerSdk.openSettingsActivity(context, true);
    }

    @Override
    protected void onOptionalEvent(Context context, SdkEvent event) {
        if (POSTCALL_SPAM_OVERLAY.equals(event.getCategory())
            && MISSED_CALL.equals(event.getAction())
            && AppReviewHelper.isTimeToAskForAppReview(context)) {
            // The user just got warned against a known spam caller.
            // Experience has shown, that he is likely to reward it.
            // As he matches the defined criteria, it is a good chance,
            // to ask him to review / rate the app.
            AppReviewHelper.askForAppReview(context);
        }
    }

    @Override
    protected void onFeedbackClicked(Context context, SdkEvent sdkEvent) {
        // The user clicked the feedback button in the app-review-overlay.
        // As the user made his decision, it is really important to prevent
        // asking him again.
        AppReviewHelper.deactivateAppReview(context);

        // Use the SdkEventHandler to enable the user to send an email
        // to your support team.
        SdkEventHandler
                .openMailClient(context,
                                "<partner>@support.com",
                                "Feedback (v " + VERSION_NAME + ")",
                                null);
    }

    @Override
    protected void onAppReviewClicked(Context context, SdkEvent sdkEvent) {
        // The user clicked the review button in the app-review-overlay.
        // As the user made his decision, it is really important to prevent
        // asking him again.
        AppReviewHelper.deactivateAppReview(context);

        // Use the SdkEventHandler to open the apps Play Store page to
        // enable the user to add an app review.
        // CAUTION: If the hosting app is listed in `AppGallery`, too, it
        // has to care about sending the user to the right store.
        SdkEventHandler.openPlayStorePage(context);
    }
}
Last Updated: 3/13/2024, 2:42:48 PM