From 491759ea914cb09ee881cb057198a6e542298cd4 Mon Sep 17 00:00:00 2001 From: lesclaz Date: Thu, 8 Feb 2024 18:13:24 -0500 Subject: [PATCH 1/7] add java compatibility --- .../cu/suitetecsa/sdkandroid/di/AppModule.kt | 6 +- .../presentation/balance/BalanceEvent.kt | 2 +- .../presentation/balance/BalanceScreen.kt | 62 +++--- .../presentation/balance/BalanceState.kt | 22 ++- .../presentation/balance/BalancesViewModel.kt | 176 +++++++++++------- .../sdk/android/SimCardCollector.java | 25 +++ .../sdk/android/SimCardCollectorImpl.java | 111 +++++++++++ .../cu/suitetecsa/sdk/android/SimCardsAPI.kt | 59 ------ .../java/cu/suitetecsa/sdk/android/Utils.kt | 42 ----- .../ConsultBalanceCallBack.java} | 20 +- .../sdk/android/balance/RequestCallback.java | 37 ++++ .../android/balance/UssdRequestSender.java | 42 +++++ .../balance/UssdRequestSenderImpl.java | 147 +++++++++++++++ .../android/balance/consult/UssdRequest.java | 22 +++ .../exception/UssdRequestException.java | 15 ++ .../balance/parser/BonusBalanceParser.java | 93 +++++++++ .../balance/parser/DailyDataParser.java | 52 ++++++ .../balance/parser/MailDataParser.java | 53 ++++++ .../balance/parser/MainBalanceParser.java | 107 +++++++++++ .../balance/parser/MainDataParser.java | 74 ++++++++ .../android/balance/parser/MainSmsParser.java | 51 +++++ .../balance/parser/MainVoiceParser.java | 51 +++++ .../balance/response/BonusBalance.java | 39 ++++ .../sdk/android/balance/response/Custom.java | 16 ++ .../android/balance/response/DataBalance.java | 11 ++ .../balance/response/MessagesBalance.java | 7 + .../balance/response/PrincipalBalance.java | 38 ++++ .../balance/response/UssdResponse.java | 9 + .../balance/response/VoiceBalance.java | 22 +++ .../sdk/android/domain/model/BonusCredit.kt | 12 -- .../sdk/android/domain/model/BonusData.kt | 15 -- .../sdk/android/domain/model/BonusDataCU.kt | 12 -- .../domain/model/BonusUnlimitedData.kt | 8 - .../sdk/android/domain/model/DailyData.kt | 9 - .../sdk/android/domain/model/MailData.kt | 9 - .../sdk/android/domain/model/MainBalance.kt | 24 --- .../sdk/android/domain/model/MainData.kt | 16 -- .../sdk/android/domain/model/MainSms.kt | 9 - .../sdk/android/domain/model/MainVoice.kt | 9 - .../sdk/android/domain/model/SimCard.kt | 20 -- .../sdk/android/framework/DateExtension.kt | 22 --- .../sdk/android/framework/DoubleExtension.kt | 19 -- .../sdk/android/framework/LongExtension.kt | 17 -- .../sdk/android/framework/SimCardCollector.kt | 25 --- .../android/framework/SimCardCollectorImpl.kt | 125 ------------- .../sdk/android/framework/SimCardExtension.kt | 55 ------ .../sdk/android/framework/StringExtension.kt | 49 ----- .../framework/UssdBalanceCommandExecutor.kt | 153 --------------- .../framework/UssdBalanceRequestExecutor.kt | 14 -- .../UssdBalanceRequestExecutorCallBack.kt | 34 ---- .../sdk/android/framework/UssdConsultType.kt | 36 ---- .../android/framework/UssdRequestException.kt | 8 - .../sdk/android/framework/UssdResponse.kt | 84 --------- .../framework/extensions/ParseBonusBalance.kt | 74 -------- .../framework/extensions/ParseDailyData.kt | 26 --- .../framework/extensions/ParseMailData.kt | 27 --- .../framework/extensions/ParseMainBalance.kt | 82 -------- .../framework/extensions/ParseMainData.kt | 41 ---- .../framework/extensions/ParseMainSms.kt | 23 --- .../framework/extensions/ParseMainVoice.kt | 27 --- .../sdk/android/kotlin/LongUtils.kt | 8 + .../sdk/android/kotlin/SimCardExtension.kt | 65 +++++++ .../sdk/android/model/BonusCredit.java | 4 + .../sdk/android/model/BonusData.java | 4 + .../sdk/android/model/BonusDataCU.java | 4 + .../sdk/android/model/BonusUnlimitedData.java | 4 + .../sdk/android/model/DailyData.java | 4 + .../sdk/android/model/MailData.java | 4 + .../sdk/android/model/MainBalance.java | 5 + .../sdk/android/model/MainData.java | 4 + .../suitetecsa/sdk/android/model/MainSms.java | 4 + .../sdk/android/model/MainVoice.java | 4 + .../suitetecsa/sdk/android/model/SimCard.java | 7 + .../sdk/android/utils/LongUtils.java | 53 ++++++ .../sdk/android/utils/SimCardUtils.java | 24 +++ .../sdk/android/utils/StringUtils.java | 41 ++++ 76 files changed, 1427 insertions(+), 1307 deletions(-) create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/SimCardCollector.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/SimCardCollectorImpl.java delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/SimCardsAPI.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/Utils.kt rename sdk-android/src/main/java/cu/suitetecsa/sdk/android/{framework/ConsultBalanceCallBack.kt => balance/ConsultBalanceCallBack.java} (55%) create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/RequestCallback.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/UssdRequestSender.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/UssdRequestSenderImpl.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/consult/UssdRequest.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/exception/UssdRequestException.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/BonusBalanceParser.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/DailyDataParser.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MailDataParser.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainBalanceParser.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainDataParser.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainSmsParser.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainVoiceParser.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/BonusBalance.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/Custom.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/DataBalance.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/MessagesBalance.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/PrincipalBalance.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/UssdResponse.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/VoiceBalance.java delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/BonusCredit.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/BonusData.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/BonusDataCU.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/BonusUnlimitedData.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/DailyData.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/MailData.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/MainBalance.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/MainData.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/MainSms.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/MainVoice.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/SimCard.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/DateExtension.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/DoubleExtension.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/LongExtension.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/SimCardCollector.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/SimCardCollectorImpl.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/SimCardExtension.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/StringExtension.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdBalanceCommandExecutor.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdBalanceRequestExecutor.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdBalanceRequestExecutorCallBack.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdConsultType.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdRequestException.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdResponse.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseBonusBalance.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseDailyData.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseMailData.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseMainBalance.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseMainData.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseMainSms.kt delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseMainVoice.kt create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/LongUtils.kt create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/SimCardExtension.kt create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/BonusCredit.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/BonusData.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/BonusDataCU.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/BonusUnlimitedData.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/DailyData.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/MailData.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/MainBalance.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/MainData.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/MainSms.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/MainVoice.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/SimCard.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/LongUtils.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/SimCardUtils.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/StringUtils.java diff --git a/app/src/main/java/cu/suitetecsa/sdkandroid/di/AppModule.kt b/app/src/main/java/cu/suitetecsa/sdkandroid/di/AppModule.kt index 12c141e..565537a 100644 --- a/app/src/main/java/cu/suitetecsa/sdkandroid/di/AppModule.kt +++ b/app/src/main/java/cu/suitetecsa/sdkandroid/di/AppModule.kt @@ -1,7 +1,7 @@ package cu.suitetecsa.sdkandroid.di import android.content.Context -import cu.suitetecsa.sdk.android.SimCardsAPI +import cu.suitetecsa.sdk.android.SimCardCollector import cu.suitetecsa.sdkandroid.data.source.PreferenceDataSource import dagger.Module import dagger.Provides @@ -21,6 +21,6 @@ class AppModule { @Provides @Singleton - fun provideSimCardApi(@ApplicationContext context: Context): SimCardsAPI = - SimCardsAPI.Builder(context).build() + fun provideSimCardApi(@ApplicationContext context: Context): SimCardCollector = + SimCardCollector.Builder().build(context) } diff --git a/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalanceEvent.kt b/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalanceEvent.kt index db45fc5..371d87d 100644 --- a/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalanceEvent.kt +++ b/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalanceEvent.kt @@ -1,6 +1,6 @@ package cu.suitetecsa.sdkandroid.presentation.balance -import cu.suitetecsa.sdk.android.domain.model.SimCard +import cu.suitetecsa.sdk.android.model.SimCard sealed class BalanceEvent { data object UpdateBalance : BalanceEvent() diff --git a/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalanceScreen.kt b/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalanceScreen.kt index fc1a8df..fef8280 100644 --- a/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalanceScreen.kt +++ b/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalanceScreen.kt @@ -36,13 +36,14 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel -import cu.suitetecsa.sdk.android.domain.model.BonusDataCU -import cu.suitetecsa.sdk.android.domain.model.MainData -import cu.suitetecsa.sdk.android.domain.model.MainSms -import cu.suitetecsa.sdk.android.domain.model.MainVoice -import cu.suitetecsa.sdk.android.domain.model.SimCard -import cu.suitetecsa.sdk.android.framework.toSizeString -import cu.suitetecsa.sdk.android.framework.toTimeString +import cu.suitetecsa.sdk.android.kotlin.asRemainingDays +import cu.suitetecsa.sdk.android.kotlin.asSizeString +import cu.suitetecsa.sdk.android.kotlin.asTimeString +import cu.suitetecsa.sdk.android.model.BonusDataCU +import cu.suitetecsa.sdk.android.model.MainData +import cu.suitetecsa.sdk.android.model.MainSms +import cu.suitetecsa.sdk.android.model.MainVoice +import cu.suitetecsa.sdk.android.model.SimCard import cu.suitetecsa.sdkandroid.R import cu.suitetecsa.sdkandroid.presentation.balance.component.Spinner import cu.suitetecsa.sdkandroid.ui.theme.SDKAndroidTheme @@ -107,6 +108,7 @@ fun BalanceScreen( } else { Text(text = "Not supported") } + Text(text = state.errorText ?: "") } } @@ -168,11 +170,11 @@ fun PlansSection(state: BalanceState) { ) { state.data?.let { data -> val dataCount = if (data.data != null && data.dataLte != null) { - "${data.data!!.toSizeString()} + ${data.dataLte!!.toSizeString()} LTE" + "${data.data!!.asSizeString} + ${data.dataLte!!.asSizeString} LTE" } else if (data.data != null) { - data.data!!.toSizeString() + data.data!!.asSizeString } else { - "${data.dataLte!!.toSizeString()} LTE" + "${data.dataLte!!.asSizeString} LTE" } DataPlan( planTitle = "Datos", @@ -183,29 +185,29 @@ fun PlansSection(state: BalanceState) { state.voice?.let { voice -> DataPlan( planTitle = "Voz", - dataCount = "${voice.mainVoice.toTimeString()} MIN", + dataCount = voice.seconds.asTimeString, dataExpire = voice.remainingDays?.let { "$it días" } ) } state.sms?.let { sms -> DataPlan( planTitle = "SMS", - dataCount = "${sms.mainSms} SMS", + dataCount = "${sms.sms} SMS", dataExpire = sms.remainingDays?.let { "$it días" } ) } state.dailyData?.let { dailyData -> DataPlan( planTitle = "Bolsa diaria", - dataCount = dailyData.data.toSizeString(), - dataExpire = dailyData.remainingHours?.let { "$it horas" } + dataCount = dailyData.data.asSizeString, + dataExpire = dailyData.remainingHours()?.let { "$it horas" } ) } state.mailData?.let { mailData -> DataPlan( planTitle = "Bolsa correo", - dataCount = mailData.data.toSizeString(), - dataExpire = mailData.remainingDays?.let { "$it días" } + dataCount = mailData.data.asSizeString, + dataExpire = mailData.remainingDays()?.let { "$it días" } ) } } @@ -222,38 +224,38 @@ fun BonusSection(state: BalanceState) { state.bonusCredit?.let { bonusCredit -> DataPlan( planTitle = "Saldo", - dataCount = "$%.2f CUP".format(bonusCredit.credit), - dataExpire = bonusCredit.bonusCreditDueDate + dataCount = "$%.2f CUP".format(bonusCredit.balance), + dataExpire = "${bonusCredit.dueDate.asRemainingDays} dias" ) } state.bonusData?.let { bonusData -> val dataCount = - if (bonusData.bonusDataCount != null && bonusData.bonusDataCountLte != null) { - "${bonusData.bonusDataCount!!.toSizeString()} + " + - "${bonusData.bonusDataCountLte!!.toSizeString()} LTE" - } else if (bonusData.bonusDataCount != null) { - bonusData.bonusDataCount!!.toSizeString() + if (bonusData.data != null && bonusData.dataLte != null) { + "${bonusData.data!!.asSizeString} + " + + "${bonusData.dataLte!!.asSizeString} LTE" + } else if (bonusData.data != null) { + bonusData.data!!.asSizeString } else { - "${bonusData.bonusDataCountLte!!.toSizeString()} LTE" + "${bonusData.dataLte!!.asSizeString} LTE" } DataPlan( planTitle = "Datos", dataCount = dataCount, - dataExpire = bonusData.bonusDataDueDate + dataExpire = "${bonusData.dueDate.asRemainingDays} dias" ) } state.bonusDataCU?.let { bonusDataCU -> DataPlan( planTitle = "Datos CU", - dataCount = bonusDataCU.bonusDataCuCount.toSizeString(), - dataExpire = bonusDataCU.bonusDataCuDueDate + dataCount = bonusDataCU.data.asSizeString, + dataExpire = "${bonusDataCU.dueDate.asRemainingDays} dias" ) } state.bonusUnlimitedData?.let { bonusUnlimitedData -> DataPlan( planTitle = "Datos Ilimitados", dataCount = "12:00 a.m -> 7:00 a.m", - dataExpire = bonusUnlimitedData.bonusUnlimitedDataDueDate + dataExpire = "${bonusUnlimitedData.dueDate.asRemainingDays} dias" ) } } @@ -280,8 +282,8 @@ private fun BalanceInfoPreviewDark() { balance = 123.45f, activeUntil = "10/10/2022", mainBalanceDueDate = "10/10/2022", - data = MainData(false, 8345369725.0, 29376382496.0, 25), - bonusDataCU = BonusDataCU(236975200.0, "10/10/2022"), + data = MainData(false, 8345369725, 29376382496, 25), + bonusDataCU = BonusDataCU(236975200, 55665L), voice = MainVoice(586314L, 25), sms = MainSms(50, 25) ) diff --git a/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalanceState.kt b/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalanceState.kt index f1eecb9..d40270f 100644 --- a/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalanceState.kt +++ b/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalanceState.kt @@ -1,15 +1,16 @@ package cu.suitetecsa.sdkandroid.presentation.balance -import cu.suitetecsa.sdk.android.domain.model.BonusCredit -import cu.suitetecsa.sdk.android.domain.model.BonusData -import cu.suitetecsa.sdk.android.domain.model.BonusDataCU -import cu.suitetecsa.sdk.android.domain.model.BonusUnlimitedData -import cu.suitetecsa.sdk.android.domain.model.DailyData -import cu.suitetecsa.sdk.android.domain.model.MailData -import cu.suitetecsa.sdk.android.domain.model.MainData -import cu.suitetecsa.sdk.android.domain.model.MainSms -import cu.suitetecsa.sdk.android.domain.model.MainVoice -import cu.suitetecsa.sdk.android.domain.model.SimCard +import cu.suitetecsa.sdk.android.model.BonusCredit +import cu.suitetecsa.sdk.android.model.BonusData +import cu.suitetecsa.sdk.android.model.BonusDataCU +import cu.suitetecsa.sdk.android.model.BonusUnlimitedData +import cu.suitetecsa.sdk.android.model.DailyData +import cu.suitetecsa.sdk.android.model.MailData +import cu.suitetecsa.sdk.android.model.MainData +import cu.suitetecsa.sdk.android.model.MainSms +import cu.suitetecsa.sdk.android.model.MainVoice +import cu.suitetecsa.sdk.android.model.SimCard + data class BalanceState( val currentSimCard: SimCard? = null, @@ -29,4 +30,5 @@ data class BalanceState( val loading: Boolean = false, val consultMessage: String? = null, val error: String? = null, + val errorText: String? = null, ) diff --git a/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalancesViewModel.kt b/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalancesViewModel.kt index 1b3c3c9..85b76f9 100644 --- a/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalancesViewModel.kt +++ b/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalancesViewModel.kt @@ -9,16 +9,29 @@ import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import cu.suitetecsa.sdk.android.SimCardsAPI -import cu.suitetecsa.sdk.android.domain.model.MainData -import cu.suitetecsa.sdk.android.domain.model.MainSms -import cu.suitetecsa.sdk.android.domain.model.MainVoice -import cu.suitetecsa.sdk.android.domain.model.SimCard -import cu.suitetecsa.sdk.android.framework.ConsultBalanceCallBack -import cu.suitetecsa.sdk.android.framework.UssdConsultType -import cu.suitetecsa.sdk.android.framework.UssdResponse -import cu.suitetecsa.sdk.android.framework.consultBalance -import cu.suitetecsa.sdk.android.framework.ussdExecute +import cu.suitetecsa.sdk.android.SimCardCollector +import cu.suitetecsa.sdk.android.balance.ConsultBalanceCallBack +import cu.suitetecsa.sdk.android.balance.consult.UssdRequest +import cu.suitetecsa.sdk.android.balance.consult.UssdRequest.BONUS_BALANCE +import cu.suitetecsa.sdk.android.balance.consult.UssdRequest.CUSTOM +import cu.suitetecsa.sdk.android.balance.consult.UssdRequest.DATA_BALANCE +import cu.suitetecsa.sdk.android.balance.consult.UssdRequest.MESSAGES_BALANCE +import cu.suitetecsa.sdk.android.balance.consult.UssdRequest.PRINCIPAL_BALANCE +import cu.suitetecsa.sdk.android.balance.consult.UssdRequest.VOICE_BALANCE +import cu.suitetecsa.sdk.android.balance.response.BonusBalance +import cu.suitetecsa.sdk.android.balance.response.Custom +import cu.suitetecsa.sdk.android.balance.response.DataBalance +import cu.suitetecsa.sdk.android.balance.response.MessagesBalance +import cu.suitetecsa.sdk.android.balance.response.PrincipalBalance +import cu.suitetecsa.sdk.android.balance.response.UssdResponse +import cu.suitetecsa.sdk.android.balance.response.VoiceBalance +import cu.suitetecsa.sdk.android.kotlin.asDateString +import cu.suitetecsa.sdk.android.kotlin.consultBalance +import cu.suitetecsa.sdk.android.kotlin.ussdExecute +import cu.suitetecsa.sdk.android.model.MainData +import cu.suitetecsa.sdk.android.model.MainSms +import cu.suitetecsa.sdk.android.model.MainVoice +import cu.suitetecsa.sdk.android.model.SimCard import cu.suitetecsa.sdkandroid.data.source.PreferenceDataSource import cu.suitetecsa.sdkandroid.domain.model.Preferences import dagger.hilt.android.lifecycle.HiltViewModel @@ -31,7 +44,7 @@ import javax.inject.Inject @HiltViewModel class BalancesViewModel @Inject constructor( private val preferenceDataSource: PreferenceDataSource, - private val simCardsAPI: SimCardsAPI, + private val simCardsCollector: SimCardCollector, ) : ViewModel() { private val preferences: StateFlow = preferenceDataSource.preferences() .stateIn( @@ -43,22 +56,25 @@ class BalancesViewModel @Inject constructor( get() = preferences.value.currentSimCardId private val simCards: List @SuppressLint("MissingPermission") - get() = simCardsAPI.getSimCards() + get() = simCardsCollector.collect() private val currentSimCard: SimCard? get() { return if (currentSimCardId.isNotBlank()) { simCards.firstOrNull { - it.serialNumber == preferences.value.currentSimCardId + it.serialNumber() == preferences.value.currentSimCardId }.let { it ?: simCards.firstOrNull() } - } else { simCards.firstOrNull() } + } else { + simCards.firstOrNull() + } } - private val _state = mutableStateOf(BalanceState(currentSimCard = currentSimCard, simCards = simCards)) + private val _state = + mutableStateOf(BalanceState(currentSimCard = currentSimCard, simCards = simCards)) val state: State get() = _state var canUpdate = true private set - var consultType: UssdConsultType? = null + var consultType: UssdRequest? = null private set @SuppressLint("MissingPermission", "NewApi") @@ -73,10 +89,12 @@ class BalancesViewModel @Inject constructor( } } } + is BalanceEvent.ChangeSimCard -> { viewModelScope.launch { preferenceDataSource.updateCurrentSimCardId(event.simCard.serialNumber) - _state.value = BalanceState(currentSimCard = currentSimCard, simCards = simCards) + _state.value = + BalanceState(currentSimCard = currentSimCard, simCards = simCards) } } @@ -95,26 +113,27 @@ class BalancesViewModel @Inject constructor( private fun updateBalance(simCard: SimCard) { simCard.consultBalance( object : ConsultBalanceCallBack { - override fun onRequesting(consultType: UssdConsultType) { - this@BalancesViewModel.consultType = consultType - val consultMessage = when (consultType) { - UssdConsultType.BonusBalance -> "Consultando Bonos" - UssdConsultType.DataBalance -> "Consultando Datos" - UssdConsultType.MessagesBalance -> "Consultando SMS" - UssdConsultType.PrincipalBalance -> "Consultando Saldo" - UssdConsultType.VoiceBalance -> "Consultando Minutos" - is UssdConsultType.Custom -> "" + override fun onRequesting(request: UssdRequest) { + this@BalancesViewModel.consultType = request + val consultMessage = when (request) { + BONUS_BALANCE -> "Consultando Bonos" + UssdRequest.DATA_BALANCE -> "Consultando Datos" + UssdRequest.MESSAGES_BALANCE -> "Consultando SMS" + UssdRequest.PRINCIPAL_BALANCE -> "Consultando Saldo" + UssdRequest.VOICE_BALANCE -> "Consultando Minutos" + UssdRequest.CUSTOM -> "" } - _state.value = _state.value.copy( - consultMessage = consultMessage - ) + _state.value = _state.value.copy(consultMessage = consultMessage) } - override fun onSuccess(ussdResponse: UssdResponse) { - when (ussdResponse) { - is UssdResponse.BonusBalance -> { + override fun onSuccess( + request: UssdRequest, + ussdResponse: UssdResponse + ) { + when (request) { + BONUS_BALANCE -> { _state.value = _state.value.copy( - bonusCredit = ussdResponse.credit, + bonusCredit = (ussdResponse as BonusBalance).credit, bonusData = ussdResponse.data, bonusDataCU = ussdResponse.dataCu, bonusUnlimitedData = ussdResponse.unlimitedData, @@ -125,54 +144,58 @@ class BalancesViewModel @Inject constructor( ) canUpdate = true } - is UssdResponse.DataBalance -> { + + DATA_BALANCE -> { _state.value = _state.value.copy( data = MainData( - usageBasedPricing = ussdResponse.usageBasedPricing, - data = ussdResponse.data, - dataLte = ussdResponse.dataLte, - remainingDays = ussdResponse.remainingDays + (ussdResponse as DataBalance).usageBasedPricing, + ussdResponse.data(), + ussdResponse.dataLte(), + ussdResponse.remainingDays() ), - mailData = ussdResponse.mailData, - dailyData = ussdResponse.dailyData + mailData = ussdResponse.mailData(), + dailyData = ussdResponse.dailyData() ) } - is UssdResponse.MessagesBalance -> { + + MESSAGES_BALANCE -> { _state.value = _state.value.copy( sms = MainSms( - mainSms = ussdResponse.count, - remainingDays = ussdResponse.remainingDays + (ussdResponse as MessagesBalance).sms(), + ussdResponse.remainingDays() ) ) } - is UssdResponse.PrincipalBalance -> { + + PRINCIPAL_BALANCE -> { _state.value = _state.value.copy( - balance = ussdResponse.credit, - activeUntil = ussdResponse.activeUntil, - mainBalanceDueDate = ussdResponse.dueDate, + balance = (ussdResponse as PrincipalBalance).balance.toFloat(), + activeUntil = ussdResponse.activeUntil.asDateString, + mainBalanceDueDate = ussdResponse.dueDate.asDateString, ) } - is UssdResponse.VoiceBalance -> { + + VOICE_BALANCE -> { _state.value = _state.value.copy( voice = MainVoice( - mainVoice = ussdResponse.time, - remainingDays = ussdResponse.remainingDays + (ussdResponse as VoiceBalance).time, + ussdResponse.remainingDays ) ) } - is UssdResponse.Custom -> {} + + else -> {} } } override fun onFailure(throwable: Throwable) { throwable.printStackTrace() - if (consultType is UssdConsultType.BonusBalance) { - _state.value = _state.value.copy( - consultMessage = null, - loading = false, - ) - canUpdate = true - } + _state.value = _state.value.copy( + errorText = throwable.message, + consultMessage = null, + loading = false, + ) + canUpdate = true } } ) @@ -183,34 +206,46 @@ class BalancesViewModel @Inject constructor( private fun turnUsageBasedPricing(isActive: Boolean) { val ussdCode = if (!isActive) { "*133*1*1*2${Uri.parse("#")}" - } else { "*133*1*1*1${Uri.parse("#")}" } + } else { + "*133*1*1*1${Uri.parse("#")}" + } currentSimCard?.also { it.ussdExecute( ussdCode, object : ConsultBalanceCallBack { - override fun onRequesting(consultType: UssdConsultType) { + override fun onRequesting(request: UssdRequest) { _state.value = _state.value.copy( consultMessage = if (!isActive) { "Desactivando TPC" - } else { "Activando TPC" } + } else { + "Activando TPC" + } ) } - override fun onSuccess(ussdResponse: UssdResponse) { - when (ussdResponse) { - is UssdResponse.Custom -> { - if (ussdResponse.response == UssdResponse.PROCESSING_RESPONSE) { + override fun onSuccess( + request: UssdRequest, + ussdResponse: UssdResponse + ) { + when (request) { + CUSTOM -> { + if ((ussdResponse as Custom).response == UssdResponse.PROCESSING_RESPONSE) { _state.value.data?.let { data -> _state.value = _state.value.copy( - data = data.copy(usageBasedPricing = isActive) + data = MainData( + isActive, + data.data, + data.dataLte, + data.remainingDays + ) ) } ?: run { _state.value = _state.value.copy( data = MainData( - usageBasedPricing = isActive, - data = null, - dataLte = null, - remainingDays = null + isActive, + null, + null, + null ) ) } @@ -221,6 +256,7 @@ class BalancesViewModel @Inject constructor( ) canUpdate = true } + else -> {} } } diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/SimCardCollector.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/SimCardCollector.java new file mode 100644 index 0000000..7a19bed --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/SimCardCollector.java @@ -0,0 +1,25 @@ +package cu.suitetecsa.sdk.android; + +import android.content.Context; + +import java.util.List; + +import cu.suitetecsa.sdk.android.model.SimCard; + +/** + * Interface for collecting SIM card information. + */ +public interface SimCardCollector { + /** + * Collects the SIM card information. + * + * @return The list of SIM cards. + */ + List collect(); + + class Builder { + public SimCardCollector build(Context context) { + return new SimCardCollectorImpl(context); + } + } +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/SimCardCollectorImpl.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/SimCardCollectorImpl.java new file mode 100644 index 0000000..db2dd2d --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/SimCardCollectorImpl.java @@ -0,0 +1,111 @@ +package cu.suitetecsa.sdk.android; + +import android.Manifest; +import android.content.Context; +import android.os.Build; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresPermission; + +import java.util.ArrayList; +import java.util.List; + +import cu.suitetecsa.sdk.android.model.SimCard; +import cz.mroczis.netmonster.core.factory.NetMonsterFactory; + +/** + * Implementation of the SimCardCollector interface for collecting SIM card information. + */ +class SimCardCollectorImpl implements SimCardCollector { + private final Context context; + + SimCardCollectorImpl(Context context) { + this.context = context; + } + + /** + * Retrieves the list of SubscriptionInfo objects for active subscriptions. + * + * @param context The application context. + * @return The list of SubscriptionInfo objects. + */ + @RequiresPermission(Manifest.permission.READ_PHONE_STATE) + private List getSubscriptionInfoList(@NonNull Context context) { + SubscriptionManager subscriptionManager = ((SubscriptionManager) context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE)); + return subscriptionManager.getActiveSubscriptionInfoList(); + } + + /** + * Converts a list of SubscriptionInfo objects to a list of SimCard objects. + * + * @param subscriptionInfoList The list of SubscriptionInfo objects. + * @return The list of SimCard objects. + */ + @NonNull + private List getSimCardsFromSubscriptionInfoList(@NonNull List subscriptionInfoList) { + List simCards = new ArrayList<>(); + for (SubscriptionInfo subscribedNetwork : subscriptionInfoList) { + TelephonyManager telephonyManager = null; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + if (telephonyManager != null) { + telephonyManager = telephonyManager.createForSubscriptionId(subscribedNetwork.getSubscriptionId()); + } + } + simCards.add(new SimCard( + String.valueOf(subscribedNetwork.getSubscriptionId()), + "", + subscribedNetwork.getSimSlotIndex(), + subscribedNetwork.getSubscriptionId(), + telephonyManager + )); + } + return simCards; + } + + /** + * Retrieves the list of SimCard objects using NetMonster library. + * + * @param context The application context. + * @return The list of SimCard objects. + */ + @NonNull + @RequiresPermission( + allOf = {Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.ACCESS_COARSE_LOCATION, + Manifest.permission.READ_PHONE_STATE} + ) + private List getSimCardsFromNetMonster(Context context) { + SubscriptionManager subscriptionManager = (SubscriptionManager) NetMonsterFactory.INSTANCE.getSubscription(context); + List subscriptionInfoList = subscriptionManager.getActiveSubscriptionInfoList(); + + return getSimCardsFromSubscriptionInfoList(subscriptionInfoList); + } + + /** + * Collects the SIM card information. + * + * @return The list of SIM cards. + */ + @RequiresPermission( + allOf = {Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.ACCESS_COARSE_LOCATION, + Manifest.permission.READ_PHONE_STATE} + ) + @Override + public List collect() { + List simCards = new ArrayList<>(); + + List subscriptionInfoList = getSubscriptionInfoList(context); + if (!subscriptionInfoList.isEmpty()) { + simCards.addAll(getSimCardsFromSubscriptionInfoList(subscriptionInfoList)); + } else { + simCards.addAll(getSimCardsFromNetMonster(context)); + } + + return simCards; + } +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/SimCardsAPI.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/SimCardsAPI.kt deleted file mode 100644 index a10065b..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/SimCardsAPI.kt +++ /dev/null @@ -1,59 +0,0 @@ -package cu.suitetecsa.sdk.android - -import android.Manifest -import android.content.Context -import androidx.annotation.RequiresPermission -import cu.suitetecsa.sdk.android.domain.model.SimCard -import cu.suitetecsa.sdk.android.framework.SimCardCollector -import cu.suitetecsa.sdk.android.framework.SimCardCollectorImpl - -/** - * API for retrieving SIM card information. - * - * @property simCardCollector The SIM card collector used to retrieve the information. - */ -class SimCardsAPI private constructor(private val simCardCollector: SimCardCollector) { - - /** - * Retrieves the list of SIM cards installed on the device. - * - * @return The list of SIM cards. - */ - - @RequiresPermission( - allOf = [ - Manifest.permission.ACCESS_FINE_LOCATION, - Manifest.permission.ACCESS_COARSE_LOCATION, - Manifest.permission.READ_PHONE_STATE - ] - ) - fun getSimCards(): List { - return simCardCollector.collect() - } - - /** - * Builder for constructing an instance of SimCardsAPI. - * - * @property context The application context. - */ - class Builder(private val context: Context) { - private var simCardCollector: SimCardCollector? = null - - /** - * Sets the custom SIM card collector. - * - * @param dataSource The custom SIM card collector. - * @return The updated Builder. - */ - fun withDataSource(dataSource: SimCardCollector): Builder = - also { it.simCardCollector = dataSource } - - /** - * Builds an instance of SimCardsAPI. - * - * @return The instance of SimCardsAPI. - */ - fun build(): SimCardsAPI = - SimCardsAPI(simCardCollector ?: SimCardCollectorImpl(context)) - } -} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/Utils.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/Utils.kt deleted file mode 100644 index 370e356..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/Utils.kt +++ /dev/null @@ -1,42 +0,0 @@ -package cu.suitetecsa.sdk.android - -import android.content.Context -import android.content.Intent -import android.net.Uri -import android.os.Build -import cu.suitetecsa.sdk.android.domain.model.SimCard - -object Utils { -// private val simSlotName = listOf( -// "extra_asus_dial_use_dualsim", -// "com.android.phone.extra.slot", -// "slot", -// "simslot", -// "sim_slot", -// "subscription", -// "Subscription", -// "phone", -// "com.android.phone.DialingMode", -// "simSlot", -// "slot_id", -// "simId", -// "simnum", -// "phone_type", -// "slotId", -// "slotIdx" -// ) - - fun makeCall(context: Context, phoneNumber: String, simCard: SimCard) { - val uri = Uri.parse("tel:${phoneNumber}") - val intent = Intent(Intent.ACTION_CALL, uri) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - intent.putExtra("android.telecom.extra.PHONE_ACCOUNT_HANDLE", simCard.subscriptionId.toString()) - } else { - intent.putExtra("con.android.phone.extra.PHONE_ACCOUNT_HANDLE", simCard.subscriptionId.toString()) - } - - intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK - context.startActivity(intent) - } -} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/ConsultBalanceCallBack.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/ConsultBalanceCallBack.java similarity index 55% rename from sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/ConsultBalanceCallBack.kt rename to sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/ConsultBalanceCallBack.java index 3c4db5f..0871ddd 100644 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/ConsultBalanceCallBack.kt +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/ConsultBalanceCallBack.java @@ -1,32 +1,36 @@ -package cu.suitetecsa.sdk.android.framework +package cu.suitetecsa.sdk.android.balance; + +import cu.suitetecsa.sdk.android.balance.consult.UssdRequest; +import cu.suitetecsa.sdk.android.balance.response.UssdResponse; /** * Callback interface for USSD balance requests. - * + *

* This interface defines three callback functions that handle the different stages of a USSD balance request: * - `onRequesting`: Called when a USSD request is being sent. * - `onSuccess`: Called when a USSD response is received successfully. * - `onFailure`: Called when an error occurs during the USSD request. */ -interface ConsultBalanceCallBack { +public interface ConsultBalanceCallBack { /** * Called when a USSD request is being sent. * - * @param consultType The type of USSD consult being requested. + * @param request The type of USSD consult being requested. */ - fun onRequesting(consultType: UssdConsultType) + void onRequesting(UssdRequest request); /** * Called when a USSD response is received successfully. * - * @param ussdResponse The USSD response received. + * @param request The type of USSD consult being requested. + * @param response The USSD response received. */ - fun onSuccess(ussdResponse: UssdResponse) + void onSuccess(UssdRequest request, UssdResponse response); /** * Called when an error occurs during the USSD request. * * @param throwable The throwable representing the error. */ - fun onFailure(throwable: Throwable) + void onFailure(Throwable throwable); } diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/RequestCallback.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/RequestCallback.java new file mode 100644 index 0000000..50a3227 --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/RequestCallback.java @@ -0,0 +1,37 @@ +package cu.suitetecsa.sdk.android.balance; + +import android.telephony.TelephonyManager; + +import cu.suitetecsa.sdk.android.balance.consult.UssdRequest; +import cu.suitetecsa.sdk.android.balance.response.UssdResponse; + +/** + * Interfaz de devolución de llamada para la ejecución de solicitudes de saldo USSD + */ +public interface RequestCallback { + /** + * Método para obtener la instancia de TelephonyManager asociada con la solicitud de saldo USSD + * @return a TelephonyManager instance + */ + TelephonyManager getTelephonyManager(); + + /** + * Método de devolución de llamada invocado cuando se realiza una solicitud de saldo USSD + * @param ussdRequest a UssdRequest instance + */ + void onRequesting(UssdRequest ussdRequest); + + /** + * Método de devolución de llamada invocado cuando una solicitud de saldo USSD tiene éxito + * + * @param request a UssdRequest instance + * @param response a UssdResponse instance + */ + void onSuccess(UssdRequest request, UssdResponse response); + + /** + * Método de devolución de llamada invocado cuando una solicitud de saldo USSD falla + * @param throwable a Throwable instance + */ + void onFailure(Throwable throwable); +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/UssdRequestSender.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/UssdRequestSender.java new file mode 100644 index 0000000..5ddf873 --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/UssdRequestSender.java @@ -0,0 +1,42 @@ +package cu.suitetecsa.sdk.android.balance; + +import android.os.Build; + +import androidx.annotation.RequiresApi; +import androidx.annotation.RequiresPermission; + +/** + * Interfaz para ejecutar una solicitud de saldo USSD + */ +public interface UssdRequestSender { + /** + * Método para ejecutar una solicitud de saldo USSD con el callback proporcionado + * @param callback a RequestCallback instance + */ + @RequiresApi(Build.VERSION_CODES.O) + @RequiresPermission(android.Manifest.permission.CALL_PHONE) + void send(RequestCallback callback); + + /** + * Método para ejecutar una solicitud de saldo USSD con el código USSD y el callback proporcionados + * @param ussdCode ussdCode to send request + * @param callback a RequestCallback instance + */ + @RequiresApi(Build.VERSION_CODES.O) + @RequiresPermission(android.Manifest.permission.CALL_PHONE) + void send(String ussdCode, RequestCallback callback); + + + class Builder { + private Long DELAY_MS; + + public Builder withDelay(long delay) { + this.DELAY_MS = delay; + return this; + } + + public UssdRequestSender build() { + return new UssdRequestSenderImpl(DELAY_MS != null ? DELAY_MS : 2000L); + } + } +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/UssdRequestSenderImpl.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/UssdRequestSenderImpl.java new file mode 100644 index 0000000..f323c0c --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/UssdRequestSenderImpl.java @@ -0,0 +1,147 @@ +package cu.suitetecsa.sdk.android.balance; + +import static cu.suitetecsa.sdk.android.balance.consult.UssdRequest.BONUS_BALANCE; +import static cu.suitetecsa.sdk.android.balance.consult.UssdRequest.CUSTOM; +import static cu.suitetecsa.sdk.android.balance.consult.UssdRequest.DATA_BALANCE; +import static cu.suitetecsa.sdk.android.balance.consult.UssdRequest.MESSAGES_BALANCE; +import static cu.suitetecsa.sdk.android.balance.consult.UssdRequest.PRINCIPAL_BALANCE; +import static cu.suitetecsa.sdk.android.balance.consult.UssdRequest.VOICE_BALANCE; +import static cu.suitetecsa.sdk.android.balance.parser.BonusBalanceParser.parseBonusBalance; +import static cu.suitetecsa.sdk.android.balance.parser.DailyDataParser.parseDailyData; +import static cu.suitetecsa.sdk.android.balance.parser.MailDataParser.parseMailData; +import static cu.suitetecsa.sdk.android.balance.parser.MainBalanceParser.parseMainBalance; +import static cu.suitetecsa.sdk.android.balance.parser.MainDataParser.parseMainData; +import static cu.suitetecsa.sdk.android.balance.parser.MainSmsParser.parseMainSms; +import static cu.suitetecsa.sdk.android.balance.parser.MainVoiceParser.parseMainVoice; + +import android.Manifest; +import android.os.Build; +import android.os.Handler; +import android.os.Looper; +import android.telephony.TelephonyManager; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.annotation.RequiresPermission; + +import java.text.ParseException; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Queue; + +import cu.suitetecsa.sdk.android.balance.consult.UssdRequest; +import cu.suitetecsa.sdk.android.balance.exception.UssdRequestException; +import cu.suitetecsa.sdk.android.balance.response.Custom; +import cu.suitetecsa.sdk.android.balance.response.DataBalance; +import cu.suitetecsa.sdk.android.balance.response.PrincipalBalance; +import cu.suitetecsa.sdk.android.model.MainBalance; +import cu.suitetecsa.sdk.android.model.MainData; + +class UssdRequestSenderImpl implements UssdRequestSender { + + private final long DELAY_MS; + + UssdRequestSenderImpl(long delay) { + this.DELAY_MS = delay; + } + + @RequiresApi(api = Build.VERSION_CODES.O) + @RequiresPermission(Manifest.permission.CALL_PHONE) + @Override + public void send(RequestCallback callback) { + Queue requestsTypes = new LinkedList<>(); + requestsTypes.offer(PRINCIPAL_BALANCE); + new Handler(Looper.getMainLooper()).postDelayed(() -> sendRequest(callback, requestsTypes, null), DELAY_MS); + } + + @RequiresApi(api = Build.VERSION_CODES.O) + @RequiresPermission(Manifest.permission.CALL_PHONE) + @Override + public void send(@NonNull String ussdCode, RequestCallback callback) { + Queue requestsTypes = new LinkedList<>(); + requestsTypes.offer(CUSTOM); + new Handler(Looper.getMainLooper()).postDelayed(() -> sendRequest(callback, requestsTypes, ussdCode), DELAY_MS); + } + + @RequiresApi(api = Build.VERSION_CODES.O) + @RequiresPermission(Manifest.permission.CALL_PHONE) + private void sendRequest(RequestCallback callback, @NonNull Queue requestsTypes, String ussdCode) { + UssdRequest ussdRequest = requestsTypes.poll(); + if (ussdRequest != null) { + callback.onRequesting(ussdRequest); + String code = ussdRequest == UssdRequest.CUSTOM ? ussdCode : ussdRequest.getUssdCode(); + callback.getTelephonyManager().sendUssdRequest(code, new TelephonyManager.UssdResponseCallback() { + @RequiresPermission(Manifest.permission.CALL_PHONE) + @Override + public void onReceiveUssdResponse(TelephonyManager telephonyManager, String request, CharSequence response) { + switch (ussdRequest) { + case PRINCIPAL_BALANCE: + try { + MainBalance balance = parseMainBalance(response); + if (balance == null) callback.onFailure(new UssdRequestException(response.toString())); + else { + if (balance.data() != null) + requestsTypes.offer(DATA_BALANCE); + if (balance.voice() != null) + requestsTypes.offer(VOICE_BALANCE); + if (balance.sms() != null) + requestsTypes.offer(MESSAGES_BALANCE); + requestsTypes.offer(BONUS_BALANCE); + + callback.onSuccess(ussdRequest, new PrincipalBalance( + balance.balance(), + balance.activeUntil(), + balance.dueDate(), + new ArrayList<>(requestsTypes) + )); + } + } catch (ParseException e) { + callback.onFailure(e); + } + break; + case DATA_BALANCE: + MainData data = parseMainData(response); + try { + callback.onSuccess(ussdRequest, new DataBalance( + data.usageBasedPricing(), data.data(), data.dataLte(), data.remainingDays(), parseDailyData(response), parseMailData(response) + )); + } catch (ParseException e) { + callback.onFailure(e); + } + break; + case VOICE_BALANCE: + try { + callback.onSuccess(ussdRequest, parseMainVoice(response)); + } catch (ParseException e) { + callback.onFailure(e); + } + break; + case MESSAGES_BALANCE: + try { + callback.onSuccess(ussdRequest, parseMainSms(response)); + } catch (ParseException e) { + callback.onFailure(e); + } + break; + case BONUS_BALANCE: + try { + callback.onSuccess(ussdRequest, parseBonusBalance(response)); + } catch (ParseException e) { + callback.onFailure(e); + } + break; + default: + callback.onSuccess(ussdRequest, new Custom(response.toString())); + break; + } + new Handler(Looper.getMainLooper()).postDelayed(() -> sendRequest(callback, requestsTypes, null), DELAY_MS); + } + + @Override + public void onReceiveUssdResponseFailed(TelephonyManager telephonyManager, String request, int failureCode) { + callback.onFailure(new UssdRequestException("Exception code :: " + failureCode)); + } + }, new Handler(Looper.getMainLooper())); + } + } +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/consult/UssdRequest.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/consult/UssdRequest.java new file mode 100644 index 0000000..3b33103 --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/consult/UssdRequest.java @@ -0,0 +1,22 @@ +package cu.suitetecsa.sdk.android.balance.consult; + +import android.net.Uri; + +public enum UssdRequest { + PRINCIPAL_BALANCE("*222" + Uri.parse("#")), + DATA_BALANCE("*222*328" + Uri.parse("#")), + VOICE_BALANCE("*222*869" + Uri.parse("#")), + MESSAGES_BALANCE("*222*767" + Uri.parse("#")), + BONUS_BALANCE("*222*266" + Uri.parse("#")), + CUSTOM("Nothing"); + + private final String ussdCode; + + UssdRequest(String ussdCode) { + this.ussdCode = ussdCode; + } + + public String getUssdCode() { + return ussdCode; + } +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/exception/UssdRequestException.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/exception/UssdRequestException.java new file mode 100644 index 0000000..4e0d0f3 --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/exception/UssdRequestException.java @@ -0,0 +1,15 @@ +package cu.suitetecsa.sdk.android.balance.exception; + +public class UssdRequestException extends Exception { + public UssdRequestException() { + super(); + } + + public UssdRequestException(String message) { + super(message); + } + + public UssdRequestException(String message, Throwable throwable) { + super(message, throwable); + } +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/BonusBalanceParser.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/BonusBalanceParser.java new file mode 100644 index 0000000..6a31137 --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/BonusBalanceParser.java @@ -0,0 +1,93 @@ +package cu.suitetecsa.sdk.android.balance.parser; + +import android.os.Build; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; + +import org.jetbrains.annotations.Contract; + +import java.text.ParseException; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import cu.suitetecsa.sdk.android.balance.response.BonusBalance; +import cu.suitetecsa.sdk.android.model.BonusCredit; +import cu.suitetecsa.sdk.android.model.BonusData; +import cu.suitetecsa.sdk.android.model.BonusDataCU; +import cu.suitetecsa.sdk.android.model.BonusUnlimitedData; +import cu.suitetecsa.sdk.android.utils.StringUtils; + +public class BonusBalanceParser { + + /** + * Parses the bonus balance from a given CharSequence and returns a BonusBalance object. + * + * @return The parsed bonus balance as a BonusBalance object. + */ + @RequiresApi(api = Build.VERSION_CODES.O) + @NonNull + @Contract("_ -> new") + public static BonusBalance parseBonusBalance(CharSequence input) throws ParseException { + // Regular expressions to match the bonus credit, bonus data, and bonus data CU patterns + String creditPattern = "\\$(?([\\d.]+))\\s+vence\\s+(?(\\d{2}-\\d{2}-\\d{2}))\\."; + Pattern creditRegex = Pattern.compile(creditPattern); + Matcher creditMatcher = creditRegex.matcher(input); + + String dataPattern = + "Datos:\\s+(ilimitados\\s+vence\\s+(?(\\d{2}-\\d{2}-\\d{2}))\\.)?" + + "(\\s+)?((?(\\d+(\\.\\d+)?)(\\s)*([GMK])?B))?\\s+\\+\\s+" + + "((?(\\d+(\\.\\d+)?)(\\s)*([GMK])?B)\\s+LTE)?\\s+vence\\s+" + + "((?(\\d{2}-\\d{2}-\\d{2})))\\."; + Pattern dataRegex = Pattern.compile(dataPattern); + Matcher dataMatcher = dataRegex.matcher(input); + + String dataCUPattern = + "Datos\\.cu\\s+(?(\\d+(\\.\\d+)?)(\\s)*([GMK])?B)?\\s+vence\\s+" + + "(?(\\d{2}-\\d{2}-\\d{2}))\\."; + Pattern dataCURegex = Pattern.compile(dataCUPattern); + Matcher dataCUMatcher = dataCURegex.matcher(input); + + BonusCredit bonusCredit = null; + BonusData bonusData = null; + BonusDataCU bonusDataCU = null; + BonusUnlimitedData bonusUnlimitedData = null; + + if (creditMatcher.find()) { + // Parse bonus credit + bonusCredit = new BonusCredit( + Float.parseFloat(Objects.requireNonNull(creditMatcher.group("bonusCredit"))), + StringUtils.toDateMillis(creditMatcher.group("bonusCreditDueDate")) + ); + } + + if (dataMatcher.find()) { + // Parse bonus data and bonus unlimited data + String dataAllNetworkBonus = dataMatcher.group("dataAllNetworkBonus"); + String bonusDataLte = dataMatcher.group("bonusDataLte"); + String bonusDataDueDate = dataMatcher.group("bonusDataDueDate"); + bonusData = new BonusData( + dataAllNetworkBonus != null ? StringUtils.toBytes(dataAllNetworkBonus) : null, + bonusDataLte != null ? StringUtils.toBytes(bonusDataLte) : null, + StringUtils.toDateMillis(bonusDataDueDate) + ); + + String unlimitedData = dataMatcher.group("unlimitedData"); + if (unlimitedData != null) { + bonusUnlimitedData = new BonusUnlimitedData(StringUtils.toDateMillis(unlimitedData)); + } + } + + if (dataCUMatcher.find()) { + // Parse bonus data CU + bonusDataCU = new BonusDataCU( + StringUtils.toBytes(Objects.requireNonNull(dataCUMatcher.group("bonusDataCu"))), + StringUtils.toDateMillis(dataCUMatcher.group("bonusDataCuDueDate")) + ); + } + + // Return the parsed bonus balance + return new BonusBalance(bonusCredit, bonusUnlimitedData, bonusData, bonusDataCU); + } +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/DailyDataParser.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/DailyDataParser.java new file mode 100644 index 0000000..ee8ece1 --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/DailyDataParser.java @@ -0,0 +1,52 @@ +package cu.suitetecsa.sdk.android.balance.parser; + +import android.os.Build; + +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; + +import org.jetbrains.annotations.Contract; + +import java.text.ParseException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import cu.suitetecsa.sdk.android.model.DailyData; +import cu.suitetecsa.sdk.android.utils.StringUtils; + +public class DailyDataParser { + + /** + * Parses the daily data from a given CharSequence and returns a DailyData object. + * + * @return The parsed daily data as a DailyData object, or null if the data cannot be parsed. + */ + @Nullable + @RequiresApi(api = Build.VERSION_CODES.O) + @Contract("_ -> new") + public static DailyData parseDailyData(CharSequence input) throws ParseException { + // Regular expression to match the daily data pattern + String dailyDataRegexPattern = + "Diaria:\\s+(?(\\d+(\\.\\d+)?)(\\s)*([GMK])?B)?" + + "(\\s+no activos)?" + + "(\\s+validos\\s+(?(\\d+))\\s+horas)?\\."; + Pattern dailyDataPattern = Pattern.compile(dailyDataRegexPattern); + Matcher dailyDataMatcher = dailyDataPattern.matcher(input); + + Integer remainingHours = null; + + if (!dailyDataMatcher.find()) return null; + // Parse the daily data + String dataDailyStr = dailyDataMatcher.group("dataDaily"); + assert dataDailyStr != null; + long dataDaily = StringUtils.toBytes(dataDailyStr); + + String remainingHoursStr = dailyDataMatcher.group("dueDate"); + if (remainingHoursStr != null) { + remainingHours = Integer.parseInt(remainingHoursStr); + } + + // Create and return the DailyData object + return new DailyData(dataDaily, remainingHours); + } +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MailDataParser.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MailDataParser.java new file mode 100644 index 0000000..4057f8b --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MailDataParser.java @@ -0,0 +1,53 @@ +package cu.suitetecsa.sdk.android.balance.parser; + +import android.os.Build; + +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; + +import org.jetbrains.annotations.Contract; + +import java.text.ParseException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import cu.suitetecsa.sdk.android.model.MailData; +import cu.suitetecsa.sdk.android.utils.StringUtils; + +public class MailDataParser { + + /** + * Parses the mail data from a given CharSequence and returns a MailData object. + * + * @return The parsed mail data as a MailData object, or null if the data cannot be parsed. + */ + @Nullable + @RequiresApi(api = Build.VERSION_CODES.O) + @Contract("_ -> new") + public static MailData parseMailData(CharSequence input) throws ParseException { + // Regular expression to match the mail data pattern + String mailDataRegexPattern = + "Mensajeria:\\s+(?(\\d+(\\.\\d+)?)(\\s)*([GMK])?B)?" + + "(\\s+no activos)?" + + "(\\s+validos\\s+(?(\\d+))\\s+dias)?\\."; + Pattern mailDataPattern = Pattern.compile(mailDataRegexPattern); + Matcher mailDataMatcher = mailDataPattern.matcher(input); + + + Integer remainingDays = null; + + if (!mailDataMatcher.find()) return null;; + // Parse the mail data + String dataMailStr = mailDataMatcher.group("dataMail"); + assert dataMailStr != null; + long dataMail = StringUtils.toBytes(dataMailStr); + + String remainingDaysStr = mailDataMatcher.group("dueDate"); + if (remainingDaysStr != null) { + remainingDays = Integer.parseInt(remainingDaysStr); + } + + // Create and return the MailData object + return new MailData(dataMail, remainingDays); + } +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainBalanceParser.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainBalanceParser.java new file mode 100644 index 0000000..1805b0d --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainBalanceParser.java @@ -0,0 +1,107 @@ +package cu.suitetecsa.sdk.android.balance.parser; + +import android.os.Build; + +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; + +import java.text.ParseException; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import cu.suitetecsa.sdk.android.model.MainBalance; +import cu.suitetecsa.sdk.android.model.MainData; +import cu.suitetecsa.sdk.android.model.MainSms; +import cu.suitetecsa.sdk.android.model.MainVoice; +import cu.suitetecsa.sdk.android.utils.StringUtils; + +public class MainBalanceParser { + + /** + * Parses the main balance data from a given CharSequence and returns a MainBalance object. + * + * @return The parsed main balance data as a MainBalance object, or null if the data cannot be parsed. + */ + @RequiresApi(api = Build.VERSION_CODES.O) + @Nullable + public static MainBalance parseMainBalance(CharSequence input) throws ParseException { + // Regular expression to match the credit, activeUntil, and dueDate pattern + String creditRegexPattern = "Saldo:\\s+(?([\\d.]+))\\s+CUP\\.\\s+([^\"]*?)?" + + "Linea activa hasta\\s+(?(\\d{2}-\\d{2}-\\d{2}))" + + "\\s+vence\\s+(?(\\d{2}-\\d{2}-\\d{2}))\\."; + Pattern creditPattern = Pattern.compile(creditRegexPattern); + Matcher creditMatcher = creditPattern.matcher(input); + + if (creditMatcher.find()) { + // Parse the credit, activeUntil, and dueDate + float credit = Float.parseFloat(Objects.requireNonNull(creditMatcher.group("principalCredit"))); + long activeUntil = StringUtils.toDateMillis(creditMatcher.group("activeUntil")); + long dueDate = StringUtils.toDateMillis(creditMatcher.group("dueDate")); + + // Regular expression to match the dataAllNetwork and dataLte pattern + String dataRegexPattern = "Datos:\\s+(?(\\d+(\\.\\d+)?)(\\s)*([GMK])?B)?" + + "(\\s+\\+\\s+)?" + + "((?(\\d+(\\.\\d+)?)(\\s)*([GMK])?B)\\s+LTE)\\."; + Pattern dataPattern = Pattern.compile(dataRegexPattern); + Matcher dataMatcher = dataPattern.matcher(input); + + Long dataAllNetwork = null; + Long dataLte = null; + + if (dataMatcher.find()) { + // Parse the dataAllNetwork and dataLte + String dataAllNetworkStr = dataMatcher.group("dataAllNetwork"); + if (dataAllNetworkStr != null) { + dataAllNetwork = StringUtils.toBytes(dataAllNetworkStr); + } + String dataLteStr = dataMatcher.group("dataLte"); + if (dataLteStr != null) { + dataLte = StringUtils.toBytes(dataLteStr); + } + } + + // Create the MainData object + MainData mainData = new MainData(false, dataAllNetwork, dataLte, null); + + // Regular expression to match the voice pattern + String voiceRegexPattern = "Voz:\\s+(?(\\d{1,3}:\\d{2}:\\d{2}))\\."; + Pattern voicePattern = Pattern.compile(voiceRegexPattern); + Matcher voiceMatcher = voicePattern.matcher(input); + + Long voice = null; + + if (voiceMatcher.find()) { + // Parse the voice + String voiceStr = voiceMatcher.group("voice"); + assert voiceStr != null; + voice = StringUtils.toSeconds(voiceStr); + } + + // Create the MainVoice object + MainVoice mainVoice = voice != null ? new MainVoice(voice, null) : null; + + // Regular expression to match the sms pattern + String smsRegexPattern = "SMS:\\s+(?(\\d+))\\."; + Pattern smsPattern = Pattern.compile(smsRegexPattern); + Matcher smsMatcher = smsPattern.matcher(input); + + Integer sms = null; + + if (smsMatcher.find()) { + // Parse the sms + String smsStr = smsMatcher.group("sms"); + assert smsStr != null; + sms = Integer.parseInt(smsStr); + } + + // Create the MainSms object + MainSms mainSms = sms != null ? new MainSms(sms, null) : null; + + // Create and return the MainBalance object + return new MainBalance(credit, mainData, mainVoice, mainSms, null, null, activeUntil, dueDate); + } + + return null; + } +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainDataParser.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainDataParser.java new file mode 100644 index 0000000..bf5c827 --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainDataParser.java @@ -0,0 +1,74 @@ +package cu.suitetecsa.sdk.android.balance.parser; + +import android.os.Build; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; + +import org.jetbrains.annotations.Contract; + +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import cu.suitetecsa.sdk.android.model.MainData; +import cu.suitetecsa.sdk.android.utils.StringUtils; + +public class MainDataParser { + + /** + * Parses the main data from a given CharSequence and returns a MainData object. + * + * @return The parsed main data as a MainData object, or null if the data cannot be parsed. + */ + @RequiresApi(api = Build.VERSION_CODES.O) + @NonNull + @Contract("_ -> new") + public static MainData parseMainData(CharSequence input) { + // Regular expression to match the usageBasedPricing pattern + String usageBasedPricingRegexPattern = "Tarifa:\\s+(?[^\"]*?)\\."; + Pattern usageBasedPricingPattern = Pattern.compile(usageBasedPricingRegexPattern); + Matcher usageBasedPricingMatcher = usageBasedPricingPattern.matcher(input); + + boolean usageBasedPricing = false; + + if (usageBasedPricingMatcher.find()) { + // Parse the usageBasedPricing + usageBasedPricing = !Objects.equals(usageBasedPricingMatcher.group("tfc"), "No activa"); + } + + // Regular expression to match the dataAllNetwork, dataLte, and remainingDays pattern + String mainDataRegexPattern = "Paquetes:\\s+(?(\\d+(\\.\\d+)?)(\\s)*([GMK])?B)?" + + "(\\s+\\+\\s+)?" + + "((?(\\d+(\\.\\d+)?)(\\s)*([GMK])?B)\\s+LTE)?" + + "(\\s+no activos)?" + + "(\\s+validos\\s+(?(\\d+))\\s+dias)?\\."; + Pattern mainDataPattern = Pattern.compile(mainDataRegexPattern); + Matcher mainDataMatcher = mainDataPattern.matcher(input); + + Long dataAllNetwork = null; + Long dataLte = null; + Integer remainingDays = null; + + if (mainDataMatcher.find()) { + // Parse the dataAllNetwork, dataLte, and remainingDays + String dataAllNetworkStr = mainDataMatcher.group("dataAllNetwork"); + if (dataAllNetworkStr != null) { + dataAllNetwork = StringUtils.toBytes(dataAllNetworkStr); + } + + String dataLteStr = mainDataMatcher.group("dataLte"); + if (dataLteStr != null) { + dataLte = StringUtils.toBytes(dataLteStr); + } + + String remainingDaysStr = mainDataMatcher.group("dueDate"); + if (remainingDaysStr != null) { + remainingDays = Integer.parseInt(remainingDaysStr); + } + } + + // Create and return the MainData object + return new MainData(usageBasedPricing, dataAllNetwork, dataLte, remainingDays); + } +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainSmsParser.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainSmsParser.java new file mode 100644 index 0000000..a8ae120 --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainSmsParser.java @@ -0,0 +1,51 @@ +package cu.suitetecsa.sdk.android.balance.parser; + +import android.os.Build; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; + +import org.jetbrains.annotations.Contract; + +import java.text.ParseException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import cu.suitetecsa.sdk.android.balance.response.MessagesBalance; + +public class MainSmsParser { + + /** + * Parses the main SMS balance from a given CharSequence and returns a MessagesBalance object. + * + * @return The parsed main SMS balance as a MessagesBalance object, or null if the data cannot be parsed. + */ + @RequiresApi(api = Build.VERSION_CODES.O) + @NonNull + @Contract("_ -> new") + public static MessagesBalance parseMainSms(CharSequence input) throws ParseException { + // Regular expression to match the SMS balance pattern + String smsPattern = + "Usted dispone de\\s+(?(\\d+))\\s+SMS(\\s+no activos)?" + + "(\\s+validos por\\s+(?(\\d+))\\s+dias)?(\\.)?"; + Pattern smsRegex = Pattern.compile(smsPattern); + Matcher smsMatcher = smsRegex.matcher(input); + + + Integer remainingDays = null; + + if(!smsMatcher.find()) throw new ParseException(input.toString(), 0);; + // Parse the SMS balance and due date + String smsStr = smsMatcher.group("sms"); + assert smsStr != null; + int sms = Integer.parseInt(smsStr); + + String remainingDaysStr = smsMatcher.group("dueDate"); + if (remainingDaysStr != null) { + remainingDays = Integer.parseInt(remainingDaysStr); + } + + // Create and return the MessagesBalance object + return new MessagesBalance(sms, remainingDays); + } +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainVoiceParser.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainVoiceParser.java new file mode 100644 index 0000000..6f82066 --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainVoiceParser.java @@ -0,0 +1,51 @@ +package cu.suitetecsa.sdk.android.balance.parser; + +import android.os.Build; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; + +import org.jetbrains.annotations.Contract; + +import java.text.ParseException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import cu.suitetecsa.sdk.android.balance.response.VoiceBalance; +import cu.suitetecsa.sdk.android.utils.StringUtils; + +public class MainVoiceParser { + + /** + * Parses the main voice balance from a given CharSequence and returns a VoiceBalance object. + * + * @return The parsed main voice balance as a VoiceBalance object, or null if the data cannot be parsed. + */ + @RequiresApi(api = Build.VERSION_CODES.O) + @NonNull + @Contract("_ -> new") + public static VoiceBalance parseMainVoice(CharSequence input) throws ParseException { + // Regular expression to match the voice balance pattern + String voicePattern = + "Usted dispone de\\s+(?(\\d+:\\d{2}:\\d{2}))\\s+MIN(\\s+no activos)?" + + "(\\s+validos por\\s+(?(\\d+))\\s+dias)?"; + Pattern voiceRegex = Pattern.compile(voicePattern); + Matcher voiceMatcher = voiceRegex.matcher(input); + + Integer remainingDays = null; + + if(!voiceMatcher.find()) throw new ParseException(input.toString(), 0);; + // Parse the voice balance and due date + String voiceStr = voiceMatcher.group("voice"); + assert voiceStr != null; + long voice = StringUtils.toSeconds(voiceStr); + + String remainingDaysStr = voiceMatcher.group("dueDate"); + if (remainingDaysStr != null) { + remainingDays = Integer.parseInt(remainingDaysStr); + } + + // Create and return the VoiceBalance object + return new VoiceBalance(voice, remainingDays); + } +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/BonusBalance.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/BonusBalance.java new file mode 100644 index 0000000..2f7847b --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/BonusBalance.java @@ -0,0 +1,39 @@ +package cu.suitetecsa.sdk.android.balance.response; + +import cu.suitetecsa.sdk.android.model.BonusCredit; +import cu.suitetecsa.sdk.android.model.BonusData; +import cu.suitetecsa.sdk.android.model.BonusDataCU; +import cu.suitetecsa.sdk.android.model.BonusUnlimitedData; + +/** + * Clase para representar la respuesta de saldo de bonificación + */ +public class BonusBalance implements UssdResponse { + private final BonusCredit credit; + private final BonusUnlimitedData unlimitedData; + private final BonusData data; + private final BonusDataCU dataCu; + + public BonusBalance(BonusCredit credit, BonusUnlimitedData unlimitedData, BonusData data, BonusDataCU dataCu) { + this.credit = credit; + this.unlimitedData = unlimitedData; + this.data = data; + this.dataCu = dataCu; + } + + public BonusCredit getCredit() { + return credit; + } + + public BonusUnlimitedData getUnlimitedData() { + return unlimitedData; + } + + public BonusData getData() { + return data; + } + + public BonusDataCU getDataCu() { + return dataCu; + } +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/Custom.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/Custom.java new file mode 100644 index 0000000..afacd68 --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/Custom.java @@ -0,0 +1,16 @@ +package cu.suitetecsa.sdk.android.balance.response; + +/** + * Clase para representar una respuesta USSD personalizada + */ +public class Custom implements UssdResponse { + private final String response; + + public Custom(String response) { + this.response = response; + } + + public String getResponse() { + return response; + } +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/DataBalance.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/DataBalance.java new file mode 100644 index 0000000..a6accef --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/DataBalance.java @@ -0,0 +1,11 @@ +package cu.suitetecsa.sdk.android.balance.response; + +import cu.suitetecsa.sdk.android.model.DailyData; +import cu.suitetecsa.sdk.android.model.MailData; + +/** + * Clase para representar la respuesta de saldo de datos + */ +public record DataBalance(boolean usageBasedPricing, Long data, Long dataLte, Integer remainingDays, + DailyData dailyData, MailData mailData) implements UssdResponse { +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/MessagesBalance.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/MessagesBalance.java new file mode 100644 index 0000000..6f707d8 --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/MessagesBalance.java @@ -0,0 +1,7 @@ +package cu.suitetecsa.sdk.android.balance.response; + +/** + * Clase para representar la respuesta de saldo de mensajes + */ +public record MessagesBalance(long sms, Integer remainingDays) implements UssdResponse { +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/PrincipalBalance.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/PrincipalBalance.java new file mode 100644 index 0000000..68a971e --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/PrincipalBalance.java @@ -0,0 +1,38 @@ +package cu.suitetecsa.sdk.android.balance.response; + +import java.util.List; + +import cu.suitetecsa.sdk.android.balance.consult.UssdRequest; + +/** + * Clase para representar la respuesta de saldo principal + */ +public class PrincipalBalance implements UssdResponse { + private final double balance; + private final long activeUntil; + private final long dueDate; + private final List consults; + + public PrincipalBalance(double balance, long activeUntil, long dueDate, List consults) { + this.balance = balance; + this.activeUntil = activeUntil; + this.dueDate = dueDate; + this.consults = consults; + } + + public double getBalance() { + return balance; + } + + public long getActiveUntil() { + return activeUntil; + } + + public long getDueDate() { + return dueDate; + } + + public List getConsults() { + return consults; + } +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/UssdResponse.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/UssdResponse.java new file mode 100644 index 0000000..97a6f20 --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/UssdResponse.java @@ -0,0 +1,9 @@ +package cu.suitetecsa.sdk.android.balance.response; + +/** + * Interfaz para representar las diferentes respuestas USSD + */ +public interface UssdResponse { + public static final String PROCESSING_RESPONSE = "Su solicitud esta siendo procesada."; +} + diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/VoiceBalance.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/VoiceBalance.java new file mode 100644 index 0000000..68f262e --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/VoiceBalance.java @@ -0,0 +1,22 @@ +package cu.suitetecsa.sdk.android.balance.response; + +/** + * Clase para representar la respuesta de saldo de voz + */ +public class VoiceBalance implements UssdResponse { + private final long time; + private final Integer remainingDays; + + public VoiceBalance(long time, Integer remainingDays) { + this.time = time; + this.remainingDays = remainingDays; + } + + public long getTime() { + return time; + } + + public Integer getRemainingDays() { + return remainingDays; + } +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/BonusCredit.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/BonusCredit.kt deleted file mode 100644 index 5be46e3..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/BonusCredit.kt +++ /dev/null @@ -1,12 +0,0 @@ -package cu.suitetecsa.sdk.android.domain.model - -/** - * Data class representing the bonus credit amount and due date for bonus credit in a USSD balance request. - * - * @param credit The bonus credit amount. - * @param bonusCreditDueDate The due date for the bonus credit, or null if there is no due date. - */ -data class BonusCredit( - val credit: Float, - val bonusCreditDueDate: String -) diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/BonusData.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/BonusData.kt deleted file mode 100644 index 2afc82a..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/BonusData.kt +++ /dev/null @@ -1,15 +0,0 @@ -package cu.suitetecsa.sdk.android.domain.model - -/** - * Data class representing the bonus data count, LTE bonus data count, and due date for bonus data in a - * USSD balance request. - * - * @param bonusDataCount The count of bonus data. - * @param bonusDataCountLte The count of LTE bonus data. - * @param bonusDataDueDate The due date for the bonus data, or null if there is no due date. - */ -data class BonusData( - val bonusDataCount: Double?, - val bonusDataCountLte: Double?, - val bonusDataDueDate: String? -) diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/BonusDataCU.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/BonusDataCU.kt deleted file mode 100644 index c6bd371..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/BonusDataCU.kt +++ /dev/null @@ -1,12 +0,0 @@ -package cu.suitetecsa.sdk.android.domain.model - -/** - * Data class representing the bonus data count and due date for bonus data in a USSD balance request. - * - * @param bonusDataCuCount The count of bonus data. - * @param bonusDataCuDueDate The due date for the bonus data, or null if there is no due date. - */ -data class BonusDataCU( - val bonusDataCuCount: Double, - val bonusDataCuDueDate: String? -) diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/BonusUnlimitedData.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/BonusUnlimitedData.kt deleted file mode 100644 index 66f59a6..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/BonusUnlimitedData.kt +++ /dev/null @@ -1,8 +0,0 @@ -package cu.suitetecsa.sdk.android.domain.model - -/** - * Data class representing the due date for bonus unlimited data in a USSD balance request. - * - * @param bonusUnlimitedDataDueDate The due date for the bonus unlimited data. - */ -data class BonusUnlimitedData(val bonusUnlimitedDataDueDate: String) diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/DailyData.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/DailyData.kt deleted file mode 100644 index 3ae2d2e..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/DailyData.kt +++ /dev/null @@ -1,9 +0,0 @@ -package cu.suitetecsa.sdk.android.domain.model - -/** - * Data class representing the daily data balance and remaining hours for a USSD balance request. - * - * @param data The daily data balance. - * @param remainingHours The remaining hours for the balance, or null if the balance is not time-based. - */ -data class DailyData(val data: Double, val remainingHours: Int?) diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/MailData.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/MailData.kt deleted file mode 100644 index 4154f04..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/MailData.kt +++ /dev/null @@ -1,9 +0,0 @@ -package cu.suitetecsa.sdk.android.domain.model - -/** - * Data class representing the mail data balance and remaining days for a USSD balance request. - * - * @param data The mail data balance. - * @param remainingDays The remaining days for the balance. - */ -data class MailData(val data: Double, val remainingDays: Int?) diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/MainBalance.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/MainBalance.kt deleted file mode 100644 index 4413a87..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/MainBalance.kt +++ /dev/null @@ -1,24 +0,0 @@ -package cu.suitetecsa.sdk.android.domain.model - -/** - * Data class representing the main balance information for a USSD balance request. - * - * @param credit The credit balance. - * @param data The main data balance. - * @param voice The main voice balance. - * @param sms The main SMS balance. - * @param dailyData The daily data balance. - * @param mailData The mail data balance. - * @param activeUntil The active until date. - * @param mainBalanceDueDate The main balance due date. - */ -internal data class MainBalance( - val credit: Float, - var data: MainData?, - var voice: MainVoice?, - var sms: MainSms?, - var dailyData: DailyData?, - var mailData: MailData?, - val activeUntil: String, - val mainBalanceDueDate: String -) diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/MainData.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/MainData.kt deleted file mode 100644 index add3947..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/MainData.kt +++ /dev/null @@ -1,16 +0,0 @@ -package cu.suitetecsa.sdk.android.domain.model - -/** - * Data class representing the main data balance and related information for a USSD balance request. - * - * @param usageBasedPricing Indicates whether the data balance is subject to usage-based pricing. - * @param data The main data balance in megabytes (MB). - * @param dataLte The main LTE data balance in megabytes (MB). - * @param remainingDays The remaining days for the data balance. - */ -data class MainData( - val usageBasedPricing: Boolean, - val data: Double?, - val dataLte: Double?, - val remainingDays: Int? -) diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/MainSms.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/MainSms.kt deleted file mode 100644 index 6f2dd25..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/MainSms.kt +++ /dev/null @@ -1,9 +0,0 @@ -package cu.suitetecsa.sdk.android.domain.model - -/** - * Data class representing the main SMS balance and remaining days for a USSD balance request. - * - * @param mainSms The main SMS balance. - * @param remainingDays The remaining days for the balance. - */ -data class MainSms(val mainSms: Int, val remainingDays: Int?) diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/MainVoice.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/MainVoice.kt deleted file mode 100644 index 62109f1..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/MainVoice.kt +++ /dev/null @@ -1,9 +0,0 @@ -package cu.suitetecsa.sdk.android.domain.model - -/** - * Data class representing the main voice balance and remaining days for a USSD balance request. - * - * @param mainVoice The main voice balance. - * @param remainingDays The remaining days for the balance. - */ -data class MainVoice(val mainVoice: Long, val remainingDays: Int?) diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/SimCard.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/SimCard.kt deleted file mode 100644 index 70eb16f..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/domain/model/SimCard.kt +++ /dev/null @@ -1,20 +0,0 @@ -package cu.suitetecsa.sdk.android.domain.model - -import android.telephony.TelephonyManager - -/** - * Represents a SIM card installed on the device. - * - * @property serialNumber The serial number of the SIM card. - * @property displayName The display name of the SIM card. - * @property slotIndex The index of the SIM card slot. - * @property subscriptionId The subscription ID of the SIM card. - * @property telephony The TelephonyManager instance associated with the SIM card. - */ -data class SimCard( - val serialNumber: String, - val displayName: String, - val slotIndex: Int, - val subscriptionId: Int, - val telephony: TelephonyManager? -) diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/DateExtension.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/DateExtension.kt deleted file mode 100644 index 53259ff..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/DateExtension.kt +++ /dev/null @@ -1,22 +0,0 @@ -package cu.suitetecsa.sdk.android.framework - -import java.util.Calendar -import java.util.Date - -private const val HOURS_PER_DAY = 24 -private const val MINUTES_PER_HOUR = 60 -private const val MILLISECONDS = 1000 - -/** - * Calculates the number of days between the current date and the given date. - * - * @return The number of days between the current date and the given date. - */ -fun Date.daysBetweenDates(): Int { - val calendar = Calendar.getInstance() - calendar.time = this - val currentDate = Calendar.getInstance() - val diffInMillis = calendar.timeInMillis - currentDate.timeInMillis - val diffInDays = diffInMillis / (HOURS_PER_DAY * MINUTES_PER_HOUR * MINUTES_PER_HOUR * MILLISECONDS) - return diffInDays.toInt() + 1 -} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/DoubleExtension.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/DoubleExtension.kt deleted file mode 100644 index 1c72b09..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/DoubleExtension.kt +++ /dev/null @@ -1,19 +0,0 @@ -package cu.suitetecsa.sdk.android.framework - -private const val SIZE_UNIT_MAX_LENGTH: Double = 1024.0 - -/** - * Converts a size value in bytes to a human-readable string representation. - * - * @return The size value formatted as a string with the appropriate unit (bytes, KB, MB, GB, TB). - */ -fun Double.toSizeString(): String { - val sizeUnits = arrayOf("bytes", "KB", "MB", "GB", "TB") - var sizeValue = this - var sizeUnitIndex = 0 - while (sizeValue >= SIZE_UNIT_MAX_LENGTH && sizeUnitIndex < sizeUnits.lastIndex) { - sizeValue /= SIZE_UNIT_MAX_LENGTH - sizeUnitIndex++ - } - return "%.2f %s".format(sizeValue, sizeUnits[sizeUnitIndex]).replace(".", ",") -} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/LongExtension.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/LongExtension.kt deleted file mode 100644 index eed3698..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/LongExtension.kt +++ /dev/null @@ -1,17 +0,0 @@ -package cu.suitetecsa.sdk.android.framework - -private const val TIME_FORMAT = "%02d:%02d:%02d" -private const val SECONDS_IN_HOURS = 3600 -private const val SECONDS_IN_MINUTES = 60 - -/** - * Converts a duration in seconds to a time string representation in the format "HH:MM:SS". - * - * @return The duration formatted as a time string. - */ -fun Long.toTimeString(): String = String.format( - TIME_FORMAT, - this / SECONDS_IN_HOURS, - this % SECONDS_IN_HOURS / SECONDS_IN_MINUTES, - this % SECONDS_IN_MINUTES -) diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/SimCardCollector.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/SimCardCollector.kt deleted file mode 100644 index 1666c2b..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/SimCardCollector.kt +++ /dev/null @@ -1,25 +0,0 @@ -package cu.suitetecsa.sdk.android.framework - -import android.Manifest -import androidx.annotation.RequiresPermission -import cu.suitetecsa.sdk.android.domain.model.SimCard - -/** - * Interface for collecting SIM card information. - */ -interface SimCardCollector { - /** - * Collects the SIM card information. - * - * @return The list of SIM cards. - */ - - @RequiresPermission( - allOf = [ - Manifest.permission.ACCESS_FINE_LOCATION, - Manifest.permission.ACCESS_COARSE_LOCATION, - Manifest.permission.READ_PHONE_STATE - ] - ) - fun collect(): List -} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/SimCardCollectorImpl.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/SimCardCollectorImpl.kt deleted file mode 100644 index 5040f54..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/SimCardCollectorImpl.kt +++ /dev/null @@ -1,125 +0,0 @@ -package cu.suitetecsa.sdk.android.framework - -import android.Manifest -import android.content.Context -import android.os.Build -import android.telephony.SubscriptionInfo -import android.telephony.SubscriptionManager -import android.telephony.TelephonyManager -import android.util.Log -import androidx.annotation.RequiresPermission -import cu.suitetecsa.sdk.android.domain.model.SimCard -import cz.mroczis.netmonster.core.factory.NetMonsterFactory - -private const val TAG = "SimCardCollectorImpl" - -/** - * Implementation of the SimCardCollector interface for collecting SIM card information. - * - * @param context The application context. - */ -internal class SimCardCollectorImpl( - private val context: Context -) : SimCardCollector { - - /** - * Collects the SIM card information. - * - * @return The list of SIM cards. - */ - @RequiresPermission( - allOf = [ - Manifest.permission.ACCESS_FINE_LOCATION, - Manifest.permission.ACCESS_COARSE_LOCATION, - Manifest.permission.READ_PHONE_STATE - ] - ) - override fun collect(): List { - val simCards = mutableListOf() - - val subscriptionInfoList = getSubscriptionInfoList(context) - if (subscriptionInfoList.isNotEmpty()) { - simCards.addAll(getSimCardsFromSubscriptionInfoList(subscriptionInfoList)) - } else { - simCards.addAll(getSimCardsFromNetMonster(context)) - } - - Log.e(TAG, "getSimCards: ${simCards.size}") - return simCards - } - - /** - * Retrieves the list of SubscriptionInfo objects for active subscriptions. - * - * @param context The application context. - * @return The list of SubscriptionInfo objects. - */ - @RequiresPermission( - allOf = [ - Manifest.permission.ACCESS_FINE_LOCATION, - Manifest.permission.ACCESS_COARSE_LOCATION, - Manifest.permission.READ_PHONE_STATE - ] - ) - private fun getSubscriptionInfoList(context: Context): List { - val subscriptionManager = - context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) as SubscriptionManager - return subscriptionManager.activeSubscriptionInfoList ?: emptyList() - } - - /** - * Converts a list of SubscriptionInfo objects to a list of SimCard objects. - * - * @param subscriptionInfoList The list of SubscriptionInfo objects. - * @return The list of SimCard objects. - */ - private fun getSimCardsFromSubscriptionInfoList(subscriptionInfoList: List): List { - return subscriptionInfoList.map { info -> - SimCard( - serialNumber = info.iccId, - displayName = info.displayName.toString(), - slotIndex = info.simSlotIndex, - subscriptionId = info.subscriptionId, - telephony = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - (context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager) - .createForSubscriptionId(info.subscriptionId) - } else { - null - } - ) - } - } - - /** - * Retrieves the list of SimCard objects using NetMonster library. - * - * @param context The application context. - * @return The list of SimCard objects. - */ - @RequiresPermission( - allOf = [ - Manifest.permission.ACCESS_FINE_LOCATION, - Manifest.permission.ACCESS_COARSE_LOCATION, - Manifest.permission.READ_PHONE_STATE - ] - ) - private fun getSimCardsFromNetMonster(context: Context): List { - val subscriptionManager = NetMonsterFactory.getSubscription(context) - val subscriptionInfoList = subscriptionManager.getActiveSubscriptions() - - return subscriptionInfoList.map { subscribedNetwork -> - SimCard( - serialNumber = subscribedNetwork.subscriptionId.toString(), - displayName = "", - slotIndex = subscribedNetwork.simSlotIndex, - subscriptionId = subscribedNetwork.subscriptionId, - telephony = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - (context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager) - .createForSubscriptionId(subscribedNetwork.subscriptionId) - } else { - null - } - ) - } - } -} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/SimCardExtension.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/SimCardExtension.kt deleted file mode 100644 index f69c1b5..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/SimCardExtension.kt +++ /dev/null @@ -1,55 +0,0 @@ -package cu.suitetecsa.sdk.android.framework - -import android.content.Context -import android.os.Build -import android.telephony.TelephonyManager -import androidx.annotation.RequiresApi -import androidx.annotation.RequiresPermission -import cu.suitetecsa.sdk.android.Utils -import cu.suitetecsa.sdk.android.domain.model.SimCard - -/** - * Consults the balance using USSD requests. - * - * This function sends USSD requests to consult the balance and handles the responses through the provided callback. - * It requires the CALL_PHONE permission to function correctly. - * - * @param callBack The callback interface to handle USSD responses. - * @throws SecurityException if the CALL_PHONE permission is not granted. - */ -@RequiresApi(Build.VERSION_CODES.O) -@RequiresPermission(android.Manifest.permission.CALL_PHONE) -fun SimCard.consultBalance(callBack: ConsultBalanceCallBack) { - val ussdBalanceRequestExecutorCallBack = object : UssdBalanceRequestExecutorCallBack { - override val telephonyManager: TelephonyManager - get() = this@consultBalance.telephony!! - - override fun onRequesting(consultType: UssdConsultType) = callBack.onRequesting(consultType) - - override fun onSuccess(ussdResponse: UssdResponse) = callBack.onSuccess(ussdResponse) - - override fun onFailure(throwable: Throwable) = callBack.onFailure(throwable) - } - UssdBalanceCommandExecutor.execute(ussdBalanceRequestExecutorCallBack) -} - -@RequiresApi(Build.VERSION_CODES.O) -@RequiresPermission(android.Manifest.permission.CALL_PHONE) -fun SimCard.ussdExecute(ussdCode: String, callBack: ConsultBalanceCallBack) { - val ussdBalanceRequestExecutorCallBack = object : UssdBalanceRequestExecutorCallBack { - override val telephonyManager: TelephonyManager - get() = this@ussdExecute.telephony!! - - override fun onRequesting(consultType: UssdConsultType) = callBack.onRequesting(consultType) - - override fun onSuccess(ussdResponse: UssdResponse) = callBack.onSuccess(ussdResponse) - - override fun onFailure(throwable: Throwable) = callBack.onFailure(throwable) - } - UssdBalanceCommandExecutor.execute(ussdCode, ussdBalanceRequestExecutorCallBack) -} - -@RequiresPermission(android.Manifest.permission.CALL_PHONE) -fun SimCard.makeCall(context: Context, phoneNumber: String) { - Utils.makeCall(context, phoneNumber, this) -} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/StringExtension.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/StringExtension.kt deleted file mode 100644 index 37d8adb..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/StringExtension.kt +++ /dev/null @@ -1,49 +0,0 @@ -package cu.suitetecsa.sdk.android.framework - -import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale -import kotlin.math.pow - -private const val SIZE_UNIT_MAX_LENGTH: Double = 1024.0 -private const val GB_POWER: Double = 3.0 - -private const val SECONDS_IN_MINUTES = 60 - -/** - * Converts a string representation of a size value to bytes. - * - * @return The size value converted to bytes. - * @throws IllegalArgumentException if the size unit is not valid. - */ -internal fun String.toBytes(): Double { - val sizeUnit = this.split(" ").last() - val sizeValue = this.replace(" $sizeUnit", "").replace(" ", "") - return sizeValue.replace(",", ".").toDouble() * when (sizeUnit.uppercase(Locale.getDefault())) { - "KB" -> SIZE_UNIT_MAX_LENGTH - "MB" -> SIZE_UNIT_MAX_LENGTH.pow(2) - "GB" -> SIZE_UNIT_MAX_LENGTH.pow(GB_POWER) - else -> throw IllegalArgumentException("La unidad de tamaño no es válida") - } -} - -/** - * Converts a string representation of a date to a Date object. - * - * @return The Date object representing the parsed date, or null if parsing fails. - */ -internal fun String.toDate(): Date? = SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()).parse(this) - -/** - * Converts a string representation of a Cubacel date to a Date object. - * - * @return The Date object representing the parsed Cubacel date, or null if parsing fails. - */ -internal fun String.toCubacelDate(): Date? = SimpleDateFormat("dd-MM-yy", Locale.getDefault()).parse(this) - -/** - * Converts a string representation of a time to seconds. - * - * @return The time value converted to seconds. - */ -internal fun String.toSeconds() = this.split(":").fold(0L) { acc, s -> acc * SECONDS_IN_MINUTES + s.toLong() } diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdBalanceCommandExecutor.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdBalanceCommandExecutor.kt deleted file mode 100644 index 641ed67..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdBalanceCommandExecutor.kt +++ /dev/null @@ -1,153 +0,0 @@ -package cu.suitetecsa.sdk.android.framework - -import android.os.Build -import android.os.Handler -import android.os.Looper -import android.telephony.TelephonyManager -import androidx.annotation.RequiresApi -import androidx.annotation.RequiresPermission -import cu.suitetecsa.sdk.android.framework.extensions.parseBonusBalance -import cu.suitetecsa.sdk.android.framework.extensions.parseDailyData -import cu.suitetecsa.sdk.android.framework.extensions.parseMailData -import cu.suitetecsa.sdk.android.framework.extensions.parseMainBalance -import cu.suitetecsa.sdk.android.framework.extensions.parseMainData -import cu.suitetecsa.sdk.android.framework.extensions.parseMainSms -import cu.suitetecsa.sdk.android.framework.extensions.parseMainVoice -import java.util.LinkedList -import java.util.Queue - -private const val DELAY_MS = 2000L - -/** - * Object that implements the logic for executing USSD requests. - * - * This class is responsible for sending USSD requests and processing the received responses. - * It uses the CALL_PHONE permission to make the requests. - */ -object UssdBalanceCommandExecutor : UssdBalanceRequestExecutor { - - /** - * Executes a USSD balance request. - * - * This method initializes the USSD request and prepares the queue of consult types. - * It requires the CALL_PHONE permission to function correctly. - * - * @param callback The callback interface to handle USSD responses. - * @throws SecurityException if the CALL_PHONE permission is not granted. - */ - @RequiresApi(Build.VERSION_CODES.O) - @RequiresPermission(android.Manifest.permission.CALL_PHONE) - override fun execute(callback: UssdBalanceRequestExecutorCallBack) { - val requestsTypes = LinkedList() - requestsTypes.offer(UssdConsultType.PrincipalBalance) - Handler(Looper.getMainLooper()).postDelayed({ sendRequest(callback, requestsTypes) }, DELAY_MS) - } - - /** - * Executes a USSD balance request. - * - * This method initializes the USSD request and prepares the queue of consult types. - * It requires the CALL_PHONE permission to function correctly. - * - * @param callback The callback interface to handle USSD responses. - * @throws SecurityException if the CALL_PHONE permission is not granted. - */ - @RequiresApi(Build.VERSION_CODES.O) - @RequiresPermission(android.Manifest.permission.CALL_PHONE) - override fun execute(ussdCode: String, callback: UssdBalanceRequestExecutorCallBack) { - val requestsTypes = LinkedList() - requestsTypes.offer(UssdConsultType.Custom(ussdCode)) - Handler(Looper.getMainLooper()).postDelayed({ sendRequest(callback, requestsTypes) }, DELAY_MS) - } - - /** - * Sends a USSD request and processes the response. - * - * This method sends the USSD request and handles the response through the callback. - * It requires the CALL_PHONE permission to function correctly. - * - * @param callback The callback interface to handle USSD responses. - * @param requestsTypes The queue of USSD consult types. - * @throws SecurityException if the CALL_PHONE permission is not granted. - */ - @RequiresApi(Build.VERSION_CODES.O) - @RequiresPermission(android.Manifest.permission.CALL_PHONE) - private fun sendRequest( - callback: UssdBalanceRequestExecutorCallBack, - requestsTypes: Queue - ) { - requestsTypes.poll()?.also { - callback.onRequesting(it) - callback.telephonyManager.sendUssdRequest( - it.ussdCode, - object : TelephonyManager.UssdResponseCallback() { - @RequiresPermission(android.Manifest.permission.CALL_PHONE) - override fun onReceiveUssdResponse( - telephonyManager: TelephonyManager, - request: String, - response: CharSequence - ) { - when (it) { - UssdConsultType.PrincipalBalance -> { - response.parseMainBalance()?.let { balance -> - balance.data?.also { requestsTypes.offer(UssdConsultType.DataBalance) } - balance.voice?.also { requestsTypes.offer(UssdConsultType.VoiceBalance) } - balance.sms?.also { requestsTypes.offer(UssdConsultType.MessagesBalance) } - callback.onSuccess( - UssdResponse.PrincipalBalance( - balance.credit, - balance.activeUntil, - balance.mainBalanceDueDate, - requestsTypes.toList() - ) - ) - requestsTypes.offer(UssdConsultType.BonusBalance) - } ?: run { - callback.onFailure(UssdRequestException(response.toString())) - } - } - UssdConsultType.DataBalance -> { - response.parseMainData()?.let { mainData -> - callback.onSuccess( - UssdResponse.DataBalance( - usageBasedPricing = mainData.usageBasedPricing, - data = mainData.data, - dataLte = mainData.dataLte, - remainingDays = mainData.remainingDays, - dailyData = response.parseDailyData(), - mailData = response.parseMailData() - ) - ) - } ?: run { - callback.onFailure(UssdRequestException(response.toString())) - } - } - UssdConsultType.VoiceBalance -> { - response.parseMainVoice()?.let { voiceBalance -> - callback.onSuccess(voiceBalance) - } ?: run { - callback.onFailure(UssdRequestException(response.toString())) - } - } - UssdConsultType.MessagesBalance -> { - response.parseMainSms()?.let { messagesBalance -> - callback.onSuccess(messagesBalance) - } ?: run { - callback.onFailure(UssdRequestException(response.toString())) - } - } - UssdConsultType.BonusBalance -> { - callback.onSuccess(response.parseBonusBalance()) - } - is UssdConsultType.Custom -> { - callback.onSuccess(UssdResponse.Custom(response.toString())) - } - } - Handler(Looper.getMainLooper()).postDelayed({ sendRequest(callback, requestsTypes) }, DELAY_MS) - } - }, - Handler(Looper.getMainLooper()) - ) - } - } -} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdBalanceRequestExecutor.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdBalanceRequestExecutor.kt deleted file mode 100644 index 11d4652..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdBalanceRequestExecutor.kt +++ /dev/null @@ -1,14 +0,0 @@ -package cu.suitetecsa.sdk.android.framework - -/** - * Interface for executing a USSD balance request. - */ -interface UssdBalanceRequestExecutor { - /** - * Executes a USSD balance request with the provided callback. - * - * @param callback The callback to be invoked with the result of the USSD balance request. - */ - fun execute(callback: UssdBalanceRequestExecutorCallBack) - fun execute(ussdCode: String, callback: UssdBalanceRequestExecutorCallBack) -} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdBalanceRequestExecutorCallBack.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdBalanceRequestExecutorCallBack.kt deleted file mode 100644 index 411d8ed..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdBalanceRequestExecutorCallBack.kt +++ /dev/null @@ -1,34 +0,0 @@ -package cu.suitetecsa.sdk.android.framework - -import android.telephony.TelephonyManager - -/** - * Callback interface for USSD balance request execution. - */ -interface UssdBalanceRequestExecutorCallBack { - /** - * The TelephonyManager instance associated with the USSD balance request. - */ - val telephonyManager: TelephonyManager - - /** - * Callback function invoked when a USSD balance request is being made. - * - * @param consultType The type of USSD consult being requested. - */ - fun onRequesting(consultType: UssdConsultType) - - /** - * Callback function invoked when a USSD balance request is successful. - * - * @param ussdResponse The USSD response received. - */ - fun onSuccess(ussdResponse: UssdResponse) - - /** - * Callback function invoked when a USSD balance request fails. - * - * @param throwable The throwable representing the failure reason. - */ - fun onFailure(throwable: Throwable) -} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdConsultType.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdConsultType.kt deleted file mode 100644 index f35e6d5..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdConsultType.kt +++ /dev/null @@ -1,36 +0,0 @@ -package cu.suitetecsa.sdk.android.framework - -import android.net.Uri - -/** - * Represents different types of USSD consults. - * - * @property ussdCode The USSD code associated with the consult type. - */ -sealed class UssdConsultType(val ussdCode: String) { - /** - * Represents a consult for the principal balance. - */ - data object PrincipalBalance : UssdConsultType("*222${Uri.parse("#")}") - - /** - * Represents a consult for the data balance. - */ - data object DataBalance : UssdConsultType("*222*328${Uri.parse("#")}") - - /** - * Represents a consult for the voice balance. - */ - data object VoiceBalance : UssdConsultType("*222*869${Uri.parse("#")}") - - /** - * Represents a consult for the messages balance. - */ - data object MessagesBalance : UssdConsultType("*222*767${Uri.parse("#")}") - - /** - * Represents a consult for the bonus balance. - */ - data object BonusBalance : UssdConsultType("*222*266${Uri.parse("#")}") - data class Custom(val code: String) : UssdConsultType(code) -} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdRequestException.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdRequestException.kt deleted file mode 100644 index aa00e4d..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdRequestException.kt +++ /dev/null @@ -1,8 +0,0 @@ -package cu.suitetecsa.sdk.android.framework - -/** - * Exception thrown when there is an error in processing a USSD request. - * - * @param message The error message associated with the exception. - */ -class UssdRequestException(message: String) : Exception(message) diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdResponse.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdResponse.kt deleted file mode 100644 index 7f6f493..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/UssdResponse.kt +++ /dev/null @@ -1,84 +0,0 @@ -package cu.suitetecsa.sdk.android.framework - -import cu.suitetecsa.sdk.android.domain.model.BonusCredit -import cu.suitetecsa.sdk.android.domain.model.BonusData -import cu.suitetecsa.sdk.android.domain.model.BonusDataCU -import cu.suitetecsa.sdk.android.domain.model.BonusUnlimitedData -import cu.suitetecsa.sdk.android.domain.model.DailyData -import cu.suitetecsa.sdk.android.domain.model.MailData - -/** - * Sealed class representing different types of USSD responses. - */ -sealed class UssdResponse { - /** - * Represents the principal balance response. - * - * @param credit The credit amount. - * @param activeUntil The active until date. - * @param dueDate The due date. - * @param consults The list of USSD consult types. - */ - data class PrincipalBalance( - val credit: Float, - val activeUntil: String, - val dueDate: String, - val consults: List - ) : UssdResponse() - - /** - * Represents the data balance response. - * - * @param usageBasedPricing Indicates if the pricing is usage-based. - * @param data The data amount. - * @param dataLte The LTE data amount. - * @param remainingDays The remaining days. - * @param dailyData The daily data information. - * @param mailData The mail data information. - */ - data class DataBalance( - val usageBasedPricing: Boolean, - val data: Double?, - val dataLte: Double?, - val remainingDays: Int?, - val dailyData: DailyData?, - val mailData: MailData? - ) : UssdResponse() - - /** - * Represents the voice balance response. - * - * @param time The voice time in seconds. - * @param remainingDays The remaining days. - */ - data class VoiceBalance(val time: Long, val remainingDays: Int?) : UssdResponse() - - /** - * Represents the messages balance response. - * - * @param count The message count. - * @param remainingDays The remaining days. - */ - data class MessagesBalance(val count: Int, val remainingDays: Int?) : UssdResponse() - - /** - * Represents the bonus balance response. - * - * @param credit The bonus credit information. - * @param unlimitedData The bonus unlimited data information. - * @param data The bonus data information. - * @param dataCu The bonus data CU information. - */ - data class BonusBalance( - val credit: BonusCredit?, - val unlimitedData: BonusUnlimitedData?, - val data: BonusData?, - val dataCu: BonusDataCU? - ) : UssdResponse() - - data class Custom(val response: String) : UssdResponse() - - companion object { - const val PROCESSING_RESPONSE = "Su solicitud esta siendo procesada." - } -} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseBonusBalance.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseBonusBalance.kt deleted file mode 100644 index 3b0268d..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseBonusBalance.kt +++ /dev/null @@ -1,74 +0,0 @@ -package cu.suitetecsa.sdk.android.framework.extensions - -import cu.suitetecsa.sdk.android.domain.model.BonusCredit -import cu.suitetecsa.sdk.android.domain.model.BonusData -import cu.suitetecsa.sdk.android.domain.model.BonusDataCU -import cu.suitetecsa.sdk.android.domain.model.BonusUnlimitedData -import cu.suitetecsa.sdk.android.framework.UssdResponse -import cu.suitetecsa.sdk.android.framework.toBytes - -/** - * Parses the bonus balance from a given CharSequence and returns a UssdResponse.BonusBalance object. - * - * @return The parsed bonus balance as a UssdResponse.BonusBalance object. - */ -fun CharSequence.parseBonusBalance(): UssdResponse.BonusBalance { - // Regular expressions to match the bonus credit, bonus data, and bonus data CU patterns - val creditRegex = - """\$(?([\d.]+))\s+vence\s+(?(\d{2}-\d{2}-\d{2}))\.""" - .toRegex() - val dataRegex = - ( - """Datos:\s+(ilimitados\s+vence\s+(?(\d{2}-\d{2}-\d{2}))\.)?""" + - """(\s+)?((?(\d+(\.\d+)?)(\s)*([GMK])?B))?(\s+\+\s+)?""" + - """((?(\d+(\.\d+)?)(\s)*([GMK])?B)\s+LTE)?(\s+vence\s+)?""" + - """((?(\d{2}-\d{2}-\d{2}))\.)?""" - ) - .toRegex() - val dataCURegex = - ( - """Datos\.cu\s+(?(\d+(\.\d+)?)(\s)*([GMK])?B)?(\s+vence\s+)?""" + - """(?(\d{2}-\d{2}-\d{2}))?\.""" - ) - .toRegex() - - // Parse bonus credit - val bonusCredit = creditRegex.find(this)?.let { matchResult -> - BonusCredit( - credit = matchResult.groups["bonusCredit"]?.value?.toFloatOrNull()!!, - bonusCreditDueDate = matchResult.groups["bonusCreditDueDate"]?.value!! - ) - } - - // Parse bonus data and bonus unlimited data - val (bonusData, bonusUnlimitedData) = dataRegex.find(this)?.let { dataMatcher -> - Pair( - BonusData( - bonusDataCount = dataMatcher.groups["dataAllNetworkBonus"]?.value?.toBytes(), - bonusDataCountLte = dataMatcher.groups["bonusDataLte"]?.value?.toBytes(), - bonusDataDueDate = dataMatcher.groups["bonusDataDueDate"]?.value ?: "" - ), - dataMatcher.groups["unlimitedData"]?.value?.let { - BonusUnlimitedData( - bonusUnlimitedDataDueDate = it - ) - } - ) - } ?: Pair(null, null) - - // Parse bonus data CU - val bonusDataCU = dataCURegex.find(this)?.let { dataCUMatcher -> - BonusDataCU( - bonusDataCuCount = dataCUMatcher.groups["bonusDataCu"]?.value?.toBytes()!!, - bonusDataCuDueDate = dataCUMatcher.groups["bonusDataCuDueDate"]?.value!! - ) - } - - // Return the parsed bonus balance - return UssdResponse.BonusBalance( - credit = bonusCredit, - data = bonusData, - dataCu = bonusDataCU, - unlimitedData = bonusUnlimitedData - ) -} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseDailyData.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseDailyData.kt deleted file mode 100644 index daa080b..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseDailyData.kt +++ /dev/null @@ -1,26 +0,0 @@ -package cu.suitetecsa.sdk.android.framework.extensions - -import cu.suitetecsa.sdk.android.domain.model.DailyData -import cu.suitetecsa.sdk.android.framework.toBytes - -/** - * Parses the daily data from a given CharSequence and returns a DailyData object. - * - * @return The parsed daily data as a DailyData object, or null if the data cannot be parsed. - */ -fun CharSequence.parseDailyData(): DailyData? { - // Regular expression to match the daily data pattern - val dailyDataRegex = - ( - """Diaria:\s+(?(\d+(\.\d+)?)(\s)*([GMK])?B)?(\s+no activos)?""" + - """(\s+validos\s+(?(\d+))\s+horas)?\.""" - ).toRegex() - - // Parse the daily data - return dailyDataRegex.find(this)?.let { matchResult -> - DailyData( - data = matchResult.groups["dataDaily"]?.value?.toBytes()!!, - remainingHours = matchResult.groups["dueDate"]?.value?.toInt() - ) - } -} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseMailData.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseMailData.kt deleted file mode 100644 index 3af91d5..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseMailData.kt +++ /dev/null @@ -1,27 +0,0 @@ -package cu.suitetecsa.sdk.android.framework.extensions - -import cu.suitetecsa.sdk.android.domain.model.MailData -import cu.suitetecsa.sdk.android.framework.toBytes - -/** - * Parses the mail data from a given CharSequence and returns a MailData object. - * - * @return The parsed mail data as a MailData object, or null if the data cannot be parsed. - */ -fun CharSequence.parseMailData(): MailData? { - // Regular expression to match the mail data pattern - val mailDataRegex = - ( - """Mensajeria:\s+(?(\d+(\.\d+)?)(\s)*([GMK])?B)?(\s+no activos)?""" + - """(\s+validos\s+(?(\d+))\s+dias)?\.""" - ) - .toRegex() - - // Parse the mail data - return mailDataRegex.find(this)?.let { matchResult -> - MailData( - data = matchResult.groups["dataMail"]?.value?.toBytes()!!, - remainingDays = matchResult.groups["dueDate"]?.value?.toInt() - ) - } -} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseMainBalance.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseMainBalance.kt deleted file mode 100644 index 2f0656d..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseMainBalance.kt +++ /dev/null @@ -1,82 +0,0 @@ -package cu.suitetecsa.sdk.android.framework.extensions - -import cu.suitetecsa.sdk.android.domain.model.MainBalance -import cu.suitetecsa.sdk.android.domain.model.MainData -import cu.suitetecsa.sdk.android.domain.model.MainSms -import cu.suitetecsa.sdk.android.domain.model.MainVoice -import cu.suitetecsa.sdk.android.framework.toBytes -import cu.suitetecsa.sdk.android.framework.toSeconds - -/** - * Parses the main balance data from a given CharSequence and returns a MainBalance object. - * - * @return The parsed main balance data as a MainBalance object, or null if the data cannot be parsed. - */ -internal fun CharSequence.parseMainBalance(): MainBalance? { - // Regular expression to match the credit, activeUntil, and dueDate pattern - val creditRegex = - ( - """Saldo:\s+(?([\d.]+))\s+CUP\.\s+([^"]*?)?""" + - """Linea activa hasta\s+(?(\d{2}-\d{2}-\d{2}))""" + - """\s+vence\s+(?(\d{2}-\d{2}-\d{2}))\.""" - ) - .toRegex() - // Parse the credit, activeUntil, and dueDate - val (credit, activeUntil, dueDate) = creditRegex.find(this)?.let { matchResult -> - Triple( - matchResult.groups["principalCredit"]?.value!!.toFloat(), - matchResult.groups["activeUntil"]?.value!!, - matchResult.groups["dueDate"]?.value!! - ) - } ?: run { return null } - - // Regular expression to match the dataAllNetwork and dataLte pattern - val dataRegex = - ( - """Datos:\s+(?(\d+(\.\d+)?)(\s)*([GMK])?B)?(\s+\+\s+)?""" + - """((?(\d+(\.\d+)?)(\s)*([GMK])?B)\s+LTE)?\.""" - ) - .toRegex() - - // Parse the dataAllNetwork and dataLte - val (dataAllNetwork, dataLte) = dataRegex.find(this)?.let { matchResult -> - Pair( - matchResult.groups["dataAllNetwork"]?.value?.toBytes(), - matchResult.groups["dataLte"]?.value?.toBytes() - ) - } ?: Pair(null, null) - - // Create the MainData object - val mainData = MainData( - usageBasedPricing = false, - data = dataAllNetwork, - dataLte = dataLte, - remainingDays = null - ) - - // Regular expression to match the voice pattern - val voiceRegex = """Voz:\s+(?(\d{1,3}:\d{2}:\d{2}))\.""".toRegex() - // Parse the voice - val voice = voiceRegex.find(this)?.groups?.get("voice")?.value?.toSeconds() - // Create the MainVoice object - val mainVoice = voice?.let { MainVoice(mainVoice = it, remainingDays = null) } - - // Regular expression to match the sms pattern - val smsRegex = """SMS:\s+(?(\d+))\.""".toRegex() - // Parse the sms - val sms = smsRegex.find(this)?.groups?.get("sms")?.value?.toInt() - // Create the MainSms object - val mainSms = sms?.let { MainSms(mainSms = it, remainingDays = 0) } - - // Create and return the MainBalance object - return MainBalance( - credit = credit, - activeUntil = activeUntil, - mainBalanceDueDate = dueDate, - data = mainData, - voice = mainVoice, - sms = mainSms, - dailyData = null, - mailData = null - ) -} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseMainData.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseMainData.kt deleted file mode 100644 index 1fa6f91..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseMainData.kt +++ /dev/null @@ -1,41 +0,0 @@ -package cu.suitetecsa.sdk.android.framework.extensions - -import cu.suitetecsa.sdk.android.domain.model.MainData -import cu.suitetecsa.sdk.android.framework.toBytes - -/** - * Parses the main data from a given CharSequence and returns a MainData object. - * - * @return The parsed main data as a MainData object, or null if the data cannot be parsed. - */ -fun CharSequence.parseMainData(): MainData? { - // Regular expression to match the usageBasedPricing pattern - val usageBasedPricingRegex = """Tarifa:\s+(?[^"]*?)\.""".toRegex() - // Parse the usageBasedPricing - val usageBasedPricing = usageBasedPricingRegex.find(this)?.let { matchResult -> - matchResult.groups["tfc"]?.value != "No activa" - } ?: run { return null } - - // Regular expression to match the dataAllNetwork, dataLte, and remainingDays pattern - val mainDataRegex = ( - """Paquetes:\s+(?(\d+(\.\d+)?)(\s)*([GMK])?B)?""" + - """(\s+\+\s+)?((?(\d+(\.\d+)?)(\s)*([GMK])?B)\s+LTE)?""" + - """(\s+no activos)?(\s+validos\s+(?(\d+))\s+dias)?\.""" - ).toRegex() - // Parse the dataAllNetwork, dataLte, and remainingDays - val (data, dataLte, remainingDays) = mainDataRegex.find(this)?.let { matchResult -> - Triple( - matchResult.groups["dataAllNetwork"]?.value?.toBytes(), - matchResult.groups["dataLte"]?.value?.toBytes(), - matchResult.groups["dueDate"]?.value?.toInt() - ) - } ?: Triple(null, null, null) - - // Create and return the MainData object - return MainData( - usageBasedPricing = usageBasedPricing, - data = data, - dataLte = dataLte, - remainingDays = remainingDays - ) -} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseMainSms.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseMainSms.kt deleted file mode 100644 index b57cc37..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseMainSms.kt +++ /dev/null @@ -1,23 +0,0 @@ -package cu.suitetecsa.sdk.android.framework.extensions - -import cu.suitetecsa.sdk.android.framework.UssdResponse.MessagesBalance - -/** - * Parses the main SMS balance from a given CharSequence and returns a UssdResponse.MessagesBalance object. - * - * @return The parsed main SMS balance as a UssdResponse.MessagesBalance object, or null if the data cannot be parsed. - */ -fun CharSequence.parseMainSms(): MessagesBalance? { - // Regular expression to match the SMS balance pattern - val smsRegex = - """Usted dispone de\s+(?(\d+))\s+SMS(\s+no activos)?(\s+validos por\s+(?(\d+))\s+dias)?(\.)?""" - .toRegex() - - // Parse the SMS balance and due date - return smsRegex.find(this)?.let { matchResult -> - MessagesBalance( - matchResult.groups["sms"]?.value!!.toInt(), - matchResult.groups["dueDate"]?.value?.toInt() - ) - } -} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseMainVoice.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseMainVoice.kt deleted file mode 100644 index 2c44db1..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/framework/extensions/ParseMainVoice.kt +++ /dev/null @@ -1,27 +0,0 @@ -package cu.suitetecsa.sdk.android.framework.extensions - -import cu.suitetecsa.sdk.android.framework.UssdResponse.VoiceBalance -import cu.suitetecsa.sdk.android.framework.toSeconds - -/** - * Parses the main voice balance from a given CharSequence and returns a UssdResponse.VoiceBalance object. - * - * @return The parsed main voice balance as a UssdResponse.VoiceBalance object, or null if the data cannot be parsed. - */ -fun CharSequence.parseMainVoice(): VoiceBalance? { - // Regular expression to match the voice balance pattern - val voicePattern = - ( - """Usted dispone de\s+(?(\d+:\d{2}:\d{2}))\s+MIN(\s+no activos)?""" + - """(\s+validos por\s+(?(\d+))\s+dias)?""" - ) - .toRegex() - - // Parse the voice balance and due date - return voicePattern.find(this)?.let { matchResult -> - VoiceBalance( - matchResult.groups["voice"]?.value?.toSeconds()!!, - matchResult.groups["dueDate"]?.value?.toInt() - ) - } -} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/LongUtils.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/LongUtils.kt new file mode 100644 index 0000000..5da4a6e --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/LongUtils.kt @@ -0,0 +1,8 @@ +package cu.suitetecsa.sdk.android.kotlin + +import cu.suitetecsa.sdk.android.utils.LongUtils + +val Long.asDateString: String get() = LongUtils.toDateString(this) +val Long.asSizeString: String get() = LongUtils.toSizeString(this) +val Long.asTimeString: String get() = LongUtils.toTimeString(this) +val Long.asRemainingDays: Int get() = LongUtils.toRemainingDays(this) diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/SimCardExtension.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/SimCardExtension.kt new file mode 100644 index 0000000..549976a --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/SimCardExtension.kt @@ -0,0 +1,65 @@ +package cu.suitetecsa.sdk.android.kotlin + +import android.content.Context +import android.os.Build +import android.telephony.TelephonyManager +import androidx.annotation.RequiresApi +import androidx.annotation.RequiresPermission +import cu.suitetecsa.sdk.android.balance.ConsultBalanceCallBack +import cu.suitetecsa.sdk.android.balance.RequestCallback +import cu.suitetecsa.sdk.android.balance.UssdRequestSender +import cu.suitetecsa.sdk.android.balance.consult.UssdRequest +import cu.suitetecsa.sdk.android.balance.response.UssdResponse +import cu.suitetecsa.sdk.android.model.SimCard +import cu.suitetecsa.sdk.android.utils.SimCardUtils + +/** + * Consults the balance using USSD requests. + * + * This function sends USSD requests to consult the balance and handles the responses through the provided callback. + * It requires the CALL_PHONE permission to function correctly. + * + * @param callBack The callback interface to handle USSD responses. + * @throws SecurityException if the CALL_PHONE permission is not granted. + */ +@RequiresApi(Build.VERSION_CODES.O) +@RequiresPermission(android.Manifest.permission.CALL_PHONE) +fun SimCard.consultBalance(callBack: ConsultBalanceCallBack) { + val ussdBalanceRequestExecutorCallBack = object : RequestCallback { + + override fun getTelephonyManager(): TelephonyManager = this@consultBalance.telephony()!! + + override fun onRequesting(ussdRequest: UssdRequest) = callBack.onRequesting(ussdRequest) + + override fun onSuccess( + request: UssdRequest, + response: UssdResponse + ) = callBack.onSuccess(request, response) + + override fun onFailure(throwable: Throwable) = callBack.onFailure(throwable) + } + UssdRequestSender.Builder().build().send(ussdBalanceRequestExecutorCallBack) +} + +@RequiresApi(Build.VERSION_CODES.O) +@RequiresPermission(android.Manifest.permission.CALL_PHONE) +fun SimCard.ussdExecute(ussdCode: String, callBack: ConsultBalanceCallBack) { + val ussdBalanceRequestExecutorCallBack = object : RequestCallback { + override fun getTelephonyManager(): TelephonyManager = this@ussdExecute.telephony()!! + + override fun onRequesting(ussdRequest: UssdRequest) = callBack.onRequesting(ussdRequest) + + override fun onSuccess( + request: UssdRequest, + response: UssdResponse + ) = callBack.onSuccess(request, response) + + override fun onFailure(throwable: Throwable) = callBack.onFailure(throwable) + } + UssdRequestSender.Builder().build().send(ussdCode, ussdBalanceRequestExecutorCallBack) +} + +@RequiresPermission(android.Manifest.permission.CALL_PHONE) +fun SimCard.makeCall(context: Context, phoneNumber: String) { + SimCardUtils.makeCall(this, context, phoneNumber) +} \ No newline at end of file diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/BonusCredit.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/BonusCredit.java new file mode 100644 index 0000000..6b77639 --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/BonusCredit.java @@ -0,0 +1,4 @@ +package cu.suitetecsa.sdk.android.model; + +public record BonusCredit(double balance, long dueDate) { +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/BonusData.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/BonusData.java new file mode 100644 index 0000000..f36da1f --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/BonusData.java @@ -0,0 +1,4 @@ +package cu.suitetecsa.sdk.android.model; + +public record BonusData(Long data, Long dataLte, long dueDate) { +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/BonusDataCU.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/BonusDataCU.java new file mode 100644 index 0000000..e4da810 --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/BonusDataCU.java @@ -0,0 +1,4 @@ +package cu.suitetecsa.sdk.android.model; + +public record BonusDataCU(long data, long dueDate) { +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/BonusUnlimitedData.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/BonusUnlimitedData.java new file mode 100644 index 0000000..857551d --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/BonusUnlimitedData.java @@ -0,0 +1,4 @@ +package cu.suitetecsa.sdk.android.model; + +public record BonusUnlimitedData(long dueDate) { +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/DailyData.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/DailyData.java new file mode 100644 index 0000000..93fffac --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/DailyData.java @@ -0,0 +1,4 @@ +package cu.suitetecsa.sdk.android.model; + +public record DailyData(long data, Integer remainingHours) { +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/MailData.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/MailData.java new file mode 100644 index 0000000..b16d424 --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/MailData.java @@ -0,0 +1,4 @@ +package cu.suitetecsa.sdk.android.model; + +public record MailData(long data, Integer remainingDays) { +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/MainBalance.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/MainBalance.java new file mode 100644 index 0000000..0559c0a --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/MainBalance.java @@ -0,0 +1,5 @@ +package cu.suitetecsa.sdk.android.model; + +public record MainBalance(double balance, MainData data, MainVoice voice, MainSms sms, + DailyData dailyData, MailData mailData, long activeUntil, long dueDate) { +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/MainData.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/MainData.java new file mode 100644 index 0000000..3ad35e1 --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/MainData.java @@ -0,0 +1,4 @@ +package cu.suitetecsa.sdk.android.model; + +public record MainData(boolean usageBasedPricing, Long data, Long dataLte, Integer remainingDays) { +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/MainSms.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/MainSms.java new file mode 100644 index 0000000..18f8eee --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/MainSms.java @@ -0,0 +1,4 @@ +package cu.suitetecsa.sdk.android.model; + +public record MainSms(long sms, Integer remainingDays) { +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/MainVoice.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/MainVoice.java new file mode 100644 index 0000000..b99df3f --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/MainVoice.java @@ -0,0 +1,4 @@ +package cu.suitetecsa.sdk.android.model; + +public record MainVoice(long seconds, Integer remainingDays) { +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/SimCard.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/SimCard.java new file mode 100644 index 0000000..d5b3287 --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/model/SimCard.java @@ -0,0 +1,7 @@ +package cu.suitetecsa.sdk.android.model; + +import android.telephony.TelephonyManager; + +public record SimCard(String serialNumber, String displayName, int slotIndex, int subscriptionId, + TelephonyManager telephony) { +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/LongUtils.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/LongUtils.java new file mode 100644 index 0000000..0dcf329 --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/LongUtils.java @@ -0,0 +1,53 @@ +package cu.suitetecsa.sdk.android.utils; + +import androidx.annotation.NonNull; + +import org.jetbrains.annotations.NotNull; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Locale; + +public class LongUtils { + public static @NotNull String toDateString(Long date) { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(date); + return new SimpleDateFormat("dd/MM/yy", Locale.getDefault()).format(calendar.getTime()); + } + + @NonNull + public static String toTimeString(Long time) { + int SECONDS_IN_HOUR = 3600; + int SECONDS_IN_MINUTE = 60; + long hours = time / SECONDS_IN_HOUR; + long minutes = (time % SECONDS_IN_HOUR) / SECONDS_IN_MINUTE; + long seconds = time % SECONDS_IN_MINUTE; + return String.format(Locale.getDefault(), "%02d:%02d:%02d", hours, minutes, seconds); + } + + /** + * Converts a size value in bytes to a human-readable string representation. + * + * @return The size value formatted as a string with the appropriate unit (bytes, KB, MB, GB, TB). + */ + public static @NotNull String toSizeString(long size) { + double SIZE_UNIT_MAX_LENGTH = 1024.0; + String[] sizeUnits = {"bytes", "KB", "MB", "GB", "TB"}; + double sizeValue = size; + int sizeUnitIndex = 0; + while (sizeValue >= SIZE_UNIT_MAX_LENGTH && sizeUnitIndex < sizeUnits.length - 1) { + sizeValue /= SIZE_UNIT_MAX_LENGTH; + sizeUnitIndex++; + } + return String.format(Locale.getDefault(), "%.2f %s", sizeValue, sizeUnits[sizeUnitIndex]); + } + + public static int toRemainingDays(long date) { + int HOURS_PER_DAY = 24; + int MINUTES_PER_HOUR = 60; + int MILLISECONDS = 1000; + Calendar calendar = Calendar.getInstance(); + long diffInMillis = date - calendar.getTimeInMillis(); + return (int) ((diffInMillis / (HOURS_PER_DAY * MINUTES_PER_HOUR * MINUTES_PER_HOUR * MILLISECONDS)) + 1); + } +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/SimCardUtils.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/SimCardUtils.java new file mode 100644 index 0000000..7e2bb58 --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/SimCardUtils.java @@ -0,0 +1,24 @@ +package cu.suitetecsa.sdk.android.utils; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Build; + +import cu.suitetecsa.sdk.android.model.SimCard; + +public class SimCardUtils { + public static void makeCall(SimCard simCard, Context context, String phoneNumber) { + Uri uri = Uri.parse("tel:" + phoneNumber); + Intent intent = new Intent(Intent.ACTION_CALL, uri); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + intent.putExtra("android.telecom.extra.PHONE_ACCOUNT_HANDLE", String.valueOf(simCard.subscriptionId())); + } else { + intent.putExtra("con.android.phone.extra.PHONE_ACCOUNT_HANDLE", String.valueOf(simCard.subscriptionId())); + } + + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/StringUtils.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/StringUtils.java new file mode 100644 index 0000000..fd1a9e5 --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/StringUtils.java @@ -0,0 +1,41 @@ +package cu.suitetecsa.sdk.android.utils; + +import androidx.annotation.NonNull; + +import org.jetbrains.annotations.NotNull; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; + +public class StringUtils { + public static long toSeconds(@NotNull String time) { + String[] parts = time.split(":"); + long totalSeconds = 0; + + for (String part : parts) { + int SECONDS_PER_MINUTE = 60; + totalSeconds = totalSeconds * SECONDS_PER_MINUTE + Long.parseLong(part); + } + + return totalSeconds; + } + + public static long toDateMillis(String date) throws ParseException { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(toDate(date)); + return calendar.getTimeInMillis(); + } + + public static Date toDate(String date) throws ParseException { + return new SimpleDateFormat("dd-MM-yy", Locale.getDefault()).parse(date); + } + + public static long toBytes(@NotNull String data) { + String count = data.replaceAll("[GMKBT]", ""); + String unit = data.split(" ")[data.split(" ").length - 1].toUpperCase(); + return (long) (Double.parseDouble(count) * Math.pow(1024, "BKMGT".indexOf(unit.charAt(0)))); + } +} From 2c9e512c43380de763703cd4f177ae7b9dfbdd2c Mon Sep 17 00:00:00 2001 From: lesclaz Date: Thu, 8 Feb 2024 18:38:34 -0500 Subject: [PATCH 2/7] lint fixes --- .../presentation/balance/BalancesViewModel.kt | 16 +++++----- .../balance/parser/MailDataParser.java | 2 +- .../android/balance/parser/MainSmsParser.java | 2 +- .../balance/parser/MainVoiceParser.java | 2 +- .../balance/response/PrincipalBalance.java | 30 ++----------------- .../balance/response/UssdResponse.java | 2 +- .../sdk/android/kotlin/SimCardExtension.kt | 2 +- .../sdk/android/utils/StringUtils.java | 2 -- 8 files changed, 15 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalancesViewModel.kt b/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalancesViewModel.kt index 85b76f9..99add1c 100644 --- a/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalancesViewModel.kt +++ b/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalancesViewModel.kt @@ -117,11 +117,11 @@ class BalancesViewModel @Inject constructor( this@BalancesViewModel.consultType = request val consultMessage = when (request) { BONUS_BALANCE -> "Consultando Bonos" - UssdRequest.DATA_BALANCE -> "Consultando Datos" - UssdRequest.MESSAGES_BALANCE -> "Consultando SMS" - UssdRequest.PRINCIPAL_BALANCE -> "Consultando Saldo" - UssdRequest.VOICE_BALANCE -> "Consultando Minutos" - UssdRequest.CUSTOM -> "" + DATA_BALANCE -> "Consultando Datos" + MESSAGES_BALANCE -> "Consultando SMS" + PRINCIPAL_BALANCE -> "Consultando Saldo" + VOICE_BALANCE -> "Consultando Minutos" + CUSTOM -> "" } _state.value = _state.value.copy(consultMessage = consultMessage) } @@ -169,9 +169,9 @@ class BalancesViewModel @Inject constructor( PRINCIPAL_BALANCE -> { _state.value = _state.value.copy( - balance = (ussdResponse as PrincipalBalance).balance.toFloat(), - activeUntil = ussdResponse.activeUntil.asDateString, - mainBalanceDueDate = ussdResponse.dueDate.asDateString, + balance = (ussdResponse as PrincipalBalance).balance().toFloat(), + activeUntil = ussdResponse.activeUntil().asDateString, + mainBalanceDueDate = ussdResponse.dueDate().asDateString, ) } diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MailDataParser.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MailDataParser.java index 4057f8b..7026026 100644 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MailDataParser.java +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MailDataParser.java @@ -36,7 +36,7 @@ public static MailData parseMailData(CharSequence input) throws ParseException { Integer remainingDays = null; - if (!mailDataMatcher.find()) return null;; + if (!mailDataMatcher.find()) return null; // Parse the mail data String dataMailStr = mailDataMatcher.group("dataMail"); assert dataMailStr != null; diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainSmsParser.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainSmsParser.java index a8ae120..cb063f0 100644 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainSmsParser.java +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainSmsParser.java @@ -34,7 +34,7 @@ public static MessagesBalance parseMainSms(CharSequence input) throws ParseExcep Integer remainingDays = null; - if(!smsMatcher.find()) throw new ParseException(input.toString(), 0);; + if(!smsMatcher.find()) throw new ParseException(input.toString(), 0); // Parse the SMS balance and due date String smsStr = smsMatcher.group("sms"); assert smsStr != null; diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainVoiceParser.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainVoiceParser.java index 6f82066..b8d16cf 100644 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainVoiceParser.java +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/parser/MainVoiceParser.java @@ -34,7 +34,7 @@ public static VoiceBalance parseMainVoice(CharSequence input) throws ParseExcept Integer remainingDays = null; - if(!voiceMatcher.find()) throw new ParseException(input.toString(), 0);; + if(!voiceMatcher.find()) throw new ParseException(input.toString(), 0); // Parse the voice balance and due date String voiceStr = voiceMatcher.group("voice"); assert voiceStr != null; diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/PrincipalBalance.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/PrincipalBalance.java index 68a971e..07e1692 100644 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/PrincipalBalance.java +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/PrincipalBalance.java @@ -7,32 +7,6 @@ /** * Clase para representar la respuesta de saldo principal */ -public class PrincipalBalance implements UssdResponse { - private final double balance; - private final long activeUntil; - private final long dueDate; - private final List consults; - - public PrincipalBalance(double balance, long activeUntil, long dueDate, List consults) { - this.balance = balance; - this.activeUntil = activeUntil; - this.dueDate = dueDate; - this.consults = consults; - } - - public double getBalance() { - return balance; - } - - public long getActiveUntil() { - return activeUntil; - } - - public long getDueDate() { - return dueDate; - } - - public List getConsults() { - return consults; - } +public record PrincipalBalance(double balance, long activeUntil, long dueDate, + List consults) implements UssdResponse { } diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/UssdResponse.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/UssdResponse.java index 97a6f20..cb5943b 100644 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/UssdResponse.java +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/UssdResponse.java @@ -4,6 +4,6 @@ * Interfaz para representar las diferentes respuestas USSD */ public interface UssdResponse { - public static final String PROCESSING_RESPONSE = "Su solicitud esta siendo procesada."; + String PROCESSING_RESPONSE = "Su solicitud esta siendo procesada."; } diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/SimCardExtension.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/SimCardExtension.kt index 549976a..c8acee2 100644 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/SimCardExtension.kt +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/SimCardExtension.kt @@ -62,4 +62,4 @@ fun SimCard.ussdExecute(ussdCode: String, callBack: ConsultBalanceCallBack) { @RequiresPermission(android.Manifest.permission.CALL_PHONE) fun SimCard.makeCall(context: Context, phoneNumber: String) { SimCardUtils.makeCall(this, context, phoneNumber) -} \ No newline at end of file +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/StringUtils.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/StringUtils.java index fd1a9e5..8b15eac 100644 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/StringUtils.java +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/StringUtils.java @@ -1,7 +1,5 @@ package cu.suitetecsa.sdk.android.utils; -import androidx.annotation.NonNull; - import org.jetbrains.annotations.NotNull; import java.text.ParseException; From b014d6815478657acababea840075fd075ab9006 Mon Sep 17 00:00:00 2001 From: lesclaz Date: Thu, 8 Feb 2024 19:45:56 -0500 Subject: [PATCH 3/7] various improvements --- .../presentation/balance/BalancesViewModel.kt | 14 ++++----- .../sdk/android/balance/RequestCallback.java | 4 +-- .../balance/response/BonusBalance.java | 30 ++----------------- .../sdk/android/balance/response/Custom.java | 11 +------ .../balance/response/VoiceBalance.java | 17 +---------- .../sdk/android/kotlin/SimCardExtension.kt | 4 +-- .../sdk/android/kotlin/StringUtils.kt | 24 +++++++++++++++ .../sdk/android/utils/SimCardUtils.java | 5 ++++ 8 files changed, 44 insertions(+), 65 deletions(-) create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/StringUtils.kt diff --git a/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalancesViewModel.kt b/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalancesViewModel.kt index 99add1c..fac20ab 100644 --- a/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalancesViewModel.kt +++ b/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalancesViewModel.kt @@ -133,10 +133,10 @@ class BalancesViewModel @Inject constructor( when (request) { BONUS_BALANCE -> { _state.value = _state.value.copy( - bonusCredit = (ussdResponse as BonusBalance).credit, - bonusData = ussdResponse.data, - bonusDataCU = ussdResponse.dataCu, - bonusUnlimitedData = ussdResponse.unlimitedData, + bonusCredit = (ussdResponse as BonusBalance).credit(), + bonusData = ussdResponse.data(), + bonusDataCU = ussdResponse.dataCu(), + bonusUnlimitedData = ussdResponse.unlimitedData(), ) _state.value = _state.value.copy( consultMessage = null, @@ -178,8 +178,8 @@ class BalancesViewModel @Inject constructor( VOICE_BALANCE -> { _state.value = _state.value.copy( voice = MainVoice( - (ussdResponse as VoiceBalance).time, - ussdResponse.remainingDays + (ussdResponse as VoiceBalance).seconds(), + ussdResponse.remainingDays() ) ) } @@ -229,7 +229,7 @@ class BalancesViewModel @Inject constructor( ) { when (request) { CUSTOM -> { - if ((ussdResponse as Custom).response == UssdResponse.PROCESSING_RESPONSE) { + if ((ussdResponse as Custom).response() == UssdResponse.PROCESSING_RESPONSE) { _state.value.data?.let { data -> _state.value = _state.value.copy( data = MainData( diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/RequestCallback.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/RequestCallback.java index 50a3227..a0033eb 100644 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/RequestCallback.java +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/RequestCallback.java @@ -17,9 +17,9 @@ public interface RequestCallback { /** * Método de devolución de llamada invocado cuando se realiza una solicitud de saldo USSD - * @param ussdRequest a UssdRequest instance + * @param request a UssdRequest instance */ - void onRequesting(UssdRequest ussdRequest); + void onRequesting(UssdRequest request); /** * Método de devolución de llamada invocado cuando una solicitud de saldo USSD tiene éxito diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/BonusBalance.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/BonusBalance.java index 2f7847b..f8382d5 100644 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/BonusBalance.java +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/BonusBalance.java @@ -8,32 +8,6 @@ /** * Clase para representar la respuesta de saldo de bonificación */ -public class BonusBalance implements UssdResponse { - private final BonusCredit credit; - private final BonusUnlimitedData unlimitedData; - private final BonusData data; - private final BonusDataCU dataCu; - - public BonusBalance(BonusCredit credit, BonusUnlimitedData unlimitedData, BonusData data, BonusDataCU dataCu) { - this.credit = credit; - this.unlimitedData = unlimitedData; - this.data = data; - this.dataCu = dataCu; - } - - public BonusCredit getCredit() { - return credit; - } - - public BonusUnlimitedData getUnlimitedData() { - return unlimitedData; - } - - public BonusData getData() { - return data; - } - - public BonusDataCU getDataCu() { - return dataCu; - } +public record BonusBalance(BonusCredit credit, BonusUnlimitedData unlimitedData, BonusData data, + BonusDataCU dataCu) implements UssdResponse { } diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/Custom.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/Custom.java index afacd68..f2d5ce3 100644 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/Custom.java +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/Custom.java @@ -3,14 +3,5 @@ /** * Clase para representar una respuesta USSD personalizada */ -public class Custom implements UssdResponse { - private final String response; - - public Custom(String response) { - this.response = response; - } - - public String getResponse() { - return response; - } +public record Custom(String response) implements UssdResponse { } diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/VoiceBalance.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/VoiceBalance.java index 68f262e..65c14d5 100644 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/VoiceBalance.java +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/response/VoiceBalance.java @@ -3,20 +3,5 @@ /** * Clase para representar la respuesta de saldo de voz */ -public class VoiceBalance implements UssdResponse { - private final long time; - private final Integer remainingDays; - - public VoiceBalance(long time, Integer remainingDays) { - this.time = time; - this.remainingDays = remainingDays; - } - - public long getTime() { - return time; - } - - public Integer getRemainingDays() { - return remainingDays; - } +public record VoiceBalance(long seconds, Integer remainingDays) implements UssdResponse { } diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/SimCardExtension.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/SimCardExtension.kt index c8acee2..685a2bb 100644 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/SimCardExtension.kt +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/SimCardExtension.kt @@ -29,7 +29,7 @@ fun SimCard.consultBalance(callBack: ConsultBalanceCallBack) { override fun getTelephonyManager(): TelephonyManager = this@consultBalance.telephony()!! - override fun onRequesting(ussdRequest: UssdRequest) = callBack.onRequesting(ussdRequest) + override fun onRequesting(request: UssdRequest) = callBack.onRequesting(request) override fun onSuccess( request: UssdRequest, @@ -47,7 +47,7 @@ fun SimCard.ussdExecute(ussdCode: String, callBack: ConsultBalanceCallBack) { val ussdBalanceRequestExecutorCallBack = object : RequestCallback { override fun getTelephonyManager(): TelephonyManager = this@ussdExecute.telephony()!! - override fun onRequesting(ussdRequest: UssdRequest) = callBack.onRequesting(ussdRequest) + override fun onRequesting(request: UssdRequest) = callBack.onRequesting(request) override fun onSuccess( request: UssdRequest, diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/StringUtils.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/StringUtils.kt new file mode 100644 index 0000000..b2ec7fc --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/StringUtils.kt @@ -0,0 +1,24 @@ +package cu.suitetecsa.sdk.android.kotlin + +import android.os.Build +import androidx.annotation.RequiresApi +import cu.suitetecsa.sdk.android.balance.parser.BonusBalanceParser +import cu.suitetecsa.sdk.android.balance.parser.MainBalanceParser +import cu.suitetecsa.sdk.android.balance.parser.MainDataParser +import cu.suitetecsa.sdk.android.balance.parser.MainSmsParser +import cu.suitetecsa.sdk.android.balance.parser.MainVoiceParser + +@RequiresApi(Build.VERSION_CODES.O) +fun String.parseMainBalance() = MainBalanceParser.parseMainBalance(this) + +@RequiresApi(Build.VERSION_CODES.O) +fun String.parseMainData() = MainDataParser.parseMainData(this) + +@RequiresApi(Build.VERSION_CODES.O) +fun String.parseMainVoice() = MainVoiceParser.parseMainVoice(this) + +@RequiresApi(Build.VERSION_CODES.O) +fun String.parseMainSms() = MainSmsParser.parseMainSms(this) + +@RequiresApi(Build.VERSION_CODES.O) +fun String.parseBonusBalance() = BonusBalanceParser.parseBonusBalance(this) diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/SimCardUtils.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/SimCardUtils.java index 7e2bb58..e611458 100644 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/SimCardUtils.java +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/SimCardUtils.java @@ -5,6 +5,7 @@ import android.net.Uri; import android.os.Build; +import cu.suitetecsa.sdk.android.balance.ConsultBalanceCallBack; import cu.suitetecsa.sdk.android.model.SimCard; public class SimCardUtils { @@ -21,4 +22,8 @@ public static void makeCall(SimCard simCard, Context context, String phoneNumber intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); } + + public static void ussdExecute(SimCard simCard, String ussdCode, ConsultBalanceCallBack callBack) { + + } } From bdfd7b0e7c3ef63622ffde075772bca29982938c Mon Sep 17 00:00:00 2001 From: lesclaz Date: Thu, 8 Feb 2024 19:47:13 -0500 Subject: [PATCH 4/7] update README.md --- README.md | 206 ++++++++++++++++++++++++++---------------------------- 1 file changed, 101 insertions(+), 105 deletions(-) diff --git a/README.md b/README.md index 8e6a21b..3ff6b94 100644 --- a/README.md +++ b/README.md @@ -21,24 +21,20 @@ Para obtener información sobre las tarjetas SIM insertadas en el dispositivo, p ```kotlin // Instancia SimCardsAPI -val simCardsAPI = SimCardsAPI - .Builder(context) - .build() +val simCardCollector = SimCardCollector.Builder().build(context) // Obtiene las tarjetas SIM insertadas en el dispositivo -val simCards = simCardsAPI.getSimCards() +val simCards = simCardCollector.collect() ``` #### Java ```java // Instancia SimCardsAPI -SimCardsAPI simCardsAPI = SimCardsAPI - .Builder(context) - .build(); +SimCardCollector simCardCollector = new SimCardCollector.Builder().build(context); // Obtiene las tarjetas SIM insertadas en el dispositivo -List simCards = simCardsAPI.getSimCards(); +List simCards = simCardCollector.collect(); ``` ### Realizar llamadas con una SIM @@ -46,13 +42,13 @@ List simCards = simCardsAPI.getSimCards(); #### Kotlin ```kotlin -simcCards.last().makeCall(context, "51234567") +simCards.last().makeCall(context, "51234567") ``` #### Java ```java -SimCardExtensionKt.makeCall(simCards.get(0), context, "51234567") +SimCardUtils.makeCall(simCards.get(0), context, "51234567"); ``` ### Obtener saldo de la tarjeta SIM @@ -66,17 +62,19 @@ Para obtener el saldo de la primera tarjeta SIM de la lista, puedes seguir estos val firstSimCard = simCards.first() var balance: MainBalance? = null // Enviar la solicitud + firstSimCard.ussdExecute( "*222#", object : ConsultBalanceCallBack { - override fun onRequesting(consultType: UssdConsultType) { + override fun onRequesting(request: UssdRequest) { Toast.makeText(context, "Consultando saldo...", Toast.LENGTH_LONG).show() } - override fun onSuccess(ussdResponse: UssdResponse) { - when (ussdResponse) { - is UssdResponse.Custom -> { + @SuppressLint("MissingPermission") + override fun onSuccess(request: UssdRequest, ussdResponse: UssdResponse) { + when (request) { + UssdRequest.CUSTOM -> { // Convierte el objeto UssdResponse en un objeto MainBalance - balance = ussdResponse.response.parseMainBalance() + balance = (ussdResponse as Custom).response.parseMainBalance() } else -> {} } @@ -93,27 +91,25 @@ firstSimCard.ussdExecute( ```java // Obtener la primera SIM de la lista SimCard firstSimCard = simCards.get(0); -MainBalance balance; +final MainBalance balance; // Enviar la solicitud -SimCardExtensionKt.ussdExecute(firstSimCard, "*222#", new ConsultBalanceCallBack() { - @Override - public void onRequesting(@NonNull UssdConsultType consultType) { +SimCardUtils.ussdExecute(firstSimCard, "*222#", new ConsultBalanceCallBack() { + @Override + public void onRequesting(UssdRequest request) { Toast.makeText(context, "Consultando saldo...", Toast.LENGTH_LONG).show(); } @Override - public void onSuccess(@NonNull UssdResponse ussdResponse) { - if (ussdResponse instanceof UssdResponse.Custom) { - UssdResponse.Custom customResponse = (UssdResponse.Custom) ussdResponse; - // Convierte el objeto UssdResponse en un objeto MainBalance - balance = parseMainBalance(customResponse.getResponse()); + public void onSuccess(UssdRequest request, UssdResponse response) { + if (Objects.requireNonNull(request) == UssdRequest.CUSTOM) { + balance = MainBalanceParser.parseMainBalance(((Custom) response).response()); } } @Override - public void onFailure(@NonNull Throwable throwable) { - throw throwable; + public void onFailure(Throwable throwable) { + throwable.printStackTrace(); } }); ``` @@ -128,69 +124,73 @@ SimCardExtensionKt.ussdExecute(firstSimCard, "*222#", new ConsultBalanceCallBack if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { simCard.consultBalance( object : ConsultBalanceCallBack { - override fun onRequesting(consultType: UssdConsultType) { - val consultMessage = when (consultType) { - UssdConsultType.BonusBalance -> "Consultando Bonos" - UssdConsultType.DataBalance -> "Consultando Datos" - UssdConsultType.MessagesBalance -> "Consultando SMS" - UssdConsultType.PrincipalBalance -> "Consultando Saldo" - UssdConsultType.VoiceBalance -> "Consultando Minutos" - is UssdConsultType.Custom -> "" + override fun onRequesting(resquest: UssdRequest) { + val consultMessage = when (resquest) { + UssdRequest.BONUS_BALANCE -> "Consultando Bonos" + UssdRequest.DATA_BALANCE -> "Consultando Datos" + UssdRequest.MESSAGES_BALANCE -> "Consultando SMS" + UssdRequest.PRINCIPAL_BALANCE -> "Consultando Saldo" + UssdRequest.VOICE_BALANCE -> "Consultando Minutos" + UssdRequest.CUSTOM -> "" } Toast.makeText(context, consultMessage, Toast.LENGTH_LONG).show() } - override fun onSuccess(ussdResponse: UssdResponse) { - when (ussdResponse) { - is UssdResponse.BonusBalance -> { + override fun onSuccess(resquest: UssdRequest, ussdResponse: UssdResponse) { + when (resquest) { + UssdRequest.BONUS_BALANCE -> { // Contiene la informacion extraida de la consulta de bono (*222*266#). // Es la ultima operacion en realizarse Toast.makeText( context, - "${ussdResponse.credit}", + "${(ussdResponse as BonusBalance).credit.balance}", Toast.LENGTH_LONG ).show() } - is UssdResponse.DataBalance -> { + UssdRequest.DATA_BALANCE -> { // Contiene la informacion extraida de la consulta de datos (*222*328#). // Solo se ejecuta si se detecta paquetes de datos en el saldo principal. Toast.makeText( context, - "${ussdResponse.usageBasedPricing}", + "${(ussdResponse as DataBalance).usageBasedPricing}", Toast.LENGTH_LONG ).show() } - is UssdResponse.MessagesBalance -> { + UssdRequest.MESSAGES_BALANCE -> { // Contiene la informacion extraida de la consulta de mensajes (*222*767#). // Solo se ejecuta si se detecta paquetes de SMS en el saldo principal. Toast.makeText( context, - "${ussdResponse.count}", + "${(ussdResponse as MessagesBalance).sms}", Toast.LENGTH_LONG ).show() } - is UssdResponse.PrincipalBalance -> { + UssdRequest.PRINCIPAL_BALANCE -> { // Contiene la informacion extraida de la consulta de saldo (*222#). // Es la primera operacion en realizarse Toast.makeText( context, - "${ussdResponse.credit}", + "${(ussdResponse as PrincipalBalance).balance}", Toast.LENGTH_LONG ).show() } - is UssdResponse.VoiceBalance -> { + UssdRequest.VOICE_BALANCE -> { // Contiene la informacion extraida de la consulta de mensajes (*222*869#). // Solo se ejecuta si se detecta paquetes de Voz en el saldo principal. Toast.makeText( context, - "${ussdResponse.count}", + "${(ussdResponse as VoiceBalance).seconds}", Toast.LENGTH_LONG ).show() } - is UssdResponse.Custom -> { + UssdRequest.CUSTOM -> { // No se ejecuta en la consulta de saldo automacica. } } } + + override fun onFailure(throwable: Throwable?) { + throwable?.let { throw it } + } } ) } @@ -200,74 +200,70 @@ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { ```java if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - SimCardExtensionKt.ussdExecute(firstSimCard, new ConsultBalanceCallBack() { + SimCardUtils.ussdExecute(firstSimCard, new ConsultBalanceCallBack() { @SuppressLint("MissingPermission") @Override - public void onRequesting(@NonNull UssdConsultType consultType) { - String consultMessage; - if (consultType instanceof UssdConsultType.BonusBalance) { - consultMessage = "Consultando Bonos..."; - } else if (consultType instanceof UssdConsultType.DataBalance) { - consultMessage = "Consultando Datos..."; - } else if (consultType instanceof UssdConsultType.MessagesBalance) { - consultMessage = "Consultando SMS..."; - } else if (consultType instanceof UssdConsultType.PrincipalBalance) { - consultMessage = "Consultando Saldo..."; - } else if (consultType instanceof UssdConsultType.VoiceBalance) { - consultMessage = "Consultando Minutos..."; - } else { - consultMessage = ""; - } + public void onRequesting(UssdRequest request) { + String consultMessage = switch (request) { + case BONUS_BALANCE -> "Consultando Bonos..."; + case DATA_BALANCE -> "Consultando Datos..."; + case MESSAGES_BALANCE -> "Consultando SMS..."; + case PRINCIPAL_BALANCE -> "Consultando Saldo..."; + case VOICE_BALANCE -> "Consultando Minutos..."; + default -> ""; + }; Toast.makeText(context, consultMessage, Toast.LENGTH_LONG).show(); } @Override - public void onSuccess(@NonNull UssdResponse ussdResponse) { - if (ussdResponse instanceof UssdResponse.BonusBalance) { - // Contiene la informacion extraida de la consulta de bono (*222*266#). - // Es la ultima operacion en realizarse - Toast.makeText( - context, - ((UssdResponse.BonusBalance) ussdResponse).getCredit(), - Toast.LENGTH_LONG - ).show(); - } else if (ussdResponse instanceof UssdResponse.DataBalance) { - // Contiene la informacion extraida de la consulta de datos (*222*328#). - // Solo se ejecuta si se detecta paquetes de datos en el saldo principal. - Toast.makeText( - context, - ((UssdResponse.DataBalance) ussdResponse).getUsageBasedPricing(), - Toast.LENGTH_LONG - ).show(); - } else if (ussdResponse instanceof UssdResponse.MessagesBalance) { - // Contiene la informacion extraida de la consulta de mensajes (*222*767#). - // Solo se ejecuta si se detecta paquetes de SMS en el saldo principal. - Toast.makeText( - context, - ((UssdResponse.MessagesBalance) ussdResponse).getCount(), - Toast.LENGTH_LONG - ).show(); - } else if (ussdResponse instanceof UssdResponse.PrincipalBalance) { - // Contiene la informacion extraida de la consulta de saldo (*222#). - // Es la primera operacion en realizarse - Toast.makeText( - context, - ((UssdResponse.PrincipalBalance) ussdResponse).getCredit(), - Toast.LENGTH_LONG - ).show(); - } else if (ussdResponse instanceof UssdResponse.VoiceBalance) { - // Contiene la informacion extraida de la consulta de mensajes (*222*869#). - // Solo se ejecuta si se detecta paquetes de Voz en el saldo principal. - Toast.makeText( - context, - ((UssdResponse.VoiceBalance) ussdResponse).getTime(), - Toast.LENGTH_LONG - ).show(); + public void onSuccess(UssdRequest request, UssdResponse response) { + switch (request) { + case PRINCIPAL_BALANCE -> + // Contiene la informacion extraida de la consulta de saldo (*222#). + // Es la primera operacion en realizarse + Toast.makeText( + context, + ((PrincipalBalance) response).balance(), + Toast.LENGTH_LONG + ).show(); + case DATA_BALANCE -> + // Contiene la informacion extraida de la consulta de datos (*222*328#). + // Solo se ejecuta si se detecta paquetes de datos en el saldo principal. + Toast.makeText( + context, + ((DataBalance) response).usageBasedPricing(), + Toast.LENGTH_LONG + ).show(); + case VOICE_BALANCE -> + // Contiene la informacion extraida de la consulta de mensajes (*222*869#). + // Solo se ejecuta si se detecta paquetes de Voz en el saldo principal. + Toast.makeText( + context, + ((VoiceBalance) response).seconds(), + Toast.LENGTH_LONG + ).show(); + case MESSAGES_BALANCE -> + // Contiene la informacion extraida de la consulta de mensajes (*222*767#). + // Solo se ejecuta si se detecta paquetes de SMS en el saldo principal. + Toast.makeText( + context, + ((MessagesBalance) response).sms(), + Toast.LENGTH_LONG + ).show(); + case BONUS_BALANCE -> + // Contiene la informacion extraida de la consulta de bono (*222*266#). + // Es la ultima operacion en realizarse + Toast.makeText( + context, + ((BonusBalance) response).credit().balance(), + Toast.LENGTH_LONG + ).show(); + default -> {} } } @Override - public void onFailure(@NonNull Throwable throwable) { + public void onFailure(Throwable throwable) { throwable.printStackTrace(); } }); From d27dff7a1530c8bbcf7974e7b3bdd2e53c016ff5 Mon Sep 17 00:00:00 2001 From: lesclaz Date: Sat, 10 Feb 2024 14:45:58 -0500 Subject: [PATCH 5/7] some fixes --- .../java/cu/suitetecsa/sdk/android/utils/SimCardUtils.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/SimCardUtils.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/SimCardUtils.java index e611458..c93c552 100644 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/SimCardUtils.java +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/SimCardUtils.java @@ -10,8 +10,7 @@ public class SimCardUtils { public static void makeCall(SimCard simCard, Context context, String phoneNumber) { - Uri uri = Uri.parse("tel:" + phoneNumber); - Intent intent = new Intent(Intent.ACTION_CALL, uri); + Intent intent = new Intent(Intent.ACTION_CALL).setData(Uri.parse("tel:" + phoneNumber)); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { intent.putExtra("android.telecom.extra.PHONE_ACCOUNT_HANDLE", String.valueOf(simCard.subscriptionId())); From b6c99db02f042187ff8de1df9d22e2ee31dbf395 Mon Sep 17 00:00:00 2001 From: lesclaz Date: Tue, 13 Feb 2024 14:50:42 -0500 Subject: [PATCH 6/7] some fixes --- .../presentation/balance/BalancesViewModel.kt | 18 +++--- .../balance/ConsultBalanceCallBack.java | 36 ----------- .../android/balance/FetchBalanceCallBack.java | 36 +++++++++++ .../sdk/android/kotlin/SimCardExtension.kt | 22 +++---- .../sdk/android/utils/SimCardUtils.java | 62 ++++++++++++++++++- 5 files changed, 116 insertions(+), 58 deletions(-) delete mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/ConsultBalanceCallBack.java create mode 100644 sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/FetchBalanceCallBack.java diff --git a/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalancesViewModel.kt b/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalancesViewModel.kt index fac20ab..f58f77c 100644 --- a/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalancesViewModel.kt +++ b/app/src/main/java/cu/suitetecsa/sdkandroid/presentation/balance/BalancesViewModel.kt @@ -10,7 +10,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import cu.suitetecsa.sdk.android.SimCardCollector -import cu.suitetecsa.sdk.android.balance.ConsultBalanceCallBack +import cu.suitetecsa.sdk.android.balance.FetchBalanceCallBack import cu.suitetecsa.sdk.android.balance.consult.UssdRequest import cu.suitetecsa.sdk.android.balance.consult.UssdRequest.BONUS_BALANCE import cu.suitetecsa.sdk.android.balance.consult.UssdRequest.CUSTOM @@ -26,8 +26,8 @@ import cu.suitetecsa.sdk.android.balance.response.PrincipalBalance import cu.suitetecsa.sdk.android.balance.response.UssdResponse import cu.suitetecsa.sdk.android.balance.response.VoiceBalance import cu.suitetecsa.sdk.android.kotlin.asDateString -import cu.suitetecsa.sdk.android.kotlin.consultBalance -import cu.suitetecsa.sdk.android.kotlin.ussdExecute +import cu.suitetecsa.sdk.android.kotlin.smartFetchBalance +import cu.suitetecsa.sdk.android.kotlin.ussdFetch import cu.suitetecsa.sdk.android.model.MainData import cu.suitetecsa.sdk.android.model.MainSms import cu.suitetecsa.sdk.android.model.MainVoice @@ -111,9 +111,9 @@ class BalancesViewModel @Inject constructor( @RequiresApi(Build.VERSION_CODES.O) @RequiresPermission(android.Manifest.permission.CALL_PHONE) private fun updateBalance(simCard: SimCard) { - simCard.consultBalance( - object : ConsultBalanceCallBack { - override fun onRequesting(request: UssdRequest) { + simCard.smartFetchBalance( + object : FetchBalanceCallBack { + override fun onFetching(request: UssdRequest) { this@BalancesViewModel.consultType = request val consultMessage = when (request) { BONUS_BALANCE -> "Consultando Bonos" @@ -210,10 +210,10 @@ class BalancesViewModel @Inject constructor( "*133*1*1*1${Uri.parse("#")}" } currentSimCard?.also { - it.ussdExecute( + it.ussdFetch( ussdCode, - object : ConsultBalanceCallBack { - override fun onRequesting(request: UssdRequest) { + object : FetchBalanceCallBack { + override fun onFetching(request: UssdRequest) { _state.value = _state.value.copy( consultMessage = if (!isActive) { "Desactivando TPC" diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/ConsultBalanceCallBack.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/ConsultBalanceCallBack.java deleted file mode 100644 index 0871ddd..0000000 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/ConsultBalanceCallBack.java +++ /dev/null @@ -1,36 +0,0 @@ -package cu.suitetecsa.sdk.android.balance; - -import cu.suitetecsa.sdk.android.balance.consult.UssdRequest; -import cu.suitetecsa.sdk.android.balance.response.UssdResponse; - -/** - * Callback interface for USSD balance requests. - *

- * This interface defines three callback functions that handle the different stages of a USSD balance request: - * - `onRequesting`: Called when a USSD request is being sent. - * - `onSuccess`: Called when a USSD response is received successfully. - * - `onFailure`: Called when an error occurs during the USSD request. - */ -public interface ConsultBalanceCallBack { - /** - * Called when a USSD request is being sent. - * - * @param request The type of USSD consult being requested. - */ - void onRequesting(UssdRequest request); - - /** - * Called when a USSD response is received successfully. - * - * @param request The type of USSD consult being requested. - * @param response The USSD response received. - */ - void onSuccess(UssdRequest request, UssdResponse response); - - /** - * Called when an error occurs during the USSD request. - * - * @param throwable The throwable representing the error. - */ - void onFailure(Throwable throwable); -} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/FetchBalanceCallBack.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/FetchBalanceCallBack.java new file mode 100644 index 0000000..72a29ed --- /dev/null +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/balance/FetchBalanceCallBack.java @@ -0,0 +1,36 @@ +package cu.suitetecsa.sdk.android.balance; + +import cu.suitetecsa.sdk.android.balance.consult.UssdRequest; +import cu.suitetecsa.sdk.android.balance.response.UssdResponse; + +/** + * Interfaz de callback para solicitudes de saldo USSD. + *

+ * Esta interfaz define tres funciones de callback que manejan las diferentes etapas de una solicitud de saldo USSD: + * - `onFetching`: Se llama cuando se está enviando una solicitud USSD para obtener el saldo. + * - `onSuccess`: Se llama cuando se recibe una respuesta USSD exitosamente. + * - `onFailure`: Se llama cuando ocurre un error durante la solicitud USSD para obtener el saldo. + */ +public interface FetchBalanceCallBack { + /** + * Se llama cuando se está enviando una solicitud USSD para obtener el saldo. + * + * @param request El tipo de consulta USSD que se está solicitando. + */ + void onFetching(UssdRequest request); + + /** + * Se llama cuando se recibe una respuesta USSD exitosamente. + * + * @param request El tipo de consulta USSD que se está solicitando. + * @param response La respuesta USSD recibida. + */ + void onSuccess(UssdRequest request, UssdResponse response); + + /** + * Se llama cuando ocurre un error durante la solicitud USSD para obtener el saldo. + * + * @param throwable El throwable que representa el error. + */ + void onFailure(Throwable throwable); +} diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/SimCardExtension.kt b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/SimCardExtension.kt index 685a2bb..6dce28e 100644 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/SimCardExtension.kt +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/kotlin/SimCardExtension.kt @@ -5,7 +5,7 @@ import android.os.Build import android.telephony.TelephonyManager import androidx.annotation.RequiresApi import androidx.annotation.RequiresPermission -import cu.suitetecsa.sdk.android.balance.ConsultBalanceCallBack +import cu.suitetecsa.sdk.android.balance.FetchBalanceCallBack import cu.suitetecsa.sdk.android.balance.RequestCallback import cu.suitetecsa.sdk.android.balance.UssdRequestSender import cu.suitetecsa.sdk.android.balance.consult.UssdRequest @@ -24,12 +24,12 @@ import cu.suitetecsa.sdk.android.utils.SimCardUtils */ @RequiresApi(Build.VERSION_CODES.O) @RequiresPermission(android.Manifest.permission.CALL_PHONE) -fun SimCard.consultBalance(callBack: ConsultBalanceCallBack) { - val ussdBalanceRequestExecutorCallBack = object : RequestCallback { +fun SimCard.smartFetchBalance(callBack: FetchBalanceCallBack) { + val requestCallback = object : RequestCallback { - override fun getTelephonyManager(): TelephonyManager = this@consultBalance.telephony()!! + override fun getTelephonyManager(): TelephonyManager = this@smartFetchBalance.telephony()!! - override fun onRequesting(request: UssdRequest) = callBack.onRequesting(request) + override fun onRequesting(request: UssdRequest) = callBack.onFetching(request) override fun onSuccess( request: UssdRequest, @@ -38,16 +38,16 @@ fun SimCard.consultBalance(callBack: ConsultBalanceCallBack) { override fun onFailure(throwable: Throwable) = callBack.onFailure(throwable) } - UssdRequestSender.Builder().build().send(ussdBalanceRequestExecutorCallBack) + UssdRequestSender.Builder().build().send(requestCallback) } @RequiresApi(Build.VERSION_CODES.O) @RequiresPermission(android.Manifest.permission.CALL_PHONE) -fun SimCard.ussdExecute(ussdCode: String, callBack: ConsultBalanceCallBack) { - val ussdBalanceRequestExecutorCallBack = object : RequestCallback { - override fun getTelephonyManager(): TelephonyManager = this@ussdExecute.telephony()!! +fun SimCard.ussdFetch(ussdCode: String, callBack: FetchBalanceCallBack) { + val requestCallback = object : RequestCallback { + override fun getTelephonyManager(): TelephonyManager = this@ussdFetch.telephony()!! - override fun onRequesting(request: UssdRequest) = callBack.onRequesting(request) + override fun onRequesting(request: UssdRequest) = callBack.onFetching(request) override fun onSuccess( request: UssdRequest, @@ -56,7 +56,7 @@ fun SimCard.ussdExecute(ussdCode: String, callBack: ConsultBalanceCallBack) { override fun onFailure(throwable: Throwable) = callBack.onFailure(throwable) } - UssdRequestSender.Builder().build().send(ussdCode, ussdBalanceRequestExecutorCallBack) + UssdRequestSender.Builder().build().send(ussdCode, requestCallback) } @RequiresPermission(android.Manifest.permission.CALL_PHONE) diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/SimCardUtils.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/SimCardUtils.java index c93c552..8966125 100644 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/SimCardUtils.java +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/SimCardUtils.java @@ -4,8 +4,16 @@ import android.content.Intent; import android.net.Uri; import android.os.Build; +import android.telephony.TelephonyManager; -import cu.suitetecsa.sdk.android.balance.ConsultBalanceCallBack; +import androidx.annotation.RequiresApi; +import androidx.annotation.RequiresPermission; + +import cu.suitetecsa.sdk.android.balance.FetchBalanceCallBack; +import cu.suitetecsa.sdk.android.balance.RequestCallback; +import cu.suitetecsa.sdk.android.balance.UssdRequestSender; +import cu.suitetecsa.sdk.android.balance.consult.UssdRequest; +import cu.suitetecsa.sdk.android.balance.response.UssdResponse; import cu.suitetecsa.sdk.android.model.SimCard; public class SimCardUtils { @@ -22,7 +30,57 @@ public static void makeCall(SimCard simCard, Context context, String phoneNumber context.startActivity(intent); } - public static void ussdExecute(SimCard simCard, String ussdCode, ConsultBalanceCallBack callBack) { + @RequiresApi(Build.VERSION_CODES.O) + @RequiresPermission(android.Manifest.permission.CALL_PHONE) + public static void smartFetchBalance(SimCard simCard, FetchBalanceCallBack callBack) { + RequestCallback requestCallback = new RequestCallback() { + @Override + public TelephonyManager getTelephonyManager() { + return simCard.telephony(); + } + + @Override + public void onRequesting(UssdRequest request) { + callBack.onFetching(request); + } + + @Override + public void onSuccess(UssdRequest request, UssdResponse response) { + callBack.onSuccess(request, response); + } + + @Override + public void onFailure(Throwable throwable) { + callBack.onFailure(throwable); + } + }; + new UssdRequestSender.Builder().build().send(requestCallback); + } + + @RequiresApi(Build.VERSION_CODES.O) + @RequiresPermission(android.Manifest.permission.CALL_PHONE) + public static void ussdFetch(SimCard simCard, String ussdCode, FetchBalanceCallBack callBack) { + RequestCallback requestCallback = new RequestCallback() { + @Override + public TelephonyManager getTelephonyManager() { + return simCard.telephony(); + } + + @Override + public void onRequesting(UssdRequest request) { + callBack.onFetching(request); + } + + @Override + public void onSuccess(UssdRequest request, UssdResponse response) { + callBack.onSuccess(request, response); + } + @Override + public void onFailure(Throwable throwable) { + callBack.onFailure(throwable); + } + }; + new UssdRequestSender.Builder().build().send(ussdCode, requestCallback); } } From e90b7af347d4a08d8936da8d9ae161410605e1c3 Mon Sep 17 00:00:00 2001 From: lesclaz Date: Tue, 13 Feb 2024 14:52:31 -0500 Subject: [PATCH 7/7] some fixes --- .../main/java/cu/suitetecsa/sdk/android/utils/StringUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/StringUtils.java b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/StringUtils.java index 8b15eac..0bc307d 100644 --- a/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/StringUtils.java +++ b/sdk-android/src/main/java/cu/suitetecsa/sdk/android/utils/StringUtils.java @@ -33,7 +33,7 @@ public static Date toDate(String date) throws ParseException { public static long toBytes(@NotNull String data) { String count = data.replaceAll("[GMKBT]", ""); - String unit = data.split(" ")[data.split(" ").length - 1].toUpperCase(); + String unit = data.split(" ")[data.split(" ").length - 1].toUpperCase(Locale.getDefault()); return (long) (Double.parseDouble(count) * Math.pow(1024, "BKMGT".indexOf(unit.charAt(0)))); } }