Coverage Summary for Class: MindboxEventManager (cloud.mindbox.mobile_sdk.managers)
| Class |
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| MindboxEventManager |
47.8%
(11/23)
|
25%
(2/8)
|
47.2%
(17/36)
|
50%
(117/234)
|
| MindboxEventManager$appInfoUpdate$1 |
100%
(1/1)
|
|
100%
(4/4)
|
100%
(21/21)
|
| MindboxEventManager$appInstalled$1 |
100%
(1/1)
|
50%
(1/2)
|
80%
(4/5)
|
89.7%
(26/29)
|
| MindboxEventManager$appKeepalive$1 |
0%
(0/1)
|
|
0%
(0/4)
|
0%
(0/21)
|
| MindboxEventManager$appStarted$1 |
0%
(0/1)
|
|
0%
(0/3)
|
0%
(0/19)
|
| MindboxEventManager$asyncOperation$1 |
100%
(1/1)
|
|
100%
(1/1)
|
100%
(19/19)
|
| MindboxEventManager$asyncOperation$1$1 |
100%
(1/1)
|
|
100%
(4/4)
|
100%
(50/50)
|
| MindboxEventManager$asyncOperation$1$1$1 |
100%
(1/1)
|
50%
(6/12)
|
55%
(11/20)
|
66.7%
(52/78)
|
| MindboxEventManager$createSyncEvent$1 |
0%
(0/1)
|
|
0%
(0/1)
|
0%
(0/19)
|
| MindboxEventManager$pushClicked$1 |
0%
(0/1)
|
|
0%
(0/3)
|
0%
(0/19)
|
| MindboxEventManager$sendEventsIfExist$1 |
0%
(0/1)
|
0%
(0/2)
|
0%
(0/2)
|
0%
(0/10)
|
| MindboxEventManager$syncOperation$1 |
0%
(0/1)
|
0%
(0/6)
|
0%
(0/14)
|
0%
(0/57)
|
| MindboxEventManager$syncOperation$2 |
0%
(0/1)
|
0%
(0/2)
|
0%
(0/10)
|
0%
(0/30)
|
| MindboxEventManager$timeProvider$2 |
100%
(1/1)
|
|
100%
(1/1)
|
100%
(2/2)
|
| Total |
47.2%
(17/36)
|
28.1%
(9/32)
|
38.9%
(42/108)
|
47.2%
(287/608)
|
package cloud.mindbox.mobile_sdk.managers
import android.content.Context
import cloud.mindbox.mobile_sdk.InitializeLock
import cloud.mindbox.mobile_sdk.Mindbox
import cloud.mindbox.mobile_sdk.di.MindboxDI
import cloud.mindbox.mobile_sdk.di.mindboxInject
import cloud.mindbox.mobile_sdk.logger.MindboxLoggerImpl
import cloud.mindbox.mobile_sdk.logger.mindboxLogI
import cloud.mindbox.mobile_sdk.logger.mindboxLogW
import cloud.mindbox.mobile_sdk.models.*
import cloud.mindbox.mobile_sdk.models.operation.OperationResponseBaseInternal
import cloud.mindbox.mobile_sdk.repository.MindboxPreferences
import cloud.mindbox.mobile_sdk.services.BackgroundWorkManager
import cloud.mindbox.mobile_sdk.utils.loggingRunCatching
import com.google.gson.Gson
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.launch
import java.util.concurrent.Executors
internal object MindboxEventManager {
private const val EMPTY_JSON_OBJECT = "{}"
private const val NULL_JSON = "null"
const val IN_APP_OPERATION_VIEW_TYPE = "Inapp.Show"
const val IN_APP_OPERATION_CLICK_TYPE = "Inapp.Click"
const val IN_APP_OPERATION_TARGETING_TYPE = "Inapp.Targeting"
const val IN_APP_OPERATION_SHOW_FAILURE_TYPE = "Inapp.ShowFailure"
private val gson = Gson()
val eventFlow = MutableSharedFlow<InAppEventType>(replay = 20)
private val poolDispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
private val timeProvider by mindboxInject { timeProvider }
fun appInstalled(
context: Context,
initData: InitData,
shouldCreateCustomer: Boolean,
): Unit = loggingRunCatching {
val eventType = if (shouldCreateCustomer) {
EventType.AppInstalled
} else {
EventType.AppInstalledWithoutCustomer
}
asyncOperation(context, Event(eventType = eventType, body = gson.toJson(initData)))
updateLastInfoUpdateTime()
}
fun appInfoUpdate(
context: Context,
initData: UpdateData,
): Unit = loggingRunCatching {
asyncOperation(
context,
Event(eventType = EventType.AppInfoUpdated, body = gson.toJson(initData)),
)
updateLastInfoUpdateTime()
}
fun appKeepalive(
context: Context,
initData: UpdateData,
): Unit = loggingRunCatching {
asyncOperation(
context,
Event(eventType = EventType.AppKeepalive, body = gson.toJson(initData)),
)
updateLastInfoUpdateTime()
}
fun inAppShown(context: Context, body: String) {
asyncOperation(context, IN_APP_OPERATION_VIEW_TYPE, body)
}
fun inAppClicked(context: Context, body: String) {
asyncOperation(context, IN_APP_OPERATION_CLICK_TYPE, body)
}
fun sendUserTargeted(context: Context, body: String) {
asyncOperation(context, IN_APP_OPERATION_TARGETING_TYPE, body)
}
fun inAppShowFailure(context: Context, body: String) {
asyncOperation(context, IN_APP_OPERATION_SHOW_FAILURE_TYPE, body)
}
fun pushClicked(
context: Context,
clickData: TrackClickData,
): Unit = loggingRunCatching {
asyncOperation(
context,
Event(eventType = EventType.PushClicked, body = gson.toJson(clickData)),
)
}
fun appStarted(
context: Context,
trackVisitData: TrackVisitData,
): Unit = loggingRunCatching {
asyncOperation(
context,
Event(eventType = EventType.TrackVisit, body = gson.toJson(trackVisitData)),
)
}
fun asyncOperation(context: Context, name: String, body: String): Unit =
asyncOperation(
context,
Event(
eventType = EventType.AsyncOperation(name),
body = if (body.isNotBlank() && body != NULL_JSON) body else EMPTY_JSON_OBJECT,
),
)
fun appStarted(): InAppEventType.AppStartup {
return InAppEventType.AppStartup
}
private fun asyncOperation(
context: Context,
event: Event,
): Unit = loggingRunCatching {
Mindbox.mindboxScope.launch(poolDispatcher) {
InitializeLock.await(InitializeLock.State.SAVE_MINDBOX_CONFIG)
DbManager.addEventToQueue(context, event)
eventFlow.emit(InAppEventType.OrdinalEvent(event.eventType, event.body))
loggingRunCatching {
val configuration = DbManager.getConfigurations()
val deviceUuid = MindboxPreferences.deviceUuid
val isInstallEvent = event.eventType is EventType.AppInstalled ||
event.eventType is EventType.AppInstalledWithoutCustomer
val isInitialized = !MindboxPreferences.isFirstInitialize || isInstallEvent
if (!isInitialized || configuration == null) {
this@MindboxEventManager.mindboxLogW(
"Event ${event.eventType.operation} will be sent later, " +
"because configuration was not initialized"
)
this@MindboxEventManager.mindboxLogI(
"isFirstInitialize: ${MindboxPreferences.isFirstInitialize}, " +
"isInstallEvent: $isInstallEvent, configuration is null: ${configuration == null}"
)
} else {
WorkerDelegate().sendEvent(
context = context,
configuration = configuration,
deviceUuid = deviceUuid,
event = event,
parent = this@MindboxEventManager,
shouldStartWorker = true,
shouldCountOffset = false
)
if (isInstallEvent) MindboxPreferences.isFirstInitialize = false
}
}
}
}
fun <T, V : OperationResponseBaseInternal> syncOperation(
name: String,
body: T,
classOfV: Class<V>,
onSuccess: (V) -> Unit,
onError: (MindboxError) -> Unit,
): Unit = loggingRunCatching {
val configuration = checkConfiguration(onError) ?: return@loggingRunCatching
val json = gson.toJson(body)
MindboxLoggerImpl.d(this, "syncOperation. json: $json")
val jsonBody = if (json.isNotBlank() && json != NULL_JSON) json else EMPTY_JSON_OBJECT
val event = createSyncEvent(name, jsonBody)
val deviceUuid = MindboxPreferences.deviceUuid
MindboxDI.appModule.gatewayManager.sendEvent(
configuration = configuration,
deviceUuid = deviceUuid,
event = event,
classOfT = classOfV,
shouldCountOffset = false,
onSuccess = onSuccess,
onError = onError,
)
}
fun syncOperation(
name: String,
bodyJson: String,
onSuccess: (String) -> Unit,
onError: (MindboxError) -> Unit,
): Unit = loggingRunCatching {
val configuration = checkConfiguration(onError) ?: return@loggingRunCatching
val event = createSyncEvent(name, bodyJson)
val deviceUuid = MindboxPreferences.deviceUuid
MindboxDI.appModule.gatewayManager.sendEvent(
configuration = configuration,
deviceUuid = deviceUuid,
event = event,
shouldCountOffset = false,
onSuccess = onSuccess,
onError = onError,
)
}
private fun createSyncEvent(
name: String,
bodyJson: String,
): Event {
val eventType = EventType.SyncOperation(name)
Mindbox.mindboxScope.launch {
eventFlow.emit(InAppEventType.OrdinalEvent(eventType, bodyJson))
}
return Event(eventType = eventType, body = bodyJson)
}
private fun checkConfiguration(onError: (MindboxError) -> Unit): Configuration? {
val configuration = DbManager.getConfigurations()
if (MindboxPreferences.isFirstInitialize || configuration == null) {
MindboxLoggerImpl.e(this, "Configuration was not initialized")
onError.invoke(MindboxError.Unknown())
return null
}
return configuration
}
fun sendEventsIfExist(context: Context): Unit = loggingRunCatching {
if (DbManager.getFilteredEventsForBackgroundSend().isNotEmpty()) {
BackgroundWorkManager.startOneTimeService(context)
}
}
fun <T> operationBodyJson(body: T): String = gson.toJson(body)
@OptIn(ExperimentalCoroutinesApi::class)
fun resetEventFlowCache() {
eventFlow.resetReplayCache()
}
private fun updateLastInfoUpdateTime() {
MindboxPreferences.lastInfoUpdateTime = timeProvider.currentTimeMillis()
}
}