TP-45897 | HPC | Truecaller SDK version upgrade (#9271)

Co-authored-by: Shivam Goyal <shivam.goyal@navi.com>
This commit is contained in:
Ankit Yadav
2024-01-19 11:43:34 +05:30
committed by GitHub
parent db6aea2ebd
commit f719334bdc
11 changed files with 155 additions and 193 deletions

View File

@@ -141,7 +141,7 @@ android {
buildConfigField 'String', 'SSL_PINNING_KEY', formatString('sha256/nUU7NjGrGo/mxijjsX+MHerUbpIHBidF8LAYOEPFWA8=')
buildConfigField 'String', 'ALFRED_API_KEY', formatString('oMv77fgpBg9NFGom0Psizbf7lbrdBVJz')
manifestPlaceholders = [
TRUECALLER_KEY : "6E6TX0cd28bada2b14cf28534dfce68c6a245",
TRUECALLER_KEY : "yicxl1xh6jidagslpi0h9d-uklfeinnx4a6mb6rdgyi",
FACEBOOK_APP_ID: "0"
]
}
@@ -159,7 +159,7 @@ android {
buildConfigField 'String', 'SSL_PINNING_KEY', formatString('sha256/nUU7NjGrGo/mxijjsX+MHerUbpIHBidF8LAYOEPFWA8=')
buildConfigField 'String', 'ALFRED_API_KEY', formatString('oMv77fgpBg9NFGom0Psizbf7lbrdBVJz')
manifestPlaceholders = [
TRUECALLER_KEY : "6E6TX0cd28bada2b14cf28534dfce68c6a245",
TRUECALLER_KEY : "yicxl1xh6jidagslpi0h9d-uklfeinnx4a6mb6rdgyi",
FACEBOOK_APP_ID: "0"
]
}
@@ -177,7 +177,7 @@ android {
buildConfigField 'String', 'SSL_PINNING_KEY', formatString('sha256/4sMl7dWjcM6O5RKWBw3DUpd5Qy5OX5pvcHMKQIF1bgM=')
buildConfigField 'String', 'ALFRED_API_KEY', formatString('oMv77fgpBg9NFGom0Psizbf7lbrdBVJz')
manifestPlaceholders = [
TRUECALLER_KEY : "aBkmX155b2ed283a44b008d62e8975388a4d5",
TRUECALLER_KEY : "yicxl1xh6jidagslpi0h9d-uklfeinnx4a6mb6rdgyi",
FACEBOOK_APP_ID: "0"
]
}

View File

@@ -33,6 +33,8 @@
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-sdk tools:overrideLibrary="com.truecaller.android.sdk"/>
<application
android:name=".app.NaviApplication"
android:allowBackup="false"
@@ -351,7 +353,7 @@
android:authorities="com.facebook.app.FacebookContentProvider${FACEBOOK_APP_ID}"
android:exported="true" />
<meta-data
android:name="com.truecaller.android.sdk.PartnerKey"
android:name="com.truecaller.android.sdk.ClientId"
android:value="${TRUECALLER_KEY}" />
<activity
android:name=".personalloan.intermediate.activity.IntermediateActivity"

View File

@@ -1,42 +0,0 @@
/*
* *
* * Copyright (c) 2021 . All rights reserved @Navi
*
*/
package com.naviapp.models
import com.google.gson.annotations.SerializedName
data class TrueProfileData(
@SerializedName("statusCode") val statusCode: Int? = null,
@SerializedName("status") val status: String? = null,
@SerializedName("accessToken") val accessToken: String? = null,
@SerializedName("avatarUrl") val avatarUrl: String? = null,
@SerializedName("city") val city: String? = null,
@SerializedName("companyName") val companyName: String? = null,
@SerializedName("countryCode") val countryCode: String? = null,
@SerializedName("email") val email: String? = null,
@SerializedName("facebookId") val facebookId: String? = null,
@SerializedName("firstName") val firstName: String? = null,
@SerializedName("gender") val gender: String? = null,
@SerializedName("isAmbassador") val isAmbassador: Boolean? = null,
@SerializedName("isBusiness") val isBusiness: Boolean? = null,
@SerializedName("isSimChanged") val isSimChanged: Boolean? = null,
@SerializedName("isTrueName") val isTrueName: Boolean? = null,
@SerializedName("jobTitle") val jobTitle: String? = null,
@SerializedName("lastName") val lastName: String? = null,
@SerializedName("payload") val payload: String? = null,
@SerializedName("phoneNumber") val phoneNumber: String? = null,
@SerializedName("requestNonce") val requestNonce: String? = null,
@SerializedName("signature") val signature: String? = null,
@SerializedName("signatureAlgorithm") val signatureAlgorithm: String? = null,
@SerializedName("street") val street: String? = null,
@SerializedName("twitterId") val twitterId: String? = null,
@SerializedName("url") val url: String? = null,
@SerializedName("verificationMode") val verificationMode: String? = null,
@SerializedName("verificationTimestamp") val verificationTimestamp: Long? = null,
@SerializedName("zipCode") val zipCode: String? = null,
@SerializedName("userLocale") val userLocale: String? = null
)

View File

@@ -0,0 +1,15 @@
/*
*
* * Copyright © 2024 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.naviapp.models
import com.google.gson.annotations.SerializedName
data class TruecallerAuthData(
@SerializedName("authorizationCode") private val authorizationCode: String? = null,
@SerializedName("codeVerifier") private val codeVerifier: String? = null
)

View File

@@ -11,7 +11,7 @@ import com.google.gson.annotations.SerializedName
import com.navi.base.model.LineItem
import com.navi.common.model.DeviceDetail
import com.naviapp.BuildConfig
import com.naviapp.models.TrueProfileData
import com.naviapp.models.TruecallerAuthData
data class OtpRequest(
@SerializedName("otp") val otp: String? = null,
@@ -19,7 +19,7 @@ data class OtpRequest(
@SerializedName("otpAutofill") val otpAutofill: Boolean? = null,
@SerializedName("type") val loginType: String? = null,
@SerializedName("companyName") val companyName: String? = null,
@SerializedName("truecallerProfileData") val truecallerProfileData: TrueProfileData? = null,
@SerializedName("truecallerAuthData") val truecallerAuthData: TruecallerAuthData? = null,
@SerializedName("appVersion") val appVersionData: AppVersionData? = AppVersionData(
BuildConfig.VERSION_CODE.toString(),
BuildConfig.VERSION_NAME

View File

@@ -18,5 +18,7 @@ data class OtpResponse(
@SerializedName("externalCustomerId") val externalCustomerId: String? = null,
@SerializedName("nextCta") val nextCta: CtaData? = null,
@SerializedName("phone") val phoneNumber: String? = null,
@SerializedName("firstName") val firstName: String? = null,
@SerializedName("lastName") val lastName: String? = null,
@SerializedName("loginType") val loginType: String? = null
)

View File

@@ -10,6 +10,7 @@ package com.naviapp.registration
import android.app.Activity
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.os.Bundle
import android.view.View
import androidx.core.view.isVisible
@@ -35,7 +36,6 @@ import com.navi.base.utils.BaseUtils
import com.navi.base.utils.orTrue
import com.navi.base.utils.orZero
import com.navi.common.constants.APP_UPGRADE_DATA
import com.navi.common.firebasedb.FirebaseStatusType.SUCCESS
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper
import com.navi.common.firebaseremoteconfig.FirebaseRemoteConfigHelper.DISABLE_UPDATE_COMMUNICATION_MEDIUMS_ON_LOGIN
import com.navi.common.managers.PermissionsManager
@@ -96,7 +96,7 @@ import com.naviapp.common.viewmodel.BottomNavBarVM
import com.naviapp.dashboard.listeners.FragmentInteractionListener
import com.naviapp.databinding.RegistrationActivityBinding
import com.naviapp.home.viewmodel.HomeVM
import com.naviapp.models.TrueProfileData
import com.naviapp.models.TruecallerAuthData
import com.naviapp.models.WhatsappLoginConfig
import com.naviapp.models.request.LoginType
import com.naviapp.models.request.OtpRequest
@@ -104,11 +104,10 @@ import com.navi.common.model.AppUpgradeResponse
import com.naviapp.models.response.Medium
import com.naviapp.models.response.NotificationSettings
import com.naviapp.models.response.OtpResponse
import com.naviapp.network.ApiConstants.API_SUCCESS_CODE
import com.naviapp.permission.fragments.MandatePermissionFragment
import com.naviapp.pushnotification.NotificationHandler
import com.naviapp.pushnotification.NotificationHandler.getMiPushClientRegId
import com.naviapp.registration.helper.TrueCallerHelper
import com.naviapp.registration.helper.TrueCallerFacade
import com.naviapp.registration.listeners.LoginListener
import com.naviapp.registration.viewmodel.ConfigVM
import com.naviapp.registration.viewmodel.RegistrationSharedVM
@@ -125,11 +124,11 @@ import com.naviapp.utils.addDivider
import com.naviapp.utils.getUniqueRandomNumber
import com.naviapp.utils.isAllMandatoryPermissionGranted
import com.naviapp.utils.isAppInstalled
import com.naviapp.utils.removeCodeFromPhoneNumber
import com.truecaller.android.sdk.ITrueCallback
import com.truecaller.android.sdk.TrueError
import com.truecaller.android.sdk.TrueProfile
import com.truecaller.android.sdk.TruecallerSDK
import com.truecaller.android.sdk.oAuth.CodeVerifierUtil
import com.truecaller.android.sdk.oAuth.TcOAuthCallback
import com.truecaller.android.sdk.oAuth.TcOAuthData
import com.truecaller.android.sdk.oAuth.TcOAuthError
import com.truecaller.android.sdk.oAuth.TcSdk
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
@@ -137,7 +136,7 @@ class RegistrationActivity :
BaseActivity(),
FragmentInteractionListener,
FragmentStateListener,
ITrueCallback,
TcOAuthCallback,
View.OnClickListener,
LoginListener {
private lateinit var binding: RegistrationActivityBinding
@@ -150,7 +149,8 @@ class RegistrationActivity :
ViewModelProvider(this).get(RegistrationSharedVM::class.java)
}
private val configVM by lazy { ViewModelProvider(this)[ConfigVM::class.java] }
private var randomRequestId: String? = null
private var stateRequested: String? = null
private var codeVerifier: String? = null
private var isTrueCallerEnabled: Boolean = false
private val analyticsTracker = NaviAnalytics.naviAnalytics.Registration()
private var source: String? = null
@@ -196,12 +196,14 @@ class RegistrationActivity :
}
}
if (
getOsVersion() >= Build.VERSION_CODES.N &&
isTrueCallerEnabled &&
redirectStatus !in listOf(AUTH_VIA_LINK, WhatsAppLoginFragment.TAG)
redirectStatus !in listOf(AUTH_VIA_LINK, WhatsAppLoginFragment.TAG)
) {
randomRequestId = getUniqueRandomNumber()
FcmAnalyticsUtil.analytics.setCrashlyticRandomRequestId(randomRequestId)
TrueCallerHelper.init(this, this, randomRequestId)
stateRequested = getUniqueRandomNumber()
codeVerifier = CodeVerifierUtil.generateRandomCodeVerifier()
FcmAnalyticsUtil.analytics.setCrashlyticRandomRequestId(stateRequested)
TrueCallerFacade.init(this, this, stateRequested, codeVerifier)
}
initListener()
initError(registrationVM)
@@ -290,6 +292,16 @@ class RegistrationActivity :
private fun initObservers() {
registrationVM.registrationResponse.observeNonNull(this) {
analyticsTracker.truecallerNameDetails(
firstName = it.firstName,
lastName = it.lastName
)
it.phoneNumber?.let {
phoneNumber -> BaseUtils.savePhoneNumber(phoneNumber)
analyticsTracker.loginWithTrueCaller(
number = phoneNumber,
source = source)
}
onSessionTokenReceived(it, LoginType.TRUE_CALLER)
}
registrationVM.trueCallerFailureResponse.observeNonNull(this) { trueCallerLoginFailed ->
@@ -416,55 +428,16 @@ class RegistrationActivity :
registerReceiver(otpReceiver, intentFilter)
}
override fun onFailureProfileShared(error: TrueError) {
if (error.errorType == TrueError.ERROR_TYPE_CONTINUE_WITH_DIFFERENT_NUMBER) {
override fun onFailure(error: TcOAuthError) {
if (error.errorCode == TcOAuthError.UserDeniedByPressingFooterError.errorCode) {
analyticsTracker.onTrueCallerWithDiffNumber(source)
} else {
analyticsTracker.onTrueCallerLoginError(error.errorType.orZero().toString(), source)
analyticsTracker.onTrueCallerLoginError(error.errorCode.orZero().toString(), source)
}
registrationSharedVM.setLoginViaMobile(true)
}
override fun onSuccessProfileShared(profile: TrueProfile) {
val data =
TrueProfileData(
statusCode = API_SUCCESS_CODE,
status = SUCCESS,
accessToken = profile.accessToken,
avatarUrl = profile.avatarUrl,
city = profile.city,
companyName = profile.companyName,
countryCode = profile.countryCode,
email = profile.email,
facebookId = profile.facebookId,
firstName = profile.firstName,
gender = profile.gender,
isAmbassador = profile.isAmbassador,
isBusiness = profile.isBusiness,
isSimChanged = profile.isSimChanged,
isTrueName = profile.isTrueName,
jobTitle = profile.jobTitle,
lastName = profile.lastName,
payload = profile.payload,
phoneNumber = profile.phoneNumber,
requestNonce = profile.requestNonce,
signature = profile.signature,
signatureAlgorithm = profile.signatureAlgorithm,
street = profile.street,
twitterId = profile.twitterId,
url = profile.url,
verificationMode = profile.verificationMode,
verificationTimestamp = profile.verificationTimestamp,
zipCode = profile.zipcode,
userLocale = profile.userLocale?.language
)
analyticsTracker.truecallerNameDetails(
firstName = profile.firstName,
lastName = profile.lastName
)
val phone = removeCodeFromPhoneNumber(profile.phoneNumber.orEmpty())
BaseUtils.savePhoneNumber(phone)
analyticsTracker.loginWithTrueCaller(phone, source)
override fun onSuccess(tcOAuthData: TcOAuthData) {
showLoader()
val gaId = PreferenceManager.getStringPreference(GOOGLE_ADVERTISING_ID)
val fcmToken = PreferenceManager.getStringPreference(FCM_TOKEN)
@@ -516,11 +489,16 @@ class RegistrationActivity :
miPushToken = getMiPushClientRegId(applicationContext),
isInstalledOnProfiles = isInstalledInProfile(applicationContext),
localStorageLocation = getLocalStorageLocation(applicationContext),
sourceSignature = getDeviceSignature(applicationContext),
sourceSignature = getDeviceSignature(applicationContext)
)
val trueCallerAuthData =
TruecallerAuthData(
authorizationCode = tcOAuthData.authorizationCode,
codeVerifier = codeVerifier
)
val otpRequest =
OtpRequest(
truecallerProfileData = data,
truecallerAuthData = trueCallerAuthData,
loginType = LoginType.TRUE_CALLER.name,
source = source,
deviceDetail = deviceDetail,
@@ -549,16 +527,23 @@ class RegistrationActivity :
return if (parameters.size > 0) parameters else null
}
override fun onVerificationRequired(error: TrueError?) {
override fun onVerificationRequired(error: TcOAuthError?) {
// will only be called whenTruecallerSdkScope#SDK_OPTION_WITH_OTP is selected
}
override fun onFragmentOpen(type: String?) {
if (!TrueCallerHelper.isInit()) {
TrueCallerHelper.init(this, this)
if(getOsVersion() <= Build.VERSION_CODES.M) {
registrationSharedVM.setLoginViaMobile(true)
return
}
if (TruecallerSDK.getInstance().isUsable) {
TruecallerSDK.getInstance().getUserProfile(this)
if (!TrueCallerFacade.isInit()) {
stateRequested = getUniqueRandomNumber()
codeVerifier = CodeVerifierUtil.generateRandomCodeVerifier()
FcmAnalyticsUtil.analytics.setCrashlyticRandomRequestId(stateRequested)
TrueCallerFacade.init(this, this, stateRequested, codeVerifier)
}
if (TcSdk.getInstance().isOAuthFlowUsable) {
TcSdk.getInstance().getAuthorizationCode(this)
analyticsTracker.onTrueCallerBottomSheetOpen()
} else {
registrationSharedVM.setLoginViaMobile(true)
@@ -567,10 +552,9 @@ class RegistrationActivity :
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == TruecallerSDK.SHARE_PROFILE_REQUEST_CODE) {
if (TrueCallerHelper.isUsable()) {
TruecallerSDK.getInstance()
.onActivityResultObtained(this, requestCode, resultCode, data)
if (requestCode == TcSdk.SHARE_PROFILE_REQUEST_CODE) {
if (TrueCallerFacade.isUsable()) {
TcSdk.getInstance().onActivityResultObtained(this, requestCode, resultCode, data)
} else {
analyticsTracker.onTrueCallerInitError()
}
@@ -592,7 +576,7 @@ class RegistrationActivity :
override fun onDestroy() {
super.onDestroy()
if (isTrueCallerEnabled) TrueCallerHelper.clear()
if (isTrueCallerEnabled) TrueCallerFacade.clear()
}
override val screenName

View File

@@ -0,0 +1,75 @@
/*
*
* * Copyright © 2021-2023 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.naviapp.registration.helper
import com.navi.design.R as DesignR
import android.content.Context
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.navi.base.utils.orFalse
import com.navi.common.utils.log
import com.naviapp.R
import com.truecaller.android.sdk.oAuth.CodeVerifierUtil
import com.truecaller.android.sdk.oAuth.TcOAuthCallback
import com.truecaller.android.sdk.oAuth.TcSdk
import com.truecaller.android.sdk.oAuth.TcSdkOptions
object TrueCallerFacade {
private var isInit: Boolean? = null
fun init(context: Context, tcCallBack: TcOAuthCallback, stateRequested: String? = null, codeVerifier: String? = null) {
initImpl(context, tcCallBack, stateRequested, codeVerifier)
}
private fun initImpl(context: Context, tcCallBack: TcOAuthCallback, stateRequested: String? = null, codeVerifier: String? = null){
try {
val tcSdkOptions = TcSdkOptions.Builder(context, tcCallBack)
.buttonShapeOptions(TcSdkOptions.BUTTON_SHAPE_RECTANGLE)
.footerType(TcSdkOptions.FOOTER_TYPE_ANOTHER_MOBILE_NO)
.sdkOptions(TcSdkOptions.OPTION_VERIFY_ONLY_TC_USERS)
.ctaText(TcSdkOptions.CTA_TEXT_CONTINUE)
.buttonColor(context.resources.getColor(DesignR.color.color_1F002A))
.buttonTextColor(context.resources.getColor(R.color.white))
.loginTextPrefix(TcSdkOptions.LOGIN_TEXT_PREFIX_TO_CONTINUE)
.consentHeadingOption(TcSdkOptions.SDK_CONSENT_HEADING_LOG_IN_TO)
.build()
TcSdk.init(tcSdkOptions)
if (TcSdk.getInstance().isOAuthFlowUsable) {
stateRequested?.apply { TcSdk.getInstance().setOAuthState(this) }
TcSdk.getInstance().setOAuthScopes(arrayOf("profile", "phone", "openid", "offline_access"))
val codeChallenge = codeVerifier?.let { CodeVerifierUtil.getCodeChallenge(it) }
codeChallenge?.apply { TcSdk.getInstance().setCodeChallenge(this) }
}
isInit = true
} catch (e: Exception) {
isInit = null
e.log()
}
}
fun isInit(): Boolean {
return isInit.orFalse()
}
/**
* isUsable be true/false for SDK_OPTION_WITHOUT_OTP but always true for SDK_OPTION_WITH_OTP
*/
fun isUsable(): Boolean {
return isInit() && TcSdk.getInstance().isOAuthFlowUsable
}
fun clear() {
try {
isInit = null
TcSdk.clear()
} catch (e: Exception) {
e.log()
}
}
}

