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 (GitLab package registry).
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://gitlab.sellwerk.cloud/api/v4/projects/31/packages/maven"
}
}
}
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 againlimit
: Amount of times the user will be asked, before the requests are paused forrevivalDays
.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)
Booking links
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 addandroid: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 ofCheckBoxPreference
another type ofTwoStatePreference
(e.g.SwitchPreference
) could be used. - The texts for
android:title
orandroid:summary
, referenced incd_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 colorscolorPrimary
,colorPrimaryDark
andcolorAccent
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://gitlab.sellwerk.cloud/api/v4/projects/31/packages/maven"
}
}
}
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);
}
}