Okay LogoOkay Logo

Get started with Android

Use our SDK for Android apps

Get started with Android
Example
1. Connect the SDK to Your Project

If you want to test out the Okay solution, we strongly recommend that you first do a test using the Okaythis application, found either in the play store or app store, which already implements SDK. Use it with the with our guide on how to Integrate the Okay app with your service, and once that is done you can try to connect with the SDK.

If you would like to use our SDK with your Android application, we also recommend scheduling a demo, so we can help guide you through the integration steps. But, if both of those steps are done you’re in the right place.

Remember, if you are having trouble with our SDK or Push Notifications (which use Firebase), please send us an email at developer@okaythis.com.

Click here to see the full code sample on GitHub

In your app's build.gradle add this:

android {

...

// add these lines to your gradle file

dataBinding {

enabled = true

}

compileOptions {

sourceCompatibility 1.8

targetCompatibility 1.8

}

}

dependencies {

implementation 'com.okaythis.sdk:psa:1.6.2'

}

Add this to your project's build.gradle file:

allprojects {

repositories {

google()

jcenter()

maven {

url "https://gitlab.okaythis.com/api/v4/projects/15/packages/maven"

name "GitLab"

}

}

}

2. Setting Up Push Notifications

In your app, you need to configure the receiver for Firebase Cloud Messages.

You should save the Firebase instanceId for later usage - that will be your appPNS.

The Okay secure server will a send push notification to your app when the user authorisation scenario is launched. Okay secure server must be properly configured in order to send these push notifications.

You will also need to set up Firebase for our project. If you are not familiar with integrating Firebase messaging, please check out this document for more information, as Okay SDK depends on it!

dependencies {

implementation fileTree(dir: 'libs', include: ['*.jar'])

implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

implementation 'androidx.appcompat:appcompat:1.1.0'

implementation 'androidx.core:core-ktx:1.1.0'

implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

implementation 'com.google.android.material:material:1.0.0'

testImplementation 'junit:junit:4.12'

androidTestImplementation 'androidx.test:runner:1.2.0'

androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

// Okay dependency

implementation 'com.okaythis.sdk:psa:1.6.2'

// Firebase dependency

implementation 'com.google.firebase:firebase-messaging:20.0.0'

}

We can now sync our app's gradle file to build.


3. Initialise the SDK

In order for the Okay SDK to work correctly, we will need to sync the SDK with Okay's secure server. Initialisation of the Okay secure SDK should be done within our Application class, using the onCreate() method.

We use the PsaManager class from Okay to initialise our PSA. We will be using two methods from the PsaManager class: the init() and setPssAddress() methods. The init() and setPssAddress() method from the PsaManager class has the following structure:

PsaManager psaManager = PsaManager.init(this, T extends ExceptionLogger);

psaManager.setPssAddress(PSS_SERVER_ENDPOINT);

Here is a typical illustration of what our Application class should look like at this point:

// OkayDemoApplication.kt

class OkayDemoApplication: Application() {

override fun onCreate() {

super.onCreate()

initPsa()

}

private fun initPsa() {

val psaManager = PsaManager.init(this, OkayDemoLogger())

psaManager.setPssAddress("https://demostand.okaythis.com")

}

}

This is what a minimal OkayDemoLogger class looks like:

class OkayDemoLogger: ExceptionLogger { override fun setUserIdentificator(p0: String?) { Log.e("SET ID: ", "Successfully set user identificator $p0 ") } override fun exception(p0: String?, p1: Exception?) { Log.e("Exception: ", "Okay Error $p0 -- Exception: $p1") } }

We will need to add our application class to our manifest file like so:

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.ogieben.okaydemo"> <application android:name=".OkayDemoApplication" 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"> ... </application>

The Okay SDK requires certain kinds of permissions to work properly. We will have to ask our users to grant those permissions before we proceed. We can easily create helper-methods to handle permission resolution for us:

// PermissionHelper.kt class PermissionHelper(private val activity: Activity) { val REQUEST_CODE = 204 fun hasPermissions(ctx: Context, permission: Array<String>): Boolean = permission.all { ActivityCompat.checkSelfPermission(ctx, it) == PackageManager.PERMISSION_GRANTED } fun requestPermissions(permission: Array<String>) = ActivityCompat.requestPermissions(activity, permission, REQUEST_CODE) }

The Okay SDK comes with a pre-packaged PsaManager.getRequiredPermissions() method which helps us fetch an array of required permissions:

