From a6ffee5fee6d2f35e63e7c4289cfe40613322761 Mon Sep 17 00:00:00 2001 From: Adyen Release Manager Date: Tue, 28 Nov 2017 10:06:51 +0100 Subject: [PATCH] Release 1.13.0 --- README.md | 10 +- .../com/adyen/core/DeviceTokenGenerator.java | 2 +- .../com/adyen/core/models/PaymentMethod.java | 1 + .../CreditCardPaymentDetails.java | 2 + .../paymentdetails/IdealPaymentDetails.java | 4 +- .../IssuerSelectionPaymentDetails.java | 30 +++ .../QiwiWalletPaymentDetails.java | 23 ++ .../DefaultPaymentRequestDetailsListener.java | 13 +- .../adyen/ui/activities/CheckoutActivity.java | 61 +++-- .../ui/fragments/CreditCardFragment.java | 14 +- .../ui/fragments/IssuerSelectionFragment.java | 4 +- .../ui/fragments/QiwiWalletFragment.java | 119 +++++++++ .../fragments/QiwiWalletFragmentBuilder.java | 92 +++++++ .../main/res/layout/qiwi_wallet_fragment.xml | 130 ++++++++++ adyen-ui/src/main/res/values/strings.xml | 5 +- app/libs/adyencse-1.0.0.aar | Bin 23769 -> 0 bytes app/src/main/res/layout/activity_main.xml | 171 ------------- build.gradle | 5 +- checkoutdemo/build.gradle | 8 +- .../customuiapplication/MainActivity.java | 8 +- .../customwithcheckoutui/MainActivity.java | 8 +- {app => defaultApp}/build.gradle | 0 {app => defaultApp}/proguard-rules.pro | 0 .../src/androidTest/AndroidManifest.xml | 0 .../com/adyen/checkout/CardNumberService.java | 0 .../com/adyen/checkout/IbanNumberService.java | 0 .../com/adyen/checkout/PaymentAppTest.java | 2 +- .../src/main/AndroidManifest.xml | 0 .../java/com/adyen/checkout/MainActivity.java | 7 +- .../checkout/MyPaymentCardScannerFactory.java | 0 .../checkout/PaymentDataEntryFragment.java | 18 +- .../adyen/checkout/PaymentResultActivity.java | 0 .../adyen/checkout/PaymentSetupRequest.java | 18 ++ .../res/drawable/ic_camera_alt_black_24dp.xml | 0 .../src/main/res/layout/activity_main.xml | 234 ++++++++++++++++++ .../main/res/layout/verification_activity.xml | 0 .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin .../src/main/res/values-w820dp/dimens.xml | 0 .../src/main/res/values/colors.xml | 0 .../src/main/res/values/dimens.xml | 0 .../src/main/res/values/strings.xml | 0 .../src/main/res/values/styles.xml | 0 settings.gradle | 2 +- 47 files changed, 755 insertions(+), 236 deletions(-) create mode 100644 adyen-core/src/main/java/com/adyen/core/models/paymentdetails/IssuerSelectionPaymentDetails.java create mode 100644 adyen-core/src/main/java/com/adyen/core/models/paymentdetails/QiwiWalletPaymentDetails.java create mode 100644 adyen-ui/src/main/java/com/adyen/ui/fragments/QiwiWalletFragment.java create mode 100644 adyen-ui/src/main/java/com/adyen/ui/fragments/QiwiWalletFragmentBuilder.java create mode 100644 adyen-ui/src/main/res/layout/qiwi_wallet_fragment.xml delete mode 100644 app/libs/adyencse-1.0.0.aar delete mode 100644 app/src/main/res/layout/activity_main.xml rename {app => defaultApp}/build.gradle (100%) rename {app => defaultApp}/proguard-rules.pro (100%) rename {app => defaultApp}/src/androidTest/AndroidManifest.xml (100%) rename {app => defaultApp}/src/androidTest/java/com/adyen/checkout/CardNumberService.java (100%) rename {app => defaultApp}/src/androidTest/java/com/adyen/checkout/IbanNumberService.java (100%) rename {app => defaultApp}/src/androidTest/java/com/adyen/checkout/PaymentAppTest.java (99%) rename {app => defaultApp}/src/main/AndroidManifest.xml (100%) rename {app => defaultApp}/src/main/java/com/adyen/checkout/MainActivity.java (96%) rename {app => defaultApp}/src/main/java/com/adyen/checkout/MyPaymentCardScannerFactory.java (100%) rename {app => defaultApp}/src/main/java/com/adyen/checkout/PaymentDataEntryFragment.java (76%) rename {app => defaultApp}/src/main/java/com/adyen/checkout/PaymentResultActivity.java (100%) rename {app => defaultApp}/src/main/java/com/adyen/checkout/PaymentSetupRequest.java (74%) rename {app => defaultApp}/src/main/res/drawable/ic_camera_alt_black_24dp.xml (100%) create mode 100644 defaultApp/src/main/res/layout/activity_main.xml rename {app => defaultApp}/src/main/res/layout/verification_activity.xml (100%) rename {app => defaultApp}/src/main/res/mipmap-hdpi/ic_launcher.png (100%) rename {app => defaultApp}/src/main/res/mipmap-mdpi/ic_launcher.png (100%) rename {app => defaultApp}/src/main/res/mipmap-xhdpi/ic_launcher.png (100%) rename {app => defaultApp}/src/main/res/mipmap-xxhdpi/ic_launcher.png (100%) rename {app => defaultApp}/src/main/res/mipmap-xxxhdpi/ic_launcher.png (100%) rename {app => defaultApp}/src/main/res/values-w820dp/dimens.xml (100%) rename {app => defaultApp}/src/main/res/values/colors.xml (100%) rename {app => defaultApp}/src/main/res/values/dimens.xml (100%) rename {app => defaultApp}/src/main/res/values/strings.xml (100%) rename {app => defaultApp}/src/main/res/values/styles.xml (100%) diff --git a/README.md b/README.md index 4e8c361852..67dcaea61b 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,10 @@ This README provides the usage manual for the SDK itself. For the full documenta To integrate the Adyen SDK into your project, import the **core**, **utils** and **ui** module by adding the following lines to your build.gradle file. ``` -compile 'com.adyen.checkout:core:1.12.0' -compile 'com.adyen.checkout:utils:1.12.0' -compile 'com.adyen.checkout:ui:1.12.0' -compile 'com.adyen.checkout:cardscan:1.12.0' +compile 'com.adyen.checkout:core:1.13.0' +compile 'com.adyen.checkout:utils:1.13.0' +compile 'com.adyen.checkout:ui:1.13.0' +compile 'com.adyen.checkout:cardscan:1.13.0' ``` > For implementing Custom integration, only the **core** module is required. However, you might also want to include the **utils** module to use Adyen's utility methods such as Luhn check, credit card type detection, etc. @@ -174,7 +174,7 @@ For your convenience, we included the following demo modules into this repositor * **checkoutdemo** – A functioning demo of the Checkout SDK using the Quick integration. -* **app** – Also uses the Quick integration, but allows to configure parameters for setting up the payment request. +* **defaultApp** – Also uses the Quick integration, but allows to configure parameters for setting up the payment request. * **customuiapplication** – An example implementation of the Custom integration where the application fully handles the UI. diff --git a/adyen-core/src/main/java/com/adyen/core/DeviceTokenGenerator.java b/adyen-core/src/main/java/com/adyen/core/DeviceTokenGenerator.java index 0839bd06cd..64caf1f5ba 100644 --- a/adyen-core/src/main/java/com/adyen/core/DeviceTokenGenerator.java +++ b/adyen-core/src/main/java/com/adyen/core/DeviceTokenGenerator.java @@ -43,8 +43,8 @@ static String getToken(final Context context, final PaymentStateHandler paymentS deviceInfo.put("sdkVersion", SDK_VERSION); deviceInfo.put("deviceIdentifier", androidId); deviceInfo.put("locale", StringUtils.getLocale(context)); - deviceInfo.put("integration", (isQuickIntegration) ? "quick" : "custom"); + deviceInfo.put("deviceModel", Build.MANUFACTURER + " " + Build.DEVICE); } catch (final JSONException jsonException) { Log.e(TAG, "Token could not be created", jsonException); diff --git a/adyen-core/src/main/java/com/adyen/core/models/PaymentMethod.java b/adyen-core/src/main/java/com/adyen/core/models/PaymentMethod.java index 77b0f6bffc..8f6ae05ec4 100644 --- a/adyen-core/src/main/java/com/adyen/core/models/PaymentMethod.java +++ b/adyen-core/src/main/java/com/adyen/core/models/PaymentMethod.java @@ -31,6 +31,7 @@ public static class Type { public static final String SEPA_DIRECT_DEBIT = "sepadirectdebit"; public static final String PAYPAL = "paypal"; public static final String BCMC = "bcmc"; + public static final String QIWI_WALLET = "qiwiwallet"; } private static final long serialVersionUID = 2587948839462686004L; diff --git a/adyen-core/src/main/java/com/adyen/core/models/paymentdetails/CreditCardPaymentDetails.java b/adyen-core/src/main/java/com/adyen/core/models/paymentdetails/CreditCardPaymentDetails.java index 4f7149b964..46e603735e 100644 --- a/adyen-core/src/main/java/com/adyen/core/models/paymentdetails/CreditCardPaymentDetails.java +++ b/adyen-core/src/main/java/com/adyen/core/models/paymentdetails/CreditCardPaymentDetails.java @@ -13,6 +13,8 @@ public class CreditCardPaymentDetails extends PaymentDetails { public static final String INSTALLMENTS = "installments"; public static final String BILLING_ADDRESS = "billingAddress"; + public static final String CARD_HOLDER_NAME_REQUIRED = "cardHolderNameRequired"; + public enum AddressKey { street, houseNumberOrName, diff --git a/adyen-core/src/main/java/com/adyen/core/models/paymentdetails/IdealPaymentDetails.java b/adyen-core/src/main/java/com/adyen/core/models/paymentdetails/IdealPaymentDetails.java index d3441cde80..fdb51ad497 100644 --- a/adyen-core/src/main/java/com/adyen/core/models/paymentdetails/IdealPaymentDetails.java +++ b/adyen-core/src/main/java/com/adyen/core/models/paymentdetails/IdealPaymentDetails.java @@ -3,11 +3,11 @@ import java.util.Collection; /** - * PaymentDetails class for sepa direct debit payments. + * PaymentDetails class for the iDEAL issuer selection. */ public class IdealPaymentDetails extends PaymentDetails { - private static final String IDEAL_ISSUER = "idealIssuer"; + public static final String IDEAL_ISSUER = "idealIssuer"; public IdealPaymentDetails(Collection inputDetails) { super(inputDetails); diff --git a/adyen-core/src/main/java/com/adyen/core/models/paymentdetails/IssuerSelectionPaymentDetails.java b/adyen-core/src/main/java/com/adyen/core/models/paymentdetails/IssuerSelectionPaymentDetails.java new file mode 100644 index 0000000000..05f0dcafe7 --- /dev/null +++ b/adyen-core/src/main/java/com/adyen/core/models/paymentdetails/IssuerSelectionPaymentDetails.java @@ -0,0 +1,30 @@ +package com.adyen.core.models.paymentdetails; + +import java.util.Collection; + +/** + * PaymentDetails class for issuer selection. + */ +public class IssuerSelectionPaymentDetails extends PaymentDetails { + + public static final String ISSUER = "issuer"; + + public IssuerSelectionPaymentDetails(Collection inputDetails) { + super(inputDetails); + } + + public boolean fillIssuer(final String issuerId) { + for (InputDetail inputDetail: getInputDetails()) { + if (IdealPaymentDetails.IDEAL_ISSUER.equalsIgnoreCase(inputDetail.getKey()) + || ISSUER.equalsIgnoreCase(inputDetail.getKey())) { + return super.fill(inputDetail.getKey(), issuerId); + } + } + return false; + } + + public boolean fillIssuer(final InputDetail.Item issuerItem) { + return fillIssuer(issuerItem.getId()); + } + +} diff --git a/adyen-core/src/main/java/com/adyen/core/models/paymentdetails/QiwiWalletPaymentDetails.java b/adyen-core/src/main/java/com/adyen/core/models/paymentdetails/QiwiWalletPaymentDetails.java new file mode 100644 index 0000000000..9a9c240011 --- /dev/null +++ b/adyen-core/src/main/java/com/adyen/core/models/paymentdetails/QiwiWalletPaymentDetails.java @@ -0,0 +1,23 @@ +package com.adyen.core.models.paymentdetails; + +import java.util.Collection; + +/** + * PaymentDetails class for Qiwi wallet payments. + */ +public class QiwiWalletPaymentDetails extends PaymentDetails { + + private static final String QIWI_TELEPHONE_NUMBER_PREFIX = "qiwiwallet.telephoneNumberPrefix"; + private static final String QIWI_TELEPHONE_NUMBER = "qiwiwallet.telephoneNumber"; + + + public QiwiWalletPaymentDetails(Collection inputDetails) { + super(inputDetails); + } + + public boolean fillTelephoneNumber(final String countryCode, final String telephoneNumber) { + return super.fill(QIWI_TELEPHONE_NUMBER, telephoneNumber) + && super.fill(QIWI_TELEPHONE_NUMBER_PREFIX, countryCode); + } + +} diff --git a/adyen-ui/src/main/java/com/adyen/ui/DefaultPaymentRequestDetailsListener.java b/adyen-ui/src/main/java/com/adyen/ui/DefaultPaymentRequestDetailsListener.java index b77a5e76f5..4fd48aae10 100644 --- a/adyen-ui/src/main/java/com/adyen/ui/DefaultPaymentRequestDetailsListener.java +++ b/adyen-ui/src/main/java/com/adyen/ui/DefaultPaymentRequestDetailsListener.java @@ -20,8 +20,10 @@ import com.adyen.core.interfaces.UriCallback; import com.adyen.core.internals.ModuleAvailabilityUtil; import com.adyen.core.models.PaymentMethod; +import com.adyen.core.models.paymentdetails.IdealPaymentDetails; import com.adyen.core.models.paymentdetails.InputDetail; import com.adyen.core.models.paymentdetails.InputDetailsUtil; +import com.adyen.core.models.paymentdetails.IssuerSelectionPaymentDetails; import com.adyen.core.models.paymentdetails.PaymentDetails; import com.adyen.core.services.PaymentMethodService; import com.adyen.ui.activities.CheckoutActivity; @@ -120,8 +122,9 @@ public void onReceive(final Context context, final Intent intent) { public void onPaymentDetailsRequired(@NonNull PaymentRequest paymentRequest, @NonNull Collection inputDetails, @NonNull PaymentDetailsCallback callback) { - if (paymentRequest.getPaymentMethod().getType().equals(PaymentMethod.Type.IDEAL)) { + if (InputDetailsUtil.containsKey(inputDetails, IdealPaymentDetails.IDEAL_ISSUER) + || InputDetailsUtil.containsKey(inputDetails, IssuerSelectionPaymentDetails.ISSUER)) { final Intent intent = new Intent(context, CheckoutActivity.class); Bundle bundle = new Bundle(); bundle.putSerializable(PAYMENT_METHOD, paymentRequest.getPaymentMethod()); @@ -157,6 +160,14 @@ public void onPaymentDetailsRequired(@NonNull PaymentRequest paymentRequest, intent.putExtra(GENERATION_TIME, paymentRequest.getGenerationTime()); intent.putExtra(CVC_FIELD_STATUS, CreditCardFragmentBuilder.CvcFieldStatus.NOCVC.name()); context.startActivity(intent); + } else if (paymentRequest.getPaymentMethod().getType().equals(PaymentMethod.Type.QIWI_WALLET)) { + final Intent intent = new Intent(context, CheckoutActivity.class); + Bundle bundle = new Bundle(); + bundle.putSerializable(PAYMENT_METHOD, paymentRequest.getPaymentMethod()); + bundle.putSerializable(AMOUNT, paymentRequest.getAmount()); + bundle.putInt("fragment", CheckoutActivity.QIWI_WALLET_FRAGMENT); + intent.putExtras(bundle); + context.startActivity(intent); } else if (paymentRequest.getPaymentMethod().getType().equals(PaymentMethod.Type.PAYPAL)) { //We can set "storeDetails" to true if we want to set up a recurring contract. callback.completionWithPaymentDetails(new PaymentDetails(inputDetails)); diff --git a/adyen-ui/src/main/java/com/adyen/ui/activities/CheckoutActivity.java b/adyen-ui/src/main/java/com/adyen/ui/activities/CheckoutActivity.java index 3397e72495..a97072262f 100644 --- a/adyen-ui/src/main/java/com/adyen/ui/activities/CheckoutActivity.java +++ b/adyen-ui/src/main/java/com/adyen/ui/activities/CheckoutActivity.java @@ -21,7 +21,8 @@ import com.adyen.core.models.Amount; import com.adyen.core.models.PaymentMethod; import com.adyen.core.models.paymentdetails.CreditCardPaymentDetails; -import com.adyen.core.models.paymentdetails.IdealPaymentDetails; +import com.adyen.core.models.paymentdetails.IssuerSelectionPaymentDetails; +import com.adyen.core.models.paymentdetails.QiwiWalletPaymentDetails; import com.adyen.core.models.paymentdetails.SepaDirectDebitPaymentDetails; import com.adyen.ui.R; import com.adyen.ui.fragments.CreditCardFragment; @@ -32,6 +33,8 @@ import com.adyen.ui.fragments.LoadingScreenFragment; import com.adyen.ui.fragments.PaymentMethodSelectionFragment; import com.adyen.ui.fragments.PaymentMethodSelectionFragmentBuilder; +import com.adyen.ui.fragments.QiwiWalletFragment; +import com.adyen.ui.fragments.QiwiWalletFragmentBuilder; import com.adyen.ui.fragments.SepaDirectDebitFragment; import com.adyen.ui.fragments.SepaDirectDebitFragmentBuilder; @@ -58,6 +61,7 @@ public class CheckoutActivity extends FragmentActivity { public static final int ISSUER_SELECTION_FRAGMENT = 2; public static final int SEPA_DIRECT_DEBIT_FRAGMENT = 3; public static final int GIROPAY_FRAGMENT = 4; + public static final int QIWI_WALLET_FRAGMENT = 5; public static final int LOADING_SCREEN_FRAGMENT = 11; public static final String PREFERED_PAYMENT_METHODS = "preferredPaymentMethods"; @@ -125,11 +129,9 @@ public void onBackPressed() { if (backStackEntryCount == 0) { super.onBackPressed(); } else { - FragmentManager.BackStackEntry backEntry = getSupportFragmentManager(). - getBackStackEntryAt(backStackEntryCount - 1); + FragmentManager.BackStackEntry backEntry = getSupportFragmentManager().getBackStackEntryAt(backStackEntryCount - 1); String tag = backEntry.getName(); - if (PaymentMethodSelectionFragment.class.getName().equals(tag) - || LoadingScreenFragment.class.getName().equals(tag)) { + if (PaymentMethodSelectionFragment.class.getName().equals(tag) || LoadingScreenFragment.class.getName().equals(tag)) { final Intent cancellationIntent = new Intent(Constants.PaymentRequest.PAYMENT_REQUEST_CANCELLED_INTENT); LocalBroadcastManager.getInstance(this).sendBroadcast(cancellationIntent); finish(); @@ -160,10 +162,8 @@ private void initializeFragment(final Intent intent) { switch (fragmentId) { case PAYMENT_METHOD_SELECTION_FRAGMENT: { - final ArrayList preferredPaymentMethods = (ArrayList) bundle - .getSerializable(PREFERED_PAYMENT_METHODS); - final ArrayList paymentMethods = (ArrayList) bundle - .getSerializable(PAYMENT_METHODS); + final ArrayList preferredPaymentMethods = (ArrayList) bundle.getSerializable(PREFERED_PAYMENT_METHODS); + final ArrayList paymentMethods = (ArrayList) bundle.getSerializable(PAYMENT_METHODS); final PaymentMethodSelectionFragment paymentMethodSelectionFragment = new PaymentMethodSelectionFragmentBuilder() @@ -174,8 +174,7 @@ private void initializeFragment(final Intent intent) { public void onPaymentMethodSelected(PaymentMethod paymentMethod) { if (paymentMethod.isRedirectMethod() || (paymentMethod.isOneClick() && !paymentMethod.requiresInput())) { - final Intent intent = new Intent(context.getApplicationContext(), - TranslucentLoadingScreenActivity.class); + final Intent intent = new Intent(context.getApplicationContext(), TranslucentLoadingScreenActivity.class); context.startActivity(intent); } Intent intent = new Intent(PAYMENT_METHOD_SELECTED_INTENT); @@ -184,11 +183,7 @@ public void onPaymentMethodSelected(PaymentMethod paymentMethod) { } }) .build(); - - - replaceFragment(paymentMethodSelectionFragment); - hideKeyboard(); break; } @@ -213,21 +208,17 @@ public void onCreditCardInfoProvided(CreditCardPaymentDetails creditCardPaymentD } }) .build(); - - replaceFragment(creditCardFragment, TAG_CREDIT_CARD_FRAGMENT); - break; } case ISSUER_SELECTION_FRAGMENT: { final PaymentMethod paymentMethod = (PaymentMethod) bundle.getSerializable(PAYMENT_METHOD); - IssuerSelectionFragment issuerSelectionFragment = new IssuerSelectionFragmentBuilder() .setPaymentMethod(paymentMethod) .setIssuerSelectionListener(new IssuerSelectionFragment.IssuerSelectionListener() { @Override public void onIssuerSelected(String issuer) { - IdealPaymentDetails paymentDetails = new IdealPaymentDetails(paymentMethod.getInputDetails()); + IssuerSelectionPaymentDetails paymentDetails = new IssuerSelectionPaymentDetails(paymentMethod.getInputDetails()); paymentDetails.fillIssuer(issuer); final Intent intent = new Intent(Constants.PaymentRequest.PAYMENT_DETAILS_PROVIDED_INTENT); intent.putExtra(PAYMENT_DETAILS, paymentDetails); @@ -235,8 +226,6 @@ public void onIssuerSelected(String issuer) { } }) .build(); - - replaceFragment(issuerSelectionFragment); break; } @@ -258,10 +247,30 @@ public void onPaymentDetails(String iban, String accountHolder) { } }) .build(); - replaceFragment(sepaDirectDebitFragment); break; } + case QIWI_WALLET_FRAGMENT: { + final PaymentMethod paymentMethod = (PaymentMethod) bundle.getSerializable(PAYMENT_METHOD); + paymentMethod.getInputDetails(); + QiwiWalletFragment qiwiWalletFragment = new QiwiWalletFragmentBuilder() + .setAmount((Amount) intent.getSerializableExtra(AMOUNT)) + .setPaymentMethod(paymentMethod) + .setQiwiWalletPaymentDetailsListener(new QiwiWalletFragment.QiwiWalletPaymentDetailsListener() { + @Override + public void onPaymentDetails(String countryCode, String telephoneNumber) { + QiwiWalletPaymentDetails paymentDetails = new QiwiWalletPaymentDetails(paymentMethod.getInputDetails()); + paymentDetails.fillTelephoneNumber(countryCode, telephoneNumber); + + final Intent intent = new Intent(Constants.PaymentRequest.PAYMENT_DETAILS_PROVIDED_INTENT); + intent.putExtra(PAYMENT_DETAILS, paymentDetails); + LocalBroadcastManager.getInstance(context).sendBroadcast(intent); + } + }) + .build(); + replaceFragment(qiwiWalletFragment); + break; + } case GIROPAY_FRAGMENT: { final GiropayFragment giropayFragment = new GiropayFragment(); @@ -298,9 +307,13 @@ public void onClick(View v) { } public void setActionBarTitle(int titleId) { + setActionBarTitle(getString(titleId)); + } + + public void setActionBarTitle(String title) { ActionBar actionBar = getActionBar(); if (actionBar != null && actionBar.getCustomView() != null) { - ((TextView) actionBar.getCustomView().findViewById(R.id.action_bar_title)).setText(getString(titleId)); + ((TextView) actionBar.getCustomView().findViewById(R.id.action_bar_title)).setText(title); actionBar.show(); } } diff --git a/adyen-ui/src/main/java/com/adyen/ui/fragments/CreditCardFragment.java b/adyen-ui/src/main/java/com/adyen/ui/fragments/CreditCardFragment.java index a324041724..17d15e39f6 100644 --- a/adyen-ui/src/main/java/com/adyen/ui/fragments/CreditCardFragment.java +++ b/adyen-ui/src/main/java/com/adyen/ui/fragments/CreditCardFragment.java @@ -72,6 +72,7 @@ public class CreditCardFragment extends Fragment implements CreditCardEditText.C private CreditCardInfoListener creditCardInfoListener; private boolean oneClick; private boolean nameRequired; + private boolean storeDetailsOptionAvailable; private Amount amount; private String shopperReference; private PaymentMethod paymentMethod; @@ -124,8 +125,15 @@ public void setArguments(final Bundle args) { cvcFieldStatus = CreditCardFragmentBuilder.CvcFieldStatus.valueOf(args.getString(Constants.DataKeys.CVC_FIELD_STATUS)); for (InputDetail inputDetail : paymentMethod.getInputDetails()) { - if (inputDetail.getKey().equals("cardHolderName")) { - nameRequired = true; + if (CreditCardPaymentDetails.ADDITIONAL_DATA_CARD.equals(inputDetail.getKey())) { + if (inputDetail.getConfiguration() != null + && inputDetail.getConfiguration().containsKey(CreditCardPaymentDetails.CARD_HOLDER_NAME_REQUIRED) + && "true".equalsIgnoreCase(inputDetail.getConfiguration().get(CreditCardPaymentDetails.CARD_HOLDER_NAME_REQUIRED))) { + nameRequired = true; + } + } + if (inputDetail.getKey().equals("storeDetails")) { + storeDetailsOptionAvailable = true; } } @@ -305,7 +313,7 @@ public void onReadyStateChanged(boolean isReady) { } saveCardCheckBox = (CheckoutCheckBox) fragmentView.findViewById(R.id.save_card_checkbox); - if (!StringUtils.isEmptyOrNull(shopperReference)) { + if (!StringUtils.isEmptyOrNull(shopperReference) && storeDetailsOptionAvailable) { fragmentView.findViewById(R.id.layout_save_card).setVisibility(VISIBLE); fragmentView.findViewById(R.id.layout_click_area_save_card).setOnClickListener(new View.OnClickListener() { @Override diff --git a/adyen-ui/src/main/java/com/adyen/ui/fragments/IssuerSelectionFragment.java b/adyen-ui/src/main/java/com/adyen/ui/fragments/IssuerSelectionFragment.java index 34f92e5372..61a689b68e 100644 --- a/adyen-ui/src/main/java/com/adyen/ui/fragments/IssuerSelectionFragment.java +++ b/adyen-ui/src/main/java/com/adyen/ui/fragments/IssuerSelectionFragment.java @@ -67,7 +67,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa fragmentView = localInflater.inflate(R.layout.issuer_selection_fragment, container, false); for (InputDetail inputDetail : paymentMethod.getInputDetails()) { - if (inputDetail.getKey().equals("idealIssuer")) { + if (inputDetail.getKey().equals("idealIssuer") || inputDetail.getKey().equals("issuer")) { issuers = inputDetail.getItems(); break; } @@ -85,7 +85,7 @@ public void onItemClick(final AdapterView adapterView, final View view, final }); if (getActivity() instanceof CheckoutActivity) { - ((CheckoutActivity) getActivity()).setActionBarTitle(R.string.title_issuers); + ((CheckoutActivity) getActivity()).setActionBarTitle(paymentMethod.getName()); } return fragmentView; } diff --git a/adyen-ui/src/main/java/com/adyen/ui/fragments/QiwiWalletFragment.java b/adyen-ui/src/main/java/com/adyen/ui/fragments/QiwiWalletFragment.java new file mode 100644 index 0000000000..7958992290 --- /dev/null +++ b/adyen-ui/src/main/java/com/adyen/ui/fragments/QiwiWalletFragment.java @@ -0,0 +1,119 @@ +package com.adyen.ui.fragments; + +import android.content.Context; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.view.ContextThemeWrapper; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Spinner; +import android.widget.TextView; + +import com.adyen.core.models.Amount; +import com.adyen.core.models.PaymentMethod; +import com.adyen.core.models.paymentdetails.InputDetail; +import com.adyen.core.utils.AmountUtil; +import com.adyen.core.utils.StringUtils; +import com.adyen.ui.R; +import com.adyen.ui.activities.CheckoutActivity; + +import java.util.Collection; + + +/** + * Fragment for collecting payment details for Qiwi Wallet + * Should be instantiated via {@link QiwiWalletFragmentBuilder}. + */ +public class QiwiWalletFragment extends Fragment { + + private PaymentMethod paymentMethod; + private Amount amount; + + private int theme; + + private QiwiWalletPaymentDetailsListener qiwiWalletPaymentDetailsListener; + + /** + * Use {@link QiwiWalletFragmentBuilder} instead. + */ + public QiwiWalletFragment() { + //Default empty constructor + } + + + public interface QiwiWalletPaymentDetailsListener { + void onPaymentDetails(String countryCode, String telephoneNumber); + } + + @Override + public void setArguments(Bundle args) { + super.setArguments(args); + amount = (Amount) args.get(CheckoutActivity.AMOUNT); + + paymentMethod = (PaymentMethod) args.getSerializable(CheckoutActivity.PAYMENT_METHOD); + + theme = args.getInt("theme"); + + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { + final View fragmentView; + final Context contextThemeWrapper = new ContextThemeWrapper(getActivity(), theme); + LayoutInflater localInflater = inflater.cloneInContext(contextThemeWrapper); + fragmentView = localInflater.inflate(R.layout.qiwi_wallet_fragment, container, false); + + + final EditText telephoneNumber = (EditText) fragmentView.findViewById(R.id.telephone_number_edit_text); + + final Spinner countryCode = (Spinner) fragmentView.findViewById(R.id.country_code_spinner); + + Collection inputDetails = paymentMethod.getInputDetails(); + for (InputDetail inputDetail : inputDetails) { + if ("qiwiwallet.telephoneNumberPrefix".equals(inputDetail.getKey())) { + java.util.ArrayList countryCodes = new java.util.ArrayList<>(); + for (InputDetail.Item country : inputDetail.getItems()) { + countryCodes.add(country.getName() + " (" + country.getId() + ")"); + } + ArrayAdapter adapter = new ArrayAdapter<>(getActivity(), android.R.layout.select_dialog_item, countryCodes); + countryCode.setAdapter(adapter); + + // TODO: Use a proper list adapter here to get rid of string magic below. + } + } + + final Button confirmButton = (Button) fragmentView.findViewById(R.id.collect_direct_debit_data); + confirmButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + String countryCodeString = countryCode.getSelectedItem().toString(); + String strippedCountryCode = countryCodeString.substring(countryCodeString.indexOf("+"), countryCodeString.indexOf(")")); + qiwiWalletPaymentDetailsListener.onPaymentDetails(strippedCountryCode, telephoneNumber.getText().toString()); + } + }); + confirmButton.setEnabled(true); + + final TextView amountTextview = (TextView) fragmentView.findViewById(R.id.amount_text_view); + final String valueString = AmountUtil.format(amount, true, StringUtils.getLocale(getActivity())); + final String amountString = getString(R.string.pay_with_amount, valueString); + amountTextview.setText(amountString); + + if (getActivity() instanceof CheckoutActivity) { + ((CheckoutActivity) getActivity()).setActionBarTitle(R.string.title_qiwi_wallet); + } + + return fragmentView; + } + + void setQiwiWalletPaymentDetailsListener(QiwiWalletPaymentDetailsListener listener) { + this.qiwiWalletPaymentDetailsListener = listener; + } + +} diff --git a/adyen-ui/src/main/java/com/adyen/ui/fragments/QiwiWalletFragmentBuilder.java b/adyen-ui/src/main/java/com/adyen/ui/fragments/QiwiWalletFragmentBuilder.java new file mode 100644 index 0000000000..067e484266 --- /dev/null +++ b/adyen-ui/src/main/java/com/adyen/ui/fragments/QiwiWalletFragmentBuilder.java @@ -0,0 +1,92 @@ +package com.adyen.ui.fragments; + +import android.os.Bundle; + +import com.adyen.core.models.Amount; +import com.adyen.core.models.PaymentMethod; +import com.adyen.ui.R; +import com.adyen.ui.activities.CheckoutActivity; + +import static com.adyen.core.constants.Constants.DataKeys.AMOUNT; + +/** + * Builder to create {@link QiwiWalletFragment}. + */ +public class QiwiWalletFragmentBuilder { + private PaymentMethod paymentMethod; + private Amount amount; + + private int theme = R.style.AdyenTheme; + + private QiwiWalletFragment.QiwiWalletPaymentDetailsListener qiwiWalletPaymentDetailsListener; + + public QiwiWalletFragmentBuilder() { + + } + + public QiwiWalletFragmentBuilder setPaymentMethod(final PaymentMethod paymentMethod) { + this.paymentMethod = paymentMethod; + return this; + } + + /** + * Set the {@link Amount} of this payment. + * This is only to display the amount in the ui. + * @param amount The {@link Amount} to be displayed to the user. + * @return CreditCardFragmentBuilder + */ + public QiwiWalletFragmentBuilder setAmount(final Amount amount) { + this.amount = amount; + return this; + } + + /** + * Set the theme that should be applied to the generated fragment. + * If not set the default Adyen style will be applied. + * @param theme The theme that should be applied. + * @return QiwiWalletFragmentBuilder + */ + public QiwiWalletFragmentBuilder setTheme(final int theme) { + this.theme = theme; + return this; + } + + public QiwiWalletFragmentBuilder setQiwiWalletPaymentDetailsListener(QiwiWalletFragment.QiwiWalletPaymentDetailsListener listener) { + this.qiwiWalletPaymentDetailsListener = listener; + return this; + } + + /** + * Build the {@link QiwiWalletFragment}. + * This will fail with {@link IllegalStateException} if one or more mandatory parameters have not been set. + * @return The fragment that can be displayed in the ui. + */ + public QiwiWalletFragment build() { + checkParameters(); + + QiwiWalletFragment fragment = new QiwiWalletFragment(); + Bundle bundle = new Bundle(); + bundle.putSerializable(CheckoutActivity.PAYMENT_METHOD, paymentMethod); + bundle.putSerializable(AMOUNT, amount); + bundle.putInt("theme", theme); + + fragment.setArguments(bundle); + fragment.setQiwiWalletPaymentDetailsListener(qiwiWalletPaymentDetailsListener); + + return fragment; + } + + private void checkParameters() { + if (amount == null) { + throw new IllegalStateException("Amount not set."); + } + + if (paymentMethod == null) { + throw new IllegalStateException("PaymentMethod not set."); + } + + if (qiwiWalletPaymentDetailsListener == null) { + throw new IllegalStateException("QiwiWalletPaymentDataListener not set."); + } + } +} diff --git a/adyen-ui/src/main/res/layout/qiwi_wallet_fragment.xml b/adyen-ui/src/main/res/layout/qiwi_wallet_fragment.xml new file mode 100644 index 0000000000..9546a70f53 --- /dev/null +++ b/adyen-ui/src/main/res/layout/qiwi_wallet_fragment.xml @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/adyen-ui/src/main/res/values/strings.xml b/adyen-ui/src/main/res/values/strings.xml index b29c0cf6cc..2a124f117f 100644 --- a/adyen-ui/src/main/res/values/strings.xml +++ b/adyen-ui/src/main/res/values/strings.xml @@ -14,9 +14,12 @@ Payment Methods Bank account number (IBAN) NL53 ABNA 1925 1294 122 + Country code + Telephone number + 0123456789 - iDeal SEPA Direct Debit + Qiwi Wallet I agree that the amount below will be debited from my bank account. Giropay Bankname / BIC / Bankleitzahl diff --git a/app/libs/adyencse-1.0.0.aar b/app/libs/adyencse-1.0.0.aar deleted file mode 100644 index 95d470bce2f59d48d513b8460944497e09206174..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23769 zcmafaV~i%iwr$&*wr$(CZQHhO+xE0=+cu~BYuoOgH+lER%}H)@l1kRfUR9}G`&U)= zDn%JkFc=^pC@7$uKxnDDNip7gARwR#U?3ore<);c>g-@;DraPGWp3u;O7CfBYnL=F zKf(wn_WB)7{b_}{A-L*_bfpzIf}S<99F?76oH4$iLWQUL+ca%sT;r8{_h7pF1C(VG zGj)SQqj;>aq|r#x_z-ZTj{8ydh;;QU>M|J8nkW;uR_SmgSDQ+zU;&g(rgw2sMzUl^ z()o8(6+J}|zL6l=fUgOs%dGEmX#aq4draB5B}~uX_E#``i)o8xKQ@wGQAr+Vz?U|n z7mohS+egNeye(2VFJb-fOB|)?7}nCG8VLHlSxQa}0Rrg`Dyl)Rq1vtx4_E0Ol+&i2 zru-*#>0mlZ6=^0GzGj^k>8{NnT`kHwZm;+BA4tXjs1O5IYyK-O5YXNi5D@sk3MtdO zdb*bR>7)SIn@&D|qJMxN36r}N6a2Ec+--6tdOw=p2vCIf{Xy+XUU%iZPOh=5}e7C-DhshaByVRxD7K>wbY z$B6Pzk(V#Pl8^1UVSi=(*9Y<35P%)-#_EkjkQMjP8~aA#bsc5kno}2QlR2?oP9_K( zQM3{*;e+~Tq$v%T`6@Cy=!^ep{xCk!wG!WXguy5dXQ{rR{Qkr0E8eNJtRP3j!U%am z74t5ogI5)0-=MxYD_aKA^wQ){0>BC^n-t3a3cN(zhBzO@pEr(Uu+>{md}L5SZuYf2 zOmmAd46nW(RhnBxguo+O*JUCAE+b!fl9T!@og zQ8Ul5X#XZ3N?!bAj@yFt=VfcpX@@RG?1w+(87ge*gMVF5U?^D`kqSye6Yl1UI{&e< zlm|3h%?C`-_lCcDj~)tKc+E8Qkh%>94prdx>W5=JIm#)YoygPciNAlS|lTrW( zM3)25GfqEa##^9B(5^kl2{{9JZvf->zI;*LihZFk2JomIW!fDV9pl;-eBuq5tAfDN z7hEeE&+S-CcqT|?YY1!ggtkMo5znzHD+4JVyP6V+HASoQ$324}9&mRS_dAlirg>Jq zM$ieLE4i9q>4O1S4k9hVY$AffDa`$>7*5{F>`^Db4}#BZxYFYanU=S~^*nxp$&pz?IANnrA&N}tt@^Sp$ymC$d`lv=IN^e;4_GCm|Io-}iU;8l7p)C)17`QVd%?}I6BBaw9{Wj%Tf zq_`*K=*E8S_~N7%5Dgx~VA?Un&jMWk&PQbG2L!6G1J#~A*F2daOEAe5|6O|G%k^KA zfP<%KXbqfqSXX)ch-m{B(5YibLZ%N?r}KIl=7j&7t_LjczWfU{y_pK?h=c1C0go0! z-Q1+m(5PiU0*I-1z1ixIs5%W4Gfm+9aGVo|&M#u07}va7+!;h-#T@trdZ;#8p$VK|{j{K~c5+8O@H@!Ec^jAW{q0PeSa>N$tw41Fj&;PtA3Z2GM6bAw zkfwt11!&M0nGH4?#t{bRz<^H8`Og)p=KEn?AU_|h`NQw)f^`ChUez$3vw~S}Q6mXN zaj!s-A-7&{MqJ3n0MBnz+u3$dRweIN3-_))5UitO5eSoIuMWv}+K{7Dsc;IS9!erz z2;f;O{FDS`p1`{S6omHqDh!coy}{&CWMdoZKtqZaZ}4jYDYNunZwoP ziLdO^1y;$)&4uG=Ia^q9x)1tb3UrA{Dz=d3!tYb3MDg@8Qg`e7K=OhDQ|uq{b%_~-psi@f44&R1Z29g zVzHe7@HIb&=DlT^)hAF!E3E)Rp_NXMIIObal%nlVnOBgNF5oa-xrkxK;>$^ZSPlIc3pB|BKX3IVS!xPg0w}c6A6Oz_vHjG?wSS^i0<4EMAv~v8(!QUh{-l5`^#F3E!HtWlH(Kxcwynt3�F(U=xGG{>BeBp)` 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

