Skip to content

Commit

Permalink
Add Cardinal UI Type and Render Type (#738)
Browse files Browse the repository at this point in the history
* Add setUiType to ThreeDSecureRequest
* Add setRenderType to ThreeDSecureRequest
* Set default parameters in Demo app
* Add unit tests

Co-authored-by: Sammy Cannillo <[email protected]>
  • Loading branch information
jaxdesmarais and scannillo authored May 22, 2023
1 parent 4f0f9f2 commit 1204898
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* Reverting native version upgrade
* ThreeDSecure
* Bump Cardinal version to `2.2.7-3`
* Add `setUiType` and `setRenderTypes` to `ThreeDSecureRequest`

## 4.28.0

Expand Down
12 changes: 12 additions & 0 deletions Demo/src/main/java/com/braintreepayments/demo/CardFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
import com.braintreepayments.cardform.view.CardForm;
import com.google.android.material.textfield.TextInputLayout;

import java.util.Arrays;

public class CardFragment extends BaseFragment implements OnCardFormSubmitListener, OnCardFormFieldFocusedListener, ThreeDSecureListener {

private static final String EXTRA_THREE_D_SECURE_REQUESTED = "com.braintreepayments.demo.EXTRA_THREE_D_SECURE_REQUESTED";
Expand Down Expand Up @@ -443,6 +445,16 @@ private ThreeDSecureRequest threeDSecureRequest(PaymentMethodNonce paymentMethod
threeDSecureRequest.setV2UiCustomization(v2UiCustomization);
threeDSecureRequest.setV1UiCustomization(v1UiCustomization);

threeDSecureRequest.setUiType(ThreeDSecureRequest.BOTH);

threeDSecureRequest.setRenderTypes(Arrays.asList(
ThreeDSecureRequest.OTP,
ThreeDSecureRequest.SINGLE_SELECT,
ThreeDSecureRequest.MULTI_SELECT,
ThreeDSecureRequest.OOB,
ThreeDSecureRequest.RENDER_HTML
));

return threeDSecureRequest;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@

import com.cardinalcommerce.cardinalmobilesdk.Cardinal;
import com.cardinalcommerce.cardinalmobilesdk.enums.CardinalEnvironment;
import com.cardinalcommerce.cardinalmobilesdk.enums.CardinalRenderType;
import com.cardinalcommerce.cardinalmobilesdk.enums.CardinalUiType;
import com.cardinalcommerce.cardinalmobilesdk.models.CardinalConfigurationParameters;
import com.cardinalcommerce.cardinalmobilesdk.models.ValidateResponse;
import com.cardinalcommerce.cardinalmobilesdk.services.CardinalInitService;
import com.cardinalcommerce.cardinalmobilesdk.services.CardinalValidateReceiver;

import org.json.JSONArray;

class CardinalClient {

private String consumerSessionId;
Expand Down Expand Up @@ -65,6 +69,36 @@ private void configureCardinal(Context context, Configuration configuration, Thr
cardinalConfigurationParameters.setEnvironment(cardinalEnvironment);
cardinalConfigurationParameters.setRequestTimeout(8000);
cardinalConfigurationParameters.setEnableDFSync(true);

switch (request.getUiType()) {
case ThreeDSecureRequest.NATIVE:
cardinalConfigurationParameters.setUiType(CardinalUiType.NATIVE);
case ThreeDSecureRequest.HTML:
cardinalConfigurationParameters.setUiType(CardinalUiType.HTML);
case ThreeDSecureRequest.BOTH:
cardinalConfigurationParameters.setUiType(CardinalUiType.BOTH);
}

if (request.getRenderTypes() != null) {
JSONArray renderTypes = new JSONArray();

for (Integer renderType : request.getRenderTypes()) {
if (renderType.equals(ThreeDSecureRequest.OTP)) {
renderTypes.put(CardinalRenderType.OTP);
} else if (renderType.equals(ThreeDSecureRequest.SINGLE_SELECT)) {
renderTypes.put(CardinalRenderType.SINGLE_SELECT);
} else if (renderType.equals(ThreeDSecureRequest.MULTI_SELECT)) {
renderTypes.put(CardinalRenderType.MULTI_SELECT);
} else if (renderType.equals(ThreeDSecureRequest.OOB)) {
renderTypes.put(CardinalRenderType.OOB);
} else if (renderType.equals(ThreeDSecureRequest.RENDER_HTML)) {
renderTypes.put(CardinalRenderType.HTML);
}
}

cardinalConfigurationParameters.setRenderType(renderTypes);
}

if (request.getV2UiCustomization() != null) {
cardinalConfigurationParameters.setUICustomization(request.getV2UiCustomization().getCardinalUiCustomization());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import android.os.Parcel;
import android.os.Parcelable;

import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.annotation.StringDef;

Expand All @@ -11,6 +12,7 @@

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;

/**
* A class to contain 3D Secure request information used for authentication
Expand All @@ -36,6 +38,22 @@ public class ThreeDSecureRequest implements Parcelable {
public static final String TRUSTED_BENEFICIARY = "trusted_beneficiary";
public static final String TRANSACTION_RISK_ANALYSIS = "transaction_risk_analysis";

@Retention(RetentionPolicy.SOURCE)
@IntDef({NATIVE, HTML, BOTH})
@interface ThreeDSecureUiType {}
public static final int NATIVE = 1;
public static final int HTML = 2;
public static final int BOTH = 3;

@Retention(RetentionPolicy.SOURCE)
@IntDef({OTP, SINGLE_SELECT, MULTI_SELECT, OOB, RENDER_HTML})
@interface ThreeDSecureRenderType {}
public static final int OTP = 1;
public static final int SINGLE_SELECT = 2;
public static final int MULTI_SELECT = 3;
public static final int OOB = 4;
public static final int RENDER_HTML = 5;

private String nonce;
private String amount;
private String mobilePhoneNumber;
Expand All @@ -52,6 +70,8 @@ public class ThreeDSecureRequest implements Parcelable {
private Boolean cardAddChallengeRequested;
private ThreeDSecureV2UiCustomization v2UiCustomization;
private ThreeDSecureV1UiCustomization v1UiCustomization;
private @ThreeDSecureUiType int uiType;
private List<Integer> renderTypes;

/**
* Set the nonce
Expand Down Expand Up @@ -217,6 +237,35 @@ public void setV1UiCustomization(@Nullable ThreeDSecureV1UiCustomization v1UiCus
this.v1UiCustomization = v1UiCustomization;
}

/**
* Optional. Sets all UI types that the device supports for displaying specific challenge user interfaces in the 3D Secure challenge.
* Possible Values:
* 01 BOTH
* 02 Native
* 03 HTML
*
* Defaults to BOTH
*
* @param uiType {@link ThreeDSecureUiType} The UI type to request.
*/
public void setUiType(@ThreeDSecureUiType int uiType) {
this.uiType = uiType;
}

/**
* Optional. List of all the render types that the device supports for displaying specific challenge user interfaces within the 3D Secure challenge.
*
* When using `ThreeDSecureUIType.BOTH` or `ThreeDSecureUIType.HTML`, all `ThreeDSecureRenderType` options must be set.
* When using `ThreeDSecureUIType.NATIVE`, all `ThreeDSecureRenderType` options except `ThreeDSecureRenderType.RENDER_HTML` must be set.
*
* Defaults to OTP, OOB, SINGLE_SELECT, MULTI_SELECT, RENDER_HTML
*
* @param renderType specifies what render type to use in the 3D Secure challenge
*/
public void setRenderTypes(List<Integer> renderTypes) {
this.renderTypes = renderTypes;
}

/**
* @return The nonce to use for 3D Secure verification
*/
Expand Down Expand Up @@ -341,6 +390,20 @@ public ThreeDSecureV1UiCustomization getV1UiCustomization() {
return v1UiCustomization;
}

/**
* @return The UI type.
*/
public @ThreeDSecureUiType int getUiType() {
return uiType;
}

/**
* @return The render type.
*/
public List<Integer> getRenderTypes() {
return renderTypes;
}

public ThreeDSecureRequest() {}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

import com.cardinalcommerce.cardinalmobilesdk.Cardinal;
import com.cardinalcommerce.cardinalmobilesdk.enums.CardinalEnvironment;
import com.cardinalcommerce.cardinalmobilesdk.enums.CardinalRenderType;
import com.cardinalcommerce.cardinalmobilesdk.enums.CardinalUiType;
import com.cardinalcommerce.cardinalmobilesdk.models.CardinalConfigurationParameters;
import com.cardinalcommerce.cardinalmobilesdk.services.CardinalInitService;
import com.cardinalcommerce.cardinalmobilesdk.services.CardinalValidateReceiver;
Expand All @@ -33,6 +35,8 @@
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import java.util.ArrayList;

@RunWith(PowerMockRunner.class)
@PrepareForTest({Cardinal.class})
public class CardinalClientUnitTest {
Expand Down Expand Up @@ -110,6 +114,46 @@ public void initialize_whenEnvironmentProduction_configuresCardinalEnvironmentPr
assertEquals(CardinalEnvironment.PRODUCTION, parameters.getEnvironment());
}

@Test
public void initialize_whenUiTypeNotNull_setsCardinalConfigurationParameters() throws BraintreeException {
when(Cardinal.getInstance()).thenReturn(cardinalInstance);
CardinalClient sut = new CardinalClient();

ThreeDSecureRequest request = new ThreeDSecureRequest();
request.setUiType(ThreeDSecureRequest.BOTH);
sut.initialize(context, configuration, request, cardinalInitializeCallback);

ArgumentCaptor<CardinalConfigurationParameters> captor = ArgumentCaptor.forClass(CardinalConfigurationParameters.class);
verify(cardinalInstance).configure(same(context), captor.capture());

CardinalConfigurationParameters parameters = captor.getValue();
assertEquals(CardinalUiType.BOTH, parameters.getUiType());
}

@Test
public void initialize_whenRenderTypeNotNull_setsCardinalConfigurationParameters() throws BraintreeException {
when(Cardinal.getInstance()).thenReturn(cardinalInstance);
CardinalClient sut = new CardinalClient();

ArrayList renderTypes = new ArrayList<>();
renderTypes.add(ThreeDSecureRequest.OTP);
renderTypes.add(ThreeDSecureRequest.SINGLE_SELECT);
renderTypes.add(ThreeDSecureRequest.MULTI_SELECT);
renderTypes.add(ThreeDSecureRequest.OOB);
renderTypes.add(ThreeDSecureRequest.RENDER_HTML);

ThreeDSecureRequest request = new ThreeDSecureRequest();
request.setRenderTypes(renderTypes);

sut.initialize(context, configuration, request, cardinalInitializeCallback);

ArgumentCaptor<CardinalConfigurationParameters> captor = ArgumentCaptor.forClass(CardinalConfigurationParameters.class);
verify(cardinalInstance).configure(same(context), captor.capture());

CardinalConfigurationParameters parameters = captor.getValue();
assertEquals(5, parameters.getRenderType().length());
}

@Test
public void initialize_returnsConsumerSessionIdToListener() throws BraintreeException {
when(Cardinal.getInstance()).thenReturn(cardinalInstance);
Expand Down

0 comments on commit 1204898

Please sign in to comment.