Skip to content
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

Migrate PaymentController to PaymentLauncher within PaymentSheet components. #4159

Merged
merged 16 commits into from
Sep 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions paymentsheet/api/paymentsheet.api
Original file line number Diff line number Diff line change
Expand Up @@ -271,11 +271,11 @@ public abstract interface class com/stripe/android/paymentsheet/PaymentSheetResu
}

public final class com/stripe/android/paymentsheet/PaymentSheetViewModel_Factory : dagger/internal/Factory {
public fun <init> (Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;)V
public static fun create (Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;)Lcom/stripe/android/paymentsheet/PaymentSheetViewModel_Factory;
public fun <init> (Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;)V
public static fun create (Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;Ljavax/inject/Provider;)Lcom/stripe/android/paymentsheet/PaymentSheetViewModel_Factory;
public fun get ()Lcom/stripe/android/paymentsheet/PaymentSheetViewModel;
public synthetic fun get ()Ljava/lang/Object;
public static fun newInstance (Landroid/app/Application;Lcom/stripe/android/paymentsheet/PaymentSheetContract$Args;Lcom/stripe/android/paymentsheet/analytics/EventReporter;Ldagger/Lazy;Lcom/stripe/android/paymentsheet/repositories/StripeIntentRepository;Lcom/stripe/android/paymentsheet/model/StripeIntentValidator;Lcom/stripe/android/paymentsheet/repositories/CustomerRepository;Ljavax/inject/Provider;Lcom/stripe/android/paymentsheet/PrefsRepository;Lcom/stripe/android/PaymentController;Lcom/stripe/android/googlepaylauncher/GooglePayPaymentMethodLauncherFactory;Lcom/stripe/android/Logger;Lkotlin/coroutines/CoroutineContext;)Lcom/stripe/android/paymentsheet/PaymentSheetViewModel;
public static fun newInstance (Landroid/app/Application;Lcom/stripe/android/paymentsheet/PaymentSheetContract$Args;Lcom/stripe/android/paymentsheet/analytics/EventReporter;Ldagger/Lazy;Lcom/stripe/android/paymentsheet/repositories/StripeIntentRepository;Lcom/stripe/android/paymentsheet/model/StripeIntentValidator;Lcom/stripe/android/paymentsheet/repositories/CustomerRepository;Lcom/stripe/android/paymentsheet/PrefsRepository;Lcom/stripe/android/payments/paymentlauncher/StripePaymentLauncherAssistedFactory;Lcom/stripe/android/googlepaylauncher/GooglePayPaymentMethodLauncherFactory;Lcom/stripe/android/Logger;Lkotlin/coroutines/CoroutineContext;)Lcom/stripe/android/paymentsheet/PaymentSheetViewModel;
}

