diff --git a/stripe/src/main/java/com/stripe/android/PaymentAuthWebViewStarter.kt b/stripe/src/main/java/com/stripe/android/PaymentAuthWebViewStarter.kt index 3c2939f817a..1ab65cacc18 100644 --- a/stripe/src/main/java/com/stripe/android/PaymentAuthWebViewStarter.kt +++ b/stripe/src/main/java/com/stripe/android/PaymentAuthWebViewStarter.kt @@ -29,7 +29,8 @@ internal class PaymentAuthWebViewStarter internal constructor( val url: String, val returnUrl: String? = null, val enableLogging: Boolean = false, - val toolbarCustomization: StripeToolbarCustomization? = null + val toolbarCustomization: StripeToolbarCustomization? = null, + val stripeAccountId: String? = null ) : Parcelable internal companion object { diff --git a/stripe/src/main/java/com/stripe/android/PaymentController.kt b/stripe/src/main/java/com/stripe/android/PaymentController.kt index 11ab4a71a87..81b85b6ebe1 100644 --- a/stripe/src/main/java/com/stripe/android/PaymentController.kt +++ b/stripe/src/main/java/com/stripe/android/PaymentController.kt @@ -57,7 +57,6 @@ internal interface PaymentController { */ fun handlePaymentResult( data: Intent, - requestOptions: ApiRequest.Options, callback: ApiResultCallback ) @@ -72,7 +71,6 @@ internal interface PaymentController { */ fun handleSetupResult( data: Intent, - requestOptions: ApiRequest.Options, callback: ApiResultCallback ) @@ -107,7 +105,8 @@ internal interface PaymentController { internal val exception: StripeException? = null, internal val shouldCancelSource: Boolean = false, internal val sourceId: String? = null, - internal val source: Source? = null + internal val source: Source? = null, + internal val stripeAccountId: String? = null ) : Parcelable { @JvmSynthetic fun toBundle(): Bundle { @@ -124,7 +123,8 @@ internal interface PaymentController { exception = parcel.readSerializable() as? StripeException?, shouldCancelSource = parcel.readInt() == 1, sourceId = parcel.readString(), - source = parcel.readParcelable(Source::class.java.classLoader) + source = parcel.readParcelable(Source::class.java.classLoader), + stripeAccountId = parcel.readString() ) } @@ -135,6 +135,7 @@ internal interface PaymentController { parcel.writeInt(1.takeIf { shouldCancelSource } ?: 0) parcel.writeString(sourceId) parcel.writeParcelable(source, flags) + parcel.writeString(stripeAccountId) } private const val EXTRA = "extra_args" diff --git a/stripe/src/main/java/com/stripe/android/PaymentRelayStarter.kt b/stripe/src/main/java/com/stripe/android/PaymentRelayStarter.kt index efb723e69bf..cc0e971ea86 100644 --- a/stripe/src/main/java/com/stripe/android/PaymentRelayStarter.kt +++ b/stripe/src/main/java/com/stripe/android/PaymentRelayStarter.kt @@ -28,7 +28,8 @@ internal interface PaymentRelayStarter : AuthActivityStarter { @JvmSynthetic - internal fun create(stripeIntent: StripeIntent): Args { - return Args(stripeIntent = stripeIntent) + internal fun create(stripeIntent: StripeIntent, stripeAccountId: String? = null): Args { + return Args(stripeIntent = stripeIntent, stripeAccountId = stripeAccountId) } @JvmSynthetic @@ -64,7 +66,8 @@ internal interface PaymentRelayStarter : AuthActivityStarter ): Boolean { return if (data != null && paymentController.shouldHandlePaymentResult(requestCode, data)) { - paymentController.handlePaymentResult( - data, - ApiRequest.Options( - apiKey = publishableKey, - stripeAccount = stripeAccountId - ), - callback - ) + paymentController.handlePaymentResult(data, callback) true } else { false @@ -362,10 +363,14 @@ class Stripe internal constructor( * Confirm and, if necessary, authenticate a [SetupIntent]. * * @param activity the `Activity` that is launching the payment authentication flow + * @param stripeAccountId Optional, the Connect account to associate with this request. + * By default, will use the Connect account that was used to instantiate the `Stripe` object, if specified. */ + @JvmOverloads fun confirmSetupIntent( activity: Activity, - confirmSetupIntentParams: ConfirmSetupIntentParams + confirmSetupIntentParams: ConfirmSetupIntentParams, + stripeAccountId: String? = this.stripeAccountId ) { paymentController.startConfirmAndAuth( AuthActivityStarter.Host.create(activity), @@ -508,14 +513,7 @@ class Stripe internal constructor( callback: ApiResultCallback ): Boolean { return if (data != null && paymentController.shouldHandleSetupResult(requestCode, data)) { - paymentController.handleSetupResult( - data, - ApiRequest.Options( - apiKey = publishableKey, - stripeAccount = stripeAccountId - ), - callback - ) + paymentController.handleSetupResult(data, callback) true } else { false diff --git a/stripe/src/main/java/com/stripe/android/StripePaymentController.kt b/stripe/src/main/java/com/stripe/android/StripePaymentController.kt index d25dc1263ea..838aa6cc4f0 100644 --- a/stripe/src/main/java/com/stripe/android/StripePaymentController.kt +++ b/stripe/src/main/java/com/stripe/android/StripePaymentController.kt @@ -42,7 +42,7 @@ import kotlinx.coroutines.Dispatchers */ internal class StripePaymentController internal constructor( context: Context, - publishableKey: String, + private val publishableKey: String, private val stripeRepository: StripeRepository, private val enableLogging: Boolean = false, private val messageVersionRegistry: MessageVersionRegistry = @@ -195,7 +195,6 @@ internal class StripePaymentController internal constructor( */ override fun handlePaymentResult( data: Intent, - requestOptions: ApiRequest.Options, callback: ApiResultCallback ) { val result = PaymentController.Result.fromIntent(data) ?: PaymentController.Result() @@ -209,6 +208,11 @@ internal class StripePaymentController internal constructor( val sourceId = result.sourceId.orEmpty() @StripeIntentResult.Outcome val flowOutcome = result.flowOutcome + val requestOptions = ApiRequest.Options( + apiKey = publishableKey, + stripeAccount = result.stripeAccountId + ) + stripeRepository.retrieveIntent( getClientSecret(data), requestOptions, @@ -230,7 +234,6 @@ internal class StripePaymentController internal constructor( */ override fun handleSetupResult( data: Intent, - requestOptions: ApiRequest.Options, callback: ApiResultCallback ) { val result = PaymentController.Result.fromIntent(data) ?: PaymentController.Result() @@ -244,6 +247,11 @@ internal class StripePaymentController internal constructor( val sourceId = result.sourceId.orEmpty() @StripeIntentResult.Outcome val flowOutcome = result.flowOutcome + val requestOptions = ApiRequest.Options( + apiKey = publishableKey, + stripeAccount = result.stripeAccountId + ) + stripeRepository.retrieveIntent( getClientSecret(data), requestOptions, @@ -413,11 +421,12 @@ internal class StripePaymentController internal constructor( getRequestCode(stripeIntent), stripeIntent.clientSecret.orEmpty(), Stripe3dsRedirect.create(sdkData).url, + requestOptions.stripeAccount, enableLogging = enableLogging ) } else -> // authentication type is not supported - bypassAuth(host, stripeIntent) + bypassAuth(host, stripeIntent, requestOptions.stripeAccount) } } StripeIntent.NextActionType.RedirectToUrl -> { @@ -437,22 +446,27 @@ internal class StripePaymentController internal constructor( getRequestCode(stripeIntent), stripeIntent.clientSecret.orEmpty(), redirectData?.url.toString(), + requestOptions.stripeAccount, redirectData?.returnUrl, enableLogging = enableLogging ) } else -> // next action type is not supported, so bypass authentication - bypassAuth(host, stripeIntent) + bypassAuth(host, stripeIntent, requestOptions.stripeAccount) } } else { // no action required, so bypass authentication - bypassAuth(host, stripeIntent) + bypassAuth(host, stripeIntent, requestOptions.stripeAccount) } } - private fun bypassAuth(host: AuthActivityStarter.Host, stripeIntent: StripeIntent) { + private fun bypassAuth( + host: AuthActivityStarter.Host, + stripeIntent: StripeIntent, + stripeAccountId: String? + ) { PaymentRelayStarter.create(host, getRequestCode(stripeIntent)) - .start(PaymentRelayStarter.Args.create(stripeIntent)) + .start(PaymentRelayStarter.Args.create(stripeIntent, stripeAccountId)) } private fun bypassAuth(host: AuthActivityStarter.Host, source: Source) { @@ -480,6 +494,10 @@ internal class StripePaymentController internal constructor( Stripe3ds2CompletionActivity.EXTRA_CLIENT_SECRET, stripeIntent.clientSecret ) + .putExtra( + Stripe3ds2CompletionActivity.EXTRA_STRIPE_ACCOUNT, + requestOptions.stripeAccount + ) .addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT), challengeCompletionRequestCode = getRequestCode(stripeIntent) ) @@ -609,6 +627,7 @@ internal class StripePaymentController internal constructor( getRequestCode(stripeIntent), stripeIntent.clientSecret.orEmpty(), result.fallbackRedirectUrl, + requestOptions.stripeAccount, enableLogging = enableLogging ) } else { @@ -927,13 +946,14 @@ internal class StripePaymentController internal constructor( requestCode: Int, clientSecret: String, authUrl: String, + stripeAccount: String?, returnUrl: String? = null, enableLogging: Boolean = false ) { Logger.getInstance(enableLogging).debug("PaymentAuthWebViewStarter#start()") val starter = PaymentAuthWebViewStarter(host, requestCode) starter.start( - PaymentAuthWebViewStarter.Args(clientSecret, authUrl, returnUrl, enableLogging) + PaymentAuthWebViewStarter.Args(clientSecret, authUrl, returnUrl, enableLogging, stripeAccountId = stripeAccount) ) } diff --git a/stripe/src/main/java/com/stripe/android/view/PaymentAuthWebViewActivityViewModel.kt b/stripe/src/main/java/com/stripe/android/view/PaymentAuthWebViewActivityViewModel.kt index 98870ef2bae..b0cb1609d1f 100644 --- a/stripe/src/main/java/com/stripe/android/view/PaymentAuthWebViewActivityViewModel.kt +++ b/stripe/src/main/java/com/stripe/android/view/PaymentAuthWebViewActivityViewModel.kt @@ -34,7 +34,8 @@ internal class PaymentAuthWebViewActivityViewModel( get() { return PaymentController.Result( clientSecret = args.clientSecret, - sourceId = Uri.parse(args.url).lastPathSegment.orEmpty() + sourceId = Uri.parse(args.url).lastPathSegment.orEmpty(), + stripeAccountId = args.stripeAccountId ) } diff --git a/stripe/src/main/java/com/stripe/android/view/Stripe3ds2CompletionActivity.kt b/stripe/src/main/java/com/stripe/android/view/Stripe3ds2CompletionActivity.kt index a98d3650ce9..c33caffd0cc 100644 --- a/stripe/src/main/java/com/stripe/android/view/Stripe3ds2CompletionActivity.kt +++ b/stripe/src/main/java/com/stripe/android/view/Stripe3ds2CompletionActivity.kt @@ -41,7 +41,8 @@ class Stripe3ds2CompletionActivity : AppCompatActivity() { super.onCreate(savedInstanceState) val result = PaymentController.Result( clientSecret = intent.getStringExtra(EXTRA_CLIENT_SECRET), - flowOutcome = flowOutcome + flowOutcome = flowOutcome, + stripeAccountId = intent.getStringExtra(EXTRA_STRIPE_ACCOUNT) ) LocalBroadcastManager.getInstance(this) @@ -56,6 +57,7 @@ class Stripe3ds2CompletionActivity : AppCompatActivity() { internal companion object { const val EXTRA_CLIENT_SECRET = "extra_client_secret" + const val EXTRA_STRIPE_ACCOUNT = "extra_stripe_account" private const val UNKNOWN_FLOW_OUTCOME = -1 } } diff --git a/stripe/src/test/java/com/stripe/android/StripePaymentAuthTest.kt b/stripe/src/test/java/com/stripe/android/StripePaymentAuthTest.kt index f53c510a01d..95c41a06e3d 100644 --- a/stripe/src/test/java/com/stripe/android/StripePaymentAuthTest.kt +++ b/stripe/src/test/java/com/stripe/android/StripePaymentAuthTest.kt @@ -103,9 +103,7 @@ class StripePaymentAuthTest { stripe.onPaymentResult(StripePaymentController.PAYMENT_REQUEST_CODE, data, callback = paymentCallback) - verify(paymentController).handlePaymentResult(data, - ApiRequest.Options(ApiKeyFixtures.FAKE_PUBLISHABLE_KEY), - paymentCallback) + verify(paymentController).handlePaymentResult(data, paymentCallback) } @Test @@ -118,9 +116,7 @@ class StripePaymentAuthTest { stripe.onSetupResult(StripePaymentController.SETUP_REQUEST_CODE, data, callback = setupCallback) - verify(paymentController).handleSetupResult(data, - ApiRequest.Options(ApiKeyFixtures.FAKE_PUBLISHABLE_KEY), - setupCallback) + verify(paymentController).handleSetupResult(data, setupCallback) } private fun createStripe(): Stripe { diff --git a/stripe/src/test/java/com/stripe/android/StripePaymentControllerTest.kt b/stripe/src/test/java/com/stripe/android/StripePaymentControllerTest.kt index 032ba48b714..77febcdd792 100644 --- a/stripe/src/test/java/com/stripe/android/StripePaymentControllerTest.kt +++ b/stripe/src/test/java/com/stripe/android/StripePaymentControllerTest.kt @@ -513,7 +513,7 @@ class StripePaymentControllerTest { ).toBundle() ) - controller.handlePaymentResult(intent, REQUEST_OPTIONS, paymentAuthResultCallback) + controller.handlePaymentResult(intent, paymentAuthResultCallback) verify(paymentAuthResultCallback).onError(exception) verify(paymentAuthResultCallback, never()) .onSuccess(anyOrNull()) @@ -528,7 +528,7 @@ class StripePaymentControllerTest { ).toBundle() ) - controller.handleSetupResult(intent, REQUEST_OPTIONS, setupAuthResultCallback) + controller.handleSetupResult(intent, setupAuthResultCallback) verify(setupAuthResultCallback).onError(exception) verify(setupAuthResultCallback, never()) @@ -546,7 +546,7 @@ class StripePaymentControllerTest { ).toBundle() ) - controller.handleSetupResult(intent, REQUEST_OPTIONS, setupAuthResultCallback) + controller.handleSetupResult(intent, setupAuthResultCallback) verify(setupAuthResultCallback).onSuccess(setupIntentResultArgumentCaptor.capture()) val result = setupIntentResultArgumentCaptor.firstValue @@ -657,7 +657,7 @@ class StripePaymentControllerTest { ) createController(stripeRepository) - .handlePaymentResult(intent, REQUEST_OPTIONS, paymentAuthResultCallback) + .handlePaymentResult(intent, paymentAuthResultCallback) verify(stripeRepository).retrieveIntent( eq(clientSecret),