Browse Source

Merge pull request #2953 from element-hq/feature/valere/super_properties

Analytics | Add support for SuperProperties
pull/2606/head
Valere 4 months ago committed by GitHub
parent
commit
b4b07d8ce9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 16
      appnav/src/main/kotlin/io/element/android/appnav/root/RootPresenter.kt
  2. 4
      appnav/src/test/kotlin/io/element/android/appnav/RootPresenterTest.kt
  3. 1
      changelog.d/2953.misc
  4. 2
      gradle/libs.versions.toml
  5. 5
      services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsService.kt
  6. 23
      services/analytics/impl/src/test/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsServiceTest.kt
  7. 2
      services/analytics/noop/src/main/kotlin/io/element/android/services/analytics/noop/NoopAnalyticsService.kt
  8. 5
      services/analytics/test/src/main/kotlin/io/element/android/services/analytics/test/FakeAnalyticsService.kt
  9. 7
      services/analyticsproviders/api/src/main/kotlin/io/element/android/services/analyticsproviders/api/trackers/AnalyticsTracker.kt
  10. 38
      services/analyticsproviders/posthog/src/main/kotlin/io/element/android/services/analyticsproviders/posthog/PosthogAnalyticsProvider.kt
  11. 111
      services/analyticsproviders/posthog/src/test/kotlin/io/element/android/services/analyticsproviders/posthog/PosthogAnalyticsProviderTest.kt
  12. 4
      services/analyticsproviders/sentry/src/main/kotlin/io/element/android/services/analyticsproviders/sentry/SentryAnalyticsProvider.kt
  13. 3
      services/analyticsproviders/test/src/main/kotlin/io/element/android/services/analyticsproviders/test/FakeAnalyticsProvider.kt

16
appnav/src/main/kotlin/io/element/android/appnav/root/RootPresenter.kt

