adicionando enum de erros

This commit is contained in:
Ighor Moura 2025-07-18 17:16:48 -04:00
parent f53369428d
commit 06c9c4abea
6 changed files with 381 additions and 24 deletions

View File

@ -1,5 +1,40 @@
<component name="ProjectCodeStyleConfiguration"> <component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173"> <code_scheme name="Project" version="173">
<JavaCodeStyleSettings>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="" withSubpackages="true" static="false" module="true" />
<package name="android" withSubpackages="true" static="true" />
<package name="androidx" withSubpackages="true" static="true" />
<package name="com" withSubpackages="true" static="true" />
<package name="junit" withSubpackages="true" static="true" />
<package name="net" withSubpackages="true" static="true" />
<package name="org" withSubpackages="true" static="true" />
<package name="java" withSubpackages="true" static="true" />
<package name="javax" withSubpackages="true" static="true" />
<package name="" withSubpackages="true" static="true" />
<emptyLine />
<package name="android" withSubpackages="true" static="false" />
<emptyLine />
<package name="androidx" withSubpackages="true" static="false" />
<emptyLine />
<package name="com" withSubpackages="true" static="false" />
<emptyLine />
<package name="junit" withSubpackages="true" static="false" />
<emptyLine />
<package name="net" withSubpackages="true" static="false" />
<emptyLine />
<package name="org" withSubpackages="true" static="false" />
<emptyLine />
<package name="java" withSubpackages="true" static="false" />
<emptyLine />
<package name="javax" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
<emptyLine />
</value>
</option>
</JavaCodeStyleSettings>
<JetCodeStyleSettings> <JetCodeStyleSettings>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings> </JetCodeStyleSettings>

