diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 0e20e4fbdc..fdf34a9da6 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -219,6 +219,7 @@ dependencies { /** Chucker */ debugImplementation(deps.chucker) + mockedImplementation(deps.chuckerStub) externalImplementation(deps.chuckerStub) internalImplementation(deps.chuckerStub) releaseImplementation(deps.chuckerStub) diff --git a/app/src/main/assets/tangem-app-config b/app/src/main/assets/tangem-app-config index 82f4a8aebc..b098560072 160000 --- a/app/src/main/assets/tangem-app-config +++ b/app/src/main/assets/tangem-app-config @@ -1 +1 @@ -Subproject commit 82f4a8aebcab924047705ad3ecd5f008f07ca0b5 +Subproject commit b0985600722953fae0a93bcbbc2a83930b9e0cbe diff --git a/app/src/main/java/com/tangem/tap/di/ActivityModule.kt b/app/src/main/java/com/tangem/tap/di/ActivityModule.kt index 2ff65f28a2..c9b778f7c3 100644 --- a/app/src/main/java/com/tangem/tap/di/ActivityModule.kt +++ b/app/src/main/java/com/tangem/tap/di/ActivityModule.kt @@ -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 diff --git a/app/src/main/java/com/tangem/tap/domain/DefaultTangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/DefaultTangemSdkManager.kt new file mode 100644 index 0000000000..979f79f1ca --- /dev/null +++ b/app/src/main/java/com/tangem/tap/domain/DefaultTangemSdkManager.kt @@ -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 { + 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 { + 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 { + 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) { + if (result is CompletionResult.Failure) { + (result.error as? TangemSdkError)?.let { error -> + Analytics.send(Basic.ScanError(error)) + } + } + } + + override suspend fun derivePublicKeys( + cardId: String?, + derivations: Map>, + ): CompletionResult { + return runTaskAsyncReturnOnMain(DeriveMultipleWalletPublicKeysTask(derivations), cardId) + } + + override suspend fun deriveExtendedPublicKey( + cardId: String?, + walletPublicKey: ByteArray, + derivation: DerivationPath, + ): CompletionResult = withContext(Dispatchers.Main) { + runTaskAsyncReturnOnMain( + DeriveWalletPublicKeyTask(walletPublicKey, derivation), + cardId, + ) + } + + override suspend fun resetToFactorySettings( + cardId: String, + allowsRequestAccessCodeFromRepository: Boolean, + ): CompletionResult { + 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): CompletionResult { + return userCodeRepository.save( + cardsIds = cardsIds, + userCode = UserCode( + type = UserCodeType.AccessCode, + stringValue = accessCode, + ), + ) + } + + override suspend fun deleteSavedUserCodes(cardsIds: Set): CompletionResult { + return userCodeRepository.delete(cardsIds.toSet()) + } + + override suspend fun clearSavedUserCodes(): CompletionResult { + return userCodeRepository.clear() + } + + override suspend fun setPasscode(cardId: String?): CompletionResult { + return runTaskAsyncReturnOnMain( + SetUserCodeCommand.changePasscode(null), + cardId, + initialMessage = Message(resources.getString(R.string.initial_message_change_passcode_body)), + ) + } + + override suspend fun setAccessCode(cardId: String?): CompletionResult { + 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 { + return runTaskAsyncReturnOnMain( + SetUserCodeCommand.resetUserCodes(), + cardId, + initialMessage = Message(resources.getString(R.string.initial_message_tap_header)), + ) + } + + override suspend fun setAccessCodeRecoveryEnabled( + cardId: String?, + enabled: Boolean, + ): CompletionResult { + return runTaskAsyncReturnOnMain( + SetUserCodeRecoveryAllowedTask(enabled), + cardId, + initialMessage = Message(resources.getString(R.string.initial_message_tap_header)), + ) + } + + override suspend fun scanCard( + cardId: String?, + allowRequestAccessCodeFromRepository: Boolean, + ): CompletionResult { + return runTaskAsyncReturnOnMain( + runnable = ScanTask(allowRequestAccessCodeFromRepository), + cardId = cardId, + initialMessage = Message(resources.getString(R.string.initial_message_tap_header)), + ) + .map { CardDTO(it) } + } + + override suspend fun runTaskAsync( + runnable: CardSessionRunnable, + cardId: String?, + initialMessage: Message?, + accessCode: String?, + @DrawableRes iconScanRes: Int?, + ): CompletionResult = withContext(Dispatchers.Main) { + suspendCancellableCoroutine { continuation -> + tangemSdk.startSessionWithRunnable(runnable, cardId, initialMessage, accessCode, iconScanRes) { result -> + if (continuation.isActive) continuation.resume(result) + } + } + } + + private suspend fun runTaskAsyncReturnOnMain( + runnable: CardSessionRunnable, + cardId: String? = null, + initialMessage: Message? = null, + ): CompletionResult { + 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"), + ), + ), + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/MockTangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/MockTangemSdkManager.kt new file mode 100644 index 0000000000..0981871a0f --- /dev/null +++ b/app/src/main/java/com/tangem/tap/domain/MockTangemSdkManager.kt @@ -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 { + TODO() + } + + override suspend fun createProductWallet( + scanResponse: ScanResponse, + shouldReset: Boolean, + ): CompletionResult { + TODO() + } + + override suspend fun importWallet( + scanResponse: ScanResponse, + mnemonic: String, + passphrase: String?, + shouldReset: Boolean, + ): CompletionResult { + TODO() + } + + override suspend fun derivePublicKeys( + cardId: String?, + derivations: Map>, + ): CompletionResult { + TODO() + } + + override suspend fun deriveExtendedPublicKey( + cardId: String?, + walletPublicKey: ByteArray, + derivation: DerivationPath, + ): CompletionResult { + TODO() + } + + override suspend fun resetToFactorySettings( + cardId: String, + allowsRequestAccessCodeFromRepository: Boolean, + ): CompletionResult { + TODO() + } + + override suspend fun saveAccessCode(accessCode: String, cardsIds: Set): CompletionResult { + TODO() + } + + override suspend fun deleteSavedUserCodes(cardsIds: Set): CompletionResult { + TODO() + } + + override suspend fun clearSavedUserCodes(): CompletionResult { + TODO() + } + + override suspend fun setPasscode(cardId: String?): CompletionResult { + TODO() + } + + override suspend fun setAccessCode(cardId: String?): CompletionResult { + TODO() + } + + override suspend fun setLongTap(cardId: String?): CompletionResult { + TODO() + } + + override suspend fun setAccessCodeRecoveryEnabled( + cardId: String?, + enabled: Boolean, + ): CompletionResult { + TODO() + } + + override suspend fun scanCard( + cardId: String?, + allowRequestAccessCodeFromRepository: Boolean, + ): CompletionResult { + TODO() + } + + override suspend fun runTaskAsync( + runnable: CardSessionRunnable, + cardId: String?, + initialMessage: Message?, + accessCode: String?, + @DrawableRes iconScanRes: Int?, + ): CompletionResult = 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() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt index 4097061289..6df4d03090 100644 --- a/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/TangemSdkManager.kt @@ -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 { - 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 suspend fun createProductWallet( scanResponse: ScanResponse, shouldReset: Boolean = false, - ): CompletionResult { - 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 suspend fun importWallet( scanResponse: ScanResponse, mnemonic: String, passphrase: String?, shouldReset: Boolean, - ): CompletionResult { - 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) { - if (result is CompletionResult.Failure) { - (result.error as? TangemSdkError)?.let { error -> - Analytics.send(Basic.ScanError(error)) - } - } - } + ): CompletionResult suspend fun derivePublicKeys( cardId: String?, derivations: Map>, - ): CompletionResult { - return runTaskAsyncReturnOnMain(DeriveMultipleWalletPublicKeysTask(derivations), cardId) - } + ): CompletionResult suspend fun deriveExtendedPublicKey( cardId: String?, walletPublicKey: ByteArray, derivation: DerivationPath, - ): CompletionResult = withContext(Dispatchers.Main) { - runTaskAsyncReturnOnMain( - DeriveWalletPublicKeyTask(walletPublicKey, derivation), - cardId, - ) - } + ): CompletionResult suspend fun resetToFactorySettings( cardId: String, allowsRequestAccessCodeFromRepository: Boolean, - ): CompletionResult { - return runTaskAsyncReturnOnMain( - runnable = ResetToFactorySettingsTask( - allowsRequestAccessCodeFromRepository = allowsRequestAccessCodeFromRepository, - ), - cardId = cardId, - initialMessage = Message(resources.getString(R.string.card_settings_reset_card_to_factory)), - ) - .map { CardDTO(it) } - } + ): CompletionResult - suspend fun saveAccessCode(accessCode: String, cardsIds: Set): CompletionResult { - return userCodeRepository.save( - cardsIds = cardsIds, - userCode = UserCode( - type = UserCodeType.AccessCode, - stringValue = accessCode, - ), - ) - } + suspend fun saveAccessCode(accessCode: String, cardsIds: Set): CompletionResult - suspend fun deleteSavedUserCodes(cardsIds: Set): CompletionResult { - return userCodeRepository.delete(cardsIds.toSet()) - } + suspend fun deleteSavedUserCodes(cardsIds: Set): CompletionResult - suspend fun clearSavedUserCodes(): CompletionResult { - return userCodeRepository.clear() - } + suspend fun clearSavedUserCodes(): CompletionResult - suspend fun setPasscode(cardId: String?): CompletionResult { - return runTaskAsyncReturnOnMain( - SetUserCodeCommand.changePasscode(null), - cardId, - initialMessage = Message(resources.getString(R.string.initial_message_change_passcode_body)), - ) - } + suspend fun setPasscode(cardId: String?): CompletionResult - suspend fun setAccessCode(cardId: String?): CompletionResult { - return runTaskAsyncReturnOnMain( - SetUserCodeCommand.changeAccessCode(null), - cardId, - initialMessage = Message(resources.getString(R.string.initial_message_change_access_code_body)), - ) - } + suspend fun setAccessCode(cardId: String?): CompletionResult - suspend fun setLongTap(cardId: String?): CompletionResult { - return runTaskAsyncReturnOnMain( - SetUserCodeCommand.resetUserCodes(), - cardId, - initialMessage = Message(resources.getString(R.string.initial_message_tap_header)), - ) - } + suspend fun setLongTap(cardId: String?): CompletionResult - suspend fun setAccessCodeRecoveryEnabled(cardId: String?, enabled: Boolean): CompletionResult { - return runTaskAsyncReturnOnMain( - SetUserCodeRecoveryAllowedTask(enabled), - cardId, - initialMessage = Message(resources.getString(R.string.initial_message_tap_header)), - ) - } + suspend fun setAccessCodeRecoveryEnabled(cardId: String?, enabled: Boolean): CompletionResult suspend fun scanCard( cardId: String? = null, allowRequestAccessCodeFromRepository: Boolean = false, - ): CompletionResult { - return runTaskAsyncReturnOnMain( - runnable = ScanTask(allowRequestAccessCodeFromRepository), - cardId = cardId, - initialMessage = Message(resources.getString(R.string.initial_message_tap_header)), - ) - .map { CardDTO(it) } - } + ): CompletionResult suspend fun runTaskAsync( runnable: CardSessionRunnable, @@ -235,53 +86,13 @@ class TangemSdkManager( initialMessage: Message? = null, accessCode: String? = null, @DrawableRes iconScanRes: Int? = null, - ): CompletionResult = withContext(Dispatchers.Main) { - suspendCancellableCoroutine { continuation -> - tangemSdk.startSessionWithRunnable(runnable, cardId, initialMessage, accessCode, iconScanRes) { result -> - if (continuation.isActive) continuation.resume(result) - } - } - } - - private suspend fun runTaskAsyncReturnOnMain( - runnable: CardSessionRunnable, - cardId: String? = null, - initialMessage: Message? = null, - ): CompletionResult { - val result = runTaskAsync(runnable, cardId, initialMessage) - return withContext(Dispatchers.Main) { result } - } + ): CompletionResult @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) } \ No newline at end of file diff --git a/app/src/test/kotlin/com/tangem/tap/domain/card/DefaultDerivationsRepositoryTest.kt b/app/src/test/kotlin/com/tangem/tap/domain/card/DefaultDerivationsRepositoryTest.kt index b1e1189c8e..a7b0038bf6 100644 --- a/app/src/test/kotlin/com/tangem/tap/domain/card/DefaultDerivationsRepositoryTest.kt +++ b/app/src/test/kotlin/com/tangem/tap/domain/card/DefaultDerivationsRepositoryTest.kt @@ -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() + private val tangemSdkManager = mockk() private val userWalletsStore = mockk() private val repository = DefaultDerivationsRepository( tangemSdkManager = tangemSdkManager, diff --git a/core/datasource/build.gradle.kts b/core/datasource/build.gradle.kts index e4239e40d6..6aff99a356 100644 --- a/core/datasource/build.gradle.kts +++ b/core/datasource/build.gradle.kts @@ -53,6 +53,7 @@ dependencies { /** Chucker */ debugImplementation(deps.chucker) + mockedImplementation(deps.chuckerStub) externalImplementation(deps.chuckerStub) internalImplementation(deps.chuckerStub) releaseImplementation(deps.chuckerStub) diff --git a/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt b/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt index 0e572bd3e5..2a79daad20 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/config/models/JsonModels.kt @@ -7,6 +7,7 @@ import com.squareup.moshi.JsonClass [REDACTED_AUTHOR] */ +// TODO remove class FeatureModel( val isTopUpEnabled: Boolean, val isCreatingTwinCardsAllowed: Boolean, diff --git a/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/extension/AppExtensionConfigurations.kt b/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/extension/AppExtensionConfigurations.kt index f288d89a7d..6975388bc0 100644 --- a/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/extension/AppExtensionConfigurations.kt +++ b/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/configurations/extension/AppExtensionConfigurations.kt @@ -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) diff --git a/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/model/BuildConfigField.kt b/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/model/BuildConfigField.kt index 66437a1de5..17f61ecdd2 100644 --- a/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/model/BuildConfigField.kt +++ b/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/model/BuildConfigField.kt @@ -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(), + ) } \ No newline at end of file diff --git a/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/model/BuildType.kt b/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/model/BuildType.kt index 767e46ba25..53a1c18637 100644 --- a/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/model/BuildType.kt +++ b/plugins/configuration/src/main/kotlin/com/tangem/plugin/configuration/model/BuildType.kt @@ -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), ), ), } \ No newline at end of file