-
Notifications
You must be signed in to change notification settings - Fork 66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Analytics #1591
Merged
Merged
Analytics #1591
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
OscarSpruit
force-pushed
the
feature/analytics
branch
from
May 7, 2024 15:29
d2a3fd0
to
44485a3
Compare
OscarSpruit
added
Chore
[PRs only] Indicates any task that does not need to be mentioned in the public release notes
and removed
Feature
[PRs only] Indicates a new feature addition
labels
May 16, 2024
OscarSpruit
force-pushed
the
feature/analytics
branch
3 times, most recently
from
May 22, 2024 13:22
9397fd3
to
6c4799f
Compare
OscarSpruit
force-pushed
the
feature/analytics
branch
5 times, most recently
from
May 23, 2024 15:07
6c4799f
to
f0c7301
Compare
OscarSpruit
force-pushed
the
feature/analytics
branch
3 times, most recently
from
May 28, 2024 09:18
b6d5936
to
35086e9
Compare
COAND-844 diff --git a/checkout-core/src/main/java/com/adyen/checkout/core/internal/analytics/AdyenAnalytics.kt b/checkout-core/src/main/java/com/adyen/checkout/core/internal/analytics/AdyenAnalytics.kt deleted file mode 100644 index 4106710ea..000000000 --- a/checkout-core/src/main/java/com/adyen/checkout/core/internal/analytics/AdyenAnalytics.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2024 Adyen N.V. - * - * This file is open source and available under the MIT license. See the LICENSE file for more info. - * - * Created by oscars on 6/2/2024. - */ - -package com.adyen.checkout.core.internal.analytics - -import androidx.annotation.RestrictTo - -@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) -class AdyenAnalytics { - - fun setup() { - // See DefaultAnalyticsRepository.setupAnalytics - } - - fun track(event: AnalyticsEvent) { - // Queue the event - // Send it - } -} diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AdyenAnalytics.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AdyenAnalytics.kt new file mode 100644 index 000000000..d012b5721 --- /dev/null +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AdyenAnalytics.kt @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2024 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by oscars on 12/2/2024. + */ + +package com.adyen.checkout.components.core.internal.analytics + +import androidx.annotation.RestrictTo +import androidx.annotation.VisibleForTesting +import com.adyen.checkout.components.core.internal.data.api.AnalyticsService +import com.adyen.checkout.components.core.internal.ui.model.AnalyticsParams +import com.adyen.checkout.components.core.internal.ui.model.AnalyticsParamsLevel +import com.adyen.checkout.core.AdyenLogLevel +import com.adyen.checkout.core.internal.util.adyenLog +import com.adyen.checkout.core.internal.util.runSuspendCatching +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch + +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +class AdyenAnalytics( + private val analyticsProvider: AnalyticsProvider, + private val analyticsParams: AnalyticsParams, + private val analyticsService: AnalyticsService, + coroutineDispatcher: CoroutineDispatcher = Dispatchers.Default, +) { + + // TODO: Check if Job or SupervisorJob is better for us + private val coroutineScope = CoroutineScope(coroutineDispatcher + SupervisorJob()) + + @volatile + var checkoutAttemptId: String? = null + private set + + @volatile + private var state: State = State.Uninitialized + + fun setup() { + if (cannotSendEvent()) { + checkoutAttemptId = CHECKOUT_ATTEMPT_ID_FOR_DISABLED_ANALYTICS + return + } + + if (state != State.Uninitialized) return + state = State.InProgress + adyenLog(AdyenLogLevel.VERBOSE) { "Setting up analytics" } + + coroutineScope.launch { + runSuspendCatching { + val analyticsSetupRequest = analyticsProvider.provide() + val response = analyticsService.setupAnalytics(analyticsSetupRequest, analyticsParams.clientKey) + checkoutAttemptId = response.checkoutAttemptId + state = State.Ready + adyenLog(AdyenLogLevel.VERBOSE) { "Analytics setup call successful" } + }.onFailure { e -> + state = State.Failed + adyenLog(AdyenLogLevel.ERROR) { + "Failed to send analytics setup call - ${e::class.simpleName}: ${e.message}" + } + } + } + } + + fun track(event: AnalyticsEvent) { + // TODO: Check if we can send events anyway, because attempt id is anonymous already + if (cannotSendEvent()) return + + // Queue the event + // Send it + } + + private fun cannotSendEvent(): Boolean { + return analyticsParams.level.priority <= AnalyticsParamsLevel.NONE.priority + } + + companion object { + private const val CHECKOUT_ATTEMPT_ID_FOR_DISABLED_ANALYTICS = "do-not-track" + } + + @VisibleForTesting + internal sealed class State { + data object Uninitialized : State() + data object InProgress : State() + data object Ready : State() + data object Failed : State() + } +} diff --git a/checkout-core/src/main/java/com/adyen/checkout/core/internal/analytics/AnalyticsEventApi.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsEventApi.kt similarity index 78% rename from checkout-core/src/main/java/com/adyen/checkout/core/internal/analytics/AnalyticsEventApi.kt rename to components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsEventApi.kt index 8a98d58f6..d3775c469 100644 --- a/checkout-core/src/main/java/com/adyen/checkout/core/internal/analytics/AnalyticsEventApi.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsEventApi.kt @@ -3,10 +3,10 @@ * * This file is open source and available under the MIT license. See the LICENSE file for more info. * - * Created by oscars on 7/2/2024. + * Created by oscars on 12/2/2024. */ -package com.adyen.checkout.core.internal.analytics +package com.adyen.checkout.components.core.internal.analytics import androidx.annotation.RestrictTo diff --git a/checkout-core/src/main/java/com/adyen/checkout/core/internal/analytics/AnalyticsEvents.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsEvents.kt similarity index 96% rename from checkout-core/src/main/java/com/adyen/checkout/core/internal/analytics/AnalyticsEvents.kt rename to components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsEvents.kt index 28027debc..d90089e3e 100644 --- a/checkout-core/src/main/java/com/adyen/checkout/core/internal/analytics/AnalyticsEvents.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsEvents.kt @@ -6,7 +6,7 @@ * Created by oscars on 7/2/2024. */ -package com.adyen.checkout.core.internal.analytics +package com.adyen.checkout.components.core.internal.analytics import androidx.annotation.RestrictTo import java.util.Date diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsProvider.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsProvider.kt index fd6f27593..70a792048 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsProvider.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsProvider.kt @@ -21,7 +21,6 @@ import com.adyen.checkout.components.core.internal.ui.model.ComponentParams class AnalyticsProvider( val application: Application, val componentParams: ComponentParams, - // drop-in or txVariant val source: AnalyticsSource, val sessionId: String?, ) { diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsSource.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsSource.kt index 4b4c58185..7938e93c7 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsSource.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/AnalyticsSource.kt @@ -12,11 +12,12 @@ import androidx.annotation.RestrictTo @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) sealed class AnalyticsSource { - data class DropIn(val paymentMethods: List<String>) : AnalyticsSource() + data class DropIn(val paymentMethodList: List<String>) : AnalyticsSource() data class PaymentComponent(val paymentMethodType: String) : AnalyticsSource() + // TODO: Check if we can rename paymentMethodList and not make it clash with this function fun getPaymentMethods(): List<String> = when(this) { - is DropIn -> paymentMethods + is DropIn -> paymentMethodList is PaymentComponent -> listOf(paymentMethodType) } } diff --git a/checkout-core/src/main/java/com/adyen/checkout/core/internal/analytics/GenericEvents.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/GenericEvents.kt similarity index 80% rename from checkout-core/src/main/java/com/adyen/checkout/core/internal/analytics/GenericEvents.kt rename to components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/GenericEvents.kt index f9e46dd02..b99a56ce0 100644 --- a/checkout-core/src/main/java/com/adyen/checkout/core/internal/analytics/GenericEvents.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/analytics/GenericEvents.kt @@ -3,10 +3,10 @@ * * This file is open source and available under the MIT license. See the LICENSE file for more info. * - * Created by oscars on 7/2/2024. + * Created by oscars on 12/2/2024. */ -package com.adyen.checkout.core.internal.analytics +package com.adyen.checkout.components.core.internal.analytics import androidx.annotation.RestrictTo @@ -22,7 +22,7 @@ object GenericEvents { brand: String? = null, ) = AnalyticsEvent.Info( component = component, - type = InfoEventType.RENDERED, + type = AnalyticsEvent.Info.Type.RENDERED, isStoredPaymentMethod = isStoredPaymentMethod, brand = brand, ) @@ -32,7 +32,7 @@ object GenericEvents { target: String, ) = AnalyticsEvent.Info( component = component, - type = InfoEventType.DISPLAYED, + type = AnalyticsEvent.Info.Type.DISPLAYED, target = target, ) @@ -42,7 +42,7 @@ object GenericEvents { issuer: String, ) = AnalyticsEvent.Info( component = component, - type = InfoEventType.SELECTED, + type = AnalyticsEvent.Info.Type.SELECTED, target = target, issuer = issuer, ) @@ -52,7 +52,7 @@ object GenericEvents { target: String, ) = AnalyticsEvent.Info( component = component, - type = InfoEventType.INPUT, + type = AnalyticsEvent.Info.Type.INPUT, target = target, ) @@ -63,7 +63,7 @@ object GenericEvents { target: String, ) = AnalyticsEvent.Info( component = component, - type = InfoEventType.FOCUS, + type = AnalyticsEvent.Info.Type.FOCUS, target = target, ) @@ -72,7 +72,7 @@ object GenericEvents { target: String, ) = AnalyticsEvent.Info( component = component, - type = InfoEventType.UNFOCUS, + type = AnalyticsEvent.Info.Type.UNFOCUS, target = target, ) @@ -81,7 +81,7 @@ object GenericEvents { target: String, ) = AnalyticsEvent.Info( component = component, - type = InfoEventType.DOWNLOAD, + type = AnalyticsEvent.Info.Type.DOWNLOAD, target = target, ) @@ -92,7 +92,7 @@ object GenericEvents { validationErrorMessage: String?, ) = AnalyticsEvent.Info( component = component, - type = InfoEventType.VALIDATION_ERROR, + type = AnalyticsEvent.Info.Type.VALIDATION_ERROR, target = target, validationErrorCode = validationErrorCode, validationErrorMessage = validationErrorMessage, @@ -103,7 +103,7 @@ object GenericEvents { component: String, ) = AnalyticsEvent.Log( component = component, - type = LogEventType.SUBMIT, + type = AnalyticsEvent.Log.Type.SUBMIT, ) fun threeDS2( @@ -111,7 +111,7 @@ object GenericEvents { message: String, ) = AnalyticsEvent.Log( component = component, - type = LogEventType.THREEDS2, + type = AnalyticsEvent.Log.Type.THREEDS2, message = message, ) @@ -121,7 +121,7 @@ object GenericEvents { message: String, ) = AnalyticsEvent.Log( component = component, - type = LogEventType.ACTION, + type = AnalyticsEvent.Log.Type.ACTION, subType = subType, message = message, ) diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/AnalyticsRepositoryData.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/AnalyticsRepositoryData.kt index 5d215f7ea..f5fea4d92 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/AnalyticsRepositoryData.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/AnalyticsRepositoryData.kt @@ -40,7 +40,7 @@ data class AnalyticsRepositoryData( ) : this( application = application, componentParams = componentParams, - source = AnalyticsSource.PaymentComponent(componentParams.isCreatedByDropIn, paymentMethod), + source = AnalyticsSource.PaymentComponent(paymentMethod.type.orEmpty()), paymentMethodType = paymentMethod.type, sessionId = sessionId, ) @@ -53,7 +53,7 @@ data class AnalyticsRepositoryData( ) : this( application = application, componentParams = componentParams, - source = AnalyticsSource.PaymentComponent(componentParams.isCreatedByDropIn, storedPaymentMethod), + source = AnalyticsSource.PaymentComponent(storedPaymentMethod.type.orEmpty()), paymentMethodType = storedPaymentMethod.type, sessionId = sessionId, ) diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/DefaultAnalyticsRepository.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/DefaultAnalyticsRepository.kt index b9557b82a..fbd5e7918 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/DefaultAnalyticsRepository.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/data/api/DefaultAnalyticsRepository.kt @@ -40,33 +40,33 @@ class DefaultAnalyticsRepository( state = State.InProgress adyenLog(AdyenLogLevel.VERBOSE) { "Setting up analytics" } - runSuspendCatching { - val analyticsSetupRequest = with(analyticsRepositoryData) { - analyticsMapper.getAnalyticsSetupRequest( - packageName = packageName, - locale = locale, - source = source, - amount = amount, - screenWidth = screenWidth.toLong(), - paymentMethods = paymentMethods, - sessionId = sessionId, - ) - } - val response = analyticsService.setupAnalytics(analyticsSetupRequest, analyticsRepositoryData.clientKey) - checkoutAttemptId = response.checkoutAttemptId - state = State.Ready - adyenLog(AdyenLogLevel.VERBOSE) { "Analytics setup call successful" } - }.onFailure { e -> - state = State.Failed - adyenLog(AdyenLogLevel.ERROR) { - "Failed to send analytics setup call - ${e::class.simpleName}: ${e.message}" - } - } +// runSuspendCatching { +// val analyticsSetupRequest = with(analyticsRepositoryData) { +// analyticsMapper.getAnalyticsSetupRequest( +// packageName = packageName, +// locale = locale, +// source = source, +// amount = amount, +// screenWidth = screenWidth.toLong(), +// paymentMethods = paymentMethods, +// sessionId = sessionId, +// ) +// } +// val response = analyticsService.setupAnalytics(analyticsSetupRequest, analyticsRepositoryData.clientKey) +// checkoutAttemptId = response.checkoutAttemptId +// state = State.Ready +// adyenLog(AdyenLogLevel.VERBOSE) { "Analytics setup call successful" } +// }.onFailure { e -> +// state = State.Failed +// adyenLog(AdyenLogLevel.ERROR) { +// "Failed to send analytics setup call - ${e::class.simpleName}: ${e.message}" +// } +// } } private fun canSendAnalytics(requiredLevel: AnalyticsParamsLevel): Boolean { require(requiredLevel != NONE) { "Analytics are not allowed with level NONE" } - return !analyticsRepositoryData.level.hasHigherPriorityThan(requiredLevel) + return true } companion object { diff --git a/components-core/src/main/java/com/adyen/checkout/components/core/internal/ui/model/AnalyticsParams.kt b/components-core/src/main/java/com/adyen/checkout/components/core/internal/ui/model/AnalyticsParams.kt index c95ed163f..8214b77f5 100644 --- a/components-core/src/main/java/com/adyen/checkout/components/core/internal/ui/model/AnalyticsParams.kt +++ b/components-core/src/main/java/com/adyen/checkout/components/core/internal/ui/model/AnalyticsParams.kt @@ -15,20 +15,19 @@ import com.adyen.checkout.components.core.AnalyticsLevel @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) data class AnalyticsParams( val level: AnalyticsParamsLevel, + val clientKey: String, ) { - constructor(analyticsConfiguration: AnalyticsConfiguration?) : - this(level = getLevel(analyticsConfiguration)) + constructor( + analyticsConfiguration: AnalyticsConfiguration?, + clientKey: String, + ) : this(level = getLevel(analyticsConfiguration), clientKey = clientKey) } @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) -enum class AnalyticsParamsLevel(private val priority: Int) { - ALL(1), - NONE(2); - - internal fun hasHigherPriorityThan(level: AnalyticsParamsLevel): Boolean { - return priority > level.priority - } +enum class AnalyticsParamsLevel(val priority: Int) { + NONE(1), + ALL(2), } private fun getLevel(analyticsConfiguration: AnalyticsConfiguration?): AnalyticsParamsLevel { diff --git a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModelFactory.kt b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModelFactory.kt index f65293023..fd98091ce 100644 --- a/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModelFactory.kt +++ b/drop-in/src/main/java/com/adyen/checkout/dropin/internal/ui/DropInViewModelFactory.kt @@ -13,6 +13,7 @@ import androidx.lifecycle.AbstractSavedStateViewModelFactory import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import com.adyen.checkout.components.core.CheckoutConfiguration +import com.adyen.checkout.components.core.internal.analytics.AnalyticsSource import com.adyen.checkout.components.core.internal.data.api.AnalyticsMapper import com.adyen.checkout.components.core.internal.data.api.AnalyticsRepositoryData import com.adyen.checkout.components.core.internal.data.api.AnalyticsService
COAND-844
COAND-844
COAND-844
COAND-844
COAND-844
…k submit event. COAND-845
COAND-845
…Delegate COAND-845
…ectDebitDelegate COAND-845
COAND-845
COAND-845
COAND-845
COAND-845
The line was logged even when no events were actually sent. Now it should only log when events are actually successfully sent. COAND-845
This will prevent an edge case where we would accidentally clear events that were not sent yet. COAND-845
initState can be called from other places, so it's not the right place to send the event. COAND-845
araratthehero
force-pushed
the
feature/analytics
branch
from
May 28, 2024 13:15
35086e9
to
6114555
Compare
OscarSpruit
approved these changes
May 28, 2024
Quality Gate passedIssues Measures |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
Chore
[PRs only] Indicates any task that does not need to be mentioned in the public release notes
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Description
Add Analytics
Checklist
COAND-846