Commit 84204fda authored by rouslan's avatar rouslan Committed by Commit bot

Autofill cards at the bottom of the PaymentRequest UI

This patch arranges the payment instruments in the following order:
> Non-autofill payment apps
> Complete credit cards from Autofill.
> Incomplete credit card from Autofill (need editing before sending to
  the merchant).

BUG=629882

Review-Url: https://codereview.chromium.org/2165163002
Cr-Commit-Position: refs/heads/master@{#407179}
parent d2a8f72e
......@@ -53,6 +53,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
/**
......@@ -89,8 +90,14 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
}
private static final String TAG = "cr_PaymentRequest";
private static final int SUGGESTIONS_LIMIT = 4;
private static final Comparator<Completable> COMPLETENESS_COMPARATOR =
new Comparator<Completable>() {
@Override
public int compare(Completable a, Completable b) {
return (b.isComplete() ? 1 : 0) - (a.isComplete() ? 1 : 0);
}
};
private static PaymentRequestServiceObserverForTest sObserverForTest;
......@@ -127,12 +134,12 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
*/
private SectionInformation mUiShippingOptions;
private HashMap<String, JSONObject> mMethodData;
private Map<String, JSONObject> mMethodData;
private SectionInformation mShippingAddressesSection;
private SectionInformation mContactSection;
private List<PaymentApp> mPendingApps;
private int mFirstCompletePendingInstrument;
private List<PaymentInstrument> mPendingInstruments;
private List<PaymentInstrument> mPendingAutofillInstruments;
private SectionInformation mPaymentMethodsSection;
private PaymentRequestUI mUI;
private Callback<PaymentInformation> mPaymentInformationCallback;
......@@ -237,20 +244,6 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
return;
}
// Create a comparator to sort the suggestions by completeness.
Comparator<Completable> completenessComparator = new Comparator<Completable>() {
@Override
public int compare(Completable a, Completable b) {
if (a.isComplete() == b.isComplete()) {
return 0;
} else if (a.isComplete()) {
return -1;
} else {
return 1;
}
}
};
// If the merchant requests shipping and does not provide a selected shipping option, then
// the merchant needs the shipping address to calculate the shipping price and availability.
boolean requestShipping = options != null && options.requestShipping;
......@@ -277,7 +270,7 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
}
// Suggest complete addresses first.
Collections.sort(addresses, completenessComparator);
Collections.sort(addresses, COMPLETENESS_COMPARATOR);
// Limit the number of suggestions.
addresses = addresses.subList(0, Math.min(addresses.size(), SUGGESTIONS_LIMIT));
......@@ -324,7 +317,7 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
}
// Suggest complete contact infos first.
Collections.sort(contacts, completenessComparator);
Collections.sort(contacts, COMPLETENESS_COMPARATOR);
// Limit the number of suggestions.
contacts = contacts.subList(0, Math.min(contacts.size(), SUGGESTIONS_LIMIT));
......@@ -351,11 +344,11 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
if (mContactEditor != null) mContactEditor.setEditorView(mUI.getEditorView());
}
private static HashMap<String, JSONObject> getValidatedMethodData(
private static Map<String, JSONObject> getValidatedMethodData(
PaymentMethodData[] methodData, CardEditor paymentMethodsCollector) {
// Payment methodData are required.
if (methodData == null || methodData.length == 0) return null;
HashMap<String, JSONObject> result = new HashMap<>();
Map<String, JSONObject> result = new HashMap<>();
for (int i = 0; i < methodData.length; i++) {
JSONObject data = null;
if (!TextUtils.isEmpty(methodData[i].stringifiedData)) {
......@@ -395,10 +388,11 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
*/
private boolean getMatchingPaymentInstruments() {
mPendingApps = new ArrayList<>(mApps);
mFirstCompletePendingInstrument = SectionInformation.NO_SELECTION;
mPendingInstruments = new ArrayList<>();
mPendingAutofillInstruments = new ArrayList<>();
boolean arePaymentMethodsSupported = false;
Map<PaymentApp, JSONObject> queryApps = new HashMap<>();
for (int i = 0; i < mApps.size(); i++) {
PaymentApp app = mApps.get(i);
Set<String> appMethods = app.getSupportedMethodNames();
......@@ -407,11 +401,18 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
mPendingApps.remove(app);
} else {
arePaymentMethodsSupported = true;
mMerchantSupportsAutofillPaymentInstruments = app instanceof AutofillPaymentApp;
app.getInstruments(mMethodData.get(appMethods.iterator().next()), this);
mMerchantSupportsAutofillPaymentInstruments |= app instanceof AutofillPaymentApp;
queryApps.put(app, mMethodData.get(appMethods.iterator().next()));
}
}
// Query instruments after mMerchantSupportsAutofillPaymentInstruments has been initialized,
// so a fast response from a non-autofill payment app at the front of the app list does not
// cause NOT_SUPPORTED payment rejection.
for (Map.Entry<PaymentApp, JSONObject> q : queryApps.entrySet()) {
q.getKey().getInstruments(q.getValue(), this);
}
return arePaymentMethodsSupported;
}
......@@ -868,12 +869,13 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
public void onInstrumentsReady(PaymentApp app, List<PaymentInstrument> instruments) {
mPendingApps.remove(app);
// Place the instruments into either "autofill" or "non-autofill" list to be displayed when
// all apps have responded.
if (instruments != null) {
for (int i = 0; i < instruments.size(); i++) {
PaymentInstrument instrument = instruments.get(i);
if (mMethodData.containsKey(instrument.getMethodName())) {
checkForCompletePaymentInstrument(instrument, mPendingInstruments.size());
mPendingInstruments.add(instrument);
addPendingInstrument(instrument);
} else {
instrument.dismiss();
}
......@@ -893,25 +895,56 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie
return;
}
// List order:
// > Non-autofill instruments.
// > Complete autofill instruments.
// > Incomplete autofill instruments.
Collections.sort(mPendingAutofillInstruments, COMPLETENESS_COMPARATOR);
mPendingInstruments.addAll(mPendingAutofillInstruments);
mPendingAutofillInstruments.clear();
mPendingAutofillInstruments = null;
// Pre-select the first instrument on the list, if it is complete.
int selection = SectionInformation.NO_SELECTION;
if (!mPendingInstruments.isEmpty()) {
PaymentInstrument first = mPendingInstruments.get(0);
if (!(first instanceof AutofillPaymentInstrument)
|| ((AutofillPaymentInstrument) first).isComplete()) {
selection = 0;
}
}
// The list of payment instruments is ready to display.
mPaymentMethodsSection = new SectionInformation(PaymentRequestUI.TYPE_PAYMENT_METHODS,
mFirstCompletePendingInstrument, mPendingInstruments);
selection, mPendingInstruments);
mPendingInstruments.clear();
mPendingInstruments = null;
// UI has requested the full list of payment instruments. Provide it now.
if (mPaymentInformationCallback != null) providePaymentInformation();
}
private void checkForCompletePaymentInstrument(PaymentInstrument instrument, int index) {
boolean isComplete = true;
/**
* Saves the given instrument in either "autofill" or "non-autofill" list. The separation
* enables placing autofill instruments on the bottom of the list.
*
* Autofill instruments are also checked for completeness. A complete autofill instrument can be
* sent to the merchant as-is, without editing first. Such instruments should be displayed
* higher in the list.
*
* @param instrument The instrument to add to either "autofill" or "non-autofill" list.
*/
private void addPendingInstrument(PaymentInstrument instrument) {
if (instrument instanceof AutofillPaymentInstrument) {
AutofillPaymentInstrument autofillInstrument = (AutofillPaymentInstrument) instrument;
isComplete = mCardEditor.isCardComplete(autofillInstrument.getCard());
if (isComplete) autofillInstrument.setIsComplete();
}
if (isComplete && mFirstCompletePendingInstrument == SectionInformation.NO_SELECTION) {
mFirstCompletePendingInstrument = index;
if (mCardEditor.isCardComplete(autofillInstrument.getCard())) {
autofillInstrument.setIsComplete();
}
mPendingAutofillInstruments.add(instrument);
} else {
mPendingInstruments.add(instrument);
}
}
......
......@@ -1198,6 +1198,7 @@ chrome_test_java_sources = [
"javatests/src/org/chromium/chrome/browser/payments/PaymentRequestIncompletePhoneTest.java",
"javatests/src/org/chromium/chrome/browser/payments/PaymentRequestNoShippingTest.java",
"javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppTest.java",
"javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPaymentAppAndCardsTest.java",
"javatests/src/org/chromium/chrome/browser/payments/PaymentRequestPhoneTest.java",
"javatests/src/org/chromium/chrome/browser/payments/PaymentRequestRemoveBillingAddressTest.java",
"javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java",
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.payments;
import android.content.DialogInterface;
import android.test.suitebuilder.annotation.MediumTest;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.autofill.AutofillTestHelper;
import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
/**
* A payment integration test for a merchant that requests payment via Bob Pay or cards.
*/
public class PaymentRequestPaymentAppAndCardsTest extends PaymentRequestTestBase {
public PaymentRequestPaymentAppAndCardsTest() {
super("payment_request_bobpay_and_cards_test.html");
}
@Override
public void onMainActivityStarted() throws InterruptedException, ExecutionException,
TimeoutException {
AutofillTestHelper helper = new AutofillTestHelper();
String billingAddressId = helper.setProfile(new AutofillProfile("", "https://example.com",
true, "Jon Doe", "Google", "340 Main St", "CA", "Los Angeles", "", "90291", "",
"US", "310-310-6000", "jon.doe@gmail.com", "en-US"));
// Mastercard card without a billing address.
helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
"5454545454545454", "", "12", "2050", "mastercard", R.drawable.pr_mc,
""));
// Visa card with complete set of information.
helper.setCreditCard(new CreditCard("", "https://example.com", true, true, "Jon Doe",
"4111111111111111", "", "12", "2050", "visa", R.drawable.pr_visa,
billingAddressId));
}
/**
* If Bob Pay does not have any instruments, show [visa, mastercard]. Here the payment app
* responds quickly.
*/
@MediumTest
public void testNoInstrumentsInFastBobPay() throws InterruptedException, ExecutionException,
TimeoutException {
runTest(NO_INSTRUMENTS, IMMEDIATE_RESPONSE);
}
/**
* If Bob Pay does not have any instruments, show [visa, mastercard]. Here the payment app
* responds slowly.
*/
@MediumTest
public void testNoInstrumentsInSlowBobPay() throws InterruptedException, ExecutionException,
TimeoutException {
runTest(NO_INSTRUMENTS, DELAYED_RESPONSE);
}
/**
* If Bob Pay has instruments, show [bobpay, visa, mastercard]. Here the payment app responds
* quickly.
*/
@MediumTest
public void testHaveInstrumentsInFastBobPay() throws InterruptedException, ExecutionException,
TimeoutException {
runTest(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE);
}
/**
* If Bob Pay has instruments, show [bobpay, visa, mastercard]. Here the payment app responds
* slowly.
*/
@MediumTest
public void testHaveInstrumentsInSlowBobPay() throws InterruptedException, ExecutionException,
TimeoutException {
runTest(HAVE_INSTRUMENTS, DELAYED_RESPONSE);
}
private void runTest(int instrumentPresence, int responseSpeed) throws InterruptedException,
ExecutionException, TimeoutException {
installPaymentApp(instrumentPresence, responseSpeed);
triggerUIAndWait(mReadyToPay);
clickInPaymentMethodAndWait(R.id.payments_section, mReadyForInput);
// Check the number of instruments.
assertEquals(
instrumentPresence == HAVE_INSTRUMENTS ? 3 : 2, getNumberOfPaymentInstruments());
// Check the labesl of the instruments.
int i = 0;
if (instrumentPresence == HAVE_INSTRUMENTS) {
assertEquals("Bob Pay", getPaymentInstrumentLabel(i++));
}
// \u00A0\u22EF is a non-breaking space followed by a midline ellipsis.
assertEquals("Visa\u00A0\u22EF1111\nJon Doe", getPaymentInstrumentLabel(i++));
assertEquals("MasterCard\u00A0\u22EF5454\nJon Doe", getPaymentInstrumentLabel(i++));
// Check the output of the selected instrument.
if (instrumentPresence == HAVE_INSTRUMENTS) {
clickAndWait(R.id.button_primary, mDismissed);
expectResultContains(new String[]{"https://bobpay.com", "\"transaction\"", "1337"});
} else {
clickAndWait(R.id.button_primary, mReadyForUnmaskInput);
setTextInCardUnmaskDialogAndWait(R.id.card_unmask_input, "123", mReadyToUnmask);
clickCardUnmaskButtonAndWait(DialogInterface.BUTTON_POSITIVE, mDismissed);
expectResultContains(new String[] {"Jon Doe", "4111111111111111", "12", "2050", "visa",
"123"});
}
}
}
......@@ -4,20 +4,10 @@
package org.chromium.chrome.browser.payments;
import android.os.Handler;
import android.test.suitebuilder.annotation.MediumTest;
import org.chromium.base.ThreadUtils;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.payments.PaymentAppFactory.PaymentAppFactoryAddition;
import org.chromium.content_public.browser.WebContents;
import org.chromium.mojom.payments.PaymentItem;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
......@@ -25,12 +15,6 @@ import java.util.concurrent.TimeoutException;
* A payment integration test for a merchant that requests payment via Bob Pay.
*/
public class PaymentRequestPaymentAppTest extends PaymentRequestTestBase {
private static final int NO_INSTRUMENTS = 0;
private static final int HAVE_INSTRUMENTS = 1;
private static final int IMMEDIATE_RESPONSE = 0;
private static final int DELAYED_RESPONSE = 1;
public PaymentRequestPaymentAppTest() {
super("payment_request_bobpay_test.html");
}
......@@ -55,7 +39,7 @@ public class PaymentRequestPaymentAppTest extends PaymentRequestTestBase {
@MediumTest
public void testNoInstrumentsInFastBobPay() throws InterruptedException, ExecutionException,
TimeoutException {
installBobPay(NO_INSTRUMENTS, IMMEDIATE_RESPONSE);
installPaymentApp(NO_INSTRUMENTS, IMMEDIATE_RESPONSE);
triggerUIAndWait(mShowFailed);
expectResultContains(
new String[]{"show() rejected", "The payment method is not supported"});
......@@ -68,7 +52,7 @@ public class PaymentRequestPaymentAppTest extends PaymentRequestTestBase {
@MediumTest
public void testNoInstrumentsInSlowBobPay() throws InterruptedException, ExecutionException,
TimeoutException {
installBobPay(NO_INSTRUMENTS, DELAYED_RESPONSE);
installPaymentApp(NO_INSTRUMENTS, DELAYED_RESPONSE);
triggerUIAndWait(mShowFailed);
expectResultContains(
new String[]{"show() rejected", "The payment method is not supported"});
......@@ -81,7 +65,7 @@ public class PaymentRequestPaymentAppTest extends PaymentRequestTestBase {
@MediumTest
public void testPayViaFastBobPay() throws InterruptedException, ExecutionException,
TimeoutException {
installBobPay(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE);
installPaymentApp(HAVE_INSTRUMENTS, IMMEDIATE_RESPONSE);
triggerUIAndWait(mReadyToPay);
clickAndWait(R.id.button_primary, mDismissed);
expectResultContains(new String[]{"https://bobpay.com", "\"transaction\"", "1337"});
......@@ -94,92 +78,9 @@ public class PaymentRequestPaymentAppTest extends PaymentRequestTestBase {
@MediumTest
public void testPayViaSlowBobPay() throws InterruptedException, ExecutionException,
TimeoutException {
installBobPay(HAVE_INSTRUMENTS, DELAYED_RESPONSE);
installPaymentApp(HAVE_INSTRUMENTS, DELAYED_RESPONSE);
triggerUIAndWait(mReadyToPay);
clickAndWait(R.id.button_primary, mDismissed);
expectResultContains(new String[]{"https://bobpay.com", "\"transaction\"", "1337"});
}
/**
* Installs a payment app for testing.
*
* @param instrumentPresence Whether Bob Pay has any payment instruments. Either NO_INSTRUMENTS
* or HAVE_INSTRUMENTS.
* @param responseSpeed How quickly Bob Pay will respond to "get instruments" query. Either
* IMMEDIATE_RESPONSE or DELAYED_RESPONSE.
*/
private void installBobPay(final int instrumentPresence, final int responseSpeed) {
PaymentAppFactory.setAdditionalFactory(new PaymentAppFactoryAddition() {
@Override
public List<PaymentApp> create(WebContents webContents) {
List<PaymentApp> additionalApps = new ArrayList<>();
additionalApps.add(new BobPay(instrumentPresence, responseSpeed));
return additionalApps;
}
});
}
/** A payment app implementation for test. */
private static class BobPay implements PaymentApp {
private final int mInstrumentPresence;
private final int mResponseSpeed;
BobPay(int instrumentPresence, int responseSpeed) {
mInstrumentPresence = instrumentPresence;
mResponseSpeed = responseSpeed;
}
@Override
public void getInstruments(JSONObject details, final InstrumentsCallback
instrumentsCallback) {
final List<PaymentInstrument> instruments = new ArrayList<>();
if (mInstrumentPresence == HAVE_INSTRUMENTS) instruments.add(new BobPayInstrument());
Runnable instrumentsReady = new Runnable() {
@Override
public void run() {
ThreadUtils.assertOnUiThread();
instrumentsCallback.onInstrumentsReady(BobPay.this, instruments);
}
};
if (mResponseSpeed == IMMEDIATE_RESPONSE) {
instrumentsReady.run();
} else {
new Handler().postDelayed(instrumentsReady, 100);
}
}
@Override
public Set<String> getSupportedMethodNames() {
Set<String> methodNames = new HashSet<>();
methodNames.add("https://bobpay.com");
return methodNames;
}
@Override
public String getIdentifier() {
return "https://bobpay.com";
}
}
/** A payment instrument implementation for test. */
private static class BobPayInstrument extends PaymentInstrument {
BobPayInstrument() {
super("https://bobpay.com", "Bob Pay", null, NO_ICON);
}
@Override
public String getMethodName() {
return "https://bobpay.com";
}
@Override
public void getDetails(String merchantName, String origin, PaymentItem total,
List<PaymentItem> cart, JSONObject details, DetailsCallback detailsCallback) {
detailsCallback.onInstrumentDetailsReady(
"https://bobpay.com", "{\"transaction\": 1337}");
}
@Override
public void dismiss() {}
}
}
......@@ -4,6 +4,7 @@
package org.chromium.chrome.browser.payments;
import android.os.Handler;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
......@@ -17,6 +18,7 @@ import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.autofill.CardUnmaskPrompt;
import org.chromium.chrome.browser.autofill.CardUnmaskPrompt.CardUnmaskObserverForTest;
import org.chromium.chrome.browser.payments.PaymentAppFactory.PaymentAppFactoryAddition;
import org.chromium.chrome.browser.payments.PaymentRequestImpl.PaymentRequestServiceObserverForTest;
import org.chromium.chrome.browser.payments.ui.EditorTextField;
import org.chromium.chrome.browser.payments.ui.PaymentRequestSection.OptionSection;
......@@ -29,8 +31,13 @@ import org.chromium.content.browser.test.util.Criteria;
import org.chromium.content.browser.test.util.CriteriaHelper;
import org.chromium.content.browser.test.util.DOMUtils;
import org.chromium.content_public.browser.WebContents;
import org.chromium.mojom.payments.PaymentItem;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
......@@ -42,6 +49,18 @@ import java.util.concurrent.atomic.AtomicReference;
abstract class PaymentRequestTestBase extends ChromeActivityTestCaseBase<ChromeActivity>
implements PaymentRequestObserverForTest, PaymentRequestServiceObserverForTest,
CardUnmaskObserverForTest {
/** Flag for installing a payment app without instruments. */
protected static final int NO_INSTRUMENTS = 0;
/** Flag for installing a payment app with instruments. */
protected static final int HAVE_INSTRUMENTS = 1;
/** Flag for installing a fast payment app. */
protected static final int IMMEDIATE_RESPONSE = 0;
/** Flag for installing a slow payment app. */
protected static final int DELAYED_RESPONSE = 1;
protected final PaymentsCallbackHelper<PaymentRequestUI> mReadyForInput;
protected final PaymentsCallbackHelper<PaymentRequestUI> mReadyToPay;
protected final PaymentsCallbackHelper<PaymentRequestUI> mReadyToClose;
......@@ -240,14 +259,23 @@ abstract class PaymentRequestTestBase extends ChromeActivityTestCaseBase<ChromeA
});
}
/** Returns the label corresponding to the payment instrument at the specified |index|. */
protected String getPaymentInstrumentLabel(final int index) throws ExecutionException {
return ThreadUtils.runOnUiThreadBlocking(new Callable<String>() {
@Override
public String call() {
return ((OptionSection) mUI.getPaymentMethodSectionForTest())
.getOptionLabelsForTest(index).getText().toString();
}
});
}
/**
* Returns the label corresponding to the contact detail suggestion at the specified
* |suggestionIndex|.
*/
protected String getContactDetailsSuggestionLabel(final int suggestionIndex)
throws ExecutionException {
assert (suggestionIndex < getNumberOfContactDetailSuggestions());
return ThreadUtils.runOnUiThreadBlocking(new Callable<String>() {
@Override
public String call() {
......@@ -257,9 +285,18 @@ abstract class PaymentRequestTestBase extends ChromeActivityTestCaseBase<ChromeA
});
}
/**
* Returns the the number of contact detail suggestions,
*/
/** Returns the the number of payment instruments. */
protected int getNumberOfPaymentInstruments() throws ExecutionException {
return ThreadUtils.runOnUiThreadBlocking(new Callable<Integer>() {
@Override
public Integer call() {
return ((OptionSection) mUI.getPaymentMethodSectionForTest())
.getNumberOfOptionLabelsForTest();
}
});
}
/** Returns the the number of contact detail suggestions. */
protected int getNumberOfContactDetailSuggestions() throws ExecutionException {
return ThreadUtils.runOnUiThreadBlocking(new Callable<Integer>() {
@Override
......@@ -528,4 +565,87 @@ abstract class PaymentRequestTestBase extends ChromeActivityTestCaseBase<ChromeA
notifyCalled();
}
}
/**
* Installs a payment app for testing.
*
* @param instrumentPresence Whether the app has any payment instruments. Either NO_INSTRUMENTS
* or HAVE_INSTRUMENTS.
* @param responseSpeed How quickly the app will respond to "get instruments" query. Either
* IMMEDIATE_RESPONSE or DELAYED_RESPONSE.
*/
protected void installPaymentApp(final int instrumentPresence, final int responseSpeed) {
PaymentAppFactory.setAdditionalFactory(new PaymentAppFactoryAddition() {
@Override
public List<PaymentApp> create(WebContents webContents) {
List<PaymentApp> additionalApps = new ArrayList<>();
additionalApps.add(new BobPay(instrumentPresence, responseSpeed));
return additionalApps;
}
});
}
/** A payment app implementation for test. */
private static class BobPay implements PaymentApp {
private final int mInstrumentPresence;
private final int mResponseSpeed;
BobPay(int instrumentPresence, int responseSpeed) {
mInstrumentPresence = instrumentPresence;
mResponseSpeed = responseSpeed;
}
@Override
public void getInstruments(JSONObject details, final InstrumentsCallback
instrumentsCallback) {
final List<PaymentInstrument> instruments = new ArrayList<>();
if (mInstrumentPresence == HAVE_INSTRUMENTS) instruments.add(new BobPayInstrument());
Runnable instrumentsReady = new Runnable() {
@Override
public void run() {
ThreadUtils.assertOnUiThread();
instrumentsCallback.onInstrumentsReady(BobPay.this, instruments);
}
};
if (mResponseSpeed == IMMEDIATE_RESPONSE) {
instrumentsReady.run();
} else {
new Handler().postDelayed(instrumentsReady, 100);
}
}
@Override
public Set<String> getSupportedMethodNames() {
Set<String> methodNames = new HashSet<>();
methodNames.add("https://bobpay.com");
return methodNames;
}
@Override
public String getIdentifier() {
return "https://bobpay.com";
}
}
/** A payment instrument implementation for test. */
private static class BobPayInstrument extends PaymentInstrument {
BobPayInstrument() {
super("https://bobpay.com", "Bob Pay", null, NO_ICON);
}
@Override
public String getMethodName() {
return "https://bobpay.com";
}
@Override
public void getDetails(String merchantName, String origin, PaymentItem total,
List<PaymentItem> cart, JSONObject details, DetailsCallback detailsCallback) {
detailsCallback.onInstrumentDetailsReady(
"https://bobpay.com", "{\"transaction\": 1337}");
}
@Override
public void dismiss() {}
}
}
/*
* Copyright 2016 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* global PaymentRequest:false */
/**
* Launches the PaymentRequest UI with Bob Pay and credit cards as payment
* methods.
*/
function buy() { // eslint-disable-line no-unused-vars
try {
new PaymentRequest(
[{supportedMethods: ['https://bobpay.com', 'visa', 'mastercard']}],
{total: {label: 'Total', amount: {currency: 'USD', value: '5.00'}}})
.show()
.then(function(resp) {
resp.complete('success')
.then(function() {
print(resp.methodName + '<br>' +
JSON.stringify(resp.details, undefined, 2));
})
.catch(function(error) {
print(error.message);
});
})
.catch(function(error) {
print(error.message);
});
} catch (error) {
print(error.message);
}
}
<!DOCTYPE html>
<!--
Copyright 2016 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<html>
<head>
<title>Bob Pay and Cards Test</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<button onclick="buy()" id="buy">Bob Pay and Cards Test</button><br>
<pre id="result"></pre>
<script src="util.js"></script>
<script src="bobpay_and_cards.js"></script>
</body>
</html>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment