TP-87434 | Introduce data ingestion check before web redirection (#13059)
Co-authored-by: Kishan Kumar <kishan.kumar@navi.com>
This commit is contained in:
@@ -5940,6 +5940,9 @@ class NaviAnalytics private constructor() {
|
||||
const val REDIRECTION_TO_WEB_STARTED = "redirection_to_web_started"
|
||||
const val REDIRECTION_TO_WEB_FAILED = "redirection_to_web_failed"
|
||||
const val REDIRECTION_TO_WEB_SUCCESS = "redirection_to_web_success"
|
||||
const val REDIRECTION_TO_WEB_SUCCESS_ON_TIME_OUT = "redirection_to_web_success_on_time_out"
|
||||
const val REDIRECTION_TO_WEB_SUCCESS_ON_DATA_RECEIVED =
|
||||
"redirection_to_web_success_on_data_received"
|
||||
const val REDIRECTION_TO_WEB_AUTH_API_FAILED = "redirection_to_web_auth_api_failed"
|
||||
const val REDIRECTION_TO_WEB_DATA_INGESTION_INITIATED =
|
||||
"redirection_to_web_data_ingestion_initiated"
|
||||
|
||||
@@ -7,11 +7,14 @@
|
||||
|
||||
package com.naviapp.webredirection.presentation.activity
|
||||
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.viewModels
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.lifecycle.Lifecycle
|
||||
@@ -26,12 +29,16 @@ import com.navi.common.model.ModuleNameV2
|
||||
import com.navi.common.ui.activity.BaseActivity
|
||||
import com.navi.common.ui.errorview.FullScreenErrorComposeView
|
||||
import com.navi.common.useruploaddata.model.IngestionStatusType
|
||||
import com.navi.common.useruploaddata.model.PreSignedUrlListResponse
|
||||
import com.navi.common.useruploaddata.model.UserDataUploadCallbackResponse
|
||||
import com.navi.common.useruploaddata.viewmodel.UserDataViewModel
|
||||
import com.navi.common.utils.Constants.STATUS
|
||||
import com.navi.common.utils.Constants.URL
|
||||
import com.navi.common.utils.Constants.VERTICAL_TYPE
|
||||
import com.navi.common.utils.log
|
||||
import com.navi.common.utils.observeWithTimeout
|
||||
import com.navi.payment.nativepayment.tribute.NaviPaymentWebBridge
|
||||
import com.naviapp.R
|
||||
import com.naviapp.analytics.utils.NaviAnalytics
|
||||
import com.naviapp.analytics.utils.NaviAnalytics.Companion.REDIRECTION_TO_WEB_AUTH_API_FAILED
|
||||
import com.naviapp.analytics.utils.NaviAnalytics.Companion.REDIRECTION_TO_WEB_DATA_INGESTION_FAILED
|
||||
@@ -41,6 +48,8 @@ import com.naviapp.analytics.utils.NaviAnalytics.Companion.REDIRECTION_TO_WEB_DA
|
||||
import com.naviapp.analytics.utils.NaviAnalytics.Companion.REDIRECTION_TO_WEB_FAILED
|
||||
import com.naviapp.analytics.utils.NaviAnalytics.Companion.REDIRECTION_TO_WEB_STARTED
|
||||
import com.naviapp.analytics.utils.NaviAnalytics.Companion.REDIRECTION_TO_WEB_SUCCESS
|
||||
import com.naviapp.analytics.utils.NaviAnalytics.Companion.REDIRECTION_TO_WEB_SUCCESS_ON_DATA_RECEIVED
|
||||
import com.naviapp.analytics.utils.NaviAnalytics.Companion.REDIRECTION_TO_WEB_SUCCESS_ON_TIME_OUT
|
||||
import com.naviapp.common.navigator.NaviDeepLinkNavigator
|
||||
import com.naviapp.home.dashboard.ui.compose.loansTab.LoansTabContentShimmer
|
||||
import com.naviapp.home.dashboard.ui.compose.loansTab.RenderWebView
|
||||
@@ -97,7 +106,6 @@ class WebRedirectionActivity : BaseActivity() {
|
||||
initialise()
|
||||
setContent {
|
||||
InitialiseContent(
|
||||
redirectToExternalWeb = ::redirectToExternalWeb,
|
||||
handleNavigation = ::handleNavigation,
|
||||
handleException = ::handleException
|
||||
)
|
||||
@@ -105,20 +113,51 @@ class WebRedirectionActivity : BaseActivity() {
|
||||
initialiseDataIngestion()
|
||||
webRedirectionVM.fetchTemporarySessionToken()
|
||||
observeWebRedirectionNavigation()
|
||||
observeSmsUploadDataResponse()
|
||||
}
|
||||
|
||||
private fun observeSmsUploadDataResponse() {
|
||||
userDataViewModel.preSignedUrlList.observeWithTimeout(
|
||||
lifecycleOwner = this,
|
||||
timeout =
|
||||
FirebaseRemoteConfigHelper.getLong(
|
||||
DATA_INGESTION_TIMEOUT,
|
||||
defaultValue = DATA_INGESTION_TIMEOUT_DEFAULT_VALUE
|
||||
),
|
||||
onTimeout = {
|
||||
NaviTrackEvent.trackEvent(eventName = REDIRECTION_TO_WEB_SUCCESS_ON_TIME_OUT)
|
||||
handleRedirection(PreSignedUrlListResponse(null))
|
||||
},
|
||||
observer = { preSignedUrlResponse ->
|
||||
NaviTrackEvent.trackEvent(
|
||||
eventName = REDIRECTION_TO_WEB_SUCCESS_ON_DATA_RECEIVED,
|
||||
eventValues =
|
||||
mapOf(PRE_SIGNED_URL_LIST_RESPONSE to preSignedUrlResponse.toString())
|
||||
)
|
||||
handleRedirection(preSignedUrlResponse)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun handleRedirection(preSignedUrlResponse: PreSignedUrlListResponse?) {
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
webRedirectionVM.screenState.collect {
|
||||
webRedirectionVM.startRedirectionProcess(preSignedUrlResponse)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeWebRedirectionNavigation() {
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
webRedirectionVM.webRedirectionCtaData.collect { ctaData ->
|
||||
ctaData?.let {
|
||||
trackEvent(NAVIGATING_TO_WEB_BROWSER)
|
||||
NaviDeepLinkNavigator.navigateTo(
|
||||
activity = this@WebRedirectionActivity,
|
||||
ctaData = it,
|
||||
finish = true
|
||||
)
|
||||
}
|
||||
webRedirectionVM.webPageUrl.collect { webPageUrl ->
|
||||
NaviTrackEvent.trackEvent(
|
||||
eventName = REDIRECTION_TO_WEB_SUCCESS,
|
||||
eventValues = mapOf(URL to webPageUrl.toString())
|
||||
)
|
||||
webPageUrl?.let { url -> launchWebPageInChrome(url) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,7 +175,7 @@ class WebRedirectionActivity : BaseActivity() {
|
||||
businessVertical = ModuleNameV2.PL.name,
|
||||
isOpLifecycleBound = false,
|
||||
needTohandleIngestionPolling = false,
|
||||
callback = { timeTaken, userUploadDataResponse ->
|
||||
callback = { timeTaken, _, userUploadDataResponse ->
|
||||
userUploadDataResponse.ingestionStatusList?.ingestionStatusList.let {
|
||||
ingestionStatusList ->
|
||||
if (
|
||||
@@ -200,7 +239,6 @@ class WebRedirectionActivity : BaseActivity() {
|
||||
|
||||
@Composable
|
||||
private fun InitialiseContent(
|
||||
redirectToExternalWeb: (ctaData: CtaData) -> Unit,
|
||||
handleNavigation: (CtaData) -> Unit,
|
||||
handleException: (Throwable) -> Unit
|
||||
) {
|
||||
@@ -209,15 +247,6 @@ class WebRedirectionActivity : BaseActivity() {
|
||||
webRedirectionVM.webRedirectionPlatform.collectAsStateWithLifecycle()
|
||||
val data by webRedirectionVM.screenState.collectAsStateWithLifecycle()
|
||||
val webRedirectionData by webRedirectionVM.webRedirectionData.collectAsStateWithLifecycle()
|
||||
|
||||
LaunchedEffect(key1 = data) {
|
||||
if (
|
||||
data is UiState.Success && webRedirectionPlatform != WebRedirectionPlatform.WEBVIEW
|
||||
) {
|
||||
trackEvent(eventName = REDIRECTION_TO_WEB_SUCCESS)
|
||||
redirectToExternalWeb((data as UiState.Success).ctaData)
|
||||
}
|
||||
}
|
||||
when (webRedirectionPlatform) {
|
||||
WebRedirectionPlatform.WEBVIEW ->
|
||||
InternalWebViewScreen(
|
||||
@@ -299,10 +328,6 @@ class WebRedirectionActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun redirectToExternalWeb(ctaData: CtaData) {
|
||||
webRedirectionVM.startRedirectionProcess()
|
||||
}
|
||||
|
||||
private fun handleNavigation(ctaData: CtaData) =
|
||||
NaviDeepLinkNavigator.navigateTo(
|
||||
activity = this,
|
||||
@@ -340,6 +365,38 @@ class WebRedirectionActivity : BaseActivity() {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a web page in the default web browser, specifically targeting Google Chrome.
|
||||
*
|
||||
* This function attempts to launch an intent that directs the user to a specified URL. If
|
||||
* Google Chrome is not installed on the device, it falls back to any available web browser.
|
||||
*
|
||||
* @param url The URL of the web page to be opened. It should be a valid URL format (e.g.,
|
||||
* "https://www.example.com").
|
||||
* @throws ActivityNotFoundException if no applications can handle the intent to view the URL.
|
||||
*
|
||||
* After attempting to open the URL, this function calls `finish()`, which will close the
|
||||
* current activity.
|
||||
*/
|
||||
private fun launchWebPageInChrome(url: String) {
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)).apply { setPackage(CHROME_PACKAGE) }
|
||||
|
||||
try {
|
||||
startActivity(intent)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
intent.setPackage(null)
|
||||
e.log()
|
||||
try {
|
||||
startActivity(intent)
|
||||
} catch (e: Exception) {
|
||||
Toast.makeText(this, getString(R.string.no_browser_found), Toast.LENGTH_LONG).show()
|
||||
e.log()
|
||||
}
|
||||
} finally {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
override val screenName: String
|
||||
get() = NaviAnalytics.WEB_REDIRECTION_SCREEN
|
||||
|
||||
@@ -349,5 +406,9 @@ class WebRedirectionActivity : BaseActivity() {
|
||||
companion object {
|
||||
const val WEB_REDIRECTION_SESSION_ID = "WEB_REDIRECTION_SESSION_ID"
|
||||
const val NAVIGATING_TO_WEB_BROWSER = "NAVIGATING_TO_WEB_BROWSER"
|
||||
const val DATA_INGESTION_TIMEOUT = "DATA_INGESTION_TIMEOUT"
|
||||
const val DATA_INGESTION_TIMEOUT_DEFAULT_VALUE = 3000L
|
||||
const val CHROME_PACKAGE = "com.android.chrome"
|
||||
const val PRE_SIGNED_URL_LIST_RESPONSE = "pre_signed_url_list_response"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,12 +17,16 @@ import com.navi.base.model.LineItem
|
||||
import com.navi.base.sharedpref.PreferenceManager
|
||||
import com.navi.base.utils.BaseUtils
|
||||
import com.navi.base.utils.isNotNullAndNotEmpty
|
||||
import com.navi.base.utils.orFalse
|
||||
import com.navi.common.constants.APP_VERSION_CODE
|
||||
import com.navi.common.constants.OS_VERSION
|
||||
import com.navi.common.constants.OS_VERSION_NAME
|
||||
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper
|
||||
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper.WEB_REDIRECTION_DEFAULT_DELAY_IN_MILLIS
|
||||
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper.WEB_REDIRECTION_SMS_UPLOADED_DELAY_IN_MILLIS
|
||||
import com.navi.common.network.models.GenericErrorResponse
|
||||
import com.navi.common.useruploaddata.model.IngestionType
|
||||
import com.navi.common.useruploaddata.model.PreSignedUrlListResponse
|
||||
import com.navi.common.utils.Constants.URL
|
||||
import com.navi.common.utils.getSessionId
|
||||
import com.navi.common.utils.isValidResponse
|
||||
@@ -31,6 +35,7 @@ import com.naviapp.analytics.utils.NaviAnalytics
|
||||
import com.naviapp.common.navigator.NaviDeepLinkNavigator.WEB_URL
|
||||
import com.naviapp.manager.usecase.UserDataUploadWorkerUseCase
|
||||
import com.naviapp.registration.helper.isReadSmsPermissionGranted
|
||||
import com.naviapp.utils.Constants
|
||||
import com.naviapp.utils.buildUrlWithParameters
|
||||
import com.naviapp.utils.generateRandomString
|
||||
import com.naviapp.utils.generateSHA256Hash
|
||||
@@ -78,8 +83,8 @@ constructor(
|
||||
private val _webRedirectionData = MutableStateFlow<WebRedirectionData?>(null)
|
||||
val webRedirectionData = _webRedirectionData.asStateFlow()
|
||||
|
||||
private val _webRedirectionCtaData = MutableStateFlow<CtaData?>(null)
|
||||
val webRedirectionCtaData = _webRedirectionCtaData.asStateFlow()
|
||||
private val _webPageUrl = MutableStateFlow<String?>(null)
|
||||
val webPageUrl = _webPageUrl.asStateFlow()
|
||||
|
||||
private var businessUnit: String? = null
|
||||
|
||||
@@ -110,26 +115,49 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun startRedirectionProcess() {
|
||||
fun startRedirectionProcess(preSignedUrlListResponse: PreSignedUrlListResponse?) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val webRedirectionSessionId = "${businessUnit}_$WEB_REDIRECTION_SESSION_ID"
|
||||
if (PreferenceManager.getStringPreference(webRedirectionSessionId) != getSessionId()) {
|
||||
delay(getWebRedirectionDelayInMillis())
|
||||
getSessionId()?.let {
|
||||
PreferenceManager.setStringPreference(webRedirectionSessionId, it)
|
||||
if (isSuccessAndRedirectToNonWebView()) {
|
||||
val webRedirectionDelay =
|
||||
calculateRedirectDelayForSmsUpload(preSignedUrlListResponse)
|
||||
val webRedirectionSessionId = "${businessUnit}_$WEB_REDIRECTION_SESSION_ID"
|
||||
if (
|
||||
PreferenceManager.getStringPreference(webRedirectionSessionId) != getSessionId()
|
||||
) {
|
||||
delay(webRedirectionDelay)
|
||||
getSessionId()?.let {
|
||||
PreferenceManager.setStringPreference(webRedirectionSessionId, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (screenState.value is UiState.Success) {
|
||||
_webRedirectionCtaData.value = (screenState.value as UiState.Success).ctaData
|
||||
_webPageUrl.value = extractWebPageUrl()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getWebRedirectionDelayInMillis(): Long {
|
||||
val webRedirectionDelayInMillis =
|
||||
private fun extractWebPageUrl(): String? {
|
||||
val ctaData = (screenState.value as UiState.Success).ctaData
|
||||
return ctaData.parameters?.firstOrNull { it.key == Constants.URL }?.value
|
||||
}
|
||||
|
||||
private fun isSuccessAndRedirectToNonWebView() =
|
||||
screenState.value is UiState.Success &&
|
||||
webRedirectionPlatform.value != WebRedirectionPlatform.WEBVIEW
|
||||
|
||||
private fun calculateRedirectDelayForSmsUpload(
|
||||
preSignedUrlListResponse: PreSignedUrlListResponse?
|
||||
): Long {
|
||||
val smsUploadStatus =
|
||||
preSignedUrlListResponse
|
||||
?.preSignedUrlList
|
||||
?.find { it.ingestionType == IngestionType.SMS.name }
|
||||
?.upload
|
||||
.orFalse()
|
||||
return if (smsUploadStatus) {
|
||||
FirebaseRemoteConfigHelper.getLong(WEB_REDIRECTION_SMS_UPLOADED_DELAY_IN_MILLIS)
|
||||
} else {
|
||||
webRedirectionData.value?.webRedirectionDelayInMillis
|
||||
?: FirebaseRemoteConfigHelper.getLong(WEB_REDIRECTION_DEFAULT_DELAY_IN_MILLIS)
|
||||
return webRedirectionDelayInMillis
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateUrlForWebRedirect(codeVerifier: String, token: String): String? {
|
||||
|
||||
@@ -523,4 +523,5 @@
|
||||
<string name="scan_pay">Scan & pay</string>
|
||||
<string name="pl_web_redirection_title">For a better experience, redirecting to Navi official webpage...</string>
|
||||
<string name="pl_web_redirection_subtitle">https://navi-finserv.com</string>
|
||||
<string name="no_browser_found">No web browser found. Please install a browser app, such as Google Chrome or Mozilla Firefox, from the Google Play Store to continue.</string>
|
||||
</resources>
|
||||
|
||||
@@ -115,7 +115,7 @@ fun HandleUploadDataAction(
|
||||
uploadAppsDataToS3,
|
||||
businessVertical.orEmpty(),
|
||||
numberOfRetriesLeft,
|
||||
) { _, userDataUploadCallbackResponse ->
|
||||
) { _, _, userDataUploadCallbackResponse ->
|
||||
val needIngestionPolling =
|
||||
FirebaseRemoteConfigHelper.getBoolean(
|
||||
FirebaseRemoteConfigHelper.UW_INGESTION_POLLING,
|
||||
|
||||
@@ -214,6 +214,8 @@ object FirebaseRemoteConfigHelper {
|
||||
const val DEEPLINK_RESOLVER_WAIT_TIME = "DEEPLINK_RESOLVER_WAIT_TIME"
|
||||
|
||||
const val WEB_REDIRECTION_DEFAULT_DELAY_IN_MILLIS = "WEB_REDIRECTION_DEFAULT_DELAY_IN_MILLIS"
|
||||
const val WEB_REDIRECTION_SMS_UPLOADED_DELAY_IN_MILLIS =
|
||||
"WEB_REDIRECTION_SMS_UPLOADED_DELAY_IN_MILLIS"
|
||||
|
||||
const val RETRY_INTERCEPTOR_ENABLED = "RETRY_INTERCEPTOR_ENABLED"
|
||||
const val ROOT_CA_ADDITION_TARGET_SDK = "ROOT_CA_ADDITION_TARGET_SDK"
|
||||
|
||||
@@ -81,7 +81,9 @@ object PermissionUtil {
|
||||
needTohandleIngestionPolling: Boolean = false,
|
||||
callback:
|
||||
((
|
||||
timeTakenToUpload: Long, userUploadDataResponse: UserDataUploadCallbackResponse
|
||||
timeTakenToUpload: Long,
|
||||
preSignedUrlListResponse: PreSignedUrlListResponse?,
|
||||
userUploadDataResponse: UserDataUploadCallbackResponse
|
||||
) -> Unit)? =
|
||||
null
|
||||
) {
|
||||
@@ -116,7 +118,9 @@ object PermissionUtil {
|
||||
scope: CoroutineScope,
|
||||
callback:
|
||||
(
|
||||
timeTakenToUpload: Long, userUploadDataResponse: UserDataUploadCallbackResponse
|
||||
timeTakenToUpload: Long,
|
||||
preSignedUrlListResponse: PreSignedUrlListResponse?,
|
||||
userUploadDataResponse: UserDataUploadCallbackResponse
|
||||
) -> Unit,
|
||||
needTohandleIngestionPolling: Boolean
|
||||
) {
|
||||
@@ -130,7 +134,11 @@ object PermissionUtil {
|
||||
while ((response.error != null || !response.errors.isNullOrEmpty()) && retryCount <= 4) {
|
||||
if (retryCount == 4) {
|
||||
withContext(Dispatchers.Main) {
|
||||
callback.invoke(0, UserDataUploadCallbackResponse(null, null))
|
||||
callback.invoke(
|
||||
0,
|
||||
PreSignedUrlListResponse(null),
|
||||
UserDataUploadCallbackResponse(null, null)
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -168,7 +176,11 @@ object PermissionUtil {
|
||||
uploadedResponseData
|
||||
)
|
||||
withContext(Dispatchers.Main) {
|
||||
callback.invoke(timeTakenToUploadAppData, userDataUploadCallbackResponse)
|
||||
callback.invoke(
|
||||
timeTakenToUploadAppData,
|
||||
response.data,
|
||||
userDataUploadCallbackResponse
|
||||
)
|
||||
}
|
||||
if (needTohandleIngestionPolling) {
|
||||
UploadDataPollingUtil().handleUploadDataResponse(userDataUploadCallbackResponse)
|
||||
@@ -197,7 +209,7 @@ object PermissionUtil {
|
||||
uploadedResponse.data
|
||||
)
|
||||
withContext(Dispatchers.Main) {
|
||||
callback.invoke(-1, userDataUploadCallbackResponse)
|
||||
callback.invoke(-1, response.data, userDataUploadCallbackResponse)
|
||||
}
|
||||
if (needTohandleIngestionPolling) {
|
||||
UploadDataPollingUtil()
|
||||
|
||||
@@ -16,6 +16,7 @@ import com.navi.base.sharedpref.PreferenceManager
|
||||
import com.navi.base.utils.orFalse
|
||||
import com.navi.common.model.DeviceDetail
|
||||
import com.navi.common.useruploaddata.model.IngestionStatusType
|
||||
import com.navi.common.useruploaddata.model.PreSignedUrlListResponse
|
||||
import com.navi.common.useruploaddata.model.UserDataUploadCallbackResponse
|
||||
import com.navi.common.useruploaddata.repository.UserDataRepository
|
||||
import com.navi.common.useruploaddata.utils.PermissionUtil
|
||||
@@ -36,6 +37,10 @@ class UserDataViewModel(application: Application) : AndroidViewModel(application
|
||||
val deviceDataSentStatus: LiveData<Boolean>
|
||||
get() = _deviceDataSentStatus
|
||||
|
||||
private val _preSignedUrlList = MutableLiveData<PreSignedUrlListResponse>()
|
||||
val preSignedUrlList: LiveData<PreSignedUrlListResponse>
|
||||
get() = _preSignedUrlList
|
||||
|
||||
fun sendUserDataToAws(
|
||||
uploadSms: Boolean = false,
|
||||
uploadAppUsedInfo: Boolean = false,
|
||||
@@ -44,7 +49,9 @@ class UserDataViewModel(application: Application) : AndroidViewModel(application
|
||||
needTohandleIngestionPolling: Boolean = false,
|
||||
callback:
|
||||
((
|
||||
timeTakenToUpload: Long, userUploadDataResponse: UserDataUploadCallbackResponse
|
||||
timeTakenToUpload: Long,
|
||||
preSignedUrlListResponse: PreSignedUrlListResponse?,
|
||||
userUploadDataResponse: UserDataUploadCallbackResponse
|
||||
) -> Unit)? =
|
||||
null
|
||||
) {
|
||||
@@ -56,9 +63,13 @@ class UserDataViewModel(application: Application) : AndroidViewModel(application
|
||||
uploadAppUsedInfo,
|
||||
businessVertical,
|
||||
needTohandleIngestionPolling
|
||||
) { timeTakenToUpload, userDataUploadCallbackResponse ->
|
||||
) { timeTakenToUpload, presignedUrlResponse, userDataUploadCallbackResponse ->
|
||||
_userDataSentStatus.value = userDataUploadCallbackResponse
|
||||
callback?.invoke(timeTakenToUpload, userDataUploadCallbackResponse)
|
||||
callback?.invoke(
|
||||
timeTakenToUpload,
|
||||
presignedUrlResponse,
|
||||
userDataUploadCallbackResponse
|
||||
)
|
||||
}
|
||||
Timber.d("SmsTask, ContactsTask and Device Details Task Done")
|
||||
}
|
||||
@@ -71,9 +82,12 @@ class UserDataViewModel(application: Application) : AndroidViewModel(application
|
||||
numberOfRetriesLeft: Int = 0,
|
||||
isOpLifecycleBound: Boolean = true,
|
||||
needTohandleIngestionPolling: Boolean = false,
|
||||
dataUploadCallback: (PreSignedUrlListResponse?) -> Unit = {},
|
||||
callback:
|
||||
((
|
||||
timeTakenToUpload: Long, userUploadDataResponse: UserDataUploadCallbackResponse
|
||||
timeTakenToUpload: Long,
|
||||
preSignedUrlListResponse: PreSignedUrlListResponse?,
|
||||
userUploadDataResponse: UserDataUploadCallbackResponse
|
||||
) -> Unit)? =
|
||||
null
|
||||
) {
|
||||
@@ -82,8 +96,8 @@ class UserDataViewModel(application: Application) : AndroidViewModel(application
|
||||
uploadAppsDataToS3,
|
||||
businessVertical,
|
||||
isOpLifecycleBound,
|
||||
needTohandleIngestionPolling
|
||||
) { timeTakenToUpload, userDataUploadCallbackResponse ->
|
||||
needTohandleIngestionPolling,
|
||||
) { timeTakenToUpload, presignedUrlResponse, userDataUploadCallbackResponse ->
|
||||
if (
|
||||
numberOfRetriesLeft > 0 &&
|
||||
userDataUploadCallbackResponse.ingestionStatusList
|
||||
@@ -98,11 +112,17 @@ class UserDataViewModel(application: Application) : AndroidViewModel(application
|
||||
numberOfRetriesLeft - 1,
|
||||
isOpLifecycleBound,
|
||||
needTohandleIngestionPolling,
|
||||
dataUploadCallback,
|
||||
callback
|
||||
)
|
||||
} else {
|
||||
_preSignedUrlList.value = presignedUrlResponse
|
||||
_userDataSentStatus.value = userDataUploadCallbackResponse
|
||||
callback?.invoke(timeTakenToUpload, userDataUploadCallbackResponse)
|
||||
callback?.invoke(
|
||||
timeTakenToUpload,
|
||||
presignedUrlResponse,
|
||||
userDataUploadCallbackResponse
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright © 2019-2022 by Navi Technologies Limited
|
||||
* * Copyright © 2019-2024 by Navi Technologies Limited
|
||||
* * All rights reserved. Strictly confidential
|
||||
*
|
||||
*/
|
||||
|
||||
package com.navi.common.utils
|
||||
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
fun <T> LiveData<T>.observeNullable(owner: LifecycleOwner, observer: (T?) -> Unit) =
|
||||
observe(owner, Observer<T> { v -> observer.invoke(v) })
|
||||
@@ -17,3 +23,38 @@ fun <T> LiveData<T>.observeNullable(owner: LifecycleOwner, observer: (T?) -> Uni
|
||||
fun <T> LiveData<T>.observeNonNull(owner: LifecycleOwner, observer: (T) -> Unit) {
|
||||
this.observe(owner, Observer { it?.let { observer(it) } })
|
||||
}
|
||||
|
||||
fun <T> LiveData<T>.observeWithTimeout(
|
||||
lifecycleOwner: LifecycleOwner,
|
||||
timeout: Long,
|
||||
onTimeout: () -> Unit,
|
||||
observer: (T) -> Unit
|
||||
) {
|
||||
var localOnTimeOut: (() -> Unit)? = onTimeout
|
||||
|
||||
val localObserver =
|
||||
Observer<T> { value ->
|
||||
value?.let {
|
||||
observer(it)
|
||||
localOnTimeOut = null
|
||||
}
|
||||
}
|
||||
this.observe(lifecycleOwner, localObserver)
|
||||
|
||||
val job =
|
||||
lifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
|
||||
delay(timeout)
|
||||
withContext(Dispatchers.Main.immediate) {
|
||||
this@observeWithTimeout.removeObserver(localObserver)
|
||||
localOnTimeOut?.invoke()
|
||||
}
|
||||
}
|
||||
lifecycleOwner.lifecycle.addObserver(
|
||||
object : DefaultLifecycleObserver {
|
||||
override fun onDestroy(owner: LifecycleOwner) {
|
||||
job.cancel()
|
||||
removeObserver(localObserver)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user