@ -17,11 +17,15 @@ @@ -17,11 +17,15 @@
package io.element.android.appnav.root
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import im.vector.app.features.analytics.plan.SuperProperties
import io.element.android.features.rageshake.api.crash.CrashDetectionPresenter
import io.element.android.features.rageshake.api.detection.RageshakeDetectionPresenter
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.matrix.api.SdkMetadata
import io.element.android.services.analytics.api.AnalyticsService
import io.element.android.services.apperror.api.AppErrorStateService
import javax.inject.Inject
@ -29,6 +33,8 @@ class RootPresenter @Inject constructor( @@ -29,6 +33,8 @@ class RootPresenter @Inject constructor(
private val crashDetectionPresenter: CrashDetectionPresenter,
private val rageshakeDetectionPresenter: RageshakeDetectionPresenter,
private val appErrorStateService: AppErrorStateService,
private val analyticsService: AnalyticsService,
private val sdkMetadata: SdkMetadata,
) : Presenter<RootState> {
@Composable
override fun present(): RootState {
@ -36,6 +42,16 @@ class RootPresenter @Inject constructor( @@ -36,6 +42,16 @@ class RootPresenter @Inject constructor(
val crashDetectionState = crashDetectionPresenter.present()
val appErrorState by appErrorStateService.appErrorStateFlow.collectAsState()
LaunchedEffect(Unit) {
analyticsService.updateSuperProperties(
SuperProperties(
cryptoSDK = SuperProperties.CryptoSDK.Rust,
appPlatform = SuperProperties.AppPlatform.EXA,
cryptoSDKVersion = sdkMetadata.sdkGitSha,
)
)
}
return RootState(
rageshakeDetectionState = rageshakeDetectionState,
crashDetectionState = crashDetectionState,

4
appnav/src/test/kotlin/io/element/android/appnav/RootPresenterTest.kt

@ -28,7 +28,9 @@ import io.element.android.features.rageshake.test.crash.FakeCrashDataStore @@ -28,7 +28,9 @@ import io.element.android.features.rageshake.test.crash.FakeCrashDataStore
import io.element.android.features.rageshake.test.rageshake.FakeRageShake
import io.element.android.features.rageshake.test.rageshake.FakeRageshakeDataStore
import io.element.android.features.rageshake.test.screenshot.FakeScreenshotHolder
import io.element.android.libraries.matrix.test.FakeSdkMetadata
import io.element.android.libraries.matrix.test.core.aBuildMeta
import io.element.android.services.analytics.test.FakeAnalyticsService
import io.element.android.services.apperror.api.AppErrorState
import io.element.android.services.apperror.api.AppErrorStateService
import io.element.android.services.apperror.impl.DefaultAppErrorStateService
@ -99,6 +101,8 @@ class RootPresenterTest { @@ -99,6 +101,8 @@ class RootPresenterTest {
crashDetectionPresenter = crashDetectionPresenter,
rageshakeDetectionPresenter = rageshakeDetectionPresenter,
appErrorStateService = appErrorService,
analyticsService = FakeAnalyticsService(),
sdkMetadata = FakeSdkMetadata("sha")
)
}
}

1
changelog.d/2953.misc

@ -0,0 +1 @@ @@ -0,0 +1 @@
Analytics | Add support for SuperProperties

2
gradle/libs.versions.toml

@ -187,7 +187,7 @@ zxing_cpp = "io.github.zxing-cpp:android:2.2.0" @@ -187,7 +187,7 @@ zxing_cpp = "io.github.zxing-cpp:android:2.2.0"
posthog = "com.posthog:posthog-android:3.3.0"
sentry = "io.sentry:sentry-android:7.9.0"
# main branch can be tested replacing the version with main-SNAPSHOT
matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:0.21.0"
matrix_analytics_events = "com.github.matrix-org:matrix-analytics-events:0.23.0"
# Emojibase
matrix_emojibase_bindings = "io.element.android:emojibase-bindings:1.1.3"

5
services/analytics/impl/src/main/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsService.kt

@ -19,6 +19,7 @@ package io.element.android.services.analytics.impl @@ -19,6 +19,7 @@ package io.element.android.services.analytics.impl
import com.squareup.anvil.annotations.ContributesBinding
import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
import im.vector.app.features.analytics.itf.VectorAnalyticsScreen
import im.vector.app.features.analytics.plan.SuperProperties
import im.vector.app.features.analytics.plan.UserProperties
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.SingleIn
@ -148,6 +149,10 @@ class DefaultAnalyticsService @Inject constructor( @@ -148,6 +149,10 @@ class DefaultAnalyticsService @Inject constructor(
}
}
override fun updateSuperProperties(updatedProperties: SuperProperties) {
this.analyticsProviders.onEach { it.updateSuperProperties(updatedProperties) }
}
override fun trackError(throwable: Throwable) {
if (userConsent.get()) {
analyticsProviders.onEach { it.trackError(throwable) }

23
services/analytics/impl/src/test/kotlin/io/element/android/services/analytics/impl/DefaultAnalyticsServiceTest.kt

@ -23,6 +23,7 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent @@ -23,6 +23,7 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
import im.vector.app.features.analytics.itf.VectorAnalyticsScreen
import im.vector.app.features.analytics.plan.MobileScreen
import im.vector.app.features.analytics.plan.PollEnd
import im.vector.app.features.analytics.plan.SuperProperties
import im.vector.app.features.analytics.plan.UserProperties
import io.element.android.libraries.sessionstorage.api.observer.SessionObserver
import io.element.android.libraries.sessionstorage.test.observer.NoOpSessionObserver
@ -255,6 +256,23 @@ class DefaultAnalyticsServiceTest { @@ -255,6 +256,23 @@ class DefaultAnalyticsServiceTest {
updateUserPropertiesLambda.assertions().isCalledOnce().with(value(aUserProperty))
}
@Test
fun `when super properties are updated, updateSuperProperties is sent to the provider`() = runCancellableScopeTest {
val updateSuperPropertiesLambda = lambdaRecorder<SuperProperties, Unit> { _ -> }
val sut = createDefaultAnalyticsService(
coroutineScope = it,
analyticsProviders = setOf(
FakeAnalyticsProvider(
initLambda = { },
updateSuperPropertiesLambda = updateSuperPropertiesLambda,
)
),
analyticsStore = FakeAnalyticsStore(defaultUserConsent = true),
)
sut.updateSuperProperties(aSuperProperty)
updateSuperPropertiesLambda.assertions().isCalledOnce().with(value(aSuperProperty))
}
private suspend fun createDefaultAnalyticsService(
coroutineScope: CoroutineScope,
analyticsProviders: Set<@JvmSuppressWildcards AnalyticsProvider> = setOf(
@ -280,6 +298,11 @@ class DefaultAnalyticsServiceTest { @@ -280,6 +298,11 @@ class DefaultAnalyticsServiceTest {
private val aUserProperty = UserProperties(
ftueUseCaseSelection = UserProperties.FtueUseCaseSelection.WorkMessaging,
)
private val aSuperProperty = SuperProperties(
appPlatform = SuperProperties.AppPlatform.EXA,
cryptoSDK = SuperProperties.CryptoSDK.Rust,
cryptoSDKVersion = "0.0"
)
private val anError = Exception("a reason")
private const val AN_ID = "anId"
}

2
services/analytics/noop/src/main/kotlin/io/element/android/services/analytics/noop/NoopAnalyticsService.kt

@ -19,6 +19,7 @@ package io.element.android.services.analytics.noop @@ -19,6 +19,7 @@ package io.element.android.services.analytics.noop
import com.squareup.anvil.annotations.ContributesBinding
import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
import im.vector.app.features.analytics.itf.VectorAnalyticsScreen
import im.vector.app.features.analytics.plan.SuperProperties
import im.vector.app.features.analytics.plan.UserProperties
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.SingleIn
@ -43,4 +44,5 @@ class NoopAnalyticsService @Inject constructor() : AnalyticsService { @@ -43,4 +44,5 @@ class NoopAnalyticsService @Inject constructor() : AnalyticsService {
override fun screen(screen: VectorAnalyticsScreen) = Unit
override fun updateUserProperties(userProperties: UserProperties) = Unit
override fun trackError(throwable: Throwable) = Unit
override fun updateSuperProperties(updatedProperties: SuperProperties) = Unit
}

5
services/analytics/test/src/main/kotlin/io/element/android/services/analytics/test/FakeAnalyticsService.kt

@ -18,6 +18,7 @@ package io.element.android.services.analytics.test @@ -18,6 +18,7 @@ package io.element.android.services.analytics.test
import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
import im.vector.app.features.analytics.itf.VectorAnalyticsScreen
import im.vector.app.features.analytics.plan.SuperProperties
import im.vector.app.features.analytics.plan.UserProperties
import io.element.android.services.analytics.api.AnalyticsService
import io.element.android.services.analyticsproviders.api.AnalyticsProvider
@ -70,6 +71,10 @@ class FakeAnalyticsService( @@ -70,6 +71,10 @@ class FakeAnalyticsService(
trackedErrors += throwable
}
override fun updateSuperProperties(updatedProperties: SuperProperties) {
// No op
}
override suspend fun reset() {
didAskUserConsentFlow.value = false
}

7
services/analyticsproviders/api/src/main/kotlin/io/element/android/services/analyticsproviders/api/trackers/AnalyticsTracker.kt

@ -19,6 +19,7 @@ package io.element.android.services.analyticsproviders.api.trackers @@ -19,6 +19,7 @@ package io.element.android.services.analyticsproviders.api.trackers
import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
import im.vector.app.features.analytics.itf.VectorAnalyticsScreen
import im.vector.app.features.analytics.plan.Interaction
import im.vector.app.features.analytics.plan.SuperProperties
import im.vector.app.features.analytics.plan.UserProperties
interface AnalyticsTracker {
@ -36,6 +37,12 @@ interface AnalyticsTracker { @@ -36,6 +37,12 @@ interface AnalyticsTracker {
* Update user specific properties.
*/
fun updateUserProperties(userProperties: UserProperties)
/**
* Update the super properties.
* Super properties are added to any tracked event automatically.
*/
fun updateSuperProperties(updatedProperties: SuperProperties)
}
fun AnalyticsTracker.captureInteraction(name: Interaction.Name, type: Interaction.InteractionType? = null) {

38
services/analyticsproviders/posthog/src/main/kotlin/io/element/android/services/analyticsproviders/posthog/PosthogAnalyticsProvider.kt

@ -20,7 +20,7 @@ import com.posthog.PostHogInterface @@ -20,7 +20,7 @@ import com.posthog.PostHogInterface
import com.squareup.anvil.annotations.ContributesMultibinding
import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
import im.vector.app.features.analytics.itf.VectorAnalyticsScreen
import im.vector.app.features.analytics.plan.Error
import im.vector.app.features.analytics.plan.SuperProperties
import im.vector.app.features.analytics.plan.UserProperties
import io.element.android.libraries.di.AppScope
import io.element.android.services.analyticsproviders.api.AnalyticsProvider
@ -42,6 +42,8 @@ class PosthogAnalyticsProvider @Inject constructor( @@ -42,6 +42,8 @@ class PosthogAnalyticsProvider @Inject constructor(
private var pendingUserProperties: MutableMap<String, Any>? = null
private var superProperties: SuperProperties? = null
private val userPropertiesLock = Any()
override fun init() {
@ -64,7 +66,7 @@ class PosthogAnalyticsProvider @Inject constructor( @@ -64,7 +66,7 @@ class PosthogAnalyticsProvider @Inject constructor(
synchronized(userPropertiesLock) {
posthog?.capture(
event = event.getName(),
properties = event.getProperties()?.keepOnlyNonNullValues().withExtraProperties(),
properties = event.getProperties()?.keepOnlyNonNullValues().withSuperProperties(),
userProperties = pendingUserProperties,
)
pendingUserProperties = null
@ -74,7 +76,7 @@ class PosthogAnalyticsProvider @Inject constructor( @@ -74,7 +76,7 @@ class PosthogAnalyticsProvider @Inject constructor(
override fun screen(screen: VectorAnalyticsScreen) {
posthog?.screen(
screenTitle = screen.getName(),
properties = screen.getProperties().withExtraProperties(),
properties = screen.getProperties().withSuperProperties(),
)
}
@ -94,6 +96,14 @@ class PosthogAnalyticsProvider @Inject constructor( @@ -94,6 +96,14 @@ class PosthogAnalyticsProvider @Inject constructor(
}
}
override fun updateSuperProperties(updatedProperties: SuperProperties) {
this.superProperties = SuperProperties(
cryptoSDK = updatedProperties.cryptoSDK ?: this.superProperties?.cryptoSDK,
appPlatform = updatedProperties.appPlatform ?: this.superProperties?.appPlatform,
cryptoSDKVersion = updatedProperties.cryptoSDKVersion ?: superProperties?.cryptoSDKVersion
)
}
override fun trackError(throwable: Throwable) {
// Not implemented
}
@ -110,6 +120,17 @@ class PosthogAnalyticsProvider @Inject constructor( @@ -110,6 +120,17 @@ class PosthogAnalyticsProvider @Inject constructor(
// posthog?.identify(id, lateInitUserPropertiesFactory.createUserProperties()?.getProperties()?.toPostHogUserProperties(), IGNORED_OPTIONS)
}
}
private fun Map<String, Any>?.withSuperProperties(): Map<String, Any>? {
val withSuperProperties = this.orEmpty().toMutableMap()
val superProperties = this@PosthogAnalyticsProvider.superProperties?.getProperties()
superProperties?.forEach {
if (!withSuperProperties.containsKey(it.key)) {
withSuperProperties[it.key] = it.value
}
}
return withSuperProperties.takeIf { it.isEmpty().not() }
}
}
private fun Map<String, Any?>.keepOnlyNonNullValues(): Map<String, Any> {
@ -122,14 +143,3 @@ private fun Map<String, Any?>.keepOnlyNonNullValues(): Map<String, Any> { @@ -122,14 +143,3 @@ private fun Map<String, Any?>.keepOnlyNonNullValues(): Map<String, Any> {
}
return result
}
/**
* Properties which will be added to all Events and Screens.
*/
private val extraProperties: Map<String, Any> = mapOf(
"cryptoSDK" to Error.CryptoSDK.Rust
)
private fun Map<String, Any>?.withExtraProperties(): Map<String, Any> {
return orEmpty() + extraProperties
}

111
services/analyticsproviders/posthog/src/test/kotlin/io/element/android/services/analyticsproviders/posthog/PosthogAnalyticsProviderTest.kt

@ -19,6 +19,8 @@ package io.element.android.services.analyticsproviders.posthog @@ -19,6 +19,8 @@ package io.element.android.services.analyticsproviders.posthog
import com.google.common.truth.Truth.assertThat
import com.posthog.PostHogInterface
import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
import im.vector.app.features.analytics.plan.MobileScreen
import im.vector.app.features.analytics.plan.SuperProperties
import im.vector.app.features.analytics.plan.UserProperties
import io.element.android.tests.testutils.WarmUpRule
import io.mockk.every
@ -113,4 +115,113 @@ class PosthogAnalyticsProviderTest { @@ -113,4 +115,113 @@ class PosthogAnalyticsProviderTest {
assertThat(userPropertiesSlot.captured).isNotNull()
assertThat(userPropertiesSlot.captured["verificationState"] as String).isEqualTo(testUserPropertiesUpdate.verificationState?.name)
}
@Test
fun `Posthog - Test super properties added to all captured events`() = runTest {
val mockPosthog = mockk<PostHogInterface>().also {
every { it.optIn() } just runs
every { it.capture(any(), any(), any(), any(), any(), any()) } just runs
every { it.screen(any(), any()) } just runs
}
val mockPosthogFactory = mockk<PostHogFactory>()
every { mockPosthogFactory.createPosthog() } returns mockPosthog
val analyticsProvider = PosthogAnalyticsProvider(mockPosthogFactory)
analyticsProvider.init()
val testSuperProperties = SuperProperties(
appPlatform = SuperProperties.AppPlatform.EXA,
)
analyticsProvider.updateSuperProperties(testSuperProperties)
// Test with events having different sort of properties
listOf(
mapOf("foo" to "bar"),
mapOf("a" to "aValue1", "b" to "aValue2"),
null
).forEach { eventProperties ->
// report an event with properties
val mockEvent = mockk<VectorAnalyticsEvent>().also {
every {
it.getProperties()
} returns eventProperties
every { it.getName() } returns "MockEventName"
}
analyticsProvider.capture(mockEvent)
val expectedProperties = eventProperties.orEmpty() + testSuperProperties.getProperties().orEmpty()
verify { mockPosthog.capture(event = "MockEventName", any(), properties = expectedProperties, any()) }
}
// / Test it is also added to screens
val screenEvent = MobileScreen(null, MobileScreen.ScreenName.Home)
analyticsProvider.screen(screenEvent)
verify { mockPosthog.screen(MobileScreen.ScreenName.Home.rawValue, testSuperProperties.getProperties()) }
}
@Test
fun `Posthog - Test super properties can be updated`() = runTest {
val mockPosthog = mockk<PostHogInterface>().also {
every { it.optIn() } just runs
every { it.capture(any(), any(), any(), any(), any(), any()) } just runs
}
val mockPosthogFactory = mockk<PostHogFactory>()
every { mockPosthogFactory.createPosthog() } returns mockPosthog
val analyticsProvider = PosthogAnalyticsProvider(mockPosthogFactory)
analyticsProvider.init()
// Test with events having different sort of aggregation
// left is the updated properties, right is the expected aggregated state
mapOf(
SuperProperties(appPlatform = SuperProperties.AppPlatform.EXA) to SuperProperties(appPlatform = SuperProperties.AppPlatform.EXA),
SuperProperties(cryptoSDKVersion = "0.0") to SuperProperties(appPlatform = SuperProperties.AppPlatform.EXA, cryptoSDKVersion = "0.0"),
SuperProperties(cryptoSDKVersion = "1.0") to SuperProperties(appPlatform = SuperProperties.AppPlatform.EXA, cryptoSDKVersion = "1.0"),
SuperProperties(cryptoSDK = SuperProperties.CryptoSDK.Rust) to SuperProperties(
appPlatform = SuperProperties.AppPlatform.EXA,
cryptoSDKVersion = "1.0",
cryptoSDK = SuperProperties.CryptoSDK.Rust
),
).entries.forEach { (updated, expected) ->
// report an event with properties
val mockEvent = mockk<VectorAnalyticsEvent>().also {
every {
it.getProperties()
} returns null
every { it.getName() } returns "MockEventName"
}
analyticsProvider.updateSuperProperties(updated)
analyticsProvider.capture(mockEvent)
verify { mockPosthog.capture(event = "MockEventName", any(), properties = expected.getProperties(), any()) }
}
}
@Test
fun `Posthog - Test super properties do not override property with same name on the event`() = runTest {
val mockPosthog = mockk<PostHogInterface>().also {
every { it.optIn() } just runs
every { it.capture(any(), any(), any(), any(), any(), any()) } just runs
}
val mockPosthogFactory = mockk<PostHogFactory>()
every { mockPosthogFactory.createPosthog() } returns mockPosthog
val analyticsProvider = PosthogAnalyticsProvider(mockPosthogFactory)
analyticsProvider.init()
// report an event with properties
val mockEvent = mockk<VectorAnalyticsEvent>().also {
every {
it.getProperties()
} returns mapOf("appPlatform" to SuperProperties.AppPlatform.Other)
every { it.getName() } returns "MockEventName"
}
analyticsProvider.updateSuperProperties(SuperProperties(appPlatform = SuperProperties.AppPlatform.EXA))
analyticsProvider.capture(mockEvent)
verify { mockPosthog.capture(event = "MockEventName", any(), properties = mapOf("appPlatform" to SuperProperties.AppPlatform.Other), any()) }
}
}

4
services/analyticsproviders/sentry/src/main/kotlin/io/element/android/services/analyticsproviders/sentry/SentryAnalyticsProvider.kt

@ -20,6 +20,7 @@ import android.content.Context @@ -20,6 +20,7 @@ import android.content.Context
import com.squareup.anvil.annotations.ContributesMultibinding
import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
import im.vector.app.features.analytics.itf.VectorAnalyticsScreen
import im.vector.app.features.analytics.plan.SuperProperties
import im.vector.app.features.analytics.plan.UserProperties
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.core.meta.BuildType
@ -67,6 +68,9 @@ class SentryAnalyticsProvider @Inject constructor( @@ -67,6 +68,9 @@ class SentryAnalyticsProvider @Inject constructor(
override fun updateUserProperties(userProperties: UserProperties) {
}
override fun updateSuperProperties(updatedProperties: SuperProperties) {
}
override fun trackError(throwable: Throwable) {
Sentry.captureException(throwable)
}

3
services/analyticsproviders/test/src/main/kotlin/io/element/android/services/analyticsproviders/test/FakeAnalyticsProvider.kt

@ -18,6 +18,7 @@ package io.element.android.services.analyticsproviders.test @@ -18,6 +18,7 @@ package io.element.android.services.analyticsproviders.test
import im.vector.app.features.analytics.itf.VectorAnalyticsEvent
import im.vector.app.features.analytics.itf.VectorAnalyticsScreen
import im.vector.app.features.analytics.plan.SuperProperties
import im.vector.app.features.analytics.plan.UserProperties
import io.element.android.services.analyticsproviders.api.AnalyticsProvider
import io.element.android.tests.testutils.lambda.lambdaError
@ -29,6 +30,7 @@ class FakeAnalyticsProvider( @@ -29,6 +30,7 @@ class FakeAnalyticsProvider(
private val captureLambda: (VectorAnalyticsEvent) -> Unit = { lambdaError() },
private val screenLambda: (VectorAnalyticsScreen) -> Unit = { lambdaError() },
private val updateUserPropertiesLambda: (UserProperties) -> Unit = { lambdaError() },
private val updateSuperPropertiesLambda: (SuperProperties) -> Unit = { lambdaError() },
private val trackErrorLambda: (Throwable) -> Unit = { lambdaError() }
) : AnalyticsProvider {
override fun init() = initLambda()
@ -37,4 +39,5 @@ class FakeAnalyticsProvider( @@ -37,4 +39,5 @@ class FakeAnalyticsProvider(
override fun screen(screen: VectorAnalyticsScreen) = screenLambda(screen)
override fun updateUserProperties(userProperties: UserProperties) = updateUserPropertiesLambda(userProperties)
override fun trackError(throwable: Throwable) = trackErrorLambda(throwable)
override fun updateSuperProperties(updatedProperties: SuperProperties) = updateSuperPropertiesLambda(updatedProperties)
}

Loading…
Cancel
Save