// MainActivity.kt val permissionHelper = PermissionHelper(activity) private fun checkPermissions() { // prepacked method val requiredPermissions = PsaManager.getRequiredPermissions() if (!permissionHelper.hasPermissions(this, requiredPermissions)) { permissionHelper.requestPermissions(requiredPermissions) } }

We can now use the checkPermission() method within our MainActivity’s onCreate method to request for full permission:

// MainActivity.kt override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) setSupportActionBar(toolbar) checkPermissions() }

Firebase PNS Token

We will need our device token from Firebase to be able to use the SDK for enrolment, linking, and authorisation.

If Firebase has been successfully set up, we can request our device token using the code sample below. If you do not have Firebase correctly set up, please refer to this document, as the Okay SDK requires this service to work correctly.

// MainActivity.kt

private var preferenceRepo: PreferenceRepo = PreferenceRepo(context)

private fun fetchInstanceId () {

FirebaseInstanceId.getInstance().instanceId

.addOnCompleteListener(OnCompleteListener { task ->

if (!task.isSuccessful) {

Log.w("", "getInstanceId failed", task.exception)

Toast.makeText(this@MainActivity, "Error could not fetch token", Toast.LENGTH_LONG).show()

return@OnCompleteListener

}

val token = task.result?.token

// save token to SharedPreference storage for easy retrieval

preferenceRepo.persistAppPns(token.toString())

})

}

We can now invoke this method from our onCreate() method within our activity like so:


class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)

setSupportActionBar(toolbar)

// request permissions

checkPermissions()

// fetch token

fetchInstanceId()

}

}

4. User Enrollment

If all permissions have been granted and our appPns (also know as Firebase token) has been retrieved successfully, we can now proceed with device enrolment.

PsaManager.startEnrollmentActivity(activity Activity, data SpaEnrollData);

activity - An activity reference that will receive enrollment result from onActivityResult callback.

SpaEnrollData contains:

  • String appPns - Firebase instanceId
  • String pubPss - Should be the same on both app and server.
  • String installationId - Should be the same on both app and server.
  • PageTheme pageTheme - Can be used for the Authorisation UI customisation Document (pass null if you don't need UI customisation)
  • PsaType psaType - Use PsaType.OKAY


private fun beginEnrollment() {

val appPns = preferenceRepo.getAppPns() // retrieve Firebase token from SharedPreference storage

val pubPssB64 = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxgyacF1NNWTA6rzCrtK60se9fVpTPe3HiDjHB7MybJvNdJZIgZbE9k3gQ6cdEYgTOSG823hkJCVHZrcf0/AK7G8Xf/rjhWxccOEXFTg4TQwmhbwys+sY/DmGR8nytlNVbha1DV/qOGcqAkmn9SrqW76KK+EdQFpbiOzw7RRWZuizwY3BqRfQRokr0UBJrJrizbT9ZxiVqGBwUDBQrSpsj3RUuoj90py1E88ExyaHui+jbXNITaPBUFJjbas5OOnSLVz6GrBPOD+x0HozAoYuBdoztPRxpjoNIYvgJ72wZ3kOAVPAFb48UROL7sqK2P/jwhdd02p/MDBZpMl/+BG+qQIDAQAB"

val installationId = "9990"

val spaEnroll = SpaEnrollData(appPns,

pubPssB64,

installationId,

null,

PsaType.OKAY)

PsaManager.startEnrollmentActivity(this, spaEnroll)

}

After successful enrolment, Okay SDK will trigger an onActivityResult() callback for the activity we passed to startEnrollmentActivity(), returning an intent with the result of our enrolment data. Use PsaIntentUtils.enrollResultFromIntent() to extract enrolment data from Intent. For example:

// MainActivity.kt

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {

super.onActivityResult(requestCode, resultCode, data)

if (requestCode == PsaConstants.ACTIVITY_REQUEST_CODE_PSA_ENROLL) {

if (resultCode == RESULT_OK) {

//We should save data from Enrollment result, for future usage

data?.run {

val resultData = PsaIntentUtils.enrollResultFromIntent(this)

resultData.let {

preferenceRepo.saveExternalID(it.externalId)

}

Toast.makeText(applicationContext, "Successfully got this externalId " + resultData.externalId, Toast.LENGTH_SHORT).show()

}

} else {

Toast.makeText(this, "Error Retrieving intent after enrollment", Toast.LENGTH_SHORT).show()

}

}

}

5. Linking a user with the Okay SDK

In order to successfully finish the initialisation stage, we need to link the user with Okay. This allows us to authorise/authenticate a particular user's action. The linkingCode is a six-digit number generated for this purpose.

To enable linking on your app, you will need to add a line of code to your app's Application file. In this case, it is going to be OkayDemoApplication.kt.

class OkayDemoApplication: Application() {

override fun onCreate() {

super.onCreate()

initPsa()

// Added this method call

initGatewayServer()

}

private fun initPsa() {

val psaManager = PsaManager.init(this, OkayDemoLogger())

psaManager.setPssAddress("https://demostand.okaythis.com")

}

// Added this method

private fun initGatewayServer() {

GatewayRestServer.init(PsaGsonFactory().create(), "https://demostand.okaythis.com/gateway/")

}

}

This section is divided into two sub-sections. The first section is for developers who do not have a hosted server of their own, but wants to implement linking in their apps. The second section is for developers who already have a hosted server, and want to link their users with Okay. The hosted server can also be a local server, hosted through a tunnelling service such as Ngrok.

For Users Without a Hosted Server

We have created a demo server that illustrates how to generate linking codes, send authorisation requests, and handle Okay webhook callbacks here. You can run this server on your local machine to generate the required linking code.

You can also read more about how the server works on our Integrate Okay app with your service guide.

//MainActivity.kt

class MainActivity : AppCompatActivity() {

private lateinit var preferenceRepo: PreferenceRepo

private val permissionHelper = PermissionHelper(this)

private val retrofitWrapper = RetrofitWrapper()

private val transactionHandler = retrofitWrapper.handleTransactionEndpoints()

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)

setSupportActionBar(toolbar)

preferenceRepo = PreferenceRepo(this)

checkPermissions()

fetchInstanceId()

handleIntent(intent)

enrollmentButton.setOnClickListener { view ->

beginEnrollment()

}

manualLinkButton.setOnClickListener{

// retreive the linkingCode (i.e the linkingCode from editText)

// from the EditTextView entered into the app

val linkingCode = linkingCodeEditText.text.toString()

if(linkingCode.isEmpty()){

Toast.makeText(this, "Linking code can't be empty. Please enter linking code in the input field", Toast.LENGTH_LONG).show()

return@setOnClickListener

}

linkUser(linkingCode)

}

}

