diff --git a/app/src/main/java/com/tangem/tap/ForegroundActivityObserver.kt b/app/src/main/java/com/tangem/tap/ForegroundActivityObserver.kt index ecfb707001..f459c74e77 100644 --- a/app/src/main/java/com/tangem/tap/ForegroundActivityObserver.kt +++ b/app/src/main/java/com/tangem/tap/ForegroundActivityObserver.kt @@ -7,16 +7,16 @@ import android.os.Bundle import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity -import java.util.* +import java.util.WeakHashMap import kotlin.reflect.KClass class ForegroundActivityObserver : ActivityResultCaller { override var activityResultLauncher: ActivityResultLauncher? = null private set - private val activities = WeakHashMap, Activity>() + private val activities = WeakHashMap, AppCompatActivity>() - val foregroundActivity: Activity? + val foregroundActivity: AppCompatActivity? get() = activities.entries .filterNot { it.value.isDestroyed } .firstOrNull() @@ -35,7 +35,7 @@ class ForegroundActivityObserver : ActivityResultCaller { } override fun onActivityResumed(activity: Activity) { - activities[activity::class] = activity + activities[activity::class] = activity as? AppCompatActivity } override fun onActivityDestroyed(activity: Activity) { @@ -59,6 +59,6 @@ class ForegroundActivityObserver : ActivityResultCaller { } } -fun ForegroundActivityObserver.withForegroundActivity(block: (Activity) -> Unit) { +fun ForegroundActivityObserver.withForegroundActivity(block: (AppCompatActivity) -> Unit) { foregroundActivity?.let { block(it) } } \ No newline at end of file diff --git a/data/card/src/main/java/com/tangem/data/card/sdk/DefaultCardSdkProvider.kt b/app/src/main/java/com/tangem/tap/data/DefaultCardSdkProvider.kt similarity index 63% rename from data/card/src/main/java/com/tangem/data/card/sdk/DefaultCardSdkProvider.kt rename to app/src/main/java/com/tangem/tap/data/DefaultCardSdkProvider.kt index cdc3c2e305..a164e0dde1 100644 --- a/data/card/src/main/java/com/tangem/data/card/sdk/DefaultCardSdkProvider.kt +++ b/app/src/main/java/com/tangem/tap/data/DefaultCardSdkProvider.kt @@ -1,8 +1,7 @@ -package com.tangem.data.card.sdk +package com.tangem.tap.data import androidx.fragment.app.FragmentActivity import androidx.lifecycle.DefaultLifecycleObserver -import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.LifecycleOwner import com.tangem.Log import com.tangem.TangemSdk @@ -11,11 +10,15 @@ import com.tangem.common.authentication.AuthenticationManager import com.tangem.common.card.FirmwareVersion import com.tangem.common.core.Config import com.tangem.common.services.secure.SecureStorage +import com.tangem.core.analytics.api.AnalyticsEventHandler import com.tangem.crypto.bip39.Wordlist +import com.tangem.data.card.sdk.CardSdkOwner +import com.tangem.data.card.sdk.CardSdkProvider import com.tangem.sdk.DefaultSessionViewDelegate import com.tangem.sdk.extensions.* import com.tangem.sdk.nfc.NfcManager import com.tangem.sdk.storage.create +import com.tangem.tap.foregroundActivityObserver import javax.inject.Inject import javax.inject.Singleton @@ -25,19 +28,24 @@ import javax.inject.Singleton [REDACTED_AUTHOR] */ @Singleton -internal class DefaultCardSdkProvider @Inject constructor() : CardSdkProvider, CardSdkOwner { +internal class DefaultCardSdkProvider @Inject constructor( + private val analyticsEventHandler: AnalyticsEventHandler, +) : CardSdkProvider, CardSdkOwner { - override val sdk: TangemSdk - get() = requireNotNull(value = holder?.sdk) { - "Impossible to get the TangemSdk when activity is destroyed" - } - - private val observer: LifecycleObserver = Observer() + private val observer = Observer() private var holder: Holder? = null + override val sdk: TangemSdk + get() = holder?.sdk ?: tryToRegisterWithForegroundActivity() + override fun register(activity: FragmentActivity) { - Log.info { "Tangem SDK owner registered" } + if (activity.isDestroyed || activity.isFinishing || activity.isChangingConfigurations) { + val message = "Tangem SDK owner registration skipped: activity is destroyed or finishing" + analyticsEventHandler.send(TangemSdkWarningEvent(message)) + Log.info { message } + return + } if (holder != null) { unsubscribeAndCleanup() @@ -46,6 +54,36 @@ internal class DefaultCardSdkProvider @Inject constructor() : CardSdkProvider, C initialize(activity) activity.lifecycle.addObserver(observer) + + Log.info { "Tangem SDK owner registered" } + } + + private fun tryToRegisterWithForegroundActivity(): TangemSdk { + val warning = "Tangem SDK holder is null, trying to recreate it with foreground activity" + analyticsEventHandler.send(TangemSdkWarningEvent(warning)) + Log.warning { warning } + + val activity = foregroundActivityObserver.foregroundActivity + + if (activity == null) { + val error = "Tangem SDK holder is null and foreground activity is null" + analyticsEventHandler.send(TangemSdkWarningEvent(error)) + Log.error { error } + error(error) + } + + register(activity) + + val sdk = holder?.sdk + + if (sdk == null) { + val error = "Tangem SDK is null after re-registering with foreground activity" + analyticsEventHandler.send(TangemSdkWarningEvent(error)) + Log.error { error } + error(error) + } + + return sdk } private fun initialize(activity: FragmentActivity) { @@ -78,7 +116,14 @@ internal class DefaultCardSdkProvider @Inject constructor() : CardSdkProvider, C } private fun unsubscribeAndCleanup() { - with(receiver = holder ?: return) { + val currentHolder = holder + + if (currentHolder == null) { + Log.info { "Tangem SDK already unsubscribed and cleaned up" } + return + } + + with(currentHolder) { nfcManager.unsubscribe(activity) authenticationManager.unsubscribe(activity) diff --git a/app/src/main/java/com/tangem/tap/data/TangemSdkWarningEvent.kt b/app/src/main/java/com/tangem/tap/data/TangemSdkWarningEvent.kt new file mode 100644 index 0000000000..1393bfbf57 --- /dev/null +++ b/app/src/main/java/com/tangem/tap/data/TangemSdkWarningEvent.kt @@ -0,0 +1,9 @@ +package com.tangem.tap.data + +import com.tangem.core.analytics.models.AnalyticsEvent + +internal class TangemSdkWarningEvent(message: String) : AnalyticsEvent( + category = "Tangem SDK", + event = "Warning", + error = IllegalStateException(message), +) \ No newline at end of file diff --git a/data/card/src/main/java/com/tangem/data/card/di/CardSdkModule.kt b/app/src/main/java/com/tangem/tap/di/data/CardSdkModule.kt similarity index 86% rename from data/card/src/main/java/com/tangem/data/card/di/CardSdkModule.kt rename to app/src/main/java/com/tangem/tap/di/data/CardSdkModule.kt index 891c418cb1..118bcb16a7 100644 --- a/data/card/src/main/java/com/tangem/data/card/di/CardSdkModule.kt +++ b/app/src/main/java/com/tangem/tap/di/data/CardSdkModule.kt @@ -1,8 +1,8 @@ -package com.tangem.data.card.di +package com.tangem.tap.di.data import com.tangem.data.card.sdk.CardSdkOwner import com.tangem.data.card.sdk.CardSdkProvider -import com.tangem.data.card.sdk.DefaultCardSdkProvider +import com.tangem.tap.data.DefaultCardSdkProvider import dagger.Binds import dagger.Module import dagger.hilt.InstallIn diff --git a/data/card/src/main/java/com/tangem/data/card/sdk/CardSdkProvider.kt b/data/card/src/main/java/com/tangem/data/card/sdk/CardSdkProvider.kt index 0d0b88fa41..71c34a1266 100644 --- a/data/card/src/main/java/com/tangem/data/card/sdk/CardSdkProvider.kt +++ b/data/card/src/main/java/com/tangem/data/card/sdk/CardSdkProvider.kt @@ -7,7 +7,7 @@ import com.tangem.TangemSdk * [REDACTED_AUTHOR] */ -internal interface CardSdkProvider { +interface CardSdkProvider { /** CardSDK instance */ val sdk: TangemSdk