Updated on 2026-08-14

This commit is contained in:
Tangem 2024-04-09 15:05:44 +02:00
parent 423e125974
commit 3e5bf1d8c3
12 changed files with 505 additions and 212 deletions

View file

@ -219,6 +219,7 @@ dependencies {
/** Chucker */
debugImplementation(deps.chucker)
mockedImplementation(deps.chuckerStub)
externalImplementation(deps.chuckerStub)
internalImplementation(deps.chuckerStub)
releaseImplementation(deps.chuckerStub)

@ -1 +1 @@
Subproject commit 82f4a8aebcab924047705ad3ecd5f008f07ca0b5
Subproject commit b0985600722953fae0a93bcbbc2a83930b9e0cbe

View file

@ -1,9 +1,12 @@
package com.tangem.tap.di
import android.content.Context
import com.tangem.domain.card.BuildConfig
import com.tangem.domain.card.ScanCardUseCase
import com.tangem.domain.card.repository.CardSdkConfigRepository
import com.tangem.domain.exchange.RampStateManager
import com.tangem.tap.domain.DefaultTangemSdkManager
import com.tangem.tap.domain.MockTangemSdkManager
import com.tangem.tap.domain.TangemSdkManager
import com.tangem.tap.domain.scanCard.repository.DefaultScanCardRepository
import com.tangem.tap.network.exchangeServices.DefaultRampManager
@ -28,7 +31,11 @@ internal object ActivityModule {
@ApplicationContext context: Context,
cardSdkConfigRepository: CardSdkConfigRepository,
): TangemSdkManager {
return TangemSdkManager(cardSdkConfigRepository = cardSdkConfigRepository, resources = context.resources)
return if (BuildConfig.MOCK_DATA_SOURCE) {
MockTangemSdkManager(resources = context.resources)
} else {
DefaultTangemSdkManager(cardSdkConfigRepository = cardSdkConfigRepository, resources = context.resources)
}
}
@Provides

View file

@ -0,0 +1,290 @@
package com.tangem.tap.domain
import android.content.res.Resources
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import com.tangem.Message
import com.tangem.TangemSdk
import com.tangem.common.*
import com.tangem.common.authentication.keystore.KeystoreManager
import com.tangem.common.card.FirmwareVersion
import com.tangem.common.core.*
import com.tangem.common.extensions.ByteArrayKey
import com.tangem.common.services.secure.SecureStorage
import com.tangem.common.usersCode.UserCodeRepository
import com.tangem.core.analytics.Analytics
import com.tangem.core.analytics.models.Basic
import com.tangem.crypto.bip39.DefaultMnemonic
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.domain.card.repository.CardSdkConfigRepository
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.operations.ScanTask
import com.tangem.operations.derivation.DerivationTaskResponse
import com.tangem.operations.derivation.DeriveMultipleWalletPublicKeysTask
import com.tangem.operations.pins.SetUserCodeCommand
import com.tangem.operations.usersetttings.SetUserCodeRecoveryAllowedTask
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
import com.tangem.operations.derivation.DeriveWalletPublicKeyTask
import com.tangem.tap.derivationsFinder
import com.tangem.tap.domain.tasks.product.CreateProductWalletTask
import com.tangem.tap.domain.tasks.product.CreateProductWalletTaskResponse
import com.tangem.tap.domain.tasks.product.ResetToFactorySettingsTask
import com.tangem.tap.domain.tasks.product.ScanProductTask
import com.tangem.wallet.R
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
import kotlin.coroutines.resume
@Suppress("TooManyFunctions")
class DefaultTangemSdkManager(
private val cardSdkConfigRepository: CardSdkConfigRepository,
private val resources: Resources,
) : TangemSdkManager {
private val tangemSdk: TangemSdk
get() = cardSdkConfigRepository.sdk
private val userCodeRepository by lazy {
UserCodeRepository(
keystoreManager = tangemSdk.keystoreManager,
secureStorage = tangemSdk.secureStorage,
)
}
override val canUseBiometry: Boolean
get() = tangemSdk.authenticationManager.canAuthenticate || needEnrollBiometrics
override val needEnrollBiometrics: Boolean
get() = tangemSdk.authenticationManager.needEnrollBiometrics
override val keystoreManager: KeystoreManager
get() = tangemSdk.keystoreManager
override val secureStorage: SecureStorage
get() = tangemSdk.secureStorage
override val userCodeRequestPolicy: UserCodeRequestPolicy
get() = tangemSdk.config.userCodeRequestPolicy
override suspend fun scanProduct(
cardId: String?,
messageRes: Int?,
allowsRequestAccessCodeFromRepository: Boolean,
): CompletionResult<ScanResponse> {
val message = Message(resources.getString(messageRes ?: R.string.initial_message_scan_header))
return runTaskAsyncReturnOnMain(
runnable = ScanProductTask(
card = null,
derivationsFinder = derivationsFinder,
allowsRequestAccessCodeFromRepository = allowsRequestAccessCodeFromRepository,
),
cardId = cardId,
initialMessage = message,
).also { sendScanResultsToAnalytics(it) }
}
override suspend fun createProductWallet(
scanResponse: ScanResponse,
shouldReset: Boolean,
): CompletionResult<CreateProductWalletTaskResponse> {
return runTaskAsync(
runnable = CreateProductWalletTask(
cardTypesResolver = scanResponse.cardTypesResolver,
derivationStyleProvider = scanResponse.derivationStyleProvider,
shouldReset = shouldReset,
),
cardId = scanResponse.card.cardId,
initialMessage = Message(resources.getString(R.string.initial_message_create_wallet_body)),
iconScanRes = if (scanResponse.cardTypesResolver.isRing()) R.drawable.img_hand_scan_ring else null,
)
}
override suspend fun importWallet(
scanResponse: ScanResponse,
mnemonic: String,
passphrase: String?,
shouldReset: Boolean,
): CompletionResult<CreateProductWalletTaskResponse> {
val defaultMnemonic = try {
DefaultMnemonic(mnemonic, tangemSdk.wordlist)
} catch (e: TangemSdkError.MnemonicException) {
return CompletionResult.Failure(e)
}
return runTaskAsync(
CreateProductWalletTask(
cardTypesResolver = scanResponse.cardTypesResolver,
derivationStyleProvider = scanResponse.derivationStyleProvider,
mnemonic = defaultMnemonic,
passphrase = passphrase,
shouldReset = shouldReset,
),
scanResponse.card.cardId,
Message(resources.getString(R.string.initial_message_create_wallet_body)),
)
}
private fun sendScanResultsToAnalytics(result: CompletionResult<ScanResponse>) {
if (result is CompletionResult.Failure) {
(result.error as? TangemSdkError)?.let { error ->
Analytics.send(Basic.ScanError(error))
}
}
}
override suspend fun derivePublicKeys(
cardId: String?,
derivations: Map<ByteArrayKey, List<DerivationPath>>,
): CompletionResult<DerivationTaskResponse> {
return runTaskAsyncReturnOnMain(DeriveMultipleWalletPublicKeysTask(derivations), cardId)
}
override suspend fun deriveExtendedPublicKey(
cardId: String?,
walletPublicKey: ByteArray,
derivation: DerivationPath,
): CompletionResult<ExtendedPublicKey> = withContext(Dispatchers.Main) {
runTaskAsyncReturnOnMain(
DeriveWalletPublicKeyTask(walletPublicKey, derivation),
cardId,
)
}
override suspend fun resetToFactorySettings(
cardId: String,
allowsRequestAccessCodeFromRepository: Boolean,
): CompletionResult<CardDTO> {
return runTaskAsyncReturnOnMain(
runnable = ResetToFactorySettingsTask(
allowsRequestAccessCodeFromRepository = allowsRequestAccessCodeFromRepository,
),
cardId = cardId,
initialMessage = Message(resources.getString(R.string.card_settings_reset_card_to_factory)),
)
.map { CardDTO(it) }
}
override suspend fun saveAccessCode(accessCode: String, cardsIds: Set<String>): CompletionResult<Unit> {
return userCodeRepository.save(
cardsIds = cardsIds,
userCode = UserCode(
type = UserCodeType.AccessCode,
stringValue = accessCode,
),
)
}
override suspend fun deleteSavedUserCodes(cardsIds: Set<String>): CompletionResult<Unit> {
return userCodeRepository.delete(cardsIds.toSet())
}
override suspend fun clearSavedUserCodes(): CompletionResult<Unit> {
return userCodeRepository.clear()
}
override suspend fun setPasscode(cardId: String?): CompletionResult<SuccessResponse> {
return runTaskAsyncReturnOnMain(
SetUserCodeCommand.changePasscode(null),
cardId,
initialMessage = Message(resources.getString(R.string.initial_message_change_passcode_body)),
)
}
override suspend fun setAccessCode(cardId: String?): CompletionResult<SuccessResponse> {
return runTaskAsyncReturnOnMain(
SetUserCodeCommand.changeAccessCode(null),
cardId,
initialMessage = Message(resources.getString(R.string.initial_message_change_access_code_body)),
)
}
override suspend fun setLongTap(cardId: String?): CompletionResult<SuccessResponse> {
return runTaskAsyncReturnOnMain(
SetUserCodeCommand.resetUserCodes(),
cardId,
initialMessage = Message(resources.getString(R.string.initial_message_tap_header)),
)
}
override suspend fun setAccessCodeRecoveryEnabled(
cardId: String?,
enabled: Boolean,
): CompletionResult<SuccessResponse> {
return runTaskAsyncReturnOnMain(
SetUserCodeRecoveryAllowedTask(enabled),
cardId,
initialMessage = Message(resources.getString(R.string.initial_message_tap_header)),
)
}
override suspend fun scanCard(
cardId: String?,
allowRequestAccessCodeFromRepository: Boolean,
): CompletionResult<CardDTO> {
return runTaskAsyncReturnOnMain(
runnable = ScanTask(allowRequestAccessCodeFromRepository),
cardId = cardId,
initialMessage = Message(resources.getString(R.string.initial_message_tap_header)),
)
.map { CardDTO(it) }
}
override suspend fun <T> runTaskAsync(
runnable: CardSessionRunnable<T>,
cardId: String?,
initialMessage: Message?,
accessCode: String?,
@DrawableRes iconScanRes: Int?,
): CompletionResult<T> = withContext(Dispatchers.Main) {
suspendCancellableCoroutine { continuation ->
tangemSdk.startSessionWithRunnable(runnable, cardId, initialMessage, accessCode, iconScanRes) { result ->
if (continuation.isActive) continuation.resume(result)
}
}
}
private suspend fun <T> runTaskAsyncReturnOnMain(
runnable: CardSessionRunnable<T>,
cardId: String? = null,
initialMessage: Message? = null,
): CompletionResult<T> {
val result = runTaskAsync(runnable, cardId, initialMessage)
return withContext(Dispatchers.Main) { result }
}
@Suppress("MagicNumber")
override fun changeDisplayedCardIdNumbersCount(scanResponse: ScanResponse?) {
tangemSdk.config.cardIdDisplayFormat = when {
scanResponse == null -> CardIdDisplayFormat.Full
scanResponse.cardTypesResolver.isTangemTwins() -> CardIdDisplayFormat.LastLuhn(4)
else -> CardIdDisplayFormat.Full
}
}
@Deprecated("TangemSdkManager shouldn't returns a string from resources")
override fun getString(@StringRes stringResId: Int, vararg formatArgs: Any?): String {
return resources.getString(stringResId, *formatArgs)
}
override fun setUserCodeRequestPolicy(policy: UserCodeRequestPolicy) {
tangemSdk.config.userCodeRequestPolicy = policy
}
companion object {
@Deprecated("Use [DefaultCardSdkProvider] instead")
val config = Config(
linkedTerminal = true,
allowUntrustedCards = true,
filter = CardFilter(
allowedCardTypes = FirmwareVersion.FirmwareType.values().toList(),
maxFirmwareVersion = FirmwareVersion(major = 6, minor = 33),
batchIdFilter = CardFilter.Companion.ItemFilter.Deny(
items = setOf("0027", "0030", "0031", "0035"),
),
),
)
}
}

View file

@ -0,0 +1,148 @@
package com.tangem.tap.domain
import android.content.res.Resources
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import com.tangem.Message
import com.tangem.common.*
import com.tangem.common.authentication.keystore.KeystoreManager
import com.tangem.common.core.*
import com.tangem.common.extensions.ByteArrayKey
import com.tangem.common.services.secure.SecureStorage
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.operations.derivation.DerivationTaskResponse
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
import com.tangem.tap.domain.tasks.product.CreateProductWalletTaskResponse
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@Suppress("TooManyFunctions")
class MockTangemSdkManager(
private val resources: Resources,
) : TangemSdkManager {
override val canUseBiometry: Boolean
get() = TODO()
override val needEnrollBiometrics: Boolean
get() = TODO()
override val keystoreManager: KeystoreManager
get() = TODO()
override val secureStorage: SecureStorage
get() = TODO()
override val userCodeRequestPolicy: UserCodeRequestPolicy
get() = TODO()
override suspend fun scanProduct(
cardId: String?,
messageRes: Int?,
allowsRequestAccessCodeFromRepository: Boolean,
): CompletionResult<ScanResponse> {
TODO()
}
override suspend fun createProductWallet(
scanResponse: ScanResponse,
shouldReset: Boolean,
): CompletionResult<CreateProductWalletTaskResponse> {
TODO()
}
override suspend fun importWallet(
scanResponse: ScanResponse,
mnemonic: String,
passphrase: String?,
shouldReset: Boolean,
): CompletionResult<CreateProductWalletTaskResponse> {
TODO()
}
override suspend fun derivePublicKeys(
cardId: String?,
derivations: Map<ByteArrayKey, List<DerivationPath>>,
): CompletionResult<DerivationTaskResponse> {
TODO()
}
override suspend fun deriveExtendedPublicKey(
cardId: String?,
walletPublicKey: ByteArray,
derivation: DerivationPath,
): CompletionResult<ExtendedPublicKey> {
TODO()
}
override suspend fun resetToFactorySettings(
cardId: String,
allowsRequestAccessCodeFromRepository: Boolean,
): CompletionResult<CardDTO> {
TODO()
}
override suspend fun saveAccessCode(accessCode: String, cardsIds: Set<String>): CompletionResult<Unit> {
TODO()
}
override suspend fun deleteSavedUserCodes(cardsIds: Set<String>): CompletionResult<Unit> {
TODO()
}
override suspend fun clearSavedUserCodes(): CompletionResult<Unit> {
TODO()
}
override suspend fun setPasscode(cardId: String?): CompletionResult<SuccessResponse> {
TODO()
}
override suspend fun setAccessCode(cardId: String?): CompletionResult<SuccessResponse> {
TODO()
}
override suspend fun setLongTap(cardId: String?): CompletionResult<SuccessResponse> {
TODO()
}
override suspend fun setAccessCodeRecoveryEnabled(
cardId: String?,
enabled: Boolean,
): CompletionResult<SuccessResponse> {
TODO()
}
override suspend fun scanCard(
cardId: String?,
allowRequestAccessCodeFromRepository: Boolean,
): CompletionResult<CardDTO> {
TODO()
}
override suspend fun <T> runTaskAsync(
runnable: CardSessionRunnable<T>,
cardId: String?,
initialMessage: Message?,
accessCode: String?,
@DrawableRes iconScanRes: Int?,
): CompletionResult<T> = withContext(Dispatchers.Main) {
TODO()
}
@Suppress("MagicNumber")
override fun changeDisplayedCardIdNumbersCount(scanResponse: ScanResponse?) {
TODO()
}
@Deprecated("TangemSdkManager shouldn't returns a string from resources")
override fun getString(@StringRes stringResId: Int, vararg formatArgs: Any?): String {
return resources.getString(stringResId, *formatArgs)
}
override fun setUserCodeRequestPolicy(policy: UserCodeRequestPolicy) {
TODO()
}
}

View file

@ -1,233 +1,84 @@
package com.tangem.tap.domain
import android.content.res.Resources
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import com.tangem.Message
import com.tangem.TangemSdk
import com.tangem.common.*
import com.tangem.common.authentication.keystore.KeystoreManager
import com.tangem.common.card.FirmwareVersion
import com.tangem.common.core.*
import com.tangem.common.extensions.ByteArrayKey
import com.tangem.common.services.secure.SecureStorage
import com.tangem.common.usersCode.UserCodeRepository
import com.tangem.core.analytics.Analytics
import com.tangem.core.analytics.models.Basic
import com.tangem.crypto.bip39.DefaultMnemonic
import com.tangem.crypto.hdWallet.DerivationPath
import com.tangem.domain.card.repository.CardSdkConfigRepository
import com.tangem.domain.common.util.cardTypesResolver
import com.tangem.domain.common.util.derivationStyleProvider
import com.tangem.domain.models.scan.CardDTO
import com.tangem.domain.models.scan.ScanResponse
import com.tangem.operations.ScanTask
import com.tangem.operations.derivation.DerivationTaskResponse
import com.tangem.operations.derivation.DeriveMultipleWalletPublicKeysTask
import com.tangem.operations.pins.SetUserCodeCommand
import com.tangem.operations.usersetttings.SetUserCodeRecoveryAllowedTask
import com.tangem.crypto.hdWallet.bip32.ExtendedPublicKey
import com.tangem.operations.derivation.DeriveWalletPublicKeyTask
import com.tangem.tap.derivationsFinder
import com.tangem.tap.domain.tasks.product.CreateProductWalletTask
import com.tangem.tap.domain.tasks.product.CreateProductWalletTaskResponse
import com.tangem.tap.domain.tasks.product.ResetToFactorySettingsTask
import com.tangem.tap.domain.tasks.product.ScanProductTask
import com.tangem.wallet.R
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
import kotlin.coroutines.resume
@Suppress("TooManyFunctions")
class TangemSdkManager(
private val cardSdkConfigRepository: CardSdkConfigRepository,
private val resources: Resources,
) {
private val tangemSdk: TangemSdk
get() = cardSdkConfigRepository.sdk
private val userCodeRepository by lazy {
UserCodeRepository(
keystoreManager = tangemSdk.keystoreManager,
secureStorage = tangemSdk.secureStorage,
)
}
interface TangemSdkManager {
val canUseBiometry: Boolean
get() = tangemSdk.authenticationManager.canAuthenticate || needEnrollBiometrics
val needEnrollBiometrics: Boolean
get() = tangemSdk.authenticationManager.needEnrollBiometrics
val keystoreManager: KeystoreManager
get() = tangemSdk.keystoreManager
val secureStorage: SecureStorage
get() = tangemSdk.secureStorage
val userCodeRequestPolicy: UserCodeRequestPolicy
get() = tangemSdk.config.userCodeRequestPolicy
suspend fun scanProduct(
cardId: String? = null,
messageRes: Int? = null,
allowsRequestAccessCodeFromRepository: Boolean = false,
): CompletionResult<ScanResponse> {
val message = Message(resources.getString(messageRes ?: R.string.initial_message_scan_header))
return runTaskAsyncReturnOnMain(
runnable = ScanProductTask(
card = null,
derivationsFinder = derivationsFinder,
allowsRequestAccessCodeFromRepository = allowsRequestAccessCodeFromRepository,
),
cardId = cardId,
initialMessage = message,
).also { sendScanResultsToAnalytics(it) }
}
): CompletionResult<ScanResponse>
suspend fun createProductWallet(
scanResponse: ScanResponse,
shouldReset: Boolean = false,
): CompletionResult<CreateProductWalletTaskResponse> {
return runTaskAsync(
runnable = CreateProductWalletTask(
cardTypesResolver = scanResponse.cardTypesResolver,
derivationStyleProvider = scanResponse.derivationStyleProvider,
shouldReset = shouldReset,
),
cardId = scanResponse.card.cardId,
initialMessage = Message(resources.getString(R.string.initial_message_create_wallet_body)),
iconScanRes = if (scanResponse.cardTypesResolver.isRing()) R.drawable.img_hand_scan_ring else null,
)
}
): CompletionResult<CreateProductWalletTaskResponse>
suspend fun importWallet(
scanResponse: ScanResponse,
mnemonic: String,
passphrase: String?,
shouldReset: Boolean,
): CompletionResult<CreateProductWalletTaskResponse> {
val defaultMnemonic = try {
DefaultMnemonic(mnemonic, tangemSdk.wordlist)
} catch (e: TangemSdkError.MnemonicException) {
return CompletionResult.Failure(e)
}
return runTaskAsync(
CreateProductWalletTask(
cardTypesResolver = scanResponse.cardTypesResolver,
derivationStyleProvider = scanResponse.derivationStyleProvider,
mnemonic = defaultMnemonic,
passphrase = passphrase,
shouldReset = shouldReset,
),
scanResponse.card.cardId,
Message(resources.getString(R.string.initial_message_create_wallet_body)),
)
}
private fun sendScanResultsToAnalytics(result: CompletionResult<ScanResponse>) {
if (result is CompletionResult.Failure) {
(result.error as? TangemSdkError)?.let { error ->
Analytics.send(Basic.ScanError(error))
}
}
}
): CompletionResult<CreateProductWalletTaskResponse>
suspend fun derivePublicKeys(
cardId: String?,
derivations: Map<ByteArrayKey, List<DerivationPath>>,
): CompletionResult<DerivationTaskResponse> {
return runTaskAsyncReturnOnMain(DeriveMultipleWalletPublicKeysTask(derivations), cardId)
}
): CompletionResult<DerivationTaskResponse>
suspend fun deriveExtendedPublicKey(
cardId: String?,
walletPublicKey: ByteArray,
derivation: DerivationPath,
): CompletionResult<ExtendedPublicKey> = withContext(Dispatchers.Main) {
runTaskAsyncReturnOnMain(
DeriveWalletPublicKeyTask(walletPublicKey, derivation),
cardId,
)
}
): CompletionResult<ExtendedPublicKey>
suspend fun resetToFactorySettings(
cardId: String,
allowsRequestAccessCodeFromRepository: Boolean,
): CompletionResult<CardDTO> {
return runTaskAsyncReturnOnMain(
runnable = ResetToFactorySettingsTask(
allowsRequestAccessCodeFromRepository = allowsRequestAccessCodeFromRepository,
),
cardId = cardId,
initialMessage = Message(resources.getString(R.string.card_settings_reset_card_to_factory)),
)
.map { CardDTO(it) }
}
): CompletionResult<CardDTO>
suspend fun saveAccessCode(accessCode: String, cardsIds: Set<String>): CompletionResult<Unit> {
return userCodeRepository.save(
cardsIds = cardsIds,
userCode = UserCode(
type = UserCodeType.AccessCode,
stringValue = accessCode,
),
)
}
suspend fun saveAccessCode(accessCode: String, cardsIds: Set<String>): CompletionResult<Unit>
suspend fun deleteSavedUserCodes(cardsIds: Set<String>): CompletionResult<Unit> {
return userCodeRepository.delete(cardsIds.toSet())
}
suspend fun deleteSavedUserCodes(cardsIds: Set<String>): CompletionResult<Unit>
suspend fun clearSavedUserCodes(): CompletionResult<Unit> {
return userCodeRepository.clear()
}
suspend fun clearSavedUserCodes(): CompletionResult<Unit>
suspend fun setPasscode(cardId: String?): CompletionResult<SuccessResponse> {
return runTaskAsyncReturnOnMain(
SetUserCodeCommand.changePasscode(null),
cardId,
initialMessage = Message(resources.getString(R.string.initial_message_change_passcode_body)),
)
}
suspend fun setPasscode(cardId: String?): CompletionResult<SuccessResponse>
suspend fun setAccessCode(cardId: String?): CompletionResult<SuccessResponse> {
return runTaskAsyncReturnOnMain(
SetUserCodeCommand.changeAccessCode(null),
cardId,
initialMessage = Message(resources.getString(R.string.initial_message_change_access_code_body)),
)
}
suspend fun setAccessCode(cardId: String?): CompletionResult<SuccessResponse>
suspend fun setLongTap(cardId: String?): CompletionResult<SuccessResponse> {
return runTaskAsyncReturnOnMain(
SetUserCodeCommand.resetUserCodes(),
cardId,
initialMessage = Message(resources.getString(R.string.initial_message_tap_header)),
)
}
suspend fun setLongTap(cardId: String?): CompletionResult<SuccessResponse>
suspend fun setAccessCodeRecoveryEnabled(cardId: String?, enabled: Boolean): CompletionResult<SuccessResponse> {
return runTaskAsyncReturnOnMain(
SetUserCodeRecoveryAllowedTask(enabled),
cardId,
initialMessage = Message(resources.getString(R.string.initial_message_tap_header)),
)
}
suspend fun setAccessCodeRecoveryEnabled(cardId: String?, enabled: Boolean): CompletionResult<SuccessResponse>
suspend fun scanCard(
cardId: String? = null,
allowRequestAccessCodeFromRepository: Boolean = false,
): CompletionResult<CardDTO> {
return runTaskAsyncReturnOnMain(
runnable = ScanTask(allowRequestAccessCodeFromRepository),
cardId = cardId,
initialMessage = Message(resources.getString(R.string.initial_message_tap_header)),
)
.map { CardDTO(it) }
}
): CompletionResult<CardDTO>
suspend fun <T> runTaskAsync(
runnable: CardSessionRunnable<T>,
@ -235,53 +86,13 @@ class TangemSdkManager(
initialMessage: Message? = null,
accessCode: String? = null,
@DrawableRes iconScanRes: Int? = null,
): CompletionResult<T> = withContext(Dispatchers.Main) {
suspendCancellableCoroutine { continuation ->
tangemSdk.startSessionWithRunnable(runnable, cardId, initialMessage, accessCode, iconScanRes) { result ->
if (continuation.isActive) continuation.resume(result)
}
}
}
private suspend fun <T> runTaskAsyncReturnOnMain(
runnable: CardSessionRunnable<T>,
cardId: String? = null,
initialMessage: Message? = null,
): CompletionResult<T> {
val result = runTaskAsync(runnable, cardId, initialMessage)
return withContext(Dispatchers.Main) { result }
}
): CompletionResult<T>
@Suppress("MagicNumber")
fun changeDisplayedCardIdNumbersCount(scanResponse: ScanResponse?) {
tangemSdk.config.cardIdDisplayFormat = when {
scanResponse == null -> CardIdDisplayFormat.Full
scanResponse.cardTypesResolver.isTangemTwins() -> CardIdDisplayFormat.LastLuhn(4)
else -> CardIdDisplayFormat.Full
}
}
fun changeDisplayedCardIdNumbersCount(scanResponse: ScanResponse?)
@Deprecated("TangemSdkManager shouldn't returns a string from resources")
fun getString(@StringRes stringResId: Int, vararg formatArgs: Any?): String {
return resources.getString(stringResId, *formatArgs)
}
fun getString(@StringRes stringResId: Int, vararg formatArgs: Any?): String
fun setUserCodeRequestPolicy(policy: UserCodeRequestPolicy) {
tangemSdk.config.userCodeRequestPolicy = policy
}
companion object {
@Deprecated("Use [DefaultCardSdkProvider] instead")
val config = Config(
linkedTerminal = true,
allowUntrustedCards = true,
filter = CardFilter(
allowedCardTypes = FirmwareVersion.FirmwareType.values().toList(),
maxFirmwareVersion = FirmwareVersion(major = 6, minor = 33),
batchIdFilter = CardFilter.Companion.ItemFilter.Deny(
items = setOf("0027", "0030", "0031", "0035"),
),
),
)
}
fun setUserCodeRequestPolicy(policy: UserCodeRequestPolicy)
}

