Okay LogoOkay Logo

Get started with Android

Use our SDK for Android apps

Get started with Android
Download Android SDKExample
1. Connect SDK to Your Project

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.2.0'

}

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

allprojects {

repositories {

google()

jcenter()

maven {

url https://dl.bintray.com/okaythis/maven

}

}

}

2. Setting Up Push Notification

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

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

PSS will send push notifications to your app when the user authorization scenario would be launched. PSS must be properly configured to send push notifications.

We will also need to set up Firebase for our project. If you are not familiar with integrating Firebase messaging please check this documentation for more information as the 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.2.0'

// Firebase dependency

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

}

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

3. Initialize SDK

In order for Okay SDk to work correctly we will need to sync the SDK with PSS. Initialization of the PSA should be done within our Application class, inside the onCreate() method.

We use the PsaManager class from Okay to initialize 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);

A typical illustration of how our Application class should be:

// 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 my 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 the users to grant these permissions before we proceed. We can easily create these 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 prepacked method PsaManager.getRequiredPermissions() that helps us fetch an array of all 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.kt's onCreate method to request for all 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 enrollment, linking and authorization.

If firebase has been successfully setup, we can request for our device token using the code sample below. If you have not been able to setup Firebase please refer to this documentation as Okay 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())

})

}

If all is good, 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

We can now proceed with our enrollment if all permissions has been granted and our appPns(also know as Firebase token) has been retrieved successfully.

PsaManager.startEnrollmentActivity(activity Activity, data SpaEnrollData);

activity - 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 Authorization UI customization Documentation (pass null if you don't need UI customization)
  • 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)

}

And after successful enrollment, Okay will call onActivityResult() callback on the activity we passed to startEnrollmentActivity() returning an intent with the result of our enrollment data. Use PsaIntentUtils.enrollResultFromIntent() to extract enrollment 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 Okay SDK

In order to successfully finish the initialization stage, we need to link the user with Okay. This allows us to authorize/authenticate a particular user's action.

To enable linking on the your app you will need to add this 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 dedicated server of their own but want to implement linking in their apps. While the second section is for developers who have a dedicated server and wants to link their users with Okay.

For Users With No Dedicated Server

Since you do not have a server to generate linkingCodes, you can just generate your linking codes from this url http://spacey.okaythis.com (Note: This is for demonstration purposes only, do not use this url for your production apps) then sign in with "tenant" as your username and "password" as your password. You will receive a linking code that you will pass to PsaManager.linkTenant(), in order to manually link the current user.

//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 Dedicated Server

We will send a request to our server to start the linking process. We will be sending the externalId generated from the Okay SDK as a parameter to our server(Note: externalId can be generated by your system/server as a key or userId that is used to uniquely identify you users. We used the one from the SDK for simplicity). If our request was processed successfully, we will receive a response with the linkingCode required to finish linking. The linkingCode is a six digit number generated for this purpose.

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

// /network/RetrofitWrapper.kt

class RetrofitWrapper {

private val BASE_URL = "URL_TO_YOU_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{

startServerLinking(preferenceRepo.externalId)

}

}

private fun startServerLinking(userExternalId: String?) {

transactionHandler.linkUser(userExternalId).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 linking the user with the Okay SDK.

PsaManager provides us with a helper function that allows us to link users with SPS right from the Okay SDK. The structure of the method we can use is like so.

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

The LinkingScenarioListener must be implemented, as it allows us to listen for two possible events: onLinkingCompletedSuccessful and onLinkingFailed. We will be implementing this listener soon.

We will also need to implment the SpaStorage interface in our application. I think the easiest place to do this, is from one of our repositories(PreferenceRepo class in this case). Of course this is just for convenience.

Below is a typical example of what my PreferenceRepo class might 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" } }

This is a typical way to make a call to linkTenant() method.

// 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{

startServerLinking(preferenceRepo.externalId)

}

}

...

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(userExternalId: String?) {

transactionHandler.linkUser(userExternalId).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

From FCM you can receive push notification as a RemoteMessage object.

From this remoteMessage you can extract notificationData:

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

If "type" equals 10 then it is a "WakeUpNotification" and it's "data "JSON containing two fields:

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

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

The steps are pretty straight forward. We make a request to our server to begin our authorization. Our server will make a call to PSS, PSS in turn will send a push notification to our app with the current tenantId of our server and the current transaction sessionId field. Once we receive the push notification from Okay Servers we can now proceed by using the SDK's PsaManager.startAuthorizationActivity(activity: Activity, spaAuthorizationData :SpaAuthorizationData) method, passing in the current instance of our activity and an instance of SpaAuthorizationData class.

Starting an authorization begins with a simple request to your server like so. This is just a simple request 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(userExternalId: String?) {

transactionHandler.authorizeTransaction(userExternalId).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 authorization with PSS. Our application will receive a Push Notification that will be handled by our FirebaseMassagingService (This service is part of Firebase messaging if you are yet to setup Firebase, please see this documentation). In this illustration, 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{

startServerLinking(preferenceRepo.externalId)

}

authorizeButton.setOnClickListener {

startServerAuthorization(preferenceRepo.externalId)

}

}

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(userExternalId: String?) {

transactionHandler.authorizeTransaction(userExternalId).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 the Authorization process begins immediately, allowing Okay SDK to communicate with PSS.

8. PageTheme

PageTheme is a class (provided by the Okay SDK) that describes styling of authorization screens. If you want to customize the authorization screen provided by Okay SDK, you should create or extend PageTheme object, configure it's 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 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 pictures will help you to understand which key you need.

9. Ways to Trigger Authorization

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

9.1 With Activity

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

By triggering an authorization this way you must implement onActivityResult inside the activity you passed to PsaManager.startAuthorizationActivity(). The status of the authorization will be sent to this method notifying you if the authorization 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 - From the push notification.
  • String appPNS - Firebase instanceID
  • PageTheme pageTheme - Can be used for the Authorization UI customization Documentation (pass null if you don't need UI customization)
  • PsaType psaType - Use PsaType.OKAY
10. Client Settings
10.1 Mobile Client Settings

To use the Okay SDK, you need installationId and pubPss key. They are issued for every version.

Android:
PSMP Version: 1.0.3
Installation: 9990

Public PSS Keys

Note: Keys are encoded in PKCS#1 format.

Installation 9980

-----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-----

10.2 AuthData Types

// These are the following types of user response that may come from the mobile application:

Code | Value

-----|-------

101 | CANCEL

102 | PIN

103 | OK

10.3 Maven Artifacts Repository

While using bintray to distribute artifacts, use the following settings to add dependencies in your project.

Firstly, add the bintray repository to the repositories section in pom.xml:

<repositories> <repository> <snapshots> <enabled>false</enabled> </snapshots> <id>bintray-okaythis-maven</id> <name>bintray</name> <url>https://dl.bintray.com/okaythis/maven</url> </repository> </repositories>

Then add the multi-tenant-gateway-client dependency:

<dependency> <groupId>com.protectoria.pss</groupId> <artifactId>multi-tenant-gateway-client</artifactId> <version>1.0.3</version> </dependency>

The latest version is 1.0.3