Skip to content

Commit

Permalink
3.0.0-rc02
Browse files Browse the repository at this point in the history
  • Loading branch information
adyen-git-manager committed Jul 9, 2019
1 parent 89954b4 commit 9b1c4e2
Show file tree
Hide file tree
Showing 60 changed files with 401 additions and 328 deletions.
5 changes: 0 additions & 5 deletions 3ds2/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,6 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

dependencies {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,17 @@
import com.adyen.checkout.adyen3ds2.model.ChallengeToken;
import com.adyen.checkout.adyen3ds2.model.FingerprintToken;
import com.adyen.checkout.base.ActionComponentData;
import com.adyen.checkout.base.DetailsComponentProvider;
import com.adyen.checkout.base.ComponentError;
import com.adyen.checkout.base.ActionComponentProvider;
import com.adyen.checkout.base.component.ActionComponentProviderImpl;
import com.adyen.checkout.base.component.BaseActionComponent;
import com.adyen.checkout.base.component.DetailsComponentProviderImpl;
import com.adyen.checkout.base.encoding.Base64Encoder;
import com.adyen.checkout.base.model.payments.response.Action;
import com.adyen.checkout.base.model.payments.response.Threeds2ChallengeAction;
import com.adyen.checkout.base.model.payments.response.Threeds2FingerprintAction;
import com.adyen.checkout.core.api.ThreadManager;
import com.adyen.checkout.core.code.Lint;
import com.adyen.checkout.core.exeption.CheckoutException;
import com.adyen.checkout.core.exeption.ComponentException;
import com.adyen.checkout.core.log.LogUtil;
import com.adyen.checkout.core.log.Logger;
import com.adyen.checkout.core.util.StringUtil;
Expand All @@ -52,24 +54,24 @@
import java.util.List;

public final class Adyen3DS2Component extends BaseActionComponent implements ChallengeStatusReceiver {
private static final String TAG = LogUtil.getTag();
@SuppressWarnings(Lint.SYNTHETIC)
static final String TAG = LogUtil.getTag();

public static final DetailsComponentProvider<Adyen3DS2Component> PROVIDER = new DetailsComponentProviderImpl<>(Adyen3DS2Component.class);
public static final ActionComponentProvider<Adyen3DS2Component> PROVIDER = new ActionComponentProviderImpl<>(Adyen3DS2Component.class);

private static final String FINGERPRINT_DETAILS_KEY = "threeds2.fingerprint";
private static final String CHALLENGE_DETAILS_KEY = "threeds2.challengeResult";

private static final int DEFAULT_CHALLENGE_TIME_OUT = 10;
private static boolean sGotDestroyedWhileChallenging = false;

private Transaction mTransaction;
@SuppressWarnings(Lint.SYNTHETIC)
Transaction mTransaction;

public Adyen3DS2Component(@NonNull Application application) {
super(application);
}

//TODO review error flows

@Override
protected void onCleared() {
super.onCleared();
Expand Down Expand Up @@ -98,25 +100,19 @@ protected List<String> getSupportedActionTypes() {
}

@Override
public void handleActionInternal(@NonNull Activity activity, @NonNull Action action) {
protected void handleActionInternal(@NonNull Activity activity, @NonNull Action action) throws ComponentException {
if (Threeds2FingerprintAction.ACTION_TYPE.equals(action.getType())) {
final Threeds2FingerprintAction fingerprintAction = (Threeds2FingerprintAction) action;
if (!StringUtil.hasContent(fingerprintAction.getToken())) {
notifyError(new ComponentError("Fingerprint token not found."));
return;
}
final String encodedFingerprint = identifyShopper(activity, fingerprintAction.getToken());
try {
notifyDetails(createFingerprintDetails(encodedFingerprint));
} catch (JSONException e) {
Logger.e(TAG, "Failed to create fingerprint.", e);
notifyError(new ComponentError("Failed to create fingerprint."));
throw new ComponentException("Fingerprint token not found.");
}

identifyShopper(activity, fingerprintAction.getToken());

} else if (Threeds2ChallengeAction.ACTION_TYPE.equals(action.getType())) {
final Threeds2ChallengeAction challengeAction = (Threeds2ChallengeAction) action;
if (!StringUtil.hasContent(challengeAction.getToken())) {
notifyError(new ComponentError("Challenge token not found."));
return;
throw new ComponentException("Challenge token not found.");
}
challengeShopper(activity, challengeAction.getToken());
}
Expand All @@ -126,72 +122,98 @@ public void handleActionInternal(@NonNull Activity activity, @NonNull Action act
public void completed(@NonNull CompletionEvent completionEvent) {
Logger.d(TAG, "challenge completed");
try {
final ChallengeResult result = ChallengeResult.from(completionEvent);
notifyDetails(createChallengeDetails(result));
notifyDetails(createChallengeDetails(completionEvent));
} catch (CheckoutException e) {
notifyException(e);
} finally {
closeTransaction(getApplication());
} catch (JSONException e) {
throw new CheckoutException("Failed to parse challenge result.", e);
}
}

@Override
public void cancelled() {
Logger.d(TAG, "challenge cancelled");
notifyException(new Authentication3DS2Exception("Challenge canceled."));
closeTransaction(getApplication());
}

@Override
public void timedout() {
Logger.d(TAG, "challenge timedout");
Logger.d(TAG, "challenge timed out");
notifyException(new Authentication3DS2Exception("Challenge timed out."));
closeTransaction(getApplication());
}

@Override
public void protocolError(@NonNull ProtocolErrorEvent protocolErrorEvent) {
Logger.d(TAG, "protocolError");
notifyException(new Authentication3DS2Exception("Protocol Error - " + protocolErrorEvent.getErrorMessage()));
closeTransaction(getApplication());
}

@Override
public void runtimeError(@NonNull RuntimeErrorEvent runtimeErrorEvent) {
Logger.d(TAG, "runtimeError");
notifyException(new Authentication3DS2Exception("Runtime Error - " + runtimeErrorEvent.getErrorMessage()));
closeTransaction(getApplication());
}

private String identifyShopper(Context context, String encodedFingerprintToken) {
private void identifyShopper(final Context context, final String encodedFingerprintToken) throws ComponentException {
Logger.d(TAG, "identifyShopper");
final String decodedFingerprintToken = Base64Encoder.decode(encodedFingerprintToken);

final JSONObject fingerprintJson;
try {
fingerprintJson = new JSONObject(decodedFingerprintToken);
} catch (JSONException e) {
throw new CheckoutException("JSON parsing of FingerprintToken failed", e);
throw new ComponentException("JSON parsing of FingerprintToken failed", e);
}

final FingerprintToken fingerprintToken = FingerprintToken.SERIALIZER.deserialize(fingerprintJson);
final ConfigParameters configParameters = new AdyenConfigParameters.Builder(fingerprintToken.getDirectoryServerId(),
fingerprintToken.getDirectoryServerPublicKey()).build();

try {
ThreeDS2Service.INSTANCE.initialize(context, configParameters, null, null);
} catch (SDKAlreadyInitializedException e) {
// This shouldn't cause any side effect.
Logger.e(TAG, "3DS2 Service already initialized.");
}

try {
mTransaction = ThreeDS2Service.INSTANCE.createTransaction(null, null);
} catch (SDKNotInitializedException e) {
throw new CheckoutException("Failed to create transaction", e);
}

final AuthenticationRequestParameters authenticationRequestParameters = mTransaction.getAuthenticationRequestParameters();

return createEncodedFingerprint(authenticationRequestParameters);
ThreadManager.EXECUTOR.submit(new Runnable() {
@Override
public void run() {
try {
Logger.d(TAG, "initialize 3DS2 SDK");
ThreeDS2Service.INSTANCE.initialize(context, configParameters, null, null);
} catch (SDKAlreadyInitializedException e) {
// This shouldn't cause any side effect.
Logger.w(TAG, "3DS2 Service already initialized.");
}

try {
Logger.d(TAG, "create transaction");
mTransaction = ThreeDS2Service.INSTANCE.createTransaction(null, null);
} catch (final SDKNotInitializedException e) {
ThreadManager.MAIN_HANDLER.post(new Runnable() {
@Override
public void run() {
notifyException(new ComponentException("Failed to create transaction", e));
}
}
);
}

final AuthenticationRequestParameters authenticationRequestParameters = mTransaction.getAuthenticationRequestParameters();

final String encodedFingerprint = createEncodedFingerprint(authenticationRequestParameters);

ThreadManager.MAIN_HANDLER.post(new Runnable() {
@Override
public void run() {
notifyDetails(createFingerprintDetails(encodedFingerprint));
}
}
);
}
});
}

private void challengeShopper(Activity activity, String encodedChallengeToken) {
private void challengeShopper(Activity activity, String encodedChallengeToken) throws ComponentException {
Logger.d(TAG, "challengeShopper");

final String decodedChallengeToken = Base64Encoder.decode(encodedChallengeToken);
Expand All @@ -200,7 +222,7 @@ private void challengeShopper(Activity activity, String encodedChallengeToken) {
try {
challengeTokenJson = new JSONObject(decodedChallengeToken);
} catch (JSONException e) {
throw new CheckoutException("JSON parsing of FingerprintToken failed", e);
throw new ComponentException("JSON parsing of FingerprintToken failed", e);
}

final ChallengeToken challengeToken = ChallengeToken.SERIALIZER.deserialize(challengeTokenJson);
Expand All @@ -210,7 +232,8 @@ private void challengeShopper(Activity activity, String encodedChallengeToken) {
}

@NonNull
private String createEncodedFingerprint(AuthenticationRequestParameters authenticationRequestParameters) {
@SuppressWarnings(Lint.SYNTHETIC)
String createEncodedFingerprint(AuthenticationRequestParameters authenticationRequestParameters) throws ComponentException {

final JSONObject fingerprintJson = new JSONObject();
try {
Expand All @@ -221,7 +244,7 @@ private String createEncodedFingerprint(AuthenticationRequestParameters authenti
fingerprintJson.put("sdkReferenceNumber", authenticationRequestParameters.getSDKReferenceNumber());
fingerprintJson.put("sdkTransID", authenticationRequestParameters.getSDKTransactionID());
} catch (JSONException e) {
throw new CheckoutException("Failed to create fingerprintJson", e);
throw new ComponentException("Failed to create encoded fingerprint", e);
}

return Base64Encoder.encode(fingerprintJson.toString());
Expand Down Expand Up @@ -251,15 +274,25 @@ private void closeTransaction(Context context) {
}
}

private JSONObject createFingerprintDetails(String encodedFingerprint) throws JSONException {
@SuppressWarnings(Lint.SYNTHETIC)
JSONObject createFingerprintDetails(String encodedFingerprint) throws ComponentException {
final JSONObject fingerprintDetails = new JSONObject();
fingerprintDetails.put(FINGERPRINT_DETAILS_KEY, encodedFingerprint);
try {
fingerprintDetails.put(FINGERPRINT_DETAILS_KEY, encodedFingerprint);
} catch (JSONException e) {
throw new ComponentException("Failed to create fingerprint details", e);
}
return fingerprintDetails;
}

private JSONObject createChallengeDetails(ChallengeResult challengeResult) throws JSONException {
private JSONObject createChallengeDetails(@NonNull CompletionEvent completionEvent) throws ComponentException {
final JSONObject challengeDetails = new JSONObject();
challengeDetails.put(CHALLENGE_DETAILS_KEY, challengeResult.getPayload());
try {
final ChallengeResult challengeResult = ChallengeResult.from(completionEvent);
challengeDetails.put(CHALLENGE_DETAILS_KEY, challengeResult.getPayload());
} catch (JSONException e) {
throw new ComponentException("Failed to create challenge details", e);
}
return challengeDetails;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2019 Adyen N.V.
*
* This file is open source and available under the MIT license. See the LICENSE file for more info.
*
* Created by caiof on 3/7/2019.
*/

package com.adyen.checkout.adyen3ds2;

import android.support.annotation.NonNull;

import com.adyen.checkout.core.exeption.ComponentException;

/**
* This exception is just an indication that the 3DS2 Authentication did not finish as expected.
* Can be caused by an actual error or by user cancellation.
*/
public class Authentication3DS2Exception extends ComponentException {

private static final long serialVersionUID = 7142998120028361912L;

public Authentication3DS2Exception(@NonNull String errorMessage) {
super(errorMessage);
}
}
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ The Components are available through [jcenter][dl], you only need to add the Gra
Import the Component module for the Payment Method you want to use by adding it to your `build.gradle` file.
For example, for the Drop-in solution you should add:
```groovy
implementation "com.adyen.checkout:drop-in:3.0.0-rc01"
implementation "com.adyen.checkout:drop-in:3.0.0-rc02"
```
For a Credit Card component you should add:
```groovy
implementation "com.adyen.checkout:card-ui:3.0.0-rc01"
implementation "com.adyen.checkout:card-ui:3.0.0-rc02"
```
For and iDeal component you should add:
```groovy
implementation "com.adyen.checkout:ideal-ui:3.0.0-rc01"
implementation "com.adyen.checkout:ideal-ui:3.0.0-rc02"
```

## Drop-in
Expand Down Expand Up @@ -140,7 +140,7 @@ You can also find the components that can handle the `action` object.

This repository is open source and available under the MIT license. For more information, see the LICENSE file.

[dl]: https://bintray.com/checkout/checkout-v3
[dl]: https://jcenter.bintray.com/com/adyen/checkout/
[apiExplorer.paymentMethods]: https://docs.adyen.com/api-explorer/#/PaymentSetupAndVerificationService/v46/paymentMethods
[apiExplorer.payments]: https://docs.adyen.com/api-explorer/#/PaymentSetupAndVerificationService/v46/payments
[apiExplorer.paymentsDetails]: https://docs.adyen.com/api-explorer/#/PaymentSetupAndVerificationService/v46/paymentsDetails
2 changes: 1 addition & 1 deletion README_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ You can also find the components that can handle the `action` object.

This repository is open source and available under the MIT license. For more information, see the LICENSE file.

[dl]: https://bintray.com/checkout/checkout-v3
[dl]: https://jcenter.bintray.com/com/adyen/checkout/
[apiExplorer.paymentMethods]: https://docs.adyen.com/api-explorer/#/PaymentSetupAndVerificationService/v46/paymentMethods
[apiExplorer.payments]: https://docs.adyen.com/api-explorer/#/PaymentSetupAndVerificationService/v46/payments
[apiExplorer.paymentsDetails]: https://docs.adyen.com/api-explorer/#/PaymentSetupAndVerificationService/v46/paymentsDetails
4 changes: 3 additions & 1 deletion RELEASE_NOTES
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<ul>
<li>Release 3.0.0-rc01</li>
<li>Improve error handling, notify to observer.</li>
<li>3DS2 error flows go to observer.</li>
<li>Bug fixes.</li>
</ul>
5 changes: 0 additions & 5 deletions base-ui/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,6 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

dependencies {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,26 @@
import android.support.annotation.CallSuper;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.View;

import com.adyen.checkout.core.log.LogUtil;
import com.adyen.checkout.core.log.Logger;

public abstract class ClickableListRecyclerAdapter<ViewHolderT extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<ViewHolderT> {
private static final String TAG = LogUtil.getTag();
static final String TAG = LogUtil.getTag();

OnItemCLickedListener mOnItemCLickedListener;

@CallSuper
@Override
public void onBindViewHolder(@NonNull ViewHolderT viewHolderT, int position) {
viewHolderT.itemView.setOnClickListener(v -> {
Logger.d(TAG, "click");
if (mOnItemCLickedListener != null) {
mOnItemCLickedListener.onItemClicked(viewHolderT.getAdapterPosition());
public void onBindViewHolder(@NonNull final ViewHolderT viewHolderT, int position) {
viewHolderT.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Logger.d(TAG, "click");
if (mOnItemCLickedListener != null) {
mOnItemCLickedListener.onItemClicked(viewHolderT.getAdapterPosition());
}
}
});
}
Expand Down
Loading

0 comments on commit 9b1c4e2

Please sign in to comment.