Skip to content

Use a supervisor job and exception hander in UIService #652

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,41 @@
package com.adobe.marketing.mobile.services.ui

import android.app.Application
import com.adobe.marketing.mobile.services.Log
import com.adobe.marketing.mobile.services.ServiceConstants
import com.adobe.marketing.mobile.services.ui.alert.AlertPresentable
import com.adobe.marketing.mobile.services.ui.common.AppLifecycleProvider
import com.adobe.marketing.mobile.services.ui.floatingbutton.FloatingButtonPresentable
import com.adobe.marketing.mobile.services.ui.floatingbutton.FloatingButtonViewModel
import com.adobe.marketing.mobile.services.ui.message.InAppMessagePresentable
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob

/**
* UI Service implementation for AEP SDK
*/
internal class AEPUIService : UIService {
companion object {
private const val LOG_TAG = "AEPUIService"
}

private var presentationDelegate: PresentationDelegate? = null

private val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
Log.error(
ServiceConstants.LOG_TAG,
LOG_TAG,
"An error occurred while processing the presentation: ${throwable.message}",
throwable
)
}

private val mainScope by lazy {
CoroutineScope(Dispatchers.Main + SupervisorJob() + exceptionHandler)
}

@Suppress("UNCHECKED_CAST")
override fun <T : Presentation<T>> create(
presentation: T,
Expand All @@ -44,7 +65,7 @@ internal class AEPUIService : UIService {
presentationDelegate,
presentationUtilityProvider,
AppLifecycleProvider.INSTANCE,
CoroutineScope(Dispatchers.Main)
mainScope
) as Presentable<T>
}

Expand All @@ -53,7 +74,8 @@ internal class AEPUIService : UIService {
presentation,
presentationDelegate,
presentationUtilityProvider,
AppLifecycleProvider.INSTANCE
AppLifecycleProvider.INSTANCE,
mainScope
) as Presentable<T>
}

Expand All @@ -63,7 +85,8 @@ internal class AEPUIService : UIService {
FloatingButtonViewModel(presentation.settings),
presentationDelegate,
presentationUtilityProvider,
AppLifecycleProvider.INSTANCE
AppLifecycleProvider.INSTANCE,
mainScope
) as Presentable<T>
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.adobe.marketing.mobile.services.ui.PresentationUtilityProvider
import com.adobe.marketing.mobile.services.ui.alert.views.AlertScreen
import com.adobe.marketing.mobile.services.ui.common.AEPPresentable
import com.adobe.marketing.mobile.services.ui.common.AppLifecycleProvider
import kotlinx.coroutines.CoroutineScope

