Skip to content

Commit

Permalink
fix(intercom): AND-6752 intercom initialisation & logout (#4093)
Browse files Browse the repository at this point in the history
  • Loading branch information
dserrano-bc committed Nov 10, 2022
1 parent 7c65d93 commit b71258d
Show file tree
Hide file tree
Showing 13 changed files with 66 additions and 36 deletions.
Expand Up @@ -183,7 +183,6 @@ val applicationModule = module {
trust = get(),
pinRepository = get(),
remoteLogger = get(),
isIntercomEnabledFlag = get(intercomChatFeatureFlag),
walletStatusPrefs = get()
)
}.bind(AppUtilAPI::class)
Expand Down Expand Up @@ -252,7 +251,8 @@ val applicationModule = module {
walletOptionsState = get(),
nabuDataManager = get(),
notificationTokenManager = get(),
storeWiper = get()
storeWiper = get(),
intercomEnabledFF = get(intercomChatFeatureFlag)
)
}

Expand Down
Expand Up @@ -32,7 +32,6 @@ import com.google.android.gms.security.ProviderInstaller
import com.google.android.play.core.missingsplits.MissingSplitsManagerFactory
import com.google.firebase.FirebaseApp
import io.embrace.android.embracesdk.Embrace
import io.intercom.android.sdk.Intercom
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.kotlin.subscribeBy
Expand Down Expand Up @@ -90,10 +89,6 @@ open class BlockchainApplication : Application() {
initLifecycleListener()
initFraudService()

if (environmentSettings.isCompanyInternalBuild() || environmentSettings.isRunningInDebugMode()) {
Intercom.initialize(this, BuildConfig.INTERCOM_API_KEY, BuildConfig.INTERCOM_APP_ID)
}

if (environmentSettings.isRunningInDebugMode()) {
Stetho.initializeWithDefaults(this)
}
Expand Down
Expand Up @@ -3,11 +3,13 @@ package piuk.blockchain.android.ui.home
import com.blockchain.core.chains.bitcoincash.BchDataManager
import com.blockchain.core.chains.ethereum.EthDataManager
import com.blockchain.core.walletoptions.WalletOptionsState
import com.blockchain.featureflag.FeatureFlag
import com.blockchain.metadata.MetadataService
import com.blockchain.nabu.datamanagers.NabuDataManager
import com.blockchain.notifications.NotificationTokenManager
import com.blockchain.storedatasource.StoreWiper
import com.blockchain.utils.then
import com.blockchain.utils.thenSingle
import com.blockchain.walletmode.WalletModeService
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Completable
Expand All @@ -26,7 +28,8 @@ class CredentialsWiper(
private val metadataService: MetadataService,
private val nabuDataManager: NabuDataManager,
private val walletOptionsState: WalletOptionsState,
private val storeWiper: StoreWiper
private val storeWiper: StoreWiper,
private val intercomEnabledFF: FeatureFlag
) {
fun wipe() {
notificationTokenManager.revokeAccessToken().then {
Expand All @@ -42,6 +45,8 @@ class CredentialsWiper(
}.onErrorComplete()
.then {
rxCompletable { storeWiper.wipe() }
}.thenSingle {
intercomEnabledFF.enabled
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
Expand All @@ -51,8 +56,8 @@ class CredentialsWiper(
// StoreWiper failed, we can't safely recover at this point
throw it
},
onComplete = {
appUtil.logout()
onSuccess = { intercomEnabled ->
appUtil.logout(intercomEnabled)
appUtil.restartApp()
}
)
Expand Down
Expand Up @@ -270,7 +270,8 @@ val redesignSettingsModule = module {
credentialsWiper = get(),
walletOptionsDataManager = get(),
defaultLabels = get(),
isIntercomEnabledFlag = get(intercomChatFeatureFlag)
isIntercomEnabledFlag = get(intercomChatFeatureFlag),
application = get()
)
}

Expand Down
Expand Up @@ -345,6 +345,7 @@ class PinActivity :
setApiOutageMessage()

with(model) {
process(PinIntent.CheckIntercomStatus)
process(PinIntent.CheckNumPinAttempts)
process(PinIntent.GetAction)
process(PinIntent.CheckApiStatus)
Expand Down Expand Up @@ -476,10 +477,10 @@ class PinActivity :
.setMessage(R.string.upgrade_fail_info)
.setCancelable(false)
.setPositiveButton(R.string.exit) { _, _ ->
util.logout()
util.logout(lastState.isIntercomEnabled)
}
.setNegativeButton(R.string.logout) { _, _ ->
util.logout()
util.logout(lastState.isIntercomEnabled)
util.restartApp()
}
.show()
Expand Down Expand Up @@ -714,10 +715,10 @@ class PinActivity :
.setPositiveButton(
R.string.exit
) { _, _ ->
util.logout()
util.logout(lastState.isIntercomEnabled)
}
.setNegativeButton(R.string.logout) { _, _ ->
util.logout()
util.logout(lastState.isIntercomEnabled)
util.restartApp()
}
.show()
Expand Down Expand Up @@ -817,7 +818,7 @@ class PinActivity :
}
else -> {
fraudService.endFlow(FraudFlow.LOGIN)
appUtil.logout()
appUtil.logout(lastState.isIntercomEnabled)
}
}
}
Expand Down Expand Up @@ -911,7 +912,7 @@ class PinActivity :
}
alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE)
.setOnClickListener {
util.logout()
util.logout(lastState.isIntercomEnabled)
}
fraudService.endFlow(FraudFlow.LOGIN)
}
Expand Down
Expand Up @@ -132,6 +132,10 @@ sealed class PinIntent : MviIntent<PinState> {
override fun reduce(oldState: PinState): PinState = oldState
}

