Skip to content

Commit

Permalink
Merge pull request #392 from Adyen/feature/availability-provider
Browse files Browse the repository at this point in the history
Improve component availability checks
  • Loading branch information
jreij authored May 18, 2021
2 parents 80bf27a + 077b3b9 commit 96f6e42
Show file tree
Hide file tree
Showing 15 changed files with 124 additions and 115 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@
*/
package com.adyen.checkout.bcmc

import android.app.Application
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStoreOwner
import com.adyen.checkout.card.repository.PublicKeyRepository
import com.adyen.checkout.components.ComponentAvailableCallback
import com.adyen.checkout.components.PaymentComponentProvider
import com.adyen.checkout.components.base.GenericPaymentMethodDelegate
import com.adyen.checkout.components.base.lifecycle.viewModelFactory
Expand All @@ -33,13 +31,4 @@ class BcmcComponentProvider : PaymentComponentProvider<BcmcComponent, BcmcConfig
}
return ViewModelProvider(viewModelStoreOwner, bcmcFactory).get(BcmcComponent::class.java)
}

override fun isAvailable(
applicationContext: Application,
paymentMethod: PaymentMethod,
configuration: BcmcConfiguration,
callback: ComponentAvailableCallback<BcmcConfiguration>
) {
callback.onAvailabilityResult(true, paymentMethod, configuration)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,11 @@
*/
package com.adyen.checkout.card

import android.app.Application
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStoreOwner
import com.adyen.checkout.card.data.CardType
import com.adyen.checkout.card.repository.BinLookupRepository
import com.adyen.checkout.card.repository.PublicKeyRepository
import com.adyen.checkout.components.ComponentAvailableCallback
import com.adyen.checkout.components.StoredPaymentComponentProvider
import com.adyen.checkout.components.base.lifecycle.viewModelFactory
import com.adyen.checkout.components.model.paymentmethods.PaymentMethod
Expand Down Expand Up @@ -60,15 +58,6 @@ class CardComponentProvider : StoredPaymentComponentProvider<CardComponent, Card
return ViewModelProvider(viewModelStoreOwner, factory).get(CardComponent::class.java)
}

override fun isAvailable(
applicationContext: Application,
paymentMethod: PaymentMethod,
configuration: CardConfiguration,
callback: ComponentAvailableCallback<CardConfiguration?>
) {
callback.onAvailabilityResult(true, paymentMethod, configuration)
}

/**
* Check which set of supported cards to pass to the component.
* Priority is: Custom -> PaymentMethod.brands -> Default
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2021 Adyen N.V.
*
* This file is open source and available under the MIT license. See the LICENSE file for more info.
*
* Created by josephj on 18/5/2021.
*/

package com.adyen.checkout.components

import android.app.Application
import com.adyen.checkout.components.base.Configuration
import com.adyen.checkout.components.model.paymentmethods.PaymentMethod

class AlwaysAvailablePaymentMethod : PaymentMethodAvailabilityCheck<Configuration> {

override fun isAvailable(
applicationContext: Application,
paymentMethod: PaymentMethod,
configuration: Configuration?,
callback: ComponentAvailableCallback<Configuration>
) {
callback.onAvailabilityResult(true, paymentMethod, configuration)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@

package com.adyen.checkout.components;

import android.app.Application;

import androidx.annotation.NonNull;
import androidx.lifecycle.ViewModelStoreOwner;

Expand All @@ -18,9 +16,9 @@
import com.adyen.checkout.core.exception.CheckoutException;

/**
* Provides an instance of te associated Component linked to provided lifecycle and config.
* Provides an instance of the associated Component linked to provided lifecycle and config.
*
* @param <ComponentT> The Component to be provided
* @param <ComponentT> The Component to be provided
* @param <ConfigurationT> The Configuration for the Component to be provided
*/
public interface PaymentComponentProvider<ComponentT extends PaymentComponent, ConfigurationT extends Configuration>
Expand All @@ -33,10 +31,4 @@ ComponentT get(
@NonNull PaymentMethod paymentMethod,
@NonNull ConfigurationT configuration
) throws CheckoutException;

void isAvailable(
@NonNull Application applicationContext,
@NonNull PaymentMethod paymentMethod,
@NonNull ConfigurationT configuration,
@NonNull ComponentAvailableCallback<ConfigurationT> callback);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2021 Adyen N.V.
*
* This file is open source and available under the MIT license. See the LICENSE file for more info.
*
* Created by josephj on 17/5/2021.
*/
package com.adyen.checkout.components

import android.app.Application
import com.adyen.checkout.components.base.Configuration
import com.adyen.checkout.components.model.paymentmethods.PaymentMethod

/**
* Specifies whether a certain payment method is available for use with the provided parameters.
*
* @param ConfigurationT The Configuration for the Component corresponding to this payment method. Simply use [Configuration] if not applicable.
*/
interface PaymentMethodAvailabilityCheck<ConfigurationT : Configuration> {
fun isAvailable(
applicationContext: Application,
paymentMethod: PaymentMethod,
configuration: ConfigurationT?,
callback: ComponentAvailableCallback<ConfigurationT>
)
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@
*/
package com.adyen.checkout.components.base

import android.app.Application
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStoreOwner
import com.adyen.checkout.components.ComponentAvailableCallback
import com.adyen.checkout.components.PaymentComponentProvider
import com.adyen.checkout.components.base.lifecycle.viewModelFactory
import com.adyen.checkout.components.model.paymentmethods.PaymentMethod
Expand All @@ -32,13 +30,4 @@ class GenericPaymentComponentProvider<BaseComponentT : BasePaymentComponent<*, *
}
return ViewModelProvider(viewModelStoreOwner, genericFactory).get(componentClass)
}

override fun isAvailable(
applicationContext: Application,
paymentMethod: PaymentMethod,
config: ConfigurationT,
callback: ComponentAvailableCallback<ConfigurationT>
) {
callback.onAvailabilityResult(true, paymentMethod, config)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,8 @@

package com.adyen.checkout.components.base

import android.app.Application
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStoreOwner
import com.adyen.checkout.components.ComponentAvailableCallback
import com.adyen.checkout.components.StoredPaymentComponentProvider
import com.adyen.checkout.components.base.lifecycle.viewModelFactory
import com.adyen.checkout.components.model.paymentmethods.PaymentMethod
Expand Down Expand Up @@ -49,13 +47,4 @@ class GenericStoredPaymentComponentProvider<
}
return ViewModelProvider(viewModelStoreOwner, genericFactory)[componentClass]
}