fun linkUser(linkingCode: String) {

// grab PsaManager instance

val psaManager = PsaManager.getInstance()

// LinkingScenarioListener listener

val linkingScenarioListener: LinkingScenarioListener = object: LinkingScenarioListener{

override fun onLinkingCompletedSuccessful(var1: Long, var3: String){

Toast.makeText(this@MainActivity, "Linking Successful", Toast.LENGTH_LONG).show()

}

override fun onLinkingFailed(var1: ApplicationState) {

Toast.makeText(this@MainActivity, "Linking not Successful: linkingCode: ${linkingCodeEditText.text} errorCode: ${var1.code} ", Toast.LENGTH_LONG).show()

}

}

// call PsaManager linkTenant method

psaManager.linkTenant(linkingCode, preferenceRepo, linkingScenarioListener)

}

}


For Users With a Hosted Server

We will send a request to our server to start the linking process. If our request was processed successfully, we will receive a response with the linking code required to finish linking.

We created a wrapper class called RetrofitWrapper to handle network requests.

// /network/RetrofitWrapper.kt

class RetrofitWrapper {

private val BASE_URL = "URL_TO_YOUR_SERVER"

fun createClient(): Retrofit {

return Retrofit.Builder()

.baseUrl(BASE_URL)

.addConverterFactory(GsonConverterFactory.create())

.build()

}

fun handleTransactionEndpoints(): TransactionEndpoints {

val retrofit: Retrofit = this.createClient()

return retrofit.create(TransactionEndpoints::class.java)

}

}

We make a very simple POST request to our server to initiate the linking process using our retrofit wrapper like so:

