Coverage Summary for Class: MigrationManager (cloud.mindbox.mobile_sdk.utils)
| Class |
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| MigrationManager |
100%
(7/7)
|
50%
(4/8)
|
100%
(29/29)
|
98.5%
(201/204)
|
| MigrationManager$gson$2 |
100%
(1/1)
|
|
100%
(1/1)
|
100%
(2/2)
|
| MigrationManager$migrateAll$1 |
|
| MigrationManager$migrateAll$3$job$1 |
100%
(1/1)
|
50%
(1/2)
|
100%
(3/3)
|
100%
(22/22)
|
| MigrationManager$Migration |
|
| MigrationManager$timeProvider$2 |
100%
(1/1)
|
|
100%
(1/1)
|
100%
(2/2)
|
| MigrationManager$version2120$1 |
50%
(2/4)
|
12.5%
(2/16)
|
18.8%
(3/16)
|
15.5%
(17/110)
|
| MigrationManager$version2140$1 |
100%
(4/4)
|
75%
(3/4)
|
100%
(11/11)
|
97.2%
(69/71)
|
| MigrationManager$version2140$1$run$newMapString$1 |
100%
(1/1)
|
|
100%
(1/1)
|
100%
(9/9)
|
| MigrationManager$version2140$1$run$newMapString$1$invoke$$inlined$toJsonTyped$1 |
0%
(0/1)
|
|
| MigrationManager$version2140$1$run$oldShownInApps$1 |
100%
(1/1)
|
50%
(1/2)
|
66.7%
(2/3)
|
86.7%
(13/15)
|
| MigrationManager$version2140$1$run$oldShownInApps$1$invoke$$inlined$fromJsonTyped$1 |
0%
(0/1)
|
|
| MigrationManager$version2150$1 |
100%
(4/4)
|
80%
(8/10)
|
100%
(15/15)
|
95.9%
(70/73)
|
| MigrationManager$version290$1 |
100%
(4/4)
|
|
100%
(9/9)
|
100%
(53/53)
|
| MigrationManager$version290$1$run$newMapString$1 |
100%
(1/1)
|
|
100%
(1/1)
|
100%
(10/10)
|
| MigrationManager$version290$1$run$newMapString$1$1 |
100%
(1/1)
|
|
100%
(1/1)
|
100%
(2/2)
|
| MigrationManager$version290$1$run$oldShownInApps$1 |
100%
(1/1)
|
50%
(1/2)
|
75%
(3/4)
|
86.7%
(13/15)
|
| MigrationManager$version290$1$run$oldShownInApps$1$1 |
100%
(1/1)
|
|
100%
(1/1)
|
100%
(2/2)
|
| Total |
88.2%
(30/34)
|
45.5%
(20/44)
|
84.4%
(81/96)
|
82.2%
(485/590)
|
package cloud.mindbox.mobile_sdk.utils
import android.content.Context
import cloud.mindbox.mobile_sdk.InitializeLock
import cloud.mindbox.mobile_sdk.Mindbox
import cloud.mindbox.mobile_sdk.di.mindboxInject
import cloud.mindbox.mobile_sdk.fromJsonTyped
import cloud.mindbox.mobile_sdk.logger.MindboxLog
import cloud.mindbox.mobile_sdk.logger.mindboxLogI
import cloud.mindbox.mobile_sdk.managers.SharedPreferencesManager
import cloud.mindbox.mobile_sdk.models.convertToIso8601String
import cloud.mindbox.mobile_sdk.models.toTimestamp
import cloud.mindbox.mobile_sdk.pushes.PrefPushToken
import cloud.mindbox.mobile_sdk.repository.MindboxPreferences
import cloud.mindbox.mobile_sdk.toJsonTyped
import com.google.gson.reflect.TypeToken
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
internal class MigrationManager(val context: Context) : MindboxLog {
@Volatile
private var isMigrating = false
private val gson by mindboxInject { gson }
private val timeProvider by mindboxInject { timeProvider }
suspend fun migrateAll() {
if (isMigrating) return
mindboxLogI("Check migrations needed")
if (MindboxPreferences.isFirstInitialize) {
MindboxPreferences.versionCode = Constants.SDK_VERSION_CODE
}
isMigrating = true
listOf(
version290(),
version2120(),
version2140(),
version2150()
).filter { it.isNeeded }
.onEach { migration ->
val job = Mindbox.mindboxScope.launch {
if (migration.isNeeded) {
logI("Run migration '${migration.description}'")
migration.run()
}
}
job.join()
}.also {
if (MindboxPreferences.versionCode != Constants.SDK_VERSION_CODE) {
logE("Migrations failed, reset memory")
MindboxPreferences.softReset()
MindboxPreferences.versionCode = Constants.SDK_VERSION_CODE
}
}
InitializeLock.complete(InitializeLock.State.MIGRATION)
}
private interface Migration {
val description: String
val isNeeded: Boolean
suspend fun run()
}
private fun version290() = object : Migration {
override val description: String
get() = "Replaces set of shown inapps to map of inapp metadata"
override val isNeeded: Boolean
get() = MindboxPreferences.shownInAppIds != ""
override suspend fun run() {
val oldShownInApps = LoggingExceptionHandler.runCatching<Set<String>>(HashSet()) {
gson.fromJson(
MindboxPreferences.shownInAppIds,
object : TypeToken<HashSet<String>>() {}.type
) ?: emptySet()
}
val newShownInApps = oldShownInApps.associateWith {
0L
}
val newMapString = LoggingExceptionHandler.runCatching("") {
gson.toJson(newShownInApps, object : TypeToken<HashMap<String, Long>>() {}.type)
}
MindboxPreferences.shownInApps = newMapString
MindboxPreferences.shownInAppIds = ""
}
}
private fun version2120() = object : Migration {
val VERSION_CODE = 2
override val description: String
get() = "Changes the push token save format to multiple tokens with providers."
override val isNeeded: Boolean
get() = (MindboxPreferences.versionCode ?: 0) < VERSION_CODE
override suspend fun run() {
val provider = SharedPreferencesManager.getString("key_notification_provider")
val token = SharedPreferencesManager.getString("key_firebase_token")
val updateDate = SharedPreferencesManager.getString("key_firebase_token_save_date")
SharedPreferencesManager.remove("key_notification_provider")
SharedPreferencesManager.remove("key_firebase_token")
SharedPreferencesManager.remove("key_firebase_token_save_date")
val savedTokens = MindboxPreferences.pushTokens
if (token != null && provider != null && savedTokens.isEmpty()) {
val timestamp: Long? = updateDate?.let {
SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.ENGLISH).parse(it)?.time
}
MindboxPreferences.pushTokens = mapOf(provider to PrefPushToken(token, timestamp ?: Date().time))
}
MindboxPreferences.versionCode = VERSION_CODE
}
}
private fun version2140() = object : Migration {
val VERSION_CODE = 3
override val description: String
get() = "Changes the format of shown in-app messages from Map<String, Long> to Map<String, List<Long>>"
override val isNeeded: Boolean
get() = (MindboxPreferences.versionCode ?: 0) < VERSION_CODE
override suspend fun run() {
val oldShownInApps = loggingRunCatching(emptyMap()) {
gson.fromJsonTyped<Map<String, Long>>(
MindboxPreferences.shownInApps
) ?: emptyMap()
}
val newShownInApps = oldShownInApps.mapValues { (_, timestamp) ->
listOf(timestamp)
}
val newMapString = loggingRunCatching("") {
gson.toJsonTyped<Map<String, List<Long>>>(newShownInApps)
}
MindboxPreferences.shownInApps = newMapString
SharedPreferencesManager.remove("SHOWN_IDS")
MindboxPreferences.versionCode = VERSION_CODE
}
}
private fun version2150() = object : Migration {
val VERSION_CODE = 4
override val description: String
get() = "Stores the first SDK initialization time"
override val isNeeded: Boolean
get() = (MindboxPreferences.versionCode ?: 0) < VERSION_CODE
override suspend fun run() {
if (MindboxPreferences.firstInitializationTime == null) {
val firstInitTimestamp = MindboxPreferences.pushTokens.values
.map { token -> token.updateDate }
.filter { timestamp -> timestamp > 0L }
.minOrNull()
?: timeProvider.currentTimestamp().ms
MindboxPreferences.firstInitializationTime =
firstInitTimestamp
.toTimestamp()
.convertToIso8601String()
}
MindboxPreferences.versionCode = VERSION_CODE
}
}
}