NTP-74177 | Retry on integrity manager and updated logic for marking binding as failure (#16743)

This commit is contained in:
Ujjwal Kumar
2025-06-25 16:13:46 +05:30
committed by GitHub
parent cf4f5d2610
commit 0b47272ce2
5 changed files with 104 additions and 62 deletions

View File

@@ -151,6 +151,7 @@ object FirebaseRemoteConfigHelper {
const val NAVI_PAY_TSTORE_MERCHANT_ICONS_SYNC_ENABLED =
"NAVI_PAY_TSTORE_MERCHANT_ICONS_SYNC_ENABLED"
const val NAVI_PAY_ENABLE_BANK_SENSE_USE_CASE = "NAVI_PAY_ENABLE_BANK_SENSE_USE_CASE"
const val NAVI_PAY_IS_ARC_ENABLED = "NAVI_PAY_IS_ARC_ENABLED"
const val AUTO_REDIRECT_TO_HOME_PAGE_LIMIT_TIME_IN_MIN =
"AUTO_REDIRECT_TO_HOME_PAGE_LIMIT_TIME_IN_MIN"

View File

@@ -104,6 +104,7 @@ class BankSenseUseCaseTest {
isCreditLineSupported = false,
isUpiLiteAutoTopUpSupported = false,
isEmiConversionSupported = false,
isRegularVersionSupported = true,
)
}

View File

@@ -12,6 +12,7 @@ import com.google.android.play.core.integrity.IntegrityManagerFactory
import com.google.android.play.core.integrity.StandardIntegrityManager.PrepareIntegrityTokenRequest
import com.google.android.play.core.integrity.StandardIntegrityManager.StandardIntegrityTokenProvider
import com.google.android.play.core.integrity.StandardIntegrityManager.StandardIntegrityTokenRequest
import com.navi.base.utils.retry
import com.navi.common.utils.log
import com.navi.pay.BuildConfig
import com.navi.pay.analytics.NaviPayAnalytics
@@ -53,23 +54,31 @@ class StandardIntegrityManager @Inject constructor(@ApplicationContext val conte
.setCloudProjectNumber(BuildConfig.FIREBASE_CLOUD_PROJECT_NUMBER.toLong())
.build()
try {
val integrityTokenProviderRequestHolder = measureTimedValue {
standardIntegrityManager
.prepareIntegrityToken(prepareIntegrityTokenRequest)
.await()
}
integrityTokenProvider = integrityTokenProviderRequestHolder.value
naviPayAnalytics.onIntegrityTokenProviderGeneration(
timeTaken =
integrityTokenProviderRequestHolder.duration.inWholeMilliseconds.toString()
)
} catch (e: Exception) {
e.log()
naviPayAnalytics.onIntegrityTokenProviderGenerationFailure(
exception = e.message.toString()
)
}
retry(
execute = {
try {
val integrityTokenProviderRequestHolder = measureTimedValue {
standardIntegrityManager
.prepareIntegrityToken(prepareIntegrityTokenRequest)
.await()
}
integrityTokenProvider = integrityTokenProviderRequestHolder.value
naviPayAnalytics.onIntegrityTokenProviderGeneration(
timeTaken =
integrityTokenProviderRequestHolder.duration.inWholeMilliseconds
.toString()
)
true
} catch (e: Exception) {
e.log()
naviPayAnalytics.onIntegrityTokenProviderGenerationFailure(
exception = e.message.toString()
)
false
}
},
shouldRetry = { providerResult -> !providerResult },
)
}
}
@@ -89,7 +98,12 @@ class StandardIntegrityManager @Inject constructor(@ApplicationContext val conte
.build()
val integrityTokenRequestHolder = measureTimedValue {
integrityTokenProvider?.request(integrityTokenRequest)?.await()?.token()
retry(
execute = {
integrityTokenProvider?.request(integrityTokenRequest)?.await()?.token()
},
shouldRetry = { token -> token.isNullOrBlank() },
)
}
naviPayAnalytics.onIntegrityTokenGeneration(

View File

@@ -310,8 +310,7 @@ constructor(
totalPollingDurationInMillis = MAX_POLLING_DURATION_IN_MILLIS,
)
}
private val naviPayDefaultConfig =
MutableStateFlow<NaviPayDefaultConfig>(NaviPayDefaultConfig())
private val naviPayDefaultConfig = MutableStateFlow(NaviPayDefaultConfig())
private val _triggerSmsRetrieverInstance = MutableSharedFlow<Boolean>(replay = 1)
val triggerSmsRetrieverInstance = _triggerSmsRetrieverInstance.asSharedFlow()
@@ -708,6 +707,7 @@ constructor(
val isBindingEligibleForRsms = getRsmsEligibilityStatus()
if (isBindingEligibleForRsms) {
bindingType = BindingType.RSMS()
markRsmsTriggeredStatus(isInitiated = true)
startSimBinding()
return@safeLaunch
}
@@ -720,6 +720,7 @@ constructor(
}
bindingType = BindingType.SMV
markSmvTriggeredStatus(isInitiated = true)
// SMV is eligible cases
if (!smvEligibilityStatus.isSmsPermissionEnabled) {
@@ -939,11 +940,6 @@ constructor(
} else {
onBindingError(bindDeviceAPIResponse)
}
if (bindingType is BindingType.RSMS) {
markRsmsTriggeredAndFailed()
}
return
}
@@ -971,12 +967,18 @@ constructor(
merchantCustomerId = merchantCustomerId,
)
if (bindingType is BindingType.RSMS) {
processBindDeviceResponseForRsms()
} else if (bindingType is BindingType.SMV) {
processBindDeviceResponseForSmv()
} else {
processBindDeviceResponseForSms(provider = provider)
when (bindingType) {
is BindingType.RSMS -> {
processBindDeviceResponseForRsms()
}
is BindingType.SMV -> {
processBindDeviceResponseForSmv()
}
else -> {
processBindDeviceResponseForSms(provider = provider)
}
}
}
@@ -1121,8 +1123,6 @@ constructor(
if (initiateSmvResponse.code() == 200 && initiateSmvResponse.body() == null) {
startStatusPolling(bindingType = BindingType.SMV)
} else {
// Mark in cache that SMV was triggered & failed
markSmvTriggeredAndFailed()
updateBottomSheetUIState(showBottomSheet = false)
updateDeviceBindingState(deviceBindingState = DeviceBindingState.Failure)
notifyError(errorConfig = getGenericErrorConfig().copy(cancelable = false))
@@ -1331,16 +1331,6 @@ constructor(
updateDeviceBindingState(DeviceBindingState.Failure)
naviApiPoller.stopPolling()
onBindingError(bindDeviceStatusAPIResponse)
when (bindingType) {
is BindingType.RSMS -> {
markRsmsTriggeredAndFailed()
}
BindingType.SMV -> {
markSmvTriggeredAndFailed()
}
else -> Unit
}
}
}
return
@@ -1362,6 +1352,12 @@ constructor(
}
handleDropOffFunnel(funnelStep = FunnelStep.ACCOUNT_ADDITION)
when (bindingType) {
BindingType.RSMS() -> markRsmsTriggeredStatus(isCompleted = true)
BindingType.SMV -> markSmvTriggeredStatus(isCompleted = true)
else -> Unit
}
saveDeviceDataInSharedPreferenceAndUpdateUiState(
deviceFingerPrint =
bindDeviceStatusResponse.pspDetails[onboardingPsp]?.deviceFingerPrint.orEmpty(),
@@ -1399,26 +1395,46 @@ constructor(
handleNavigationOnCustomerStatus(customerStatus = customerStatus)
}
private suspend fun markSmvTriggeredAndFailed() {
naviCacheRepository.save(
naviCacheEntity =
NaviCacheEntity(
key = NAVI_PAY_DEVICE_BINDING_IS_SMV_TRIGGERED_AND_FAILED,
value = "true",
version = 1,
)
)
private suspend fun markSmvTriggeredStatus(
isInitiated: Boolean? = null,
isCompleted: Boolean? = null,
) {
isInitiated?.let {
naviCacheRepository.save(
naviCacheEntity =
NaviCacheEntity(
key = NAVI_PAY_DEVICE_BINDING_IS_SMV_TRIGGERED_AND_FAILED,
value = true.toString(),
version = 1,
)
)
}
isCompleted?.let {
naviCacheRepository.clear(key = NAVI_PAY_DEVICE_BINDING_IS_SMV_TRIGGERED_AND_FAILED)
}
}
private suspend fun markRsmsTriggeredAndFailed() {
naviCacheRepository.save(
naviCacheEntity =
NaviCacheEntity(
key = NAVI_PAY_DEVICE_BINDING_IS_RSMS_TRIGGERED_AND_FAILED,
value = "true",
version = 1,
)
)
private suspend fun markRsmsTriggeredStatus(
isInitiated: Boolean? = null,
isCompleted: Boolean? = null,
) {
isInitiated?.let {
naviCacheRepository.save(
naviCacheEntity =
NaviCacheEntity(
key = NAVI_PAY_DEVICE_BINDING_IS_RSMS_TRIGGERED_AND_FAILED,
value = true.toString(),
version = 1,
)
)
}
isCompleted?.let {
naviCacheRepository.clear(key = NAVI_PAY_DEVICE_BINDING_IS_RSMS_TRIGGERED_AND_FAILED)
}
}
fun declineDeviceBinding() {
@@ -2100,7 +2116,7 @@ constructor(
?.variant
val isRsmsExperimentEnabled =
rsmsLitmusVariant?.name == "enabled" && rsmsLitmusVariant.enabled == true
rsmsLitmusVariant?.name == "enabled" && rsmsLitmusVariant.enabled
naviPayAnalytics.onRsmsLitmusEligibility(isEligible = isRsmsExperimentEnabled)
if (isRsmsExperimentEnabled) {

View File

@@ -16,6 +16,7 @@ import com.navi.base.utils.retry
import com.navi.common.checkmate.model.MetricInfo
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper.NAVI_PAY_DATA_REFRESH_MIN_TIMESTAMP
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper.NAVI_PAY_IS_ARC_ENABLED
import com.navi.common.network.models.isSuccessWithData
import com.navi.common.utils.Constants.ONE_DAY_IN_MILLIS
import com.navi.payments.shared.core.di.PaymentsSharedGsonBuilder
@@ -34,6 +35,15 @@ constructor(
suspend fun execute(skipLastSyncedTimestampCheck: Boolean = false) {
if (
!FirebaseRemoteConfigHelper.getBoolean(
key = NAVI_PAY_IS_ARC_ENABLED,
defaultValue = false,
)
) {
return
}
val arcNudgeCacheResponse = naviCacheRepository.get(key = ARC_NUDGE_RESPONSE_CACHE_KEY)
val arcResponseCacheLastSyncTs = arcNudgeCacheResponse?.updatedAt ?: 0