Consent Covid-19 Aid

This article is part of the SDK integration guide for partners in combating Covid-19.

📝Asking for the user consent

Inloco SDK can be initialized without data collection to respect the user's privacy. In order to wait for the user's consent to start data collection, you must set <bool name="inloco_privacy_consent_required">true</bool> on the inloco.xml file.

You then must request the user's consent for the SDK to properly function.

🔐Consent request

This section will guide you how to create a dialog to show a prompt such as the one in the image below.

Inloco's SDK provides a consent dialog that configures the consent correctly after the user interaction with the form. You can customize the message attributes such as dialog title, message body, accept and deny button messages, but we provide an example of such content that you can copy and only include your application name on it.

Text in Portuguese.

The following code demonstrates how to build the request dialog:

Java
Kotlin
Objective-C
Swift
Java
public class MainActivity extends Activity {
private final static String TAG = "MainActivity";
private ConsentRequest consentRequest;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);;
showConsentDialogUsingInLoco();
}
private void showConsentDialogUsingInLoco() {
// Dialog Options
ConsentDialogOptions options = new ConsentDialogOptions.Builder(context)
.title(getString(R.string.consent_dialog_title))
.message(getString(R.string.consent_dialog_message))
.acceptText(getString(R.string.consent_dialog_accept_button))
.denyText(getString(R.string.consent_dialog_deny_button))
.consentTypes(ConsentTypes.COVID_19_AID)
.build();
this.consentRequest = InLoco.requestPrivacyConsent(options, new ConsentListener() {
@Override
public void onConsentResult(final ConsentResult result) {
if (result.areAllConsentTypesGiven()) {
Log.i(TAG, "Success!");
}
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
// Dismisses the dialog if the activity is abruptly closed
if (consentRequest != null) {
consentRequest.dismiss();
}
}
}
Kotlin
class MainActivity : Activity() {
companion object {
private const val TAG = "MainActivity"
}
private var consentRequest: ConsentRequest? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
showConsentDialogUsingInLoco()
}
private fun showConsentDialogUsingInLoco() {
// Dialog Options
val consentDialogOptions = ConsentDialogOptions.Builder(this)
.acceptText(getString(R.string.consent_dialog_accept_button))
.denyText(getString(R.string.consent_dialog_deny_button))
.title(getString(R.string.consent_dialog_title))
.message(getString(R.string.consent_dialog_message))
.consentTypes(ConsentTypes.COVID_19_AID)
.build()
consentRequest = InLoco.requestPrivacyConsent(consentDialogOptions) { response ->
if (response.areAllConsentTypesGiven()) {
Log.i(TAG, "Success!")
}
}
}
override fun onDestroy() {
super.onDestroy()
consentRequest?.dismiss()
}
}
Objective-C
@interface MainViewController : UIViewController
@end
@implementation MainViewController
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self showConsentAlertUsingInLoco];
}
- (void)showConsentAlertUsingInLoco
{
NSSet *consentTypes = [NSSet setWithObjects:ILM_CONSENT_TYPE_COVID_19_AID, nil];
//Dialog options. Note that all of the properties below must be set in order to the dialog show.
ILMConsentDialogOptionsBuilder *builder = [[ILMConsentDialogOptionsBuilder alloc] init];
[builder setTitle:@"Do you want to help the fight against Covid-19?"];
[builder setMessage:@"Do you allow <Your App> and our partner In Loco to use your location data and device information? \nYou can help monitoring isolation and receive risk alerts for nearby locations. \nDon't worry, your privacy is protected. All collected data will be aggregated and deleted after the COVID-19 crisis."];
[builder setAcceptText:@"Accept"];
[builder setDenyText:@"Refuse"];
[builder setConsentTypes:consentTypes];
ILMError *err;
ILMConsentDialogOptions *options = [builder build:&err];
//This request will show the consent dialog to the user
[ILMInLoco requestPrivacyConsentWithOptions:options andConsentBlock:^(ILMConsentResult *result) {
if (result) {
if (![result hasFinished]) {
//Some error occurred during the process and the operation could not be finished
NSLog(@"Error");
} else if ([result areAllConsentTypesGiven]) {
//The dialog was shown and the consent was given
NSLog(@"Success!");
} else {
//The dialog was shown but the consent was denied
NSLog(@"Success, but user denied.");
}
}
}];
}
@end
Swift
class ViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.showConsentAlertUsingInLoco()
}
func showConsentAlertUsingInLoco() {
let consentTypes: Set = [ILM_CONSENT_TYPE_COVID_19_AID]
var builder = ILMConsentDialogOptionsBuilder()
builder.title = "Do you want to help the fight against Covid-19?"
builder.message = "Do you allow <Your App> and our partner In Loco to use your location data and device information? \nYou can help monitoring isolation and receive risk alerts for nearby locations. \nDon't worry, your privacy is protected. All collected data will be aggregated and deleted after the COVID-19 crisis."
builder.acceptText = "Accept"
builder.denyText = "Refuse"
builder.consentTypes = consentTypes
let dialogOptions = builder.build()
ILMInLoco.requestPrivacyConsentWithOptions(dialogOptions, { (result: ILMConsentResult?) in
if (!result?.hasFinished) {
//Some error occurred during the process and the operation could not be finished
print("Error")
} else if (result?.areAllConsentTypesGiven) {
//The dialog was shown and the consent was given
print("Success!")
} else {
//The dialog was shown but the consent was denied
print("Success, but user denied.")
}
})
}
}

