NTP-74177 | Added handling of awaiting bind device API response for polling crash fix (#16689)

This commit is contained in:
Ujjwal Kumar
2025-06-21 17:23:58 +05:30
committed by GitHub
parent 83abfe5e8b
commit 2c25041e84
3 changed files with 49 additions and 6 deletions

View File

@@ -1036,6 +1036,13 @@ class NaviPayAnalytics private constructor() {
NaviTrackEvent.trackEventOnClickStream("NaviPay_RsmsAutoReadOtpSuccess")
}
fun onRsmsBindDeviceApiResponseAwaitFailed(message: String) {
NaviTrackEvent.trackEventOnClickStream(
"NaviPay_RsmsBindDeviceApiResponseAwaitFailed",
mapOf("message" to message),
)
}
fun onDropOffFunnelEntered(funnelStep: FunnelStep) {
NaviTrackEvent.trackEventOnClickStream(
eventName = "NaviPay_DropOffFunnelEntered",

View File

@@ -22,6 +22,7 @@ import com.navi.base.deeplink.util.DeeplinkConstants
import com.navi.base.utils.BaseUtils
import com.navi.base.utils.ResourceProvider
import com.navi.base.utils.TrustedTimeAccessor
import com.navi.base.utils.isNull
import com.navi.base.utils.orFalse
import com.navi.base.utils.orTrue
import com.navi.common.di.CoroutineDispatcherProvider
@@ -115,6 +116,7 @@ import com.navi.pay.tstore.list.usecase.SyncOrderHistoryUseCase
import com.navi.pay.utils.ALLOW
import com.navi.pay.utils.DEFAULT_CONFIG
import com.navi.pay.utils.DENY
import com.navi.pay.utils.DEVICE_BINDING_TIMEOUT
import com.navi.pay.utils.INDIA_COUNTRY_CODE_WITHOUT_PLUS
import com.navi.pay.utils.KEY_IS_FIRST_TRANSACTION_SUCCESSFUL
import com.navi.pay.utils.LITMUS_EXPERIMENT_NAVIPAY_REVERSE_SMS_BINDING
@@ -130,7 +132,6 @@ import com.navi.pay.utils.NON_VERIFIED_SENDER_LOGIN
import com.navi.pay.utils.ONBOARDING_CONFIG
import com.navi.pay.utils.OTP_AUTO_READ_TIMEOUT_IN_SECONDS
import com.navi.pay.utils.PHONE_NUMBER_LENGTH
import com.navi.pay.utils.SMS_SENT_CHECK_TIMEOUT
import com.navi.pay.utils.SMS_VERIFICATION_PENDING
import com.navi.pay.utils.TOO_MANY_OTP_GENERATE_ATTEMPTS
import com.navi.pay.utils.TOO_MANY_OTP_VALIDATION_ATTEMPTS
@@ -162,6 +163,7 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.withTimeout
import kotlinx.serialization.json.Json
import org.json.JSONObject
@@ -249,6 +251,9 @@ constructor(
private var deviceData: DeviceData? = null
private lateinit var bindDeviceResponse: BindDeviceResponse
private val bindDeviceApiSuccessCompletionSignal =
MutableSharedFlow<BindDeviceResponse>(replay = 1)
private val deferredApiCallList = mutableListOf<Deferred<Any>>()
private val _isHardUpdateRequired = MutableSharedFlow<Boolean>(replay = 1)
@@ -957,6 +962,7 @@ constructor(
)
this@NaviPayOnboardingViewModel.bindDeviceResponse = bindDeviceAPIResponse.data!!
bindDeviceApiSuccessCompletionSignal.tryEmit(bindDeviceAPIResponse.data!!)
val merchantCustomerId =
bindDeviceResponse.pspDetails[onboardingPsp]?.merchantCustomerId.orEmpty()
@@ -1156,7 +1162,7 @@ constructor(
val smsContent = smsBindingData.smsContent
val startTime = System.currentTimeMillis()
while (System.currentTimeMillis() - startTime < SMS_SENT_CHECK_TIMEOUT) {
while (System.currentTimeMillis() - startTime < DEVICE_BINDING_TIMEOUT) {
delay(timeMillis = 1000)
if (checkIfMessageIsSent(vmnNumbers = vmnNumbers, smsContent = smsContent)) {
startStatusPolling(bindingType = BindingType.SMS)
@@ -1218,6 +1224,19 @@ constructor(
bindingType = bindingType,
)
if (!::bindDeviceResponse.isInitialized || bindDeviceResponse.isNull()) {
updateBottomSheetUIState(showBottomSheet = false)
notifyError(errorConfig = getGenericErrorConfig().copy(cancelable = false))
naviPayAnalytics.simBindingFailure(
errorType = "BindDeviceResponse not initialized",
error = null,
onboardingSource = onboardingSource.value,
naviPaySessionAttributes = getNaviPaySessionAttributes(),
)
updateDeviceBindingState(DeviceBindingState.Failure)
return
}
naviApiPoller
.startPolling(
onTimeout = {
@@ -2095,9 +2114,6 @@ constructor(
fun onRsmsAutoReadOtpReceived(otp: String, senderAddress: String?) {
viewModelScope.launch(Dispatchers.IO) {
if (bindingType !is BindingType.RSMS) {
return@launch
}
updateGeneratedOtp(otp = otp)
updateAutoReadOtpVerificationState(AutoReadOtpVerificationState.VERIFYING)
otpTimerJob?.cancel()
@@ -2105,6 +2121,26 @@ constructor(
naviPayAnalytics.onRsmsAutoReadOtpSuccess()
try {
withTimeout(timeMillis = DEVICE_BINDING_TIMEOUT) {
bindDeviceApiSuccessCompletionSignal.first()
}
} catch (e: Exception) {
naviPayAnalytics.onRsmsBindDeviceApiResponseAwaitFailed(
message = e.message.toString()
)
updateBottomSheetUIState(showBottomSheet = false)
notifyError(errorConfig = getGenericErrorConfig().copy(cancelable = false))
naviPayAnalytics.simBindingFailure(
errorType = e.message ?: "",
error = null,
onboardingSource = onboardingSource.value,
naviPaySessionAttributes = getNaviPaySessionAttributes(),
)
updateDeviceBindingState(DeviceBindingState.Failure)
return@launch
}
startStatusPolling(
bindingType = BindingType.RSMS(otp = otp, senderAddress = senderAddress ?: "")
)

View File

@@ -24,7 +24,7 @@ const val IS_FROM_IAN = "IS_FROM_IAN"
const val LITE_MAX_SEND_MONEY = 500.0
const val AADHAAR_OTP_LENGTH = 6
const val PAY_AGAIN = "|PAY_AGAIN"
const val SMS_SENT_CHECK_TIMEOUT = 45 * 1000L // 45 seconds
const val DEVICE_BINDING_TIMEOUT = 45 * 1000L // 45 seconds
const val DOT_PNG = ".png"
const val BOTTOM_SHEET_HEIGHT_PERCENTAGE_80 = 0.80f
const val BOTTOM_SHEET_HEIGHT_PERCENTAGE_85 = 0.85f