diff --git a/analytics/src/main/java/com/rakuten/tech/mobile/analytics/RatTracker.kt b/analytics/src/main/java/com/rakuten/tech/mobile/analytics/RatTracker.kt new file mode 100644 index 00000000..838e558b --- /dev/null +++ b/analytics/src/main/java/com/rakuten/tech/mobile/analytics/RatTracker.kt @@ -0,0 +1,7 @@ +package com.rakuten.tech.mobile.analytics + +class RatTracker { + companion object { + fun event(type: String, parameters: Map): Event = Event(type, parameters) + } +} \ No newline at end of file diff --git a/inappmessaging/USERGUIDE.md b/inappmessaging/USERGUIDE.md index 23deafc6..d07aad00 100644 --- a/inappmessaging/USERGUIDE.md +++ b/inappmessaging/USERGUIDE.md @@ -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. diff --git a/inappmessaging/build.gradle b/inappmessaging/build.gradle index 46d246be..2e8a41a5 100644 --- a/inappmessaging/build.gradle +++ b/inappmessaging/build.gradle @@ -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") diff --git a/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/EventTrackerHelper.kt b/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/EventTrackerHelper.kt index 5a73a77a..d8b9cc1d 100644 --- a/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/EventTrackerHelper.kt +++ b/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/EventTrackerHelper.kt @@ -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 @@ -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?): Boolean { if (!TextUtils.isEmpty(eventName)) { val serializableData: HashMap = when (data) { @@ -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") + } } } diff --git a/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/BaseEvent.kt b/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/BaseEvent.kt index aec03bc7..f8955ad1 100644 --- a/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/BaseEvent.kt +++ b/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/BaseEvent.kt @@ -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 @@ -72,8 +73,8 @@ abstract class BaseEvent( @NotNull override fun getRatEventMap(): Map { val map = HashMap() - 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) } diff --git a/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/CustomEvent.kt b/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/CustomEvent.kt index 182b646a..d4f1e80e 100644 --- a/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/CustomEvent.kt +++ b/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/CustomEvent.kt @@ -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 @@ -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) } diff --git a/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/PurchaseSuccessfulEvent.kt b/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/PurchaseSuccessfulEvent.kt index 42f10488..c56668ca 100644 --- a/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/PurchaseSuccessfulEvent.kt +++ b/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/PurchaseSuccessfulEvent.kt @@ -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 @@ -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) } diff --git a/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/manager/AnalyticsManager.kt b/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/manager/AnalyticsManager.kt new file mode 100644 index 00000000..b62219e7 --- /dev/null +++ b/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/manager/AnalyticsManager.kt @@ -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) { + // 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() + params[AnalyticsKey.CUSTOM_PARAM.key] = data + + if (RmcHelper.isRmcIntegrated()) { + if (analyticsEvent.rmcName == null) { + return + } + + val paramsCopy = HashMap(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) + } + } +} diff --git a/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/manager/ImpressionManager.kt b/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/manager/ImpressionManager.kt index a6b4c677..1b87815b 100644 --- a/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/manager/ImpressionManager.kt +++ b/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/manager/ImpressionManager.kt @@ -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 /** @@ -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, - campaignId: String, - isTestMessage: Boolean, - sendEvent: (String, data: Map?) -> Boolean = EventTrackerHelper::sendEvent, - ) { + fun scheduleReportImpression(impressionList: List, 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 -> @@ -66,7 +55,6 @@ internal object ImpressionManager { internal fun sendImpressionEvent( campaignId: String, impressionList: List, - sendEvent: (String, data: Map?) -> Boolean = EventTrackerHelper::sendEvent, impressionTypeOnly: Boolean = false, ) { if (impressionList.isEmpty()) return @@ -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 = 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() + params[AnalyticsKey.IMPRESSIONS.key] = createRatImpressionList(impressionList) + AnalyticsManager.sendEvent(AnalyticsEvent.IMPRESSION, campaignId, params) } /** diff --git a/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/manager/PushPrimerTrackerManager.kt b/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/manager/PushPrimerTrackerManager.kt index 9cf2f3e8..66a8d9f9 100644 --- a/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/manager/PushPrimerTrackerManager.kt +++ b/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/manager/PushPrimerTrackerManager.kt @@ -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?) -> Boolean = EventTrackerHelper::sendEvent, - ) { - val params: MutableMap = 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 = HashMap() + params[AnalyticsKey.PUSH_PERMISSION.key] = permission - sendEvent(InAppMessagingConstants.RAT_EVENT_KEY_PRIMER, params) + AnalyticsManager.sendEvent(AnalyticsEvent.PUSH_PRIMER, campaignId, params) campaignId = "" // reset value } diff --git a/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/utils/InAppMessagingConstants.kt b/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/utils/InAppMessagingConstants.kt index 71fbf805..f7b3a0a2 100644 --- a/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/utils/InAppMessagingConstants.kt +++ b/inappmessaging/src/main/java/com/rakuten/tech/mobile/inappmessaging/runtime/utils/InAppMessagingConstants.kt @@ -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" diff --git a/inappmessaging/src/test/java/com/rakuten/tech/mobile/analytics/RatTracker.kt b/inappmessaging/src/test/java/com/rakuten/tech/mobile/analytics/RatTracker.kt new file mode 100644 index 00000000..3563956e --- /dev/null +++ b/inappmessaging/src/test/java/com/rakuten/tech/mobile/analytics/RatTracker.kt @@ -0,0 +1,7 @@ +package com.rakuten.tech.mobile.analytics + +class RatTracker { + companion object { + fun event(type: String, parameters: Map): Event = Event(type, parameters) + } +} diff --git a/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/InAppMessagingSpec.kt b/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/InAppMessagingSpec.kt index 66b9b0f6..5d520831 100644 --- a/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/InAppMessagingSpec.kt +++ b/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/InAppMessagingSpec.kt @@ -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 @@ -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 @@ -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 @@ -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 @@ -721,7 +721,7 @@ class InAppMessagingPrimerTrackerSpec : InAppMessagingSpec() { intArrayOf(PackageManager.PERMISSION_DENIED), ) - verify(mockMgr, never()).sendPrimerEvent(any(), any()) + verify(mockMgr, never()).sendPrimerEvent(any()) } @Test @@ -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()) } } diff --git a/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/CustomEventSpec.kt b/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/CustomEventSpec.kt index 796fccda..2798355a 100644 --- a/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/CustomEventSpec.kt +++ b/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/CustomEventSpec.kt @@ -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 @@ -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 { diff --git a/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/EventSpec.kt b/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/EventSpec.kt index 98712229..0b6e7657 100644 --- a/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/EventSpec.kt +++ b/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/EventSpec.kt @@ -2,7 +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.EventType -import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants +import com.rakuten.tech.mobile.inappmessaging.runtime.manager.AnalyticsKey import org.amshove.kluent.* import org.junit.Test import org.junit.runner.RunWith @@ -39,15 +39,15 @@ class EventSpec( @Test fun `RAT event map should contain correct keys`() { val map = event.getRatEventMap() - map shouldHaveKey InAppMessagingConstants.RAT_EVENT_KEY_EVENT_NAME - map shouldHaveKey InAppMessagingConstants.RAT_EVENT_KEY_EVENT_TIMESTAMP + map shouldHaveKey AnalyticsKey.EVENT_NAME.key + map shouldHaveKey AnalyticsKey.TIMESTAMP.key } @Test fun `RAT event map should correct values`() { val map = event.getRatEventMap() - map[InAppMessagingConstants.RAT_EVENT_KEY_EVENT_NAME] shouldBeEqualTo expectedName - map[InAppMessagingConstants.RAT_EVENT_KEY_EVENT_TIMESTAMP] as Long shouldBeGreaterThan 0L + map[AnalyticsKey.EVENT_NAME.key] shouldBeEqualTo expectedName + map[AnalyticsKey.TIMESTAMP.key] as Long shouldBeGreaterThan 0L } @Test diff --git a/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/PurchaseSuccessfulEventSpec.kt b/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/PurchaseSuccessfulEventSpec.kt index 13b0192f..fbe15206 100644 --- a/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/PurchaseSuccessfulEventSpec.kt +++ b/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/data/models/appevents/PurchaseSuccessfulEventSpec.kt @@ -2,7 +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.models.rat.RatAttribute -import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants +import com.rakuten.tech.mobile.inappmessaging.runtime.manager.AnalyticsKey import org.amshove.kluent.shouldContain import org.amshove.kluent.shouldHaveKey import org.amshove.kluent.shouldHaveSize @@ -34,8 +34,8 @@ class PurchaseSuccessfulEventSpec : BaseTest() { .purchaseAmountMicros(5000000) val map = event.getRatEventMap() - map shouldHaveKey InAppMessagingConstants.RAT_EVENT_KEY_EVENT_CUSTOM_ATTRIBUTE - val attr = map[InAppMessagingConstants.RAT_EVENT_KEY_EVENT_CUSTOM_ATTRIBUTE] as ArrayList + map shouldHaveKey AnalyticsKey.CUSTOM_ATTRIBUTES.key + val attr = map[AnalyticsKey.CUSTOM_ATTRIBUTES.key] as ArrayList attr shouldHaveSize 4 attr shouldContain RatAttribute(PURCHASE_AMOUNT_MICROS_TAG, 5000000) attr shouldContain RatAttribute(NUMBER_OF_ITEMS_TAG, 5) diff --git a/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/manager/AnalyticsManagerSpec.kt b/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/manager/AnalyticsManagerSpec.kt new file mode 100644 index 00000000..0bc7568e --- /dev/null +++ b/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/manager/AnalyticsManagerSpec.kt @@ -0,0 +1,87 @@ +package com.rakuten.tech.mobile.inappmessaging.runtime.manager + +import com.nhaarman.mockitokotlin2.any +import com.nhaarman.mockitokotlin2.argumentCaptor +import com.nhaarman.mockitokotlin2.never +import com.nhaarman.mockitokotlin2.times +import com.rakuten.tech.mobile.inappmessaging.runtime.EventTrackerHelper +import com.rakuten.tech.mobile.inappmessaging.runtime.RmcHelper +import org.amshove.kluent.shouldContain +import org.amshove.kluent.shouldContainAll +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito.mockStatic + +@SuppressWarnings("LongMethod") +class AnalyticsManagerSpec { + + private val eventTrackerHelper = mockStatic(EventTrackerHelper::class.java) + private val rmcHelper = mockStatic(RmcHelper::class.java) + + @Before + fun setup() { + rmcHelper.`when` { RmcHelper.isRmcIntegrated() }.thenReturn(true) + } + + @After + fun teardown() { + eventTrackerHelper.close() + rmcHelper.close() + } + + @Test + fun `should not process if there is no corresponding event name`() { + rmcHelper.`when` { RmcHelper.isRmcIntegrated() }.thenReturn(false) + + AnalyticsManager.sendEvent(AnalyticsEvent.PUSH_PRIMER, "1234", mutableMapOf("param1" to 1)) + + eventTrackerHelper.verify({ EventTrackerHelper.sendEvent(any(), any()) }, never()) + } + + @Test + fun `should set all required custom parameter (cp)`() { + rmcHelper.`when` { RmcHelper.isRmcIntegrated() }.thenReturn(false) + + AnalyticsManager.sendEvent(AnalyticsEvent.IMPRESSION, "1234", mutableMapOf("param1" to 1)) + + val captor = argumentCaptor>() + eventTrackerHelper.verify { EventTrackerHelper.sendEvent(any(), captor.capture()) } + captor.firstValue.keys.shouldContain(AnalyticsKey.CUSTOM_PARAM.key) + val params = (captor.firstValue[AnalyticsKey.CUSTOM_PARAM.key] as Map).keys + params.shouldContainAll( + arrayOf( + AnalyticsKey.CAMPAIGN_ID.key, + AnalyticsKey.SUBS_ID.key, + AnalyticsKey.DEVICE_ID.key, + "param1", + ), + ) + } + + @Test + fun `should set all required custom parameter (cp) for RMC`() { + AnalyticsManager.sendEvent(AnalyticsEvent.PUSH_PRIMER, "1234", mutableMapOf("param1" to 1)) + + val captor = argumentCaptor>() + eventTrackerHelper.verify({ EventTrackerHelper.sendEvent(any(), captor.capture()) }, times(2)) + captor.firstValue.keys.shouldContain(AnalyticsKey.CUSTOM_PARAM.key) + captor.secondValue.keys.shouldContainAll( + arrayOf( + AnalyticsKey.CUSTOM_PARAM.key, + AnalyticsKey.ACCOUNT.key, + AnalyticsKey.APP_ID.key, + ), + ) + + val params = (captor.firstValue[AnalyticsKey.CUSTOM_PARAM.key] as Map).keys + params.shouldContainAll( + arrayOf( + AnalyticsKey.CAMPAIGN_ID.key, + AnalyticsKey.SUBS_ID.key, + AnalyticsKey.DEVICE_ID.key, + "param1", + ), + ) + } +} diff --git a/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/manager/ImpressionManagerSpec.kt b/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/manager/ImpressionManagerSpec.kt index 63845e33..3b89a106 100644 --- a/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/manager/ImpressionManagerSpec.kt +++ b/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/manager/ImpressionManagerSpec.kt @@ -1,44 +1,35 @@ package com.rakuten.tech.mobile.inappmessaging.runtime.manager -import android.content.Context -import android.provider.Settings -import androidx.test.core.app.ApplicationProvider -import androidx.work.WorkManager -import androidx.work.testing.WorkManagerTestInitHelper import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.argumentCaptor -import com.nhaarman.mockitokotlin2.KArgumentCaptor -import com.nhaarman.mockitokotlin2.eq import com.nhaarman.mockitokotlin2.never import com.rakuten.tech.mobile.inappmessaging.runtime.* 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.requests.Impression -import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants import org.amshove.kluent.* +import org.junit.After import org.junit.Before import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.ArgumentMatchers -import org.mockito.Mockito -import org.robolectric.RobolectricTestRunner -import java.util.* -import java.util.concurrent.ExecutionException +import org.mockito.Mockito.mockStatic +import java.util.Date /** * Test class for ImpressionManager. */ -@RunWith(RobolectricTestRunner::class) -class ImpressionManagerSpec : BaseTest() { +class ImpressionManagerSpec { - private val eventTracker = Mockito.mock(EventTrackerHelper::class.java) + private val analyticsManager = mockStatic(AnalyticsManager::class.java) @Before - override fun setup() { - super.setup() + fun setup() { impressionList = ImpressionManager.createImpressionList(VALID_IMPRESSION_TYPES) } + @After + fun teardown() { + analyticsManager.close() + } + @Test fun `should create impression list with correct attributes`() { impressionList!![0].timestamp shouldBeGreaterThan 0L @@ -52,93 +43,32 @@ class ImpressionManagerSpec : BaseTest() { } @Test - @Throws(ExecutionException::class, InterruptedException::class) - fun `should invoke start impression worker`() { - setupEventBroadcaster() - val status = - WorkManager.getInstance(ApplicationProvider.getApplicationContext()) - .getWorkInfosByTag(IMPRESSION_WORKER_NAME) - status.get().shouldHaveSize(1) - } - - @Test - fun `should invoke broadcaster`() { - val captor = setupEventBroadcaster() + fun `should not track empty impression list`() { + ImpressionManager.scheduleReportImpression(emptyList(), "1234", false) - val map = captor.firstValue - map[InAppMessagingConstants.RAT_EVENT_CAMP_ID] shouldBeEqualTo "1234" - (map[InAppMessagingConstants.RAT_EVENT_SUBS_ID] as String).shouldNotBeEmpty() - (map[InAppMessagingConstants.RAT_EVENT_IMP] as List) shouldHaveSize impressionList!!.size + analyticsManager.verify({ AnalyticsManager.sendEvent(any(), any(), any()) }, never()) } @Test - fun `should not invoke broadcaster if empty list`() { - ImpressionManager.scheduleReportImpression( - emptyList(), - "1234", - false, - eventTracker::sendEvent, - ) - Mockito.verify(eventTracker, never()).sendEvent( - ArgumentMatchers.anyString(), ArgumentMatchers.anyMap(), - ) - } - - @Test - fun `should invoke broadcaster with valid impression content`() { + fun `should track valid impression event`() { ImpressionManager.impressionMap["1234"] = Impression(ImpressionType.IMPRESSION, Date().time) - val captor = setupEventBroadcaster() - - val map = captor.firstValue - map[InAppMessagingConstants.RAT_EVENT_CAMP_ID] shouldBeEqualTo "1234" - (map[InAppMessagingConstants.RAT_EVENT_SUBS_ID] as String).shouldNotBeEmpty() - (map[InAppMessagingConstants.RAT_EVENT_IMP] as List) shouldHaveSize impressionList!!.size - - ImpressionManager.impressionMap.clear() - } - - @Test - fun `should invoke broadcaster for impression type`() { - ImpressionManager.sendImpressionEvent( - "1234", listOf(Impression(ImpressionType.IMPRESSION, Date().time)), eventTracker::sendEvent, - ) - - val captor = argumentCaptor>() - Mockito.verify(eventTracker).sendEvent( - eq(InAppMessagingConstants.RAT_EVENT_KEY_IMPRESSION), captor.capture(), - ) + ImpressionManager.scheduleReportImpression(impressionList!!, "1234", false) - val map = captor.firstValue - map[InAppMessagingConstants.RAT_EVENT_CAMP_ID] shouldBeEqualTo "1234" - (map[InAppMessagingConstants.RAT_EVENT_SUBS_ID] as String).shouldNotBeEmpty() - (map[InAppMessagingConstants.RAT_EVENT_IMP] as List) shouldHaveSize 1 - } + val eTypeCaptor = argumentCaptor() + val idCaptor = argumentCaptor() + val dataCaptor = argumentCaptor>() - @Test - fun `should not invoke broadcaster for empty list`() { - ImpressionManager.sendImpressionEvent("1234", listOf(), eventTracker::sendEvent) + analyticsManager.verify { + AnalyticsManager.sendEvent(eTypeCaptor.capture(), idCaptor.capture(), dataCaptor.capture()) + } + eTypeCaptor.firstValue shouldBeEqualTo AnalyticsEvent.IMPRESSION + idCaptor.firstValue shouldBeEqualTo "1234" + dataCaptor.firstValue.keys.shouldContain(AnalyticsKey.IMPRESSIONS.key) - val captor = argumentCaptor>() - Mockito.verify(eventTracker, never()).sendEvent(eq(InAppMessagingConstants.RAT_EVENT_KEY_IMPRESSION), any()) - } - - private fun setupEventBroadcaster(): KArgumentCaptor> { - WorkManagerTestInitHelper.initializeTestWorkManager(ApplicationProvider.getApplicationContext()) - Settings.Secure.putString( - ApplicationProvider.getApplicationContext().contentResolver, - Settings.Secure.ANDROID_ID, - "test_device_id", - ) - InAppMessaging.initialize(ApplicationProvider.getApplicationContext(), true) - InAppMessaging.instance().registerPreference(TestUserInfoProvider()) - ImpressionManager.scheduleReportImpression(impressionList!!, "1234", false, eventTracker::sendEvent) - val captor = argumentCaptor>() - Mockito.verify(eventTracker).sendEvent(eq(InAppMessagingConstants.RAT_EVENT_KEY_IMPRESSION), captor.capture()) - return captor + ImpressionManager.impressionMap.clear() } companion object { - private const val IMPRESSION_WORKER_NAME = "iam_impression_work" private val VALID_IMPRESSION_TYPES: MutableList = mutableListOf(ImpressionType.ACTION_ONE, ImpressionType.OPT_OUT) private val IMPRESSION_TYPES: MutableList = diff --git a/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/manager/PushPrimerTrackerManagerSpec.kt b/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/manager/PushPrimerTrackerManagerSpec.kt index 936314e1..eb0922d9 100644 --- a/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/manager/PushPrimerTrackerManagerSpec.kt +++ b/inappmessaging/src/test/java/com/rakuten/tech/mobile/inappmessaging/runtime/manager/PushPrimerTrackerManagerSpec.kt @@ -1,35 +1,27 @@ package com.rakuten.tech.mobile.inappmessaging.runtime.manager import com.nhaarman.mockitokotlin2.argumentCaptor -import com.nhaarman.mockitokotlin2.eq -import com.nhaarman.mockitokotlin2.verify -import com.rakuten.tech.mobile.inappmessaging.runtime.BaseTest -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.RAT_EVENT_CAMP_ID -import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants.RAT_EVENT_KEY_PERMISSION -import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants.RAT_EVENT_KEY_PRIMER -import com.rakuten.tech.mobile.inappmessaging.runtime.utils.InAppMessagingConstants.RAT_EVENT_SUBS_ID import org.amshove.kluent.shouldBeEmpty import org.amshove.kluent.shouldBeEqualTo +import org.junit.After import org.junit.Before import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mockito -import org.robolectric.RobolectricTestRunner +import org.mockito.Mockito.mockStatic -@RunWith(RobolectricTestRunner::class) -class PushPrimerTrackerManagerSpec : BaseTest() { - private val eventTracker = Mockito.mock(EventTrackerHelper::class.java) - private val captor = argumentCaptor>() +class PushPrimerTrackerManagerSpec { - @Before - override fun setup() { - super.setup() + private val analyticsManager = mockStatic(AnalyticsManager::class.java) + @Before + fun setup() { PushPrimerTrackerManager.campaignId = "test" } + @After + fun teardown() { + analyticsManager.close() + } + @Test fun `should send event with granted permission`() { verifyTracker(1) @@ -53,13 +45,19 @@ class PushPrimerTrackerManagerSpec : BaseTest() { } private fun verifyTracker(result: Int, campaignId: String = "test") { - PushPrimerTrackerManager.sendPrimerEvent(result, eventTracker::sendEvent) + PushPrimerTrackerManager.sendPrimerEvent(result) + + val eTypeCaptor = argumentCaptor() + val idCaptor = argumentCaptor() + val dataCaptor = argumentCaptor>() - verify(eventTracker).sendEvent(eq(RAT_EVENT_KEY_PRIMER), captor.capture()) + analyticsManager.verify { + AnalyticsManager.sendEvent(eTypeCaptor.capture(), idCaptor.capture(), dataCaptor.capture()) + } - captor.firstValue[RAT_EVENT_CAMP_ID] shouldBeEqualTo campaignId - captor.firstValue[RAT_EVENT_SUBS_ID] shouldBeEqualTo HostAppInfoRepository.instance().getSubscriptionKey() - captor.firstValue[RAT_EVENT_KEY_PERMISSION] shouldBeEqualTo result + eTypeCaptor.firstValue shouldBeEqualTo AnalyticsEvent.PUSH_PRIMER + idCaptor.firstValue shouldBeEqualTo campaignId + dataCaptor.firstValue[AnalyticsKey.PUSH_PERMISSION.key] shouldBeEqualTo result PushPrimerTrackerManager.campaignId.shouldBeEmpty() } diff --git a/test/src/main/java/com/rakuten/test/MainActivity.kt b/test/src/main/java/com/rakuten/test/MainActivity.kt index 22d5cc17..3b6ac916 100644 --- a/test/src/main/java/com/rakuten/test/MainActivity.kt +++ b/test/src/main/java/com/rakuten/test/MainActivity.kt @@ -97,4 +97,12 @@ class MainActivity : AppCompatActivity() { } viewIds.forEach { viewId -> InAppMessaging.instance().closeTooltip(viewId) } } + + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + when(requestCode) { + InAppMessaging.PUSH_PRIMER_REQ_CODE -> { + InAppMessaging.instance().trackPushPrimer(permissions, grantResults) + } + } + } } \ No newline at end of file