//MainActivity.kt class MainActivity : AppCompatActivity() { private lateinit var preferenceRepo: PreferenceRepo private val permissionHelper = PermissionHelper(this) private val retrofitWrapper = RetrofitWrapper() private val transactionHandler = retrofitWrapper.handleTransactionEndpoints() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) setSupportActionBar(toolbar) preferenceRepo = PreferenceRepo(this) checkPermissions() fetchInstanceId() handleIntent(intent) enrollmentButton.setOnClickListener { view -> beginEnrollment() } linkingButton.setOnClickListener{ // userId is the user's identifier for your service. // You are required to retrieve this from your server startServerLinking(userId) } } private fun startServerLinking(userId: String?) { transactionHandler.linkUser(userId).enqueue(object: Callback<OkayLinking>{ override fun onFailure(call: Call<OkayLinking>, t: Throwable) { Toast.makeText(this@MainActivity, "Error making request to Server ${t.localizedMessage}", Toast.LENGTH_LONG).show() t.printStackTrace() } override fun onResponse(call: Call<OkayLinking>, response: Response<OkayLinking>) { // Retrieve user linkingCode here after network call // then link user afterwards by passing linkingCode // to PsaManager.linkingTenant() method } }) } }

After we successfully generated the linking code, we can now proceed to link the user with Okay SDK.

PsaManager provides us with a helper function that allows us to link users with SPS right from Okay SDK. This is what the method’s signature looks like:

PsaManager.linkTenant(linkingCode: String, spaStorage: SpaStorage, linkingScenarioListener: LinkingScenarioListener)

The last parameter is a LinkingScenarioListener which must be implemented. This listener allows us to listen for two possible events: onLinkingCompletedSuccessful and onLinkingFailed. We will be implementing this listener in one of the code snippets below. See linkUser(linkingCode: String) method body.

We will also need to implement the SpaStorage interface in our application. The easiest way to implement this class is to implement it as one of your repositories (PreferenceRepo class as shown in the following example).

This is a typical example of what an implementation of the SpaStorage interface class looks like:

class PreferenceRepo(context: Context): SpaStorage { private val prefStorage: SharedPreferences = context.getSharedPreferences(PREFERENCE_KEY, Context.MODE_PRIVATE) override fun getPubPssBase64(): String? { return prefStorage.getString(PUB_PSS_B64, "") } override fun putAppPNS(p0: String?) { with(prefStorage.edit()) { putString(APP_PNS, p0) commit() } } override fun putPubPssBase64(p0: String?) { with(prefStorage.edit()) { putString(PUB_PSS_B64, p0) commit() } } override fun getAppPNS(): String? { return prefStorage.getString(APP_PNS, "") } override fun getEnrollmentId(): String? { return prefStorage.getString(ENROLLMENT_ID, "") } override fun putInstallationId(p0: String?) { with(prefStorage.edit()) { putString(INSTALLATION_ID, p0) commit() } } override fun putExternalId(p0: String?) { with(prefStorage.edit()) { putString(EXTERNAL_ID, p0) commit() } } override fun putEnrollmentId(p0: String?) { with(prefStorage.edit()) { putString(ENROLLMENT_ID, p0) commit() } } override fun getInstallationId(): String? { return prefStorage.getString(INSTALLATION_ID, "") } override fun getExternalId(): String? { return prefStorage.getString(EXTERNAL_ID, "") } companion object { const val PREFERENCE_KEY = "firebase_instance_id" const val APP_PNS = "app_pns" const val EXTERNAL_ID = "external_id" const val PUB_PSS_B64 = "pub_pss_b64" const val ENROLLMENT_ID = "enrollment_id" const val INSTALLATION_ID = "installation_id" } }

The following code snippet is a practical illustration of how we can successfully implement user linking:

// MainActivity.kt class MainActivity : AppCompatActivity() { private lateinit var preferenceRepo: PreferenceRepo private val permissionHelper = PermissionHelper(this) private val retrofitWrapper = RetrofitWrapper() private val transactionHandler = retrofitWrapper.handleTransactionEndpoints() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) setSupportActionBar(toolbar) preferenceRepo = PreferenceRepo(this) checkPermissions() fetchInstanceId() handleIntent(intent) enrollmentButton.setOnClickListener { view -> beginEnrollment() } linkingButton.setOnClickListener{ // userId is the users's identifier for your service // You are required to retrieve this from your server startServerLinking(userId) } } ... private fun linkUser(linkingCode: String) { val psaManager = PsaManager.getInstance() val linkingScenarioListener: LinkingScenarioListener = object: LinkingScenarioListener{ override fun onLinkingCompletedSuccessful(var1: Long, var3: String){ Toast.makeText(this@MainActivity, "Linking Successful", Toast.LENGTH_LONG).show() } override fun onLinkingFailed(var1: ApplicationState) { Toast.makeText(this@MainActivity, "Linking not Successful: linkingCode: ${linkingCodeEditText.text} errorCode: ${var1.code} ", Toast.LENGTH_LONG).show() } } // pass in linkingCode to PsaManager here to // initiate the linking process psaManager.linkTenant(linkingCode, preferenceRepo, linkingScenarioListener) } ... private fun startServerLinking(userId: String?) { transactionHandler.linkUser(userId).enqueue(object: Callback<OkayLinking>{ override fun onFailure(call: Call<OkayLinking>, t: Throwable) { Toast.makeText(this@MainActivity, "Error making request to Server ${t.localizedMessage}", Toast.LENGTH_LONG).show() t.printStackTrace() } override fun onResponse(call: Call<OkayLinking>, response: Response<OkayLinking>) { // Retrieve user linkingCode here after netwok call // we retrieve the user linkingCode here and // we pass in the linkingCode to linkUser method to start linking linkUser(response?.body()!!.linkingCode) } }) } }

