From f43fb6a8ac87db74b445745497ea8020990e694b Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 22 Apr 2026 11:55:20 +0400 Subject: [PATCH] Updated on 2026-08-14 --- .../tangem/tap/data/DefaultAppInfoProvider.kt | 19 +++--- .../tangem/tap/data/DefaultCardSdkProvider.kt | 7 +- .../java/com/tangem/tap/di/UtilsModule.kt | 6 ++ .../network/auth/DefaultAppVersionProvider.kt | 11 --- .../tangem/tap/network/auth/di/AuthModule.kt | 7 -- .../datasource/api/common/config/Express.kt | 5 +- .../api/common/config/GaslessTxService.kt | 4 +- .../datasource/api/common/config/News.kt | 4 +- .../datasource/api/common/config/TangemPay.kt | 14 ++-- .../api/common/config/TangemTech.kt | 4 +- .../api/common/config/YieldSupply.kt | 4 +- .../tangem/datasource/di/ApiConfigsModule.kt | 68 +++++++------------ .../com/tangem/datasource/di/AppInfoModule.kt | 21 ------ .../tangem/datasource/utils/RequestHeader.kt | 10 +-- .../api/common/config/ApiConfigTest.kt | 9 +-- .../managers/ProdApiConfigsManagerTest.kt | 26 +++---- .../com/tangem/utils/info/AppInfoProvider.kt | 33 +++++++++ .../utils/version/AppVersionProvider.kt | 8 --- .../feedback/DefaultFeedbackRepository.kt | 13 ++-- .../tangem/data/feedback/di/FeedbackModule.kt | 6 +- .../features/details/model/DetailsModel.kt | 6 +- .../ExcludedBlockchainsViewModel.kt | 6 +- .../viewmodels/FeatureTogglesViewModel.kt | 8 +-- 23 files changed, 122 insertions(+), 177 deletions(-) rename core/datasource/src/main/java/com/tangem/datasource/info/AndroidAppInfoProvider.kt => app/src/main/java/com/tangem/tap/data/DefaultAppInfoProvider.kt (57%) delete mode 100644 app/src/main/java/com/tangem/tap/network/auth/DefaultAppVersionProvider.kt delete mode 100644 core/datasource/src/main/java/com/tangem/datasource/di/AppInfoModule.kt delete mode 100644 core/utils/src/main/java/com/tangem/utils/version/AppVersionProvider.kt diff --git a/core/datasource/src/main/java/com/tangem/datasource/info/AndroidAppInfoProvider.kt b/app/src/main/java/com/tangem/tap/data/DefaultAppInfoProvider.kt similarity index 57% rename from core/datasource/src/main/java/com/tangem/datasource/info/AndroidAppInfoProvider.kt rename to app/src/main/java/com/tangem/tap/data/DefaultAppInfoProvider.kt index d33089ff1b..69194e58e1 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/info/AndroidAppInfoProvider.kt +++ b/app/src/main/java/com/tangem/tap/data/DefaultAppInfoProvider.kt @@ -1,26 +1,27 @@ -package com.tangem.datasource.info +package com.tangem.tap.data import android.os.Build import com.tangem.utils.info.AppInfoProvider -import com.tangem.utils.version.AppVersionProvider -import java.util.* +import com.tangem.wallet.BuildConfig +import java.util.Locale +import java.util.TimeZone import javax.inject.Inject -internal class AndroidAppInfoProvider @Inject constructor( - private val appVersionProvider: AppVersionProvider, -) : AppInfoProvider { +internal class DefaultAppInfoProvider @Inject constructor() : AppInfoProvider { override val platform: String get() = "Android" override val device: String get() = "${Build.MANUFACTURER} ${Build.MODEL}" override val osVersion: String get() = Build.VERSION.RELEASE + override val sdkVersion: Int + get() = Build.VERSION.SDK_INT override val language: String - get() = Locale.getDefault().language + get() = Locale.getDefault().toLanguageTag() override val timezone: String get() = TimeZone.getDefault().id - override val appVersion: String - get() = appVersionProvider.versionName + override val appVersion: String = BuildConfig.VERSION_NAME + override val appVersionCode: Int = BuildConfig.VERSION_CODE override val isHuaweiDevice: Boolean get() = Build.MANUFACTURER.equals("HUAWEI", ignoreCase = true) || Build.BRAND.equals("HUAWEI", ignoreCase = true) diff --git a/app/src/main/java/com/tangem/tap/data/DefaultCardSdkProvider.kt b/app/src/main/java/com/tangem/tap/data/DefaultCardSdkProvider.kt index 9918edc9f1..41ed151c3f 100644 --- a/app/src/main/java/com/tangem/tap/data/DefaultCardSdkProvider.kt +++ b/app/src/main/java/com/tangem/tap/data/DefaultCardSdkProvider.kt @@ -32,7 +32,6 @@ import com.tangem.tap.foregroundActivityObserver import com.tangem.utils.Provider import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.info.AppInfoProvider -import com.tangem.utils.version.AppVersionProvider import kotlinx.coroutines.runBlocking import javax.inject.Inject import javax.inject.Singleton @@ -48,7 +47,6 @@ internal class DefaultCardSdkProvider @Inject constructor( private val analyticsExceptionHandler: AnalyticsExceptionHandler, private val dispatchers: CoroutineDispatcherProvider, private val apiConfigsManager: ApiConfigsManager, - appVersionProvider: AppVersionProvider, appInfoProvider: AppInfoProvider, authProvider: AuthProvider, ) : CardSdkProvider, CardSdkOwner { @@ -74,10 +72,7 @@ internal class DefaultCardSdkProvider @Inject constructor( val apiEnvironment = Provider { apiConfigsManager.getEnvironmentConfig(ApiConfig.ID.TangemTech).environment } - val platformHeaders = RequestHeader.AppVersionPlatformHeaders( - appVersionProvider = appVersionProvider, - appInfoProvider = appInfoProvider, - ) + val platformHeaders = RequestHeader.AppVersionPlatformHeaders(appInfoProvider) val apiKeyHeader = RequestHeader.TangemApiKeyHeader(authProvider, apiEnvironment) TangemApiServiceSettings.addInterceptors( AddHeadersInterceptor(platformHeaders.values + apiKeyHeader.values), diff --git a/app/src/main/java/com/tangem/tap/di/UtilsModule.kt b/app/src/main/java/com/tangem/tap/di/UtilsModule.kt index 0021307180..492904d18a 100644 --- a/app/src/main/java/com/tangem/tap/di/UtilsModule.kt +++ b/app/src/main/java/com/tangem/tap/di/UtilsModule.kt @@ -13,6 +13,8 @@ import com.tangem.tap.common.settings.IntentSettingsManager import com.tangem.tap.common.share.IntentShareManager import com.tangem.tap.common.url.CustomTabsUrlOpener import com.tangem.tap.core.DefaultAppCoroutineScope +import com.tangem.tap.data.DefaultAppInfoProvider +import com.tangem.utils.info.AppInfoProvider import dagger.Binds import dagger.Module import dagger.Provides @@ -28,6 +30,10 @@ internal interface UtilsModule { @Binds fun provideAppScope(defaultAppScope: DefaultAppCoroutineScope): AppCoroutineScope + @Binds + @Singleton + fun bindAppInfoProvider(impl: DefaultAppInfoProvider): AppInfoProvider + companion object { @Provides diff --git a/app/src/main/java/com/tangem/tap/network/auth/DefaultAppVersionProvider.kt b/app/src/main/java/com/tangem/tap/network/auth/DefaultAppVersionProvider.kt deleted file mode 100644 index a5093725e5..0000000000 --- a/app/src/main/java/com/tangem/tap/network/auth/DefaultAppVersionProvider.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.tangem.tap.network.auth - -import com.tangem.utils.version.AppVersionProvider -import com.tangem.wallet.BuildConfig - -internal class DefaultAppVersionProvider : AppVersionProvider { - - override val versionName: String = BuildConfig.VERSION_NAME - - override val versionCode: Int = BuildConfig.VERSION_CODE -} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt b/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt index 6ef9e06f96..6313d30db9 100644 --- a/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt +++ b/app/src/main/java/com/tangem/tap/network/auth/di/AuthModule.kt @@ -7,7 +7,6 @@ import com.tangem.lib.auth.ExpressAuthProvider import com.tangem.lib.auth.P2PEthPoolAuthProvider import com.tangem.lib.auth.StakeKitAuthProvider import com.tangem.tap.network.auth.* -import com.tangem.utils.version.AppVersionProvider import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -47,10 +46,4 @@ internal class AuthModule { fun provideP2PEthPoolAuthProvider(environmentConfig: EnvironmentConfig): P2PEthPoolAuthProvider { return DefaultP2PEthPoolAuthProvider(environmentConfig) } - - @Provides - @Singleton - fun provideAppVersionProvider(): AppVersionProvider { - return DefaultAppVersionProvider() - } } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/Express.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/Express.kt index 3cf8112a90..b0c61cbfc6 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/Express.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/Express.kt @@ -6,20 +6,17 @@ import com.tangem.datasource.utils.RequestHeader import com.tangem.lib.auth.ExpressAuthProvider import com.tangem.utils.ProviderSuspend import com.tangem.utils.info.AppInfoProvider -import com.tangem.utils.version.AppVersionProvider /** * Express [ApiConfig] * * @property environmentConfig environment config * @property expressAuthProvider express auth provider - * @property appVersionProvider app version provider * @property appInfoProvider app info provider */ internal class Express( private val environmentConfig: EnvironmentConfig, private val expressAuthProvider: ExpressAuthProvider, - private val appVersionProvider: AppVersionProvider, private val appInfoProvider: AppInfoProvider, ) : ApiConfig() { @@ -102,7 +99,7 @@ internal class Express( private fun createHeaders(isProd: Boolean) = buildMap { put(key = "api-key", value = ProviderSuspend { getApiKey(isProd) }) put(key = "session-id", value = ProviderSuspend(expressAuthProvider::getSessionId)) - putAll(from = RequestHeader.AppVersionPlatformHeaders(appVersionProvider, appInfoProvider).values) + putAll(from = RequestHeader.AppVersionPlatformHeaders(appInfoProvider).values) } private fun getApiKey(isProd: Boolean): String { diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/GaslessTxService.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/GaslessTxService.kt index 35935f0c9d..111d593100 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/GaslessTxService.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/GaslessTxService.kt @@ -6,14 +6,12 @@ import com.tangem.datasource.utils.RequestHeader import com.tangem.utils.Provider import com.tangem.utils.ProviderSuspend import com.tangem.utils.info.AppInfoProvider -import com.tangem.utils.version.AppVersionProvider /** * Gasless transactions [ApiConfig] */ internal class GaslessTxService( private val authProvider: AuthProvider, - private val appVersionProvider: AppVersionProvider, private val appInfoProvider: AppInfoProvider, ) : ApiConfig() { @@ -50,7 +48,7 @@ internal class GaslessTxService( ) private fun createHeaders(environment: ApiEnvironment) = buildMap { - putAll(RequestHeader.AppVersionPlatformHeaders(appVersionProvider, appInfoProvider).values) + putAll(RequestHeader.AppVersionPlatformHeaders(appInfoProvider).values) put( key = "Authorization", value = ProviderSuspend { diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/News.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/News.kt index 26b8b74472..8e4138d515 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/News.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/News.kt @@ -5,14 +5,12 @@ import com.tangem.datasource.api.common.AuthProvider import com.tangem.datasource.utils.RequestHeader import com.tangem.utils.Provider import com.tangem.utils.info.AppInfoProvider -import com.tangem.utils.version.AppVersionProvider /** * News [ApiConfig] [REDACTED_AUTHOR] */ internal class News( - private val appVersionProvider: AppVersionProvider, private val appInfoProvider: AppInfoProvider, private val authProvider: AuthProvider, ) : ApiConfig() { @@ -64,7 +62,7 @@ internal class News( apiEnvironment = Provider { environment }, ).values, ) - putAll(from = RequestHeader.AppVersionPlatformHeaders(appVersionProvider, appInfoProvider).values) + putAll(from = RequestHeader.AppVersionPlatformHeaders(appInfoProvider).values) } private companion object { diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemPay.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemPay.kt index f6c8752c2d..a7dd87e4db 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemPay.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemPay.kt @@ -3,11 +3,11 @@ package com.tangem.datasource.api.common.config import com.tangem.datasource.BuildConfig import com.tangem.datasource.local.config.environment.EnvironmentConfig import com.tangem.utils.ProviderSuspend -import com.tangem.utils.version.AppVersionProvider +import com.tangem.utils.info.AppInfoProvider internal sealed class TangemPay( private val environmentConfig: EnvironmentConfig, - private val appVersionProvider: AppVersionProvider, + private val appInfoProvider: AppInfoProvider, ) : ApiConfig() { override val defaultEnvironment: ApiEnvironment = getInitialEnvironment() @@ -52,7 +52,7 @@ internal sealed class TangemPay( ) private fun createHeaders(apiEnvironment: ApiEnvironment) = mapOf( - "version" to ProviderSuspend { appVersionProvider.versionName }, + "version" to ProviderSuspend { appInfoProvider.appVersion }, "platform" to ProviderSuspend { "Android" }, "X-API-KEY" to ProviderSuspend { getBffStaticToken(apiEnvironment) }, ) @@ -74,8 +74,8 @@ internal sealed class TangemPay( class Bff( environmentConfig: EnvironmentConfig, - appVersionProvider: AppVersionProvider, - ) : TangemPay(environmentConfig, appVersionProvider) { + appInfoProvider: AppInfoProvider, + ) : TangemPay(environmentConfig, appInfoProvider) { override fun getBaseUrl(apiEnvironment: ApiEnvironment): String { return when (apiEnvironment) { ApiEnvironment.DEV -> "https://api.dev.us.paera.com/bff-v2/" @@ -93,8 +93,8 @@ internal sealed class TangemPay( class Auth( environmentConfig: EnvironmentConfig, - appVersionProvider: AppVersionProvider, - ) : TangemPay(environmentConfig, appVersionProvider) { + appInfoProvider: AppInfoProvider, + ) : TangemPay(environmentConfig, appInfoProvider) { override fun getBaseUrl(apiEnvironment: ApiEnvironment): String { return when (apiEnvironment) { ApiEnvironment.DEV -> "https://api.dev.us.paera.com/" diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemTech.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemTech.kt index 96ef551d23..9500ec26e3 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemTech.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemTech.kt @@ -5,11 +5,9 @@ import com.tangem.datasource.api.common.AuthProvider import com.tangem.datasource.utils.RequestHeader import com.tangem.utils.Provider import com.tangem.utils.info.AppInfoProvider -import com.tangem.utils.version.AppVersionProvider /** TangemTech [ApiConfig] */ internal class TangemTech( - private val appVersionProvider: AppVersionProvider, private val authProvider: AuthProvider, private val appInfoProvider: AppInfoProvider, ) : ApiConfig() { @@ -62,7 +60,7 @@ internal class TangemTech( private fun createHeaders(apiEnvironment: ApiEnvironment) = buildMap { putAll(from = RequestHeader.TangemApiKeyHeader(authProvider, Provider { apiEnvironment }).values) - putAll(from = RequestHeader.AppVersionPlatformHeaders(appVersionProvider, appInfoProvider).values) + putAll(from = RequestHeader.AppVersionPlatformHeaders(appInfoProvider).values) putAll(from = RequestHeader.AuthenticationHeader(authProvider).values) } } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/YieldSupply.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/YieldSupply.kt index 4964259c7d..6b8f203c1d 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/YieldSupply.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/YieldSupply.kt @@ -6,12 +6,10 @@ import com.tangem.datasource.local.config.environment.EnvironmentConfig import com.tangem.datasource.utils.RequestHeader import com.tangem.utils.ProviderSuspend import com.tangem.utils.info.AppInfoProvider -import com.tangem.utils.version.AppVersionProvider /** YieldSupply [ApiConfig] */ internal class YieldSupply( private val environmentConfig: EnvironmentConfig, - private val appVersionProvider: AppVersionProvider, private val authProvider: AuthProvider, private val appInfoProvider: AppInfoProvider, ) : ApiConfig() { @@ -66,7 +64,7 @@ internal class YieldSupply( put(key = "api-key", value = ProviderSuspend { getApiKey(apiEnvironment) }) - putAll(from = RequestHeader.AppVersionPlatformHeaders(appVersionProvider, appInfoProvider).values) + putAll(from = RequestHeader.AppVersionPlatformHeaders(appInfoProvider).values) putAll(from = RequestHeader.AuthenticationHeader(authProvider).values) } diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/ApiConfigsModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/ApiConfigsModule.kt index e8db8ec219..e341d9724b 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/di/ApiConfigsModule.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/di/ApiConfigsModule.kt @@ -7,7 +7,6 @@ import com.tangem.lib.auth.ExpressAuthProvider import com.tangem.lib.auth.P2PEthPoolAuthProvider import com.tangem.lib.auth.StakeKitAuthProvider import com.tangem.utils.info.AppInfoProvider -import com.tangem.utils.version.AppVersionProvider import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -23,13 +22,11 @@ internal object ApiConfigsModule { fun provideExpressConfig( environmentConfig: EnvironmentConfig, expressAuthProvider: ExpressAuthProvider, - appVersionProvider: AppVersionProvider, appInfoProvider: AppInfoProvider, ): ApiConfig { return Express( environmentConfig = environmentConfig, expressAuthProvider = expressAuthProvider, - appVersionProvider = appVersionProvider, appInfoProvider = appInfoProvider, ) } @@ -48,55 +45,47 @@ internal object ApiConfigsModule { @Provides @IntoSet - fun provideTangemTechConfig( - appVersionProvider: AppVersionProvider, - authProvider: AuthProvider, - appInfoProvider: AppInfoProvider, - ): ApiConfig = TangemTech( - appVersionProvider = appVersionProvider, - authProvider = authProvider, - appInfoProvider = appInfoProvider, - ) + fun provideTangemTechConfig(authProvider: AuthProvider, appInfoProvider: AppInfoProvider): ApiConfig { + return TangemTech( + authProvider = authProvider, + appInfoProvider = appInfoProvider, + ) + } @Provides @IntoSet - fun provideNewsConfig( - appVersionProvider: AppVersionProvider, - authProvider: AuthProvider, - appInfoProvider: AppInfoProvider, - ): ApiConfig = News( - appVersionProvider = appVersionProvider, - appInfoProvider = appInfoProvider, - authProvider = authProvider, - ) + fun provideNewsConfig(authProvider: AuthProvider, appInfoProvider: AppInfoProvider): ApiConfig { + return News( + appInfoProvider = appInfoProvider, + authProvider = authProvider, + ) + } @Provides @IntoSet fun provideYieldSupplyConfig( environmentConfig: EnvironmentConfig, - appVersionProvider: AppVersionProvider, authProvider: AuthProvider, appInfoProvider: AppInfoProvider, - ): ApiConfig = YieldSupply( - environmentConfig = environmentConfig, - appVersionProvider = appVersionProvider, - authProvider = authProvider, - appInfoProvider = appInfoProvider, - ) + ): ApiConfig { + return YieldSupply( + environmentConfig = environmentConfig, + authProvider = authProvider, + appInfoProvider = appInfoProvider, + ) + } @Provides @IntoSet - fun provideTangemPayBffConfig( - environmentConfig: EnvironmentConfig, - appVersionProvider: AppVersionProvider, - ): ApiConfig = TangemPay.Bff(environmentConfig, appVersionProvider) + fun provideTangemPayBffConfig(environmentConfig: EnvironmentConfig, appInfoProvider: AppInfoProvider): ApiConfig { + return TangemPay.Bff(environmentConfig, appInfoProvider) + } @Provides @IntoSet - fun provideTangemPayAuthConfig( - environmentConfig: EnvironmentConfig, - appVersionProvider: AppVersionProvider, - ): ApiConfig = TangemPay.Auth(environmentConfig, appVersionProvider) + fun provideTangemPayAuthConfig(environmentConfig: EnvironmentConfig, appInfoProvider: AppInfoProvider): ApiConfig { + return TangemPay.Auth(environmentConfig, appInfoProvider) + } @Provides @IntoSet @@ -112,14 +101,9 @@ internal object ApiConfigsModule { @Provides @IntoSet - fun provideGaslessServiceConfig( - appVersionProvider: AppVersionProvider, - authProvider: AuthProvider, - appInfoProvider: AppInfoProvider, - ): ApiConfig { + fun provideGaslessServiceConfig(authProvider: AuthProvider, appInfoProvider: AppInfoProvider): ApiConfig { return GaslessTxService( authProvider = authProvider, - appVersionProvider = appVersionProvider, appInfoProvider = appInfoProvider, ) } diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/AppInfoModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/AppInfoModule.kt deleted file mode 100644 index c67a5baa1f..0000000000 --- a/core/datasource/src/main/java/com/tangem/datasource/di/AppInfoModule.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.tangem.datasource.di - -import com.tangem.datasource.info.AndroidAppInfoProvider -import com.tangem.utils.info.AppInfoProvider -import com.tangem.utils.version.AppVersionProvider -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import javax.inject.Singleton - -@Module -@InstallIn(SingletonComponent::class) -internal object AppInfoModule { - - @Singleton - @Provides - fun provideAppInfoProvider(appVersionProvider: AppVersionProvider): AppInfoProvider { - return AndroidAppInfoProvider(appVersionProvider) - } -} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/utils/RequestHeader.kt b/core/datasource/src/main/java/com/tangem/datasource/utils/RequestHeader.kt index ef2b83b6df..821a90cbba 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/utils/RequestHeader.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/utils/RequestHeader.kt @@ -1,14 +1,11 @@ package com.tangem.datasource.utils -import android.os.Build import com.tangem.datasource.api.common.AuthProvider import com.tangem.datasource.api.common.config.ApiEnvironment import com.tangem.datasource.utils.RequestHeader.CacheControlHeader.checkHeaderValueOrEmpty import com.tangem.utils.Provider import com.tangem.utils.ProviderSuspend import com.tangem.utils.info.AppInfoProvider -import com.tangem.utils.version.AppVersionProvider -import java.util.Locale import java.util.TimeZone /** @@ -29,17 +26,16 @@ sealed class RequestHeader(vararg pairs: Pair>) ) class AppVersionPlatformHeaders( - appVersionProvider: AppVersionProvider, appInfoProvider: AppInfoProvider, ) : RequestHeader( "system_version" to ProviderSuspend { appInfoProvider.osVersion }, - "version" to ProviderSuspend { appVersionProvider.versionName }, + "version" to ProviderSuspend { appInfoProvider.appVersion }, "platform" to ProviderSuspend { "android" }, - "language" to ProviderSuspend { Locale.getDefault().language.checkHeaderValueOrEmpty() }, + "language" to ProviderSuspend { appInfoProvider.language.checkHeaderValueOrEmpty() }, "timezone" to ProviderSuspend { TimeZone.getDefault().getDisplayName(false, TimeZone.SHORT).checkHeaderValueOrEmpty() }, - "device" to ProviderSuspend { "${Build.MANUFACTURER} ${Build.MODEL}".checkHeaderValueOrEmpty() }, + "device" to ProviderSuspend { appInfoProvider.device.checkHeaderValueOrEmpty() }, ) /** diff --git a/core/datasource/src/test/kotlin/com/tangem/datasource/api/common/config/ApiConfigTest.kt b/core/datasource/src/test/kotlin/com/tangem/datasource/api/common/config/ApiConfigTest.kt index 1b1693d5a7..2e820ceaac 100644 --- a/core/datasource/src/test/kotlin/com/tangem/datasource/api/common/config/ApiConfigTest.kt +++ b/core/datasource/src/test/kotlin/com/tangem/datasource/api/common/config/ApiConfigTest.kt @@ -51,21 +51,18 @@ class ApiConfigTest { Express( environmentConfig = environmentConfig, expressAuthProvider = mockk(), - appVersionProvider = mockk(), appInfoProvider = mockk(), ) } ApiConfig.ID.YieldSupply -> { YieldSupply( environmentConfig = environmentConfig, - appVersionProvider = mockk(), authProvider = appAuthProvider, appInfoProvider = mockk(), ) } ApiConfig.ID.TangemTech -> { TangemTech( - appVersionProvider = mockk(), authProvider = appAuthProvider, appInfoProvider = mockk(), ) @@ -73,23 +70,21 @@ class ApiConfigTest { ApiConfig.ID.StakeKit -> StakeKit(stakeKitAuthProvider = mockk()) ApiConfig.ID.TangemPay -> TangemPay.Bff( environmentConfig = environmentConfig, - appVersionProvider = mockk(), + appInfoProvider = mockk(), ) ApiConfig.ID.TangemPayAuth -> TangemPay.Auth( environmentConfig = environmentConfig, - appVersionProvider = mockk(), + appInfoProvider = mockk(), ) ApiConfig.ID.BlockAid -> BlockAid(environmentConfig = environmentConfig) ApiConfig.ID.MoonPay -> MoonPay() ApiConfig.ID.P2PEthPool -> P2PEthPool(p2pAuthProvider = mockk()) ApiConfig.ID.News -> News( - appVersionProvider = mockk(), authProvider = appAuthProvider, appInfoProvider = mockk(), ) ApiConfig.ID.GaslessTxService -> GaslessTxService( authProvider = appAuthProvider, - appVersionProvider = mockk(), appInfoProvider = mockk(), ) } diff --git a/core/datasource/src/test/kotlin/com/tangem/datasource/api/common/config/managers/ProdApiConfigsManagerTest.kt b/core/datasource/src/test/kotlin/com/tangem/datasource/api/common/config/managers/ProdApiConfigsManagerTest.kt index becd832cbc..102cfd0da8 100644 --- a/core/datasource/src/test/kotlin/com/tangem/datasource/api/common/config/managers/ProdApiConfigsManagerTest.kt +++ b/core/datasource/src/test/kotlin/com/tangem/datasource/api/common/config/managers/ProdApiConfigsManagerTest.kt @@ -19,7 +19,6 @@ import com.tangem.lib.auth.StakeKitAuthProvider import com.tangem.test.core.ProvideTestModels import com.tangem.utils.ProviderSuspend import com.tangem.utils.info.AppInfoProvider -import com.tangem.utils.version.AppVersionProvider import io.mockk.clearMocks import io.mockk.coEvery import io.mockk.every @@ -38,7 +37,6 @@ import java.util.TimeZone internal class ProdApiConfigsManagerTest { private val environmentConfig = createMockEnvironmentConfig() - private val appVersionProvider = mockk() private val expressAuthProvider = mockk() private val stakeKitAuthProvider = mockk() private val p2pEthPoolAuthProvider = mockk() @@ -52,14 +50,13 @@ internal class ProdApiConfigsManagerTest { @BeforeEach fun setup() { clearMocks( - appVersionProvider, expressAuthProvider, stakeKitAuthProvider, appAuthProvider, appInfoProvider, ) - every { appVersionProvider.versionName } returns VERSION_NAME + every { appInfoProvider.appVersion } returns VERSION_NAME every { expressAuthProvider.getSessionId() } returns EXPRESS_SESSION_ID every { stakeKitAuthProvider.getApiKey() } returns STAKE_KIT_API_KEY every { p2pEthPoolAuthProvider.getApiKey() } returns P2P_API_KEY @@ -71,6 +68,8 @@ internal class ProdApiConfigsManagerTest { coEvery { appAuthProvider.getCardPublicKey() } returns APP_CARD_PUBLIC_KEY every { appInfoProvider.osVersion } returns "Android 16" + every { appInfoProvider.language } returns Locale.getDefault().toLanguageTag() + every { appInfoProvider.device } returns "${Build.MANUFACTURER} ${Build.MODEL}" manager = ProdApiConfigsManager(apiConfigs = createApiConfigs()) } @@ -94,21 +93,18 @@ internal class ProdApiConfigsManagerTest { Express( environmentConfig = environmentConfig, expressAuthProvider = expressAuthProvider, - appVersionProvider = appVersionProvider, appInfoProvider = appInfoProvider, ) } ApiConfig.ID.YieldSupply -> { YieldSupply( environmentConfig = environmentConfig, - appVersionProvider = appVersionProvider, authProvider = appAuthProvider, appInfoProvider = appInfoProvider, ) } ApiConfig.ID.TangemTech -> { TangemTech( - appVersionProvider = appVersionProvider, authProvider = appAuthProvider, appInfoProvider = appInfoProvider, ) @@ -116,23 +112,21 @@ internal class ProdApiConfigsManagerTest { ApiConfig.ID.StakeKit -> StakeKit(stakeKitAuthProvider = stakeKitAuthProvider) ApiConfig.ID.TangemPay -> TangemPay.Bff( environmentConfig = environmentConfig, - appVersionProvider = appVersionProvider, + appInfoProvider = appInfoProvider, ) ApiConfig.ID.TangemPayAuth -> TangemPay.Auth( environmentConfig = environmentConfig, - appVersionProvider = appVersionProvider, + appInfoProvider = appInfoProvider, ) ApiConfig.ID.BlockAid -> BlockAid(environmentConfig = environmentConfig) ApiConfig.ID.MoonPay -> MoonPay() ApiConfig.ID.P2PEthPool -> P2PEthPool(p2pAuthProvider = p2pEthPoolAuthProvider) ApiConfig.ID.News -> News( - appVersionProvider = appVersionProvider, authProvider = appAuthProvider, appInfoProvider = appInfoProvider, ) ApiConfig.ID.GaslessTxService -> GaslessTxService( authProvider = appAuthProvider, - appVersionProvider = appVersionProvider, appInfoProvider = appInfoProvider, ) } @@ -195,7 +189,7 @@ internal class ProdApiConfigsManagerTest { "version" to ProviderSuspend { VERSION_NAME }, "system_version" to ProviderSuspend { "Android 16" }, "platform" to ProviderSuspend { "android" }, - "language" to ProviderSuspend { Locale.getDefault().language.checkHeaderValueOrEmpty() }, + "language" to ProviderSuspend { Locale.getDefault().toLanguageTag().checkHeaderValueOrEmpty() }, "timezone" to ProviderSuspend { TimeZone.getDefault().getDisplayName(false, TimeZone.SHORT).checkHeaderValueOrEmpty() }, @@ -218,7 +212,7 @@ internal class ProdApiConfigsManagerTest { "version" to ProviderSuspend { VERSION_NAME }, "platform" to ProviderSuspend { "android" }, "system_version" to ProviderSuspend { "Android 16" }, - "language" to ProviderSuspend { Locale.getDefault().language.checkHeaderValueOrEmpty() }, + "language" to ProviderSuspend { Locale.getDefault().toLanguageTag().checkHeaderValueOrEmpty() }, "timezone" to ProviderSuspend { TimeZone.getDefault().getDisplayName(false, TimeZone.SHORT).checkHeaderValueOrEmpty() }, @@ -241,7 +235,7 @@ internal class ProdApiConfigsManagerTest { "version" to ProviderSuspend { VERSION_NAME }, "platform" to ProviderSuspend { "android" }, "system_version" to ProviderSuspend { "Android 16" }, - "language" to ProviderSuspend { Locale.getDefault().language.checkHeaderValueOrEmpty() }, + "language" to ProviderSuspend { Locale.getDefault().toLanguageTag().checkHeaderValueOrEmpty() }, "timezone" to ProviderSuspend { TimeZone.getDefault().getDisplayName(false, TimeZone.SHORT).checkHeaderValueOrEmpty() }, @@ -316,7 +310,7 @@ internal class ProdApiConfigsManagerTest { "version" to ProviderSuspend { VERSION_NAME }, "platform" to ProviderSuspend { "android" }, "system_version" to ProviderSuspend { "Android 16" }, - "language" to ProviderSuspend { Locale.getDefault().language.checkHeaderValueOrEmpty() }, + "language" to ProviderSuspend { Locale.getDefault().toLanguageTag().checkHeaderValueOrEmpty() }, "timezone" to ProviderSuspend { TimeZone.getDefault().getDisplayName(false, TimeZone.SHORT).checkHeaderValueOrEmpty() }, @@ -394,7 +388,7 @@ internal class ProdApiConfigsManagerTest { "version" to ProviderSuspend { VERSION_NAME }, "platform" to ProviderSuspend { "android" }, "system_version" to ProviderSuspend { "Android 16" }, - "language" to ProviderSuspend { Locale.getDefault().language.checkHeaderValueOrEmpty() }, + "language" to ProviderSuspend { Locale.getDefault().toLanguageTag().checkHeaderValueOrEmpty() }, "timezone" to ProviderSuspend { TimeZone.getDefault().getDisplayName(false, TimeZone.SHORT).checkHeaderValueOrEmpty() }, diff --git a/core/utils/src/main/java/com/tangem/utils/info/AppInfoProvider.kt b/core/utils/src/main/java/com/tangem/utils/info/AppInfoProvider.kt index 7337a4f114..4ef568d2e6 100644 --- a/core/utils/src/main/java/com/tangem/utils/info/AppInfoProvider.kt +++ b/core/utils/src/main/java/com/tangem/utils/info/AppInfoProvider.kt @@ -1,11 +1,44 @@ package com.tangem.utils.info +/** + * Runtime information about the host application and device. + * + * Consumed by API layers to populate request headers and bodies (see + * `RequestHeader.AppVersionPlatformHeaders` and push-notification registration) and by feature + * code that needs to branch on platform / vendor. + */ interface AppInfoProvider { + + /** Platform identifier, e.g. `"Android"`. */ val platform: String + + /** Human-readable device name in the form `"$MANUFACTURER $MODEL"`, e.g. `"Google Pixel 8"`. */ val device: String + + /** OS release string, e.g. `"14"` on Android 14. Corresponds to `Build.VERSION.RELEASE`. */ val osVersion: String + + /** + * Android API level of the running system, e.g. `34` on Android 14. Corresponds to + * `Build.VERSION.SDK_INT`. Use this (not [osVersion]) when branching by framework capability. + */ + val sdkVersion: Int + + /** Current locale as a BCP 47 language tag (e.g. `"en-US"`, `"zh-CN"`). */ val language: String + + /** IANA time-zone id of the device's current time zone, e.g. `"Europe/Moscow"`, `"UTC"`. */ val timezone: String + + /** User-visible app version string (e.g. `"5.36.4"`), matching `BuildConfig.VERSION_NAME`. */ val appVersion: String + + /** Monotonically-increasing internal build number, matching `BuildConfig.VERSION_CODE`. */ + val appVersionCode: Int + + /** + * `true` if the device manufacturer or brand is Huawei. Used to gate features that depend on + * Google Play Services (HMS-only devices cannot rely on FCM, Play Billing, etc.). + */ val isHuaweiDevice: Boolean } \ No newline at end of file diff --git a/core/utils/src/main/java/com/tangem/utils/version/AppVersionProvider.kt b/core/utils/src/main/java/com/tangem/utils/version/AppVersionProvider.kt deleted file mode 100644 index 23e26bebd1..0000000000 --- a/core/utils/src/main/java/com/tangem/utils/version/AppVersionProvider.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.tangem.utils.version - -interface AppVersionProvider { - - val versionName: String - - val versionCode: Int -} \ No newline at end of file diff --git a/data/feedback/src/main/java/com/tangem/data/feedback/DefaultFeedbackRepository.kt b/data/feedback/src/main/java/com/tangem/data/feedback/DefaultFeedbackRepository.kt index 76ef2e52f0..511dcdc2e5 100644 --- a/data/feedback/src/main/java/com/tangem/data/feedback/DefaultFeedbackRepository.kt +++ b/data/feedback/src/main/java/com/tangem/data/feedback/DefaultFeedbackRepository.kt @@ -1,6 +1,5 @@ package com.tangem.data.feedback -import android.os.Build import com.tangem.blockchainsdk.utils.toBlockchain import com.tangem.core.navigation.email.EmailSender import com.tangem.data.feedback.converters.BlockchainInfoConverter @@ -14,8 +13,8 @@ import com.tangem.domain.models.network.Network import com.tangem.domain.models.scan.ScanResponse import com.tangem.domain.models.wallet.UserWallet import com.tangem.domain.models.wallet.UserWalletId +import com.tangem.utils.info.AppInfoProvider import com.tangem.utils.logging.TangemLogger -import com.tangem.utils.version.AppVersionProvider import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update import java.io.File @@ -27,7 +26,7 @@ import java.io.File * @property userWalletsListRepository repository for getting user wallets * @property walletManagersStore wallet managers store * @property emailSender email sender - * @property appVersionProvider app version provider + * @property appInfoProvider app info provider * [REDACTED_AUTHOR] */ @@ -36,7 +35,7 @@ internal class DefaultFeedbackRepository( private val userWalletsListRepository: UserWalletsListRepository, private val walletManagersStore: WalletManagersStore, private val emailSender: EmailSender, - private val appVersionProvider: AppVersionProvider, + private val appInfoProvider: AppInfoProvider, ) : FeedbackRepository { private val blockchainsErrors = MutableStateFlow>(emptyMap()) @@ -77,9 +76,9 @@ internal class DefaultFeedbackRepository( override fun getPhoneInfo(): PhoneInfo { return PhoneInfo( - phoneModel = Build.MODEL, - osVersion = Build.VERSION.SDK_INT.toString(), - appVersion = appVersionProvider.versionName, + phoneModel = appInfoProvider.device, + osVersion = appInfoProvider.sdkVersion.toString(), + appVersion = appInfoProvider.appVersion, ) } diff --git a/data/feedback/src/main/java/com/tangem/data/feedback/di/FeedbackModule.kt b/data/feedback/src/main/java/com/tangem/data/feedback/di/FeedbackModule.kt index 6d4d9176c1..05133c89d1 100644 --- a/data/feedback/src/main/java/com/tangem/data/feedback/di/FeedbackModule.kt +++ b/data/feedback/src/main/java/com/tangem/data/feedback/di/FeedbackModule.kt @@ -9,7 +9,7 @@ import com.tangem.datasource.local.walletmanager.WalletManagersStore import com.tangem.domain.common.wallets.UserWalletsListRepository import com.tangem.domain.feedback.repository.FeedbackFeatureToggles import com.tangem.domain.feedback.repository.FeedbackRepository -import com.tangem.utils.version.AppVersionProvider +import com.tangem.utils.info.AppInfoProvider import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -27,13 +27,13 @@ internal object FeedbackModule { userWalletsListRepository: UserWalletsListRepository, walletManagersStore: WalletManagersStore, emailSender: EmailSender, - appVersionProvider: AppVersionProvider, + appInfoProvider: AppInfoProvider, ): FeedbackRepository { return DefaultFeedbackRepository( appLogsStore = appLogsStore, walletManagersStore = walletManagersStore, emailSender = emailSender, - appVersionProvider = appVersionProvider, + appInfoProvider = appInfoProvider, userWalletsListRepository = userWalletsListRepository, ) } diff --git a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt index e501fd3751..394aa04245 100644 --- a/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt +++ b/features/details/impl/src/main/kotlin/com/tangem/features/details/model/DetailsModel.kt @@ -36,7 +36,7 @@ import com.tangem.features.details.entity.SelectEmailFeedbackTypeBS import com.tangem.features.details.utils.ItemsBuilder import com.tangem.features.details.utils.SocialsBuilder import com.tangem.utils.coroutines.CoroutineDispatcherProvider -import com.tangem.utils.version.AppVersionProvider +import com.tangem.utils.info.AppInfoProvider import kotlinx.collections.immutable.ImmutableList import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.launchIn @@ -54,7 +54,7 @@ internal class DetailsModel @Inject constructor( paramsContainer: ParamsContainer, feedbackFeatureToggles: FeedbackFeatureToggles, private val itemsBuilder: ItemsBuilder, - private val appVersionProvider: AppVersionProvider, + private val appInfoProvider: AppInfoProvider, private val checkIsWalletConnectAvailableUseCase: CheckIsWalletConnectAvailableUseCase, private val router: Router, private val urlOpener: UrlOpener, @@ -269,7 +269,7 @@ internal class DetailsModel @Inject constructor( } } - private fun getAppVersion(): String = "${appVersionProvider.versionName} (${appVersionProvider.versionCode})" + private fun getAppVersion(): String = "${appInfoProvider.appVersion} (${appInfoProvider.appVersionCode})" private companion object { val SYSTEM_LANGUAGE = runCatching { Resources.getSystem().configuration.locales[0].language }.getOrElse { "" } diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/excludedblockchains/ExcludedBlockchainsViewModel.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/excludedblockchains/ExcludedBlockchainsViewModel.kt index 3c2015978a..42f614a97d 100644 --- a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/excludedblockchains/ExcludedBlockchainsViewModel.kt +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/excludedblockchains/ExcludedBlockchainsViewModel.kt @@ -13,7 +13,7 @@ import com.tangem.feature.tester.presentation.excludedblockchains.state.Blockcha import com.tangem.feature.tester.presentation.excludedblockchains.state.ExcludedBlockchainsScreenUM import com.tangem.feature.tester.presentation.excludedblockchains.state.mapper.toUiModels import com.tangem.feature.tester.presentation.navigation.InnerTesterRouter -import com.tangem.utils.version.AppVersionProvider +import com.tangem.utils.info.AppInfoProvider import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.mutate @@ -25,7 +25,7 @@ import javax.inject.Inject @HiltViewModel internal class ExcludedBlockchainsViewModel @Inject constructor( - private val appVersionProvider: AppVersionProvider, + private val appInfoProvider: AppInfoProvider, excludedBlockchainsManager: ExcludedBlockchainsManager, ) : ViewModel() { @@ -56,7 +56,7 @@ internal class ExcludedBlockchainsViewModel @Inject constructor( search = getInitialSearchBar(), blockchains = getBlockchains(), showRecoverWarning = !excludedBlockchainsManager.isMatchLocalConfig(), - appVersion = appVersionProvider.versionName, + appVersion = appInfoProvider.appVersion, onRestartClick = {}, onRecoverClick = ::recoverLocalConfig, ) diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/featuretoggles/viewmodels/FeatureTogglesViewModel.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/featuretoggles/viewmodels/FeatureTogglesViewModel.kt index 95338c3250..130a27e2ff 100644 --- a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/featuretoggles/viewmodels/FeatureTogglesViewModel.kt +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/featuretoggles/viewmodels/FeatureTogglesViewModel.kt @@ -13,7 +13,7 @@ import com.tangem.feature.tester.presentation.common.components.appbar.TopBarWit import com.tangem.feature.tester.presentation.featuretoggles.models.TesterFeatureToggle import com.tangem.feature.tester.presentation.featuretoggles.state.FeatureTogglesContentState import com.tangem.feature.tester.presentation.navigation.InnerTesterRouter -import com.tangem.utils.version.AppVersionProvider +import com.tangem.utils.info.AppInfoProvider import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList @@ -25,14 +25,14 @@ import javax.inject.Inject * ViewModel for screen with list of feature toggles * * @property featureTogglesManager manager for getting information about the availability of feature toggles - * @property appVersionProvider app version provider + * @property appInfoProvider app info provider * [REDACTED_AUTHOR] */ @HiltViewModel internal class FeatureTogglesViewModel @Inject constructor( private val featureTogglesManager: FeatureTogglesManager, - private val appVersionProvider: AppVersionProvider, + private val appInfoProvider: AppInfoProvider, ) : ViewModel() { /** Current ui state */ @@ -55,7 +55,7 @@ internal class FeatureTogglesViewModel @Inject constructor( private fun initState(): FeatureTogglesContentState { return FeatureTogglesContentState( topBar = getConfigSetupState(isPrimarySetup = true), - appVersion = appVersionProvider.versionName, + appVersion = appInfoProvider.appVersion, featureToggles = mutableFeatureTogglesManager.getTesterFeatureToggles(), onToggleValueChange = ::onToggleValueChange, onRestartAppClick = {},