diff --git a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt index f179f7d71b9..c80dd6a9abd 100644 --- a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt +++ b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/PaymentSheetPlaygroundActivity.kt @@ -31,6 +31,7 @@ import com.stripe.android.customersheet.CustomerSheetResult import com.stripe.android.customersheet.rememberCustomerSheet import com.stripe.android.model.PaymentMethod import com.stripe.android.paymentelement.AnalyticEvent +import com.stripe.android.paymentelement.ExperimentalAnalyticEventCallbackApi import com.stripe.android.paymentsheet.ExperimentalCustomerSessionApi import com.stripe.android.paymentsheet.ExternalPaymentMethodConfirmHandler import com.stripe.android.paymentsheet.PaymentSheet @@ -79,7 +80,7 @@ internal class PaymentSheetPlaygroundActivity : AppCompatActivity(), ExternalPay viewModel.onEmbeddedResult(success) } - @OptIn(ExperimentalCustomerSessionApi::class) + @OptIn(ExperimentalCustomerSessionApi::class, ExperimentalAnalyticEventCallbackApi::class) @Suppress("LongMethod") override fun onCreate(savedInstanceState: Bundle?) { enableEdgeToEdge() diff --git a/paymentsheet/api/paymentsheet.api b/paymentsheet/api/paymentsheet.api index bb6757f4729..2a6ce25ba05 100644 --- a/paymentsheet/api/paymentsheet.api +++ b/paymentsheet/api/paymentsheet.api @@ -556,41 +556,62 @@ public abstract class com/stripe/android/paymentelement/AnalyticEvent { public final class com/stripe/android/paymentelement/AnalyticEvent$CompletedPaymentMethodForm : com/stripe/android/paymentelement/AnalyticEvent { public static final field $stable I + public fun equals (Ljava/lang/Object;)Z public final fun getPaymentMethodType ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; } public final class com/stripe/android/paymentelement/AnalyticEvent$DisplayedPaymentMethodForm : com/stripe/android/paymentelement/AnalyticEvent { public static final field $stable I + public fun equals (Ljava/lang/Object;)Z public final fun getPaymentMethodType ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; } -public final class com/stripe/android/paymentelement/AnalyticEvent$PresentPaymentSheet : com/stripe/android/paymentelement/AnalyticEvent { +public final class com/stripe/android/paymentelement/AnalyticEvent$PresentedSheet : com/stripe/android/paymentelement/AnalyticEvent { public static final field $stable I } public final class com/stripe/android/paymentelement/AnalyticEvent$RemovedSavedPaymentMethod : com/stripe/android/paymentelement/AnalyticEvent { public static final field $stable I + public fun equals (Ljava/lang/Object;)Z public final fun getPaymentMethodType ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; } public final class com/stripe/android/paymentelement/AnalyticEvent$SelectedPaymentMethodType : com/stripe/android/paymentelement/AnalyticEvent { public static final field $stable I + public fun equals (Ljava/lang/Object;)Z public final fun getPaymentMethodType ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; } public final class com/stripe/android/paymentelement/AnalyticEvent$SelectedSavedPaymentMethod : com/stripe/android/paymentelement/AnalyticEvent { public static final field $stable I + public fun equals (Ljava/lang/Object;)Z public final fun getPaymentMethodType ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; } public final class com/stripe/android/paymentelement/AnalyticEvent$StartedInteractionWithPaymentMethodForm : com/stripe/android/paymentelement/AnalyticEvent { public static final field $stable I + public fun equals (Ljava/lang/Object;)Z public final fun getPaymentMethodType ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; } public final class com/stripe/android/paymentelement/AnalyticEvent$TappedConfirmButton : com/stripe/android/paymentelement/AnalyticEvent { public static final field $stable I + public fun equals (Ljava/lang/Object;)Z public final fun getPaymentMethodType ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; } public abstract interface class com/stripe/android/paymentelement/AnalyticEventCallback { diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentelement/AnalyticEventCallback.kt b/paymentsheet/src/main/java/com/stripe/android/paymentelement/AnalyticEventCallback.kt index 0df342a09d7..174d7d8a2dc 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentelement/AnalyticEventCallback.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentelement/AnalyticEventCallback.kt @@ -11,11 +11,12 @@ import kotlinx.coroutines.flow.asSharedFlow * * @param event the [AnalyticEvent] that was emitted */ +@ExperimentalAnalyticEventCallbackApi fun interface AnalyticEventCallback { fun onEvent(event: AnalyticEvent) } - +@ExperimentalAnalyticEventCallbackApi abstract class AnalyticEvent internal constructor() { @Override @@ -55,6 +56,7 @@ abstract class AnalyticEvent internal constructor() { class RemovedSavedPaymentMethod internal constructor(val paymentMethodType: String) : AnalyticEvent() } +@OptIn(ExperimentalAnalyticEventCallbackApi::class) internal object AnalyticsManager { private val _events = MutableSharedFlow() val events = _events.asSharedFlow() diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentelement/EmbeddedPaymentElement.kt b/paymentsheet/src/main/java/com/stripe/android/paymentelement/EmbeddedPaymentElement.kt index 8786d0cb9d2..0213221e3b6 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentelement/EmbeddedPaymentElement.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentelement/EmbeddedPaymentElement.kt @@ -91,6 +91,7 @@ class EmbeddedPaymentElement private constructor( * * Creation can be completed with [rememberEmbeddedPaymentElement]. */ + @OptIn(ExperimentalAnalyticEventCallbackApi::class) @ExperimentalEmbeddedPaymentElementApi @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) class Builder( @@ -105,6 +106,8 @@ class EmbeddedPaymentElement private constructor( ) { internal var externalPaymentMethodConfirmHandler: ExternalPaymentMethodConfirmHandler? = null private set + internal var analyticEventCallback: AnalyticEventCallback? = null + private set /** * Called when a user confirms payment for an external payment method. @@ -112,6 +115,14 @@ class EmbeddedPaymentElement private constructor( fun externalPaymentMethodConfirmHandler(handler: ExternalPaymentMethodConfirmHandler) = apply { this.externalPaymentMethodConfirmHandler = handler } + + /** + * Called when an analytic event is emitted. + */ + @ExperimentalAnalyticEventCallbackApi + fun analyticEventCallback(callback: AnalyticEventCallback) = apply { + analyticEventCallback = callback + } } /** Configuration for [EmbeddedPaymentElement] **/ diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentelement/ExperimentalAnalyticEventCallbackApi.kt b/paymentsheet/src/main/java/com/stripe/android/paymentelement/ExperimentalAnalyticEventCallbackApi.kt new file mode 100644 index 00000000000..ef9871ab7ac --- /dev/null +++ b/paymentsheet/src/main/java/com/stripe/android/paymentelement/ExperimentalAnalyticEventCallbackApi.kt @@ -0,0 +1,11 @@ +package com.stripe.android.paymentelement + +import androidx.annotation.RestrictTo + +@RequiresOptIn( + level = RequiresOptIn.Level.ERROR, + message = "This API is under construction. It can be changed or removed at any time (use at your own risk)." +) +@Retention(AnnotationRetention.BINARY) +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +annotation class ExperimentalAnalyticEventCallbackApi diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/AnalyticEventInterceptor.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/AnalyticEventInterceptor.kt index fdc56554420..81f4092924d 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/AnalyticEventInterceptor.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/AnalyticEventInterceptor.kt @@ -1,7 +1,9 @@ package com.stripe.android.paymentsheet import com.stripe.android.paymentelement.AnalyticEventCallback +import com.stripe.android.paymentelement.ExperimentalAnalyticEventCallbackApi +@OptIn(ExperimentalAnalyticEventCallbackApi::class) internal object AnalyticEventInterceptor { var analyticEventCallback: AnalyticEventCallback? = null } diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/DefaultPaymentSheetLauncher.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/DefaultPaymentSheetLauncher.kt index da728d42f7a..c7cec3e69ff 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/DefaultPaymentSheetLauncher.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/DefaultPaymentSheetLauncher.kt @@ -13,6 +13,7 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import com.stripe.android.paymentelement.AnalyticsManager +import com.stripe.android.paymentelement.ExperimentalAnalyticEventCallbackApi import com.stripe.android.paymentelement.confirmation.intent.IntentConfirmationInterceptor import com.stripe.android.paymentsheet.state.PaymentElementLoader import com.stripe.android.uicore.utils.AnimationConstants @@ -25,6 +26,7 @@ import org.jetbrains.annotations.TestOnly * This is used internally for integrations that don't use Jetpack Compose and are * able to pass in an activity. */ +@OptIn(ExperimentalAnalyticEventCallbackApi::class) internal class DefaultPaymentSheetLauncher( private val activityResultLauncher: ActivityResultLauncher, private val activity: Activity, diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheet.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheet.kt index 306b7aab94b..e1ff31d6ee1 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheet.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheet.kt @@ -20,6 +20,7 @@ import com.stripe.android.model.CardBrand import com.stripe.android.model.PaymentIntent import com.stripe.android.model.SetupIntent import com.stripe.android.paymentelement.AnalyticEventCallback +import com.stripe.android.paymentelement.ExperimentalAnalyticEventCallbackApi import com.stripe.android.paymentelement.ExperimentalEmbeddedPaymentElementApi import com.stripe.android.paymentelement.confirmation.intent.IntentConfirmationInterceptor import com.stripe.android.paymentsheet.addresselement.AddressDetails @@ -190,6 +191,7 @@ class PaymentSheet internal constructor( * * @param resultCallback Called with the result of the payment after [PaymentSheet] is dismissed. */ + @OptIn(ExperimentalAnalyticEventCallbackApi::class) class Builder(internal val resultCallback: PaymentSheetResultCallback) { internal var externalPaymentMethodConfirmHandler: ExternalPaymentMethodConfirmHandler? = null private set @@ -217,6 +219,7 @@ class PaymentSheet internal constructor( /** * @param callback Called when an analytic event occurs. */ + @ExperimentalAnalyticEventCallbackApi fun analyticEventCallback(callback: AnalyticEventCallback) = apply { analyticEventCallback = callback } @@ -2094,6 +2097,7 @@ class PaymentSheet internal constructor( * @param resultCallback Called when a [PaymentSheetResult] is available. * @param paymentOptionCallback Called when the customer's desired payment method changes. */ + @OptIn(ExperimentalAnalyticEventCallbackApi::class) class Builder( internal val resultCallback: PaymentSheetResultCallback, internal val paymentOptionCallback: PaymentOptionCallback @@ -2122,6 +2126,7 @@ class PaymentSheet internal constructor( /** * @param callback If specified, called when an analytic event occurs. */ + @ExperimentalAnalyticEventCallbackApi fun analyticEventCallback(callback: AnalyticEventCallback) = apply { analyticEventCallback = callback } diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/analytics/DefaultEventReporter.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/analytics/DefaultEventReporter.kt index dcd32e25513..7d5c1a41a60 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/analytics/DefaultEventReporter.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/analytics/DefaultEventReporter.kt @@ -9,6 +9,7 @@ import com.stripe.android.model.PaymentMethodCode import com.stripe.android.networking.PaymentAnalyticsRequestFactory import com.stripe.android.paymentelement.AnalyticEvent import com.stripe.android.paymentelement.AnalyticsManager +import com.stripe.android.paymentelement.ExperimentalAnalyticEventCallbackApi import com.stripe.android.paymentelement.confirmation.intent.DeferredIntentConfirmationType import com.stripe.android.paymentsheet.PaymentSheet import com.stripe.android.paymentsheet.model.PaymentSelection @@ -18,6 +19,7 @@ import kotlinx.coroutines.launch import javax.inject.Inject import kotlin.coroutines.CoroutineContext +@OptIn(ExperimentalAnalyticEventCallbackApi::class) internal class DefaultEventReporter @Inject internal constructor( private val mode: EventReporter.Mode, private val analyticsRequestExecutor: AnalyticsRequestExecutor,