User Consent¶
Part of the Human Scoring use case.
The SDK records how the user interacts with your app, so by default it records nothing until the user agrees. Your app asks the question — with the SDK's ready-made dialog, or in its own UI — and the SDK stores the answer and enforces it.
When to use it¶
- Always, unless your app already obtains consent before calling
DeaSdk.init— in that case, setrequireConsent = false - To let the user withdraw consent from a settings screen
- To ask again, for example when a different account signs in
Prerequisites¶
- The SDK is installed and initialized. See the Quick Start.
Usage¶
Ask with the built-in dialog¶
import ai.dea.sdk.DeaConsentDialog
// In an Activity, on the main thread:
DeaConsentDialog.show(this) { granted ->
// The user's answer, or the answer already on file.
}
- When an answer is already stored, the dialog is not shown:
onResultis called at once with that answer. Put the call in front of a session unconditionally; it only interrupts the user the first time. - The dialog does not close on a tap outside it. The back button closes it and calls
onResultwithfalse, but stores nothing, so the user is asked again next time. - When the SDK is not initialized,
showshows nothing and callsonResult(false). So does an activity that is finishing, when no answer is stored. - Pass
ask = falseto read the stored answer without ever showing the dialog.
The dialog's text is the ConsentCopy you pass. The default, in English, says what is recorded and
what never is:
| Field | Default |
|---|---|
title |
Record this session? |
body |
This app measures how a real person moves, so that people can be told apart from bots. |
recorded |
Where you touch, and how hard · How fast your finger travels · How the handset moves in your hand |
notRecorded |
What you type · What's on your screen · Anything you say |
closing |
Nothing is recorded until you agree, and you can stop at any time. |
accept, decline |
I agree · Not now |
The lists are claims about your app. If they are not true of it — for example because your app
reports key presses with captureKey — pass your own text:
import ai.dea.sdk.ConsentCopy
import ai.dea.sdk.DeaConsentDialog
DeaConsentDialog.show(
this,
copy = ConsentCopy(
title = "Help us keep bots out",
notRecorded = listOf("What's on your screen", "Anything you say"),
),
) { granted -> }
An empty list drops that section of the dialog.
Ask in your own UI, then record the answer¶
import ai.dea.sdk.DeaSdk
val dea = DeaSdk.instance ?: return
if (!dea.consent.isAnswered) {
// Show your prompt, then:
dea.setConsent(true) // the user agreed
// or
dea.setConsent(false) // the user declined
}
- Recording starts or stops as soon as
setConsentis called. - The answer is stored on the device, so
isAnsweredstaystrueon later launches and you only ask once. - A decline is an answer and is stored too. Do not ask again on every launch after a decline.
Read the current answer¶
val consent = DeaSdk.instance!!.consent
consent.isAnswered // false until the user has answered
consent.isGranted // true only if the user agreed
consent.decision // ConsentDecision.UNKNOWN, GRANTED or DENIED
Withdraw consent¶
Recording stops immediately and anything captured but not yet processed is discarded. The session is kept, so if the user agrees again, recording continues in the same session.
Ask again¶
forget() clears the stored answer, so isAnswered is false again and your app asks next time —
for example when a different account signs in on the same device. Unlike declining, it is not an
answer. Nothing is recorded until the user answers again.
Be notified when the answer changes¶
import ai.dea.base.ConsentDecision
val unsubscribe = DeaSdk.instance!!.consent.onChange { decision: ConsentDecision ->
updateConsentSwitch(decision == ConsentDecision.GRANTED)
}
// Later, when you no longer need updates:
unsubscribe()
Shared devices¶
When a different person may use the device each session (a kiosk, a test device), do not store the
answer. Pass a Consent that is kept for this launch only:
import ai.dea.base.Consent
import ai.dea.sdk.DeaConfig
import ai.dea.sdk.DeaSdk
DeaSdk.init(this, DeaConfig(appId = "YOUR_APP_ID", appKey = "YOUR_APP_KEY", consent = Consent()))
Or keep the default store and record each answer for this launch only:
The built-in dialog does the same with remember = false. It also clears the stored answer first,
because that answer was given by whoever held the device before, and then asks on every call:
Consent you already have¶
If your own consent record already says yes, pass it in instead of asking again:
import ai.dea.base.Consent
import ai.dea.sdk.DeaConfig
import ai.dea.sdk.DeaSdk
DeaSdk.init(this, DeaConfig(appId = "YOUR_APP_ID", appKey = "YOUR_APP_KEY", consent = Consent.granted()))
To keep the answer in your own records instead of the SDK's, implement ConsentStore and pass
Consent(store = yourStore). The answer is read from your store when you create the Consent, and
every answer recorded with remember = true is written to it.
Examples¶
Ask on the first screen¶
import ai.dea.sdk.DeaSdk
import android.app.AlertDialog
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
class HomeActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home)
val dea = DeaSdk.instance ?: return
if (dea.consent.isAnswered) return
AlertDialog.Builder(this)
.setTitle("Help us keep bots out")
.setMessage(
"We measure how you touch the screen and how the phone moves in your hand, to " +
"tell people apart from bots. We never record what you type or what is on " +
"your screen. You can change this at any time in Settings.",
)
.setCancelable(false)
.setPositiveButton("Allow") { _, _ -> dea.setConsent(true) }
.setNegativeButton("Not now") { _, _ -> dea.setConsent(false) }
.show()
}
}
Make sure the wording stays true for your app.
A settings switch¶
import ai.dea.sdk.DeaSdk
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SwitchCompat
class SettingsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_settings)
val dea = DeaSdk.instance
val toggle = findViewById<SwitchCompat>(R.id.bot_protection)
toggle.isEnabled = dea != null
toggle.isChecked = dea?.consent?.isGranted ?: false
toggle.setOnCheckedChangeListener { _, checked -> dea?.setConsent(checked) }
}
}
API¶
| Member | Returns | Description |
|---|---|---|
DeaConsentDialog.show(activity, sdk, copy, remember, ask, onResult) |
Unit |
Shows the built-in dialog unless an answer is stored, records the answer, and calls onResult |
DeaSdk.setConsent(granted, remember = true) |
Unit |
Records the answer and applies it at once; remember = false keeps it for this launch only |
DeaSdk.consent |
Consent |
The current answer |
Consent.isAnswered |
Boolean |
Whether the user has answered |
Consent.isGranted |
Boolean |
Whether the user agreed |
Consent.decision |
ConsentDecision |
UNKNOWN, GRANTED or DENIED |
Consent.forget() |
Unit |
Clears the stored answer |
Consent.onChange(listener) |
() -> Unit |
Calls listener when the answer changes; returns the unsubscribe |
Consent() |
Consent |
An answer kept for this launch only |
Consent.granted() |
Consent |
An answer that is already yes |
Consent(store) |
Consent |
An answer kept in your own ConsentStore |