6. Push Notification Parsing

Firebase push notification services send push notifications as a RemoteMessage object. This object contains two properties: type and data.

From this remote message, you can extract a map that contains these properties:

Map<String, String> notificationData = remoteMessage.getData(); String type = notificationData.get("type"); String data = notificationData.get("data");

After retrieving the notification data map from the RemoteMessage object, we check if the type property is equal to 10. If "type" equals 10, then it is a "WakeUpNotification". A wake-up notification is a notification that is sent to the SDK to start an authorisation process. It's "data" property contains the following object:


 { tenantId: <int>, sessionId: <int> }
7. Authorising a Transaction with Okay

If we have successfully linked our user, we can now proceed to authorising transactions or authenticating users.

The steps are pretty straight forward:

1. We make a request to our server to begin our authorisation.
2. Our server will make a call to the Okay secure server.
3. The server will, in turn, send a push notification to our app with the current tenantId of our server and the current transaction sessionId field.
4. Once we receive the push notification from Okay Servers, we start the authorisation process by calling the SDK's PsaManager.startAuthorizationActivity (activity: Activity, spaAuthorizationData :SpaAuthorizationData) method.
5. We pass in the current instance of our activity and an instance of SpaAuthorizationData class to the method.

Starting an authorisation begins with a simple request to your server using Retrofit in Android:


//MainActivity.kt

private val retrofitWrapper = RetrofitWrapper() // A simple wrapper around retrofit for network calls

private val transactionHandler = retrofitWrapper.handleTransactionEndpoints()

private fun startServerAuthorization(userId: String?) {

transactionHandler.authorizeTransaction(userId).enqueue(object: Callback<AuthorizationResponse> {

override fun onFailure(call: Call<AuthorizationResponse>, t: Throwable) {

Toast.makeText(this@MainActivity, "Error making request to Server", Toast.LENGTH_LONG).show()

}

override fun onResponse(

call: Call<AuthorizationResponse>,

response: Response<AuthorizationResponse>

) {

Toast.makeText(this@MainActivity, "Request made successfully", Toast.LENGTH_LONG).show()

}

})

}

This code sends a request to your server that initiates the authorisation with Okay secure server. Our application will receive a Push Notification that will be handled by FirebaseMassagingService (This service is part of Firebase messaging. If you are yet to setup Firebase, please see this document). In this example, we extend this service in our app using the OkayDemoFirebaseMessagingService class.

This is what our OkayDemoFirebaseMessagingService class looks like:

// OkayDemoFirebaseMessagingService.kt class OkayDemoFirebaseMessagingService : FirebaseMessagingService() { override fun onNewToken(token: String) { super.onNewToken(token) token?.run { PreferenceRepo(this@OkayDemoFirebaseMessagingService).putExternalId(token) } } override fun onMessageReceived(remoteData: RemoteMessage) { if(remoteData.data.isNotEmpty()){ // handle notification val notificationData = NotificationHandler.extractRemoteData(remoteData) // You can handle the data from the push notification here // However you seem fit // But in this illustration we just send sessionId as an Intent extra to MainActivity startActivity(Intent(this, MainActivity::class.java).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) putExtra(ACTIVITY_WAKE_UP_KEY, notificationData.sessionId!!.toLong() ) }) } } override fun onDeletedMessages() { super.onDeletedMessages() } companion object { val ACTIVITY_WAKE_UP_KEY = "wake_up_key" }

We simply receive this sessionId inside MainActivity.kt:

// MainActivity.kt

class MainActivity : AppCompatActivity() {

private lateinit var preferenceRepo: PreferenceRepo

private val permissionHelper = PermissionHelper(this)

private val retrofitWrapper = RetrofitWrapper()

private val transactionHandler = retrofitWrapper.handleTransactionEndpoints()

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)

