Updated on 2026-08-14

This commit is contained in:
Tangem 2025-01-15 16:19:43 +03:00
parent 58d57d7b85
commit 5b02239896
4 changed files with 130 additions and 2 deletions

View file

@ -3,7 +3,10 @@ package com.tangem.tap.features.main
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.tangem.blockchainsdk.BlockchainSDKFactory
import com.tangem.common.keyboard.KeyboardValidator
import com.tangem.core.analytics.Analytics
import com.tangem.core.analytics.api.AnalyticsEventHandler
import com.tangem.core.analytics.models.event.TechAnalyticsEvent
import com.tangem.core.decompose.di.GlobalUiMessageSender
import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.ui.R
@ -44,8 +47,9 @@ internal class MainViewModel @Inject constructor(
private val fetchStakingTokensUseCase: FetchStakingTokensUseCase,
private val apiConfigsManager: ApiConfigsManager,
private val fetchUserCountryUseCase: FetchUserCountryUseCase,
@GlobalUiMessageSender
private val messageSender: UiMessageSender,
@GlobalUiMessageSender private val messageSender: UiMessageSender,
private val keyboardValidator: KeyboardValidator,
private val analyticsEventHandler: AnalyticsEventHandler,
getBalanceHidingSettingsUseCase: GetBalanceHidingSettingsUseCase,
) : ViewModel() {
@ -74,6 +78,8 @@ internal class MainViewModel @Inject constructor(
fetchStakingTokens()
deleteDeprecatedLogsUseCase()
sendKeyboardIdentifierEvent()
}
/** Loading the resources needed to run the application */
@ -252,4 +258,24 @@ internal class MainViewModel @Inject constructor(
private fun onBottomSheetDismissed() {
listenToFlipsUseCase.changeUpdateEnabled(isUpdateEnabled = true)
}
private fun sendKeyboardIdentifierEvent() {
viewModelScope.launch {
val keyboardId = keyboardValidator.getKeyboardId()
if (keyboardId != null) {
Timber.d("Keyboard ID: https://play.google.com/store/apps/details?id=${keyboardId.getPackageName()}")
analyticsEventHandler.send(
event = TechAnalyticsEvent.KeyboardIdentifier(
id = keyboardId.value,
packageName = keyboardId.getPackageName(),
isTrusted = keyboardValidator.validate(id = keyboardId),
),
)
} else {
Timber.e("Unable to get keyboard identifier")
}
}
}
}

View file

@ -1,6 +1,8 @@
plugins {
alias(deps.plugins.android.library)
alias(deps.plugins.kotlin.android)
alias(deps.plugins.kotlin.kapt)
alias(deps.plugins.hilt.android)
id("configuration")
}
@ -25,4 +27,9 @@ dependencies {
implementation(deps.test.junit)
implementation(deps.test.truth)
// region DI
implementation(deps.hilt.android)
kapt(deps.hilt.kapt)
// end
}

View file

@ -0,0 +1,83 @@
package com.tangem.common.keyboard
import android.content.Context
import android.provider.Settings
import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject
import javax.inject.Singleton
/**
* Keyboard validator
*
* @property context application context
*/
@Singleton
class KeyboardValidator @Inject constructor(
@ApplicationContext private val context: Context,
) {
/** Get keyboard identifier [KeyboardID] */
fun getKeyboardId(): KeyboardID? {
val id = Settings.Secure.getString(
this.context.contentResolver,
Settings.Secure.DEFAULT_INPUT_METHOD,
) ?: return null
return KeyboardID(value = id)
}
/** Check if [id] is trusted */
fun validate(id: KeyboardID): Boolean = trustedIdentifiers.contains(id.getPackageName())
/**
* Keyboard identifier
*
* @property value value
*/
@JvmInline
value class KeyboardID(val value: String) {
/** Get package name */
fun getPackageName(): String? = value.split("/").firstOrNull()
}
private companion object {
val trustedIdentifiers = listOf(
// Google
"com.android.inputmethod.latin",
"com.google.android.inputmethod.latin",
"com.google.android.tts",
// Samsung
"com.sec.android.inputmethod.latin",
"com.sec.android.inputmethod/.SamsungVoiceIME",
"com.samsung.android.honeyboard",
// Microsoft
"com.microsoft.SwiftKeyApp",
"com.touchtype.swiftkey",
"com.touchtype.swiftkey.beta",
// HtC
"com.htc.sense.ime.langpack.tger",
// LG
"com.lge.ime",
// Huawei
"com.huawei.ohos.inputmethod",
// Third party
"com.menny.android.anysoftkeyboard",
"ch.icoaching.wrio",
"rkr.simplekeyboard.inputmethod",
"keepass2android.keepass2android",
"keepass2android.keepass2android_nonet",
"com.softwarevalencia.openboard.inputmethod.latin",
"kl.ime.oh",
"com.syntellia.fleksy.keyboard",
"org.pocketworkstation.pckeyboard",
)
}
}

View file

@ -23,4 +23,16 @@ sealed class TechAnalyticsEvent(
FULLY,
}
}
class KeyboardIdentifier(id: String, packageName: String?, isTrusted: Boolean) : TechAnalyticsEvent(
event = "Keyboard Identifier",
params = buildMap {
put("Id", id)
packageName?.let {
put("Package", it)
put("GPUrl", "https://play.google.com/store/apps/details?id=$packageName")
}
put("isTrusted", isTrusted.toString())
},
)
}