Include the dialog attributes in your strings.xml file.

strings.xml (en)
strings.xml (pt)
strings.xml (en)
<resources>
<string name="consent_dialog_title">Do you want to help the fight against Covid-19?</string>
<string name="consent_dialog_message">
Do you allow <Your App> and our partner Inloco to use your location data and device information?
You can help monitoring crowded places and receive risk alerts for nearby locations.
Don\'t worry, your privacy is protected. All collected data will be aggregated and deleted after the COVID-19 crisis.
</string>
<string name="consent_dialog_accept_button">Accept</string>
<string name="consent_dialog_deny_button">Refuse</string>
</resources>
strings.xml (pt)
<resources>
<string name="consent_dialog_title">Quer ajudar a combater a COVID-19?</string>
<string name="consent_dialog_message">
Para ajudar a monitorar locais com aglomerações de pessoas e receber alertas de riscos próximos, você permite que <Seu App> e a parceira Inloco utilize sua localização e dados do dispositivo? \n
Não se preocupe, pois sua privacidade está garantida. Todos os dados serão agrupados e deletados após a crise da COVID-19.
</string>
<string name="consent_dialog_accept_button">Aceitar</string>
<string name="consent_dialog_deny_button">Recusar</string>
</resources>

📬Custom prompt

You can achieve the same results without using Inloco's dialog. To do so, just do the following.

Java
Kotlin
Java
public class MainActivity extends Activity {
private final static String TAG = "MainActivity";
private AlertDialog consentDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
showConsentDialog();
}
private void showConsentDialog() {
// Verify the necessary consent
InLoco.checkConsent(MainActivity.this, new ConsentListener() {
@Override
public void onConsentResult(ConsentResult response) {
if (response.isWaitingConsent()) {
// Create a dialog with custom message asking the user's consent. Remember to define the messages in your strings.xml file
consentDialog = new AlertDialog.Builder(MainActivity.this)
.setTitle(getString(R.string.consent_dialog_title))
.setMessage(getString(R.string.consent_dialog_message))
.setCancelable(false)
.setPositiveButton(getString(R.string.consent_dialog_accept_button), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// Notify Inloco's SDK
InLoco.allowConsentTypes(MainActivity.this, ConsentTypes.COVID_19_AID);
Log.i(TAG, "Success!");
}
})
.setNegativeButton(getString(R.string.consent_dialog_deny_button), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// Notify Inloco's SDK
InLoco.denyConsentTypes(MainActivity.this, ConsentTypes.COVID_19_AID);
}
})
.create();
if (!isFinishing() && (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 || !isDestroyed())) {
consentDialog.show();
}
}
}
}, ConsentTypes.COVID_19_AID);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (consentDialog != null && consentDialog.isShowing()) {
consentDialog.dismiss();
}
}
}
Kotlin
class MainActivity : Activity() {
companion object {
private const val TAG = "MainActivity"
}
private var consentDialog: AlertDialog? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
showConsentDialog()
}
private fun showConsentDialog() {
// Verify the necessary consent
InLoco.checkConsent(this@MainActivity, ConsentListener { response ->
if (response.isWaitingConsent) {
// Create a dialog with custom message asking the user's consent. Remember to define the messages in your strings.xml file
consentDialog = AlertDialog.Builder(this@MainActivity)
.setTitle(getString(R.string.consent_dialog_title))
.setMessage(getString(R.string.consent_dialog_message))
.setCancelable(false)
.setPositiveButton(getString(R.string.consent_dialog_accept_button)) { _, _ ->
// Notify In Loco's SDK
InLoco.allowConsentTypes(this@MainActivity, ConsentTypes.COVID_19_AID)
Log.i(TAG, "Success!")
}
.setNegativeButton(getString(R.string.consent_dialog_deny_button)) { _, _ ->
// Notify In Loco's SDK
InLoco.denyConsentTypes(this@MainActivity, ConsentTypes.COVID_19_AID)
}
.create()
if (!isFinishing && (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 || !isDestroyed)) {
consentDialog?.show()
}
}
}, ConsentTypes.COVID_19_AID)
}
override fun onDestroy() {
super.onDestroy()
// Dismisses the dialog if the activity is abruptly closed
if (consentDialog != null && consentDialog!!.isShowing) {
consentDialog?.dismiss()
}
}
}