6
.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@ -14,11 +14,15 @@ android {
targetSdk = 36 targetSdk = 36
versionCode = 1 versionCode = 1
versionName = "1.0" versionName = "1.0"
buildConfigField ("String", "ACTIVATION_CODE", "\"\"")
buildConfigField ("String", "APPLICATION_TOKEN", "\"\"")
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }
buildTypes { buildTypes {
debug {
buildConfigField ("String", "APPLICATION_TOKEN", "\"mk_MbQ92RRHEOcGFRIf9/R1A\"")
}
release { release {
isMinifyEnabled = false isMinifyEnabled = false
proguardFiles( proguardFiles(
@ -43,6 +47,7 @@ android {
dependencies { dependencies {
implementation(files("libs/AditumSdkIntegration-2.3.6.67824-release.aar")) implementation(files("libs/AditumSdkIntegration-2.3.6.67824-release.aar"))
implementation("com.google.code.gson:gson:2.13.1")
implementation(libs.androidx.core.ktx) implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose) implementation(libs.androidx.activity.compose)

View File

@ -0,0 +1,42 @@
package com.example.mypos.data
object AditumError {
const val SERVICE_NOT_AVAILABLE = "SERVICE_NOT_AVAILABLE"
const val SERVICE_NOT_AVAILABLE_MESSAGE = "Failed to connect to Aditum SDK service"
const val SERVICE_NULL = "SERVICE_NULL"
const val SERVICE_NULL_MESSAGE = "Aditum SDK service is null"
const val INIT_RESPONSE_NULL = "INIT_RESPONSE_NULL"
const val INIT_RESPONSE_NULL_MESSAGE = "Init response is null"
const val INIT_ERROR = "INIT_ERROR"
const val INIT_ERROR_MESSAGE = "Initialization failed"
const val MERCHANT_DATA_NULL = "MERCHANT_DATA_NULL"
const val MERCHANT_DATA_NULL_MESSAGE = "Merchant data is null"
const val MERCHANT_DATA_ERROR = "MERCHANT_DATA_ERROR"
const val MERCHANT_DATA_ERROR_MESSAGE = "Failed to retrieve merchant data"
const val PAYMENT_RESPONSE_NULL = "PAYMENT_RESPONSE_NULL"
const val PAYMENT_RESPONSE_NULL_MESSAGE = "Payment response is null"
const val PAYMENT_ERROR = "PAYMENT_ERROR"
const val PAYMENT_ERROR_MESSAGE = "Payment processing failed"
const val INVALID_NSU = "INVALID_NSU"
const val INVALID_NSU_MESSAGE = "NSU cannot be null"
const val CONFIRM_ERROR = "CONFIRM_ERROR"
const val CONFIRM_ERROR_MESSAGE = "Transaction confirmation failed"
const val CANCEL_RESPONSE_NULL = "CANCEL_RESPONSE_NULL"
const val CANCEL_RESPONSE_NULL_MESSAGE = "Cancelation response is null"
const val CANCEL_ERROR = "CANCEL_ERROR"
const val CANCEL_ERROR_MESSAGE = "Cancelation processing failed"
const val DEACTIVATE_ERROR = "DEACTIVATE_ERROR"
const val DEACTIVATE_ERROR_MESSAGE = "Deactivation failed"
}

View File

@ -0,0 +1,231 @@
package com.example.mypos.services
import android.util.Log
import br.com.aditum.data.v2.enums.InstallmentType
import br.com.aditum.data.v2.enums.PayOperationType
import br.com.aditum.data.v2.enums.PaymentType
import br.com.aditum.data.v2.model.MerchantData
import br.com.aditum.data.v2.model.PinpadMessages
import br.com.aditum.data.v2.model.cancelation.CancelationRequest
import br.com.aditum.data.v2.model.cancelation.CancelationResponse
import br.com.aditum.data.v2.model.cancelation.CancelationResponseCallback
import br.com.aditum.data.v2.model.deactivation.DeactivationResponseCallback
import br.com.aditum.data.v2.model.init.InitRequest
import br.com.aditum.data.v2.model.init.InitResponse
import br.com.aditum.data.v2.model.init.InitResponseCallback
import br.com.aditum.data.v2.model.payment.PaymentRequest
import br.com.aditum.data.v2.model.payment.PaymentResponse
import br.com.aditum.data.v2.model.payment.PaymentResponseCallback
import br.com.aditum.data.v2.model.transactions.ConfirmTransactionCallback
import com.example.mypos.BuildConfig
import com.example.mypos.data.AditumError
import com.google.gson.Gson
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.util.UUID
class AditumSdkService(private val paymentApplication: PaymentApplication) {
companion object {
private const val TAG = "AditumSdkModule"
}
private val gson = Gson()
private val coroutineScope = CoroutineScope(Dispatchers.IO)
fun getName(): String = "AditumSdkModule"
fun initAditumSdk(
applicationName: String,
applicationVersion: String,
activationCode: String?,
resolve: (Boolean) -> Unit = {},
reject: (String, String?) -> Unit = { _, _ -> }
) {
coroutineScope.launch {
try {
if (!paymentApplication.ensureServiceConnected()) {
reject(AditumError.SERVICE_NOT_AVAILABLE, AditumError.SERVICE_NOT_AVAILABLE_MESSAGE)
return@launch
}
val pinpadMessages = PinpadMessages().apply {
mainMessage = applicationName
}
val initRequest = InitRequest().apply {
this.pinpadMessages = pinpadMessages
this.activationCode = if (BuildConfig.DEBUG) BuildConfig.ACTIVATION_CODE else activationCode
this.applicationName = applicationName
this.applicationVersion = applicationVersion
this.applicationToken = BuildConfig.APPLICATION_TOKEN
}
val callback = object : InitResponseCallback.Stub() {
override fun onResponse(initResponse: InitResponse?) {
if (initResponse != null) {
resolve(initResponse.initialized)
} else {
Log.e(TAG, "onResponse - initResponse is null")
reject(AditumError.INIT_RESPONSE_NULL, AditumError.INIT_RESPONSE_NULL_MESSAGE)
}
}
}
paymentApplication.communicationService?.init(initRequest, callback)
?: reject(AditumError.SERVICE_NULL, AditumError.SERVICE_NULL_MESSAGE)
} catch (e: Exception) {
reject(AditumError.INIT_ERROR, "${AditumError.INIT_ERROR_MESSAGE}: ${e.message}")
}
}
}
fun getMerchantData(resolve: (MerchantData) -> Unit = {}, reject: (String, String?) -> Unit = { _, _ -> }) {
coroutineScope.launch {
try {
if (!paymentApplication.ensureServiceConnected()) {
reject(AditumError.SERVICE_NOT_AVAILABLE, AditumError.SERVICE_NOT_AVAILABLE_MESSAGE)
return@launch
}
val merchantData: MerchantData? = paymentApplication.communicationService?.merchantData
if (merchantData != null) {
resolve(merchantData)
} else {
reject(AditumError.MERCHANT_DATA_NULL, AditumError.MERCHANT_DATA_NULL_MESSAGE)
}
} catch (e: Exception) {
reject(AditumError.MERCHANT_DATA_ERROR, "${AditumError.MERCHANT_DATA_ERROR_MESSAGE}: ${e.message}")
}
}
}
fun pay(
amount: Int,
installments: Int,
merchantChargeId: String?,
resolve: (Any) -> Unit = {},
reject: (String, String?) -> Unit = { _, _ -> }
) {
coroutineScope.launch {
try {
if (!paymentApplication.ensureServiceConnected()) {
reject(AditumError.SERVICE_NOT_AVAILABLE, AditumError.SERVICE_NOT_AVAILABLE_MESSAGE)
return@launch
}
val paymentRequest = PaymentRequest().apply {
operationType = PayOperationType.Authorization
paymentType = PaymentType.Credit
this.amount = amount.toLong()
this.merchantChargeId = merchantChargeId ?: UUID.randomUUID().toString()
currency = 986
allowContactless = true
manualEntry = false
installmentType = InstallmentType.Merchant
installmentNumber = installments
}
val callback = object : PaymentResponseCallback.Stub() {
override fun onResponse(paymentResponse: PaymentResponse?) {
if (paymentResponse != null) {
val json = gson.toJson(paymentResponse)
resolve(json)
} else {
Log.e(TAG, "onResponse - paymentResponse is null")
reject(AditumError.PAYMENT_RESPONSE_NULL, AditumError.PAYMENT_RESPONSE_NULL_MESSAGE)
}
}
}
paymentApplication.communicationService?.pay(paymentRequest, callback)
?: reject(AditumError.SERVICE_NULL, AditumError.SERVICE_NULL_MESSAGE)
} catch (e: Exception) {
reject(AditumError.PAYMENT_ERROR, "${AditumError.PAYMENT_ERROR_MESSAGE}: ${e.message}")
}
}
}
fun confirm(nsu: String?, resolve: (Boolean) -> Unit = {}, reject: (String, String?) -> Unit = { _, _ -> }) {
coroutineScope.launch {
try {
if (!paymentApplication.ensureServiceConnected()) {
reject(AditumError.SERVICE_NOT_AVAILABLE, AditumError.SERVICE_NOT_AVAILABLE_MESSAGE)
return@launch
}
if (nsu == null) {
reject(AditumError.INVALID_NSU, AditumError.INVALID_NSU_MESSAGE)
return@launch
}
val callback = object : ConfirmTransactionCallback.Stub() {
override fun onResponse(confirmed: Boolean) {
resolve(confirmed)
}
}
paymentApplication.communicationService?.confirmTransaction(nsu, callback)
?: reject(AditumError.SERVICE_NULL, AditumError.SERVICE_NULL_MESSAGE)
} catch (e: Exception) {
reject(AditumError.CONFIRM_ERROR, "${AditumError.CONFIRM_ERROR_MESSAGE}: ${e.message}")
}
}
}
fun cancel(nsu: String?, isReversal: Boolean, resolve: (Boolean) -> Unit = {}, reject: (String, String?) -> Unit = { _, _ -> }) {
coroutineScope.launch {
try {
if (!paymentApplication.ensureServiceConnected()) {
reject(AditumError.SERVICE_NOT_AVAILABLE, AditumError.SERVICE_NOT_AVAILABLE_MESSAGE)
return@launch
}
if (nsu == null) {
reject(AditumError.INVALID_NSU, AditumError.INVALID_NSU_MESSAGE)
return@launch
}
val cancelationRequest = CancelationRequest(nsu, isReversal)
val callback = object : CancelationResponseCallback.Stub() {
override fun onResponse(cancelationResponse: CancelationResponse?) {
if (cancelationResponse != null) {
resolve(cancelationResponse.canceled)
} else {
Log.e(TAG, "onResponse - cancelationResponse is null")
reject(AditumError.CANCEL_RESPONSE_NULL, AditumError.CANCEL_RESPONSE_NULL_MESSAGE)
}
}
}
paymentApplication.communicationService?.cancel(cancelationRequest, callback)
?: reject(AditumError.SERVICE_NULL, AditumError.SERVICE_NULL_MESSAGE)
} catch (e: Exception) {
reject(AditumError.CANCEL_ERROR, "${AditumError.CANCEL_ERROR_MESSAGE}: ${e.message}")
}
}
}
fun deactivate(resolve: (Boolean) -> Unit = {}, reject: (String, String?) -> Unit = { _, _ -> }) {
coroutineScope.launch {
try {
if (!paymentApplication.ensureServiceConnected()) {
reject(AditumError.SERVICE_NOT_AVAILABLE, AditumError.SERVICE_NOT_AVAILABLE_MESSAGE)
return@launch
}
val callback = object : DeactivationResponseCallback.Stub() {
override fun onResponse(status: Boolean) {
Log.d(TAG, "onDeactivationResponse - deactivationResponse: $status")
resolve(status)
}
}
paymentApplication.communicationService?.deactivate(callback)
?: reject(AditumError.SERVICE_NULL, AditumError.SERVICE_NULL_MESSAGE)
} catch (e: Exception) {
reject(AditumError.DEACTIVATE_ERROR, "${AditumError.DEACTIVATE_ERROR_MESSAGE}: ${e.message}")
}
}
}
}

View File

@ -8,19 +8,22 @@ import android.content.ServiceConnection
import android.os.Build import android.os.Build
import android.os.IBinder import android.os.IBinder
import android.util.Log import android.util.Log
import br.com.aditum.IAditumSdkService import br.com.aditum.IAditumSdkService
import br.com.aditum.data.v2.model.MerchantData import br.com.aditum.data.v2.model.MerchantData
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.withContext
class PaymentApplication : Application() { class PaymentApplication : Application() {
public val TAG = PaymentApplication::class.simpleName companion object {
private const val TAG = "PaymentApplication"
public val PACKAGE_BASE_NAME: String = "br.com.aditum" private const val PACKAGE_BASE_NAME = "br.com.aditum"
public val PACKAGE_NAME: String = PACKAGE_BASE_NAME + ".smartpostef" const val PACKAGE_NAME = "$PACKAGE_BASE_NAME.smartpostef"
public val ACTION_COMMUNICATION_SERVICE: String = PACKAGE_BASE_NAME + ".AditumSdkService" const val ACTION_COMMUNICATION_SERVICE = "$PACKAGE_BASE_NAME.AditumSdkService"
}
private val _isServiceConnectedFlow = MutableStateFlow(false) private val _isServiceConnectedFlow = MutableStateFlow(false)
val isServiceConnectedFlow: StateFlow<Boolean> = _isServiceConnectedFlow.asStateFlow() val isServiceConnectedFlow: StateFlow<Boolean> = _isServiceConnectedFlow.asStateFlow()
@ -36,7 +39,7 @@ class PaymentApplication : Application() {
get() = mAditumSdkService get() = mAditumSdkService
@Volatile @Volatile
public var merchantData: MerchantData? = null var merchantData: MerchantData? = null
private val mServiceConnection = object : ServiceConnection { private val mServiceConnection = object : ServiceConnection {
override fun onServiceConnected(componentName: ComponentName, service: IBinder) { override fun onServiceConnected(componentName: ComponentName, service: IBinder) {
@ -59,40 +62,75 @@ class PaymentApplication : Application() {
mServiceConnectionListener = listener mServiceConnectionListener = listener
} }
public interface OnServiceConnectionListener { interface OnServiceConnectionListener {
fun onServiceConnection(serviceConnected: Boolean) fun onServiceConnection(serviceConnected: Boolean)
} }
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
Log.d(TAG, "onCreate") Log.d(TAG, "onCreate")
startAditumSdkService()
} }
override fun onTerminate() { override fun onTerminate() {
super.onTerminate() super.onTerminate()
Log.d(TAG, "onTerminate") Log.d(TAG, "onTerminate")
} }
public fun startAditumSdkService() { fun startAditumSdkService() {
Log.d(TAG, "startAditumSdkService") Log.d(TAG, "startAditumSdkService")
val intent = Intent(ACTION_COMMUNICATION_SERVICE).apply {
val intent: Intent = Intent(ACTION_COMMUNICATION_SERVICE) setPackage(PACKAGE_NAME)
intent.setPackage(PACKAGE_NAME)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Log.d(TAG, "Android Oreo or higher: " + Build.VERSION.SDK_INT);
startForegroundService(intent);
} else {
Log.d(TAG, "Android Nougat or lower: " + Build.VERSION.SDK_INT);
startService(intent);
} }
bindService(intent, mServiceConnection, (BIND_AUTO_CREATE or CONTEXT_IGNORE_SECURITY)) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Log.d(TAG, "Android Oreo or higher: ${Build.VERSION.SDK_INT}")
startForegroundService(intent)
} else {
Log.d(TAG, "Android Nougat or lower: ${Build.VERSION.SDK_INT}")
startService(intent)
}
bindService(intent, mServiceConnection, BIND_AUTO_CREATE or CONTEXT_IGNORE_SECURITY)
Log.d(TAG, "startAditumSdkService - bindService") Log.d(TAG, "startAditumSdkService - bindService")
} }
suspend fun ensureServiceConnected(): Boolean = withContext(Dispatchers.IO) {
if (isServiceConnected && mAditumSdkService?.asBinder()?.isBinderAlive == true) {
Log.d(TAG, "Service already connected")
return@withContext true
}
Log.d(TAG, "Service not connected, attempting to reconnect...")
val intent = Intent(ACTION_COMMUNICATION_SERVICE).apply {
setPackage(PACKAGE_NAME)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent)
} else {
startService(intent)
}
val bound = bindService(
intent,
mServiceConnection,
BIND_AUTO_CREATE or CONTEXT_IGNORE_SECURITY
)
if (bound) {
repeat(30) {
delay(100)
if (isServiceConnected && mAditumSdkService?.asBinder()?.isBinderAlive == true) {
Log.d(TAG, "Service reconnected successfully")
return@withContext true
}
}
}
Log.e(TAG, "Failed to reconnect service")
return@withContext false
}
private fun setServiceConnected(isConnected: Boolean) { private fun setServiceConnected(isConnected: Boolean) {
Log.d(TAG, "setServiceConnected - isConnected: $isConnected") Log.d(TAG, "setServiceConnected - isConnected: $isConnected")
@ -102,4 +140,4 @@ class PaymentApplication : Application() {
mServiceConnectionListener?.onServiceConnection(mIsServiceConnected) mServiceConnectionListener?.onServiceConnection(mIsServiceConnected)
} }
} }
} }