setSupportActionBar(toolbar)

preferenceRepo = PreferenceRepo(this)

checkPermissions()

fetchInstanceId()

handleIntent(intent)

enrollmentButton.setOnClickListener { view ->

beginEnrollment()

}

linkingButton.setOnClickListener{

// userId is the users's identifier for your service

// You are required to retrieve this from your server

startServerLinking(userId)

}

authorizeButton.setOnClickListener {

// userId is the users's identifier for your service

// You are required to retrieve this from your server

startServerAuthorization(userId)

}

}

private fun handleIntent(intent: Intent?) {

intent?.apply {

val sessionId = getLongExtra(OkayDemoFirebaseMessagingService.ACTIVITY_WAKE_UP_KEY, 0)

if (sessionId > 0) {

Toast.makeText(this@MainActivity, "Current sessionId $sessionId ", Toast.LENGTH_LONG).show()

// Start Authorization with retrieved session Id

startAuthorization(sessionId)

}

}

}

...

private fun startAuthorization(sessionId: Long) {

PsaManager.startAuthorizationActivity(this, SpaAuthorizationData(sessionId,

preferenceRepo.appPNS,

BaseTheme(this).DEFAULT_PAGE_THEME,

PsaType.OKAY))

}

private fun startServerAuthorization(userId: String?) {

transactionHandler.authorizeTransaction(userId).enqueue(object: Callback<AuthorizationResponse> {

override fun onFailure(call: Call<AuthorizationResponse>, t: Throwable) {

Toast.makeText(this@MainActivity, "Error making request to Server", Toast.LENGTH_LONG).show()

}

override fun onResponse(

call: Call<AuthorizationResponse>,

response: Response<AuthorizationResponse>

) {

// Notify user request was sent

Toast.makeText(this@MainActivity, "Request made successfully", Toast.LENGTH_LONG).show()

}

})

}

}

If you successfully retrieved the sessionId from the push notification data, the Authorisation process begins immediately, allowing the Okay SDK to communicate with Okay secure server. This should present an authorisation screen in the running application.

8. PageTheme

PageTheme is a class (provided by Okay SDK) that describes the styling of authorisation screens. If you want to customise the authorisation screen provided by Okay SDK, you should create or extend PageTheme object, configure its fields, and then pass this object as an argument of SpaAuthorizationData.

Below you can find a sample theming class, BaseTheme, which is an extension of the PageTheme class:

class BaseTheme(context: Context) {

val DEFAULT_PAGE_THEME: PageTheme = PageTheme()

init {

context.let {

DEFAULT_PAGE_THEME.apply {

actionBarBackgroundColor = it.getColor(R.color.primaryDarkColor)

actionBarTextColor = it.getColor(R.color.primaryTextColor)

screenBackgroundColor = it.getColor(R.color.primaryColor)

buttonBackgroundColor = it.getColor(R.color.secondaryColor)

buttonTextColor = it.getColor(R.color.secondaryTextColor)

pinNumberButtonTextColor = it.getColor(R.color.secondaryTextColor)

pinNumberButtonBackgroundColor = it.getColor(R.color.secondaryLightColor)

pinRemoveButtonBackgroundColor = it.getColor(R.color.secondaryLightColor)

pinRemoveButtonTextColor = it.getColor(R.color.secondaryTextColor)

pinTitleTextColor = it.getColor(R.color.primaryTextColor)

pinValueTextColor = it.getColor(R.color.primaryTextColor)

titleTextColor = it.getColor(R.color.primaryTextColor)

questionMarkColor = it.getColor(R.color.primaryLightColor)

transactionTypeTextColor = it.getColor(R.color.primaryTextColor)

authInfoBackgroundColor = it.getColor(R.color.transaction_info_background)

infoSectionTitleColor = it.getColor(R.color.secondaryLightColor)

infoSectionValueColor = it.getColor(R.color.secondaryTextColor)

fromTextColor = it.getColor(R.color.secondaryTextColor)

messageTextColor = it.getColor(R.color.secondaryTextColor)

confirmButtonBackgroundColor = it.getColor(R.color.secondaryLightColor)

confirmButtonTextColor = it.getColor(R.color.secondaryTextColor)

cancelButtonBackgroundColor = it.getColor(R.color.primaryLightColor)

cancelButtonTextColor = it.getColor(R.color.primaryTextColor)

authConfirmationButtonBackgroundColor = it.getColor(R.color.secondaryColor)

authConfirmationButtonBackgroundColor = it.getColor(R.color.secondaryColor)

authConfirmationButtonTextColor = it.getColor(R.color.secondaryTextColor)

authCancellationButtonBackgroundColor = it.getColor(R.color.primaryColor)

authCancellationButtonTextColor = it.getColor(R.color.primaryTextColor)

nameTextColor = it.getColor(R.color.secondaryTextColor)

buttonBackgroundColor = it.getColor(R.color.primaryLightColor)

buttonTextColor = it.getColor(R.color.primaryTextColor)

inputTextColor = it.getColor(R.color.secondaryTextColor)

inputSelectionColor = Color.GREEN

inputErrorColor = Color.RED

inputDefaultColor = Color.GRAY

}

}

}

}

