From 1806ddc31d6370c620b766c35683ff56fb96fbd8 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 26 Feb 2026 21:35:53 +0700 Subject: [PATCH] Updated on 2026-08-14 --- .../tap/domain/scanCard/DefaultScanCardProcessor.kt | 4 ++++ .../tap/domain/scanCard/LegacyScanProcessor.kt | 8 +++++++- .../repository/DefaultScanCardRepository.kt | 7 ++++++- .../tap/domain/sdk/impl/DefaultTangemSdkManager.kt | 3 ++- .../tap/domain/sdk/impl/MockTangemSdkManager.kt | 1 + .../repository/DefaultUserWalletsListRepository.kt | 4 +++- .../ui/cardsettings/model/CardSettingsModel.kt | 1 + .../com/tangem/domain/card/ScanCardProcessor.kt | 2 ++ .../com/tangem/domain/card/ScanCardUseCase.kt | 13 +++++++++---- .../domain/card/repository/ScanCardRepository.kt | 6 +++++- .../createwalletstart/CreateWalletStartModel.kt | 1 + .../features/details/utils/UserWalletSaver.kt | 1 + .../tangem/features/home/impl/model/HomeModel.kt | 1 + .../CreateHardwareWalletModel.kt | 1 + .../hotwallet/upgradewallet/UpgradeWalletModel.kt | 2 +- .../features/welcome/impl/model/WelcomeModel.kt | 1 + gradle/tangem_dependencies.toml | 2 +- .../kotlin/com/tangem/sdk/api/TangemSdkManager.kt | 8 ++++++++ 18 files changed, 55 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/DefaultScanCardProcessor.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/DefaultScanCardProcessor.kt index 216af3ca6d..f04b03cef6 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/DefaultScanCardProcessor.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/DefaultScanCardProcessor.kt @@ -20,6 +20,7 @@ internal class DefaultScanCardProcessor( cardId: String?, allowsRequestAccessCodeFromRepository: Boolean, analyticsSource: AnalyticsParam.ScreensSources, + shouldCheckIsAlreadyActivated: Boolean, ): CompletionResult { return if (isNewCardScanningEnabled) { UseCaseScanProcessor.scan(cardId, allowsRequestAccessCodeFromRepository) @@ -28,6 +29,7 @@ internal class DefaultScanCardProcessor( analyticsSource = analyticsSource, cardId = cardId, allowsRequestAccessCodeFromRepository = allowsRequestAccessCodeFromRepository, + shouldCheckIsAlreadyActivated = shouldCheckIsAlreadyActivated, ) } } @@ -35,6 +37,7 @@ internal class DefaultScanCardProcessor( @Suppress("LongParameterList") override suspend fun scan( analyticsSource: AnalyticsParam.ScreensSources, + shouldCheckIsAlreadyActivated: Boolean, cardId: String?, onProgressStateChange: suspend (showProgress: Boolean) -> Unit, onWalletNotCreated: suspend () -> Unit, @@ -56,6 +59,7 @@ internal class DefaultScanCardProcessor( } else { legacyScanProcessor.scan( analyticsSource = analyticsSource, + shouldCheckIsAlreadyActivated = shouldCheckIsAlreadyActivated, cardId = cardId, onProgressStateChange = onProgressStateChange, onWalletNotCreated = onWalletNotCreated, diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt index ad63237780..fd2e386a76 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/LegacyScanProcessor.kt @@ -55,10 +55,12 @@ internal class LegacyScanProcessor @Inject constructor( cardId: String? = null, allowsRequestAccessCodeFromRepository: Boolean = false, analyticsSource: AnalyticsParam.ScreensSources, + shouldCheckIsAlreadyActivated: Boolean, ): CompletionResult { return tangemSdkManager.scanProduct( cardId = cardId, allowsRequestAccessCodeFromRepository = allowsRequestAccessCodeFromRepository, + shouldCheckIsAlreadyActivated = shouldCheckIsAlreadyActivated, ) .doOnFailure { error -> onScanFailure(analyticsSource = analyticsSource, error = error, onFailure = {}, onCancel = {}) @@ -68,6 +70,7 @@ internal class LegacyScanProcessor @Inject constructor( @Suppress("LongParameterList") suspend fun scan( analyticsSource: AnalyticsParam.ScreensSources, + shouldCheckIsAlreadyActivated: Boolean, cardId: String?, onProgressStateChange: suspend (showProgress: Boolean) -> Unit, onWalletNotCreated: suspend () -> Unit, @@ -80,7 +83,10 @@ internal class LegacyScanProcessor @Inject constructor( tangemSdkManager.changeDisplayedCardIdNumbersCount(null) - val result = tangemSdkManager.scanProduct(cardId) + val result = tangemSdkManager.scanProduct( + cardId = cardId, + shouldCheckIsAlreadyActivated = shouldCheckIsAlreadyActivated, + ) val analyticsEvent = Basic.CardWasScanned(analyticsSource) store.dispatchOnMain(GlobalAction.ScanFailsCounter.ChooseBehavior(result, analyticsSource)) diff --git a/app/src/main/java/com/tangem/tap/domain/scanCard/repository/DefaultScanCardRepository.kt b/app/src/main/java/com/tangem/tap/domain/scanCard/repository/DefaultScanCardRepository.kt index 1a4b50cc5a..ecd2cffeb0 100644 --- a/app/src/main/java/com/tangem/tap/domain/scanCard/repository/DefaultScanCardRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/scanCard/repository/DefaultScanCardRepository.kt @@ -13,11 +13,16 @@ internal class DefaultScanCardRepository( private val exceptionConverter = ScanCardExceptionConverter() - override suspend fun scanCard(cardId: String?, allowRequestAccessCodeFromStorage: Boolean): ScanResponse { + override suspend fun scanCard( + cardId: String?, + allowRequestAccessCodeFromStorage: Boolean, + shouldCheckIsAlreadyActivated: Boolean, + ): ScanResponse { return when ( val result = tangemSdkManager.scanProduct( cardId = cardId, allowsRequestAccessCodeFromRepository = allowRequestAccessCodeFromStorage, + shouldCheckIsAlreadyActivated = shouldCheckIsAlreadyActivated, ) ) { is CompletionResult.Success -> result.data diff --git a/app/src/main/java/com/tangem/tap/domain/sdk/impl/DefaultTangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/sdk/impl/DefaultTangemSdkManager.kt index a9c061c5f7..aea6c8a351 100644 --- a/app/src/main/java/com/tangem/tap/domain/sdk/impl/DefaultTangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/sdk/impl/DefaultTangemSdkManager.kt @@ -166,6 +166,7 @@ internal class DefaultTangemSdkManager( cardId: String?, messageRes: Int?, allowsRequestAccessCodeFromRepository: Boolean, + shouldCheckIsAlreadyActivated: Boolean, ): CompletionResult { val message = Message(resources.getStringSafe(messageRes ?: R.string.initial_message_scan_header)) return coroutineScope { @@ -176,7 +177,7 @@ internal class DefaultTangemSdkManager( allowsRequestAccessCodeFromRepository = allowsRequestAccessCodeFromRepository, visaCardScanHandler = visaCardScanHandler, visaCoroutineScope = this, - shouldCheckIsAlreadyActivated = true, + shouldCheckIsAlreadyActivated = shouldCheckIsAlreadyActivated, onboardingV2FeatureToggles = onboardingV2FeatureToggles, ), cardId = cardId, diff --git a/app/src/main/java/com/tangem/tap/domain/sdk/impl/MockTangemSdkManager.kt b/app/src/main/java/com/tangem/tap/domain/sdk/impl/MockTangemSdkManager.kt index 00e4ea971e..c70dc421f4 100644 --- a/app/src/main/java/com/tangem/tap/domain/sdk/impl/MockTangemSdkManager.kt +++ b/app/src/main/java/com/tangem/tap/domain/sdk/impl/MockTangemSdkManager.kt @@ -59,6 +59,7 @@ class MockTangemSdkManager( cardId: String?, messageRes: Int?, allowsRequestAccessCodeFromRepository: Boolean, + shouldCheckIsAlreadyActivated: Boolean, ): CompletionResult { return MockProvider.getScanResponse() } diff --git a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/DefaultUserWalletsListRepository.kt b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/DefaultUserWalletsListRepository.kt index a45ca9387a..c75cbbbed9 100644 --- a/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/DefaultUserWalletsListRepository.kt +++ b/app/src/main/java/com/tangem/tap/domain/userWalletList/repository/DefaultUserWalletsListRepository.kt @@ -296,7 +296,9 @@ internal class DefaultUserWalletsListRepository( } val scanResponse = unlockMethod.scanResponse ?: run { - when (val res = tangemSdkManagerProvider().scanProduct()) { + when (val res = tangemSdkManagerProvider().scanProduct( + shouldCheckIsAlreadyActivated = false, + )) { is CompletionResult.Failure -> raise(UnlockWalletError.UserCancelled) is CompletionResult.Success -> res.data } diff --git a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/model/CardSettingsModel.kt b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/model/CardSettingsModel.kt index 797ef6c056..1d9a6b2f6e 100644 --- a/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/model/CardSettingsModel.kt +++ b/app/src/main/java/com/tangem/tap/features/details/ui/cardsettings/model/CardSettingsModel.kt @@ -107,6 +107,7 @@ internal class CardSettingsModel @Inject constructor( private fun scanCard() = modelScope.launch { scanCardProcessor.scan( analyticsSource = com.tangem.core.analytics.models.AnalyticsParam.ScreensSources.Settings, + shouldCheckIsAlreadyActivated = false, allowsRequestAccessCodeFromRepository = true, ) .doOnSuccess { scanResponse -> diff --git a/domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardProcessor.kt b/domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardProcessor.kt index f7a54bccda..bd97734029 100644 --- a/domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardProcessor.kt +++ b/domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardProcessor.kt @@ -11,10 +11,12 @@ interface ScanCardProcessor { cardId: String? = null, allowsRequestAccessCodeFromRepository: Boolean = false, analyticsSource: AnalyticsParam.ScreensSources, + shouldCheckIsAlreadyActivated: Boolean, ): CompletionResult suspend fun scan( analyticsSource: AnalyticsParam.ScreensSources, + shouldCheckIsAlreadyActivated: Boolean, cardId: String? = null, onProgressStateChange: suspend (showProgress: Boolean) -> Unit = {}, onWalletNotCreated: suspend () -> Unit = {}, diff --git a/domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardUseCase.kt b/domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardUseCase.kt index 04abfb1fce..046e484ec6 100644 --- a/domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardUseCase.kt +++ b/domain/card/src/main/kotlin/com/tangem/domain/card/ScanCardUseCase.kt @@ -49,9 +49,14 @@ class ScanCardUseCase( cardId: String?, allowRequestAccessCodeFromStorage: Boolean, ): Either { - return Either.catch { scanCardRepository.scanCard(cardId, allowRequestAccessCodeFromStorage) } - .mapLeft { e -> - e as? ScanCardException ?: ScanCardException.UnknownException(e) - } + return Either.catch { + scanCardRepository.scanCard( + cardId = cardId, + allowRequestAccessCodeFromStorage = allowRequestAccessCodeFromStorage, + shouldCheckIsAlreadyActivated = true, // TODO use correct when enable NEW_CARD_SCANNING_ENABLED + ) + }.mapLeft { e -> + e as? ScanCardException ?: ScanCardException.UnknownException(e) + } } } \ No newline at end of file diff --git a/domain/card/src/main/kotlin/com/tangem/domain/card/repository/ScanCardRepository.kt b/domain/card/src/main/kotlin/com/tangem/domain/card/repository/ScanCardRepository.kt index 90f2016383..0774f11004 100644 --- a/domain/card/src/main/kotlin/com/tangem/domain/card/repository/ScanCardRepository.kt +++ b/domain/card/src/main/kotlin/com/tangem/domain/card/repository/ScanCardRepository.kt @@ -17,5 +17,9 @@ interface ScanCardRepository { * @return a [ScanResponse] object with the result of the scan. * @throws [ScanCardException] if the scan process fails. */ - suspend fun scanCard(cardId: String?, allowRequestAccessCodeFromStorage: Boolean): ScanResponse + suspend fun scanCard( + cardId: String?, + allowRequestAccessCodeFromStorage: Boolean, + shouldCheckIsAlreadyActivated: Boolean, + ): ScanResponse } \ No newline at end of file diff --git a/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt b/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt index 6e840ea584..ac00b3703e 100644 --- a/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt +++ b/features/create-wallet-start/impl/src/main/kotlin/com/tangem/features/createwalletstart/CreateWalletStartModel.kt @@ -186,6 +186,7 @@ internal class CreateWalletStartModel @Inject constructor( scanCardProcessor.scan( analyticsSource = analyticsSource, + shouldCheckIsAlreadyActivated = true, onProgressStateChange = { showProgress -> if (!showProgress) { delay(HIDE_PROGRESS_DELAY) diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/UserWalletSaver.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/UserWalletSaver.kt index 1db2f97cc0..3e81799932 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/UserWalletSaver.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/utils/UserWalletSaver.kt @@ -120,6 +120,7 @@ internal class UserWalletSaver @Inject constructor( scope.launch { scanCardProcessor.scan( analyticsSource = AnalyticsParam.ScreensSources.Settings, + shouldCheckIsAlreadyActivated = true, onWalletNotCreated = { continuation.resume(Either.Right(null)) }, diff --git a/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/model/HomeModel.kt b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/model/HomeModel.kt index 767f2d00ec..7cb91f3880 100644 --- a/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/model/HomeModel.kt +++ b/features/home/impl/src/main/kotlin/com/tangem/features/home/impl/model/HomeModel.kt @@ -171,6 +171,7 @@ internal class HomeModel @Inject constructor( scanCardProcessor.scan( analyticsSource = analyticsSource, + shouldCheckIsAlreadyActivated = true, onProgressStateChange = { showProgress -> if (!showProgress) { delay(HIDE_PROGRESS_DELAY) diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createhardwarewallet/CreateHardwareWalletModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createhardwarewallet/CreateHardwareWalletModel.kt index 5d32c8952b..49c8bc6351 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createhardwarewallet/CreateHardwareWalletModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/createhardwarewallet/CreateHardwareWalletModel.kt @@ -104,6 +104,7 @@ internal class CreateHardwareWalletModel @Inject constructor( scanCardProcessor.scan( analyticsSource = analyticsSource, + shouldCheckIsAlreadyActivated = true, onProgressStateChange = { showProgress -> if (!showProgress) { delay(HIDE_PROGRESS_DELAY) diff --git a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/UpgradeWalletModel.kt b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/UpgradeWalletModel.kt index c7252d49c4..3d8d7bc0bd 100644 --- a/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/UpgradeWalletModel.kt +++ b/features/hot-wallet/impl/src/main/kotlin/com/tangem/features/hotwallet/upgradewallet/UpgradeWalletModel.kt @@ -115,7 +115,7 @@ internal class UpgradeWalletModel @Inject constructor( ) tangemSdkManager - .scanProduct() + .scanProduct(shouldCheckIsAlreadyActivated = true) .doOnSuccess { scanResponse -> checkIsWalletSuitableToBeUsedAsUpgrade(scanResponse = scanResponse) { delay(DELAY_SDK_DIALOG_CLOSE) diff --git a/features/welcome/impl/src/main/kotlin/com/tangem/features/welcome/impl/model/WelcomeModel.kt b/features/welcome/impl/src/main/kotlin/com/tangem/features/welcome/impl/model/WelcomeModel.kt index 3aa198a9d7..5c16293dd7 100644 --- a/features/welcome/impl/src/main/kotlin/com/tangem/features/welcome/impl/model/WelcomeModel.kt +++ b/features/welcome/impl/src/main/kotlin/com/tangem/features/welcome/impl/model/WelcomeModel.kt @@ -192,6 +192,7 @@ internal class WelcomeModel @Inject constructor( modelScope.launch { scanCardProcessor.scan( analyticsSource = AnalyticsParam.ScreensSources.SignIn, + shouldCheckIsAlreadyActivated = true, onWalletNotCreated = {}, disclaimerWillShow = { router.pop() }, onSuccess = { scanResponse -> diff --git a/gradle/tangem_dependencies.toml b/gradle/tangem_dependencies.toml index 423909e1bc..b1002f2997 100644 --- a/gradle/tangem_dependencies.toml +++ b/gradle/tangem_dependencies.toml @@ -7,7 +7,7 @@ tangemBlockchainSdk = "releases-5.34-1430" #tangemBlockchainSdk = "0.0.1" # Keep it! - used for local builds -tangemCardSdk = "releases-5.34-581" +tangemCardSdk = "releases-5.34-584" #tangemCardSdk = "0.0.1" # Keep it! - used for local builds ^ tangemVico = "2.0.0-alpha.25-tangem12" #tangemVico = "0.0.1" # Keep it! - used for local builds ^ diff --git a/libs/tangem-sdk-api/src/main/kotlin/com/tangem/sdk/api/TangemSdkManager.kt b/libs/tangem-sdk-api/src/main/kotlin/com/tangem/sdk/api/TangemSdkManager.kt index 64016c2cf8..a7697062bd 100644 --- a/libs/tangem-sdk-api/src/main/kotlin/com/tangem/sdk/api/TangemSdkManager.kt +++ b/libs/tangem-sdk-api/src/main/kotlin/com/tangem/sdk/api/TangemSdkManager.kt @@ -45,10 +45,18 @@ interface TangemSdkManager { suspend fun checkNeedEnrollBiometrics(awaitInitialization: Boolean = true): Boolean + /** + * Scans the card and returns [ScanResponse] with the card information. + * If [cardId] is provided, it will try to find the card with this ID in the card reader's range. + * If [allowsRequestAccessCodeFromRepository] is true, it will try to request access code from the repository + * if the card is protected by access code and the access code is not saved in the repository. + * If [shouldCheckIsAlreadyActivated] is true, it will check if the card is already activated and return an error if it is. + */ suspend fun scanProduct( cardId: String? = null, messageRes: Int? = null, allowsRequestAccessCodeFromRepository: Boolean = false, + shouldCheckIsAlreadyActivated: Boolean, ): CompletionResult suspend fun createProductWallet(