gy9kke=?WiGSRSykFD-EBbksf# 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 SKE_6WxIRC8w~}f-e)=ELhecTc diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml deleted file mode 100644 index 61642a081b..0000000000 --- a/app/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,171 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build.gradle b/build.gradle index 52d61c3718..c781020e14 100644 --- a/build.gradle +++ b/build.gradle @@ -30,8 +30,8 @@ ext { minSdkVersion = 16 targetSdkVersion = 25 - versionCode = 15 - versionName = "1.12.0" + versionCode = 16 + versionName = "1.13.0" release_debuggable = false release_minifyEnabled = false @@ -235,6 +235,7 @@ task generateJavadoc(type: Javadoc) { include('**/CreditCardPaymentDetails.java') include('**/CVCOnlyPaymentDetails.java') include('**/IdealPaymentDetails.java') + include('**/IssuerSelectionPaymentDetails.java') include('**/SepaDirectDebitPaymentDetails.java') include('**/InputDetail.java') diff --git a/checkoutdemo/build.gradle b/checkoutdemo/build.gradle index cab09ad877..96b819e966 100644 --- a/checkoutdemo/build.gradle +++ b/checkoutdemo/build.gradle @@ -37,8 +37,8 @@ dependencies { }) compile "com.android.support:appcompat-v7:${rootProject.supportLibVersion}" testCompile "junit:junit:${rootProject.jUnitVersion}" - compile 'com.adyen.checkout:core:1.12.0' - compile 'com.adyen.checkout:ui:1.12.0' - compile 'com.adyen.checkout:utils:1.12.0' - compile 'com.adyen.checkout:cardscan:1.12.0' + compile 'com.adyen.checkout:core:1.13.0' + compile 'com.adyen.checkout:ui:1.13.0' + compile 'com.adyen.checkout:utils:1.13.0' + compile 'com.adyen.checkout:cardscan:1.13.0' } diff --git a/customuiapplication/src/main/java/com/adyen/customuiapplication/MainActivity.java b/customuiapplication/src/main/java/com/adyen/customuiapplication/MainActivity.java index 88dfb98e10..44bb10715b 100644 --- a/customuiapplication/src/main/java/com/adyen/customuiapplication/MainActivity.java +++ b/customuiapplication/src/main/java/com/adyen/customuiapplication/MainActivity.java @@ -26,7 +26,7 @@ import com.adyen.core.models.PaymentRequestResult; import com.adyen.core.models.paymentdetails.CVCOnlyPaymentDetails; import com.adyen.core.models.paymentdetails.CreditCardPaymentDetails; -import com.adyen.core.models.paymentdetails.IdealPaymentDetails; +import com.adyen.core.models.paymentdetails.IssuerSelectionPaymentDetails; import com.adyen.core.models.paymentdetails.InputDetail; import com.adyen.core.models.paymentdetails.InputDetailsUtil; import com.adyen.core.utils.AsyncHttpClient; @@ -149,10 +149,10 @@ public void onCreditCardInfoProvided(String creditCardInfo) { alertDialog.setSingleChoiceItems(issuerListAdapter, -1, new DialogInterface.OnClickListener() { @Override public void onClick(@NonNull final DialogInterface dialogInterface, final int i) { - IdealPaymentDetails idealPaymentDetails = new IdealPaymentDetails(inputDetails); - idealPaymentDetails.fillIssuer(issuers.get(i)); + IssuerSelectionPaymentDetails issuerSelectionPaymentDetails = new IssuerSelectionPaymentDetails(inputDetails); + issuerSelectionPaymentDetails.fillIssuer(issuers.get(i)); dialogInterface.dismiss(); - callback.completionWithPaymentDetails(idealPaymentDetails); + callback.completionWithPaymentDetails(issuerSelectionPaymentDetails); } }); alertDialog.show(); diff --git a/customwithcheckoutui/src/main/java/com/example/customwithcheckoutui/MainActivity.java b/customwithcheckoutui/src/main/java/com/example/customwithcheckoutui/MainActivity.java index 0b4619f356..1dfc4e7cdf 100644 --- a/customwithcheckoutui/src/main/java/com/example/customwithcheckoutui/MainActivity.java +++ b/customwithcheckoutui/src/main/java/com/example/customwithcheckoutui/MainActivity.java @@ -23,7 +23,7 @@ import com.adyen.core.models.PaymentMethod; import com.adyen.core.models.PaymentRequestResult; import com.adyen.core.models.paymentdetails.CreditCardPaymentDetails; -import com.adyen.core.models.paymentdetails.IdealPaymentDetails; +import com.adyen.core.models.paymentdetails.IssuerSelectionPaymentDetails; import com.adyen.core.models.paymentdetails.InputDetail; import com.adyen.core.models.paymentdetails.SepaDirectDebitPaymentDetails; import com.adyen.core.utils.AsyncHttpClient; @@ -141,9 +141,9 @@ public void onCreditCardInfoProvided(CreditCardPaymentDetails creditCardPaymentD .setIssuerSelectionListener(new IssuerSelectionFragment.IssuerSelectionListener() { @Override public void onIssuerSelected(String issuer) { - IdealPaymentDetails idealPaymentDetails = new IdealPaymentDetails(inputDetails); - idealPaymentDetails.fillIssuer(issuer); - callback.completionWithPaymentDetails(idealPaymentDetails); + IssuerSelectionPaymentDetails issuerSelectionPaymentDetails = new IssuerSelectionPaymentDetails(inputDetails); + issuerSelectionPaymentDetails.fillIssuer(issuer); + callback.completionWithPaymentDetails(issuerSelectionPaymentDetails); } }) .build(); diff --git a/app/build.gradle b/defaultApp/build.gradle similarity index 100% rename from app/build.gradle rename to defaultApp/build.gradle diff --git a/app/proguard-rules.pro b/defaultApp/proguard-rules.pro similarity index 100% rename from app/proguard-rules.pro rename to defaultApp/proguard-rules.pro diff --git a/app/src/androidTest/AndroidManifest.xml b/defaultApp/src/androidTest/AndroidManifest.xml similarity index 100% rename from app/src/androidTest/AndroidManifest.xml rename to defaultApp/src/androidTest/AndroidManifest.xml diff --git a/app/src/androidTest/java/com/adyen/checkout/CardNumberService.java b/defaultApp/src/androidTest/java/com/adyen/checkout/CardNumberService.java similarity index 100% rename from app/src/androidTest/java/com/adyen/checkout/CardNumberService.java rename to defaultApp/src/androidTest/java/com/adyen/checkout/CardNumberService.java diff --git a/app/src/androidTest/java/com/adyen/checkout/IbanNumberService.java b/defaultApp/src/androidTest/java/com/adyen/checkout/IbanNumberService.java similarity index 100% rename from app/src/androidTest/java/com/adyen/checkout/IbanNumberService.java rename to defaultApp/src/androidTest/java/com/adyen/checkout/IbanNumberService.java diff --git a/app/src/androidTest/java/com/adyen/checkout/PaymentAppTest.java b/defaultApp/src/androidTest/java/com/adyen/checkout/PaymentAppTest.java similarity index 99% rename from app/src/androidTest/java/com/adyen/checkout/PaymentAppTest.java rename to defaultApp/src/androidTest/java/com/adyen/checkout/PaymentAppTest.java index 2c051cea38..418d42c9bb 100644 --- a/app/src/androidTest/java/com/adyen/checkout/PaymentAppTest.java +++ b/defaultApp/src/androidTest/java/com/adyen/checkout/PaymentAppTest.java @@ -382,7 +382,7 @@ public void testActionBarTitle() throws Exception { waitForText("Payment Methods"); waitForText("Payment Methods"); onView(withText(equalToIgnoringCase("iDEAL"))).perform(scrollTo(), click()); - waitForText("iDeal"); + waitForText("iDEAL"); Espresso.pressBack(); waitForText("Payment Methods"); } diff --git a/app/src/main/AndroidManifest.xml b/defaultApp/src/main/AndroidManifest.xml similarity index 100% rename from app/src/main/AndroidManifest.xml rename to defaultApp/src/main/AndroidManifest.xml diff --git a/app/src/main/java/com/adyen/checkout/MainActivity.java b/defaultApp/src/main/java/com/adyen/checkout/MainActivity.java similarity index 96% rename from app/src/main/java/com/adyen/checkout/MainActivity.java rename to defaultApp/src/main/java/com/adyen/checkout/MainActivity.java index 35c4c01319..e022878715 100644 --- a/app/src/main/java/com/adyen/checkout/MainActivity.java +++ b/defaultApp/src/main/java/com/adyen/checkout/MainActivity.java @@ -149,8 +149,8 @@ private String getSetupDataString(final String token) { amount.put("currency", paymentSetupRequest.getAmount().getCurrency()); jsonObject.put("amount", amount); jsonObject.put("channel", "Android"); - jsonObject.put("reference", "Android Checkout SDK Payment: " + System.currentTimeMillis()); - jsonObject.put("shopperReference", "example-customer@exampleprovider"); + jsonObject.put("reference", paymentSetupRequest.getReference()); + jsonObject.put("shopperReference", paymentSetupRequest.getShopperReference()); try { short maxNumberOfInstallments = Short.parseShort(paymentSetupRequest.getMaxNumberOfInstallments()); if (maxNumberOfInstallments > 1) { @@ -192,7 +192,8 @@ public void onSuccess(final byte[] response) { JSONObject jsonVerifyResponse = new JSONObject(new String(response, Charset.forName("UTF-8"))); String authResponse = jsonVerifyResponse.getString("authResponse"); if (authResponse.equalsIgnoreCase(payment.getPaymentStatus().toString())) { - resultString = "Payment is " + payment.getPaymentStatus().toString().toLowerCase() + " and verified."; + resultString = "Payment is " + payment.getPaymentStatus().toString().toLowerCase() + " and verified. Reference: " + + jsonVerifyResponse.getString("merchantReference"); } else { resultString = "Failed to verify payment."; } diff --git a/app/src/main/java/com/adyen/checkout/MyPaymentCardScannerFactory.java b/defaultApp/src/main/java/com/adyen/checkout/MyPaymentCardScannerFactory.java similarity index 100% rename from app/src/main/java/com/adyen/checkout/MyPaymentCardScannerFactory.java rename to defaultApp/src/main/java/com/adyen/checkout/MyPaymentCardScannerFactory.java diff --git a/app/src/main/java/com/adyen/checkout/PaymentDataEntryFragment.java b/defaultApp/src/main/java/com/adyen/checkout/PaymentDataEntryFragment.java similarity index 76% rename from app/src/main/java/com/adyen/checkout/PaymentDataEntryFragment.java rename to defaultApp/src/main/java/com/adyen/checkout/PaymentDataEntryFragment.java index 32381c1f09..68c8b4e3fc 100644 --- a/app/src/main/java/com/adyen/checkout/PaymentDataEntryFragment.java +++ b/defaultApp/src/main/java/com/adyen/checkout/PaymentDataEntryFragment.java @@ -71,21 +71,25 @@ public void onClick(final View view) { @NonNull private PaymentSetupRequest buildPaymentRequest(final View view) throws ParseException { Log.v(TAG, "buildPaymentRequest()"); - PaymentSetupRequest paymentRequest = new PaymentSetupRequest(); + PaymentSetupRequest paymentSetupRequest = new PaymentSetupRequest(); + paymentSetupRequest.setMerchantAccount(((EditText) view.findViewById(R.id.merchantAccountEntry)).getText() + .toString()); final String amountValueString = ((EditText) view.findViewById(R.id.orderAmountEntry)).getText().toString(); final String amountCurrencyString = ((EditText) view.findViewById(R.id.orderCurrencyEntry)) .getText().toString(); - paymentRequest.setAmount(new Amount(AmountUtil.parseMajorAmount(amountCurrencyString, amountValueString), + paymentSetupRequest.setAmount(new Amount(AmountUtil.parseMajorAmount(amountCurrencyString, amountValueString), amountCurrencyString)); - paymentRequest.setCountryCode(((EditText) view.findViewById(R.id.countryEntry)).getText().toString()); - paymentRequest.setShopperLocale(((EditText) view.findViewById(R.id.shopperLocaleEntry)).getText().toString()); - paymentRequest.setMerchantAccount(((EditText) view.findViewById(R.id.merchantAccountEntry)).getText() + paymentSetupRequest.setCountryCode(((EditText) view.findViewById(R.id.countryEntry)).getText().toString()); + paymentSetupRequest.setShopperLocale(((EditText) view.findViewById(R.id.shopperLocaleEntry)).getText().toString()); + paymentSetupRequest.setShopperReference(((EditText) view.findViewById(R.id.shopperReferenceEntry)).getText() + .toString()); + paymentSetupRequest.setReference(((EditText) view.findViewById(R.id.referenceEntry)).getText() .toString()); String maxNumberOfInstallments = ((String) ((Spinner) view.findViewById(R.id.installmentsEntry)).getSelectedItem()); - paymentRequest.setMaxNumberOfInstallments(maxNumberOfInstallments); + paymentSetupRequest.setMaxNumberOfInstallments(maxNumberOfInstallments); - return paymentRequest; + return paymentSetupRequest; } } diff --git a/app/src/main/java/com/adyen/checkout/PaymentResultActivity.java b/defaultApp/src/main/java/com/adyen/checkout/PaymentResultActivity.java similarity index 100% rename from app/src/main/java/com/adyen/checkout/PaymentResultActivity.java rename to defaultApp/src/main/java/com/adyen/checkout/PaymentResultActivity.java diff --git a/app/src/main/java/com/adyen/checkout/PaymentSetupRequest.java b/defaultApp/src/main/java/com/adyen/checkout/PaymentSetupRequest.java similarity index 74% rename from app/src/main/java/com/adyen/checkout/PaymentSetupRequest.java rename to defaultApp/src/main/java/com/adyen/checkout/PaymentSetupRequest.java index 1b2c3c060f..73c9ea7d98 100644 --- a/app/src/main/java/com/adyen/checkout/PaymentSetupRequest.java +++ b/defaultApp/src/main/java/com/adyen/checkout/PaymentSetupRequest.java @@ -8,6 +8,8 @@ public class PaymentSetupRequest { private String shopperLocale; private String merchantAccount; private String countryCode; + private String reference; + private String shopperReference; private String maxNumberOfInstallments; public Amount getAmount() { @@ -42,6 +44,22 @@ public void setCountryCode(final String countryCode) { this.countryCode = countryCode; } + public String getReference() { + return reference; + } + + public void setReference(String reference) { + this.reference = reference; + } + + public String getShopperReference() { + return shopperReference; + } + + public void setShopperReference(String shopperReference) { + this.shopperReference = shopperReference; + } + public String getMaxNumberOfInstallments() { return maxNumberOfInstallments; } diff --git a/app/src/main/res/drawable/ic_camera_alt_black_24dp.xml b/defaultApp/src/main/res/drawable/ic_camera_alt_black_24dp.xml similarity index 100% rename from app/src/main/res/drawable/ic_camera_alt_black_24dp.xml rename to defaultApp/src/main/res/drawable/ic_camera_alt_black_24dp.xml diff --git a/defaultApp/src/main/res/layout/activity_main.xml b/defaultApp/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000000..f5200b63a5 --- /dev/null +++ b/defaultApp/src/main/res/layout/activity_main.xml @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/verification_activity.xml b/defaultApp/src/main/res/layout/verification_activity.xml similarity index 100% rename from app/src/main/res/layout/verification_activity.xml rename to defaultApp/src/main/res/layout/verification_activity.xml diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/defaultApp/src/main/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from app/src/main/res/mipmap-hdpi/ic_launcher.png rename to defaultApp/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/defaultApp/src/main/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from app/src/main/res/mipmap-mdpi/ic_launcher.png rename to defaultApp/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/defaultApp/src/main/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from app/src/main/res/mipmap-xhdpi/ic_launcher.png rename to defaultApp/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/defaultApp/src/main/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from app/src/main/res/mipmap-xxhdpi/ic_launcher.png rename to defaultApp/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/defaultApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from app/src/main/res/mipmap-xxxhdpi/ic_launcher.png rename to defaultApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/app/src/main/res/values-w820dp/dimens.xml b/defaultApp/src/main/res/values-w820dp/dimens.xml similarity index 100% rename from app/src/main/res/values-w820dp/dimens.xml rename to defaultApp/src/main/res/values-w820dp/dimens.xml diff --git a/app/src/main/res/values/colors.xml b/defaultApp/src/main/res/values/colors.xml similarity index 100% rename from app/src/main/res/values/colors.xml rename to defaultApp/src/main/res/values/colors.xml diff --git a/app/src/main/res/values/dimens.xml b/defaultApp/src/main/res/values/dimens.xml similarity index 100% rename from app/src/main/res/values/dimens.xml rename to defaultApp/src/main/res/values/dimens.xml diff --git a/app/src/main/res/values/strings.xml b/defaultApp/src/main/res/values/strings.xml similarity index 100% rename from app/src/main/res/values/strings.xml rename to defaultApp/src/main/res/values/strings.xml diff --git a/app/src/main/res/values/styles.xml b/defaultApp/src/main/res/values/styles.xml similarity index 100% rename from app/src/main/res/values/styles.xml rename to defaultApp/src/main/res/values/styles.xml diff --git a/settings.gradle b/settings.gradle index 9835fe2b4d..3725b65743 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':app', ':adyen-core', ':adyen-ui', ':adyen-androidpay', ':customuiapplication', ':testutils', ':checkoutdemo', ':customwithcheckoutui', ':adyen-utils', ':adyen-cardscan' +include ':adyen-core', ':adyen-ui', ':adyen-utils', ':adyen-cardscan', ':adyen-androidpay', ':testutils', ':customuiapplication', ':checkoutdemo', ':customwithcheckoutui', ':defaultApp' \ No newline at end of file