🗺Requesting location permission

For Inloco's SDK to work properly, you must also request the Manifest.permission.ACCESS_FINE_LOCATION Manifest.permission.ACCESS_BACKGROUND_LOCATION permissions to the user.

If you application doesn't use these permissions, you may request after the user accepts the consent dialog. The following code demonstrates how to request the location permissions.

Java
Kotlin
Java
public class MainActivity extends Activity {
[...]
private static final int LOCATION_PERMISSION_REQUEST_CODE = <Any Number>;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
showConsentDialogUsingInLoco();
}
private void showConsentDialogUsingInLoco() {
[...]
this.consentRequest = InLoco.requestPrivacyConsent(options, new ConsentListener() {
@Override
public void onConsentResult(final ConsentResult result) {
if (result.areAllConsentTypesGiven()) {
requestLocationPermission();
}
}
});
}
private void requestLocationPermissions() {
Collection<String> permissions = new ArrayList<>();
permissions.add(Manifest.permission.ACCESS_FINE_LOCATION);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
permissions.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION);
}
if (!isLocationPermissionGranted()) {
ActivityCompat.requestPermissions(this, permissions.toArray(new String[0]), LOCATION_PERMISSION_REQUEST_CODE);
}
}
private boolean isLocationPermissionGranted() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
return ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED;
}
}
return false;
}
@Override
public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {
if (isLocationPermissionGranted()) {
Log.i(TAG, "Success!");
} else {
//Optional: Notify the user that he won't be participating as the app can't obtain location
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// Dismisses the dialog if the activity is abruptly closed
if (consentRequest != null) {
consentRequest.dismiss();
}
}
}
Kotlin
class MainActivity : Activity() {
companion object {
private const val TAG = "MainActivity"
private const val LOCATION_PERMISSION_REQUEST_CODE = 1457
}
[...]
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
showConsentDialogUsingInLoco()
}
private fun showConsentDialogUsingInLoco() {
[...]
consentRequest = InLoco.requestPrivacyConsent(consentDialogOptions) { response ->
if (response.areAllConsentTypesGiven()) {
Log.i(TAG, "Success!")
requestLocationPermissions()
}
}
}
private fun requestLocationPermissions() {
val permissions = ArrayList<String>()
permissions.add(Manifest.permission.ACCESS_FINE_LOCATION)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
permissions.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
}
if (!isLocationPermissionGranted()) {
ActivityCompat.requestPermissions(this, permissions.toTypedArray(), LOCATION_PERMISSION_REQUEST_CODE)
}
}
private fun isLocationPermissionGranted(): Boolean {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
return ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED
}
}
return false
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {
if (isLocationPermissionGranted()) {
Log.i(TAG, "Success!")
} else {
//Optional: Notify the user that he won't be participating as the app can't obtain location
}
}
}
override fun onDestroy() {
super.onDestroy()
// Dismisses the dialog if the activity is abruptly closed
consentRequest?.dismiss()
}
}