| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.chrome.browser.payments; | 5 package org.chromium.chrome.browser.payments; |
| 6 | 6 |
| 7 import android.app.Activity; | 7 import android.app.Activity; |
| 8 import android.graphics.Bitmap; | 8 import android.graphics.Bitmap; |
| 9 import android.os.Handler; | 9 import android.os.Handler; |
| 10 import android.support.v4.util.ArrayMap; | 10 import android.support.v4.util.ArrayMap; |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 * </ul> | 97 * </ul> |
| 98 */ | 98 */ |
| 99 void onPaymentRequestServiceShowFailed(); | 99 void onPaymentRequestServiceShowFailed(); |
| 100 | 100 |
| 101 /** | 101 /** |
| 102 * Called when the canMakeActivePayment() request has been responded. | 102 * Called when the canMakeActivePayment() request has been responded. |
| 103 */ | 103 */ |
| 104 void onPaymentRequestServiceActivePaymentQueryResponded(); | 104 void onPaymentRequestServiceActivePaymentQueryResponded(); |
| 105 } | 105 } |
| 106 | 106 |
| 107 /** The object to keep track of cached payment query results. */ |
| 108 private static class ActivePaymentQuery { |
| 109 private final Set<PaymentRequestImpl> mObservers = new HashSet<>(); |
| 110 private final Set<String> mMethods; |
| 111 private Boolean mResponse; |
| 112 |
| 113 /** |
| 114 * Keeps track of an active payment query. |
| 115 * |
| 116 * @param methods The payment methods that are being queried. |
| 117 */ |
| 118 public ActivePaymentQuery(Set<String> methods) { |
| 119 assert methods != null; |
| 120 mMethods = methods; |
| 121 } |
| 122 |
| 123 /** |
| 124 * Checks whether the given payment methods matches the previously queri
ed payment methods. |
| 125 * |
| 126 * @param methods The payment methods that are being queried. |
| 127 * @return True if the given methods match the previously queried paymen
t methods. |
| 128 */ |
| 129 public boolean matchesPaymentMethods(Set<String> methods) { |
| 130 return mMethods.equals(methods); |
| 131 } |
| 132 |
| 133 /** @return Whether active payment can be made, or null if response is n
ot known yet. */ |
| 134 public Boolean getPreviousResponse() { |
| 135 return mResponse; |
| 136 } |
| 137 |
| 138 /** @param response Whether active payment can be made. */ |
| 139 public void setResponse(boolean response) { |
| 140 if (mResponse == null) mResponse = response; |
| 141 for (PaymentRequestImpl observer : mObservers) { |
| 142 observer.respondActivePaymentQuery(mResponse.booleanValue()); |
| 143 } |
| 144 mObservers.clear(); |
| 145 } |
| 146 |
| 147 /** @param observer The observer to notify when the query response is kn
own. */ |
| 148 public void addObserver(PaymentRequestImpl observer) { |
| 149 mObservers.add(observer); |
| 150 } |
| 151 }; |
| 152 |
| 107 private static final String TAG = "cr_PaymentRequest"; | 153 private static final String TAG = "cr_PaymentRequest"; |
| 108 private static final String ANDROID_PAY_METHOD_NAME = "https://android.com/p
ay"; | 154 private static final String ANDROID_PAY_METHOD_NAME = "https://android.com/p
ay"; |
| 109 private static final int SUGGESTIONS_LIMIT = 4; | 155 private static final int SUGGESTIONS_LIMIT = 4; |
| 110 private static final Comparator<Completable> COMPLETENESS_COMPARATOR = | 156 private static final Comparator<Completable> COMPLETENESS_COMPARATOR = |
| 111 new Comparator<Completable>() { | 157 new Comparator<Completable>() { |
| 112 @Override | 158 @Override |
| 113 public int compare(Completable a, Completable b) { | 159 public int compare(Completable a, Completable b) { |
| 114 return (b.isComplete() ? 1 : 0) - (a.isComplete() ? 1 : 0); | 160 return (b.isComplete() ? 1 : 0) - (a.isComplete() ? 1 : 0); |
| 115 } | 161 } |
| 116 }; | 162 }; |
| 117 | 163 |
| 118 /** Every origin can call canMakeActivePayment() every 30 minutes. */ | 164 /** Every origin can call canMakeActivePayment() every 30 minutes. */ |
| 119 private static final int CAN_MAKE_ACTIVE_PAYMENT_QUERY_PERIOD_MS = 30 * 60 *
1000; | 165 private static final int CAN_MAKE_ACTIVE_PAYMENT_QUERY_PERIOD_MS = 30 * 60 *
1000; |
| 120 | 166 |
| 121 private static PaymentRequestServiceObserverForTest sObserverForTest; | 167 private static PaymentRequestServiceObserverForTest sObserverForTest; |
| 122 | 168 |
| 123 /** True if show() was called in any PaymentRequestImpl object. */ | 169 /** True if show() was called in any PaymentRequestImpl object. */ |
| 124 private static boolean sIsShowing; | 170 private static boolean sIsShowing; |
| 125 | 171 |
| 126 /** | 172 /** |
| 127 * In-memory mapping of the origins of websites that have recently called ca
nMakeActivePayment() | 173 * In-memory mapping of the origins of websites that have recently called ca
nMakeActivePayment() |
| 128 * to the list of the payment methods that were been queried. Used for throt
tling the usage of | 174 * to the list of the payment methods that were been queried. Used for throt
tling the usage of |
| 129 * this call. The user can clear the list by restarting the browser. | 175 * this call. The mapping is shared among all instances of PaymentRequestImp
l in the browser |
| 176 * process on UI thread. The user can reset the throttling mechanism by rest
arting the browser. |
| 130 */ | 177 */ |
| 131 private static Map<String, Set<String>> sCanMakeActivePaymentQueries; | 178 private static Map<String, ActivePaymentQuery> sCanMakeActivePaymentQueries; |
| 132 | 179 |
| 133 /** Monitors changes in the TabModelSelector. */ | 180 /** Monitors changes in the TabModelSelector. */ |
| 134 private final TabModelSelectorObserver mSelectorObserver = new EmptyTabModel
SelectorObserver() { | 181 private final TabModelSelectorObserver mSelectorObserver = new EmptyTabModel
SelectorObserver() { |
| 135 @Override | 182 @Override |
| 136 public void onTabModelSelected(TabModel newModel, TabModel oldModel) { | 183 public void onTabModelSelected(TabModel newModel, TabModel oldModel) { |
| 137 onDismiss(); | 184 onDismiss(); |
| 138 } | 185 } |
| 139 }; | 186 }; |
| 140 | 187 |
| 141 /** Monitors changes in the current TabModel. */ | 188 /** Monitors changes in the current TabModel. */ |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 } | 283 } |
| 237 mUI.setTitleBitmap(bitmap); | 284 mUI.setTitleBitmap(bitmap); |
| 238 } | 285 } |
| 239 }); | 286 }); |
| 240 | 287 |
| 241 mApps = PaymentAppFactory.create(mContext, webContents); | 288 mApps = PaymentAppFactory.create(mContext, webContents); |
| 242 | 289 |
| 243 mAddressEditor = new AddressEditor(); | 290 mAddressEditor = new AddressEditor(); |
| 244 mCardEditor = new CardEditor(webContents, mAddressEditor, sObserverForTe
st); | 291 mCardEditor = new CardEditor(webContents, mAddressEditor, sObserverForTe
st); |
| 245 | 292 |
| 293 if (sCanMakeActivePaymentQueries == null) sCanMakeActivePaymentQueries =
new ArrayMap<>(); |
| 294 |
| 246 recordSuccessFunnelHistograms("Initiated"); | 295 recordSuccessFunnelHistograms("Initiated"); |
| 247 } | 296 } |
| 248 | 297 |
| 249 /** | 298 /** |
| 250 * Called by the merchant website to initialize the payment request data. | 299 * Called by the merchant website to initialize the payment request data. |
| 251 */ | 300 */ |
| 252 @Override | 301 @Override |
| 253 public void init(PaymentRequestClient client, PaymentMethodData[] methodData
, | 302 public void init(PaymentRequestClient client, PaymentMethodData[] methodData
, |
| 254 PaymentDetails details, PaymentOptions options) { | 303 PaymentDetails details, PaymentOptions options) { |
| 255 if (mClient != null || client == null) return; | 304 if (mClient != null || client == null) return; |
| (...skipping 668 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 924 closeUI(PaymentComplete.FAIL != result); | 973 closeUI(PaymentComplete.FAIL != result); |
| 925 } | 974 } |
| 926 | 975 |
| 927 /** | 976 /** |
| 928 * Called by the merchant website to check if the user has complete payment
instruments. | 977 * Called by the merchant website to check if the user has complete payment
instruments. |
| 929 */ | 978 */ |
| 930 @Override | 979 @Override |
| 931 public void canMakeActivePayment() { | 980 public void canMakeActivePayment() { |
| 932 if (mClient == null) return; | 981 if (mClient == null) return; |
| 933 | 982 |
| 934 if (sCanMakeActivePaymentQueries == null) sCanMakeActivePaymentQueries =
new ArrayMap<>(); | 983 ActivePaymentQuery query = sCanMakeActivePaymentQueries.get(mOrigin); |
| 935 | 984 if (query == null) { |
| 936 if (sCanMakeActivePaymentQueries.containsKey(mOrigin)) { | 985 query = new ActivePaymentQuery(mMethodData.keySet()); |
| 937 if (!mMethodData.keySet().equals(sCanMakeActivePaymentQueries.get(mO
rigin))) { | 986 sCanMakeActivePaymentQueries.put(mOrigin, query); |
| 938 mClient.onCanMakeActivePayment(ActivePaymentQueryResult.QUERY_QU
OTA_EXCEEDED); | |
| 939 if (sObserverForTest != null) { | |
| 940 sObserverForTest.onPaymentRequestServiceActivePaymentQueryRe
sponded(); | |
| 941 } | |
| 942 return; | |
| 943 } | |
| 944 } else { | |
| 945 sCanMakeActivePaymentQueries.put(mOrigin, mMethodData.keySet()); | |
| 946 mHandler.postDelayed(new Runnable() { | 987 mHandler.postDelayed(new Runnable() { |
| 947 @Override | 988 @Override |
| 948 public void run() { | 989 public void run() { |
| 949 sCanMakeActivePaymentQueries.remove(mOrigin); | 990 sCanMakeActivePaymentQueries.remove(mOrigin); |
| 950 } | 991 } |
| 951 }, CAN_MAKE_ACTIVE_PAYMENT_QUERY_PERIOD_MS); | 992 }, CAN_MAKE_ACTIVE_PAYMENT_QUERY_PERIOD_MS); |
| 952 } | 993 } |
| 953 | 994 |
| 954 if (!mPendingApps.isEmpty() || !mPendingInstruments.isEmpty()) { | 995 if (!query.matchesPaymentMethods(mMethodData.keySet())) { |
| 955 mQueriedCanMakeActivePayment = true; | 996 mClient.onCanMakeActivePayment(ActivePaymentQueryResult.QUERY_QUOTA_
EXCEEDED); |
| 956 } else { | |
| 957 mClient.onCanMakeActivePayment(mPaymentMethodsSection == null | |
| 958 || mPaymentMethodsSection.getSelectedItem() == null | |
| 959 ? ActivePaymentQueryResult.CANNOT_MAKE_ACTIVE_PAYMEN
T | |
| 960 : ActivePaymentQueryResult.CAN_MAKE_ACTIVE_PAYMENT); | |
| 961 if (sObserverForTest != null) { | 997 if (sObserverForTest != null) { |
| 962 sObserverForTest.onPaymentRequestServiceActivePaymentQueryRespon
ded(); | 998 sObserverForTest.onPaymentRequestServiceActivePaymentQueryRespon
ded(); |
| 963 } | 999 } |
| 1000 return; |
| 1001 } |
| 1002 |
| 1003 if (query.getPreviousResponse() != null) { |
| 1004 respondActivePaymentQuery(query.getPreviousResponse().booleanValue()
); |
| 1005 return; |
| 1006 } |
| 1007 |
| 1008 query.addObserver(this); |
| 1009 if (mPendingApps.isEmpty() && mPendingInstruments.isEmpty()) { |
| 1010 query.setResponse(mPaymentMethodsSection != null |
| 1011 && mPaymentMethodsSection.getSelectedItem() != null); |
| 964 } | 1012 } |
| 965 } | 1013 } |
| 966 | 1014 |
| 1015 private void respondActivePaymentQuery(boolean response) { |
| 1016 mClient.onCanMakeActivePayment(response |
| 1017 ? ActivePaymentQueryResult.CAN_MAKE_ACTIVE_PAYMENT |
| 1018 : ActivePaymentQueryResult.CANNOT_MAKE_ACTIVE_PAYMENT); |
| 1019 if (sObserverForTest != null) { |
| 1020 sObserverForTest.onPaymentRequestServiceActivePaymentQueryResponded(
); |
| 1021 } |
| 1022 } |
| 1023 |
| 967 /** | 1024 /** |
| 968 * Called when the renderer closes the Mojo connection. | 1025 * Called when the renderer closes the Mojo connection. |
| 969 */ | 1026 */ |
| 970 @Override | 1027 @Override |
| 971 public void close() { | 1028 public void close() { |
| 972 if (mClient == null) return; | 1029 if (mClient == null) return; |
| 973 closeClient(); | 1030 closeClient(); |
| 974 closeUI(true); | 1031 closeUI(true); |
| 975 recordAbortReasonHistogram(PaymentRequestMetrics.ABORT_REASON_MOJO_RENDE
RER_CLOSING); | 1032 recordAbortReasonHistogram(PaymentRequestMetrics.ABORT_REASON_MOJO_RENDE
RER_CLOSING); |
| 976 } | 1033 } |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1032 // > Complete autofill instruments. | 1089 // > Complete autofill instruments. |
| 1033 // > Incomplete autofill instruments. | 1090 // > Incomplete autofill instruments. |
| 1034 Collections.sort(mPendingAutofillInstruments, COMPLETENESS_COMPARATOR); | 1091 Collections.sort(mPendingAutofillInstruments, COMPLETENESS_COMPARATOR); |
| 1035 mPendingInstruments.addAll(mPendingAutofillInstruments); | 1092 mPendingInstruments.addAll(mPendingAutofillInstruments); |
| 1036 | 1093 |
| 1037 // Log the number of suggested credit cards. | 1094 // Log the number of suggested credit cards. |
| 1038 mJourneyLogger.setNumberOfSuggestionsShown(PaymentRequestJourneyLogger.S
ECTION_CREDIT_CARDS, | 1095 mJourneyLogger.setNumberOfSuggestionsShown(PaymentRequestJourneyLogger.S
ECTION_CREDIT_CARDS, |
| 1039 mPendingAutofillInstruments.size()); | 1096 mPendingAutofillInstruments.size()); |
| 1040 | 1097 |
| 1041 mPendingAutofillInstruments.clear(); | 1098 mPendingAutofillInstruments.clear(); |
| 1042 mPendingAutofillInstruments = null; | |
| 1043 | 1099 |
| 1044 // Pre-select the first instrument on the list, if it is complete. | 1100 // Pre-select the first instrument on the list, if it is complete. |
| 1045 int selection = SectionInformation.NO_SELECTION; | 1101 int selection = SectionInformation.NO_SELECTION; |
| 1046 if (!mPendingInstruments.isEmpty()) { | 1102 if (!mPendingInstruments.isEmpty()) { |
| 1047 PaymentInstrument first = mPendingInstruments.get(0); | 1103 PaymentInstrument first = mPendingInstruments.get(0); |
| 1048 if (!(first instanceof AutofillPaymentInstrument) | 1104 if (!(first instanceof AutofillPaymentInstrument) |
| 1049 || ((AutofillPaymentInstrument) first).isComplete()) { | 1105 || ((AutofillPaymentInstrument) first).isComplete()) { |
| 1050 selection = 0; | 1106 selection = 0; |
| 1051 } | 1107 } |
| 1052 } | 1108 } |
| 1053 | 1109 |
| 1054 if (mQueriedCanMakeActivePayment) { | 1110 ActivePaymentQuery query = sCanMakeActivePaymentQueries.get(mOrigin); |
| 1055 mQueriedCanMakeActivePayment = false; | 1111 if (query != null) query.setResponse(selection == 0); |
| 1056 mClient.onCanMakeActivePayment(selection == 0 | |
| 1057 ? ActivePaymentQueryResult.CAN_MAKE_ACTIVE_PAYMENT | |
| 1058 : ActivePaymentQueryResult.CANNOT_MAKE_ACTIVE_PAYMEN
T); | |
| 1059 if (sObserverForTest != null) { | |
| 1060 sObserverForTest.onPaymentRequestServiceActivePaymentQueryRespon
ded(); | |
| 1061 } | |
| 1062 } | |
| 1063 | 1112 |
| 1064 // The list of payment instruments is ready to display. | 1113 // The list of payment instruments is ready to display. |
| 1065 mPaymentMethodsSection = new SectionInformation(PaymentRequestUI.TYPE_PA
YMENT_METHODS, | 1114 mPaymentMethodsSection = new SectionInformation(PaymentRequestUI.TYPE_PA
YMENT_METHODS, |
| 1066 selection, mPendingInstruments); | 1115 selection, mPendingInstruments); |
| 1067 | 1116 |
| 1068 mPendingInstruments.clear(); | 1117 mPendingInstruments.clear(); |
| 1069 | 1118 |
| 1070 // UI has requested the full list of payment instruments. Provide it now
. | 1119 // UI has requested the full list of payment instruments. Provide it now
. |
| 1071 if (mPaymentInformationCallback != null) providePaymentInformation(); | 1120 if (mPaymentInformationCallback != null) providePaymentInformation(); |
| 1072 } | 1121 } |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1242 "PaymentRequest.CheckoutFunnel.Aborted", abortReason, | 1291 "PaymentRequest.CheckoutFunnel.Aborted", abortReason, |
| 1243 PaymentRequestMetrics.ABORT_REASON_MAX); | 1292 PaymentRequestMetrics.ABORT_REASON_MAX); |
| 1244 | 1293 |
| 1245 if (abortReason == PaymentRequestMetrics.ABORT_REASON_ABORTED_BY_USER) { | 1294 if (abortReason == PaymentRequestMetrics.ABORT_REASON_ABORTED_BY_USER) { |
| 1246 mJourneyLogger.recordJourneyStatsHistograms("UserAborted"); | 1295 mJourneyLogger.recordJourneyStatsHistograms("UserAborted"); |
| 1247 } else { | 1296 } else { |
| 1248 mJourneyLogger.recordJourneyStatsHistograms("OtherAborted"); | 1297 mJourneyLogger.recordJourneyStatsHistograms("OtherAborted"); |
| 1249 } | 1298 } |
| 1250 } | 1299 } |
| 1251 } | 1300 } |
| OLD | NEW |