Skip to content
Draft
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
17 changes: 17 additions & 0 deletions payments-core/src/main/java/com/stripe/android/StripeClient.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.stripe.android

import android.os.Parcelable
import com.stripe.android.core.ApiKeyValidator
import dev.drewhamilton.poko.Poko
import kotlinx.parcelize.Parcelize

@Parcelize
@Poko
class StripeClient(
val publishableKey: String,
val stripeAccountId: String? = null,
) : Parcelable {
init {
ApiKeyValidator.get().requireValid(publishableKey)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.stripe.android.payments.core.injection

import com.stripe.android.StripeClient
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class StripeClientHolder @Inject constructor() {
@Volatile
var stripeClient: StripeClient? = null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.stripe.android.payments.core.injection

import android.content.Context
import com.stripe.android.PaymentConfiguration
import com.stripe.android.core.injection.PUBLISHABLE_KEY
import com.stripe.android.core.injection.STRIPE_ACCOUNT_ID
import dagger.Module
import dagger.Provides
import javax.inject.Named
import javax.inject.Provider

@Module
class StripeClientModule {
@Provides
fun providePaymentConfiguration(context: Context, holder: StripeClientHolder): PaymentConfiguration {
return holder.stripeClient?.let {
PaymentConfiguration(it.publishableKey, it.stripeAccountId)
} ?: PaymentConfiguration.getInstance(context)
}

@Provides
@Named(PUBLISHABLE_KEY)
fun providePublishableKey(paymentConfiguration: Provider<PaymentConfiguration>): () -> String =
{ paymentConfiguration.get().publishableKey }

@Provides
@Named(STRIPE_ACCOUNT_ID)
fun provideStripeAccountId(paymentConfiguration: Provider<PaymentConfiguration>): () -> String? =
{ paymentConfiguration.get().stripeAccountId }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.stripe.android

import com.google.common.truth.Truth.assertThat
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import kotlin.test.Test
import kotlin.test.assertFailsWith

@RunWith(RobolectricTestRunner::class)
class StripeClientTest {

@Test
fun `valid pk_test_ key is accepted`() {
val client = StripeClient(publishableKey = ApiKeyFixtures.FAKE_PUBLISHABLE_KEY)
assertThat(client.publishableKey).isEqualTo(ApiKeyFixtures.FAKE_PUBLISHABLE_KEY)
}

@Test
fun `key starting with sk_ throws IllegalArgumentException`() {
assertFailsWith<IllegalArgumentException> {
StripeClient(publishableKey = "sk_test_123")
}
}

@Test
fun `blank key throws`() {
assertFailsWith<IllegalArgumentException> {
StripeClient(publishableKey = "")
}
}

@Test
fun `stripeAccountId is null by default`() {
val client = StripeClient(publishableKey = ApiKeyFixtures.FAKE_PUBLISHABLE_KEY)
assertThat(client.stripeAccountId).isNull()
}

@Test
fun `stripeAccountId is set correctly when provided`() {
val client = StripeClient(
publishableKey = ApiKeyFixtures.FAKE_PUBLISHABLE_KEY,
stripeAccountId = "acct_test_123",
)
assertThat(client.stripeAccountId).isEqualTo("acct_test_123")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.stripe.android.StripeClient
import com.stripe.android.checkout.Checkout
import com.stripe.android.model.PaymentMethod
import com.stripe.android.paymentelement.AnalyticEvent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import android.util.Log
import androidx.compose.runtime.Stable
import androidx.core.content.edit
import com.stripe.android.PaymentConfiguration
import com.stripe.android.StripeClient
import com.stripe.android.checkout.Checkout
import com.stripe.android.core.utils.FeatureFlags
import com.stripe.android.customersheet.CustomerSheet
Expand Down Expand Up @@ -179,6 +180,7 @@ internal class PlaygroundSettings private constructor(
}.onEach { (settingDefinition, value) ->
settingDefinition.configure(value, builder, playgroundState, embeddedConfigurationData)
}
builder.stripeClient(StripeClient("pk_123"))
return builder.build()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStoreOwner
import com.stripe.android.ExperimentalAllowsRemovalOfLastSavedPaymentMethodApi
import com.stripe.android.SharedPaymentTokenSessionPreview
import com.stripe.android.StripeClient
import com.stripe.android.payments.core.injection.StripeClientHolder
import com.stripe.android.checkout.Checkout
import com.stripe.android.checkout.CheckoutConfigurationMerger
import com.stripe.android.checkout.CheckoutInstances
Expand Down Expand Up @@ -59,6 +61,7 @@ class EmbeddedPaymentElement @Inject internal constructor(
paymentOptionDisplayDataHolder: PaymentOptionDisplayDataHolder,
private val configurationCoordinator: EmbeddedConfigurationCoordinator,
stateHelper: EmbeddedStateHelper,
private val stripeClientHolder: StripeClientHolder,
) {

/**
Expand All @@ -85,6 +88,7 @@ class EmbeddedPaymentElement @Inject internal constructor(
intentConfiguration: PaymentSheet.IntentConfiguration,
configuration: Configuration,
): ConfigureResult {
stripeClientHolder.stripeClient = configuration.stripeClient
val initializationMode = PaymentElementLoader.InitializationMode.DeferredIntent(intentConfiguration)
return configurationCoordinator.configure(configuration, initializationMode)
}
Expand All @@ -101,7 +105,9 @@ class EmbeddedPaymentElement @Inject internal constructor(
suspend fun configure(
checkout: Checkout,
configuration: Configuration,
stripeClient: StripeClient? = null,
): ConfigureResult {
stripeClientHolder.stripeClient = stripeClient
CheckoutInstances.ensureNoMutationInFlight(checkout.internalState.key)
return configurationCoordinator.configure(
configuration = CheckoutConfigurationMerger.EmbeddedConfiguration(configuration)
Expand Down Expand Up @@ -305,6 +311,7 @@ class EmbeddedPaymentElement @Inject internal constructor(
internal val termsDisplay: Map<PaymentMethod.Type, TermsDisplay> = emptyMap(),
internal val opensCardScannerAutomatically: Boolean = ConfigurationDefaults.opensCardScannerAutomatically,
internal val userOverrideCountry: String? = ConfigurationDefaults.userOverrideCountry,
internal val stripeClient: StripeClient? = null
) : Parcelable {
@Suppress("TooManyFunctions")
class Builder(
Expand Down Expand Up @@ -342,6 +349,9 @@ class EmbeddedPaymentElement @Inject internal constructor(
private var opensCardScannerAutomatically: Boolean =
ConfigurationDefaults.opensCardScannerAutomatically
private var userOverrideCountry: String? = ConfigurationDefaults.userOverrideCountry
private var stripeClient: StripeClient? = null

fun stripeClient(stripeClient: StripeClient?) = apply { this.stripeClient = stripeClient }

/**
* If set, the customer can select a previously saved payment method.
Expand Down Expand Up @@ -602,6 +612,7 @@ class EmbeddedPaymentElement @Inject internal constructor(
termsDisplay = termsDisplay,
opensCardScannerAutomatically = opensCardScannerAutomatically,
userOverrideCountry = userOverrideCountry,
stripeClient = stripeClient
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import com.stripe.android.paymentelement.confirmation.ALLOWS_MANUAL_CONFIRMATION
import com.stripe.android.payments.core.analytics.ErrorReporter
import com.stripe.android.payments.core.analytics.RealErrorReporter
import com.stripe.android.payments.core.injection.PRODUCT_USAGE
import com.stripe.android.payments.core.injection.PaymentConfigurationModule
import com.stripe.android.payments.core.injection.StripeClientModule
import com.stripe.android.payments.core.injection.StripeRepositoryModule
import com.stripe.android.paymentsheet.BuildConfig
import com.stripe.android.paymentsheet.CustomerStateHolder
Expand Down Expand Up @@ -53,7 +53,7 @@ import kotlin.coroutines.CoroutineContext
TapToAddConnectionModule::class,
PaymentsIntegrityModule::class,
PaymentElementRequestSurfaceModule::class,
PaymentConfigurationModule::class,
StripeClientModule::class,
StripeNetworkClientModule::class,
PaymentOptionCardArtModule::class,
NfcScanningAvailabilityModule::class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ internal class DefaultEmbeddedConfigurationHandler @Inject constructor(
return coalescingOrchestrator.get()
}

// TODO: Include stripeClient in cache key once StripeClient is threaded through to Arguments
@Parcelize
data class Arguments(
val initializationMode: PaymentElementLoader.InitializationMode,
Expand Down
Loading