View File

@@ -1,72 +0,0 @@
/*
*
* * Copyright © 2021-2023 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.naviapp.registration.helper
import com.navi.design.R as DesignR
import android.content.Context
import com.navi.base.utils.orFalse
import com.navi.common.utils.log
import com.naviapp.R
import com.truecaller.android.sdk.ITrueCallback
import com.truecaller.android.sdk.TruecallerSDK
import com.truecaller.android.sdk.TruecallerSdkScope
object TrueCallerHelper {
private var isInit: Boolean? = null
fun init(context: Context, tcCallBack: ITrueCallback, requestId: String? = null) {
initImpl(context, tcCallBack, requestId)
}
private fun initImpl(context: Context, tcCallBack: ITrueCallback, requestId: String? = null) {
try {
val trueScope = TruecallerSdkScope.Builder(context, tcCallBack)
.consentMode(TruecallerSdkScope.CONSENT_MODE_BOTTOMSHEET)
.buttonColor(context.resources.getColor(DesignR.color.color_1F002A))
.buttonTextColor(context.resources.getColor(R.color.white))
// .privacyPolicyUrl("https://navi-tnc-privacy-policy-resources.s3.ap-south-1.amazonaws.com/privacy_policy/index.html")
//.termsOfServiceUrl("https://navi-tnc-privacy-policy-resources.s3.ap-south-1.amazonaws.com/privacy_policy/index.html")
.buttonShapeOptions(TruecallerSdkScope.BUTTON_SHAPE_RECTANGLE)
.footerType(TruecallerSdkScope.FOOTER_TYPE_CONTINUE)
.consentTitleOption(TruecallerSdkScope.SDK_CONSENT_TITLE_LOG_IN)
.sdkOptions(TruecallerSdkScope.SDK_OPTION_WITHOUT_OTP) // isUsable can be true/false with SDK_OPTION_WITHOUT_OTP but only true for SDK_OPTION_WITH_OTP
.build()
TruecallerSDK.init(trueScope)
if (TruecallerSDK.getInstance().isUsable) {
requestId?.apply { TruecallerSDK.getInstance().setRequestNonce(this) }
}
isInit = true
} catch (e: Exception) {
isInit = null
e.log()
}
}
fun isInit(): Boolean {
return isInit.orFalse()
}
/**
* isUsable be true/false for SDK_OPTION_WITHOUT_OTP but always true for SDK_OPTION_WITH_OTP
*/
fun isUsable(): Boolean {
return isInit() && TruecallerSDK.getInstance().isUsable
}
fun clear() {
try {
isInit = null
TruecallerSDK.clear()
} catch (e: Exception) {
}
}
}

View File

@@ -106,7 +106,7 @@ retrofit = "2.9.0"
room = "2.5.2"
shawnLin-numberPicker = "2.4.13"
spotless = "6.23.3"
truecaller = "2.7.0"
truecaller = "3.0.0"
visit = "1.24"
wasabeef-recyclerviewAnimators = "4.0.1"
zetetic-androidDatabaseSqlcipher = "4.5.4"

View File

@@ -10,8 +10,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-sdk tools:overrideLibrary="com.truecaller.android.sdk" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />