@Override public void success(PaymentMethodNonce paymentMethodNonce) { performVerification(fragment, paymentMethodNonce.getNonce(), amount); }
/** * Verification is associated with a transaction amount and your merchant account. To specify a * different merchant account (or, in turn, currency), you will need to specify the merchant * account id when <a href="https://developers.braintreepayments.com/android/sdk/overview/generate-client-token"> * generating a client token</a> * * During lookup the original payment method nonce is consumed and a new one is returned, * which points to the original payment method, as well as the 3D Secure verification. * Transactions created with this nonce will be 3D Secure, and benefit from the appropriate * liability shift if authentication is successful or fail with a 3D Secure failure. * * @param fragment the {@link BraintreeFragment} backing the http request. This fragment will * also be responsible for handling callbacks to it's listeners * @param nonce The nonce that represents a card to perform a 3D Secure verification against. * @param amount The amount of the transaction in the current merchant account's currency. */ public static void performVerification(final BraintreeFragment fragment, final String nonce, final String amount) { ThreeDSecureRequest request = new ThreeDSecureRequest() .nonce(nonce) .amount(amount); performVerification(fragment, request); }
@Override public void onPaymentMethodNonceCreated(PaymentMethodNonce paymentMethodNonce) { super.onPaymentMethodNonceCreated(paymentMethodNonce); if (!mThreeDSecureRequested && paymentMethodNonce instanceof CardNonce && Settings.isThreeDSecureEnabled(this)) { mThreeDSecureRequested = true; mLoading = ProgressDialog.show(this, getString(R.string.loading), getString(R.string.loading), true, false); ThreeDSecure.performVerification(mBraintreeFragment, paymentMethodNonce.getNonce(), "1"); } else if (paymentMethodNonce instanceof CardNonce && Settings.isAmexRewardsBalanceEnabled(this)) { mLoading = ProgressDialog.show(this, getString(R.string.loading), getString(R.string.loading), true, false); AmericanExpress.getRewardsBalance(mBraintreeFragment, paymentMethodNonce.getNonce(), "USD"); } else { Intent intent = new Intent() .putExtra(MainActivity.EXTRA_PAYMENT_RESULT, paymentMethodNonce) .putExtra(MainActivity.EXTRA_DEVICE_DATA, mDeviceData); setResult(RESULT_OK, intent); finish(); } }
@Test public void performVerification_sendsMinimumParamatersInLookupRequest() throws InterruptedException, JSONException { ThreeDSecureRequest request = new ThreeDSecureRequest() .nonce("a-nonce") .amount("1.00"); ThreeDSecure.performVerification(mFragment, request); ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class); verify(mFragment.getHttpClient()).post(anyString(), captor.capture(), any(HttpResponseCallback.class)); JSONObject body = new JSONObject(captor.getValue()); assertEquals("1.00", body.getString("amount")); JSONObject customer = body.getJSONObject("customer"); assertTrue(customer.isNull("mobilePhoneNumber")); assertTrue(customer.isNull("email")); assertTrue(customer.isNull("shippingMethod")); assertTrue(customer.isNull("billingAddress")); }
@Test(timeout = 10000) public void performVerification_doesALookupAndReturnsACardAndANullACSUrlWhenAuthenticationIsNotRequired() throws InterruptedException { BraintreeFragment fragment = getFragment(); fragment.addListener(new PaymentMethodNonceCreatedListener() { @Override public void onPaymentMethodNonceCreated(PaymentMethodNonce paymentMethodNonce) { assertIsANonce(paymentMethodNonce.getNonce()); CardNonce cardNonce = (CardNonce) paymentMethodNonce; assertEquals("51", cardNonce.getLastTwo()); assertFalse(cardNonce.getThreeDSecureInfo().isLiabilityShifted()); assertFalse(cardNonce.getThreeDSecureInfo().isLiabilityShiftPossible()); assertTrue(((CardNonce) paymentMethodNonce).getThreeDSecureInfo().wasVerified()); mCountDownLatch.countDown(); } }); CardBuilder cardBuilder = new CardBuilder() .cardNumber(THREE_D_SECURE_VERIFICATON_NOT_REQUIRED) .expirationDate("12/20"); ThreeDSecure.performVerification(fragment, cardBuilder, TEST_AMOUNT); mCountDownLatch.await(); }
@Test(timeout = 30000) public void performVerification_doesALookupAndReturnsACardAfterATimeout() throws InterruptedException { BraintreeFragment fragment = getFragment(); fragment.addListener(new PaymentMethodNonceCreatedListener() { @Override public void onPaymentMethodNonceCreated(PaymentMethodNonce paymentMethodNonce) { assertIsANonce(paymentMethodNonce.getNonce()); CardNonce cardNonce = (CardNonce) paymentMethodNonce; assertEquals("44", cardNonce.getLastTwo()); assertFalse(cardNonce.getThreeDSecureInfo().isLiabilityShifted()); assertFalse(cardNonce.getThreeDSecureInfo().isLiabilityShiftPossible()); assertTrue(((CardNonce) paymentMethodNonce).getThreeDSecureInfo().wasVerified()); mCountDownLatch.countDown(); } }); CardBuilder cardBuilder = new CardBuilder() .cardNumber(THREE_D_SECURE_LOOKUP_TIMEOUT) .expirationDate("12/20"); ThreeDSecure.performVerification(fragment, cardBuilder, TEST_AMOUNT); mCountDownLatch.await(); }
@Test(timeout = 10000) public void performVerification_doesALookupAndReturnsACardWhenThereIsAMPILookupError() throws InterruptedException { BraintreeFragment fragment = getFragment(); fragment.addListener(new PaymentMethodNonceCreatedListener() { @Override public void onPaymentMethodNonceCreated(PaymentMethodNonce paymentMethodNonce) { assertIsANonce(paymentMethodNonce.getNonce()); CardNonce cardNonce = (CardNonce) paymentMethodNonce; assertEquals("85", cardNonce.getLastTwo()); assertFalse(cardNonce.getThreeDSecureInfo().isLiabilityShifted()); assertFalse(cardNonce.getThreeDSecureInfo().isLiabilityShiftPossible()); assertTrue(((CardNonce) paymentMethodNonce).getThreeDSecureInfo().wasVerified()); mCountDownLatch.countDown(); } }); CardBuilder cardBuilder = new CardBuilder() .cardNumber(THREE_D_SECURE_MPI_LOOKUP_ERROR) .expirationDate("12/20"); ThreeDSecure.performVerification(fragment, cardBuilder, TEST_AMOUNT); mCountDownLatch.await(); }
@Test(timeout = 10000) public void performVerification_doesALookupAndReturnsACardWhenThereIsALookupError() throws InterruptedException { BraintreeFragment fragment = getFragment(); fragment.addListener(new PaymentMethodNonceCreatedListener() { @Override public void onPaymentMethodNonceCreated(PaymentMethodNonce paymentMethodNonce) { assertIsANonce(paymentMethodNonce.getNonce()); CardNonce cardNonce = (CardNonce) paymentMethodNonce; assertEquals("77", cardNonce.getLastTwo()); assertFalse(cardNonce.getThreeDSecureInfo().isLiabilityShifted()); assertFalse(cardNonce.getThreeDSecureInfo().isLiabilityShiftPossible()); assertTrue(((CardNonce) paymentMethodNonce).getThreeDSecureInfo().wasVerified()); mCountDownLatch.countDown(); } }); CardBuilder cardBuilder = new CardBuilder() .cardNumber(THREE_D_SECURE_LOOKUP_ERROR) .expirationDate("12/20"); ThreeDSecure.performVerification(fragment, cardBuilder, TEST_AMOUNT); mCountDownLatch.await(); }
@Test(timeout = 30000) public void performVerification_returnsASuccessfulAuthenticationWhenIssuerDoesNotParticipate() throws InterruptedException { BraintreeFragment fragment = getFragment(); fragment.addListener(new PaymentMethodNonceCreatedListener() { @Override public void onPaymentMethodNonceCreated(PaymentMethodNonce paymentMethodNonce) { assertIsANonce(paymentMethodNonce.getNonce()); CardNonce cardNonce = (CardNonce) paymentMethodNonce; assertEquals("01", cardNonce.getLastTwo()); assertTrue(cardNonce.getThreeDSecureInfo().isLiabilityShifted()); assertTrue(cardNonce.getThreeDSecureInfo().isLiabilityShiftPossible()); assertTrue(((CardNonce) paymentMethodNonce).getThreeDSecureInfo().wasVerified()); mCountDownLatch.countDown(); } }); CardBuilder cardBuilder = new CardBuilder() .cardNumber(THREE_D_SECURE_ISSUER_DOES_NOT_PARTICIPATE) .expirationDate("12/30"); ThreeDSecure.performVerification(fragment, cardBuilder, TEST_AMOUNT); mCountDownLatch.await(); }
@Test(timeout = 10000) public void performVerification_doesALookupAndReturnsACardWhenAuthenticationIsUnavailable() throws InterruptedException { BraintreeFragment fragment = getFragment(); fragment.addListener(new PaymentMethodNonceCreatedListener() { @Override public void onPaymentMethodNonceCreated(PaymentMethodNonce paymentMethodNonce) { assertIsANonce(paymentMethodNonce.getNonce()); CardNonce cardNonce = (CardNonce) paymentMethodNonce; assertEquals("69", cardNonce.getLastTwo()); assertFalse(cardNonce.getThreeDSecureInfo().isLiabilityShifted()); assertFalse(cardNonce.getThreeDSecureInfo().isLiabilityShiftPossible()); assertTrue(((CardNonce) paymentMethodNonce).getThreeDSecureInfo().wasVerified()); mCountDownLatch.countDown(); } }); CardBuilder cardBuilder = new CardBuilder() .cardNumber(THREE_D_SECURE_AUTHENTICATION_UNAVAILABLE) .expirationDate("12/20"); ThreeDSecure.performVerification(fragment, cardBuilder, TEST_AMOUNT); mCountDownLatch.await(); }
@Test(timeout = 1000) public void performVerification_withInvalidThreeDSecureRequest_postsException() throws InterruptedException, InvalidArgumentException { String clientToken = new TestClientTokenBuilder().withThreeDSecure().build(); BraintreeFragment fragment = getFragmentWithAuthorization(mActivity, clientToken); fragment.addListener(new BraintreeErrorListener() { @Override public void onError(Exception error) { assertEquals("The ThreeDSecureRequest nonce and amount cannot be null", error.getMessage()); mCountDownLatch.countDown(); } }); ThreeDSecureRequest request = new ThreeDSecureRequest() .amount("5"); ThreeDSecure.performVerification(fragment, request); mCountDownLatch.await(); }
@Test(timeout = 30000) public void performVerification_callsCancelListenerWhenBackIsPressed() throws InterruptedException { CardBuilder cardBuilder = new CardBuilder() .cardNumber(THREE_D_SECURE_VERIFICATON) .expirationDate("12/30"); BraintreeFragment fragment = getFragment(); fragment.addListener(new BraintreeCancelListener() { @Override public void onCancel(int requestCode) { assertEquals(BraintreeRequestCodes.THREE_D_SECURE, requestCode); mCountDownLatch.countDown(); } }); ThreeDSecure.performVerification(fragment, cardBuilder, TEST_AMOUNT); waitForView(withId(android.R.id.widget_frame)); pressBack(); mCountDownLatch.await(); }
@Test(timeout = 10000) public void performVerification_acceptsACardBuilderAndPostsAPaymentMethodNonceToListener() throws InterruptedException { BraintreeFragment fragment = getFragmentWithAuthorization(mActivity, new TestClientTokenBuilder().withThreeDSecure().build()); fragment.addListener(new PaymentMethodNonceCreatedListener() { @Override public void onPaymentMethodNonceCreated(PaymentMethodNonce paymentMethodNonce) { assertIsANonce(paymentMethodNonce.getNonce()); assertEquals("51", ((CardNonce) paymentMethodNonce).getLastTwo()); assertTrue(((CardNonce) paymentMethodNonce).getThreeDSecureInfo().wasVerified()); mCountDownLatch.countDown(); } }); CardBuilder cardBuilder = new CardBuilder() .cardNumber("4000000000000051") .expirationDate("12/20"); ThreeDSecure.performVerification(fragment, cardBuilder, "5"); mCountDownLatch.await(); }
@Test(timeout = 30000) public void performVerification_returnsAnUnexpectedErrorWhenIssuerIsDown() throws InterruptedException { BraintreeFragment fragment = getFragment(); fragment.addListener(new BraintreeErrorListener() { @Override public void onError(Exception error) { assertEquals("An unexpected error occurred", error.getMessage()); mCountDownLatch.countDown(); } }); CardBuilder cardBuilder = new CardBuilder() .cardNumber(THREE_D_SECURE_ISSUER_DOWN) .expirationDate("12/30"); ThreeDSecure.performVerification(fragment, cardBuilder, TEST_AMOUNT); waitForView(withId(android.R.id.widget_frame)); enterThreeDSPasswordAndReturnToApp(); mCountDownLatch.await(); }
@Test(timeout = 30000) public void performVerification_returnsAFailedAuthenticationWhenSignatureVerificationFails() throws InterruptedException { BraintreeFragment fragment = getFragment(); fragment.addListener(new BraintreeErrorListener() { @Override public void onError(Exception error) { assertEquals("Failed to authenticate, please try a different form of payment.", error.getMessage()); mCountDownLatch.countDown(); } }); CardBuilder cardBuilder = new CardBuilder() .cardNumber(THREE_D_SECURE_SIGNATURE_VERIFICATION_FAILURE) .expirationDate("12/30"); ThreeDSecure.performVerification(fragment, cardBuilder, TEST_AMOUNT); waitForView(withId(android.R.id.widget_frame)); enterThreeDSPasswordAndReturnToApp(); mCountDownLatch.await(); }
@Test(timeout = 10000) public void performVerification_failsWithATokenizationKey() throws InterruptedException { String clientToken = new TestClientTokenBuilder().withThreeDSecure().build(); BraintreeFragment fragment = getFragment(TOKENIZATION_KEY, clientToken); fragment.addListener(new BraintreeErrorListener() { @Override public void onError(Exception error) { assertTrue(error instanceof AuthorizationException); assertEquals( "Tokenization key authorization not allowed for this endpoint. Please use an authentication method with upgraded permissions", error.getMessage()); mCountDownLatch.countDown(); } }); CardBuilder cardBuilder = new CardBuilder() .cardNumber(THREE_D_SECURE_VERIFICATON) .expirationDate("12/20"); ThreeDSecure.performVerification(fragment, cardBuilder, TEST_AMOUNT); mCountDownLatch.await(); }
@Test(timeout = 30000) public void performVerification_returnsAnErrorWhenAuthenticationFails() throws InterruptedException { BraintreeFragment fragment = getFragment(); fragment.addListener(new BraintreeErrorListener() { @Override public void onError(Exception error) { assertEquals("Failed to authenticate, please try a different form of payment.", error.getMessage()); mCountDownLatch.countDown(); } }); CardBuilder cardBuilder = new CardBuilder() .cardNumber(THREE_D_SECURE_AUTHENTICATION_FAILED) .expirationDate("12/30"); ThreeDSecure.performVerification(fragment, cardBuilder, TEST_AMOUNT); waitForView(withId(android.R.id.widget_frame)); enterThreeDSPasswordAndReturnToApp(); mCountDownLatch.await(); }
@Test(timeout = 30000) public void performVerification_returnsAnErrorWhenCardinalReturnsError() throws InterruptedException { BraintreeFragment fragment = getFragment(); fragment.addListener(new BraintreeErrorListener() { @Override public void onError(Exception error) { assertEquals("An unexpected error occurred", error.getMessage()); mCountDownLatch.countDown(); } }); CardBuilder cardBuilder = new CardBuilder() .cardNumber(THREE_D_SECURE_MPI_SERVICE_ERROR) .expirationDate("12/30"); ThreeDSecure.performVerification(fragment, cardBuilder, TEST_AMOUNT); waitForView(withId(android.R.id.widget_frame)); enterThreeDSPasswordAndReturnToApp(); mCountDownLatch.await(); }
@Test(timeout = 10000) public void performVerification_postsPaymentMethodNonceToListenersWhenLookupReturnsACard() throws InterruptedException { String clientToken = new TestClientTokenBuilder().withThreeDSecure().build(); BraintreeFragment fragment = getFragmentWithAuthorization(mActivity, clientToken); String nonce = tokenize(fragment, new CardBuilder() .cardNumber("4000000000000051") .expirationDate("12/20")).getNonce(); fragment.addListener(new PaymentMethodNonceCreatedListener() { @Override public void onPaymentMethodNonceCreated(PaymentMethodNonce paymentMethodNonce) { assertIsANonce(paymentMethodNonce.getNonce()); assertEquals("51", ((CardNonce) paymentMethodNonce).getLastTwo()); assertTrue(((CardNonce) paymentMethodNonce).getThreeDSecureInfo().wasVerified()); mCountDownLatch.countDown(); } }); ThreeDSecure.performVerification(fragment, nonce, "5"); mCountDownLatch.await(); }
@Test(timeout = 30000) public void performVerification_callsCancelListenerWhenUpIsPressed() throws InterruptedException { CardBuilder cardBuilder = new CardBuilder() .cardNumber(THREE_D_SECURE_VERIFICATON) .expirationDate("12/30"); BraintreeFragment fragment = getFragment(); fragment.addListener(new BraintreeCancelListener() { @Override public void onCancel(int requestCode) { assertEquals(BraintreeRequestCodes.THREE_D_SECURE, requestCode); mCountDownLatch.countDown(); } }); ThreeDSecure.performVerification(getFragment(), cardBuilder, TEST_AMOUNT); waitForView(withId(android.R.id.widget_frame)); onView(withContentDescription("Navigate up")).perform(click()); mCountDownLatch.await(); }