Index: chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java |
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java |
index 71006e169b283e761c2fb71c35dd01b72f9002b5..5a43dd089e1323d4fb4117e005bd12ad7dfe8a47 100644 |
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java |
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java |
@@ -7,6 +7,7 @@ package org.chromium.chrome.browser.payments; |
import android.app.Activity; |
import android.graphics.Bitmap; |
import android.os.Handler; |
+import android.support.v4.util.ArrayMap; |
import android.text.TextUtils; |
import org.chromium.base.Callback; |
@@ -37,6 +38,7 @@ import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver; |
import org.chromium.components.url_formatter.UrlFormatter; |
import org.chromium.content_public.browser.WebContents; |
import org.chromium.mojo.system.MojoException; |
+import org.chromium.payments.mojom.ActivePaymentQueryResult; |
import org.chromium.payments.mojom.PaymentComplete; |
import org.chromium.payments.mojom.PaymentDetails; |
import org.chromium.payments.mojom.PaymentErrorReason; |
@@ -53,7 +55,6 @@ import java.util.ArrayList; |
import java.util.Arrays; |
import java.util.Collections; |
import java.util.Comparator; |
-import java.util.HashMap; |
import java.util.HashSet; |
import java.util.List; |
import java.util.Locale; |
@@ -68,16 +69,6 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie |
PaymentApp.InstrumentsCallback, PaymentInstrument.InstrumentDetailsCallback, |
PaymentResponseHelper.PaymentResponseRequesterDelegate { |
/** |
- * Observer to be notified when PaymentRequest UI has been dismissed. |
- */ |
- public interface PaymentRequestDismissObserver { |
- /** |
- * Called when PaymentRequest UI has been dismissed. |
- */ |
- void onPaymentRequestDismissed(); |
- } |
- |
- /** |
* A test-only observer for the PaymentRequest service implementation. |
*/ |
public interface PaymentRequestServiceObserverForTest { |
@@ -106,6 +97,11 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie |
* </ul> |
*/ |
void onPaymentRequestServiceShowFailed(); |
+ |
+ /** |
+ * Called when the canMakeActivePayment() request has been responded. |
+ */ |
+ void onPaymentRequestServiceActivePaymentQueryResponded(); |
} |
private static final String TAG = "cr_PaymentRequest"; |
@@ -119,8 +115,21 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie |
} |
}; |
+ /** Every origin can call canMakeActivePayment() every 30 minutes. */ |
+ private static final int CAN_MAKE_ACTIVE_PAYMENT_QUERY_PERIOD_MS = 30 * 60 * 1000; |
+ |
private static PaymentRequestServiceObserverForTest sObserverForTest; |
+ /** True if show() was called in any PaymentRequestImpl object. */ |
+ private static boolean sIsShowing; |
+ |
+ /** |
+ * In-memory mapping of the origins of websites that have recently called canMakeActivePayment() |
+ * to the list of the payment methods that were been queried. Used for throttling the usage of |
+ * this call. The user can clear the list by restarting the browser. |
+ */ |
+ private static Map<String, Set<String>> sCanMakeActivePaymentQueries; |
+ |
/** Monitors changes in the TabModelSelector. */ |
private final TabModelSelectorObserver mSelectorObserver = new EmptyTabModelSelectorObserver() { |
@Override |
@@ -139,7 +148,6 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie |
private final Handler mHandler = new Handler(); |
private final ChromeActivity mContext; |
- private final PaymentRequestDismissObserver mDismissObserver; |
private final String mMerchantName; |
private final String mOrigin; |
private final List<PaymentApp> mApps; |
@@ -187,13 +195,11 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie |
private boolean mMerchantSupportsAutofillPaymentInstruments; |
private ContactEditor mContactEditor; |
private boolean mHasRecordedAbortReason; |
+ private boolean mQueriedCanMakeActivePayment; |
/** True if any of the requested payment methods are supported. */ |
private boolean mArePaymentMethodsSupported; |
- /** True if show() was called. */ |
- private boolean mIsShowing; |
- |
/** The helper to create and fill the response to send to the merchant. */ |
private PaymentResponseHelper mPaymentResponseHelper; |
@@ -202,21 +208,18 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie |
* |
* @param context The context where PaymentRequest has been invoked. |
* @param webContents The web contents that have invoked the PaymentRequest API. |
- * @param dismissObserver The observer to notify when PaymentRequest UI has been dismissed. |
*/ |
- public PaymentRequestImpl(Activity context, WebContents webContents, |
- PaymentRequestDismissObserver dismissObserver) { |
+ public PaymentRequestImpl(Activity context, WebContents webContents) { |
assert context != null; |
assert webContents != null; |
- assert dismissObserver != null; |
assert context instanceof ChromeActivity; |
mContext = (ChromeActivity) context; |
- mDismissObserver = dismissObserver; |
mMerchantName = webContents.getTitle(); |
// The feature is available only in secure context, so it's OK to not show HTTPS. |
- mOrigin = UrlFormatter.formatUrlForSecurityDisplay(webContents.getVisibleUrl(), false); |
+ mOrigin = UrlFormatter.formatUrlForSecurityDisplay( |
+ webContents.getLastCommittedUrl(), false); |
final FaviconHelper faviconHelper = new FaviconHelper(); |
faviconHelper.getLocalFaviconImageForURL(Profile.getLastUsedProfile(), |
@@ -402,9 +405,16 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie |
*/ |
@Override |
public void show() { |
- if (mClient == null || mIsShowing) return; |
+ if (mClient == null) return; |
+ |
+ if (getIsShowing()) { |
+ disconnectFromClientWithDebugMessage("A PaymentRequest UI is already showing"); |
+ recordAbortReasonHistogram( |
+ PaymentRequestMetrics.ABORT_REASON_INVALID_DATA_FROM_RENDERER); |
+ return; |
+ } |
- mIsShowing = true; |
+ setIsShowing(true); |
if (disconnectIfNoPaymentMethodsSupported()) return; |
// Catch any time the user switches tabs. Because the dialog is modal, a user shouldn't be |
@@ -420,7 +430,7 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie |
PaymentMethodData[] methodData, CardEditor paymentMethodsCollector) { |
// Payment methodData are required. |
if (methodData == null || methodData.length == 0) return null; |
- Map<String, PaymentMethodData> result = new HashMap<>(); |
+ Map<String, PaymentMethodData> result = new ArrayMap<>(); |
for (int i = 0; i < methodData.length; i++) { |
String[] methods = methodData[i].supportedMethods; |
@@ -444,7 +454,7 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie |
mPendingInstruments = new ArrayList<>(); |
mPendingAutofillInstruments = new ArrayList<>(); |
- Map<PaymentApp, Map<String, PaymentMethodData>> queryApps = new HashMap<>(); |
+ Map<PaymentApp, Map<String, PaymentMethodData>> queryApps = new ArrayMap<>(); |
for (int i = 0; i < mApps.size(); i++) { |
PaymentApp app = mApps.get(i); |
Map<String, PaymentMethodData> appMethods = |
@@ -472,7 +482,7 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie |
Map<String, PaymentMethodData> result = null; |
for (String method : appMethods) { |
if (merchantMethodData.containsKey(method)) { |
- if (result == null) result = new HashMap<>(); |
+ if (result == null) result = new ArrayMap<>(); |
result.put(method, merchantMethodData.get(method)); |
} |
} |
@@ -915,6 +925,46 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie |
} |
/** |
+ * Called by the merchant website to check if the user has complete payment instruments. |
+ */ |
+ @Override |
+ public void canMakeActivePayment() { |
+ if (mClient == null) return; |
+ |
+ if (sCanMakeActivePaymentQueries == null) sCanMakeActivePaymentQueries = new ArrayMap<>(); |
+ |
+ if (sCanMakeActivePaymentQueries.containsKey(mOrigin)) { |
+ if (!mMethodData.keySet().equals(sCanMakeActivePaymentQueries.get(mOrigin))) { |
+ mClient.onCanMakeActivePayment(ActivePaymentQueryResult.QUERY_QUOTA_EXCEEDED); |
+ if (sObserverForTest != null) { |
+ sObserverForTest.onPaymentRequestServiceActivePaymentQueryResponded(); |
+ } |
+ return; |
+ } |
+ } else { |
+ sCanMakeActivePaymentQueries.put(mOrigin, mMethodData.keySet()); |
+ mHandler.postDelayed(new Runnable() { |
+ @Override |
+ public void run() { |
+ sCanMakeActivePaymentQueries.remove(mOrigin); |
+ } |
+ }, CAN_MAKE_ACTIVE_PAYMENT_QUERY_PERIOD_MS); |
+ } |
+ |
+ if (!mPendingApps.isEmpty() || !mPendingInstruments.isEmpty()) { |
+ mQueriedCanMakeActivePayment = true; |
+ } else { |
+ mClient.onCanMakeActivePayment(mPaymentMethodsSection == null |
+ || mPaymentMethodsSection.getSelectedItem() == null |
+ ? ActivePaymentQueryResult.CANNOT_MAKE_ACTIVE_PAYMENT |
+ : ActivePaymentQueryResult.CAN_MAKE_ACTIVE_PAYMENT); |
+ if (sObserverForTest != null) { |
+ sObserverForTest.onPaymentRequestServiceActivePaymentQueryResponded(); |
+ } |
+ } |
+ } |
+ |
+ /** |
* Called when the renderer closes the Mojo connection. |
*/ |
@Override |
@@ -1001,6 +1051,16 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie |
} |
} |
+ if (mQueriedCanMakeActivePayment) { |
+ mQueriedCanMakeActivePayment = false; |
+ mClient.onCanMakeActivePayment(selection == 0 |
+ ? ActivePaymentQueryResult.CAN_MAKE_ACTIVE_PAYMENT |
+ : ActivePaymentQueryResult.CANNOT_MAKE_ACTIVE_PAYMENT); |
+ if (sObserverForTest != null) { |
+ sObserverForTest.onPaymentRequestServiceActivePaymentQueryResponded(); |
+ } |
+ } |
+ |
// The list of payment instruments is ready to display. |
mPaymentMethodsSection = new SectionInformation(PaymentRequestUI.TYPE_PAYMENT_METHODS, |
selection, mPendingInstruments); |
@@ -1024,7 +1084,7 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie |
&& !ChromeFeatureList.isEnabled(ChromeFeatureList.NO_CREDIT_CARD_ABORT); |
if (!mArePaymentMethodsSupported |
- || (mIsShowing && !waitingForPaymentApps && !foundPaymentMethods |
+ || (getIsShowing() && !waitingForPaymentApps && !foundPaymentMethods |
&& !userCanAddCreditCard)) { |
// All payment apps have responded, but none of them have instruments. It's possible to |
// add credit cards, but the merchant does not support them either. The payment request |
@@ -1141,7 +1201,15 @@ public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie |
private void closeClient() { |
if (mClient != null) mClient.close(); |
mClient = null; |
- mDismissObserver.onPaymentRequestDismissed(); |
+ setIsShowing(false); |
+ } |
+ |
+ private static boolean getIsShowing() { |
+ return sIsShowing; |
+ } |
+ |
+ private static void setIsShowing(boolean isShowing) { |
+ sIsShowing = isShowing; |
} |
@VisibleForTesting |