/**
* Represents an Alert presentable.
Expand All @@ -33,12 +34,14 @@ internal class AlertPresentable(
val alert: Alert,
presentationDelegate: PresentationDelegate?,
presentationUtilityProvider: PresentationUtilityProvider,
appLifecycleProvider: AppLifecycleProvider
appLifecycleProvider: AppLifecycleProvider,
mainScope: CoroutineScope
) : AEPPresentable<Alert>(
alert,
presentationUtilityProvider,
presentationDelegate,
appLifecycleProvider
appLifecycleProvider,
mainScope
) {
override fun getContent(activityContext: Context): ComposeView {
return ComposeView(activityContext).apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import com.adobe.marketing.mobile.services.ui.Presentation
import com.adobe.marketing.mobile.services.ui.PresentationDelegate
import com.adobe.marketing.mobile.services.ui.PresentationUtilityProvider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.lang.ref.WeakReference
import java.util.Random
Expand All @@ -52,10 +51,10 @@ internal abstract class AEPPresentable<T : Presentation<T>> :
private val presentation: Presentation<T>
private val presentationUtilityProvider: PresentationUtilityProvider
private val presentationDelegate: PresentationDelegate?
private val mainScope: CoroutineScope
private val appLifecycleProvider: AppLifecycleProvider
private val presentationObserver: PresentationObserver
private val activityCompatOwnerUtils: ActivityCompatOwnerUtils
private val mainScope: CoroutineScope
protected val presentationStateManager: PresentationStateManager

@VisibleForTesting internal val contentIdentifier: Int = Random().nextInt()
Expand All @@ -70,15 +69,16 @@ internal abstract class AEPPresentable<T : Presentation<T>> :
presentation: Presentation<T>,
presentationUtilityProvider: PresentationUtilityProvider,
presentationDelegate: PresentationDelegate?,
appLifecycleProvider: AppLifecycleProvider
appLifecycleProvider: AppLifecycleProvider,
mainScope: CoroutineScope
) : this(
presentation,
presentationUtilityProvider,
presentationDelegate,
appLifecycleProvider,
PresentationStateManager(),
ActivityCompatOwnerUtils(),
CoroutineScope(Dispatchers.Main),
mainScope,
PresentationObserver.INSTANCE
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.adobe.marketing.mobile.services.ui.PresentationUtilityProvider
import com.adobe.marketing.mobile.services.ui.common.AEPPresentable
import com.adobe.marketing.mobile.services.ui.common.AppLifecycleProvider
import com.adobe.marketing.mobile.services.ui.floatingbutton.views.FloatingButtonScreen
import kotlinx.coroutines.CoroutineScope

/**
* Represents a presentable floating button presentation
Expand All @@ -35,12 +36,14 @@ internal class FloatingButtonPresentable(
private val floatingButtonViewModel: FloatingButtonViewModel,
presentationDelegate: PresentationDelegate?,
presentationUtilityProvider: PresentationUtilityProvider,
appLifecycleProvider: AppLifecycleProvider
appLifecycleProvider: AppLifecycleProvider,
mainScope: CoroutineScope
) : AEPPresentable<FloatingButton>(
floatingButton,
presentationUtilityProvider,
presentationDelegate,
appLifecycleProvider
appLifecycleProvider,
mainScope
) {
// event handler for the floating button
private val floatingButtonEventHandler = object : FloatingButtonEventHandler {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ internal class InAppMessagePresentable(
inAppMessage,
presentationUtilityProvider,
presentationDelegate,
appLifecycleProvider
appLifecycleProvider,
mainScope
) {

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import com.adobe.marketing.mobile.services.ui.InAppMessage
import com.adobe.marketing.mobile.services.ui.PresentationDelegate
import com.adobe.marketing.mobile.services.ui.PresentationUtilityProvider
import com.adobe.marketing.mobile.services.ui.common.AppLifecycleProvider
import kotlinx.coroutines.CoroutineScope
import org.junit.Before
import org.junit.Test
import org.mockito.Mock
Expand All @@ -40,12 +41,15 @@ class AlertPresentableTest {
@Mock
private lateinit var mockAppLifecycleProvider: AppLifecycleProvider

@Mock
private lateinit var mockScope: CoroutineScope

private lateinit var alertPresentable: AlertPresentable

@Before
fun setUp() {
MockitoAnnotations.openMocks(this)
alertPresentable = AlertPresentable(mockAlert, mockPresentationDelegate, mockPresentationUtilityProvider, mockAppLifecycleProvider)
alertPresentable = AlertPresentable(mockAlert, mockPresentationDelegate, mockPresentationUtilityProvider, mockAppLifecycleProvider, mockScope)
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import com.adobe.marketing.mobile.services.ui.InAppMessage
import com.adobe.marketing.mobile.services.ui.PresentationDelegate
import com.adobe.marketing.mobile.services.ui.PresentationUtilityProvider
import com.adobe.marketing.mobile.services.ui.common.AppLifecycleProvider
import kotlinx.coroutines.CoroutineScope
import org.junit.Before
import org.junit.Test
import org.mockito.Mock
Expand Down Expand Up @@ -47,6 +48,9 @@ class FloatingButtonPresentableTest {
@Mock
private lateinit var mockFloatingButtonSettings: FloatingButtonSettings

@Mock
private lateinit var mockScope: CoroutineScope

private lateinit var floatingButtonPresentable: FloatingButtonPresentable

@Before
Expand All @@ -61,7 +65,8 @@ class FloatingButtonPresentableTest {
mockFloatingButtonViewModel,
mockPresentationDelegate,
mockPresentationUtilityProvider,
mockAppLifecycleProvider
mockAppLifecycleProvider,
mockScope
)

verify(mockFloatingButtonViewModel).onGraphicUpdate(mockFloatingButtonSettings.initialGraphic)
Expand Down