Skip to content

Commit 1a12930

Browse files
committed
Draft CustomPaymentMethod API
1 parent 7ac1de6 commit 1a12930

31 files changed

+436
-17
lines changed

paymentsheet/api/paymentsheet.api

+32
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,30 @@ public final class com/stripe/android/lpmfoundations/paymentmethod/link/LinkInli
542542
public synthetic fun newArray (I)[Ljava/lang/Object;
543543
}
544544

545+
public final class com/stripe/android/paymentelement/CustomPaymentMethodResult$Canceled$Creator : android/os/Parcelable$Creator {
546+
public fun <init> ()V
547+
public final fun createFromParcel (Landroid/os/Parcel;)Lcom/stripe/android/paymentelement/CustomPaymentMethodResult$Canceled;
548+
public synthetic fun createFromParcel (Landroid/os/Parcel;)Ljava/lang/Object;
549+
public final fun newArray (I)[Lcom/stripe/android/paymentelement/CustomPaymentMethodResult$Canceled;
550+
public synthetic fun newArray (I)[Ljava/lang/Object;
551+
}
552+
553+
public final class com/stripe/android/paymentelement/CustomPaymentMethodResult$Completed$Creator : android/os/Parcelable$Creator {
554+
public fun <init> ()V
555+
public final fun createFromParcel (Landroid/os/Parcel;)Lcom/stripe/android/paymentelement/CustomPaymentMethodResult$Completed;
556+
public synthetic fun createFromParcel (Landroid/os/Parcel;)Ljava/lang/Object;
557+
public final fun newArray (I)[Lcom/stripe/android/paymentelement/CustomPaymentMethodResult$Completed;
558+
public synthetic fun newArray (I)[Ljava/lang/Object;
559+
}
560+
561+
public final class com/stripe/android/paymentelement/CustomPaymentMethodResult$Failed$Creator : android/os/Parcelable$Creator {
562+
public fun <init> ()V
563+
public final fun createFromParcel (Landroid/os/Parcel;)Lcom/stripe/android/paymentelement/CustomPaymentMethodResult$Failed;
564+
public synthetic fun createFromParcel (Landroid/os/Parcel;)Ljava/lang/Object;
565+
public final fun newArray (I)[Lcom/stripe/android/paymentelement/CustomPaymentMethodResult$Failed;
566+
public synthetic fun newArray (I)[Ljava/lang/Object;
567+
}
568+
545569
public final class com/stripe/android/paymentelement/EmbeddedPaymentElement$Configuration$Creator : android/os/Parcelable$Creator {
546570
public fun <init> ()V
547571
public final fun createFromParcel (Landroid/os/Parcel;)Lcom/stripe/android/paymentelement/EmbeddedPaymentElement$Configuration;
@@ -1333,6 +1357,14 @@ public final class com/stripe/android/paymentsheet/PaymentSheet$Configuration$Cr
13331357
public synthetic fun newArray (I)[Ljava/lang/Object;
13341358
}
13351359

1360+
public final class com/stripe/android/paymentsheet/PaymentSheet$CustomPaymentMethodType$Creator : android/os/Parcelable$Creator {
1361+
public fun <init> ()V
1362+
public final fun createFromParcel (Landroid/os/Parcel;)Lcom/stripe/android/paymentsheet/PaymentSheet$CustomPaymentMethodType;
1363+
public synthetic fun createFromParcel (Landroid/os/Parcel;)Ljava/lang/Object;
1364+
public final fun newArray (I)[Lcom/stripe/android/paymentsheet/PaymentSheet$CustomPaymentMethodType;
1365+
public synthetic fun newArray (I)[Ljava/lang/Object;
1366+
}
1367+
13361368
public final class com/stripe/android/paymentsheet/PaymentSheet$CustomerAccessType$CustomerSession$Creator : android/os/Parcelable$Creator {
13371369
public fun <init> ()V
13381370
public final fun createFromParcel (Landroid/os/Parcel;)Lcom/stripe/android/paymentsheet/PaymentSheet$CustomerAccessType$CustomerSession;

paymentsheet/src/main/java/com/stripe/android/common/configuration/ConfigurationDefaults.kt

+5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.stripe.android.common.configuration
22

33
import android.content.res.ColorStateList
44
import com.stripe.android.model.CardBrand
5+
import com.stripe.android.paymentelement.ExperimentalCustomPaymentMethodsApi
56
import com.stripe.android.paymentsheet.PaymentSheet
67
import com.stripe.android.paymentsheet.PaymentSheet.PaymentMethodLayout
78
import com.stripe.android.paymentsheet.addresselement.AddressDetails
@@ -26,5 +27,9 @@ internal object ConfigurationDefaults {
2627
val externalPaymentMethods: List<String> = emptyList()
2728
val paymentMethodLayout: PaymentMethodLayout = PaymentMethodLayout.Automatic
2829
val cardBrandAcceptance: PaymentSheet.CardBrandAcceptance = PaymentSheet.CardBrandAcceptance.All
30+
31+
@OptIn(ExperimentalCustomPaymentMethodsApi::class)
32+
val customPaymentMethodTypes: List<PaymentSheet.CustomPaymentMethodType> = emptyList()
33+
2934
const val embeddedViewDisplaysMandateText: Boolean = true
3035
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.stripe.android.paymentelement
2+
3+
import androidx.annotation.RestrictTo
4+
import com.stripe.android.model.PaymentMethod
5+
import com.stripe.android.paymentsheet.PaymentSheet
6+
7+
/**
8+
* Handler to be used to confirm payment with a custom payment method.
9+
*
10+
* To learn more about custom payment methods, see "docs_url"
11+
*/
12+
@ExperimentalCustomPaymentMethodsApi
13+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
14+
fun interface CustomPaymentMethodConfirmHandler {
15+
16+
/**
17+
* Called when a user confirms payment or setup with a custom payment method.
18+
*
19+
* On completion, this should call [CustomPaymentMethodResultHandler.onCustomPaymentMethodResult] with the
20+
* result of the custom payment method's confirmation.
21+
*
22+
* @param customPaymentMethodType The custom payment method to confirm payment with
23+
* @param billingDetails Any billing details you've configured Payment Element to collect
24+
*/
25+
fun confirmCustomPaymentMethod(
26+
customPaymentMethodType: PaymentSheet.CustomPaymentMethodType,
27+
billingDetails: PaymentMethod.BillingDetails,
28+
)
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package com.stripe.android.paymentelement
2+
3+
import android.content.Context
4+
import android.os.Parcelable
5+
import androidx.annotation.RestrictTo
6+
import kotlinx.parcelize.Parcelize
7+
8+
/**
9+
* Handler used to respond to custom payment method confirm results.
10+
*/
11+
@ExperimentalCustomPaymentMethodsApi
12+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
13+
object CustomPaymentMethodResultHandler {
14+
15+
/**
16+
* Updates the Payment Element UI to reflect the result of confirming a custom payment method.
17+
*
18+
* Should be called when [CustomPaymentMethodConfirmHandler.confirmCustomPaymentMethod] completes.
19+
*/
20+
@JvmStatic
21+
@SuppressWarnings("UnusedParameter")
22+
fun onCustomPaymentMethodResult(context: Context, customPaymentMethodResult: CustomPaymentMethodResult) {
23+
// TODO(samer-stripe): Implement what to do with custom payment method result
24+
}
25+
}
26+
27+
/**
28+
* The result of an attempt to confirm a custom payment method.
29+
*/
30+
@ExperimentalCustomPaymentMethodsApi
31+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
32+
sealed class CustomPaymentMethodResult : Parcelable {
33+
@Parcelize
34+
internal data object Completed : CustomPaymentMethodResult()
35+
36+
@Parcelize
37+
internal data object Canceled : CustomPaymentMethodResult()
38+
39+
@Parcelize
40+
internal data class Failed(
41+
val displayMessage: String?,
42+
) : CustomPaymentMethodResult()
43+
44+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
45+
companion object {
46+
47+
/**
48+
* The customer successfully completed the payment or setup.
49+
*/
50+
@JvmStatic
51+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
52+
fun completed(): CustomPaymentMethodResult {
53+
return Completed
54+
}
55+
56+
/**
57+
* The customer canceled the payment or setup attempt.
58+
*/
59+
@JvmStatic
60+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
61+
fun canceled(): CustomPaymentMethodResult {
62+
return Canceled
63+
}
64+
65+
/**
66+
* The payment or setup attempt failed.
67+
*
68+
* @param displayMessage Message to display to the user on failure. If null, will display Stripe's default
69+
* error message.
70+
*/
71+
@JvmStatic
72+
@JvmOverloads
73+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
74+
fun failed(displayMessage: String? = null): CustomPaymentMethodResult {
75+
return Failed(displayMessage)
76+
}
77+
}
78+
}

paymentsheet/src/main/java/com/stripe/android/paymentelement/EmbeddedPaymentElement.kt

+29
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import javax.inject.Inject
4040
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
4141
@ExperimentalEmbeddedPaymentElementApi
4242
@EmbeddedPaymentElementScope
43+
@OptIn(ExperimentalCustomPaymentMethodsApi::class)
4344
class EmbeddedPaymentElement @Inject internal constructor(
4445
private val confirmationHelper: EmbeddedConfirmationHelper,
4546
private val contentHelper: EmbeddedContentHelper,
@@ -115,12 +116,23 @@ class EmbeddedPaymentElement @Inject internal constructor(
115116
internal var externalPaymentMethodConfirmHandler: ExternalPaymentMethodConfirmHandler? = null
116117
private set
117118

119+
internal var customPaymentMethodConfirmHandler: CustomPaymentMethodConfirmHandler? = null
120+
private set
121+
118122
/**
119123
* Called when a user confirms payment for an external payment method.
120124
*/
121125
fun externalPaymentMethodConfirmHandler(handler: ExternalPaymentMethodConfirmHandler) = apply {
122126
this.externalPaymentMethodConfirmHandler = handler
123127
}
128+
129+
/**
130+
* Called when a user confirms payment for a custom payment method.
131+
*/
132+
@ExperimentalCustomPaymentMethodsApi
133+
fun customPaymentMethodConfirmHandler(handler: CustomPaymentMethodConfirmHandler) = apply {
134+
this.customPaymentMethodConfirmHandler = handler
135+
}
124136
}
125137

126138
/** Configuration for [EmbeddedPaymentElement] **/
@@ -144,6 +156,7 @@ class EmbeddedPaymentElement @Inject internal constructor(
144156
internal val paymentMethodOrder: List<String>,
145157
internal val externalPaymentMethods: List<String>,
146158
internal val cardBrandAcceptance: PaymentSheet.CardBrandAcceptance,
159+
internal val customPaymentMethodTypes: List<PaymentSheet.CustomPaymentMethodType>,
147160
internal val embeddedViewDisplaysMandateText: Boolean,
148161
) : Parcelable {
149162
@Suppress("TooManyFunctions")
@@ -174,6 +187,8 @@ class EmbeddedPaymentElement @Inject internal constructor(
174187
private var cardBrandAcceptance: PaymentSheet.CardBrandAcceptance =
175188
ConfigurationDefaults.cardBrandAcceptance
176189
private var embeddedViewDisplaysMandateText: Boolean = ConfigurationDefaults.embeddedViewDisplaysMandateText
190+
private var customPaymentMethodTypes: List<PaymentSheet.CustomPaymentMethodType> =
191+
ConfigurationDefaults.customPaymentMethodTypes
177192

178193
/**
179194
* If set, the customer can select a previously saved payment method.
@@ -330,6 +345,19 @@ class EmbeddedPaymentElement @Inject internal constructor(
330345
this.cardBrandAcceptance = cardBrandAcceptance
331346
}
332347

348+
/**
349+
* Configuration related to custom payment methods.
350+
*
351+
* If set, Embedded Payment Element will display the defined list of custom payment methods in the UI.
352+
*/
353+
@ExperimentalCustomPaymentMethodsApi
354+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
355+
fun customPaymentMethodTypes(
356+
customPaymentMethodTypes: List<PaymentSheet.CustomPaymentMethodType>,
357+
) = apply {
358+
this.customPaymentMethodTypes = customPaymentMethodTypes
359+
}
360+
333361
/**
334362
* Controls whether the view displays mandate text at the bottom for payment methods that require it.
335363
*
@@ -360,6 +388,7 @@ class EmbeddedPaymentElement @Inject internal constructor(
360388
paymentMethodOrder = paymentMethodOrder,
361389
externalPaymentMethods = externalPaymentMethods,
362390
cardBrandAcceptance = cardBrandAcceptance,
391+
customPaymentMethodTypes = customPaymentMethodTypes,
363392
embeddedViewDisplaysMandateText = embeddedViewDisplaysMandateText,
364393
)
365394
}

paymentsheet/src/main/java/com/stripe/android/paymentelement/EmbeddedPaymentElementKtx.kt

+2
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,11 @@ fun rememberEmbeddedPaymentElement(
3434
UUID.randomUUID().toString()
3535
}
3636

37+
@OptIn(ExperimentalCustomPaymentMethodsApi::class)
3738
val callbacks = remember(builder) {
3839
PaymentElementCallbacks(
3940
createIntentCallback = builder.createIntentCallback,
41+
customPaymentMethodConfirmHandler = builder.customPaymentMethodConfirmHandler,
4042
externalPaymentMethodConfirmHandler = builder.externalPaymentMethodConfirmHandler,
4143
)
4244
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.stripe.android.paymentelement
2+
3+
import androidx.annotation.RestrictTo
4+
5+
@RequiresOptIn(message = "Custom payment methods support is beta. It may be changed in the future without notice.")
6+
@Retention(AnnotationRetention.BINARY)
7+
@Target(
8+
AnnotationTarget.CLASS,
9+
AnnotationTarget.FUNCTION,
10+
AnnotationTarget.PROPERTY,
11+
)
12+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
13+
annotation class ExperimentalCustomPaymentMethodsApi
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package com.stripe.android.paymentelement.callbacks
22

3+
import com.stripe.android.paymentelement.CustomPaymentMethodConfirmHandler
4+
import com.stripe.android.paymentelement.ExperimentalCustomPaymentMethodsApi
35
import com.stripe.android.paymentsheet.CreateIntentCallback
46
import com.stripe.android.paymentsheet.ExternalPaymentMethodConfirmHandler
57

8+
@OptIn(ExperimentalCustomPaymentMethodsApi::class)
69
internal class PaymentElementCallbacks(
710
val createIntentCallback: CreateIntentCallback?,
11+
val customPaymentMethodConfirmHandler: CustomPaymentMethodConfirmHandler?,
812
val externalPaymentMethodConfirmHandler: ExternalPaymentMethodConfirmHandler?,
913
)

paymentsheet/src/main/java/com/stripe/android/paymentsheet/FlowControllerCompose.kt

+11
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import androidx.compose.runtime.saveable.rememberSaveable
77
import androidx.lifecycle.compose.LocalLifecycleOwner
88
import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner
99
import com.stripe.android.common.ui.UpdateCallbacks
10+
import com.stripe.android.paymentelement.CustomPaymentMethodConfirmHandler
11+
import com.stripe.android.paymentelement.ExperimentalCustomPaymentMethodsApi
1012
import com.stripe.android.paymentelement.callbacks.PaymentElementCallbacks
1113
import com.stripe.android.paymentsheet.flowcontroller.FlowControllerFactory
1214
import com.stripe.android.utils.rememberActivity
@@ -25,9 +27,11 @@ fun rememberPaymentSheetFlowController(
2527
paymentOptionCallback: PaymentOptionCallback,
2628
paymentResultCallback: PaymentSheetResultCallback,
2729
): PaymentSheet.FlowController {
30+
@OptIn(ExperimentalCustomPaymentMethodsApi::class)
2831
return internalRememberPaymentSheetFlowController(
2932
paymentOptionCallback = paymentOptionCallback,
3033
paymentResultCallback = paymentResultCallback,
34+
customPaymentMethodConfirmHandler = null,
3135
createIntentCallback = null,
3236
externalPaymentMethodConfirmHandler = null,
3337
)
@@ -50,9 +54,11 @@ fun rememberPaymentSheetFlowController(
5054
paymentOptionCallback: PaymentOptionCallback,
5155
paymentResultCallback: PaymentSheetResultCallback,
5256
): PaymentSheet.FlowController {
57+
@OptIn(ExperimentalCustomPaymentMethodsApi::class)
5358
return internalRememberPaymentSheetFlowController(
5459
paymentOptionCallback = paymentOptionCallback,
5560
paymentResultCallback = paymentResultCallback,
61+
customPaymentMethodConfirmHandler = null,
5662
createIntentCallback = createIntentCallback,
5763
externalPaymentMethodConfirmHandler = null,
5864
)
@@ -79,9 +85,11 @@ fun rememberPaymentSheetFlowController(
7985
paymentOptionCallback: PaymentOptionCallback,
8086
paymentResultCallback: PaymentSheetResultCallback,
8187
): PaymentSheet.FlowController {
88+
@OptIn(ExperimentalCustomPaymentMethodsApi::class)
8289
return internalRememberPaymentSheetFlowController(
8390
paymentOptionCallback = paymentOptionCallback,
8491
paymentResultCallback = paymentResultCallback,
92+
customPaymentMethodConfirmHandler = null,
8593
createIntentCallback = createIntentCallback,
8694
externalPaymentMethodConfirmHandler = externalPaymentMethodConfirmHandler
8795
)
@@ -139,10 +147,12 @@ private fun internalRememberPaymentSheetFlowController(
139147
}
140148
}
141149

150+
@OptIn(ExperimentalCustomPaymentMethodsApi::class)
142151
@Composable
143152
internal fun internalRememberPaymentSheetFlowController(
144153
createIntentCallback: CreateIntentCallback?,
145154
externalPaymentMethodConfirmHandler: ExternalPaymentMethodConfirmHandler?,
155+
customPaymentMethodConfirmHandler: CustomPaymentMethodConfirmHandler?,
146156
paymentOptionCallback: PaymentOptionCallback,
147157
paymentResultCallback: PaymentSheetResultCallback,
148158
): PaymentSheet.FlowController {
@@ -153,6 +163,7 @@ internal fun internalRememberPaymentSheetFlowController(
153163
val callbacks = remember(createIntentCallback, externalPaymentMethodConfirmHandler) {
154164
PaymentElementCallbacks(
155165
createIntentCallback = createIntentCallback,
166+
customPaymentMethodConfirmHandler = customPaymentMethodConfirmHandler,
156167
externalPaymentMethodConfirmHandler = externalPaymentMethodConfirmHandler,
157168
)
158169
}

0 commit comments

Comments
 (0)