From e786995cdf9de7cb613afbb8525cba0ce8c63baa Mon Sep 17 00:00:00 2001 From: megamegax Date: Thu, 5 Sep 2024 15:21:00 +0200 Subject: [PATCH 1/2] fix(activity-watchdog): fix new watchdog SUITEDEV-36533 Co-authored-by: davidSchuppa <32750715+davidSchuppa@users.noreply.github.com> Co-authored-by: LasOri <24588073+LasOri@users.noreply.github.com> Co-authored-by: LordAndras <49073629+LordAndras@users.noreply.github.com> Co-authored-by: matusekma <36794575+matusekma@users.noreply.github.com> --- core/build.gradle.kts | 2 +- .../activity/CurrentActivityWatchdogTest.kt | 67 --------------- .../core/di/FakeCoreDependencyContainer.kt | 2 - core/src/main/AndroidManifest.xml | 14 +++- .../java/com/emarsys/EmarsysSdkInitializer.kt | 84 +++++++++++++++++++ .../core/activity/CurrentActivityWatchdog.kt | 27 ------ .../TransitionSafeCurrentActivityWatchdog.kt | 48 +++++++---- .../java/com/emarsys/core/di/CoreComponent.kt | 3 - .../java/com/emarsys/testUtil/E2ETestUtils.kt | 2 +- .../fake/FakeFirebaseDependencyContainer.kt | 2 - .../fake/FakeHuaweiDependencyContainer.kt | 2 - .../java/com/emarsys/EmarsysTest.kt | 20 ++--- .../androidTest/java/com/emarsys/InAppTest.kt | 2 +- .../com/emarsys/di/FakeDependencyContainer.kt | 2 - .../emarsys/testUtil/IntegrationTestUtils.kt | 2 +- .../src/main/java/com/emarsys/Emarsys.kt | 35 +++++--- .../com/emarsys/di/DefaultEmarsysComponent.kt | 8 +- .../fake/FakeEmarsysDependencyContainer.kt | 2 - gradle/libs.versions.toml | 2 + .../FakeMobileEngageDependencyContainer.kt | 2 - .../iam/webview/IamWebViewFactoryTest.kt | 15 +--- .../iam/webview/IamWebViewFactory.kt | 6 +- 22 files changed, 176 insertions(+), 173 deletions(-) delete mode 100644 core/src/androidTest/java/com/emarsys/core/activity/CurrentActivityWatchdogTest.kt create mode 100644 core/src/main/java/com/emarsys/EmarsysSdkInitializer.kt delete mode 100644 core/src/main/java/com/emarsys/core/activity/CurrentActivityWatchdog.kt diff --git a/core/build.gradle.kts b/core/build.gradle.kts index e7d78556..8f1d6c6f 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -13,7 +13,7 @@ dependencies { implementation(libs.google.tink) implementation(libs.kotlinx.coroutines.core) implementation(libs.androidx.activity) - + implementation(libs.startup.runtime) androidTestImplementation(project(":testUtils")) coreLibraryDesugaring(libs.android.tools.desugar) diff --git a/core/src/androidTest/java/com/emarsys/core/activity/CurrentActivityWatchdogTest.kt b/core/src/androidTest/java/com/emarsys/core/activity/CurrentActivityWatchdogTest.kt deleted file mode 100644 index a181c91e..00000000 --- a/core/src/androidTest/java/com/emarsys/core/activity/CurrentActivityWatchdogTest.kt +++ /dev/null @@ -1,67 +0,0 @@ -package com.emarsys.core.activity - -import android.app.Activity -import android.os.Bundle -import com.emarsys.core.provider.Property -import com.emarsys.core.provider.activity.CurrentActivityProvider -import com.emarsys.core.provider.activity.FallbackActivityProvider -import com.emarsys.testUtil.AnnotationSpec -import io.kotest.matchers.shouldBe -import org.mockito.kotlin.inOrder -import org.mockito.kotlin.mock -import org.mockito.kotlin.verify -import org.mockito.kotlin.verifyNoInteractions - -class CurrentActivityWatchdogTest : AnnotationSpec() { - private lateinit var watchdog: CurrentActivityWatchdog - private lateinit var activity: Activity - private lateinit var nextActivity: Activity - private lateinit var activityProvider: Property - - - @Before - fun setUp() { - activityProvider = mock() - watchdog = CurrentActivityWatchdog(activityProvider) - activity = mock() - nextActivity = mock() - } - - @Test - fun testGetCurrentActivity_shouldStoreTheActivity_whenCallingOnResumed() { - watchdog.onActivityResumed(activity) - verify(activityProvider).set(activity) - } - - @Test - fun testGetCurrentActivity_newerActivity_shouldOverride_thePrevious() { - watchdog.onActivityResumed(activity) - watchdog.onActivityResumed(nextActivity) - watchdog.onActivityPaused(activity) - inOrder(activityProvider).apply { - verify(activityProvider).set(activity) - verify(activityProvider).set(nextActivity) - } - } - - @Test - fun testGetCurrentActivity_shouldReturnNull_whenCurrentActivityPauses_andThereIsNoNextActivity() { - activityProvider = - CurrentActivityProvider(fallbackActivityProvider = FallbackActivityProvider()) - watchdog = CurrentActivityWatchdog(activityProvider) - watchdog.onActivityResumed(activity) - watchdog.onActivityPaused(activity) - activityProvider.get() shouldBe null - } - - @Test - fun testGetCurrentActivity_otherLifecycleCallbacks_shouldBeIgnored() { - val bundle = Bundle() - watchdog.onActivityCreated(activity, bundle) - watchdog.onActivityStarted(activity) - watchdog.onActivityStopped(activity) - watchdog.onActivitySaveInstanceState(activity, bundle) - watchdog.onActivityDestroyed(activity) - verifyNoInteractions(activityProvider) - } -} \ No newline at end of file diff --git a/core/src/androidTest/java/com/emarsys/core/di/FakeCoreDependencyContainer.kt b/core/src/androidTest/java/com/emarsys/core/di/FakeCoreDependencyContainer.kt index f00e161e..4ffb597a 100644 --- a/core/src/androidTest/java/com/emarsys/core/di/FakeCoreDependencyContainer.kt +++ b/core/src/androidTest/java/com/emarsys/core/di/FakeCoreDependencyContainer.kt @@ -4,7 +4,6 @@ import android.content.SharedPreferences import com.emarsys.core.CoreCompletionHandler import com.emarsys.core.activity.ActivityLifecycleActionRegistry import com.emarsys.core.activity.ActivityLifecycleWatchdog -import com.emarsys.core.activity.CurrentActivityWatchdog import com.emarsys.core.activity.TransitionSafeCurrentActivityWatchdog import com.emarsys.core.concurrency.ConcurrentHandlerHolderFactory import com.emarsys.core.connection.ConnectionWatchDog @@ -32,7 +31,6 @@ import org.mockito.kotlin.mock class FakeCoreDependencyContainer( override val concurrentHandlerHolder: ConcurrentHandlerHolder = ConcurrentHandlerHolderFactory.create(), override val activityLifecycleWatchdog: ActivityLifecycleWatchdog = mock(), - override val currentActivityWatchdog: CurrentActivityWatchdog = mock(), override val coreSQLiteDatabase: CoreSQLiteDatabase = mock(), override val deviceInfo: DeviceInfo = mock(), override val shardRepository: Repository = mock(), diff --git a/core/src/main/AndroidManifest.xml b/core/src/main/AndroidManifest.xml index 1eb5eb2e..a2eabdc4 100644 --- a/core/src/main/AndroidManifest.xml +++ b/core/src/main/AndroidManifest.xml @@ -1,6 +1,18 @@ - + + + + + + diff --git a/core/src/main/java/com/emarsys/EmarsysSdkInitializer.kt b/core/src/main/java/com/emarsys/EmarsysSdkInitializer.kt new file mode 100644 index 00000000..f9bf8987 --- /dev/null +++ b/core/src/main/java/com/emarsys/EmarsysSdkInitializer.kt @@ -0,0 +1,84 @@ +package com.emarsys + +import android.app.Activity +import android.app.Application +import android.app.Application.ActivityLifecycleCallbacks +import android.content.Context +import android.os.Bundle +import androidx.startup.Initializer +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.launch +import java.lang.ref.WeakReference + +internal var currentActivityFlow: MutableStateFlow?> = + MutableStateFlow(null) + private set + +suspend fun getCurrentActivity(): Activity { + return currentActivityFlow.first { activity -> activity != null }!!.get()!! +} + +class EmarsysSdkInitializer : Initializer { + private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default) + private var setActivityJob: Job? = null + + override fun create(context: Context) { + (context.applicationContext as Application).registerActivityLifecycleCallbacks(object : + ActivityLifecycleCallbacks { + + override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { + currentActivityFlow.value = null + } + + override fun onActivityStarted(activity: Activity) { + currentActivityFlow.value = null + } + + override fun onActivityResumed(activity: Activity) { + setActivityJob = scope.launch { + delay(500) + currentActivityFlow.value = WeakReference(activity) + } + } + + override fun onActivityPaused(activity: Activity) { + if (activity == currentActivityFlow.value) { + currentActivityFlow.value = null + setActivityJob?.cancel() + } + } + + override fun onActivityStopped(activity: Activity) { + if (activity == currentActivityFlow.value) { + currentActivityFlow.value = null + setActivityJob?.cancel() + } + } + + override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) { + if (activity == currentActivityFlow.value) { + currentActivityFlow.value = null + setActivityJob?.cancel() + } + } + + override fun onActivityDestroyed(activity: Activity) { + if (activity == currentActivityFlow.value) { + currentActivityFlow.value = null + setActivityJob?.cancel() + } + } + }) + } + + override fun dependencies(): List>> { + return emptyList() + } +} + diff --git a/core/src/main/java/com/emarsys/core/activity/CurrentActivityWatchdog.kt b/core/src/main/java/com/emarsys/core/activity/CurrentActivityWatchdog.kt deleted file mode 100644 index 9402890b..00000000 --- a/core/src/main/java/com/emarsys/core/activity/CurrentActivityWatchdog.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.emarsys.core.activity - -import android.app.Activity -import android.app.Application.ActivityLifecycleCallbacks -import android.os.Bundle -import com.emarsys.core.Mockable -import com.emarsys.core.provider.Property - -@Mockable -class CurrentActivityWatchdog(private val currentActivityProvider: Property) : - ActivityLifecycleCallbacks { - override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {} - override fun onActivityStarted(activity: Activity) {} - override fun onActivityResumed(activity: Activity) { - currentActivityProvider.set(activity) - } - - override fun onActivityPaused(activity: Activity) { - if (currentActivityProvider.get() === activity) { - currentActivityProvider.set(null) - } - } - - override fun onActivityStopped(activity: Activity) {} - override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {} - override fun onActivityDestroyed(activity: Activity) {} -} \ No newline at end of file diff --git a/core/src/main/java/com/emarsys/core/activity/TransitionSafeCurrentActivityWatchdog.kt b/core/src/main/java/com/emarsys/core/activity/TransitionSafeCurrentActivityWatchdog.kt index 6aa064b7..c4c5ae2a 100644 --- a/core/src/main/java/com/emarsys/core/activity/TransitionSafeCurrentActivityWatchdog.kt +++ b/core/src/main/java/com/emarsys/core/activity/TransitionSafeCurrentActivityWatchdog.kt @@ -6,67 +6,77 @@ import android.os.Bundle import com.emarsys.core.Mockable import com.emarsys.core.handler.SdkHandler import com.emarsys.core.observer.Observer +import com.emarsys.core.provider.Property +import com.emarsys.getCurrentActivity +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import java.util.concurrent.CountDownLatch @Mockable -class TransitionSafeCurrentActivityWatchdog(private val handler: SdkHandler) : +class TransitionSafeCurrentActivityWatchdog( + private val handler: SdkHandler, + private val currentActivityProvider: Property +) : ActivityLifecycleCallbacks, Observer { private val activityCallbacks = mutableListOf<(Activity) -> Unit>() - private var currentActivity: Activity? = null + private var mCurrentActivity: Activity? = null private val callback: Runnable = Runnable { - if (currentActivity != null) { - notify(currentActivity!!) + if (mCurrentActivity != null) { + notify(mCurrentActivity!!) } } override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { - currentActivity = null + mCurrentActivity = null } override fun onActivityStarted(activity: Activity) { - currentActivity = null + mCurrentActivity = null } override fun onActivityResumed(activity: Activity) { - currentActivity = activity + mCurrentActivity = activity handler.postDelayed(callback, 500) } override fun onActivityPaused(activity: Activity) { - if (activity == currentActivity) { - currentActivity = null + if (activity == mCurrentActivity) { + mCurrentActivity = null handler.remove(callback) } } override fun onActivityStopped(activity: Activity) { - if (activity == currentActivity) { - currentActivity = null + if (activity == mCurrentActivity) { + mCurrentActivity = null handler.remove(callback) } } override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) { - if (activity == currentActivity) { - currentActivity = null + if (activity == mCurrentActivity) { + mCurrentActivity = null handler.remove(callback) } } override fun onActivityDestroyed(activity: Activity) { - if (activity == currentActivity) { - currentActivity = null + if (activity == mCurrentActivity) { + mCurrentActivity = null handler.remove(callback) } } override fun register(callback: (Activity) -> Unit) { activityCallbacks.add(callback) - if (currentActivity != null) { - callback(currentActivity!!) + CoroutineScope(Dispatchers.Default).launch { + val currentActivity = getCurrentActivity() + currentActivityProvider.set(currentActivity) + callback(currentActivity) } } @@ -75,10 +85,14 @@ class TransitionSafeCurrentActivityWatchdog(private val handler: SdkHandler) : } override fun notify(value: Activity) { + currentActivityProvider.set(value) activityCallbacks.forEach { it(value) } } fun activity(): Activity { + if (mCurrentActivity != null) { + return mCurrentActivity!! + } lateinit var result: Activity val latch = CountDownLatch(1) val callback: (Activity) -> Unit = { diff --git a/core/src/main/java/com/emarsys/core/di/CoreComponent.kt b/core/src/main/java/com/emarsys/core/di/CoreComponent.kt index 5299bec0..3cc28d95 100644 --- a/core/src/main/java/com/emarsys/core/di/CoreComponent.kt +++ b/core/src/main/java/com/emarsys/core/di/CoreComponent.kt @@ -4,7 +4,6 @@ import android.content.SharedPreferences import com.emarsys.core.CoreCompletionHandler import com.emarsys.core.activity.ActivityLifecycleActionRegistry import com.emarsys.core.activity.ActivityLifecycleWatchdog -import com.emarsys.core.activity.CurrentActivityWatchdog import com.emarsys.core.activity.TransitionSafeCurrentActivityWatchdog import com.emarsys.core.connection.ConnectionWatchDog import com.emarsys.core.crypto.Crypto @@ -53,8 +52,6 @@ interface CoreComponent { val activityLifecycleWatchdog: ActivityLifecycleWatchdog - val currentActivityWatchdog: CurrentActivityWatchdog - val activityLifecycleActionRegistry: ActivityLifecycleActionRegistry val coreSQLiteDatabase: CoreSQLiteDatabase diff --git a/emarsys-e2e-test/src/androidTest/java/com/emarsys/testUtil/E2ETestUtils.kt b/emarsys-e2e-test/src/androidTest/java/com/emarsys/testUtil/E2ETestUtils.kt index 9a7b4d02..b13b6d9a 100644 --- a/emarsys-e2e-test/src/androidTest/java/com/emarsys/testUtil/E2ETestUtils.kt +++ b/emarsys-e2e-test/src/androidTest/java/com/emarsys/testUtil/E2ETestUtils.kt @@ -13,7 +13,7 @@ object E2ETestUtils { emarsys().concurrentHandlerHolder.coreHandler.post { if (application != null) { application.unregisterActivityLifecycleCallbacks(emarsys().activityLifecycleWatchdog) - application.unregisterActivityLifecycleCallbacks(emarsys().currentActivityWatchdog) + application.unregisterActivityLifecycleCallbacks(emarsys().transitionSafeCurrentActivityWatchdog) } emarsys().contactTokenStorage.remove() diff --git a/emarsys-firebase/src/androidTest/java/com/emarsys/fake/FakeFirebaseDependencyContainer.kt b/emarsys-firebase/src/androidTest/java/com/emarsys/fake/FakeFirebaseDependencyContainer.kt index 410e5b00..bfab5050 100644 --- a/emarsys-firebase/src/androidTest/java/com/emarsys/fake/FakeFirebaseDependencyContainer.kt +++ b/emarsys-firebase/src/androidTest/java/com/emarsys/fake/FakeFirebaseDependencyContainer.kt @@ -6,7 +6,6 @@ import android.content.SharedPreferences import com.emarsys.core.CoreCompletionHandler import com.emarsys.core.activity.ActivityLifecycleActionRegistry import com.emarsys.core.activity.ActivityLifecycleWatchdog -import com.emarsys.core.activity.CurrentActivityWatchdog import com.emarsys.core.activity.TransitionSafeCurrentActivityWatchdog import com.emarsys.core.app.AppLifecycleObserver import com.emarsys.core.concurrency.ConcurrentHandlerHolderFactory @@ -126,7 +125,6 @@ class FakeFirebaseDependencyContainer( override val mobileEngageRequestModelFactory: MobileEngageRequestModelFactory = mock(), override val mobileEngageSession: MobileEngageSession = mock(), override val activityLifecycleWatchdog: ActivityLifecycleWatchdog = mock(), - override val currentActivityWatchdog: CurrentActivityWatchdog = mock(), override val coreSQLiteDatabase: CoreSQLiteDatabase = mock(), override val deviceInfo: DeviceInfo = mock(), override val shardRepository: Repository = mock(), diff --git a/emarsys-huawei/src/androidTest/java/com/emarsys/fake/FakeHuaweiDependencyContainer.kt b/emarsys-huawei/src/androidTest/java/com/emarsys/fake/FakeHuaweiDependencyContainer.kt index 82d8bcfe..cc8be62b 100644 --- a/emarsys-huawei/src/androidTest/java/com/emarsys/fake/FakeHuaweiDependencyContainer.kt +++ b/emarsys-huawei/src/androidTest/java/com/emarsys/fake/FakeHuaweiDependencyContainer.kt @@ -6,7 +6,6 @@ import android.content.SharedPreferences import com.emarsys.core.CoreCompletionHandler import com.emarsys.core.activity.ActivityLifecycleActionRegistry import com.emarsys.core.activity.ActivityLifecycleWatchdog -import com.emarsys.core.activity.CurrentActivityWatchdog import com.emarsys.core.activity.TransitionSafeCurrentActivityWatchdog import com.emarsys.core.app.AppLifecycleObserver import com.emarsys.core.concurrency.ConcurrentHandlerHolderFactory @@ -126,7 +125,6 @@ class FakeHuaweiDependencyContainer( override val mobileEngageRequestModelFactory: MobileEngageRequestModelFactory = mock(), override val mobileEngageSession: MobileEngageSession = mock(), override val activityLifecycleWatchdog: ActivityLifecycleWatchdog = mock(), - override val currentActivityWatchdog: CurrentActivityWatchdog = mock(), override val coreSQLiteDatabase: CoreSQLiteDatabase = mock(), override val deviceInfo: DeviceInfo = mock(), override val shardRepository: Repository = mock(), diff --git a/emarsys-sdk/src/androidTest/java/com/emarsys/EmarsysTest.kt b/emarsys-sdk/src/androidTest/java/com/emarsys/EmarsysTest.kt index d370b834..57e22e85 100644 --- a/emarsys-sdk/src/androidTest/java/com/emarsys/EmarsysTest.kt +++ b/emarsys-sdk/src/androidTest/java/com/emarsys/EmarsysTest.kt @@ -15,7 +15,7 @@ import com.emarsys.config.ConfigApi import com.emarsys.config.ConfigInternal import com.emarsys.config.EmarsysConfig import com.emarsys.core.activity.ActivityLifecycleWatchdog -import com.emarsys.core.activity.CurrentActivityWatchdog +import com.emarsys.core.activity.TransitionSafeCurrentActivityWatchdog import com.emarsys.core.api.experimental.FlipperFeature import com.emarsys.core.api.notification.ChannelSettings import com.emarsys.core.api.notification.NotificationSettings @@ -110,7 +110,7 @@ class EmarsysTest : AnnotationSpec() { } private lateinit var mockActivityLifecycleWatchdog: ActivityLifecycleWatchdog - private lateinit var mockCurrentActivityWatchdog: CurrentActivityWatchdog + private lateinit var mockCurrentActivityWatchdog: TransitionSafeCurrentActivityWatchdog private lateinit var mockCoreSQLiteDatabase: CoreSQLiteDatabase private lateinit var mockLogShardTrigger: Runnable private lateinit var mockMobileEngageInternal: MobileEngageInternal @@ -241,7 +241,6 @@ class EmarsysTest : AnnotationSpec() { setupEmarsysComponent( FakeDependencyContainer( activityLifecycleWatchdog = mockActivityLifecycleWatchdog, - currentActivityWatchdog = mockCurrentActivityWatchdog, coreSQLiteDatabase = mockCoreSQLiteDatabase, deviceInfo = deviceInfo, logShardTrigger = mockLogShardTrigger, @@ -488,7 +487,7 @@ class EmarsysTest : AnnotationSpec() { ActivityLifecycleWatchdog::class.java ) shouldNotBe null } - val currentActivityWatchdogSlot = slot() + val currentActivityWatchdogSlot = slot() verify(exactly = 1) { application .registerActivityLifecycleCallbacks(capture(currentActivityWatchdogSlot)) @@ -496,7 +495,7 @@ class EmarsysTest : AnnotationSpec() { val allRegisteredWatchdogs = listOf(currentActivityWatchdogSlot.captured) getElementByType( allRegisteredWatchdogs, - CurrentActivityWatchdog::class.java + TransitionSafeCurrentActivityWatchdog::class.java ) shouldNotBe null } @@ -507,7 +506,7 @@ class EmarsysTest : AnnotationSpec() { setup(mobileEngageConfig) runBlockingOnCoreSdkThread { - verify(exactly = 3) { application.registerActivityLifecycleCallbacks(any()) } + verify(exactly = 2) { application.registerActivityLifecycleCallbacks(any()) } } } @@ -531,12 +530,9 @@ class EmarsysTest : AnnotationSpec() { fun testSetup_registers_currentActivityWatchDog() { setup(mobileEngageConfig) - runBlockingOnCoreSdkThread { - verifyOrder { - application.registerActivityLifecycleCallbacks(mockCurrentActivityWatchdog) - application.registerActivityLifecycleCallbacks(mockActivityLifecycleWatchdog) - } - } + runBlockingOnCoreSdkThread() + application.registerActivityLifecycleCallbacks(mockActivityLifecycleWatchdog) + application.registerActivityLifecycleCallbacks(mockCurrentActivityWatchdog) } @Test diff --git a/emarsys-sdk/src/androidTest/java/com/emarsys/InAppTest.kt b/emarsys-sdk/src/androidTest/java/com/emarsys/InAppTest.kt index 3cd79759..49637127 100644 --- a/emarsys-sdk/src/androidTest/java/com/emarsys/InAppTest.kt +++ b/emarsys-sdk/src/androidTest/java/com/emarsys/InAppTest.kt @@ -38,7 +38,7 @@ class InAppTest : AnnotationSpec() { fun tearDown() { application.unregisterActivityLifecycleCallbacks( mobileEngage().activityLifecycleWatchdog) - application.unregisterActivityLifecycleCallbacks(emarsys().currentActivityWatchdog) + application.unregisterActivityLifecycleCallbacks(emarsys().transitionSafeCurrentActivityWatchdog) try { val looper: Looper = emarsys().concurrentHandlerHolder.coreLooper looper.quitSafely() diff --git a/emarsys-sdk/src/androidTest/java/com/emarsys/di/FakeDependencyContainer.kt b/emarsys-sdk/src/androidTest/java/com/emarsys/di/FakeDependencyContainer.kt index 9437d034..e79e6b4f 100644 --- a/emarsys-sdk/src/androidTest/java/com/emarsys/di/FakeDependencyContainer.kt +++ b/emarsys-sdk/src/androidTest/java/com/emarsys/di/FakeDependencyContainer.kt @@ -9,7 +9,6 @@ import com.emarsys.config.ConfigInternal import com.emarsys.core.CoreCompletionHandler import com.emarsys.core.activity.ActivityLifecycleActionRegistry import com.emarsys.core.activity.ActivityLifecycleWatchdog -import com.emarsys.core.activity.CurrentActivityWatchdog import com.emarsys.core.activity.TransitionSafeCurrentActivityWatchdog import com.emarsys.core.app.AppLifecycleObserver import com.emarsys.core.concurrency.ConcurrentHandlerHolderFactory @@ -164,7 +163,6 @@ class FakeDependencyContainer( override val mobileEngageRequestModelFactory: MobileEngageRequestModelFactory = mock(), override val mobileEngageSession: MobileEngageSession = mock(), override val activityLifecycleWatchdog: ActivityLifecycleWatchdog = mock(), - override val currentActivityWatchdog: CurrentActivityWatchdog = mock(), override val coreSQLiteDatabase: CoreSQLiteDatabase = mock(), override val deviceInfo: DeviceInfo = mock(), override val shardRepository: Repository = mock(), diff --git a/emarsys-sdk/src/androidTest/java/com/emarsys/testUtil/IntegrationTestUtils.kt b/emarsys-sdk/src/androidTest/java/com/emarsys/testUtil/IntegrationTestUtils.kt index a83eb485..afde89db 100644 --- a/emarsys-sdk/src/androidTest/java/com/emarsys/testUtil/IntegrationTestUtils.kt +++ b/emarsys-sdk/src/androidTest/java/com/emarsys/testUtil/IntegrationTestUtils.kt @@ -41,7 +41,7 @@ object IntegrationTestUtils { emarsys().concurrentHandlerHolder.coreHandler.post { if (application != null) { application.unregisterActivityLifecycleCallbacks(emarsys().activityLifecycleWatchdog) - application.unregisterActivityLifecycleCallbacks(emarsys().currentActivityWatchdog) + application.unregisterActivityLifecycleCallbacks(emarsys().transitionSafeCurrentActivityWatchdog) } emarsys().clientStateStorage.remove() diff --git a/emarsys-sdk/src/main/java/com/emarsys/Emarsys.kt b/emarsys-sdk/src/main/java/com/emarsys/Emarsys.kt index 38411a3d..0288e3b8 100644 --- a/emarsys-sdk/src/main/java/com/emarsys/Emarsys.kt +++ b/emarsys-sdk/src/main/java/com/emarsys/Emarsys.kt @@ -190,19 +190,18 @@ object Emarsys { } private fun registerWatchDogs(config: EmarsysConfig) { - config.application.registerActivityLifecycleCallbacks(emarsys().currentActivityWatchdog) config.application.registerActivityLifecycleCallbacks(emarsys().activityLifecycleWatchdog) config.application.registerActivityLifecycleCallbacks(emarsys().transitionSafeCurrentActivityWatchdog) } private fun registerDatabaseTriggers() { - emarsys().coreSQLiteDatabase - .registerTrigger( - DatabaseContract.SHARD_TABLE_NAME, - TriggerType.AFTER, - TriggerEvent.INSERT, - emarsys().predictShardTrigger - ) + emarsys().coreSQLiteDatabase + .registerTrigger( + DatabaseContract.SHARD_TABLE_NAME, + TriggerType.AFTER, + TriggerEvent.INSERT, + emarsys().predictShardTrigger + ) emarsys().coreSQLiteDatabase .registerTrigger( @@ -233,17 +232,31 @@ object Emarsys { } private fun refreshRemoteConfig(applicationCode: String?) { - if (!listOf("", "null", "nil", "0").contains(applicationCode?.lowercase()) && applicationCode != null) { + if (!listOf( + "", + "null", + "nil", + "0" + ).contains(applicationCode?.lowercase()) && applicationCode != null + ) { emarsys().configInternal.proxyApi(mobileEngage().concurrentHandlerHolder) .refreshRemoteConfig { it?.let { - val logEntry = StatusLog(Emarsys::class.java, "refreshRemoteConfig", mapOf("applicationCode" to applicationCode, "exception" to it.message)) + val logEntry = StatusLog( + Emarsys::class.java, + "refreshRemoteConfig", + mapOf("applicationCode" to applicationCode, "exception" to it.message) + ) Logger.log(logEntry) } } } else { Log.w("EmarsysSdk", "Invalid applicationCode: $applicationCode") - val logEntry = StatusLog(Emarsys::class.java, "refreshRemoteConfig", mapOf("applicationCode" to applicationCode)) + val logEntry = StatusLog( + Emarsys::class.java, + "refreshRemoteConfig", + mapOf("applicationCode" to applicationCode) + ) Logger.log(logEntry) } } diff --git a/emarsys-sdk/src/main/java/com/emarsys/di/DefaultEmarsysComponent.kt b/emarsys-sdk/src/main/java/com/emarsys/di/DefaultEmarsysComponent.kt index b37f149e..9add30c0 100644 --- a/emarsys-sdk/src/main/java/com/emarsys/di/DefaultEmarsysComponent.kt +++ b/emarsys-sdk/src/main/java/com/emarsys/di/DefaultEmarsysComponent.kt @@ -24,7 +24,6 @@ import com.emarsys.core.DefaultCoreCompletionHandler import com.emarsys.core.Mapper import com.emarsys.core.activity.ActivityLifecycleActionRegistry import com.emarsys.core.activity.ActivityLifecycleWatchdog -import com.emarsys.core.activity.CurrentActivityWatchdog import com.emarsys.core.activity.TransitionSafeCurrentActivityWatchdog import com.emarsys.core.api.notification.NotificationSettings import com.emarsys.core.api.proxyApi @@ -315,7 +314,8 @@ open class DefaultEmarsysComponent(config: EmarsysConfig) : EmarsysComponent { override val transitionSafeCurrentActivityWatchdog: TransitionSafeCurrentActivityWatchdog by lazy { TransitionSafeCurrentActivityWatchdog( - concurrentHandlerHolder.coreHandler + concurrentHandlerHolder.coreHandler, + currentActivityProvider ) } @@ -764,10 +764,6 @@ open class DefaultEmarsysComponent(config: EmarsysConfig) : EmarsysComponent { CurrentActivityProvider(fallbackActivityProvider = FallbackActivityProvider()) } - override val currentActivityWatchdog: CurrentActivityWatchdog by lazy { - CurrentActivityWatchdog(currentActivityProvider) - } - override val iamJsBridgeFactory: IamJsBridgeFactory by lazy { IamJsBridgeFactory(concurrentHandlerHolder) } diff --git a/emarsys/src/androidTest/java/com/emarsys/fake/FakeEmarsysDependencyContainer.kt b/emarsys/src/androidTest/java/com/emarsys/fake/FakeEmarsysDependencyContainer.kt index 5a6f6275..2f63cc6e 100644 --- a/emarsys/src/androidTest/java/com/emarsys/fake/FakeEmarsysDependencyContainer.kt +++ b/emarsys/src/androidTest/java/com/emarsys/fake/FakeEmarsysDependencyContainer.kt @@ -7,7 +7,6 @@ import android.content.SharedPreferences import com.emarsys.core.CoreCompletionHandler import com.emarsys.core.activity.ActivityLifecycleActionRegistry import com.emarsys.core.activity.ActivityLifecycleWatchdog -import com.emarsys.core.activity.CurrentActivityWatchdog import com.emarsys.core.activity.TransitionSafeCurrentActivityWatchdog import com.emarsys.core.app.AppLifecycleObserver import com.emarsys.core.concurrency.ConcurrentHandlerHolderFactory @@ -127,7 +126,6 @@ class FakeEmarsysDependencyContainer( override val mobileEngageRequestModelFactory: MobileEngageRequestModelFactory = mock(), override val mobileEngageSession: MobileEngageSession = mock(), override val activityLifecycleWatchdog: ActivityLifecycleWatchdog = mock(), - override val currentActivityWatchdog: CurrentActivityWatchdog = mock(), override val coreSQLiteDatabase: CoreSQLiteDatabase = mock(), override val deviceInfo: DeviceInfo = mock(), override val shardRepository: Repository = mock(), diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b38999cc..95669384 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -26,6 +26,7 @@ androidx-test-fragment = "1.8.2" androidx-test-multidex = "2.0.0" androidx-lifecycle = "2.8.4" androidx-espresso-idling-resource = "3.6.1" +androidx-startupRuntime = "1.1.1" androidx-security-crypto = "1.1.0-alpha06" androidx-navigation-safe-args = "2.7.7" io-coil = "2.5.0" @@ -101,6 +102,7 @@ androidx-compose-foundation = { module = "androidx.compose.foundation:foundation androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "androidx-navigation-compose" } androidx-compose-material = { module = "androidx.compose.material:material", version.ref = "compose" } androidx-compose-material-icons = { module = "androidx.compose.material:material-icons-extended", version.ref = "compose" } +startup-runtime = { module = "androidx.startup:startup-runtime", version.ref = "androidx-startupRuntime" } androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidx-core-ktx" } io-coil = { module = "io.coil-kt:coil-compose", version.ref = "io-coil" } io-coil-compose = { module = "io.coil-kt:coil", version.ref = "io-coil" } diff --git a/mobile-engage/src/androidTest/java/com/emarsys/mobileengage/fake/FakeMobileEngageDependencyContainer.kt b/mobile-engage/src/androidTest/java/com/emarsys/mobileengage/fake/FakeMobileEngageDependencyContainer.kt index 2bdbc04d..cf422a49 100644 --- a/mobile-engage/src/androidTest/java/com/emarsys/mobileengage/fake/FakeMobileEngageDependencyContainer.kt +++ b/mobile-engage/src/androidTest/java/com/emarsys/mobileengage/fake/FakeMobileEngageDependencyContainer.kt @@ -6,7 +6,6 @@ import android.content.SharedPreferences import com.emarsys.core.CoreCompletionHandler import com.emarsys.core.activity.ActivityLifecycleActionRegistry import com.emarsys.core.activity.ActivityLifecycleWatchdog -import com.emarsys.core.activity.CurrentActivityWatchdog import com.emarsys.core.activity.TransitionSafeCurrentActivityWatchdog import com.emarsys.core.app.AppLifecycleObserver import com.emarsys.core.concurrency.ConcurrentHandlerHolderFactory @@ -126,7 +125,6 @@ class FakeMobileEngageDependencyContainer( override val mobileEngageRequestModelFactory: MobileEngageRequestModelFactory = mock(), override val mobileEngageSession: MobileEngageSession = mock(), override val activityLifecycleWatchdog: ActivityLifecycleWatchdog = mock(), - override val currentActivityWatchdog: CurrentActivityWatchdog = mock(), override val coreSQLiteDatabase: CoreSQLiteDatabase = mock(), override val deviceInfo: DeviceInfo = mock(), override val shardRepository: Repository = mock(), diff --git a/mobile-engage/src/androidTest/java/com/emarsys/mobileengage/iam/webview/IamWebViewFactoryTest.kt b/mobile-engage/src/androidTest/java/com/emarsys/mobileengage/iam/webview/IamWebViewFactoryTest.kt index 4a7b0bfd..23e5724a 100644 --- a/mobile-engage/src/androidTest/java/com/emarsys/mobileengage/iam/webview/IamWebViewFactoryTest.kt +++ b/mobile-engage/src/androidTest/java/com/emarsys/mobileengage/iam/webview/IamWebViewFactoryTest.kt @@ -1,7 +1,7 @@ package com.emarsys.mobileengage.iam.webview -import android.app.Activity +import android.content.Context import com.emarsys.core.concurrency.ConcurrentHandlerHolderFactory import com.emarsys.core.handler.ConcurrentHandlerHolder import com.emarsys.mobileengage.iam.jsbridge.IamJsBridge @@ -10,6 +10,7 @@ import com.emarsys.mobileengage.iam.jsbridge.JSCommandFactory import com.emarsys.mobileengage.iam.jsbridge.JSCommandFactoryProvider import com.emarsys.testUtil.AnnotationSpec import com.emarsys.testUtil.ExtensionTestUtils.runOnMain +import com.emarsys.testUtil.InstrumentationRegistry.Companion.getTargetContext import io.kotest.matchers.shouldBe import io.mockk.every import io.mockk.mockk @@ -23,7 +24,7 @@ class IamWebViewFactoryTest : AnnotationSpec() { private lateinit var concurrentHandlerHolder: ConcurrentHandlerHolder private lateinit var webViewFactory: IamWebViewFactory - private lateinit var mockActivity: Activity + private lateinit var mockActivity: Context @Before fun setUp() { @@ -39,7 +40,7 @@ class IamWebViewFactoryTest : AnnotationSpec() { concurrentHandlerHolder = ConcurrentHandlerHolderFactory.create() - mockActivity = mockk(relaxed = true) + mockActivity = getTargetContext() webViewFactory = IamWebViewFactory( mockJsBridgeFactory, mockJSCommandFactoryProvider, @@ -47,14 +48,6 @@ class IamWebViewFactoryTest : AnnotationSpec() { ) } - @Test - fun testCreateWithNull() { - val iamWebView = runOnMain { - webViewFactory.create(mockActivity) - } - iamWebView::class.java shouldBe IamWebView::class.java - } - @Test fun testCreateWithActivity() { val iamWebView = runOnMain { diff --git a/mobile-engage/src/main/java/com/emarsys/mobileengage/iam/webview/IamWebViewFactory.kt b/mobile-engage/src/main/java/com/emarsys/mobileengage/iam/webview/IamWebViewFactory.kt index 3de0dc68..abd73e3a 100644 --- a/mobile-engage/src/main/java/com/emarsys/mobileengage/iam/webview/IamWebViewFactory.kt +++ b/mobile-engage/src/main/java/com/emarsys/mobileengage/iam/webview/IamWebViewFactory.kt @@ -15,8 +15,10 @@ class IamWebViewFactory( fun create(context: Context): IamWebView { return IamWebView( - concurrentHandlerHolder, jsBridgeFactory, - jsCommandFactoryProvider.provide(), context + concurrentHandlerHolder, + jsBridgeFactory, + jsCommandFactoryProvider.provide(), + context ) } From e4cd20eb3c50a459842c01117b575fdcf126c2b5 Mon Sep 17 00:00:00 2001 From: megamegax Date: Thu, 5 Sep 2024 16:24:20 +0200 Subject: [PATCH 2/2] chore(release): 3.7.7 SUITEDEV-36533 Co-authored-by: davidSchuppa <32750715+davidSchuppa@users.noreply.github.com> Co-authored-by: LasOri <24588073+LasOri@users.noreply.github.com> Co-authored-by: LordAndras <49073629+LordAndras@users.noreply.github.com> Co-authored-by: matusekma <36794575+matusekma@users.noreply.github.com> --- changelog.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/changelog.md b/changelog.md index 3d721438..06406007 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,9 @@ -# What's changed -### [Emarsys](https://github.com/emartech/android-emarsys-sdk/wiki#contents) -* Changed error handling in database operations to receive more detailed information. \ No newline at end of file +# What's fixed + +### [Geofence](https://github.com/emartech/android-emarsys-sdk/wiki#8-geofence) + +* Fixed a compatibility issue with Android 14 (API level 34) and above. + +### [In-App](https://github.com/emartech/android-emarsys-sdk/wiki#3-inapp) + +* Fixed an edge-case when the Activity was not found for the given In-App message to display. \ No newline at end of file