Coverage Summary for Class: TrackingIdsResolverImpl (cloud.mindbox.mobile_sdk.managers)
| Class |
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| TrackingIdsResolverImpl |
100%
(6/6)
|
100%
(6/6)
|
100%
(25/25)
|
100%
(196/196)
|
| TrackingIdsResolverImpl$1 |
0%
(0/1)
|
|
0%
(0/1)
|
0%
(0/2)
|
| TrackingIdsResolverImpl$2 |
0%
(0/1)
|
|
0%
(0/1)
|
0%
(0/2)
|
| TrackingIdsResolverImpl$lastSent$1 |
100%
(1/1)
|
75%
(6/8)
|
100%
(4/4)
|
95.7%
(45/47)
|
| TrackingIdsResolverImpl$markSent$1 |
100%
(1/1)
|
100%
(2/2)
|
100%
(2/2)
|
100%
(39/39)
|
| TrackingIdsResolverImpl$markSent$1$1 |
100%
(1/1)
|
|
100%
(1/1)
|
100%
(3/3)
|
| TrackingIdsResolverImpl$mergeWithLastSent$$inlined$sortedBy$1 |
0%
(0/1)
|
|
| TrackingIdsResolverImpl$mergeWithLastSent$1 |
100%
(1/1)
|
|
100%
(1/1)
|
100%
(3/3)
|
| TrackingIdsResolverImpl$resolve$1 |
|
| TrackingIdsResolverImpl$resolve$reading$1 |
100%
(1/1)
|
|
100%
(1/1)
|
100%
(16/16)
|
| TrackingIdsResolverImpl$resolve$results$1 |
100%
(1/1)
|
|
100%
(1/1)
|
100%
(20/20)
|
| Total |
80%
(12/15)
|
87.5%
(14/16)
|
94.6%
(35/37)
|
98.2%
(322/328)
|
package cloud.mindbox.mobile_sdk.managers
import android.content.Context
import cloud.mindbox.mobile_sdk.Mindbox
import cloud.mindbox.mobile_sdk.logger.mindboxLogI
import cloud.mindbox.mobile_sdk.models.TrackingId
import cloud.mindbox.mobile_sdk.pushes.PushServiceHandler
import cloud.mindbox.mobile_sdk.pushes.TrackingIdResult
import cloud.mindbox.mobile_sdk.repository.MindboxPreferences
import cloud.mindbox.mobile_sdk.utils.loggingRunCatching
import com.google.gson.Gson
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.withTimeoutOrNull
import kotlin.time.Duration.Companion.milliseconds
private const val READ_TRACKING_IDS_TIMEOUT = 5000L
internal interface TrackingIdsResolver {
suspend fun resolve(context: Context): List<TrackingId>
fun hasChanged(trackingIds: List<TrackingId>): Boolean
fun markSent(trackingIds: List<TrackingId>)
}
internal class TrackingIdsResolverImpl(
private val pushServiceHandlers: () -> List<PushServiceHandler> = { Mindbox.pushServiceHandlers },
private val scope: () -> CoroutineScope = { Mindbox.mindboxScope },
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO,
private val timeoutMillis: Long = READ_TRACKING_IDS_TIMEOUT,
) : TrackingIdsResolver {
private val gson = Gson()
override suspend fun resolve(context: Context): List<TrackingId> {
if (!MindboxPreferences.shouldCollectTrackingIds) return emptyList()
val reading = scope().async(ioDispatcher) {
pushServiceHandlers().map { handler -> handler.tryGetTrackingId(context) }
}
val results = withTimeoutOrNull(timeoutMillis.milliseconds) { reading.await() }
if (results == null) {
reading.cancel()
mindboxLogI("Timed out reading tracking id providers, repeating the last reported set")
return lastSent()
}
return results.mergeWithLastSent()
}
override fun hasChanged(trackingIds: List<TrackingId>): Boolean = trackingIds != lastSent()
override fun markSent(trackingIds: List<TrackingId>): Unit = loggingRunCatching {
MindboxPreferences.lastSentTrackingIds = gson.toJson(trackingIds)
mindboxLogI("Sent tracking ids: ${trackingIds.joinToString { it.type }.ifEmpty { "none" }}")
}
private fun lastSent(): List<TrackingId> = loggingRunCatching(defaultValue = emptyList()) {
MindboxPreferences.lastSentTrackingIds
.takeIf { it.isNotBlank() }
?.let { gson.fromJson(it, Array<TrackingId>::class.java)?.toList() }
?: emptyList()
}
private fun List<TrackingIdResult>.mergeWithLastSent(): List<TrackingId> {
val fresh = filterIsInstance<TrackingIdResult.Success>().map { it.trackingId }
val answered = fresh.map { it.type }.toSet() +
filterIsInstance<TrackingIdResult.Denied>().map { it.type }
val kept = lastSent().filterNot { it.type in answered }
if (kept.isNotEmpty()) {
mindboxLogI("Keeping tracking ids we could not read: ${kept.joinToString { it.type }}")
}
return (fresh + kept)
.sortedBy { it.type }
.distinctBy { it.type }
}
}