override fun isAvailable(
applicationContext: Application,
paymentMethod: PaymentMethod,
configuration: ConfigurationT,
callback: ComponentAvailableCallback<ConfigurationT>
) {
callback.onAvailabilityResult(true, paymentMethod, configuration)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ import com.adyen.checkout.blik.BlikView
import com.adyen.checkout.card.CardComponent
import com.adyen.checkout.card.CardConfiguration
import com.adyen.checkout.card.CardView
import com.adyen.checkout.components.AlwaysAvailablePaymentMethod
import com.adyen.checkout.components.ComponentAvailableCallback
import com.adyen.checkout.components.ComponentView
import com.adyen.checkout.components.PaymentComponent
import com.adyen.checkout.components.PaymentComponentProvider
import com.adyen.checkout.components.PaymentComponentState
import com.adyen.checkout.components.PaymentMethodAvailabilityCheck
import com.adyen.checkout.components.ViewableComponent
import com.adyen.checkout.components.base.BaseConfigurationBuilder
import com.adyen.checkout.components.base.Configuration
Expand All @@ -51,6 +53,7 @@ import com.adyen.checkout.eps.EPSConfiguration
import com.adyen.checkout.eps.EPSRecyclerView
import com.adyen.checkout.googlepay.GooglePayComponent
import com.adyen.checkout.googlepay.GooglePayConfiguration
import com.adyen.checkout.googlepay.GooglePayProvider
import com.adyen.checkout.ideal.IdealComponent
import com.adyen.checkout.ideal.IdealConfiguration
import com.adyen.checkout.ideal.IdealRecyclerView
Expand All @@ -70,6 +73,7 @@ import com.adyen.checkout.sepa.SepaComponent
import com.adyen.checkout.sepa.SepaConfiguration
import com.adyen.checkout.sepa.SepaView
import com.adyen.checkout.wechatpay.WeChatPayActionConfiguration
import com.adyen.checkout.wechatpay.WeChatPayProvider

object ComponentParsingProvider {
val TAG = LogUtil.getTag()
Expand Down Expand Up @@ -132,7 +136,7 @@ internal inline fun <reified T : Configuration> getDefaultConfigForAction(
return builder.build() as T
}

internal fun checkComponentAvailability(
internal fun checkPaymentMethodAvailability(
application: Application,
paymentMethod: PaymentMethod,
dropInConfiguration: DropInConfiguration,
Expand All @@ -143,38 +147,26 @@ internal fun checkComponentAvailability(

val type = paymentMethod.type ?: throw CheckoutException("PaymentMethod type is null")

val provider = getProviderForType(type)
val configuration = dropInConfiguration.getConfigurationForPaymentMethod<Configuration>(type, application)
val availabilityCheck = getPaymentMethodAvailabilityCheck(type)
val configuration = dropInConfiguration.getConfigurationForPaymentMethodOrNull<Configuration>(type, application)

provider.isAvailable(application, paymentMethod, configuration, callback)
availabilityCheck.isAvailable(application, paymentMethod, configuration, callback)
} catch (e: CheckoutException) {
Logger.e(ComponentParsingProvider.TAG, "Unable to initiate ${paymentMethod.type}", e)
callback.onAvailabilityResult(false, paymentMethod, null)
}
}

@Suppress("ComplexMethod")
internal fun getProviderForType(type: String): PaymentComponentProvider<PaymentComponent<*, *>, Configuration> {
/**
* Provides the [PaymentMethodAvailabilityCheck] class for the specified [paymentMethodType], if available.
*/
internal fun getPaymentMethodAvailabilityCheck(paymentMethodType: String): PaymentMethodAvailabilityCheck<Configuration> {
@Suppress("UNCHECKED_CAST")
return when (type) {
PaymentMethodTypes.BCMC -> BcmcComponent.PROVIDER
PaymentMethodTypes.BLIK -> BlikComponent.PROVIDER
PaymentMethodTypes.DOTPAY -> DotpayComponent.PROVIDER
PaymentMethodTypes.ENTERCASH -> EntercashComponent.PROVIDER
PaymentMethodTypes.EPS -> EPSComponent.PROVIDER
PaymentMethodTypes.GOOGLE_PAY -> GooglePayComponent.PROVIDER
PaymentMethodTypes.IDEAL -> IdealComponent.PROVIDER
PaymentMethodTypes.MB_WAY -> MBWayComponent.PROVIDER
PaymentMethodTypes.MOLPAY_THAILAND,
PaymentMethodTypes.MOLPAY_MALAYSIA,
PaymentMethodTypes.MOLPAY_VIETNAM -> MolpayComponent.PROVIDER
PaymentMethodTypes.OPEN_BANKING -> OpenBankingComponent.PROVIDER
PaymentMethodTypes.SCHEME -> CardComponent.PROVIDER
PaymentMethodTypes.SEPA -> SepaComponent.PROVIDER
else -> {
throw CheckoutException("Unable to find component for type - $type")
}
} as PaymentComponentProvider<PaymentComponent<*, *>, Configuration>
return when (paymentMethodType) {
PaymentMethodTypes.GOOGLE_PAY -> GooglePayProvider()
PaymentMethodTypes.WECHAT_PAY_SDK -> WeChatPayProvider()
else -> AlwaysAvailablePaymentMethod()
} as PaymentMethodAvailabilityCheck<Configuration>
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,14 @@ class DropInConfiguration : Configuration, Parcelable {
return ParcelUtils.NO_FILE_DESCRIPTOR
}

internal fun <T : Configuration> getConfigurationForPaymentMethodOrNull(paymentMethod: String, context: Context): T? {
return try {
getConfigurationForPaymentMethod(paymentMethod, context)
} catch (e: CheckoutException) {
null
}
}

internal fun <T : Configuration> getConfigurationForPaymentMethod(paymentMethod: String, context: Context): T {
return if (availablePaymentConfigs.containsKey(paymentMethod)) {
@Suppress("UNCHECKED_CAST")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import com.adyen.checkout.core.exception.CheckoutException
import com.adyen.checkout.core.log.LogUtil
import com.adyen.checkout.core.log.Logger
import com.adyen.checkout.dropin.DropInConfiguration
import com.adyen.checkout.dropin.checkComponentAvailability
import com.adyen.checkout.dropin.checkPaymentMethodAvailability
import com.adyen.checkout.dropin.ui.stored.makeStoredModel

class PaymentMethodsListViewModel(
Expand Down Expand Up @@ -84,15 +84,14 @@ class PaymentMethodsListViewModel(
type == null -> {
throw CheckoutException("PaymentMethod type is null")
}
PaymentMethodTypes.SUPPORTED_PAYMENT_METHODS.contains(type)
&& !PaymentMethodTypes.SUPPORTED_ACTION_ONLY_PAYMENT_METHODS.contains(type) -> {
PaymentMethodTypes.SUPPORTED_PAYMENT_METHODS.contains(type) -> {
Logger.v(TAG, "Supported payment method: $type")
// We assume payment method is available and remove it later when the callback comes
// this is the overwhelming majority of cases, and we keep the list ordered this way.
paymentMethodsList.add(
PaymentMethodModel(type, paymentMethod.name.orEmpty())
)
checkComponentAvailability(getApplication(), paymentMethod, dropInConfiguration, this)
checkPaymentMethodAvailability(getApplication(), paymentMethod, dropInConfiguration, this)
}
else -> {
availabilitySkipSum++
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.adyen.checkout.components.PaymentComponentProvider;
import com.adyen.checkout.components.base.BasePaymentComponent;
import com.adyen.checkout.components.base.GenericPaymentMethodDelegate;
import com.adyen.checkout.components.model.paymentmethods.Configuration;
Expand All @@ -37,7 +36,7 @@ public class GooglePayComponent extends
BasePaymentComponent<GooglePayConfiguration, GooglePayInputData, GooglePayOutputData, GooglePayComponentState> {
private static final String TAG = LogUtil.getTag();

public static final PaymentComponentProvider<GooglePayComponent, GooglePayConfiguration> PROVIDER = new GooglePayProvider();
public static final GooglePayProvider PROVIDER = new GooglePayProvider();

private static final String[] PAYMENT_METHOD_TYPES = {PaymentMethodTypes.GOOGLE_PAY};

Expand Down
Loading

0 comments on commit 96f6e42

Please sign in to comment.