Skip to content

Commit 00f7f24

Browse files
authored
Move GooglePayPaymentLauncher launching logic to InternalGooglePayPaymentMethodLauncher. (#13706)
1 parent e9de263 commit 00f7f24

12 files changed

Lines changed: 509 additions & 457 deletions

File tree

payments-core/src/main/java/com/stripe/android/googlepaylauncher/GooglePayPaymentMethodLauncher.kt

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,8 @@ import com.stripe.android.core.reactnative.registerForReactNativeActivityResult
2828
import com.stripe.android.googlepaylauncher.injection.GooglePayRepositoryFactory
2929
import com.stripe.android.model.ClientAttributionMetadata
3030
import com.stripe.android.model.PaymentMethod
31-
import com.stripe.android.networking.PaymentAnalyticsEvent
3231
import com.stripe.android.networking.PaymentAnalyticsRequestFactory
3332
import com.stripe.android.payments.core.analytics.ErrorReporter
34-
import dagger.assisted.Assisted
35-
import dagger.assisted.AssistedInject
3633
import dev.drewhamilton.poko.Poko
3734
import kotlinx.coroutines.CoroutineScope
3835
import kotlinx.coroutines.flow.first
@@ -49,16 +46,16 @@ import java.util.Locale
4946
* See the [Google Pay integration guide](https://stripe.com/docs/google-pay) for more details.
5047
*/
5148
@JvmSuppressWildcards
52-
class GooglePayPaymentMethodLauncher @AssistedInject internal constructor(
53-
@Assisted lifecycleScope: CoroutineScope,
54-
@Assisted private val config: Config,
55-
@Assisted private val readyCallback: ReadyCallback,
56-
@Assisted private val activityResultLauncher: ActivityResultLauncher<GooglePayPaymentMethodLauncherContractV2.Args>,
57-
@Assisted private val skipReadyCheck: Boolean,
49+
class GooglePayPaymentMethodLauncher internal constructor(
50+
lifecycleScope: CoroutineScope,
51+
private val config: Config,
52+
readyCallback: ReadyCallback,
53+
activityResultLauncher: ActivityResultLauncher<GooglePayPaymentMethodLauncherContractV2.Args>,
54+
private val skipReadyCheck: Boolean,
5855
context: Context,
59-
private val googlePayRepositoryFactory: GooglePayRepositoryFactory,
60-
@Assisted private val cardBrandFilter: CardBrandFilter,
61-
@Assisted private val cardFundingFilter: CardFundingFilter,
56+
googlePayRepositoryFactory: GooglePayRepositoryFactory,
57+
private val cardBrandFilter: CardBrandFilter,
58+
private val cardFundingFilter: CardFundingFilter,
6259
paymentAnalyticsRequestFactory: PaymentAnalyticsRequestFactory = PaymentAnalyticsRequestFactory(
6360
context,
6461
PaymentConfiguration.getInstance(context).publishableKey,
@@ -67,6 +64,12 @@ class GooglePayPaymentMethodLauncher @AssistedInject internal constructor(
6764
analyticsRequestExecutor: AnalyticsRequestExecutor = DefaultAnalyticsRequestExecutor(),
6865
) {
6966
private var isReady = false
67+
private val internalLauncher = InternalGooglePayPaymentMethodLauncher(
68+
activityResultLauncher = activityResultLauncher,
69+
context = context,
70+
paymentAnalyticsRequestFactory = paymentAnalyticsRequestFactory,
71+
analyticsRequestExecutor = analyticsRequestExecutor,
72+
)
7073

7174
/**
7275
* Constructor to be used when launching [GooglePayPaymentMethodLauncher] from an Activity.
@@ -194,13 +197,6 @@ class GooglePayPaymentMethodLauncher @AssistedInject internal constructor(
194197
)
195198

196199
init {
197-
if (!HAS_SENT_INIT_ANALYTIC_EVENT) {
198-
HAS_SENT_INIT_ANALYTIC_EVENT = true
199-
analyticsRequestExecutor.executeAsync(
200-
paymentAnalyticsRequestFactory.createRequest(PaymentAnalyticsEvent.GooglePayPaymentMethodLauncherInit)
201-
)
202-
}
203-
204200
if (!skipReadyCheck) {
205201
lifecycleScope.launch {
206202
val repository = googlePayRepositoryFactory(
@@ -266,21 +262,19 @@ class GooglePayPaymentMethodLauncher @AssistedInject internal constructor(
266262
"present() may only be called when Google Pay is available on this device."
267263
}
268264

269-
activityResultLauncher.launch(
270-
GooglePayPaymentMethodLauncherContractV2.Args(
271-
config = config,
272-
currencyCode = currencyCode,
273-
amount = amount,
274-
label = label,
275-
transactionId = transactionId,
276-
cardBrandFilter = cardBrandFilter,
277-
cardFundingFilter = cardFundingFilter,
278-
clientAttributionMetadata = clientAttributionMetadata,
279-
isElements = isElements,
280-
publishableKey = publishableKey,
281-
displayItems = displayItems,
282-
billingEmailOverride = billingEmailOverride,
283-
)
265+
internalLauncher.present(
266+
currencyCode = currencyCode,
267+
amount = amount,
268+
config = config,
269+
cardBrandFilter = cardBrandFilter,
270+
cardFundingFilter = cardFundingFilter,
271+
clientAttributionMetadata = clientAttributionMetadata,
272+
transactionId = transactionId,
273+
label = label,
274+
isElements = isElements,
275+
publishableKey = publishableKey,
276+
displayItems = displayItems,
277+
billingEmailOverride = billingEmailOverride,
284278
)
285279
}
286280

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package com.stripe.android.googlepaylauncher
2+
3+
import android.content.Context
4+
import androidx.activity.result.ActivityResultLauncher
5+
import androidx.annotation.RestrictTo
6+
import com.stripe.android.CardBrandFilter
7+
import com.stripe.android.CardFundingFilter
8+
import com.stripe.android.GooglePayJsonFactory
9+
import com.stripe.android.PaymentConfiguration
10+
import com.stripe.android.core.networking.AnalyticsRequestExecutor
11+
import com.stripe.android.core.networking.DefaultAnalyticsRequestExecutor
12+
import com.stripe.android.model.ClientAttributionMetadata
13+
import com.stripe.android.networking.PaymentAnalyticsEvent
14+
import com.stripe.android.networking.PaymentAnalyticsRequestFactory
15+
import dagger.assisted.Assisted
16+
import dagger.assisted.AssistedInject
17+
18+
/**
19+
* The internal engine backing [GooglePayPaymentMethodLauncher]. Unlike the public wrapper, this
20+
* class does not capture the [GooglePayPaymentMethodLauncher.Config], [CardBrandFilter], and
21+
* [CardFundingFilter] at construction time. Instead they are required unconditionally on
22+
* [isReady] and [present], which lets callers that only know these values at launch time (such as
23+
* the confirmation flow) create the launcher up front and supply them later.
24+
*/
25+
@JvmSuppressWildcards
26+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
27+
class InternalGooglePayPaymentMethodLauncher @AssistedInject internal constructor(
28+
@Assisted private val activityResultLauncher: ActivityResultLauncher<GooglePayPaymentMethodLauncherContractV2.Args>,
29+
context: Context,
30+
paymentAnalyticsRequestFactory: PaymentAnalyticsRequestFactory = PaymentAnalyticsRequestFactory(
31+
context,
32+
PaymentConfiguration.getInstance(context).publishableKey,
33+
setOf(GooglePayPaymentMethodLauncher.PRODUCT_USAGE_TOKEN)
34+
),
35+
analyticsRequestExecutor: AnalyticsRequestExecutor = DefaultAnalyticsRequestExecutor(),
36+
) {
37+
init {
38+
if (!GooglePayPaymentMethodLauncher.HAS_SENT_INIT_ANALYTIC_EVENT) {
39+
GooglePayPaymentMethodLauncher.HAS_SENT_INIT_ANALYTIC_EVENT = true
40+
analyticsRequestExecutor.executeAsync(
41+
paymentAnalyticsRequestFactory.createRequest(
42+
PaymentAnalyticsEvent.GooglePayPaymentMethodLauncherInit
43+
)
44+
)
45+
}
46+
}
47+
48+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
49+
fun present(
50+
currencyCode: String,
51+
amount: Long,
52+
config: GooglePayPaymentMethodLauncher.Config,
53+
cardBrandFilter: CardBrandFilter,
54+
cardFundingFilter: CardFundingFilter,
55+
clientAttributionMetadata: ClientAttributionMetadata?,
56+
transactionId: String?,
57+
label: String?,
58+
isElements: Boolean,
59+
publishableKey: String?,
60+
displayItems: List<GooglePayJsonFactory.DisplayItem>,
61+
billingEmailOverride: String?,
62+
) {
63+
activityResultLauncher.launch(
64+
GooglePayPaymentMethodLauncherContractV2.Args(
65+
config = config,
66+
currencyCode = currencyCode,
67+
amount = amount,
68+
label = label,
69+
transactionId = transactionId,
70+
cardBrandFilter = cardBrandFilter,
71+
cardFundingFilter = cardFundingFilter,
72+
clientAttributionMetadata = clientAttributionMetadata,
73+
isElements = isElements,
74+
publishableKey = publishableKey,
75+
displayItems = displayItems,
76+
billingEmailOverride = billingEmailOverride,
77+
)
78+
)
79+
}
80+
}

payments-core/src/main/java/com/stripe/android/googlepaylauncher/injection/GooglePayPaymentMethodLauncherFactory.kt

Lines changed: 0 additions & 24 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.stripe.android.googlepaylauncher.injection
2+
3+
import androidx.activity.result.ActivityResultLauncher
4+
import androidx.annotation.RestrictTo
5+
import com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncherContractV2
6+
import com.stripe.android.googlepaylauncher.InternalGooglePayPaymentMethodLauncher
7+
import dagger.assisted.AssistedFactory
8+
9+
@AssistedFactory
10+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
11+
interface InternalGooglePayPaymentMethodLauncherFactory {
12+
fun create(
13+
activityResultLauncher: ActivityResultLauncher<GooglePayPaymentMethodLauncherContractV2.Args>,
14+
): InternalGooglePayPaymentMethodLauncher
15+
}

paymentsheet/src/main/java/com/stripe/android/paymentelement/confirmation/gpay/GooglePayConfirmationDefinition.kt

Lines changed: 30 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
package com.stripe.android.paymentelement.confirmation.gpay
22

33
import androidx.activity.result.ActivityResultCaller
4-
import androidx.activity.result.ActivityResultLauncher
54
import com.stripe.android.core.strings.resolvableString
65
import com.stripe.android.core.utils.FeatureFlags
76
import com.stripe.android.core.utils.UserFacingLogger
87
import com.stripe.android.googlepaylauncher.GooglePayEnvironment
98
import com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncher
109
import com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncherContractV2
11-
import com.stripe.android.googlepaylauncher.injection.GooglePayPaymentMethodLauncherFactory
10+
import com.stripe.android.googlepaylauncher.InternalGooglePayPaymentMethodLauncher
11+
import com.stripe.android.googlepaylauncher.injection.InternalGooglePayPaymentMethodLauncherFactory
1212
import com.stripe.android.model.PaymentIntent
1313
import com.stripe.android.model.SetupIntent
1414
import com.stripe.android.model.StripeIntent
@@ -18,17 +18,15 @@ import com.stripe.android.paymentelement.confirmation.EmptyConfirmationLauncherA
1818
import com.stripe.android.paymentelement.confirmation.PaymentMethodConfirmationOption
1919
import com.stripe.android.paymentsheet.PaymentSheet
2020
import com.stripe.android.paymentsheet.R
21-
import kotlinx.coroutines.CoroutineScope
22-
import kotlinx.coroutines.Dispatchers
2321
import javax.inject.Inject
2422
import com.stripe.android.R as PaymentsCoreR
2523

2624
internal class GooglePayConfirmationDefinition @Inject constructor(
27-
private val googlePayPaymentMethodLauncherFactory: GooglePayPaymentMethodLauncherFactory,
25+
private val googlePayPaymentMethodLauncherFactory: InternalGooglePayPaymentMethodLauncherFactory,
2826
private val userFacingLogger: UserFacingLogger?,
2927
) : ConfirmationDefinition<
3028
GooglePayConfirmationOption,
31-
ActivityResultLauncher<GooglePayPaymentMethodLauncherContractV2.Args>,
29+
InternalGooglePayPaymentMethodLauncher,
3230
EmptyConfirmationLauncherArgs,
3331
GooglePayPaymentMethodLauncher.Result,
3432
> {
@@ -67,39 +65,41 @@ internal class GooglePayConfirmationDefinition @Inject constructor(
6765
override fun createLauncher(
6866
activityResultCaller: ActivityResultCaller,
6967
onResult: (GooglePayPaymentMethodLauncher.Result) -> Unit
70-
): ActivityResultLauncher<GooglePayPaymentMethodLauncherContractV2.Args> {
71-
return activityResultCaller.registerForActivityResult(
68+
): InternalGooglePayPaymentMethodLauncher {
69+
val activityResultLauncher = activityResultCaller.registerForActivityResult(
7270
GooglePayPaymentMethodLauncherContractV2(),
7371
onResult,
7472
)
73+
74+
return googlePayPaymentMethodLauncherFactory.create(
75+
activityResultLauncher = activityResultLauncher,
76+
)
7577
}
7678

7779
override fun launch(
78-
launcher: ActivityResultLauncher<GooglePayPaymentMethodLauncherContractV2.Args>,
80+
launcher: InternalGooglePayPaymentMethodLauncher,
7981
arguments: EmptyConfirmationLauncherArgs,
8082
confirmationOption: GooglePayConfirmationOption,
8183
confirmationArgs: ConfirmationHandler.Args,
8284
) {
8385
val config = confirmationOption.config
8486
val intent = confirmationArgs.intent
85-
val googlePayLauncher = createGooglePayLauncher(
86-
factory = googlePayPaymentMethodLauncherFactory,
87-
activityLauncher = launcher,
88-
config = confirmationOption.config,
89-
confirmationArgs = confirmationArgs,
90-
)
9187

92-
googlePayLauncher.present(
88+
launcher.present(
9389
currencyCode = intent.asPaymentIntent()?.currency
9490
?: config.merchantCurrencyCode.orEmpty(),
9591
amount = when (intent) {
9692
is PaymentIntent -> intent.amount ?: 0L
9793
is SetupIntent -> config.customAmount ?: 0L
9894
},
95+
config = config.toGooglePayLauncherConfig(confirmationArgs),
96+
cardBrandFilter = config.cardBrandFilter,
97+
cardFundingFilter = config.cardFundingFilter,
98+
clientAttributionMetadata = confirmationArgs.paymentMethodMetadata.clientAttributionMetadata,
9999
transactionId = intent.id,
100100
label = config.customLabel,
101-
clientAttributionMetadata = confirmationArgs.paymentMethodMetadata.clientAttributionMetadata,
102101
isElements = true,
102+
publishableKey = null,
103103
displayItems = config.displayItems,
104104
billingEmailOverride = config.billingEmailOverride,
105105
)
@@ -143,34 +143,21 @@ internal class GooglePayConfirmationDefinition @Inject constructor(
143143
}
144144
}
145145

146-
private fun createGooglePayLauncher(
147-
factory: GooglePayPaymentMethodLauncherFactory,
148-
activityLauncher: ActivityResultLauncher<GooglePayPaymentMethodLauncherContractV2.Args>,
149-
config: GooglePayConfirmationOption.Config,
146+
private fun GooglePayConfirmationOption.Config.toGooglePayLauncherConfig(
150147
confirmationArgs: ConfirmationHandler.Args,
151-
): GooglePayPaymentMethodLauncher {
152-
return factory.create(
153-
lifecycleScope = CoroutineScope(Dispatchers.Default),
154-
config = GooglePayPaymentMethodLauncher.Config(
155-
environment = when (config.environment) {
156-
PaymentSheet.GooglePayConfiguration.Environment.Production -> GooglePayEnvironment.Production
157-
else -> GooglePayEnvironment.Test
158-
},
159-
merchantCountryCode = config.merchantCountryCode,
160-
merchantName = confirmationArgs.paymentMethodMetadata.sellerBusinessName
161-
?: config.merchantName,
162-
isEmailRequired = config.isEmailRequired,
163-
billingAddressConfig = config.billingDetailsCollectionConfiguration.toBillingAddressConfig(),
164-
existingPaymentMethodRequired = !FeatureFlags.allowNoExistingPaymentMethodForGooglePay.isEnabled,
165-
additionalEnabledNetworks = config.additionalEnabledNetworks
166-
),
167-
readyCallback = {
168-
// Do nothing since we are skipping the ready check below
148+
): GooglePayPaymentMethodLauncher.Config {
149+
return GooglePayPaymentMethodLauncher.Config(
150+
environment = when (environment) {
151+
PaymentSheet.GooglePayConfiguration.Environment.Production -> GooglePayEnvironment.Production
152+
else -> GooglePayEnvironment.Test
169153
},
170-
activityResultLauncher = activityLauncher,
171-
skipReadyCheck = true,
172-
cardBrandFilter = config.cardBrandFilter,
173-
cardFundingFilter = config.cardFundingFilter,
154+
merchantCountryCode = merchantCountryCode,
155+
merchantName = confirmationArgs.paymentMethodMetadata.sellerBusinessName
156+
?: merchantName,
157+
isEmailRequired = isEmailRequired,
158+
billingAddressConfig = billingDetailsCollectionConfiguration.toBillingAddressConfig(),
159+
existingPaymentMethodRequired = !FeatureFlags.allowNoExistingPaymentMethodForGooglePay.isEnabled,
160+
additionalEnabledNetworks = additionalEnabledNetworks
174161
)
175162
}
176163

0 commit comments

Comments
 (0)