Skip to content

Commit

Permalink
feat: send impression and push primer analytics events (RMCCX-6936, R…
Browse files Browse the repository at this point in the history
…MCCX-6937)
  • Loading branch information
maureenorea-clores authored Jul 29, 2024
1 parent df463db commit 391fb13
Show file tree
Hide file tree
Showing 20 changed files with 272 additions and 190 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.rakuten.tech.mobile.analytics

class RatTracker {
companion object {
fun event(type: String, parameters: Map<String, Any>): Event = Event(type, parameters)
}
}
2 changes: 2 additions & 0 deletions inappmessaging/USERGUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,8 @@ All the events "launch the app event, login event, purchase successful event, cu
- RMCCX-6711: Supported redirecting to App Notification Settings on tapping PushPrimer button action.
- RMCCX-6706: Prevented showing Push Primer campaign for unsupported devices (Android 12 and below) and when push permission is granted.
- RMCCX-6711: Limited CustomJson feature to RMC SDK.
- RMCCX-6936: Supported sending `_rem_rmc_iam_impressions` event to app and SDK RAT accounts upon impression.
- RMCCX-6937: Supported sending `_rem_rmc_iam_pushprimer` event to app and SDK RAT accounts upon selection from the native push permission prompt.

#### 7.5.0 (2023-12-12)
* SDKCF-6575: Added sending of device Id in all IAM requests.
Expand Down
3 changes: 3 additions & 0 deletions inappmessaging/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ android {
resValue 'string', 'inappmessaging__version', project.version
versionName version
consumerProguardFiles 'proguard-rules.pro'

buildConfigField("boolean", "IS_CACHE_HANDLING", "true")
buildConfigField("String","VERSION_NAME","\"${defaultConfig.versionName}\"")
buildConfigField("int", "IAM_RAT_ACC", CONFIG.property("IAM_RAT_ACC"))
buildConfigField("int", "IAM_RAT_AID", CONFIG.property("IAM_RAT_AID"))

resValue("string", "config_url", CONFIG.property("CONFIG_URL_TEST_PROD") ?: "")
resValue("string", "test_sub_key", CONFIG.property("IAM_TEST_SUBSCRIPTION_KEY") ?: "test_sub_key")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ package com.rakuten.tech.mobile.inappmessaging.runtime

import android.text.TextUtils
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.ClassUtil
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppLogger

internal object EventTrackerHelper {

private const val TAG = "EventTrackerHelper"

/**
* This method sends event data to Analytics module for processing.
* This method will only send the analytics event when the real Event class exists at
Expand All @@ -15,6 +18,8 @@ internal object EventTrackerHelper {
* @param data the given Event parameters to be tracked.
* @return true if the analytics event has been sent, false otherwise.
*/
@SuppressWarnings("TooGenericExceptionCaught")
@JvmStatic
fun sendEvent(eventName: String, data: Map<String, *>?): Boolean {
if (!TextUtils.isEmpty(eventName)) {
val serializableData: HashMap<String, *> = when (data) {
Expand All @@ -23,9 +28,13 @@ internal object EventTrackerHelper {
else -> HashMap(data)
}

if (ClassUtil.hasClass("com.rakuten.tech.mobile.analytics.Event")) {
com.rakuten.tech.mobile.analytics.Event(eventName, serializableData).track()
return true
if (ClassUtil.hasClass("com.rakuten.tech.mobile.analytics.RatTracker")) {
try {
com.rakuten.tech.mobile.analytics.RatTracker.event(eventName, serializableData).track()
return true
} catch (e: Exception) {
InAppLogger(TAG).warn("Could not send event: $e")
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.annotation.RestrictTo
import androidx.annotation.RestrictTo.Scope.LIBRARY
import com.rakuten.tech.mobile.inappmessaging.runtime.data.enums.EventType
import com.rakuten.tech.mobile.inappmessaging.runtime.data.models.Attribute
import com.rakuten.tech.mobile.inappmessaging.runtime.manager.AnalyticsKey
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants
import org.jetbrains.annotations.NotNull
import java.util.Locale
Expand Down Expand Up @@ -72,8 +73,8 @@ abstract class BaseEvent(
@NotNull
override fun getRatEventMap(): Map<String, Any> {
val map = HashMap<String, Any>()
map[InAppMessagingConstants.RAT_EVENT_KEY_EVENT_NAME] = eventName
map[InAppMessagingConstants.RAT_EVENT_KEY_EVENT_TIMESTAMP] = timestamp
map[AnalyticsKey.EVENT_NAME.key] = eventName
map[AnalyticsKey.TIMESTAMP.key] = timestamp
return Collections.unmodifiableMap(map)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import com.rakuten.tech.mobile.inappmessaging.runtime.data.enums.EventType
import com.rakuten.tech.mobile.inappmessaging.runtime.data.enums.ValueType
import com.rakuten.tech.mobile.inappmessaging.runtime.data.models.Attribute
import com.rakuten.tech.mobile.inappmessaging.runtime.data.models.rat.RatAttribute
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants
import com.rakuten.tech.mobile.inappmessaging.runtime.manager.AnalyticsKey
import org.jetbrains.annotations.NotNull
import java.util.Collections
import java.util.Date
Expand Down Expand Up @@ -92,7 +92,7 @@ class CustomEvent(@NonNull eventName: String) : BaseEvent(EventType.CUSTOM, even

// Inherit basic attributes, and add custom attributes.
val map = HashMap(super.getRatEventMap())
map[InAppMessagingConstants.RAT_EVENT_KEY_EVENT_CUSTOM_ATTRIBUTE] = ratAttributeList
map[AnalyticsKey.CUSTOM_ATTRIBUTES.key] = ratAttributeList

return Collections.unmodifiableMap(map)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import com.rakuten.tech.mobile.inappmessaging.runtime.data.enums.EventType
import com.rakuten.tech.mobile.inappmessaging.runtime.data.enums.ValueType
import com.rakuten.tech.mobile.inappmessaging.runtime.data.models.Attribute
import com.rakuten.tech.mobile.inappmessaging.runtime.data.models.rat.RatAttribute
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants
import com.rakuten.tech.mobile.inappmessaging.runtime.manager.AnalyticsKey
import org.jetbrains.annotations.NotNull
import java.util.Collections
import kotlin.collections.ArrayList
Expand Down Expand Up @@ -84,7 +84,7 @@ class PurchaseSuccessfulEvent : BaseEvent(EventType.PURCHASE_SUCCESSFUL, EventTy

// Inherit basic attributes, and add custom attributes.
val map = HashMap(super.getRatEventMap())
map[InAppMessagingConstants.RAT_EVENT_KEY_EVENT_CUSTOM_ATTRIBUTE] = attributeList
map[AnalyticsKey.CUSTOM_ATTRIBUTES.key] = attributeList

return Collections.unmodifiableMap(map)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.rakuten.tech.mobile.inappmessaging.runtime.manager

import com.rakuten.tech.mobile.inappmessaging.runtime.BuildConfig
import com.rakuten.tech.mobile.inappmessaging.runtime.EventTrackerHelper
import com.rakuten.tech.mobile.inappmessaging.runtime.RmcHelper
import com.rakuten.tech.mobile.inappmessaging.runtime.data.repositories.HostAppInfoRepository

internal enum class AnalyticsEvent(val iamName: String?, val rmcName: String?) {
IMPRESSION("_rem_iam_impressions", "_rem_rmc_iam_impressions"),
PUSH_PRIMER(null, "_rem_rmc_iam_pushprimer"),
}

internal enum class AnalyticsKey(val key: String) {
EVENT_NAME("eventName"),
CUSTOM_ATTRIBUTES("customAttributes"),
CAMPAIGN_ID("campaign_id"),
SUBS_ID("subscription_id"),
DEVICE_ID("device_id"),
TIMESTAMP("timestamp"),
CUSTOM_PARAM("cp"),
ACCOUNT("acc"),
APP_ID("aid"),
IMPRESSIONS("impressions"),
PUSH_PERMISSION("push_permission"),
}

internal object AnalyticsManager {

/**
* Sends the event [analyticsEvent]. For RMC, the event is sent to both the host app account and SDK account.
* This method attaches common metadata to the event such as Device Id etc., so only add custom information that is
* specific to the event on [data].
*/
@SuppressWarnings("LongMethod")
@JvmStatic
fun sendEvent(analyticsEvent: AnalyticsEvent, campaignId: String, data: MutableMap<String, Any>) {
// Common metadata
data[AnalyticsKey.CAMPAIGN_ID.key] = campaignId
data[AnalyticsKey.SUBS_ID.key] = HostAppInfoRepository.instance().getSubscriptionKey()
data[AnalyticsKey.DEVICE_ID.key] = HostAppInfoRepository.instance().getDeviceId()

val params = hashMapOf<String, Any>()
params[AnalyticsKey.CUSTOM_PARAM.key] = data

if (RmcHelper.isRmcIntegrated()) {
if (analyticsEvent.rmcName == null) {
return
}

val paramsCopy = HashMap<String, Any>(params)
paramsCopy[AnalyticsKey.ACCOUNT.key] = BuildConfig.IAM_RAT_ACC
paramsCopy[AnalyticsKey.APP_ID.key] = BuildConfig.IAM_RAT_AID

EventTrackerHelper.sendEvent(analyticsEvent.rmcName, params)
EventTrackerHelper.sendEvent(analyticsEvent.rmcName, paramsCopy)
} else {
if (analyticsEvent.iamName == null) {
return
}

EventTrackerHelper.sendEvent(analyticsEvent.iamName, params)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,17 @@
package com.rakuten.tech.mobile.inappmessaging.runtime.manager

import com.rakuten.tech.mobile.inappmessaging.runtime.BuildConfig
import com.rakuten.tech.mobile.inappmessaging.runtime.EventTrackerHelper
import com.rakuten.tech.mobile.inappmessaging.runtime.data.enums.ImpressionType
import com.rakuten.tech.mobile.inappmessaging.runtime.data.models.rat.RatImpression
import com.rakuten.tech.mobile.inappmessaging.runtime.data.repositories.HostAppInfoRepository
import com.rakuten.tech.mobile.inappmessaging.runtime.data.requests.Impression
import com.rakuten.tech.mobile.inappmessaging.runtime.data.requests.ImpressionRequest
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppLogger
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants.RAT_EVENT_CAMP_ID
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants.RAT_EVENT_IMP
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants.RAT_EVENT_KEY_IMPRESSION
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants.RAT_EVENT_SUBS_ID
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.RuntimeUtil
import com.rakuten.tech.mobile.inappmessaging.runtime.workmanager.schedulers.ImpressionScheduler
import java.util.Date
import java.util.concurrent.ConcurrentHashMap
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
import kotlin.collections.set

/**
Expand All @@ -32,16 +26,11 @@ internal object ImpressionManager {
* Reporting impression list to IAM backend, and sending to analytics. This method is invoked on
* main thread.
*/
fun scheduleReportImpression(
impressionList: List<Impression>,
campaignId: String,
isTestMessage: Boolean,
sendEvent: (String, data: Map<String, *>?) -> Boolean = EventTrackerHelper::sendEvent,
) {
fun scheduleReportImpression(impressionList: List<Impression>, campaignId: String, isTestMessage: Boolean) {
if (impressionList.isEmpty()) return

// send user action impression
sendImpressionEvent(campaignId, impressionList, sendEvent)
sendImpressionEvent(campaignId, impressionList)

val impListRequest = impressionList.toMutableList()
impressionMap[campaignId]?.let { mapData ->
Expand All @@ -66,7 +55,6 @@ internal object ImpressionManager {
internal fun sendImpressionEvent(
campaignId: String,
impressionList: List<Impression>,
sendEvent: (String, data: Map<String, *>?) -> Boolean = EventTrackerHelper::sendEvent,
impressionTypeOnly: Boolean = false,
) {
if (impressionList.isEmpty()) return
Expand All @@ -75,12 +63,9 @@ internal object ImpressionManager {
impressionMap[campaignId] = impressionList[0] // if impression type only, it is assumed that only one entry
}

val params: MutableMap<String, Any?> = HashMap()
params[RAT_EVENT_CAMP_ID] = campaignId
params[RAT_EVENT_SUBS_ID] = HostAppInfoRepository.instance().getSubscriptionKey()
params[RAT_EVENT_IMP] = createRatImpressionList(impressionList)

sendEvent(RAT_EVENT_KEY_IMPRESSION, params)
val params = hashMapOf<String, Any>()
params[AnalyticsKey.IMPRESSIONS.key] = createRatImpressionList(impressionList)
AnalyticsManager.sendEvent(AnalyticsEvent.IMPRESSION, campaignId, params)
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,13 @@
package com.rakuten.tech.mobile.inappmessaging.runtime.manager

import com.rakuten.tech.mobile.inappmessaging.runtime.EventTrackerHelper
import com.rakuten.tech.mobile.inappmessaging.runtime.data.repositories.HostAppInfoRepository
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants

internal object PushPrimerTrackerManager {
internal var campaignId = ""

internal fun sendPrimerEvent(
permission: Int,
sendEvent: (String, data: Map<String, *>?) -> Boolean = EventTrackerHelper::sendEvent,
) {
val params: MutableMap<String, Any?> = HashMap()
params[InAppMessagingConstants.RAT_EVENT_CAMP_ID] = campaignId
params[InAppMessagingConstants.RAT_EVENT_SUBS_ID] = HostAppInfoRepository.instance().getSubscriptionKey()
params[InAppMessagingConstants.RAT_EVENT_KEY_PERMISSION] = permission
internal fun sendPrimerEvent(permission: Int) {
val params: MutableMap<String, Any> = HashMap()
params[AnalyticsKey.PUSH_PERMISSION.key] = permission

sendEvent(InAppMessagingConstants.RAT_EVENT_KEY_PRIMER, params)
AnalyticsManager.sendEvent(AnalyticsEvent.PUSH_PRIMER, campaignId, params)

campaignId = "" // reset value
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,6 @@ internal object InAppMessagingConstants {
// -------------------------------URL Only--------------------------------------------------------
const val TEMPLATE_BASE_URL = "http://your.base.url/"

// ------------------------------ Analytics Event KEYS ---------------------------------------------
const val RAT_EVENT_KEY_IMPRESSION = "_rem_iam_impressions"
const val RAT_EVENT_KEY_PRIMER = "_rem_iam_pushprimer"
const val RAT_EVENT_KEY_EVENT_NAME = "eventName"
const val RAT_EVENT_KEY_EVENT_TIMESTAMP = "timestamp"
const val RAT_EVENT_KEY_EVENT_CUSTOM_ATTRIBUTE = "customAttributes"
const val RAT_EVENT_CAMP_ID = "campaign_id"
const val RAT_EVENT_SUBS_ID = "subscription_id"
const val RAT_EVENT_IMP = "impressions"
const val RAT_EVENT_KEY_PERMISSION = "push_permission"

// ------------------------------ API HEADER KEYS ---------------------------------------------

const val DEVICE_ID_HEADER = "device_id"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.rakuten.tech.mobile.analytics

class RatTracker {
companion object {
fun event(type: String, parameters: Map<String, Any>): Event = Event(type, parameters)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,7 @@ class InAppMessagingPrimerTrackerSpec : InAppMessagingSpec() {
arrayOf(Manifest.permission.POST_NOTIFICATIONS), intArrayOf(PackageManager.PERMISSION_GRANTED),
)

verify(mockMgr).sendPrimerEvent(eq(1), any())
verify(mockMgr).sendPrimerEvent(eq(1))
}

@Test
Expand All @@ -686,7 +686,7 @@ class InAppMessagingPrimerTrackerSpec : InAppMessagingSpec() {
arrayOf(Manifest.permission.POST_NOTIFICATIONS), intArrayOf(PackageManager.PERMISSION_DENIED),
)

verify(mockMgr).sendPrimerEvent(eq(0), any())
verify(mockMgr).sendPrimerEvent(eq(0))
}

@Test
Expand All @@ -697,7 +697,7 @@ class InAppMessagingPrimerTrackerSpec : InAppMessagingSpec() {
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), intArrayOf(PackageManager.PERMISSION_DENIED),
)

verify(mockMgr, never()).sendPrimerEvent(any(), any())
verify(mockMgr, never()).sendPrimerEvent(any())
}

@Test
Expand All @@ -709,7 +709,7 @@ class InAppMessagingPrimerTrackerSpec : InAppMessagingSpec() {
intArrayOf(PackageManager.PERMISSION_DENIED, PackageManager.PERMISSION_GRANTED),
)

verify(mockMgr, never()).sendPrimerEvent(any(), any())
verify(mockMgr, never()).sendPrimerEvent(any())
}

@Test
Expand All @@ -721,7 +721,7 @@ class InAppMessagingPrimerTrackerSpec : InAppMessagingSpec() {
intArrayOf(PackageManager.PERMISSION_DENIED),
)

verify(mockMgr, never()).sendPrimerEvent(any(), any())
verify(mockMgr, never()).sendPrimerEvent(any())
}

@Test
Expand All @@ -734,6 +734,6 @@ class InAppMessagingPrimerTrackerSpec : InAppMessagingSpec() {
intArrayOf(PackageManager.PERMISSION_DENIED, PackageManager.PERMISSION_GRANTED),
)

verify(mockMgr, never()).sendPrimerEvent(any(), any())
verify(mockMgr, never()).sendPrimerEvent(any())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.rakuten.tech.mobile.inappmessaging.runtime.data.models.appevents

import com.rakuten.tech.mobile.inappmessaging.runtime.BaseTest
import com.rakuten.tech.mobile.inappmessaging.runtime.data.enums.ValueType
import com.rakuten.tech.mobile.inappmessaging.runtime.manager.AnalyticsKey
import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants
import org.amshove.kluent.shouldBeEqualTo
import org.amshove.kluent.shouldBeFalse
Expand Down Expand Up @@ -124,9 +125,9 @@ class CustomEventParameterizedSpec(
event.getAttributeMap()[key]?.value shouldBeEqualTo value
event.getAttributeMap()[key]?.valueType shouldBeEqualTo type
val ratMap = event.getRatEventMap()
ratMap shouldHaveKey InAppMessagingConstants.RAT_EVENT_KEY_EVENT_NAME
ratMap shouldHaveKey InAppMessagingConstants.RAT_EVENT_KEY_EVENT_TIMESTAMP
ratMap shouldHaveKey InAppMessagingConstants.RAT_EVENT_KEY_EVENT_CUSTOM_ATTRIBUTE
ratMap shouldHaveKey AnalyticsKey.EVENT_NAME.key
ratMap shouldHaveKey AnalyticsKey.TIMESTAMP.key
ratMap shouldHaveKey AnalyticsKey.CUSTOM_ATTRIBUTES.key
}

companion object {
Expand Down
Loading

0 comments on commit 391fb13

Please sign in to comment.