public final class com/stripe/android/paymentsheet/address/AddressFieldElementRepository_Factory : dagger/internal/Factory {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import com.stripe.android.paymentsheet.model.PaymentSheetViewState
import com.stripe.android.paymentsheet.ui.AnimationConstants
import com.stripe.android.paymentsheet.ui.BaseSheetActivity
import com.stripe.android.paymentsheet.viewmodels.BaseSheetViewModel
import com.stripe.android.view.AuthActivityStarterHost
import kotlinx.coroutines.launch

internal class PaymentSheetActivity : BaseSheetActivity<PaymentSheetResult>() {
Expand Down Expand Up @@ -145,10 +144,7 @@ internal class PaymentSheetActivity : BaseSheetActivity<PaymentSheetResult>() {
val confirmParams = event.getContentIfNotHandled()
if (confirmParams != null) {
lifecycleScope.launch {
viewModel.confirmStripeIntent(
AuthActivityStarterHost.create(this@PaymentSheetActivity),
confirmParams
)
viewModel.confirmStripeIntent(confirmParams)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,21 @@ import androidx.lifecycle.distinctUntilChanged
import androidx.lifecycle.viewModelScope
import com.stripe.android.Logger
import com.stripe.android.PaymentConfiguration
import com.stripe.android.PaymentController
import com.stripe.android.StripeIntentResult
import com.stripe.android.exception.APIConnectionException
import com.stripe.android.googlepaylauncher.GooglePayEnvironment
import com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncher
import com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncherContract
import com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncherFactory
import com.stripe.android.model.ConfirmPaymentIntentParams
import com.stripe.android.model.ConfirmSetupIntentParams
import com.stripe.android.model.ConfirmStripeIntentParams
import com.stripe.android.model.PaymentIntent
import com.stripe.android.model.PaymentMethod
import com.stripe.android.model.StripeIntent
import com.stripe.android.networking.ApiRequest
import com.stripe.android.payments.PaymentFlowResult
import com.stripe.android.payments.PaymentFlowResultProcessor
import com.stripe.android.payments.core.injection.IOContext
import com.stripe.android.payments.paymentlauncher.PaymentLauncher
import com.stripe.android.payments.paymentlauncher.PaymentLauncherContract
import com.stripe.android.payments.paymentlauncher.PaymentResult
import com.stripe.android.payments.paymentlauncher.StripePaymentLauncherAssistedFactory
import com.stripe.android.paymentsheet.analytics.EventReporter
import com.stripe.android.paymentsheet.injection.DaggerPaymentSheetViewModelComponent
import com.stripe.android.paymentsheet.model.ConfirmStripeIntentParamsFactory
Expand All @@ -41,13 +41,10 @@ import com.stripe.android.paymentsheet.repositories.CustomerRepository
import com.stripe.android.paymentsheet.repositories.StripeIntentRepository
import com.stripe.android.paymentsheet.ui.PrimaryButton
import com.stripe.android.paymentsheet.viewmodels.BaseSheetViewModel
import com.stripe.android.view.AuthActivityStarterHost
import dagger.Lazy
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject
import javax.inject.Provider
import javax.inject.Singleton
import kotlin.coroutines.CoroutineContext

Expand Down Expand Up @@ -77,10 +74,8 @@ internal class PaymentSheetViewModel @Inject internal constructor(
private val stripeIntentRepository: StripeIntentRepository,
private val stripeIntentValidator: StripeIntentValidator,
customerRepository: CustomerRepository,
private val paymentFlowResultProcessorProvider:
Provider<PaymentFlowResultProcessor<out StripeIntent, StripeIntentResult<StripeIntent>>>,
prefsRepository: PrefsRepository,
private val paymentController: PaymentController,
private val paymentLauncherFactory: StripePaymentLauncherAssistedFactory,
private val googlePayPaymentMethodLauncherFactory: GooglePayPaymentMethodLauncherFactory,
private val logger: Logger,
@IOContext workContext: CoroutineContext
Expand Down Expand Up @@ -155,26 +150,15 @@ internal class PaymentSheetViewModel @Inject internal constructor(
}
}

internal var paymentLauncher: PaymentLauncher? = null

init {
eventReporter.onInit(config)
if (googlePayLauncherConfig == null) {
_isGooglePayReady.value = false
}
}

private fun apiThrowableToString(throwable: Throwable): String? {
return when (throwable) {
is APIConnectionException -> {
getApplication<Application>().resources.getString(
R.string.stripe_failure_connection_error
)
}
else -> {
throwable.localizedMessage
}
}
}

fun setupGooglePay(
lifecycleScope: CoroutineScope,
activityResultLauncher: ActivityResultLauncher<GooglePayPaymentMethodLauncherContract.Args>
Expand Down Expand Up @@ -301,29 +285,37 @@ internal class PaymentSheetViewModel @Inject internal constructor(
}
}

suspend fun confirmStripeIntent(
authActivityStarterHost: AuthActivityStarterHost,
confirmStripeIntentParams: ConfirmStripeIntentParams
) {
paymentController.startConfirmAndAuth(
authActivityStarterHost,
confirmStripeIntentParams,
ApiRequest.Options(
lazyPaymentConfig.get().publishableKey,
lazyPaymentConfig.get().stripeAccountId
)
fun confirmStripeIntent(confirmStripeIntentParams: ConfirmStripeIntentParams) {
runCatching {
requireNotNull(paymentLauncher)
}.fold(
onSuccess = {
when (confirmStripeIntentParams) {
is ConfirmPaymentIntentParams -> {
it.confirm(confirmStripeIntentParams)
}
is ConfirmSetupIntentParams -> {
it.confirm(confirmStripeIntentParams)
}
}
},
onFailure = ::onFatal
)
}

fun registerFromActivity(activityResultCaller: ActivityResultCaller) {
paymentController.registerLaunchersWithActivityResultCaller(
activityResultCaller,
::onPaymentFlowResult
paymentLauncher = paymentLauncherFactory.create(
{ lazyPaymentConfig.get().publishableKey },
{ lazyPaymentConfig.get().stripeAccountId },
activityResultCaller.registerForActivityResult(
PaymentLauncherContract(),
::onPaymentResult
)
)
}

fun unregisterFromActivity() {
paymentController.unregisterLaunchers()
paymentLauncher = null
}

private fun confirmPaymentSelection(paymentSelection: PaymentSelection?) {
Expand All @@ -340,16 +332,28 @@ internal class PaymentSheetViewModel @Inject internal constructor(
}
}

private fun onStripeIntentResult(
stripeIntentResult: StripeIntentResult<StripeIntent>
) {
when (stripeIntentResult.outcome) {
StripeIntentResult.Outcome.SUCCEEDED -> {
@VisibleForTesting
fun onPaymentResult(paymentResult: PaymentResult) {
viewModelScope.launch {
runCatching {
stripeIntentRepository.get(args.clientSecret)
skyler-stripe marked this conversation as resolved.
Show resolved Hide resolved
}.fold(
onSuccess = {
processPayment(it, paymentResult)
},
onFailure = ::onFatal
)
}
}

private fun processPayment(stripeIntent: StripeIntent, paymentResult: PaymentResult) {
when (paymentResult) {
PaymentResult.Completed -> {
eventReporter.onPaymentSuccess(selection.value)

// SavedSelection needs to happen after new cards have been saved.
when (selection.value) {
is PaymentSelection.New -> stripeIntentResult.intent.paymentMethod?.let {
is PaymentSelection.New -> stripeIntent.paymentMethod?.let {
PaymentSelection.Saved(it)
}
PaymentSelection.GooglePay -> selection.value
Expand All @@ -367,11 +371,14 @@ internal class PaymentSheetViewModel @Inject internal constructor(
eventReporter.onPaymentFailure(selection.value)

runCatching {
stripeIntentValidator.requireValid(stripeIntentResult.intent)
stripeIntentValidator.requireValid(stripeIntent)
}.fold(
onSuccess = {
resetViewState(
stripeIntentResult.failureMessage
when (paymentResult) {
is PaymentResult.Failed -> paymentResult.throwable.message
else -> null // indicates canceled payment
}
)
},
onFailure = ::onFatal
Expand Down Expand Up @@ -399,29 +406,6 @@ internal class PaymentSheetViewModel @Inject internal constructor(
}
}

fun onPaymentFlowResult(paymentFlowResult: PaymentFlowResult.Unvalidated) {
viewModelScope.launch {
runCatching {
withContext(workContext) {
paymentFlowResultProcessorProvider.get().processResult(
paymentFlowResult
)
}
}.fold(
onSuccess = {
onStripeIntentResult(it)
},
onFailure = { error ->
selection.value?.let {
eventReporter.onPaymentFailure(it)
}

resetViewState(apiThrowableToString(error))
}
)
}
}

override fun onFatal(throwable: Throwable) {
logger.error("Payment Sheet error", throwable)
_fatal.value = throwable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import com.stripe.android.Logger
import com.stripe.android.PaymentConfiguration
import com.stripe.android.PaymentController
import com.stripe.android.PaymentIntentResult
import com.stripe.android.StripeIntentResult
import com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncher
import com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncherContract
import com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncherFactory
Expand All @@ -25,8 +24,9 @@ import com.stripe.android.model.PaymentIntentFixtures
import com.stripe.android.model.PaymentMethod
import com.stripe.android.model.PaymentMethodCreateParamsFixtures
import com.stripe.android.model.PaymentMethodFixtures
import com.stripe.android.payments.PaymentFlowResult
import com.stripe.android.payments.PaymentFlowResultProcessor
import com.stripe.android.payments.paymentlauncher.PaymentResult
import com.stripe.android.payments.paymentlauncher.StripePaymentLauncherAssistedFactory
import com.stripe.android.paymentsheet.PaymentSheetViewModel.CheckoutIdentifier
import com.stripe.android.paymentsheet.analytics.EventReporter
import com.stripe.android.paymentsheet.databinding.PrimaryButtonBinding
Expand Down Expand Up @@ -73,6 +73,8 @@ internal class PaymentSheetActivityTest {
private val eventReporter = mock<EventReporter>()
private val googlePayPaymentMethodLauncherFactory =
createGooglePayPaymentMethodLauncherFactory()
private val stripePaymentLauncherAssistedFactory =
skyler-stripe marked this conversation as resolved.
Show resolved Hide resolved
mock<StripePaymentLauncherAssistedFactory>()

private val viewModel = createViewModel()

Expand Down Expand Up @@ -508,13 +510,8 @@ internal class PaymentSheetActivityTest {
idleLooper()

viewModel.checkoutIdentifier = CheckoutIdentifier.SheetBottomBuy
viewModel.onPaymentResult(PaymentResult.Completed)

viewModel.onPaymentFlowResult(
PaymentFlowResult.Unvalidated(
"client_secret",
StripeIntentResult.Outcome.SUCCEEDED
)
)
idleLooper()

assertThat(activity.bottomSheetBehavior.state)
Expand Down Expand Up @@ -723,7 +720,7 @@ internal class PaymentSheetActivityTest {
mock<PaymentFlowResultProcessor<PaymentIntent, PaymentIntentResult>>()
whenever(paymentFlowResultProcessor.processResult(any())).thenReturn(paymentIntentResult)

val mockPaymentController: PaymentController = mock()
val mockPaymentLauncher: PaymentController = mock()
PaymentSheetViewModel(
ApplicationProvider.getApplicationContext(),
PaymentSheetFixtures.ARGS_CUSTOMER_WITH_GOOGLEPAY,
Expand All @@ -732,9 +729,8 @@ internal class PaymentSheetActivityTest {
StripeIntentRepository.Static(paymentIntent),
StripeIntentValidator(),
FakeCustomerRepository(paymentMethods),
{ paymentFlowResultProcessor },
FakePrefsRepository(),
mockPaymentController,
stripePaymentLauncherAssistedFactory,
googlePayPaymentMethodLauncherFactory,
Logger.noop(),
testDispatcher
Expand Down
Loading