diff --git a/README.md b/README.md
index 880baac2cc..9454520cc1 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.10.0'
-compile 'com.adyen.checkout:utils:1.10.0'
-compile 'com.adyen.checkout:ui:1.10.0'
-compile 'com.adyen.checkout:cardscan:1.10.0'
+compile 'com.adyen.checkout:core:1.11.0'
+compile 'com.adyen.checkout:utils:1.11.0'
+compile 'com.adyen.checkout:ui:1.11.0'
+compile 'com.adyen.checkout:cardscan:1.11.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.
diff --git a/adyen-androidpay/build.gradle b/adyen-androidpay/build.gradle
index 543c82d892..5b2310332c 100644
--- a/adyen-androidpay/build.gradle
+++ b/adyen-androidpay/build.gradle
@@ -52,6 +52,6 @@ dependencies {
debugCompile project(path: ':adyen-core', configuration: 'debug')
releaseCompile project(path: ':adyen-core', configuration: 'release')
} else {
- compile project(':adyen-core')
+ provided group: 'com.adyen.checkout', name: 'core', version: "${rootProject.versionName}"
}
}
diff --git a/adyen-androidpay/src/androidTest/java/com/adyen/androidpay/ExampleInstrumentedTest.java b/adyen-androidpay/src/androidTest/java/com/adyen/androidpay/ExampleInstrumentedTest.java
deleted file mode 100644
index c045149368..0000000000
--- a/adyen-androidpay/src/androidTest/java/com/adyen/androidpay/ExampleInstrumentedTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.adyen.androidpay;
-
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static junit.framework.Assert.assertEquals;
-
-/**
- * Instrumentation test, which will execute on an Android device.
- *
- * @see Testing documentation
- */
-@RunWith(AndroidJUnit4.class)
-public class ExampleInstrumentedTest {
- @Test
- public void useAppContext() throws Exception {
- // Context of the app under test.
- Context appContext = InstrumentationRegistry.getTargetContext();
-
- assertEquals("com.adyen.androidpay.test", appContext.getPackageName());
- }
-}
diff --git a/adyen-androidpay/src/main/AndroidManifest.xml b/adyen-androidpay/src/main/AndroidManifest.xml
index 8b181e809b..fc399fac19 100644
--- a/adyen-androidpay/src/main/AndroidManifest.xml
+++ b/adyen-androidpay/src/main/AndroidManifest.xml
@@ -11,7 +11,8 @@
android:value="true" />
+ android:name=".ui.AndroidPayActivity"
+ android:theme="@style/AndroidPayActivity"/>
diff --git a/adyen-androidpay/src/main/java/com/adyen/androidpay/AndroidPayService.java b/adyen-androidpay/src/main/java/com/adyen/androidpay/AndroidPayService.java
index 3bb682c42e..cf37255e0e 100644
--- a/adyen-androidpay/src/main/java/com/adyen/androidpay/AndroidPayService.java
+++ b/adyen-androidpay/src/main/java/com/adyen/androidpay/AndroidPayService.java
@@ -96,6 +96,7 @@ public void process(@NonNull final Context context, @NonNull final PaymentReques
intent.putExtra("amount", paymentRequest.getAmount());
intent.putExtra("publicKey", paymentMethod.getConfiguration().getPublicKey());
intent.putExtra("merchantName", paymentMethod.getConfiguration().getMerchantName());
+ intent.putExtra("environment", paymentMethod.getConfiguration().getEnvironment());
context.startActivity(intent);
}
diff --git a/adyen-androidpay/src/main/java/com/adyen/androidpay/ui/AndroidPayActivity.java b/adyen-androidpay/src/main/java/com/adyen/androidpay/ui/AndroidPayActivity.java
index d41722f08f..755ec3a993 100644
--- a/adyen-androidpay/src/main/java/com/adyen/androidpay/ui/AndroidPayActivity.java
+++ b/adyen-androidpay/src/main/java/com/adyen/androidpay/ui/AndroidPayActivity.java
@@ -1,7 +1,10 @@
package com.adyen.androidpay.ui;
import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -33,6 +36,8 @@
import java.util.Locale;
import java.util.Map;
+import static com.adyen.core.constants.Constants.PaymentRequest.ADYEN_UI_FINALIZE_INTENT;
+
public class AndroidPayActivity extends FragmentActivity implements GoogleApiClient.OnConnectionFailedListener,
GoogleApiClient.ConnectionCallbacks {
@@ -51,6 +56,13 @@ public class AndroidPayActivity extends FragmentActivity implements GoogleApiCli
private String merchantName;
private String currency;
+ private BroadcastReceiver uiFinalizationIntent = new BroadcastReceiver() {
+ @Override
+ public void onReceive(final Context context, final Intent intent) {
+ finish();
+ }
+ };
+
@SuppressWarnings("unchecked")
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -69,12 +81,22 @@ protected void onCreate(Bundle savedInstanceState) {
googleApiClient = getGoogleApiClient();
- supportWalletFragment = createWalletFragment(WalletConstants.ENVIRONMENT_TEST,
+ int environment = WalletConstants.ENVIRONMENT_TEST;
+
+ if (intent.hasExtra("environment") && intent.getExtras().getString("environment") != null
+ && !intent.getExtras().getString("environment").isEmpty()) {
+ environment = Integer.parseInt(intent.getExtras().getString("environment"));
+ }
+
+ supportWalletFragment = createWalletFragment(environment,
WalletFragmentStyle.BuyButtonAppearance.ANDROID_PAY_DARK, WalletConstants.THEME_DARK);
// add Wallet fragment to the UI
getSupportFragmentManager().beginTransaction()
.replace(R.id.android_pay_fragment_container, supportWalletFragment)
.commit();
+
+ LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(uiFinalizationIntent,
+ new IntentFilter(ADYEN_UI_FINALIZE_INTENT));
}
@Override
diff --git a/adyen-androidpay/src/main/res/layout/activity_android_pay.xml b/adyen-androidpay/src/main/res/layout/activity_android_pay.xml
index aab93fae7a..68740b388b 100644
--- a/adyen-androidpay/src/main/res/layout/activity_android_pay.xml
+++ b/adyen-androidpay/src/main/res/layout/activity_android_pay.xml
@@ -1,12 +1,22 @@
-
+
-
+
-
\ No newline at end of file
+
+
+
+
\ No newline at end of file
diff --git a/adyen-androidpay/src/main/res/values/styles.xml b/adyen-androidpay/src/main/res/values/styles.xml
new file mode 100644
index 0000000000..c3aea8e4f0
--- /dev/null
+++ b/adyen-androidpay/src/main/res/values/styles.xml
@@ -0,0 +1,10 @@
+
+
+
+
\ No newline at end of file
diff --git a/adyen-core/build.gradle b/adyen-core/build.gradle
index 545ee857d9..ef9eebc97a 100644
--- a/adyen-core/build.gradle
+++ b/adyen-core/build.gradle
@@ -52,5 +52,5 @@ dependencies {
compile 'io.reactivex.rxjava2:rxjava:2.1.2'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
- compile 'com.adyen.cse:adyen-cse:1.0.3'
+ compile 'com.adyen.cse:adyen-cse:1.0.4'
}
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 1880da3af9..0839bd06cd 100644
--- a/adyen-core/src/main/java/com/adyen/core/DeviceTokenGenerator.java
+++ b/adyen-core/src/main/java/com/adyen/core/DeviceTokenGenerator.java
@@ -20,7 +20,7 @@ final class DeviceTokenGenerator {
private static final String TAG = DeviceTokenGenerator.class.getSimpleName();
- private static final String DEVICE_FINGER_PRINT_VERSION = "1.0";
+ private static final String DEVICE_FINGER_PRINT_VERSION = "1.1";
private static final String SDK_VERSION = BuildConfig.VERSION_NAME;
private DeviceTokenGenerator() {
@@ -31,7 +31,7 @@ private DeviceTokenGenerator() {
* Uses device and SDK information to create token.
* @return token
*/
- static String getToken(final Context context, final PaymentStateHandler paymentStateHandler) {
+ static String getToken(final Context context, final PaymentStateHandler paymentStateHandler, boolean isQuickIntegration) {
final JSONObject deviceInfo = new JSONObject();
try {
final String androidId = Settings.Secure.getString(context.getContentResolver(),
@@ -44,6 +44,8 @@ static String getToken(final Context context, final PaymentStateHandler paymentS
deviceInfo.put("deviceIdentifier", androidId);
deviceInfo.put("locale", StringUtils.getLocale(context));
+ deviceInfo.put("integration", (isQuickIntegration) ? "quick" : "custom");
+
} catch (final JSONException jsonException) {
Log.e(TAG, "Token could not be created", jsonException);
paymentStateHandler.setPaymentErrorThrowableAndTriggerError(jsonException);
diff --git a/adyen-core/src/main/java/com/adyen/core/PaymentStateHandler.java b/adyen-core/src/main/java/com/adyen/core/PaymentStateHandler.java
index 0aaf69182f..483dac690c 100644
--- a/adyen-core/src/main/java/com/adyen/core/PaymentStateHandler.java
+++ b/adyen-core/src/main/java/com/adyen/core/PaymentStateHandler.java
@@ -74,7 +74,7 @@ class PaymentStateHandler implements State.StateChangeListener {
private PaymentRequestResult paymentResult;
private PaymentRequest paymentRequest;
- private List filteredPaymentMethodsList;
+ private List availablePaymentMethods;
private List preferredPaymentMethods;
private PaymentProcessorStateMachine paymentProcessorStateMachine;
@@ -92,7 +92,7 @@ class PaymentStateHandler implements State.StateChangeListener {
this.merchantPaymentRequestDetailsListener = paymentRequestDetailsListener;
paymentBroadcastReceivers = new PaymentBroadcastReceivers(this, paymentRequest);
- filteredPaymentMethodsList = new ArrayList<>();
+ availablePaymentMethods = new ArrayList<>();
paymentProcessorStateMachine = new PaymentProcessorStateMachine(this);
paymentRequestListeners.add(paymentRequestListener);
@@ -184,7 +184,7 @@ public void onStateNotChanged(State state) {
private void requestPaymentData() {
Log.d(TAG, "requestPaymentData()");
- final String token = DeviceTokenGenerator.getToken(context, this);
+ final String token = DeviceTokenGenerator.getToken(context, this, sdkHandlesUI());
for (PaymentRequestListener listener : paymentRequestListeners) {
listener.onPaymentDataRequested(paymentRequest, token, paymentBroadcastReceivers.getPaymentDataCallback());
@@ -210,7 +210,7 @@ private void requestPaymentMethodSelection() {
for (PaymentRequestDetailsListener detailsListener : paymentRequestDetailsListeners) {
detailsListener.onPaymentMethodSelectionRequired(paymentRequest, preferredPaymentMethods,
- filteredPaymentMethodsList, paymentBroadcastReceivers.getPaymentMethodCallback());
+ availablePaymentMethods, paymentBroadcastReceivers.getPaymentMethodCallback());
}
final IntentFilter intentFilter = new IntentFilter(PAYMENT_METHOD_SELECTED_INTENT);
@@ -256,19 +256,25 @@ private void unregisterBroadcastReceivers() {
private void fetchPaymentMethods() {
if (paymentResponse != null) {
- List unfilteredPaymentMethods = paymentResponse.getAvailablePaymentMethods();
this.preferredPaymentMethods = paymentResponse.getPreferredPaymentMethods();
- Observable> listObservable = ModuleAvailabilityUtil.filterPaymentMethods(context,
- unfilteredPaymentMethods);
- listObservable.subscribe(new Consumer>() {
- @Override
- public void accept(List filteredPaymentMethods) {
- filteredPaymentMethods.removeAll(Collections.singleton(null));
- PaymentStateHandler.this.filteredPaymentMethodsList.clear();
- PaymentStateHandler.this.filteredPaymentMethodsList.addAll(filteredPaymentMethods);
- paymentProcessorStateMachine.onTrigger(PaymentTrigger.PAYMENT_METHODS_AVAILABLE);
- }
- });
+
+ if (merchantPaymentRequestDetailsListener == null) {
+ List unfilteredPaymentMethods = paymentResponse.getAvailablePaymentMethods();
+ Observable> listObservable = ModuleAvailabilityUtil.filterPaymentMethods(context,
+ unfilteredPaymentMethods);
+ listObservable.subscribe(new Consumer>() {
+ @Override
+ public void accept(List filteredPaymentMethods) {
+ filteredPaymentMethods.removeAll(Collections.singleton(null));
+ PaymentStateHandler.this.availablePaymentMethods.clear();
+ PaymentStateHandler.this.availablePaymentMethods.addAll(filteredPaymentMethods);
+ paymentProcessorStateMachine.onTrigger(PaymentTrigger.PAYMENT_METHODS_AVAILABLE);
+ }
+ });
+ } else {
+ this.availablePaymentMethods = paymentResponse.getAvailablePaymentMethods();
+ paymentProcessorStateMachine.onTrigger(PaymentTrigger.PAYMENT_METHODS_AVAILABLE);
+ }
}
}
@@ -503,7 +509,7 @@ public void onSuccess(byte[] response) {
for (PaymentRequestDetailsListener detailsListener : paymentRequestDetailsListeners) {
detailsListener.onPaymentMethodSelectionRequired(paymentRequest, preferredPaymentMethods,
- filteredPaymentMethodsList, paymentBroadcastReceivers.getPaymentMethodCallback());
+ availablePaymentMethods, paymentBroadcastReceivers.getPaymentMethodCallback());
}
return;
}
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 8eaefa91d7..77b0f6bffc 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
@@ -97,6 +97,7 @@ static PaymentMethod createPaymentMethod(final JSONObject paymentMethodJSON, fin
configuration.merchantId = configurationJson.optString("merchantIdentifier");
configuration.merchantName = configurationJson.optString("merchantName");
configuration.publicKey = configurationJson.optString("publicKey").replaceAll("\\r\\n", "");
+ configuration.environment = configurationJson.optString("environment");
}
if (paymentMethod.inputDetails != null) {
@@ -313,6 +314,7 @@ public static final class Configuration implements Serializable {
private String publicKey;
private String cvcOptional;
private String noCVC;
+ private String environment; //For AndroidPay
private Configuration() { }
@@ -335,6 +337,10 @@ public String getCvcOptional() {
public String getNoCVC() {
return noCVC;
}
+
+ public String getEnvironment() {
+ return environment;
+ }
}
@Override
diff --git a/adyen-core/src/main/java/com/adyen/core/utils/AsyncImageDownloader.java b/adyen-core/src/main/java/com/adyen/core/utils/AsyncImageDownloader.java
index 7436a42c10..55b780d7b0 100644
--- a/adyen-core/src/main/java/com/adyen/core/utils/AsyncImageDownloader.java
+++ b/adyen-core/src/main/java/com/adyen/core/utils/AsyncImageDownloader.java
@@ -10,16 +10,23 @@
import android.util.Log;
import android.widget.ImageView;
+import com.adyen.core.internals.TLSSocketFactory;
+
import java.io.FileNotFoundException;
-import java.io.InputStream;
+import java.net.URL;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSocketFactory;
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Observer;
+import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
-import io.reactivex.android.schedulers.AndroidSchedulers;
/**
* Utility class for downloading images and assigning them to ImageViews.
@@ -33,6 +40,16 @@ public final class AsyncImageDownloader {
@NonNull private static final LruCache BITMAP_LRU_CACHE
= new LruCache<>(MAX_NUMBER_OF_IMAGES_TO_BE_CACHED);
+ private static final SSLSocketFactory SSL_SOCKET_FACTORY;
+
+ static {
+ try {
+ SSL_SOCKET_FACTORY = new TLSSocketFactory();
+ } catch (KeyManagementException | NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
public interface ImageListener {
void onImage(Bitmap bitmap, String url);
}
@@ -162,7 +179,7 @@ private static Bitmap retrieveImage(Context context, String url, Bitmap fallback
/**
* This method issues an http request to retrieve the image at the given url.
- * If successfull, the image will be saved in the local cache (static variable) and
+ * If successful, the image will be saved in the local cache (static variable) and
* also in the sharedpreferences.
* @param context Application context
* @param url Url of the icon to be loaded
@@ -171,10 +188,14 @@ private static Bitmap retrieveImage(Context context, String url, Bitmap fallback
*/
private static Bitmap downloadImage(Context context, String url, Bitmap fallbackImage) {
Bitmap icon = null;
+ HttpsURLConnection urlConnection = null;
try {
Log.d(TAG, "Downloading image from: " + url);
- InputStream in = new java.net.URL(url).openStream();
- icon = BitmapFactory.decodeStream(in);
+ urlConnection = (HttpsURLConnection) new URL(url).openConnection();
+ urlConnection.setSSLSocketFactory(SSL_SOCKET_FACTORY);
+ urlConnection.connect();
+
+ icon = BitmapFactory.decodeStream(urlConnection.getInputStream());
BITMAP_LRU_CACHE.put(url, icon);
IconStorage.storeIcon(context, icon, url);
} catch (@NonNull final FileNotFoundException fileNotFoundException) {
@@ -190,6 +211,10 @@ private static Bitmap downloadImage(Context context, String url, Bitmap fallback
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
+ } finally {
+ if (urlConnection != null) {
+ urlConnection.disconnect();
+ }
}
return icon;
}
diff --git a/adyen-ui/src/androidTest/java/com/adyen/ui/ExampleInstrumentedTest.java b/adyen-ui/src/androidTest/java/com/adyen/ui/ExampleInstrumentedTest.java
deleted file mode 100644
index 0f49b9a2fc..0000000000
--- a/adyen-ui/src/androidTest/java/com/adyen/ui/ExampleInstrumentedTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.adyen.ui;
-
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Instrumentation test, which will execute on an Android device.
- *
- * @see Testing documentation
- */
-@RunWith(AndroidJUnit4.class)
-public class ExampleInstrumentedTest {
- @Test
- public void useAppContext() throws Exception {
- // Context of the app under test.
- Context appContext = InstrumentationRegistry.getTargetContext();
-
- assertEquals("com.adyen.ui.test", appContext.getPackageName());
- }
-}
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 36eae84c55..b77a5e76f5 100644
--- a/adyen-ui/src/main/java/com/adyen/ui/DefaultPaymentRequestDetailsListener.java
+++ b/adyen-ui/src/main/java/com/adyen/ui/DefaultPaymentRequestDetailsListener.java
@@ -11,6 +11,7 @@
import android.support.annotation.NonNull;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
+import android.widget.Toast;
import com.adyen.core.PaymentRequest;
import com.adyen.core.interfaces.PaymentDetailsCallback;
@@ -166,25 +167,23 @@ public void onPaymentDetailsRequired(@NonNull PaymentRequest paymentRequest,
intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
context.startActivity(intent);
} else if (paymentRequest.getPaymentMethod().getPaymentModule() != null) {
- PaymentMethodService paymentMethodService;
+ PaymentMethodService paymentMethodService = null;
try {
paymentMethodService = ModuleAvailabilityUtil.getModulePaymentService(
paymentRequest.getPaymentMethod().getPaymentModule());
} catch (@NonNull final ClassNotFoundException e) {
Log.e(TAG, "requestPaymentMethodDetails(): Payment module not found.", e);
- return;
} catch (@NonNull final IllegalAccessException e) {
Log.e(TAG, "requestPaymentMethodDetails(): IllegalAccessException occurred", e);
- return;
} catch (@NonNull final InstantiationException e) {
Log.e(TAG, "requestPaymentMethodDetails(): InstantiationException occurred", e);
- return;
} catch (@NonNull NullPointerException nullPointerException) {
Log.e(TAG, "requestPaymentMethodDetails(): Null pointer exception: ", nullPointerException);
- return;
}
- if (paymentMethodService != null) {
+ if (paymentMethodService == null) {
+ Toast.makeText(context, "Payment method not supported.", Toast.LENGTH_LONG).show();
+ } else {
// Pass the request to the correct module. The rest will be handled by the module.
paymentMethodService.process(context, paymentRequest, paymentRequest.getPaymentRequestListener(), null);
}
diff --git a/adyen-ui/src/main/java/com/adyen/ui/views/CVCEditText.java b/adyen-ui/src/main/java/com/adyen/ui/views/CVCEditText.java
index bb4a8c78d7..fa9ba27a9e 100644
--- a/adyen-ui/src/main/java/com/adyen/ui/views/CVCEditText.java
+++ b/adyen-ui/src/main/java/com/adyen/ui/views/CVCEditText.java
@@ -132,7 +132,8 @@ public void setMaxLength(final int newMaxLength) {
}
public boolean hasValidInput() {
- return (this.getText().toString().length() == maxLength) || optional;
+ int cvcLength = this.getText().toString().length();
+ return optional ? ((cvcLength == maxLength) || (cvcLength == 0)) : (cvcLength == maxLength);
}
public void setOptional(final boolean optional) {
diff --git a/adyen-ui/src/main/java/com/adyen/ui/views/ExpiryDateEditText.java b/adyen-ui/src/main/java/com/adyen/ui/views/ExpiryDateEditText.java
index d8784790f8..9d48d51b6c 100644
--- a/adyen-ui/src/main/java/com/adyen/ui/views/ExpiryDateEditText.java
+++ b/adyen-ui/src/main/java/com/adyen/ui/views/ExpiryDateEditText.java
@@ -106,9 +106,9 @@ public void afterTextChanged(Editable s) {
}
if (s.length() == 2 && !deleted) {
- if (s.toString().matches("\\d/")) {
+ if (s.toString().matches("\\d[^\\d]")) {
s.insert(0, "0");
- } else if (!s.toString().contains(separatorString)) {
+ } else if (!s.toString().matches("\\d*[^\\d]\\d*")) {
s.append(SEPARATOR_CHAR);
}
}
@@ -157,7 +157,7 @@ public void afterTextChanged(Editable s) {
}
private boolean isInputDateValid(String dateStr) {
- if (dateStr.length() == 5) {
+ if (dateStr.matches("(0?[1-9]|1[0-2])/[\\d]{2}")) {
Calendar c = Calendar.getInstance();
int currentYear = c.get(Calendar.YEAR) - 2000;
int currentMonth = c.get(Calendar.MONTH) + 1; //month january is 0
diff --git a/app/src/androidTest/java/com/adyen/checkout/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/adyen/checkout/ExampleInstrumentedTest.java
deleted file mode 100644
index 6c15ecf716..0000000000
--- a/app/src/androidTest/java/com/adyen/checkout/ExampleInstrumentedTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.adyen.checkout;
-
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Instrumentation test, which will execute on an Android device.
- *
- * @see Testing documentation
- */
-@RunWith(AndroidJUnit4.class)
-public class ExampleInstrumentedTest {
- @Test
- public void useAppContext() throws Exception {
- // Context of the app under test.
- Context appContext = InstrumentationRegistry.getTargetContext();
-
- assertEquals("com.adyen.checkout", appContext.getPackageName());
- }
-}
diff --git a/app/src/androidTest/java/com/adyen/checkout/PaymentAppTest.java b/app/src/androidTest/java/com/adyen/checkout/PaymentAppTest.java
index c6001c968e..2c051cea38 100644
--- a/app/src/androidTest/java/com/adyen/checkout/PaymentAppTest.java
+++ b/app/src/androidTest/java/com/adyen/checkout/PaymentAppTest.java
@@ -1,5 +1,7 @@
package com.adyen.checkout;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.support.test.espresso.Espresso;
import android.support.test.espresso.NoActivityResumedException;
import android.support.test.filters.LargeTest;
@@ -13,15 +15,18 @@
import com.adyen.testutils.RetryTest;
import org.junit.After;
+import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Calendar;
import java.util.Collection;
import java.util.Random;
import static android.support.test.InstrumentationRegistry.getInstrumentation;
+import static android.support.test.InstrumentationRegistry.getTargetContext;
import static android.support.test.espresso.Espresso.onData;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.clearText;
@@ -71,6 +76,14 @@ public void tearDown() throws Exception {
closeAllActivities(getInstrumentation());
}
+ @Before
+ public void setUp() throws Throwable {
+ UiDevice.getInstance(getInstrumentation()).wakeUp();
+ Intent intent = new Intent(getTargetContext(), MainActivity.class);
+ mainActivityRule.launchActivity(intent);
+ mainActivityRule.getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+ }
+
@Test
public void testRefusedVisaPayment() throws Exception {
checkCardPayment("13", "EUR", "Credit Card", "4444333322221111", "12/18", "722", Payment.PaymentStatus.REFUSED.toString());
@@ -145,6 +158,46 @@ public void testCardExpDate() throws Exception {
cancelCreditCardPayment();
}
+ @Test
+ public void testCardExpiryExtended() throws Exception {
+ goToCreditCardFragment();
+
+ checkCreditCardPayButtonIsEnabled(false);
+
+ onView(withId(R.id.adyen_credit_card_no)).perform(typeText("4111111111111111"));
+ onView(withId(R.id.adyen_credit_card_cvc)).perform(typeText("737"));
+
+ int startYear = Calendar.getInstance().get(Calendar.YEAR);
+ int startMonth = Calendar.getInstance().get(Calendar.MONTH) + 1;
+
+ int start = startYear * 12 + startMonth - 3;
+ int end = 2030 * 12;
+
+ for (int i = start; i <= end; i++) {
+ int month = i % 12;
+ if (month == 0) {
+ month = 12;
+ }
+ int year = i / 12 - 2000;
+
+ if (month > 9) {
+ String text = month + "" + year;
+ onView(withId(R.id.adyen_credit_card_exp_date)).perform(clearText(), typeText(text));
+ checkCreditCardPayButtonIsEnabled(true);
+ } else {
+ String text = "0" + month + year;
+ onView(withId(R.id.adyen_credit_card_exp_date)).perform(clearText(), typeText(text));
+ checkCreditCardPayButtonIsEnabled(true);
+
+ if (month > 1) {
+ text = month + "" + year;
+ onView(withId(R.id.adyen_credit_card_exp_date)).perform(clearText(), typeText(text));
+ checkCreditCardPayButtonIsEnabled(true);
+ }
+ }
+ }
+ }
+
@Test
public void testCVCField() throws Exception {
goToCreditCardFragment();
@@ -340,7 +393,7 @@ public void testNoCVC() throws Exception {
onView(withText(equalToIgnoringCase("Bancontact card"))).perform(scrollTo(), click());
onView(withId(R.id.adyen_credit_card_no)).perform(clearText(), typeText("6703444444444449"),
closeSoftKeyboard());
- onView(withId(R.id.adyen_credit_card_exp_date)).perform(typeText("818"),
+ onView(withId(R.id.adyen_credit_card_exp_date)).perform(clearText(), typeText("818"),
closeSoftKeyboard());
checkCreditCardPayButtonIsEnabled(true);
}
@@ -352,7 +405,16 @@ public void testOptionalCVC() throws Exception {
waitForText("CVC/CVV");
onView(withId(R.id.adyen_credit_card_no)).perform(clearText(), typeText("6731 0123 4567 8906"),
closeSoftKeyboard());
- onView(withId(R.id.adyen_credit_card_exp_date)).perform(typeText("818"),
+ onView(withId(R.id.adyen_credit_card_exp_date)).perform(clearText(), typeText("818"),
+ closeSoftKeyboard());
+ checkCreditCardPayButtonIsEnabled(true);
+ onView(withId(R.id.adyen_credit_card_cvc)).perform(clearText(), typeText("7"),
+ closeSoftKeyboard());
+ checkCreditCardPayButtonIsEnabled(false);
+ onView(withId(R.id.adyen_credit_card_cvc)).perform(clearText(), typeText("73"),
+ closeSoftKeyboard());
+ checkCreditCardPayButtonIsEnabled(false);
+ onView(withId(R.id.adyen_credit_card_cvc)).perform(clearText(), typeText("737"),
closeSoftKeyboard());
checkCreditCardPayButtonIsEnabled(true);
}
diff --git a/build.gradle b/build.gradle
index 06fb4f4e6d..f9df5500d7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,7 +3,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.3.1'
+ classpath 'com.android.tools.build:gradle:2.3.3'
}
}
@@ -30,8 +30,8 @@ ext {
minSdkVersion = 16
targetSdkVersion = 25
- versionCode = 12
- versionName = "1.10.0"
+ versionCode = 14
+ versionName = "1.11.1"
release_debuggable = false
release_minifyEnabled = false
@@ -55,7 +55,7 @@ jacoco {
subprojects {
- def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*', '**/checkout/**', '**/customuiapplication/**', '**/checkoutdemo/**', '**/customwithadyenui/**']
+ def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*', '**/checkout/**', '**/customuiapplication/**', '**/checkoutdemo/**', '**/customwithcheckoutui/**']
apply plugin: 'checkstyle'
checkstyle {
@@ -162,6 +162,15 @@ task jacocoOverallTestReport(type: JacocoReport, group: 'Coverage reports') {
getReports().getHtml().setDestination(file("$buildDir/reports/jacocoOverallTestReport/html"))
getReports().getXml().setDestination(file("$buildDir/reports/jacocoOverallTestReport/merged.xml"))
+
+ doLast {
+ publishedProjects.forEach { publishedProject ->
+ copy {
+ from "$publishedProject.buildDir/reports/"
+ into "$buildDir/reports/$publishedProject.name/"
+ }
+ }
+ }
}
task jacocoOverallUnitTestReport(type: JacocoReport, group: 'Coverage reports') {
@@ -259,7 +268,7 @@ task parseXml() {
}
def parsedProjectXml = (new XmlParser()).parse('api_configuration.xml')
def env = project.findProperty('serverEnv') ?: "TEST"
- def type = project.findProperty('serverType') ?: "MERCHANT_SERVER"
+ def type = project.findProperty('serverType') ?: "DIRECT_API"
def url = parsedProjectXml[type][env].URL.text()
def apiKey = parsedProjectXml[type][env].API_KEY.text()
diff --git a/checkoutdemo/build.gradle b/checkoutdemo/build.gradle
index 862f7cbce0..7c5c64ed27 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.10.0'
- compile 'com.adyen.checkout:ui:1.10.0'
- compile 'com.adyen.checkout:utils:1.10.0'
- compile 'com.adyen.checkout:cardscan:1.10.0'
+ compile 'com.adyen.checkout:core:1.11.0'
+ compile 'com.adyen.checkout:ui:1.11.0'
+ compile 'com.adyen.checkout:utils:1.11.0'
+ compile 'com.adyen.checkout:cardscan:1.11.0'
}
diff --git a/customuiapplication/src/androidTest/java/com/adyen/customuiapplication/ExampleInstrumentedTest.java b/customuiapplication/src/androidTest/java/com/adyen/customuiapplication/ExampleInstrumentedTest.java
deleted file mode 100644
index 56a6b37977..0000000000
--- a/customuiapplication/src/androidTest/java/com/adyen/customuiapplication/ExampleInstrumentedTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.adyen.customuiapplication;
-
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static junit.framework.Assert.assertEquals;
-
-/**
- * Instrumentation test, which will execute on an Android device.
- *
- * @see Testing documentation
- */
-@RunWith(AndroidJUnit4.class)
-public class ExampleInstrumentedTest {
- @Test
- public void useAppContext() throws Exception {
- // Context of the app under test.
- Context appContext = InstrumentationRegistry.getTargetContext();
-
- assertEquals("com.adyen.customuiapplication", appContext.getPackageName());
- }
-}
diff --git a/customuiapplication/src/androidTest/java/com/adyen/customuiapplication/PaymentAppTest.java b/customuiapplication/src/androidTest/java/com/adyen/customuiapplication/PaymentAppTest.java
index 8a6666f436..743759267d 100644
--- a/customuiapplication/src/androidTest/java/com/adyen/customuiapplication/PaymentAppTest.java
+++ b/customuiapplication/src/androidTest/java/com/adyen/customuiapplication/PaymentAppTest.java
@@ -4,6 +4,7 @@
import android.support.test.filters.LargeTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
+import android.support.test.uiautomator.UiDevice;
import com.adyen.core.models.Payment;
import com.adyen.core.models.PaymentMethod;
@@ -12,6 +13,7 @@
import org.hamcrest.Matcher;
import org.junit.After;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -51,6 +53,11 @@ public class PaymentAppTest {
@Rule
public RetryTest retry = new RetryTest(5);
+ @Before
+ public void setUp() throws Throwable {
+ UiDevice.getInstance(getInstrumentation()).wakeUp();
+ }
+
@After
public void tearDown() throws Exception {
closeAllActivities(getInstrumentation());
diff --git a/customwithcheckoutui/src/androidTest/java/com/example/customwithcheckoutui/ExampleInstrumentedTest.java b/customwithcheckoutui/src/androidTest/java/com/example/customwithcheckoutui/ExampleInstrumentedTest.java
deleted file mode 100644
index c7d231a0af..0000000000
--- a/customwithcheckoutui/src/androidTest/java/com/example/customwithcheckoutui/ExampleInstrumentedTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.example.customwithcheckoutui;
-
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Instrumentation test, which will execute on an Android device.
- *
- * @see Testing documentation
- */
-@RunWith(AndroidJUnit4.class)
-public class ExampleInstrumentedTest {
- @Test
- public void useAppContext() throws Exception {
- // Context of the app under test.
- Context appContext = InstrumentationRegistry.getTargetContext();
-
- assertEquals("com.example.customwithadyenui", appContext.getPackageName());
- }
-}
diff --git a/testutils/src/androidTest/java/com/adyen/testutils/ExampleInstrumentedTest.java b/testutils/src/androidTest/java/com/adyen/testutils/ExampleInstrumentedTest.java
deleted file mode 100644
index f35516068a..0000000000
--- a/testutils/src/androidTest/java/com/adyen/testutils/ExampleInstrumentedTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.adyen.testutils;
-
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import static junit.framework.Assert.assertEquals;
-
-/**
- * Instrumentation test, which will execute on an Android device.
- *
- * @see Testing documentation
- */
-@RunWith(AndroidJUnit4.class)
-public class ExampleInstrumentedTest {
- @Test
- public void useAppContext() throws Exception {
- // Context of the app under test.
- Context appContext = InstrumentationRegistry.getTargetContext();
-
- assertEquals("com.adyen.testutils.test", appContext.getPackageName());
- }
-}