Skip to content

Commit

Permalink
fix/Track show event for control group message
Browse files Browse the repository at this point in the history
  • Loading branch information
michaela-dev committed Apr 7, 2021
1 parent ea14569 commit c705377
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,17 @@ internal class InAppMessageManagerImpl(
messages: List<InAppMessage>,
callback: ((Result<Unit>) -> Unit)?
) = runCatching {
bitmapCache.clearExcept(messages.mapNotNull { it.payload.imageUrl }.filter { it.isNotBlank() })
bitmapCache.clearExcept(
messages.mapNotNull { it.payload }
.mapNotNull { it.imageUrl }
.filter { it.isNotBlank() }
)
var shouldWaitWithPreload = false
if (pendingShowRequests.isNotEmpty()) {
Logger.i(this, "Attempt to show pending in-app message before loading all images.")
val message = pickPendingMessage(false)
if (message != null) {
val imageUrl = message.second.payload.imageUrl
val imageUrl = message.second.payload?.imageUrl
if (imageUrl.isNullOrEmpty()) {
showPendingMessage(message)
} else {
Expand Down Expand Up @@ -124,8 +128,9 @@ internal class InAppMessageManagerImpl(
}
var toPreload = AtomicInteger(messages.size)
messages.forEach {
if (!it.payload.imageUrl.isNullOrEmpty()) {
bitmapCache.preload(it.payload.imageUrl) {
val imageUrl = it.payload?.imageUrl
if (!imageUrl.isNullOrEmpty()) {
bitmapCache.preload(imageUrl) {
toPreload.getAndDecrement()
if (toPreload.get() == 0) {
onPreloaded()
Expand Down Expand Up @@ -165,7 +170,8 @@ internal class InAppMessageManagerImpl(
}

private fun hasImageFor(message: InAppMessage): Boolean {
val result = message.payload.imageUrl.isNullOrEmpty() || bitmapCache.has(message.payload.imageUrl)
val imageUrl = message.payload?.imageUrl
val result = imageUrl.isNullOrEmpty() || bitmapCache.has(imageUrl)
if (!result) {
Logger.i(this, "Image not available for ${message.name}")
}
Expand All @@ -186,9 +192,9 @@ internal class InAppMessageManagerImpl(
)
messages = messages.filter {
(!requireImageLoaded || hasImageFor(it)) &&
it.applyDateFilter(System.currentTimeMillis() / 1000) &&
it.applyEventFilter(eventType, properties, timestamp) &&
it.applyFrequencyFilter(displayStateRepository.get(it), sessionStartDate)
it.applyDateFilter(System.currentTimeMillis() / 1000) &&
it.applyEventFilter(eventType, properties, timestamp) &&
it.applyFrequencyFilter(displayStateRepository.get(it), sessionStartDate)
}
Logger.i(this, "${messages.size} messages available after filtering. Picking highest priority message.")
val highestPriority = messages.mapNotNull { it.priority }.max() ?: 0
Expand Down Expand Up @@ -240,10 +246,20 @@ internal class InAppMessageManagerImpl(
}

private fun show(message: InAppMessage, trackingDelegate: InAppMessageTrackingDelegate) {
if (message.variantId == -1 && message.payload == null) {
Logger.i(this, "Only logging in-app message for control group '${message.name}'")
trackShowEvent(message, trackingDelegate)
return
}
if (message.payload == null) {
Logger.i(this, "Not showing message with empty payload '${message.name}'")
return
}
Logger.i(this, "Attempting to show in-app message '${message.name}'")
val bitmap = if (!message.payload.imageUrl.isNullOrBlank())
bitmapCache.get(message.payload.imageUrl) ?: return
else null
val imageUrl = message.payload.imageUrl
val bitmap = if (!imageUrl.isNullOrBlank())
bitmapCache.get(imageUrl) ?: return
else null
Logger.i(this, "Posting show to main thread with delay ${message.delay ?: 0}ms.")
Handler(Looper.getMainLooper()).postDelayed(
{
Expand All @@ -263,18 +279,22 @@ internal class InAppMessageManagerImpl(
}
)
if (presented != null) {
displayStateRepository.setDisplayed(message, Date())
trackingDelegate.track(message, "show", false)
Exponea.telemetry?.reportEvent(
com.exponea.sdk.telemetry.model.EventType.SHOW_IN_APP_MESSAGE,
hashMapOf("messageType" to message.rawMessageType)
)
trackShowEvent(message, trackingDelegate)
}
},
message.delay ?: 0
)
}

private fun trackShowEvent(message: InAppMessage, trackingDelegate: InAppMessageTrackingDelegate) {
displayStateRepository.setDisplayed(message, Date())
trackingDelegate.track(message, "show", false)
Exponea.telemetry?.reportEvent(
com.exponea.sdk.telemetry.model.EventType.SHOW_IN_APP_MESSAGE,
hashMapOf("messageType" to message.rawMessageType)
)
}

private fun processInAppMessageAction(activity: Activity, button: InAppMessagePayloadButton) {
if (button.buttonType == InAppMessageButtonType.DEEPLINK) {
try {
Expand Down
2 changes: 1 addition & 1 deletion sdk/src/main/java/com/exponea/sdk/models/InAppMessage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ internal data class InAppMessage(
@SerializedName("frequency")
val rawFrequency: String,
@SerializedName("payload")
val payload: InAppMessagePayload,
val payload: InAppMessagePayload?,
@SerializedName("variant_id")
val variantId: Int,
@SerializedName("variant_name")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ internal class InAppMessageManagerImplTest {
arrayListOf(
InAppMessageTest.getInAppMessage(id = "1", priority = 0),
InAppMessageTest.getInAppMessage(id = "2")
)
)
)
every { messagesCache.get() } returns arrayListOf(
InAppMessageTest.getInAppMessage(id = "1", priority = 2),
Expand Down Expand Up @@ -358,7 +358,7 @@ internal class InAppMessageManagerImplTest {
Robolectric.flushForegroundThreadScheduler()

verify(exactly = 1) { inAppMessageDisplayStateRepository.setDisplayed(any(), any()) }
actionCallbackSlot.captured.invoke(mockActivity, InAppMessageTest.getInAppMessage().payload.buttons!![0])
actionCallbackSlot.captured.invoke(mockActivity, InAppMessageTest.getInAppMessage().payload!!.buttons!![0])
verify(exactly = 1) { inAppMessageDisplayStateRepository.setInteracted(any(), any()) }
}

Expand All @@ -384,7 +384,7 @@ internal class InAppMessageManagerImplTest {
Robolectric.flushForegroundThreadScheduler()

verify(exactly = 1) { delegate.track(InAppMessageTest.getInAppMessage(), "show", false) }
actionCallbackSlot.captured.invoke(mockActivity, InAppMessageTest.getInAppMessage().payload.buttons!![0])
actionCallbackSlot.captured.invoke(mockActivity, InAppMessageTest.getInAppMessage().payload!!.buttons!![0])
verify(exactly = 1) { delegate.track(InAppMessageTest.getInAppMessage(), "click", true, "Action") }
dismissedCallbackSlot.captured.invoke()
verify(exactly = 1) { delegate.track(InAppMessageTest.getInAppMessage(), "close", false) }
Expand All @@ -404,7 +404,7 @@ internal class InAppMessageManagerImplTest {
runBlocking { manager.showRandom("session_start", hashMapOf(), null, spyk())?.join() }
Robolectric.flushForegroundThreadScheduler()

val button = InAppMessageTest.getInAppMessage().payload.buttons!![0]
val button = InAppMessageTest.getInAppMessage().payload!!.buttons!![0]
assertNull(shadowOf(mockActivity).nextStartedActivityForResult)
actionCallbackSlot.captured.invoke(mockActivity, button)
assertEquals(
Expand Down Expand Up @@ -473,7 +473,7 @@ internal class InAppMessageManagerImplTest {
messagesCache.get()
bitmapCache.preload("pending_image_url", any())
bitmapCache.get("pending_image_url")
presenter.show(InAppMessageType.MODAL, pendingMessage.payload, any(), any(), any(), any())
presenter.show(InAppMessageType.MODAL, pendingMessage.payload!!, any(), any(), any(), any())
bitmapCache.preload("other_image_url_1", any())
bitmapCache.preload("other_image_url_2", any())
}
Expand All @@ -495,11 +495,11 @@ internal class InAppMessageManagerImplTest {
runBlocking { manager.showRandom("session_start", hashMapOf(), null, spyk())?.join() }
Robolectric.getForegroundThreadScheduler().advanceBy(1233, TimeUnit.MILLISECONDS)
verify(exactly = 0) {
presenter.show(InAppMessageType.MODAL, message.payload, any(), any(), any(), any())
presenter.show(InAppMessageType.MODAL, message.payload!!, any(), any(), any(), any())
}
Robolectric.getForegroundThreadScheduler().advanceBy(1, TimeUnit.MILLISECONDS)
verify(exactly = 1) {
presenter.show(InAppMessageType.MODAL, message.payload, any(), any(), any(), any())
presenter.show(InAppMessageType.MODAL, message.payload!!, any(), any(), any(), any())
}
}

Expand All @@ -518,7 +518,30 @@ internal class InAppMessageManagerImplTest {
runBlocking { manager.showRandom("session_start", hashMapOf(), null, spyk())?.join() }
Robolectric.flushForegroundThreadScheduler()
verify {
presenter.show(InAppMessageType.MODAL, message.payload, any(), 1234, any(), any())
presenter.show(InAppMessageType.MODAL, message.payload!!, any(), 1234, any(), any())
}
}

@Test
fun `should track control group message without showing it`() {
val message = InAppMessageTest.getInAppMessage(
payload = null,
variantId = -1,
variantName = "Control group",
timeout = 1234
)
val delegate = spyk<InAppMessageTrackingDelegate>()
every { messagesCache.get() } returns arrayListOf(message)
every { bitmapCache.has(any()) } returns true
every { bitmapCache.get(any()) } returns BitmapFactory.decodeFile("mock-file")
every { fetchManager.fetchInAppMessages(any(), any(), any(), any()) } answers {
thirdArg<(Result<ArrayList<InAppMessage>>) -> Unit>().invoke(Result(true, arrayListOf()))
}
every { presenter.show(any(), any(), any(), any(), any(), any()) } returns mockk()
waitForIt { manager.preload { it() } }
runBlocking { manager.showRandom("session_start", hashMapOf(), null, delegate) }
Robolectric.flushForegroundThreadScheduler()
verify(exactly = 1) { delegate.track(message, "show", false) }
verify(exactly = 0) { presenter.show(any(), any(), any(), any(), any(), any()) }
}
}
28 changes: 28 additions & 0 deletions sdk/src/test/java/com/exponea/sdk/models/InAppMessageTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,34 @@ internal class InAppMessageTest {
)
)
}

fun getInAppMessage(
id: String? = null,
dateFilter: DateFilter? = null,
trigger: EventFilter? = null,
frequency: String? = null,
payload: InAppMessagePayload? = null,
variantId: Int = 0,
variantName: String? = null,
priority: Int? = null,
timeout: Long? = null,
delay: Long? = null
): InAppMessage {
return InAppMessage(
id = id ?: "5dd86f44511946ea55132f29",
name = "Test serving in-app message",
rawMessageType = "modal",
rawFrequency = frequency ?: "unknown",
variantId = variantId,
variantName = variantName ?: "Variant A",
trigger = trigger ?: EventFilter("session_start", arrayListOf()),
dateFilter = dateFilter ?: DateFilter(false, null, null),
priority = priority,
delay = delay,
timeout = timeout,
payload = payload
)
}
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,16 @@ internal class InAppMessageDialogPresenterTest(
fun `should not show dialog without resumed activity`() {
buildActivity(AppCompatActivity::class.java).setup()
val presenter = InAppMessagePresenter(ApplicationProvider.getApplicationContext())
assertNull(presenter.show(inAppMessageType, payload, BitmapFactory.decodeFile("mock-file"), null, mockk(), {}))
val image = BitmapFactory.decodeFile("mock-file")
assertNull(presenter.show(inAppMessageType, payload!!, image, null, mockk(), {}))
}

@Test
fun `should show dialog once and activity is resumed`() {
val presenter = InAppMessagePresenter(ApplicationProvider.getApplicationContext())
buildActivity(AppCompatActivity::class.java).setup().resume()
assertNotNull(
presenter.show(inAppMessageType, payload, BitmapFactory.decodeFile("mock-file"), null, mockk(), {})
presenter.show(inAppMessageType, payload!!, BitmapFactory.decodeFile("mock-file"), null, mockk(), {})
)
}

Expand All @@ -59,7 +60,7 @@ internal class InAppMessageDialogPresenterTest(
val activity = buildActivity(AppCompatActivity::class.java).setup().resume()
val presenter = InAppMessagePresenter(activity.get())
assertNotNull(
presenter.show(inAppMessageType, payload, BitmapFactory.decodeFile("mock-file"), null, mockk(), {})
presenter.show(inAppMessageType, payload!!, BitmapFactory.decodeFile("mock-file"), null, mockk(), {})
)
}

Expand All @@ -68,7 +69,7 @@ internal class InAppMessageDialogPresenterTest(
val presenter = InAppMessagePresenter(ApplicationProvider.getApplicationContext())
buildActivity(AppCompatActivity::class.java).setup().resume()
val presented =
presenter.show(inAppMessageType, payload, BitmapFactory.decodeFile("mock-file"), null, mockk(), {})
presenter.show(inAppMessageType, payload!!, BitmapFactory.decodeFile("mock-file"), null, mockk(), {})
assertNotNull(presented)
presented.dismissedCallback()
buildActivity(AppCompatActivity::class.java).setup().resume().pause()
Expand All @@ -80,7 +81,7 @@ internal class InAppMessageDialogPresenterTest(
val presenter = InAppMessagePresenter(ApplicationProvider.getApplicationContext())
buildActivity(AppCompatActivity::class.java).setup().resume()
val presented =
presenter.show(inAppMessageType, payload, BitmapFactory.decodeFile("mock-file"), null, mockk(), {})
presenter.show(inAppMessageType, payload!!, BitmapFactory.decodeFile("mock-file"), null, mockk(), {})
assertNotNull(presented)
assertNull(presenter.show(inAppMessageType, payload, BitmapFactory.decodeFile("mock-file"), null, mockk(), {}))
presented.dismissedCallback()
Expand All @@ -100,7 +101,7 @@ internal class InAppMessageDialogPresenterTest(
val presenter = InAppMessagePresenter(activity.get())
val dismiss = spyk<() -> Unit>()
val presented =
presenter.show(inAppMessageType, payload, BitmapFactory.decodeFile("mock-file"), 1234, mockk(), dismiss)
presenter.show(inAppMessageType, payload!!, BitmapFactory.decodeFile("mock-file"), 1234, mockk(), dismiss)

mockkObject(Exponea)
every { Exponea.presentedInAppMessage } returns presented
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ internal class InAppMessageDialogTest {
val dialog = InAppMessageDialog(
ApplicationProvider.getApplicationContext<Context>(),
true,
payload,
payload!!,
BitmapFactory.decodeFile("mock-file"),
{},
{}
Expand Down

0 comments on commit c705377

Please sign in to comment.