diff --git a/CHANGELOG.md b/CHANGELOG.md index 914d3f2caf1..3dbf0019ff2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## XX.XX.XX - 2023-XX-XX +### Payments +* [ADDED][7431](https://github.com/stripe/stripe-android/pull/7431) Added bindings support for MobilePay. See [private beta information](https://stripe.com/docs/payments/mobilepay). + ## 20.32.1 - 2023-10-09 ### PaymentSheet diff --git a/example/AndroidManifest.xml b/example/AndroidManifest.xml index e8d856293f6..f60c7f3f5b2 100644 --- a/example/AndroidManifest.xml +++ b/example/AndroidManifest.xml @@ -81,6 +81,7 @@ + diff --git a/example/res/values/strings.xml b/example/res/values/strings.xml index 0a8ab8d83ea..c6b66584cd5 100644 --- a/example/res/values/strings.xml +++ b/example/res/values/strings.xml @@ -35,6 +35,7 @@ Cash App Pay Revolut Pay Swish + MobilePay Card Brands Card number Possible Card Brands diff --git a/example/src/main/java/com/stripe/example/activity/LauncherActivity.kt b/example/src/main/java/com/stripe/example/activity/LauncherActivity.kt index 97335fc6b3a..6f24beeb11b 100644 --- a/example/src/main/java/com/stripe/example/activity/LauncherActivity.kt +++ b/example/src/main/java/com/stripe/example/activity/LauncherActivity.kt @@ -185,6 +185,10 @@ class LauncherActivity : AppCompatActivity() { activity.getString(R.string.swish_example), SwishExampleActivity::class.java ), + Item( + activity.getString(R.string.mobilepay_example), + MobilePayExampleActivity::class.java + ), // This is for internal use so as not to confuse the user. Item( "StripeImage Example", diff --git a/example/src/main/java/com/stripe/example/activity/MobilePayExampleActivity.kt b/example/src/main/java/com/stripe/example/activity/MobilePayExampleActivity.kt new file mode 100644 index 00000000000..d7b1b08c137 --- /dev/null +++ b/example/src/main/java/com/stripe/example/activity/MobilePayExampleActivity.kt @@ -0,0 +1,90 @@ +package com.stripe.example.activity + +import android.os.Bundle +import androidx.activity.compose.setContent +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material.Button +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.Divider +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.google.accompanist.themeadapter.material.MdcTheme +import com.stripe.android.model.PaymentMethodCreateParams + +class MobilePayExampleActivity : StripeIntentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContent { + val isProcessing by viewModel.inProgress.observeAsState(initial = false) + val status by viewModel.status.observeAsState(initial = "") + + MobilePayScreen( + isProcessing = isProcessing, + status = status, + onButtonPressed = { payWithMobilePay() }, + ) + } + } + + private fun payWithMobilePay() { + val params = PaymentMethodCreateParams.createMobilePay() + + createAndConfirmPaymentIntent( + country = "FR", + currency = "EUR", + paymentMethodCreateParams = params, + supportedPaymentMethods = "mobilepay", + ) + } +} + +@Composable +private fun MobilePayScreen( + isProcessing: Boolean, + status: String, + onButtonPressed: () -> Unit, +) { + MdcTheme { + Column(modifier = Modifier.fillMaxSize()) { + Row(verticalAlignment = Alignment.CenterVertically) { + Button( + onClick = onButtonPressed, + enabled = !isProcessing, + modifier = Modifier.padding(16.dp), + ) { + Text("Pay with MobilePay") + } + + if (isProcessing) { + CircularProgressIndicator(modifier = Modifier.size(24.dp)) + } + } + + if (status.isNotBlank()) { + Divider( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + ) + + Text( + text = status, + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + ) + } + } + } +} diff --git a/payments-core/api/payments-core.api b/payments-core/api/payments-core.api index bf044fc3f94..c8c75a40983 100644 --- a/payments-core/api/payments-core.api +++ b/payments-core/api/payments-core.api @@ -3971,6 +3971,9 @@ public final class com/stripe/android/model/PaymentMethodCreateParams : android/ public static final fun createKlarna ()Lcom/stripe/android/model/PaymentMethodCreateParams; public static final fun createKlarna (Lcom/stripe/android/model/PaymentMethod$BillingDetails;)Lcom/stripe/android/model/PaymentMethodCreateParams; public static final fun createKlarna (Lcom/stripe/android/model/PaymentMethod$BillingDetails;Ljava/util/Map;)Lcom/stripe/android/model/PaymentMethodCreateParams; + public static final fun createMobilePay ()Lcom/stripe/android/model/PaymentMethodCreateParams; + public static final fun createMobilePay (Lcom/stripe/android/model/PaymentMethod$BillingDetails;)Lcom/stripe/android/model/PaymentMethodCreateParams; + public static final fun createMobilePay (Lcom/stripe/android/model/PaymentMethod$BillingDetails;Ljava/util/Map;)Lcom/stripe/android/model/PaymentMethodCreateParams; public static final fun createOxxo (Lcom/stripe/android/model/PaymentMethod$BillingDetails;)Lcom/stripe/android/model/PaymentMethodCreateParams; public static final fun createOxxo (Lcom/stripe/android/model/PaymentMethod$BillingDetails;Ljava/util/Map;)Lcom/stripe/android/model/PaymentMethodCreateParams; public static final fun createP24 (Lcom/stripe/android/model/PaymentMethod$BillingDetails;)Lcom/stripe/android/model/PaymentMethodCreateParams; @@ -4194,6 +4197,10 @@ public final class com/stripe/android/model/PaymentMethodCreateParams$Companion public final fun createKlarna (Lcom/stripe/android/model/PaymentMethod$BillingDetails;)Lcom/stripe/android/model/PaymentMethodCreateParams; public final fun createKlarna (Lcom/stripe/android/model/PaymentMethod$BillingDetails;Ljava/util/Map;)Lcom/stripe/android/model/PaymentMethodCreateParams; public static synthetic fun createKlarna$default (Lcom/stripe/android/model/PaymentMethodCreateParams$Companion;Lcom/stripe/android/model/PaymentMethod$BillingDetails;Ljava/util/Map;ILjava/lang/Object;)Lcom/stripe/android/model/PaymentMethodCreateParams; + public final fun createMobilePay ()Lcom/stripe/android/model/PaymentMethodCreateParams; + public final fun createMobilePay (Lcom/stripe/android/model/PaymentMethod$BillingDetails;)Lcom/stripe/android/model/PaymentMethodCreateParams; + public final fun createMobilePay (Lcom/stripe/android/model/PaymentMethod$BillingDetails;Ljava/util/Map;)Lcom/stripe/android/model/PaymentMethodCreateParams; + public static synthetic fun createMobilePay$default (Lcom/stripe/android/model/PaymentMethodCreateParams$Companion;Lcom/stripe/android/model/PaymentMethod$BillingDetails;Ljava/util/Map;ILjava/lang/Object;)Lcom/stripe/android/model/PaymentMethodCreateParams; public final fun createOxxo (Lcom/stripe/android/model/PaymentMethod$BillingDetails;)Lcom/stripe/android/model/PaymentMethodCreateParams; public final fun createOxxo (Lcom/stripe/android/model/PaymentMethod$BillingDetails;Ljava/util/Map;)Lcom/stripe/android/model/PaymentMethodCreateParams; public static synthetic fun createOxxo$default (Lcom/stripe/android/model/PaymentMethodCreateParams$Companion;Lcom/stripe/android/model/PaymentMethod$BillingDetails;Ljava/util/Map;ILjava/lang/Object;)Lcom/stripe/android/model/PaymentMethodCreateParams; diff --git a/payments-core/src/main/java/com/stripe/android/model/PaymentMethodCreateParams.kt b/payments-core/src/main/java/com/stripe/android/model/PaymentMethodCreateParams.kt index 7ff161dd1b7..0d3f25e9da7 100644 --- a/payments-core/src/main/java/com/stripe/android/model/PaymentMethodCreateParams.kt +++ b/payments-core/src/main/java/com/stripe/android/model/PaymentMethodCreateParams.kt @@ -1048,6 +1048,19 @@ data class PaymentMethodCreateParams internal constructor( ) } + @JvmStatic + @JvmOverloads + fun createMobilePay( + billingDetails: PaymentMethod.BillingDetails? = null, + metadata: Map? = null + ): PaymentMethodCreateParams { + return PaymentMethodCreateParams( + type = PaymentMethod.Type.MobilePay, + billingDetails = billingDetails, + metadata = metadata + ) + } + @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) fun createLink( paymentDetailsId: String, diff --git a/payments-core/src/test/java/com/stripe/android/ApiKeyFixtures.kt b/payments-core/src/test/java/com/stripe/android/ApiKeyFixtures.kt index c67f0fbe300..757a0cf6c04 100644 --- a/payments-core/src/test/java/com/stripe/android/ApiKeyFixtures.kt +++ b/payments-core/src/test/java/com/stripe/android/ApiKeyFixtures.kt @@ -32,4 +32,6 @@ internal object ApiKeyFixtures { "pk_test_51KmkHbGoesj9fw9QAZJlz1qY4dns8nFmLKc7rXiWKAIj8QU7NPFPwSY1h8mqRaFRKQ9njs9pVJoo2jhN6ZKSDA4h00mjcbGF7b" const val SWISH_PUBLISHABLE_KEY = "pk_test_51JtgfQKG6vc7r7YCU0qQNOkDaaHrEgeHgGKrJMNfuWwaKgXMLzPUA1f8ZlCNPonIROLOnzpUnJK1C1xFH3M3Mz8X00Q6O4GfUt" + const val MOBILE_PAY_PUBLISHABLE_KEY = + "pk_test_51JtgfQKG6vc7r7YCU0qQNOkDaaHrEgeHgGKrJMNfuWwaKgXMLzPUA1f8ZlCNPonIROLOnzpUnJK1C1xFH3M3Mz8X00Q6O4GfUt" } diff --git a/payments-core/src/test/java/com/stripe/android/PaymentMethodEndToEndTest.kt b/payments-core/src/test/java/com/stripe/android/PaymentMethodEndToEndTest.kt index 1bd0a49ec7e..ac96ca5b9c1 100644 --- a/payments-core/src/test/java/com/stripe/android/PaymentMethodEndToEndTest.kt +++ b/payments-core/src/test/java/com/stripe/android/PaymentMethodEndToEndTest.kt @@ -465,4 +465,13 @@ internal class PaymentMethodEndToEndTest { val paymentMethod = stripe.createPaymentMethodSynchronous(params) assertThat(paymentMethod.type).isEqualTo(PaymentMethod.Type.Swish) } + + @Test + fun createPaymentMethod_withMobilePay_shouldCreateObject() { + val params = PaymentMethodCreateParamsFixtures.MOBILE_PAY + val stripe = Stripe(context, ApiKeyFixtures.MOBILE_PAY_PUBLISHABLE_KEY) + + val paymentMethod = stripe.createPaymentMethodSynchronous(params) + assertThat(paymentMethod.type).isEqualTo(PaymentMethod.Type.MobilePay) + } } diff --git a/payments-core/src/test/java/com/stripe/android/model/PaymentMethodCreateParamsFixtures.kt b/payments-core/src/test/java/com/stripe/android/model/PaymentMethodCreateParamsFixtures.kt index fd8159c71ec..b70be47bcab 100644 --- a/payments-core/src/test/java/com/stripe/android/model/PaymentMethodCreateParamsFixtures.kt +++ b/payments-core/src/test/java/com/stripe/android/model/PaymentMethodCreateParamsFixtures.kt @@ -125,6 +125,10 @@ internal object PaymentMethodCreateParamsFixtures { billingDetails = BILLING_DETAILS, ) + internal val MOBILE_PAY = PaymentMethodCreateParams.createMobilePay( + billingDetails = BILLING_DETAILS, + ) + @JvmStatic fun createWith(metadata: Map): PaymentMethodCreateParams { return PaymentMethodCreateParams.create( diff --git a/paymentsheet-example/src/androidTest/java/com/stripe/android/lpm/TestMobilePay.kt b/paymentsheet-example/src/androidTest/java/com/stripe/android/lpm/TestMobilePay.kt new file mode 100644 index 00000000000..888bc8eac43 --- /dev/null +++ b/paymentsheet-example/src/androidTest/java/com/stripe/android/lpm/TestMobilePay.kt @@ -0,0 +1,37 @@ +package com.stripe.android.lpm + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.stripe.android.BasePlaygroundTest +import com.stripe.android.paymentsheet.example.playground.settings.Country +import com.stripe.android.paymentsheet.example.playground.settings.CountrySettingsDefinition +import com.stripe.android.paymentsheet.example.playground.settings.Currency +import com.stripe.android.paymentsheet.example.playground.settings.CurrencySettingsDefinition +import com.stripe.android.paymentsheet.example.playground.settings.SupportedPaymentMethodsSettingsDefinition +import com.stripe.android.test.core.TestParameters +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +internal class TestMobilePay : BasePlaygroundTest() { + private val testParameters = TestParameters.create( + paymentMethodCode = "mobilepay", + ) { settings -> + settings[CountrySettingsDefinition] = Country.FR + settings[CurrencySettingsDefinition] = Currency.EUR + settings[SupportedPaymentMethodsSettingsDefinition] = listOf("card", "mobilepay") + } + + @Test + fun testMobilePay() { + testDriver.confirmNewOrGuestComplete( + testParameters = testParameters, + ) + } + + @Test + fun testMobilePayInCustomFlow() { + testDriver.confirmCustom( + testParameters = testParameters, + ) + } +}