diff --git a/example/src/main/java/com/stripe/example/service/ExampleEphemeralKeyProvider.kt b/example/src/main/java/com/stripe/example/service/ExampleEphemeralKeyProvider.kt index a3312aa0f41..7270cf217e8 100644 --- a/example/src/main/java/com/stripe/example/service/ExampleEphemeralKeyProvider.kt +++ b/example/src/main/java/com/stripe/example/service/ExampleEphemeralKeyProvider.kt @@ -8,27 +8,30 @@ import com.stripe.example.Settings import com.stripe.example.module.BackendApiFactory import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import kotlin.coroutines.CoroutineContext /** * An implementation of [EphemeralKeyProvider] that can be used to generate * ephemeral keys on the backend. */ internal class ExampleEphemeralKeyProvider( - backendUrl: String + backendUrl: String, + private val workContext: CoroutineContext ) : EphemeralKeyProvider { - constructor(context: Context) : this(Settings(context).backendUrl) + constructor(context: Context) : this( + Settings(context).backendUrl, + Dispatchers.IO + ) - private val workScope = CoroutineScope(Dispatchers.IO + SupervisorJob()) private val backendApi = BackendApiFactory(backendUrl).create() override fun createEphemeralKey( @Size(min = 4) apiVersion: String, keyUpdateListener: EphemeralKeyUpdateListener ) { - workScope.launch { + CoroutineScope(workContext).launch { val response = kotlin.runCatching { backendApi diff --git a/stripe/src/main/java/com/stripe/android/AnalyticsRequestExecutor.kt b/stripe/src/main/java/com/stripe/android/AnalyticsRequestExecutor.kt index 53c8d44e734..c7a76a41e0e 100644 --- a/stripe/src/main/java/com/stripe/android/AnalyticsRequestExecutor.kt +++ b/stripe/src/main/java/com/stripe/android/AnalyticsRequestExecutor.kt @@ -7,6 +7,7 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import java.io.IOException +import kotlin.coroutines.CoroutineContext internal fun interface AnalyticsRequestExecutor { /** @@ -15,10 +16,10 @@ internal fun interface AnalyticsRequestExecutor { fun executeAsync(request: AnalyticsRequest) class Default( - private val logger: Logger = Logger.noop() + private val logger: Logger = Logger.noop(), + private val workContext: CoroutineContext = Dispatchers.IO ) : AnalyticsRequestExecutor { private val connectionFactory = ConnectionFactory.Default() - private val scope = CoroutineScope(Dispatchers.IO) /** * Make the request and ignore the response @@ -39,7 +40,7 @@ internal fun interface AnalyticsRequestExecutor { } override fun executeAsync(request: AnalyticsRequest) { - scope.launch { + CoroutineScope(workContext).launch { runCatching { execute(request) }.recover { diff --git a/stripe/src/main/java/com/stripe/android/ApiOperation.kt b/stripe/src/main/java/com/stripe/android/ApiOperation.kt index 2273cee8615..9622a276d62 100644 --- a/stripe/src/main/java/com/stripe/android/ApiOperation.kt +++ b/stripe/src/main/java/com/stripe/android/ApiOperation.kt @@ -6,21 +6,21 @@ import com.stripe.android.exception.InvalidRequestException import com.stripe.android.exception.StripeException import com.stripe.android.model.StripeModel import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers.IO -import kotlinx.coroutines.Dispatchers.Main +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.json.JSONException import java.io.IOException +import kotlin.coroutines.CoroutineContext internal abstract class ApiOperation( - private val workScope: CoroutineScope = CoroutineScope(IO), + private val workContext: CoroutineContext = Dispatchers.IO, private val callback: ApiResultCallback ) { internal abstract suspend fun getResult(): ResultType? internal fun execute() { - workScope.launch { + CoroutineScope(workContext).launch { val result: Result = try { Result.success(getResult()) } catch (e: StripeException) { @@ -38,14 +38,13 @@ internal abstract class ApiOperation( ) } - // dispatch the API operation result to the main thread - withContext(Main) { - dispatchResult(result) - } + dispatchResult(result) } } - private fun dispatchResult(result: Result) { + private suspend fun dispatchResult( + result: Result + ) = withContext(Dispatchers.Main) { result.fold( onSuccess = { when { diff --git a/stripe/src/main/java/com/stripe/android/CustomerSession.kt b/stripe/src/main/java/com/stripe/android/CustomerSession.kt index 09124f7d09c..7485b010e27 100644 --- a/stripe/src/main/java/com/stripe/android/CustomerSession.kt +++ b/stripe/src/main/java/com/stripe/android/CustomerSession.kt @@ -11,13 +11,13 @@ import com.stripe.android.model.PaymentMethod import com.stripe.android.model.ShippingInformation import com.stripe.android.model.Source import com.stripe.android.model.Source.SourceType -import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.cancelChildren import java.util.Calendar import java.util.concurrent.LinkedBlockingQueue import java.util.concurrent.ThreadPoolExecutor import java.util.concurrent.TimeUnit +import kotlin.coroutines.CoroutineContext /** * Represents a logged-in session of a single Customer. @@ -29,7 +29,7 @@ class CustomerSession @VisibleForTesting internal constructor( stripeRepository: StripeRepository, publishableKey: String, stripeAccountId: String?, - private val workDispatcher: CoroutineDispatcher = createCoroutineDispatcher(), + private val workContext: CoroutineContext = createCoroutineDispatcher(), private val operationIdFactory: OperationIdFactory = StripeOperationIdFactory(), private val timeSupplier: TimeSupplier = { Calendar.getInstance().timeInMillis }, ephemeralKeyManagerFactory: EphemeralKeyManager.Factory @@ -49,7 +49,7 @@ class CustomerSession @VisibleForTesting internal constructor( publishableKey, stripeAccountId ), - workDispatcher, + workContext, listeners ) ) @@ -458,7 +458,7 @@ class CustomerSession @VisibleForTesting internal constructor( @JvmSynthetic internal fun cancel() { listeners.clear() - workDispatcher.cancelChildren() + workContext.cancelChildren() } private fun getListener(operationId: String): L? { @@ -587,7 +587,7 @@ class CustomerSession @VisibleForTesting internal constructor( instance?.cancel() } - private fun createCoroutineDispatcher(): CoroutineDispatcher { + private fun createCoroutineDispatcher(): CoroutineContext { return ThreadPoolExecutor( THREAD_POOL_SIZE, THREAD_POOL_SIZE, diff --git a/stripe/src/main/java/com/stripe/android/CustomerSessionEphemeralKeyManagerListener.kt b/stripe/src/main/java/com/stripe/android/CustomerSessionEphemeralKeyManagerListener.kt index 63cafee2f2c..a2270623966 100644 --- a/stripe/src/main/java/com/stripe/android/CustomerSessionEphemeralKeyManagerListener.kt +++ b/stripe/src/main/java/com/stripe/android/CustomerSessionEphemeralKeyManagerListener.kt @@ -1,12 +1,12 @@ package com.stripe.android -import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch +import kotlin.coroutines.CoroutineContext internal class CustomerSessionEphemeralKeyManagerListener( private val runnableFactory: CustomerSessionRunnableFactory, - private val workDispatcher: CoroutineDispatcher, + private val workContext: CoroutineContext, private val listeners: MutableMap ) : EphemeralKeyManager.KeyManagerListener { override fun onKeyUpdate( @@ -14,7 +14,7 @@ internal class CustomerSessionEphemeralKeyManagerListener( operation: EphemeralOperation ) { runnableFactory.create(ephemeralKey, operation)?.let { - CoroutineScope(workDispatcher).launch { + CoroutineScope(workContext).launch { it.run() } } diff --git a/stripe/src/main/java/com/stripe/android/FingerprintDataRepository.kt b/stripe/src/main/java/com/stripe/android/FingerprintDataRepository.kt index 32239f2a8fc..038f23570c2 100644 --- a/stripe/src/main/java/com/stripe/android/FingerprintDataRepository.kt +++ b/stripe/src/main/java/com/stripe/android/FingerprintDataRepository.kt @@ -1,11 +1,11 @@ package com.stripe.android import android.content.Context -import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import java.util.Calendar +import kotlin.coroutines.CoroutineContext internal interface FingerprintDataRepository { fun refresh() @@ -17,7 +17,7 @@ internal interface FingerprintDataRepository { private val fingerprintRequestFactory: FingerprintRequestFactory, private val fingerprintRequestExecutor: FingerprintRequestExecutor = FingerprintRequestExecutor.Default(), - dispatcher: CoroutineDispatcher = Dispatchers.IO + private val workContext: CoroutineContext ) : FingerprintDataRepository { private var cachedFingerprintData: FingerprintData? = null @@ -25,18 +25,17 @@ internal interface FingerprintDataRepository { Calendar.getInstance().timeInMillis } - private val scope = CoroutineScope(dispatcher) - constructor( context: Context ) : this( localStore = FingerprintDataStore.Default(context), - fingerprintRequestFactory = FingerprintRequestFactory(context) + fingerprintRequestFactory = FingerprintRequestFactory(context), + workContext = Dispatchers.IO ) override fun refresh() { if (Stripe.advancedFraudSignalsEnabled) { - scope.launch { + CoroutineScope(workContext).launch { localStore.get().let { localFingerprintData -> if (localFingerprintData == null || localFingerprintData.isExpired(timestampSupplier()) diff --git a/stripe/src/main/java/com/stripe/android/FingerprintRequestExecutor.kt b/stripe/src/main/java/com/stripe/android/FingerprintRequestExecutor.kt index c394f47e6c4..2b9b515bf0c 100644 --- a/stripe/src/main/java/com/stripe/android/FingerprintRequestExecutor.kt +++ b/stripe/src/main/java/com/stripe/android/FingerprintRequestExecutor.kt @@ -1,10 +1,10 @@ package com.stripe.android import com.stripe.android.model.parsers.FingerprintDataJsonParser -import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.util.Calendar +import kotlin.coroutines.CoroutineContext internal interface FingerprintRequestExecutor { suspend fun execute( @@ -13,7 +13,7 @@ internal interface FingerprintRequestExecutor { class Default( private val connectionFactory: ConnectionFactory = ConnectionFactory.Default(), - private val workDispatcher: CoroutineDispatcher = Dispatchers.IO + private val workContext: CoroutineContext = Dispatchers.IO ) : FingerprintRequestExecutor { private val timestampSupplier = { Calendar.getInstance().timeInMillis @@ -21,7 +21,7 @@ internal interface FingerprintRequestExecutor { override suspend fun execute( request: FingerprintRequest - ) = withContext(workDispatcher) { + ) = withContext(workContext) { // fingerprint request failures should be non-fatal runCatching { executeInternal(request) diff --git a/stripe/src/main/java/com/stripe/android/Stripe.kt b/stripe/src/main/java/com/stripe/android/Stripe.kt index 532af8cce22..078c7689a82 100644 --- a/stripe/src/main/java/com/stripe/android/Stripe.kt +++ b/stripe/src/main/java/com/stripe/android/Stripe.kt @@ -35,9 +35,8 @@ import com.stripe.android.model.StripeIntent import com.stripe.android.model.Token import com.stripe.android.model.TokenParams import com.stripe.android.view.AuthActivityStarter -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlin.coroutines.CoroutineContext /** * Entry-point to the Stripe SDK. @@ -56,9 +55,8 @@ class Stripe internal constructor( private val paymentController: PaymentController, publishableKey: String, private val stripeAccountId: String? = null, - workDispatcher: CoroutineDispatcher = Dispatchers.IO + private val workContext: CoroutineContext = Dispatchers.IO ) { - private val workScope = CoroutineScope(workDispatcher) private val publishableKey: String = ApiKeyValidator().requireValid(publishableKey) /** @@ -373,7 +371,7 @@ class Stripe internal constructor( apiKey = publishableKey, stripeAccount = stripeAccountId ), - workScope, + workContext, callback ).execute() } @@ -646,7 +644,7 @@ class Stripe internal constructor( apiKey = publishableKey, stripeAccount = stripeAccountId ), - workScope, + workContext, callback ).execute() } @@ -751,7 +749,7 @@ class Stripe internal constructor( stripeAccount = stripeAccountId, idempotencyKey = idempotencyKey ), - workScope, + workContext, callback ).execute() } @@ -898,7 +896,7 @@ class Stripe internal constructor( stripeAccount = stripeAccountId, idempotencyKey = idempotencyKey ), - workScope, + workContext, callback ).execute() } @@ -979,7 +977,7 @@ class Stripe internal constructor( apiKey = publishableKey, stripeAccount = stripeAccountId ), - workScope, + workContext, callback ).execute() } @@ -1575,7 +1573,7 @@ class Stripe internal constructor( stripeAccount = stripeAccountId, idempotencyKey = idempotencyKey ), - workScope, + workContext, callback ).execute() } @@ -1604,7 +1602,7 @@ class Stripe internal constructor( stripeAccount = stripeAccountId, idempotencyKey = idempotencyKey ), - workScope, + workContext, callback ).execute() } @@ -1637,9 +1635,9 @@ class Stripe internal constructor( private val stripeRepository: StripeRepository, private val sourceParams: SourceParams, private val options: ApiRequest.Options, - workScope: CoroutineScope = CoroutineScope(Dispatchers.IO), + workContext: CoroutineContext, callback: ApiResultCallback - ) : ApiOperation(workScope, callback) { + ) : ApiOperation(workContext, callback) { @Throws(StripeException::class) override suspend fun getResult(): Source? { return stripeRepository.createSource(sourceParams, options) @@ -1651,9 +1649,9 @@ class Stripe internal constructor( private val sourceId: String, private val clientSecret: String, private val options: ApiRequest.Options, - workScope: CoroutineScope = CoroutineScope(Dispatchers.IO), + workContext: CoroutineContext, callback: ApiResultCallback - ) : ApiOperation(workScope, callback) { + ) : ApiOperation(workContext, callback) { @Throws(StripeException::class) override suspend fun getResult(): Source? { return stripeRepository.retrieveSource(sourceId, clientSecret, options) @@ -1664,9 +1662,9 @@ class Stripe internal constructor( private val stripeRepository: StripeRepository, private val paymentMethodCreateParams: PaymentMethodCreateParams, private val options: ApiRequest.Options, - workScope: CoroutineScope = CoroutineScope(Dispatchers.IO), + workContext: CoroutineContext, callback: ApiResultCallback - ) : ApiOperation(workScope, callback) { + ) : ApiOperation(workContext, callback) { @Throws(StripeException::class) override suspend fun getResult(): PaymentMethod? { return stripeRepository.createPaymentMethod(paymentMethodCreateParams, options) @@ -1677,9 +1675,9 @@ class Stripe internal constructor( private val stripeRepository: StripeRepository, private val tokenParams: TokenParams, private val options: ApiRequest.Options, - workScope: CoroutineScope = CoroutineScope(Dispatchers.IO), + workContext: CoroutineContext, callback: ApiResultCallback - ) : ApiOperation(workScope, callback) { + ) : ApiOperation(workContext, callback) { @Throws(StripeException::class) override suspend fun getResult(): Token? { return stripeRepository.createToken(tokenParams, options) @@ -1690,9 +1688,9 @@ class Stripe internal constructor( private val stripeRepository: StripeRepository, private val fileParams: StripeFileParams, private val options: ApiRequest.Options, - workScope: CoroutineScope = CoroutineScope(Dispatchers.IO), + workContext: CoroutineContext, callback: ApiResultCallback - ) : ApiOperation(workScope, callback) { + ) : ApiOperation(workContext, callback) { @Throws(StripeException::class) override suspend fun getResult(): StripeFile { return stripeRepository.createFile(fileParams, options) @@ -1703,9 +1701,9 @@ class Stripe internal constructor( private val stripeRepository: StripeRepository, private val clientSecret: String, private val options: ApiRequest.Options, - workScope: CoroutineScope = CoroutineScope(Dispatchers.IO), + workContext: CoroutineContext, callback: ApiResultCallback - ) : ApiOperation(workScope, callback) { + ) : ApiOperation(workContext, callback) { @Throws(StripeException::class) override suspend fun getResult(): PaymentIntent? { return stripeRepository.retrievePaymentIntent(clientSecret, options) @@ -1716,9 +1714,9 @@ class Stripe internal constructor( private val stripeRepository: StripeRepository, private val clientSecret: String, private val options: ApiRequest.Options, - workScope: CoroutineScope = CoroutineScope(Dispatchers.IO), + workContext: CoroutineContext, callback: ApiResultCallback - ) : ApiOperation(workScope, callback) { + ) : ApiOperation(workContext, callback) { @Throws(StripeException::class) override suspend fun getResult(): SetupIntent? { return stripeRepository.retrieveSetupIntent(clientSecret, options) diff --git a/stripe/src/main/java/com/stripe/android/StripeApiRepository.kt b/stripe/src/main/java/com/stripe/android/StripeApiRepository.kt index 6fba3d2845f..2020dd91d7d 100644 --- a/stripe/src/main/java/com/stripe/android/StripeApiRepository.kt +++ b/stripe/src/main/java/com/stripe/android/StripeApiRepository.kt @@ -44,7 +44,6 @@ import com.stripe.android.model.parsers.Stripe3ds2AuthResultJsonParser import com.stripe.android.model.parsers.StripeFileJsonParser import com.stripe.android.model.parsers.TokenJsonParser import com.stripe.android.utils.StripeUrlUtils -import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.json.JSONArray @@ -54,6 +53,7 @@ import java.io.IOException import java.net.HttpURLConnection import java.security.Security import java.util.Locale +import kotlin.coroutines.CoroutineContext /** * An implementation of [StripeRepository] that makes network requests to the Stripe API. @@ -71,7 +71,7 @@ internal class StripeApiRepository @JvmOverloads internal constructor( private val analyticsDataFactory: AnalyticsDataFactory = AnalyticsDataFactory(context, publishableKey), private val fingerprintParamsUtils: FingerprintParamsUtils = FingerprintParamsUtils(), - private val workDispatcher: CoroutineDispatcher = Dispatchers.IO, + private val workContext: CoroutineContext = Dispatchers.IO, apiVersion: String = ApiVersion.get().code, sdkVersion: String = Stripe.VERSION ) : StripeRepository { @@ -892,7 +892,7 @@ internal class StripeApiRepository @JvmOverloads internal constructor( override suspend fun getFpxBankStatus( options: ApiRequest.Options - ) = withContext(workDispatcher) { + ) = withContext(workContext) { makeApiRequest( apiRequestFactory.createGet( getApiUrl("fpx/bank_statuses"), @@ -907,18 +907,20 @@ internal class StripeApiRepository @JvmOverloads internal constructor( } } - override suspend fun getCardMetadata(bin: Bin, options: ApiRequest.Options) = - withContext(workDispatcher) { - makeApiRequest( - apiRequestFactory.createGet( - getEdgeUrl("card-metadata"), - options.copy(stripeAccount = null), - mapOf("key" to options.apiKey, "bin_prefix" to bin.value) - ) - ).let { - CardMetadataJsonParser(bin).parse(it.responseJson) - } + override suspend fun getCardMetadata( + bin: Bin, + options: ApiRequest.Options + ) = withContext(workContext) { + makeApiRequest( + apiRequestFactory.createGet( + getEdgeUrl("card-metadata"), + options.copy(stripeAccount = null), + mapOf("key" to options.apiKey, "bin_prefix" to bin.value) + ) + ).let { + CardMetadataJsonParser(bin).parse(it.responseJson) } + } /** * Analytics event: [AnalyticsEvent.Auth3ds2Start] diff --git a/stripe/src/main/java/com/stripe/android/StripePaymentController.kt b/stripe/src/main/java/com/stripe/android/StripePaymentController.kt index 2dd88427d41..7661dbf0814 100644 --- a/stripe/src/main/java/com/stripe/android/StripePaymentController.kt +++ b/stripe/src/main/java/com/stripe/android/StripePaymentController.kt @@ -39,6 +39,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import java.security.cert.CertificateException import java.util.concurrent.TimeUnit +import kotlin.coroutines.CoroutineContext /** * A controller responsible for confirming and authenticating payment (typically through resolving @@ -63,7 +64,7 @@ internal class StripePaymentController internal constructor( private val challengeFlowStarter: ChallengeFlowStarter = ChallengeFlowStarter.Default(), private val challengeProgressActivityStarter: ChallengeProgressActivityStarter = ChallengeProgressActivityStarter.Default(), - private val workScope: CoroutineScope = CoroutineScope(Dispatchers.IO) + private val workContext: CoroutineContext = Dispatchers.IO ) : PaymentController { private val logger = Logger.getInstance(enableLogging) private val analyticsRequestFactory = AnalyticsRequest.Factory(logger) @@ -103,7 +104,7 @@ internal class StripePaymentController internal constructor( stripeRepository, confirmStripeIntentParams, requestOptions, - workScope, + workContext, callback ).execute() } @@ -679,7 +680,7 @@ internal class StripePaymentController internal constructor( config.stripe3ds2Config.uiCustomization.uiCustomization ) - workScope.launch { + CoroutineScope(workContext).launch { val areqParams = transaction.createAuthenticationRequestParameters() val timeout = config.stripe3ds2Config.timeout @@ -722,9 +723,9 @@ internal class StripePaymentController internal constructor( private val stripeRepository: StripeRepository, params: ConfirmStripeIntentParams, private val requestOptions: ApiRequest.Options, - workScope: CoroutineScope, + workContext: CoroutineContext, callback: ApiResultCallback - ) : ApiOperation(workScope, callback) { + ) : ApiOperation(workContext, callback) { // mark this request as `use_stripe_sdk=true` private val params: ConfirmStripeIntentParams = params.withShouldUseStripeSdk(shouldUseStripeSdk = true) diff --git a/stripe/src/main/java/com/stripe/android/checkout/CheckoutViewModel.kt b/stripe/src/main/java/com/stripe/android/checkout/CheckoutViewModel.kt index 8f0195bda0e..0b800538b96 100644 --- a/stripe/src/main/java/com/stripe/android/checkout/CheckoutViewModel.kt +++ b/stripe/src/main/java/com/stripe/android/checkout/CheckoutViewModel.kt @@ -13,15 +13,15 @@ import com.stripe.android.StripeApiRepository import com.stripe.android.StripeRepository import com.stripe.android.model.ListPaymentMethodsParams import com.stripe.android.model.PaymentMethod -import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers +import kotlin.coroutines.CoroutineContext internal class CheckoutViewModel internal constructor( application: Application, private val publishableKey: String, private val stripeAccountId: String?, private val stripeRepository: StripeRepository, - private val workDispatcher: CoroutineDispatcher = Dispatchers.IO + private val workContext: CoroutineContext = Dispatchers.IO ) : AndroidViewModel(application) { private val mutableError = MutableLiveData() internal val error: LiveData = mutableError @@ -34,7 +34,7 @@ internal class CheckoutViewModel internal constructor( customerId: String, ephemeralKey: String, stripeAccountId: String? = this.stripeAccountId - ) = liveData(workDispatcher) { + ) = liveData(workContext) { val result = kotlin.runCatching { stripeRepository.getPaymentMethods( diff --git a/stripe/src/main/java/com/stripe/android/view/CardNumberEditText.kt b/stripe/src/main/java/com/stripe/android/view/CardNumberEditText.kt index f2c8fd36df6..115dcf3e18a 100644 --- a/stripe/src/main/java/com/stripe/android/view/CardNumberEditText.kt +++ b/stripe/src/main/java/com/stripe/android/view/CardNumberEditText.kt @@ -18,13 +18,13 @@ import com.stripe.android.cards.StaticCardAccountRangeSource import com.stripe.android.cards.StaticCardAccountRanges import com.stripe.android.model.AccountRange import com.stripe.android.model.CardBrand -import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import kotlin.coroutines.CoroutineContext /** * A [StripeEditText] that handles spacing out the digits of a credit card. @@ -35,7 +35,7 @@ class CardNumberEditText internal constructor( defStyleAttr: Int = androidx.appcompat.R.attr.editTextStyle, // TODO(mshafrir-stripe): make immutable after `CardWidgetViewModel` is integrated in `CardWidget` subclasses - internal var workDispatcher: CoroutineDispatcher, + internal var workContext: CoroutineContext, private val cardAccountRangeRepository: CardAccountRangeRepository, private val staticCardAccountRanges: StaticCardAccountRanges = DefaultStaticCardAccountRanges() @@ -140,7 +140,6 @@ class CardNumberEditText internal constructor( @JvmSynthetic internal var isLoadingCallback: (Boolean) -> Unit = {} - private val workScope = CoroutineScope(workDispatcher) private val loadingJob: Job init { @@ -154,7 +153,7 @@ class CardNumberEditText internal constructor( updateLengthFilter() - loadingJob = workScope.launch { + loadingJob = CoroutineScope(workContext).launch { cardAccountRangeRepository.loading.collect { isLoadingCallback(it) } @@ -324,7 +323,7 @@ class CardNumberEditText internal constructor( // invalidate accountRange before fetching accountRange = null - accountRangeRepositoryJob = workScope.launch { + accountRangeRepositoryJob = CoroutineScope(workContext).launch { val bin = cardNumber.bin if (bin != null) { onAccountRangeResult( diff --git a/stripe/src/main/java/com/stripe/android/view/PaymentFlowViewModel.kt b/stripe/src/main/java/com/stripe/android/view/PaymentFlowViewModel.kt index 340390fa0e4..f6a7694ad9d 100644 --- a/stripe/src/main/java/com/stripe/android/view/PaymentFlowViewModel.kt +++ b/stripe/src/main/java/com/stripe/android/view/PaymentFlowViewModel.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewModelScope import com.stripe.android.CustomerSession import com.stripe.android.PaymentSession import com.stripe.android.PaymentSessionConfig @@ -12,14 +13,11 @@ import com.stripe.android.StripeError import com.stripe.android.model.Customer import com.stripe.android.model.ShippingInformation import com.stripe.android.model.ShippingMethod -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch internal class PaymentFlowViewModel( private val customerSession: CustomerSession, - internal var paymentSessionData: PaymentSessionData, - private val workScope: CoroutineScope = CoroutineScope(Dispatchers.IO) + internal var paymentSessionData: PaymentSessionData ) : ViewModel() { internal var shippingMethods: List = emptyList() internal var isShippingInfoSubmitted: Boolean = false @@ -68,7 +66,7 @@ internal class PaymentFlowViewModel( shippingInformation: ShippingInformation ): LiveData>> { val resultData = MutableLiveData>>() - workScope.launch { + viewModelScope.launch { val isValid = shippingInfoValidator.isValid(shippingInformation) if (isValid) { val shippingMethods = diff --git a/stripe/src/main/java/com/stripe/android/view/PaymentMethodsAdapter.kt b/stripe/src/main/java/com/stripe/android/view/PaymentMethodsAdapter.kt index 6e3ef909ce9..c808123c94e 100644 --- a/stripe/src/main/java/com/stripe/android/view/PaymentMethodsAdapter.kt +++ b/stripe/src/main/java/com/stripe/android/view/PaymentMethodsAdapter.kt @@ -17,6 +17,8 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import kotlin.coroutines.CoroutineContext /** * A [RecyclerView.Adapter] that holds a set of [MaskedCardView] items for a given set @@ -29,7 +31,7 @@ internal class PaymentMethodsAdapter constructor( private val shouldShowGooglePay: Boolean = false, private val useGooglePay: Boolean = false, private val canDeletePaymentMethods: Boolean = true, - private val scope: CoroutineScope = CoroutineScope(Dispatchers.Main) + private val workContext: CoroutineContext = Dispatchers.IO ) : RecyclerView.Adapter() { internal val paymentMethods = mutableListOf() @@ -129,9 +131,12 @@ internal class PaymentMethodsAdapter constructor( @JvmSynthetic internal fun onPositionClicked(position: Int) { updateSelectedPaymentMethod(position) - scope.launch { + CoroutineScope(workContext).launch { delay(0) - listener?.onPaymentMethodClick(getPaymentMethodAtPosition(position)) + + withContext(Dispatchers.Main) { + listener?.onPaymentMethodClick(getPaymentMethodAtPosition(position)) + } } } diff --git a/stripe/src/main/java/com/stripe/android/view/StripeEditText.kt b/stripe/src/main/java/com/stripe/android/view/StripeEditText.kt index 6ee9424e2d2..bf86e939ac5 100644 --- a/stripe/src/main/java/com/stripe/android/view/StripeEditText.kt +++ b/stripe/src/main/java/com/stripe/android/view/StripeEditText.kt @@ -33,10 +33,9 @@ open class StripeEditText @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = androidx.appcompat.R.attr.editTextStyle, - workDispatcher: CoroutineContext = Dispatchers.IO + private val workContext: CoroutineContext = Dispatchers.IO ) : TextInputEditText(context, attrs, defStyleAttr) { internal val job = Job() - private val workScope: CoroutineScope = CoroutineScope(workDispatcher + job) protected var isLastKeyDelete: Boolean = false @@ -167,7 +166,7 @@ open class StripeEditText @JvmOverloads constructor( * @param delayMilliseconds a delay period, measured in milliseconds */ fun setHintDelayed(hint: CharSequence, delayMilliseconds: Long) { - workScope.launch { + CoroutineScope(workContext).launch { delay(delayMilliseconds) withContext(Dispatchers.Main) { diff --git a/stripe/src/test/java/com/stripe/android/ApiOperationTest.kt b/stripe/src/test/java/com/stripe/android/ApiOperationTest.kt index 104b01080e2..564c1ed7a6c 100644 --- a/stripe/src/test/java/com/stripe/android/ApiOperationTest.kt +++ b/stripe/src/test/java/com/stripe/android/ApiOperationTest.kt @@ -12,7 +12,6 @@ import com.stripe.android.model.PaymentIntentFixtures import com.stripe.android.utils.TestUtils.idleLooper import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestCoroutineDispatcher -import kotlinx.coroutines.test.TestCoroutineScope import org.json.JSONException import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner @@ -101,7 +100,7 @@ class ApiOperationTest { private val resultSupplier: () -> PaymentIntent?, callback: ApiResultCallback ) : ApiOperation( - workScope = TestCoroutineScope(TestCoroutineDispatcher()), + workContext = TestCoroutineDispatcher(), callback = callback ) { override suspend fun getResult(): PaymentIntent? = resultSupplier() diff --git a/stripe/src/test/java/com/stripe/android/CustomerSessionTest.kt b/stripe/src/test/java/com/stripe/android/CustomerSessionTest.kt index eebfc0a7d52..587300899e9 100644 --- a/stripe/src/test/java/com/stripe/android/CustomerSessionTest.kt +++ b/stripe/src/test/java/com/stripe/android/CustomerSessionTest.kt @@ -800,7 +800,7 @@ class CustomerSessionTest { ApiKeyFixtures.FAKE_PUBLISHABLE_KEY, "acct_abc123", timeSupplier = timeSupplier, - workDispatcher = testDispatcher, + workContext = testDispatcher, ephemeralKeyManagerFactory = ephemeralKeyManagerFactory ) } diff --git a/stripe/src/test/java/com/stripe/android/FingerprintDataRepositoryTest.kt b/stripe/src/test/java/com/stripe/android/FingerprintDataRepositoryTest.kt index c0459b52334..5a46c8d9044 100644 --- a/stripe/src/test/java/com/stripe/android/FingerprintDataRepositoryTest.kt +++ b/stripe/src/test/java/com/stripe/android/FingerprintDataRepositoryTest.kt @@ -51,7 +51,7 @@ class FingerprintDataRepositoryTest { fingerprintRequestExecutor = object : FingerprintRequestExecutor { override suspend fun execute(request: FingerprintRequest) = expectedFingerprintData }, - dispatcher = testDispatcher + workContext = testDispatcher ) repository.save(createFingerprintData(elapsedTime = -60L)) repository.refresh() @@ -71,7 +71,7 @@ class FingerprintDataRepositoryTest { localStore = store, fingerprintRequestFactory = fingerprintRequestFactory, fingerprintRequestExecutor = fingerprintRequestExecutor, - dispatcher = testDispatcher + workContext = testDispatcher ) repository.refresh() diff --git a/stripe/src/test/java/com/stripe/android/FingerprintRequestExecutorTest.kt b/stripe/src/test/java/com/stripe/android/FingerprintRequestExecutorTest.kt index f47ebd7b7fb..0c0c6a67816 100644 --- a/stripe/src/test/java/com/stripe/android/FingerprintRequestExecutorTest.kt +++ b/stripe/src/test/java/com/stripe/android/FingerprintRequestExecutorTest.kt @@ -76,7 +76,7 @@ class FingerprintRequestExecutorTest { connectionFactory: ConnectionFactory = ConnectionFactory.Default() ) = FingerprintRequestExecutor.Default( connectionFactory = connectionFactory, - workDispatcher = testDispatcher + workContext = testDispatcher ) private companion object { diff --git a/stripe/src/test/java/com/stripe/android/PaymentSessionTest.kt b/stripe/src/test/java/com/stripe/android/PaymentSessionTest.kt index 297d27fbef5..e2855b14792 100644 --- a/stripe/src/test/java/com/stripe/android/PaymentSessionTest.kt +++ b/stripe/src/test/java/com/stripe/android/PaymentSessionTest.kt @@ -340,7 +340,7 @@ class PaymentSessionTest { stripeRepository, ApiKeyFixtures.FAKE_PUBLISHABLE_KEY, "acct_abc123", - workDispatcher = testDispatcher, + workContext = testDispatcher, ephemeralKeyManagerFactory = EphemeralKeyManager.Factory.Default( keyProvider = ephemeralKeyProvider, shouldPrefetchEphemeralKey = true diff --git a/stripe/src/test/java/com/stripe/android/StripeApiRepositoryTest.kt b/stripe/src/test/java/com/stripe/android/StripeApiRepositoryTest.kt index b5800da2d2b..ae8f4a0b0ee 100644 --- a/stripe/src/test/java/com/stripe/android/StripeApiRepositoryTest.kt +++ b/stripe/src/test/java/com/stripe/android/StripeApiRepositoryTest.kt @@ -60,7 +60,7 @@ internal class StripeApiRepositoryTest { private val stripeApiRepository = StripeApiRepository( context, DEFAULT_OPTIONS.apiKey, - workDispatcher = testDispatcher + workContext = testDispatcher ) private val fileFactory = FileFactory(context) diff --git a/stripe/src/test/java/com/stripe/android/StripeEndToEndTest.kt b/stripe/src/test/java/com/stripe/android/StripeEndToEndTest.kt index 2a60438e3b7..fda593be521 100644 --- a/stripe/src/test/java/com/stripe/android/StripeEndToEndTest.kt +++ b/stripe/src/test/java/com/stripe/android/StripeEndToEndTest.kt @@ -221,7 +221,7 @@ internal class StripeEndToEndTest { stripeRepository ), publishableKey = publishableKey, - workDispatcher = testDispatcher + workContext = testDispatcher ) } } diff --git a/stripe/src/test/java/com/stripe/android/StripePaymentControllerTest.kt b/stripe/src/test/java/com/stripe/android/StripePaymentControllerTest.kt index 742565fc0b7..5b8b4d68001 100644 --- a/stripe/src/test/java/com/stripe/android/StripePaymentControllerTest.kt +++ b/stripe/src/test/java/com/stripe/android/StripePaymentControllerTest.kt @@ -45,7 +45,6 @@ import com.stripe.android.view.PaymentRelayActivity import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.TestCoroutineDispatcher -import kotlinx.coroutines.test.TestCoroutineScope import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import kotlin.test.BeforeTest @@ -82,7 +81,7 @@ class StripePaymentControllerTest { private val apiResultStripeIntentArgumentCaptor: KArgumentCaptor> = argumentCaptor() private val sourceArgumentCaptor: KArgumentCaptor = argumentCaptor() - private val testScope = TestCoroutineScope(TestCoroutineDispatcher()) + private val testDispatcher = TestCoroutineDispatcher() @BeforeTest fun setup() { @@ -768,7 +767,7 @@ class StripePaymentControllerTest { analyticsDataFactory, challengeFlowStarter, challengeProgressActivityStarter, - testScope + testDispatcher ) } diff --git a/stripe/src/test/java/com/stripe/android/view/CardInputWidgetTest.kt b/stripe/src/test/java/com/stripe/android/view/CardInputWidgetTest.kt index 4bc5e3a6c64..0ec6d27cf4d 100644 --- a/stripe/src/test/java/com/stripe/android/view/CardInputWidgetTest.kt +++ b/stripe/src/test/java/com/stripe/android/view/CardInputWidgetTest.kt @@ -53,7 +53,7 @@ internal class CardInputWidgetTest { private lateinit var cardInputWidget: CardInputWidget private val cardNumberEditText: CardNumberEditText by lazy { cardInputWidget.cardNumberEditText.also { - it.workDispatcher = testDispatcher + it.workContext = testDispatcher } } private val expiryEditText: StripeEditText by lazy { diff --git a/stripe/src/test/java/com/stripe/android/view/CardMultilineWidgetTest.kt b/stripe/src/test/java/com/stripe/android/view/CardMultilineWidgetTest.kt index 8d0b491436a..9e719d7882c 100644 --- a/stripe/src/test/java/com/stripe/android/view/CardMultilineWidgetTest.kt +++ b/stripe/src/test/java/com/stripe/android/view/CardMultilineWidgetTest.kt @@ -25,7 +25,6 @@ import com.stripe.android.model.PaymentMethod import com.stripe.android.model.PaymentMethodCreateParams import com.stripe.android.testharness.ViewTestUtils import com.stripe.android.utils.TestUtils.idleLooper -import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestCoroutineDispatcher @@ -34,6 +33,7 @@ import org.junit.runner.RunWith import org.mockito.Mockito.reset import org.robolectric.RobolectricTestRunner import java.util.Calendar +import kotlin.coroutines.CoroutineContext import kotlin.test.BeforeTest import kotlin.test.Test @@ -1054,10 +1054,10 @@ internal class CardMultilineWidgetTest { internal class WidgetControlGroup( widget: CardMultilineWidget, - workDispatcher: CoroutineDispatcher + workContext: CoroutineContext ) { val cardNumberEditText: CardNumberEditText = widget.findViewById(R.id.et_card_number).also { - it.workDispatcher = workDispatcher + it.workContext = workContext } val cardInputLayout: TextInputLayout = widget.findViewById(R.id.tl_card_number) val expiryDateEditText: ExpiryDateEditText = widget.findViewById(R.id.et_expiry) diff --git a/stripe/src/test/java/com/stripe/android/view/CardNumberEditTextTest.kt b/stripe/src/test/java/com/stripe/android/view/CardNumberEditTextTest.kt index 36ee3dd3fc5..92eb4fa7bf4 100644 --- a/stripe/src/test/java/com/stripe/android/view/CardNumberEditTextTest.kt +++ b/stripe/src/test/java/com/stripe/android/view/CardNumberEditTextTest.kt @@ -74,7 +74,7 @@ internal class CardNumberEditTextTest { private val cardNumberEditText = CardNumberEditText( context, - workDispatcher = testDispatcher, + workContext = testDispatcher, cardAccountRangeRepository = cardAccountRangeRepository ).also { it.completionCallback = completionCallback @@ -233,7 +233,7 @@ internal class CardNumberEditTextTest { fun `when 15 digit PAN is pasted, should not call completion callback`() { val cardNumberEditText = CardNumberEditText( context, - workDispatcher = testDispatcher, + workContext = testDispatcher, cardAccountRangeRepository = NullCardAccountRangeRepository() ) @@ -253,7 +253,7 @@ internal class CardNumberEditTextTest { fun `when 19 digit PAN is pasted, call completion callback`() { val cardNumberEditText = CardNumberEditText( context, - workDispatcher = testDispatcher, + workContext = testDispatcher, cardAccountRangeRepository = NullCardAccountRangeRepository(), staticCardAccountRanges = object : StaticCardAccountRanges { override fun match( @@ -278,7 +278,7 @@ internal class CardNumberEditTextTest { fun `updating text with null account range should format text correctly but not set card brand`() { val cardNumberEditText = CardNumberEditText( context, - workDispatcher = testDispatcher, + workContext = testDispatcher, cardAccountRangeRepository = NullCardAccountRangeRepository() ) @@ -635,7 +635,7 @@ internal class CardNumberEditTextTest { activityScenario.onActivity { activity -> val cardNumberEditText = CardNumberEditText( activity, - workDispatcher = testDispatcher, + workContext = testDispatcher, cardAccountRangeRepository = DelayedCardAccountRangeRepository() ) @@ -662,7 +662,7 @@ internal class CardNumberEditTextTest { var repositoryCalls = 0 val cardNumberEditText = CardNumberEditText( context, - workDispatcher = testDispatcher, + workContext = testDispatcher, cardAccountRangeRepository = object : CardAccountRangeRepository { override suspend fun getAccountRange( cardNumber: CardNumber.Unvalidated diff --git a/stripe/src/test/java/com/stripe/android/view/PaymentFlowViewModelTest.kt b/stripe/src/test/java/com/stripe/android/view/PaymentFlowViewModelTest.kt index 550862badfc..4377b1f0192 100644 --- a/stripe/src/test/java/com/stripe/android/view/PaymentFlowViewModelTest.kt +++ b/stripe/src/test/java/com/stripe/android/view/PaymentFlowViewModelTest.kt @@ -15,8 +15,6 @@ import com.stripe.android.model.ShippingInformation import com.stripe.android.model.ShippingMethod import com.stripe.android.utils.TestUtils.idleLooper import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.TestCoroutineDispatcher -import kotlinx.coroutines.test.TestCoroutineScope import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import kotlin.test.Test @@ -31,13 +29,10 @@ class PaymentFlowViewModelTest { private val customerRetrievalListener = argumentCaptor() - private val testScope = TestCoroutineScope(TestCoroutineDispatcher()) - private val viewModel: PaymentFlowViewModel by lazy { PaymentFlowViewModel( customerSession = customerSession, - paymentSessionData = PaymentSessionData(PaymentSessionFixtures.CONFIG), - workScope = testScope + paymentSessionData = PaymentSessionData(PaymentSessionFixtures.CONFIG) ) } diff --git a/stripe/src/test/java/com/stripe/android/view/PaymentMethodsAdapterTest.kt b/stripe/src/test/java/com/stripe/android/view/PaymentMethodsAdapterTest.kt index 83e29568391..5513b5bbc03 100644 --- a/stripe/src/test/java/com/stripe/android/view/PaymentMethodsAdapterTest.kt +++ b/stripe/src/test/java/com/stripe/android/view/PaymentMethodsAdapterTest.kt @@ -9,9 +9,10 @@ import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.verify import com.stripe.android.model.PaymentMethod import com.stripe.android.model.PaymentMethodFixtures +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestCoroutineDispatcher -import kotlinx.coroutines.test.TestCoroutineScope +import kotlinx.coroutines.test.setMain import org.junit.runner.RunWith import org.mockito.Mockito.times import org.robolectric.RobolectricTestRunner @@ -27,13 +28,17 @@ class PaymentMethodsAdapterTest { private val adapterDataObserver: RecyclerView.AdapterDataObserver = mock() private val listener: PaymentMethodsAdapter.Listener = mock() - private val paymentMethodsAdapter: PaymentMethodsAdapter = PaymentMethodsAdapter(ARGS) - private val context = ApplicationProvider.getApplicationContext() - private val testScope = TestCoroutineScope(TestCoroutineDispatcher()) + private val testDispatcher = TestCoroutineDispatcher() + + private val paymentMethodsAdapter: PaymentMethodsAdapter = PaymentMethodsAdapter( + ARGS, + workContext = testDispatcher + ) @BeforeTest fun setup() { + Dispatchers.setMain(testDispatcher) paymentMethodsAdapter.registerAdapterDataObserver(adapterDataObserver) } @@ -108,7 +113,8 @@ class PaymentMethodsAdapterTest { val adapter = PaymentMethodsAdapter( intentArgs = PaymentMethodsActivityStarter.Args.Builder() .build(), - initiallySelectedPaymentMethodId = "pm_1000" + initiallySelectedPaymentMethodId = "pm_1000", + workContext = testDispatcher ) adapter.setPaymentMethods(PaymentMethodFixtures.CARD_PAYMENT_METHODS) assertThat(adapter.selectedPaymentMethod?.id) @@ -120,7 +126,8 @@ class PaymentMethodsAdapterTest { val adapter = PaymentMethodsAdapter( ARGS, addableTypes = listOf(PaymentMethod.Type.Card, PaymentMethod.Type.Fpx), - shouldShowGooglePay = true + shouldShowGooglePay = true, + workContext = testDispatcher ) adapter.setPaymentMethods(PaymentMethodFixtures.CARD_PAYMENT_METHODS) @@ -146,7 +153,8 @@ class PaymentMethodsAdapterTest { val adapter = PaymentMethodsAdapter( ARGS, addableTypes = listOf(PaymentMethod.Type.Card, PaymentMethod.Type.Fpx), - shouldShowGooglePay = true + shouldShowGooglePay = true, + workContext = testDispatcher ) adapter.setPaymentMethods(PaymentMethodFixtures.CARD_PAYMENT_METHODS) @@ -168,7 +176,8 @@ class PaymentMethodsAdapterTest { val adapter = PaymentMethodsAdapter( ARGS, addableTypes = listOf(PaymentMethod.Type.Card, PaymentMethod.Type.Fpx), - shouldShowGooglePay = false + shouldShowGooglePay = false, + workContext = testDispatcher ) adapter.setPaymentMethods(PaymentMethodFixtures.CARD_PAYMENT_METHODS) @@ -186,7 +195,11 @@ class PaymentMethodsAdapterTest { @Test fun testGooglePayRowClick_shouldCallListener() { - val adapter = PaymentMethodsAdapter(ARGS, shouldShowGooglePay = true) + val adapter = PaymentMethodsAdapter( + ARGS, + shouldShowGooglePay = true, + workContext = testDispatcher + ) adapter.setPaymentMethods(PaymentMethodFixtures.CARD_PAYMENT_METHODS) adapter.listener = listener @@ -204,7 +217,7 @@ class PaymentMethodsAdapterTest { fun `onPositionClicked() should call listener's onPaymentMethodClick()`() { val adapter = PaymentMethodsAdapter( ARGS, - scope = testScope + workContext = testDispatcher ) adapter.setPaymentMethods(PaymentMethodFixtures.CARD_PAYMENT_METHODS) @@ -216,7 +229,11 @@ class PaymentMethodsAdapterTest { @Test fun getPosition_withValidPaymentMethod_returnsPosition() { - val adapter = PaymentMethodsAdapter(ARGS, shouldShowGooglePay = true) + val adapter = PaymentMethodsAdapter( + ARGS, + shouldShowGooglePay = true, + workContext = testDispatcher + ) adapter.setPaymentMethods(PaymentMethodFixtures.CARD_PAYMENT_METHODS) assertThat(adapter.getPosition(PaymentMethodFixtures.CARD_PAYMENT_METHODS.last())) @@ -225,7 +242,11 @@ class PaymentMethodsAdapterTest { @Test fun getPosition_withInvalidPaymentMethod_returnsNull() { - val adapter = PaymentMethodsAdapter(ARGS, shouldShowGooglePay = true) + val adapter = PaymentMethodsAdapter( + ARGS, + shouldShowGooglePay = true, + workContext = testDispatcher + ) adapter.setPaymentMethods(PaymentMethodFixtures.CARD_PAYMENT_METHODS) assertThat(adapter.getPosition(PaymentMethodFixtures.FPX_PAYMENT_METHOD)) diff --git a/stripe/src/test/java/com/stripe/android/view/StripeEditTextTest.kt b/stripe/src/test/java/com/stripe/android/view/StripeEditTextTest.kt index a03ef93ae29..47773b2a62f 100644 --- a/stripe/src/test/java/com/stripe/android/view/StripeEditTextTest.kt +++ b/stripe/src/test/java/com/stripe/android/view/StripeEditTextTest.kt @@ -30,7 +30,7 @@ internal class StripeEditTextTest { private val editText = StripeEditText( context, - workDispatcher = testDispatcher + workContext = testDispatcher ).also { it.setDeleteEmptyListener(deleteEmptyListener) it.setAfterTextChangedListener(afterTextChangedListener)