View file

@ -10,7 +10,7 @@ import com.tangem.domain.common.configs.MultiWalletCardConfig
import com.tangem.domain.wallets.models.UserWallet
import com.tangem.domain.wallets.models.UserWalletId
import com.tangem.operations.derivation.DerivationTaskResponse
import com.tangem.tap.domain.TangemSdkManager
import com.tangem.tap.domain.DefaultTangemSdkManager
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
import io.mockk.*
import kotlinx.coroutines.test.runTest
@ -21,7 +21,7 @@ import org.junit.Test
*/
internal class DefaultDerivationsRepositoryTest {
private val tangemSdkManager = mockk<TangemSdkManager>()
private val tangemSdkManager = mockk<DefaultTangemSdkManager>()
private val userWalletsStore = mockk<UserWalletsStore>()
private val repository = DefaultDerivationsRepository(
tangemSdkManager = tangemSdkManager,

View file

@ -53,6 +53,7 @@ dependencies {
/** Chucker */
debugImplementation(deps.chucker)
mockedImplementation(deps.chuckerStub)
externalImplementation(deps.chuckerStub)
internalImplementation(deps.chuckerStub)
releaseImplementation(deps.chuckerStub)

View file

@ -7,6 +7,7 @@ import com.squareup.moshi.JsonClass
[REDACTED_AUTHOR]
*/
// TODO remove
class FeatureModel(
val isTopUpEnabled: Boolean,
val isCreatingTwinCardsAllowed: Boolean,

View file

@ -76,6 +76,7 @@ private fun AndroidBuildType.configureBuildVariant(extension: AppExtension, buil
}
BuildType.Internal,
BuildType.External,
BuildType.Mocked
-> {
initWith(extension.buildTypes.getByName(BuildType.Release.id))
matchingFallbacks.add(BuildType.Release.id)

View file

@ -15,6 +15,7 @@ internal sealed class BuildConfigField(val type: String, val name: String, val v
value = "\"$value\"",
)
// TODO remove
class TestActionEnabled(isEnabled: Boolean) : BuildConfigField(
type = "Boolean",
name = "TEST_ACTION_ENABLED",
@ -32,4 +33,10 @@ internal sealed class BuildConfigField(val type: String, val name: String, val v
name = "TESTER_MENU_ENABLED",
value = isEnabled.toString(),
)
class MockDataSource(isEnabled: Boolean) : BuildConfigField(
type = "Boolean",
name = "MOCK_DATA_SOURCE",
value = isEnabled.toString(),
)
}

View file

@ -27,6 +27,29 @@ internal enum class BuildType(
BuildConfigField.TestActionEnabled(isEnabled = true),
BuildConfigField.LogEnabled(isEnabled = true),
BuildConfigField.TesterMenuAvailability(isEnabled = true),
BuildConfigField.MockDataSource(isEnabled = false),
),
),
/**
* Build type for QA and business
*
* Features:
* - Env: dev
* - Signing config: debug
* - Logs
* - Enabled mocked datasource
* */
Mocked(
id = "mocked",
appIdSuffix = "mocked",
versionSuffix = "mocked",
configFields = listOf(
BuildConfigField.Environment(value = "dev"),
BuildConfigField.TestActionEnabled(isEnabled = false),
BuildConfigField.LogEnabled(isEnabled = true),
BuildConfigField.TesterMenuAvailability(isEnabled = false),
BuildConfigField.MockDataSource(isEnabled = true),
),
),
@ -50,6 +73,7 @@ internal enum class BuildType(
BuildConfigField.TestActionEnabled(isEnabled = true),
BuildConfigField.LogEnabled(isEnabled = true),
BuildConfigField.TesterMenuAvailability(isEnabled = true),
BuildConfigField.MockDataSource(isEnabled = false),
),
),
@ -70,6 +94,7 @@ internal enum class BuildType(
BuildConfigField.TestActionEnabled(isEnabled = false),
BuildConfigField.LogEnabled(isEnabled = false),
BuildConfigField.TesterMenuAvailability(isEnabled = false),
BuildConfigField.MockDataSource(isEnabled = false),
),
),
@ -88,6 +113,7 @@ internal enum class BuildType(
BuildConfigField.TestActionEnabled(isEnabled = false),
BuildConfigField.LogEnabled(isEnabled = false),
BuildConfigField.TesterMenuAvailability(isEnabled = false),
BuildConfigField.MockDataSource(isEnabled = false),
),
),
}