You can now use your theme like so:

PsaManager.startAuthorizationActivity(Activity activity, PageTheme baseTheme, SpaAuthorizationData authorizationData)

Android Theme

public class PageTheme implements Parcelable { private Bundle bundle = new Bundle(); private static final String ACTION_BAR_BACKGROUND_COLOR = "actionBarBackgroundColor"; private static final String ACTION_BAR_TEXT_COLOR = "actionBarTextColor"; private static final String BUTTON_TEXT_COLOR = "buttonTextColor"; private static final String BUTTON_BACKGROUND_COLOR = "buttonBackgroundColor"; private static final String SCREEN_BACKGROUND_COLOR = "screenBackgroundColor"; private static final String NAME_TEXT_COLOR = "nameTextColor"; private static final String TITLE_TEXT_COLOR = "titleTextColor"; private static final String MESSAGE_TEXT_COLOR = "messageTextColor"; private static final String ACTION_BAR_LOGO_PATH = "actionBarLogoPath"; private static final String ACTION_BAR_TITLE = "actionBarTitle"; private static final String INPUT_TEXT_COLOR = "inputTextColor"; private static final String INPUT_SELECTION_COLOR = "inputSelectionColor"; private static final String INPUT_ERROR_COLOR = "inputErrorColor"; private static final String INPUT_DEFAULT_COLOR = "inputDefaultColor"; private static final String QUESTION_MARK_COLOR = "questionMarkColor"; private static final String TRANSACTION_TYPE_TEXT_COLOR = "transactionTypeTextColor"; private static final String INFO_SECTION_TITLE_COLOR = "infoSectionTitleColor"; private static final String INFO_SECTION_VALUE_COLOR = "infoSectionValueColor"; private static final String FROM_TEXT_COLOR = "fromTextColor"; private static final String AUTH_INFO_BACKGROUND_COLOR = "authInfoBackgroundColor"; private static final String SHOW_DETAILS_TEXT_COLOR = "showDetailsTextColor"; private static final String CONFIRM_BUTTON_BACKGROUND_COLOR = "confirmButtonBackgroundColor"; private static final String CONFIRM_BUTTON_TEXT_COLOR = "confirmButtonTextColor"; private static final String CANCEL_BUTTON_BACKGROUND_COLOR = "cancelButtonBackgroundColor"; private static final String CANCEL_BUTTON_TEXT_COLOR = "cancelButtonTextColor"; private static final String AUTH_CONFIRMATION_BACKGROUND_COLOR = "authConfirmationBackgroundColor"; private static final String AUTH_CONFIRMATION_TITLE_COLOR = "authConfirmationTitleColor"; private static final String AUTH_CONFIRMATION_MESSAGE_COLOR = "authConfirmationMessageColor"; private static final String AUTH_CONFIRMATION_THUMB_COLOR = "authConfirmationThumbColor"; private static final String AUTH_CONFIRMATION_APOSTROPHE_COLOR = "authConfirmationApostropheColor"; private static final String AUTH_CONFIRMATION_BUTTON_BACKGROUND_COLOR = "authConfirmationButtonBackgroundColor"; private static final String AUTH_CONFIRMATION_BUTTON_TEXT_COLOR = "authConfirmationButtonTextColor"; private static final String AUTH_CANCELLATION_BACKGROUND_COLOR = "authCancellationBackgroundColor"; private static final String AUTH_CANCELLATION_TITLE_COLOR = "authCancellationTitleColor"; private static final String AUTH_CANCELLATION_MESSAGE_COLOR = "authCancellationMessageColor"; private static final String AUTH_CANCELLATION_THUMB_COLOR = "authCancellationThumbColor"; private static final String AUTH_CANCELLATION_APOSTROPHE_COLOR = "authCancellationApostropheColor"; private static final String AUTH_CANCELLATION_BUTTON_BACKGROUND_COLOR = "authCancellationButtonBackgroundColor"; private static final String AUTH_CANCELLATION_BUTTON_TEXT_COLOR = "authCancellationButtonTextColor"; private static final String PIN_TITLE_TEXT_COLOR = "pinTitleTextColor"; private static final String PIN_VALUE_TEXT_COLOR = "pinValueTextColor"; private static final String PIN_NUMBER_BUTTON_TEXT_COLOR = "pinNumberButtonTextColor"; private static final String PIN_NUMBER_BUTTON_BACKGROUND_COLOR = "pinNumberButtonBackgroundColor"; private static final String PIN_REMOVE_BUTTON_TEXT_COLOR = "pinRemoveButtonTextColor"; private static final String PIN_REMOVE_BUTTON_BACKGROUND_COLOR = "pinRemoveButtonBackgroundColor"; // getters and setters }

Explanation of fields:

These images will help you to understand which key you need:

9. Ways to Trigger Authorisation

You can start authorization requests to the SDK in two ways:

9.1 With Activity

PsaManager.startAuthorizationActivity(Activity activity, SpaAuthorizationData authorizationData)

By triggering an authorisation this way, you must implement onActivityResult inside the activity you passed to PsaManager.startAuthorizationActivity(). The status of the authorisation will be sent to this method, where you can check if the transaction was successful or not.

Sample

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {

super.onActivityResult(requestCode, resultCode, data)

if (requestCode == PsaConstants.ACTIVITY_REQUEST_CODE_PSA_ENROLL) {

if (resultCode == RESULT_OK) {

//We should save data from Enrollment result, for future usage

data?.run {

val resultData = PsaIntentUtils.enrollResultFromIntent(this)

resultData.let {

preferenceRepo.putExternalId(it.externalId)

}

Toast.makeText(applicationContext, "Successfully got this externalId " + resultData.externalId, Toast.LENGTH_SHORT).show()

}

} else {

Toast.makeText(this, "Error Retrieving intent after enrollment:- code: ${linkingCodeEditText.text} errorCode: $resultCode", Toast.LENGTH_SHORT).show()

}

}

if (requestCode == PsaConstants.ACTIVITY_REQUEST_CODE_PSA_AUTHORIZATION) {

if (resultCode == RESULT_OK) {

Toast.makeText(this, "Authorization granted", Toast.LENGTH_SHORT).show()

} else {

Toast.makeText(this, "Authorization not granted", Toast.LENGTH_SHORT).show()

}

}

}

or by LocalBroadcastReceiver with:

intent filter action = PsaConstants.ACTION_AUTHORIZATION_RESULT_EVENT

9.2 With Context

PsaManager.startAuthorizationActivity(Context context, SpaAuthorizationData authorizationData)

In which you will receive results only from LocalBroadcastReceiver

SpaAuthorizationData

When you create SpaAuthorizationData you should provide:

Long sessionId - Retrieved from the push notification sent by Okay’s server
String appPNS - Firebase instance ID
PageTheme pageTheme - Can be used for the authorisation screen customisation (pass null to use default UI customisation)
PsaType psaType - Use PsaType.OKAY

10. Client Settings
10.1 Mobile Client Settings

To use the Okay SDK, you need an installation Id and a public key. Below you will find a valid installation Id and a public key that you can use in your application:

Installation ID: 9990

Public Okay Secure Server Keys

-----BEGIN RSA PUBLIC KEY-----

MIIBCgKCAQEAxgyacF1NNWTA6rzCrtK60se9fVpTPe3HiDjHB7MybJvNdJZIgZbE

9k3gQ6cdEYgTOSG823hkJCVHZrcf0/AK7G8Xf/rjhWxccOEXFTg4TQwmhbwys+sY

/DmGR8nytlNVbha1DV/qOGcqAkmn9SrqW76KK+EdQFpbiOzw7RRWZuizwY3BqRfQ

Rokr0UBJrJrizbT9ZxiVqGBwUDBQrSpsj3RUuoj90py1E88ExyaHui+jbXNITaPB

UFJjbas5OOnSLVz6GrBPOD+x0HozAoYuBdoztPRxpjoNIYvgJ72wZ3kOAVPAFb48

UROL7sqK2P/jwhdd02p/MDBZpMl/+BG+qQIDAQAB

-----END RSA PUBLIC KEY-----

Note: Keys are encoded in PKCS#1 format.