object CheckIntercomStatus : PinIntent() {
override fun reduce(oldState: PinState): PinState = oldState
}

object FetchRemoteMobileNotice : PinIntent() {
override fun reduce(oldState: PinState): PinState = oldState
}
Expand Down Expand Up @@ -265,4 +269,8 @@ sealed class PinIntent : MviIntent<PinState> {
)
)
}

data class UpdateIntercomStatus(private val isIntercomEnabled: Boolean) : PinIntent() {
override fun reduce(oldState: PinState): PinState = oldState.copy(isIntercomEnabled = isIntercomEnabled)
}
}
@@ -1,5 +1,6 @@
package piuk.blockchain.android.ui.settings.security.pin

import android.app.Application
import androidx.annotation.VisibleForTesting
import com.blockchain.core.access.PinRepository
import com.blockchain.core.auth.AuthDataManager
Expand All @@ -23,7 +24,7 @@ import io.intercom.android.sdk.identity.Registration
import io.reactivex.rxjava3.core.Completable
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.kotlin.zipWith
import piuk.blockchain.android.BuildConfig
import piuk.blockchain.android.data.biometrics.BiometricsController
import piuk.blockchain.android.ui.auth.MobileNoticeDialog
import piuk.blockchain.android.ui.auth.MobileNoticeRemoteConfig
Expand All @@ -43,6 +44,7 @@ class PinInteractor internal constructor(
private val defaultLabels: DefaultLabels,
private val remoteLogger: RemoteLogger,
private val isIntercomEnabledFlag: FeatureFlag,
private val application: Application
) {

fun shouldShowFingerprintLogin(): Boolean {
Expand Down Expand Up @@ -102,11 +104,14 @@ class PinInteractor internal constructor(
return walletOptionsDataManager.checkForceUpgrade(versionName)
}

fun validatePIN(pin: String, isForValidatingPinForResult: Boolean = false): Single<String> =
fun validatePIN(
pin: String,
isForValidatingPinForResult: Boolean = false,
isIntercomEnabled: Boolean
): Single<String> =
authDataManager.validatePin(pin)
.firstOrError()
.zipWith(isIntercomEnabledFlag.enabled)
.flatMap { (validatedPin, isIntercomEnabled) ->
.flatMap { validatedPin ->
if (isIntercomEnabled) {
registerIntercomUser()
}
Expand All @@ -120,6 +125,9 @@ class PinInteractor internal constructor(

@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
fun registerIntercomUser() {
// TODO(dserrano): Move this initialization back to BlockchainApplication when the flag is removed
Intercom.initialize(application, BuildConfig.INTERCOM_API_KEY, BuildConfig.INTERCOM_APP_ID)

val registration = Registration.create().withUserId(authPrefs.walletGuid)
Intercom.client().loginIdentifiedUser(
registration,
Expand Down Expand Up @@ -167,6 +175,8 @@ class PinInteractor internal constructor(
)
}

fun getIntercomStatus(): Single<Boolean> = isIntercomEnabledFlag.enabled

companion object {
private const val LOCAL_MAX_ATTEMPTS: Long = 4
}
Expand Down
Expand Up @@ -52,6 +52,14 @@ class PinModel(
intent: PinIntent
): Disposable? =
when (intent) {
is PinIntent.CheckIntercomStatus -> interactor.getIntercomStatus()
.subscribeBy(
onSuccess = { enabled ->
process(PinIntent.UpdateIntercomStatus(enabled))
}, onError = {
Timber.e("Error getting intercom status")
}
)
is PinIntent.GetAction -> {
when {
interactor.isCreatingNewPin() -> process(PinIntent.UpdateAction(PinScreenView.CreateNewPin))
Expand Down Expand Up @@ -87,7 +95,7 @@ class PinModel(
is PinIntent.ValidatePIN -> {
momentLogger.startEvent(MomentEvent.PIN_TO_DASHBOARD)

interactor.validatePIN(intent.pin, intent.isForValidatingPinForResult)
interactor.validatePIN(intent.pin, intent.isForValidatingPinForResult, previousState.isIntercomEnabled)
.handleProgress(R.string.validating_pin)
.subscribeBy(
onSuccess = { password ->
Expand Down Expand Up @@ -219,7 +227,8 @@ class PinModel(
is PinIntent.HandleProgressDialog,
is PinIntent.UpgradeWalletResponse,
is PinIntent.CreatePINSucceeded,
is PinIntent.SetShowFingerprint -> null
is PinIntent.SetShowFingerprint,
is PinIntent.UpdateIntercomStatus -> null
}

private fun canTriggerAnUpdateOfType(
Expand Down
Expand Up @@ -16,7 +16,8 @@ data class PinState(
val biometricStatus: BiometricStatus = BiometricStatus(),
val upgradeWalletStatus: UpgradeWalletStatus? = null,
val payloadStatus: PayloadStatus = PayloadStatus(),
val pinStatus: PinStatus = PinStatus()
val pinStatus: PinStatus = PinStatus(),
val isIntercomEnabled: Boolean = false
) : MviState

sealed class PinScreenView {
Expand Down
6 changes: 2 additions & 4 deletions app/src/main/java/piuk/blockchain/android/util/AppUtil.kt
Expand Up @@ -6,7 +6,6 @@ import com.blockchain.commonarch.presentation.base.ActivityIndicator
import com.blockchain.commonarch.presentation.base.AppUtilAPI
import com.blockchain.commonarch.presentation.base.BlockchainActivity
import com.blockchain.core.access.PinRepository
import com.blockchain.featureflag.FeatureFlag
import com.blockchain.logging.DigitalTrust
import com.blockchain.logging.RemoteLogger
import com.blockchain.preferences.SessionPrefs
Expand All @@ -24,10 +23,9 @@ class AppUtil(
private val trust: DigitalTrust,
private val pinRepository: PinRepository,
private val remoteLogger: RemoteLogger,
private val isIntercomEnabledFlag: FeatureFlag,
private val walletStatusPrefs: WalletStatusPrefs
) : AppUtilAPI {
override fun logout() {
override fun logout(isIntercomEnabled: Boolean) {
pinRepository.clearPin()
trust.clearUserId()
context.startActivity(
Expand All @@ -36,7 +34,7 @@ class AppUtil(
action = BlockchainActivity.LOGOUT_ACTION
}
)
isIntercomEnabledFlag.enabled.map {
if (isIntercomEnabled) {
Intercom.client().logout()
}
}
Expand Down
@@ -1,5 +1,6 @@
package piuk.blockchain.android.ui.settings.security.pin

import android.app.Application
import com.blockchain.core.access.PinRepository
import com.blockchain.core.auth.AuthDataManager
import com.blockchain.core.payload.PayloadDataManager
Expand Down Expand Up @@ -41,6 +42,7 @@ class PinInteractorTest {
private val biometricsController = mock<BiometricsController>()
private val defaultLabels = mock<DefaultLabels>()
private val isIntercomEnabledFlag = mock<FeatureFlag>()
private val application: Application = mock()

@Before
fun setup() {
Expand All @@ -61,7 +63,8 @@ class PinInteractorTest {
sessionPrefs = sessionPrefs,
remoteLogger = remoteLogger,
defaultLabels = defaultLabels,
isIntercomEnabledFlag = isIntercomEnabledFlag
isIntercomEnabledFlag = isIntercomEnabledFlag,
application = application
)
)
}
Expand All @@ -70,9 +73,8 @@ class PinInteractorTest {
fun `validatePIN then call validatePin`() {
val pin = "1234"
whenever(authDataManager.validatePin(pin)).thenReturn(Observable.just(pin))
whenever(isIntercomEnabledFlag.enabled).thenReturn(Single.just(false))
doNothing().whenever(interactor).registerIntercomUser()
val test = interactor.validatePIN(pin).test()
val test = interactor.validatePIN(pin, isIntercomEnabled = false).test()
test.assertValue {
it == pin
}
Expand Down
Expand Up @@ -1191,7 +1191,7 @@ class PinModelTest {
val isForValidatingPinForResult = true
val pin = "1234"

whenever(interactor.validatePIN(pin, isForValidatingPinForResult)).thenReturn(Single.just(pin))
whenever(interactor.validatePIN(pin, isForValidatingPinForResult, false)).thenReturn(Single.just(pin))

val testState = model.state.test()
model.process(PinIntent.ValidatePIN(pin, isForValidatingPinForResult))
Expand Down Expand Up @@ -1244,7 +1244,7 @@ class PinModelTest {
val isForValidatingPinForResult = false
val pin = "1234"

whenever(interactor.validatePIN(pin, isForValidatingPinForResult)).thenReturn(Single.just(pin))
whenever(interactor.validatePIN(pin, isForValidatingPinForResult, false)).thenReturn(Single.just(pin))
whenever(interactor.isWalletUpgradeRequired()).thenReturn(false)
whenever(interactor.updatePayload(any())).thenReturn(Completable.complete())

Expand Down Expand Up @@ -1287,7 +1287,7 @@ class PinModelTest {
val isForValidatingPinForResult = false
val pin = "1234"

whenever(interactor.validatePIN(pin, isForValidatingPinForResult))
whenever(interactor.validatePIN(pin, isForValidatingPinForResult, false))
.thenReturn(Single.error(InvalidCredentialsException()))

val testState = model.state.test()
Expand Down Expand Up @@ -1337,7 +1337,7 @@ class PinModelTest {
val isForValidatingPinForResult = false
val pin = "1234"

whenever(interactor.validatePIN(pin, isForValidatingPinForResult))
whenever(interactor.validatePIN(pin, isForValidatingPinForResult, false))
.thenReturn(Single.error(Throwable()))

val testState = model.state.test()
Expand Down
@@ -1,6 +1,6 @@
package com.blockchain.commonarch.presentation.base

interface AppUtilAPI {
fun logout()
fun logout(isIntercomEnabled: Boolean = false)
var activityIndicator: ActivityIndicator?
}

0 comments on commit b71258d

Please sign in to comment.