diff --git a/core/src/androidTest/java/com/emarsys/core/contentresolver/hardwareid/HardwareIdContentResolverTest.kt b/core/src/androidTest/java/com/emarsys/core/contentresolver/hardwareid/HardwareIdContentResolverTest.kt index 229a8bc7..28706f70 100644 --- a/core/src/androidTest/java/com/emarsys/core/contentresolver/hardwareid/HardwareIdContentResolverTest.kt +++ b/core/src/androidTest/java/com/emarsys/core/contentresolver/hardwareid/HardwareIdContentResolverTest.kt @@ -1,17 +1,14 @@ -package com.emarsys.core.contentresolver.hardwareid - -import android.content.Context import android.database.Cursor import android.net.Uri +import com.emarsys.core.contentresolver.EmarsysContentResolver +import com.emarsys.core.contentresolver.hardwareid.HardwareIdContentResolver import com.emarsys.core.crypto.HardwareIdentificationCrypto import com.emarsys.core.database.DatabaseContract import com.emarsys.core.device.HardwareIdentification -import com.emarsys.core.provider.hardwareid.HardwareIdProviderTest import io.kotest.matchers.shouldBe import io.mockk.every import io.mockk.mockk import io.mockk.verify - import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test @@ -26,7 +23,7 @@ class HardwareIdContentResolverTest { } - private var mockContext: Context = mockk() + private var mockEmarsysContentResolver: EmarsysContentResolver = mockk() private lateinit var contentResolver: HardwareIdContentResolver private lateinit var mockHardwareIdentificationCrypto: HardwareIdentificationCrypto private lateinit var mockCursor: Cursor @@ -38,12 +35,12 @@ class HardwareIdContentResolverTest { every { getColumnIndexOrThrow(DatabaseContract.HARDWARE_IDENTIFICATION_COLUMN_NAME_ENCRYPTED_HARDWARE_ID) } returns 0 every { getColumnIndexOrThrow(DatabaseContract.HARDWARE_IDENTIFICATION_COLUMN_NAME_SALT) } returns 1 every { getColumnIndexOrThrow(DatabaseContract.HARDWARE_IDENTIFICATION_COLUMN_NAME_IV) } returns 2 - every { getString(0) } returns HardwareIdProviderTest.ENCRYPTED_HARDWARE_ID - every { getString(1) } returns HardwareIdProviderTest.SALT - every { getString(2) } returns HardwareIdProviderTest.IV + every { getString(0) } returns ENCRYPTED_HARDWARE_ID + every { getString(1) } returns SALT + every { getString(2) } returns IV } every { - mockContext.contentResolver.query( + mockEmarsysContentResolver.query( any(), any(), any(), @@ -66,7 +63,7 @@ class HardwareIdContentResolverTest { IV ) contentResolver = HardwareIdContentResolver( - mockContext, + mockEmarsysContentResolver, mockHardwareIdentificationCrypto, SHARED_PACKAGE_NAMES ) @@ -86,13 +83,12 @@ class HardwareIdContentResolverTest { every { getColumnIndexOrThrow(DatabaseContract.HARDWARE_IDENTIFICATION_COLUMN_NAME_ENCRYPTED_HARDWARE_ID) } returns 0 every { getColumnIndexOrThrow(DatabaseContract.HARDWARE_IDENTIFICATION_COLUMN_NAME_SALT) } returns 1 every { getColumnIndexOrThrow(DatabaseContract.HARDWARE_IDENTIFICATION_COLUMN_NAME_IV) } returns 2 - every { getString(0) } returns HardwareIdProviderTest.ENCRYPTED_HARDWARE_ID - every { getString(1) } returns HardwareIdProviderTest.SALT - every { getString(2) } returns HardwareIdProviderTest.IV + every { getString(0) } returns ENCRYPTED_HARDWARE_ID + every { getString(1) } returns SALT + every { getString(2) } returns IV } - val mockContext: Context = mockk() every { - mockContext.contentResolver.query( + mockEmarsysContentResolver.query( any(), any(), any(), @@ -101,7 +97,7 @@ class HardwareIdContentResolverTest { ) } returns mockCursor val contentResolver = HardwareIdContentResolver( - mockContext, + mockEmarsysContentResolver, mockHardwareIdentificationCrypto, SHARED_PACKAGE_NAMES ) @@ -114,7 +110,11 @@ class HardwareIdContentResolverTest { @Test fun testProvideHardwareId_shouldReturnFalse_whenSharedPackageNamesIsMissing() { val contentResolver = - HardwareIdContentResolver(mockContext, mockHardwareIdentificationCrypto, null) + HardwareIdContentResolver( + mockEmarsysContentResolver, + mockHardwareIdentificationCrypto, + null + ) val result = contentResolver.resolveHardwareId() diff --git a/core/src/main/java/com/emarsys/core/activity/ActivityLifecycleActionRegistry.kt b/core/src/main/java/com/emarsys/core/activity/ActivityLifecycleActionRegistry.kt index 356d942a..2a8d6364 100644 --- a/core/src/main/java/com/emarsys/core/activity/ActivityLifecycleActionRegistry.kt +++ b/core/src/main/java/com/emarsys/core/activity/ActivityLifecycleActionRegistry.kt @@ -14,7 +14,7 @@ class ActivityLifecycleActionRegistry( val triggerOnActivityActions: MutableList = mutableListOf() fun execute(activity: Activity?, lifecycles: List) { - concurrentHandlerHolder.coreHandler.post { + concurrentHandlerHolder.post { (lifecycleActions + triggerOnActivityActions) .filter { lifecycles.contains(it.triggeringLifecycle) @@ -33,7 +33,7 @@ class ActivityLifecycleActionRegistry( } fun addTriggerOnActivityAction(activityLifecycleAction: ActivityLifecycleAction) { - concurrentHandlerHolder.coreHandler.post { + concurrentHandlerHolder.post { val currentActivity = currentActivityProvider.get() triggerOnActivityActions.add(activityLifecycleAction) if (currentActivity != null) { diff --git a/core/src/main/java/com/emarsys/core/contentresolver/EmarsysContentResolver.kt b/core/src/main/java/com/emarsys/core/contentresolver/EmarsysContentResolver.kt new file mode 100644 index 00000000..071d4f8b --- /dev/null +++ b/core/src/main/java/com/emarsys/core/contentresolver/EmarsysContentResolver.kt @@ -0,0 +1,18 @@ +package com.emarsys.core.contentresolver + +import android.content.Context +import android.database.Cursor +import android.net.Uri +import com.emarsys.core.Mockable + +@Mockable +class EmarsysContentResolver(private val context: Context) { + + fun query( + uri: Uri, + projection: Array?, selection: String?, + selectionArgs: Array?, sortOrder: String? + ): Cursor? { + return context.contentResolver.query(uri, projection, selection, selectionArgs, sortOrder) + } +} \ No newline at end of file diff --git a/core/src/main/java/com/emarsys/core/contentresolver/hardwareid/HardwareIdContentResolver.kt b/core/src/main/java/com/emarsys/core/contentresolver/hardwareid/HardwareIdContentResolver.kt index c92e688a..db411456 100644 --- a/core/src/main/java/com/emarsys/core/contentresolver/hardwareid/HardwareIdContentResolver.kt +++ b/core/src/main/java/com/emarsys/core/contentresolver/hardwareid/HardwareIdContentResolver.kt @@ -1,14 +1,16 @@ package com.emarsys.core.contentresolver.hardwareid -import android.content.Context import com.emarsys.core.Mockable +import com.emarsys.core.contentresolver.EmarsysContentResolver import com.emarsys.core.crypto.HardwareIdentificationCrypto import com.emarsys.core.database.DatabaseContract @Mockable -class HardwareIdContentResolver(private val context: Context, - private val crypto: HardwareIdentificationCrypto, - private val sharedPackageNames: List?) { +class HardwareIdContentResolver( + private val emarsysContentResolver: EmarsysContentResolver, + private val crypto: HardwareIdentificationCrypto, + private val sharedPackageNames: List? +) { fun resolveHardwareId(): String? { var index = 0 @@ -16,15 +18,22 @@ class HardwareIdContentResolver(private val context: Context, var encryptedHardwareId: String? = null if (sharedPackageNames != null) { while (encryptedHardwareId == null && index < sharedPackageNames.size) { - val cursor = context.contentResolver.query(DatabaseContract.getHardwareIdProviderUri(sharedPackageNames[index]), - arrayOf(DatabaseContract.HARDWARE_IDENTIFICATION_COLUMN_NAME_ENCRYPTED_HARDWARE_ID, - DatabaseContract.HARDWARE_IDENTIFICATION_COLUMN_NAME_SALT, - DatabaseContract.HARDWARE_IDENTIFICATION_COLUMN_NAME_IV), - null, null, null) + val cursor = emarsysContentResolver.query( + DatabaseContract.getHardwareIdProviderUri(sharedPackageNames[index]), + arrayOf( + DatabaseContract.HARDWARE_IDENTIFICATION_COLUMN_NAME_ENCRYPTED_HARDWARE_ID, + DatabaseContract.HARDWARE_IDENTIFICATION_COLUMN_NAME_SALT, + DatabaseContract.HARDWARE_IDENTIFICATION_COLUMN_NAME_IV + ), + null, null, null + ) if (cursor != null && cursor.moveToFirst()) { - encryptedHardwareId = cursor.getString(cursor.getColumnIndexOrThrow(DatabaseContract.HARDWARE_IDENTIFICATION_COLUMN_NAME_ENCRYPTED_HARDWARE_ID)) - val salt = cursor.getString(cursor.getColumnIndexOrThrow(DatabaseContract.HARDWARE_IDENTIFICATION_COLUMN_NAME_SALT)) - val iv = cursor.getString(cursor.getColumnIndexOrThrow(DatabaseContract.HARDWARE_IDENTIFICATION_COLUMN_NAME_IV)) + encryptedHardwareId = + cursor.getString(cursor.getColumnIndexOrThrow(DatabaseContract.HARDWARE_IDENTIFICATION_COLUMN_NAME_ENCRYPTED_HARDWARE_ID)) + val salt = + cursor.getString(cursor.getColumnIndexOrThrow(DatabaseContract.HARDWARE_IDENTIFICATION_COLUMN_NAME_SALT)) + val iv = + cursor.getString(cursor.getColumnIndexOrThrow(DatabaseContract.HARDWARE_IDENTIFICATION_COLUMN_NAME_IV)) sharedHardwareId = crypto.decrypt(encryptedHardwareId, salt, iv) cursor.close() } diff --git a/core/src/main/java/com/emarsys/core/handler/ConcurrentHandlerHolder.kt b/core/src/main/java/com/emarsys/core/handler/ConcurrentHandlerHolder.kt index 6d079fdf..cd12ccc8 100644 --- a/core/src/main/java/com/emarsys/core/handler/ConcurrentHandlerHolder.kt +++ b/core/src/main/java/com/emarsys/core/handler/ConcurrentHandlerHolder.kt @@ -17,7 +17,13 @@ class ConcurrentHandlerHolder( val backgroundLooper = backgroundHandler.handler.looper fun post(runnable: Runnable) { - coreHandler.post(runnable) + if (coreHandler.handler.looper.thread.state != Thread.State.TERMINATED) { + coreHandler.post(runnable) + } else { + postOnMain { + coreHandler.post(runnable) + } + } } fun postOnMain(runnable: Runnable) { 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 d1226a80..92c5679f 100644 --- a/emarsys-sdk/src/main/java/com/emarsys/di/DefaultEmarsysComponent.kt +++ b/emarsys-sdk/src/main/java/com/emarsys/di/DefaultEmarsysComponent.kt @@ -32,6 +32,7 @@ import com.emarsys.core.app.AppLifecycleObserver import com.emarsys.core.concurrency.ConcurrentHandlerHolderFactory import com.emarsys.core.connection.ConnectionProvider import com.emarsys.core.connection.ConnectionWatchDog +import com.emarsys.core.contentresolver.EmarsysContentResolver import com.emarsys.core.contentresolver.hardwareid.HardwareIdContentResolver import com.emarsys.core.crypto.Crypto import com.emarsys.core.crypto.HardwareIdentificationCrypto @@ -452,8 +453,9 @@ open class DefaultEmarsysComponent(config: EmarsysConfig) : EmarsysComponent { override val hardwareIdProvider: HardwareIdProvider by lazy { val hardwareRepository = HardwareRepository(coreDbHelper, concurrentHandlerHolder) val hardwareIdentificationCrypto = HardwareIdentificationCrypto(config.sharedSecret, crypto) + val emarsysContentResolver = EmarsysContentResolver(config.application) val hardwareIdContentResolver = HardwareIdContentResolver( - config.application, + emarsysContentResolver, hardwareIdentificationCrypto, config.sharedPackageNames ) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a26472e0..14463451 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ androidx-navigation-compose = "2.7.6" compose-compiler = "1.5.6" compose-plugin = "1.6.0-dev1419" android-compileSdk = "34" -android-minSdk = "28" +android-minSdk = "26" android-targetSdk = "34" androidx-activity = "1.8.2" androidx-activityCompose = "1.8.2"