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 21 matching lines...) Expand all Loading... |
32 import org.chromium.chrome.browser.tab.Tab; | 32 import org.chromium.chrome.browser.tab.Tab; |
33 import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver; | 33 import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver; |
34 import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver; | 34 import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver; |
35 import org.chromium.chrome.browser.tabmodel.TabModel; | 35 import org.chromium.chrome.browser.tabmodel.TabModel; |
36 import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType; | 36 import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType; |
37 import org.chromium.chrome.browser.tabmodel.TabModelObserver; | 37 import org.chromium.chrome.browser.tabmodel.TabModelObserver; |
38 import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver; | 38 import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver; |
39 import org.chromium.components.url_formatter.UrlFormatter; | 39 import org.chromium.components.url_formatter.UrlFormatter; |
40 import org.chromium.content_public.browser.WebContents; | 40 import org.chromium.content_public.browser.WebContents; |
41 import org.chromium.mojo.system.MojoException; | 41 import org.chromium.mojo.system.MojoException; |
42 import org.chromium.payments.mojom.ActivePaymentQueryResult; | 42 import org.chromium.payments.mojom.CanMakePaymentQueryResult; |
43 import org.chromium.payments.mojom.PaymentComplete; | 43 import org.chromium.payments.mojom.PaymentComplete; |
44 import org.chromium.payments.mojom.PaymentDetails; | 44 import org.chromium.payments.mojom.PaymentDetails; |
45 import org.chromium.payments.mojom.PaymentErrorReason; | 45 import org.chromium.payments.mojom.PaymentErrorReason; |
46 import org.chromium.payments.mojom.PaymentItem; | 46 import org.chromium.payments.mojom.PaymentItem; |
47 import org.chromium.payments.mojom.PaymentMethodData; | 47 import org.chromium.payments.mojom.PaymentMethodData; |
48 import org.chromium.payments.mojom.PaymentOptions; | 48 import org.chromium.payments.mojom.PaymentOptions; |
49 import org.chromium.payments.mojom.PaymentRequest; | 49 import org.chromium.payments.mojom.PaymentRequest; |
50 import org.chromium.payments.mojom.PaymentRequestClient; | 50 import org.chromium.payments.mojom.PaymentRequestClient; |
51 import org.chromium.payments.mojom.PaymentResponse; | 51 import org.chromium.payments.mojom.PaymentResponse; |
52 import org.chromium.payments.mojom.PaymentShippingOption; | 52 import org.chromium.payments.mojom.PaymentShippingOption; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
94 * Called when a show request failed. This can happen when: | 94 * Called when a show request failed. This can happen when: |
95 * <ul> | 95 * <ul> |
96 * <li>The merchant requests only unsupported payment methods.</li> | 96 * <li>The merchant requests only unsupported payment methods.</li> |
97 * <li>The merchant requests only payment methods that don't have inst
ruments and are not | 97 * <li>The merchant requests only payment methods that don't have inst
ruments and are not |
98 * able to add instruments from PaymentRequest UI.</li> | 98 * able to add instruments from PaymentRequest UI.</li> |
99 * </ul> | 99 * </ul> |
100 */ | 100 */ |
101 void onPaymentRequestServiceShowFailed(); | 101 void onPaymentRequestServiceShowFailed(); |
102 | 102 |
103 /** | 103 /** |
104 * Called when the canMakeActivePayment() request has been responded. | 104 * Called when the canMakePayment() request has been responded. |
105 */ | 105 */ |
106 void onPaymentRequestServiceActivePaymentQueryResponded(); | 106 void onPaymentRequestServiceCanMakePaymentQueryResponded(); |
107 } | 107 } |
108 | 108 |
109 /** The object to keep track of cached payment query results. */ | 109 /** The object to keep track of cached payment query results. */ |
110 private static class ActivePaymentQuery { | 110 private static class CanMakePaymentQuery { |
111 private final Set<PaymentRequestImpl> mObservers = new HashSet<>(); | 111 private final Set<PaymentRequestImpl> mObservers = new HashSet<>(); |
112 private final Set<String> mMethods; | 112 private final Set<String> mMethods; |
113 private Boolean mResponse; | 113 private Boolean mResponse; |
114 | 114 |
115 /** | 115 /** |
116 * Keeps track of an active payment query. | 116 * Keeps track of a payment query. |
117 * | 117 * |
118 * @param methods The payment methods that are being queried. | 118 * @param methods The payment methods that are being queried. |
119 */ | 119 */ |
120 public ActivePaymentQuery(Set<String> methods) { | 120 public CanMakePaymentQuery(Set<String> methods) { |
121 assert methods != null; | 121 assert methods != null; |
122 mMethods = methods; | 122 mMethods = methods; |
123 } | 123 } |
124 | 124 |
125 /** | 125 /** |
126 * Checks whether the given payment methods matches the previously queri
ed payment methods. | 126 * Checks whether the given payment methods matches the previously queri
ed payment methods. |
127 * | 127 * |
128 * @param methods The payment methods that are being queried. | 128 * @param methods The payment methods that are being queried. |
129 * @return True if the given methods match the previously queried paymen
t methods. | 129 * @return True if the given methods match the previously queried paymen
t methods. |
130 */ | 130 */ |
131 public boolean matchesPaymentMethods(Set<String> methods) { | 131 public boolean matchesPaymentMethods(Set<String> methods) { |
132 return mMethods.equals(methods); | 132 return mMethods.equals(methods); |
133 } | 133 } |
134 | 134 |
135 /** @return Whether active payment can be made, or null if response is n
ot known yet. */ | 135 /** @return Whether payment can be made, or null if response is not know
n yet. */ |
136 public Boolean getPreviousResponse() { | 136 public Boolean getPreviousResponse() { |
137 return mResponse; | 137 return mResponse; |
138 } | 138 } |
139 | 139 |
140 /** @param response Whether active payment can be made. */ | 140 /** @param response Whether payment can be made. */ |
141 public void setResponse(boolean response) { | 141 public void setResponse(boolean response) { |
142 if (mResponse == null) mResponse = response; | 142 if (mResponse == null) mResponse = response; |
143 for (PaymentRequestImpl observer : mObservers) { | 143 for (PaymentRequestImpl observer : mObservers) { |
144 observer.respondActivePaymentQuery(mResponse.booleanValue()); | 144 observer.respondCanMakePaymentQuery(mResponse.booleanValue()); |
145 } | 145 } |
146 mObservers.clear(); | 146 mObservers.clear(); |
147 } | 147 } |
148 | 148 |
149 /** @param observer The observer to notify when the query response is kn
own. */ | 149 /** @param observer The observer to notify when the query response is kn
own. */ |
150 public void addObserver(PaymentRequestImpl observer) { | 150 public void addObserver(PaymentRequestImpl observer) { |
151 mObservers.add(observer); | 151 mObservers.add(observer); |
152 } | 152 } |
153 }; | 153 }; |
154 | 154 |
155 private static final String TAG = "cr_PaymentRequest"; | 155 private static final String TAG = "cr_PaymentRequest"; |
156 private static final String ANDROID_PAY_METHOD_NAME = "https://android.com/p
ay"; | 156 private static final String ANDROID_PAY_METHOD_NAME = "https://android.com/p
ay"; |
157 private static final int SUGGESTIONS_LIMIT = 4; | 157 private static final int SUGGESTIONS_LIMIT = 4; |
158 private static final Comparator<Completable> COMPLETENESS_COMPARATOR = | 158 private static final Comparator<Completable> COMPLETENESS_COMPARATOR = |
159 new Comparator<Completable>() { | 159 new Comparator<Completable>() { |
160 @Override | 160 @Override |
161 public int compare(Completable a, Completable b) { | 161 public int compare(Completable a, Completable b) { |
162 return (b.isComplete() ? 1 : 0) - (a.isComplete() ? 1 : 0); | 162 return (b.isComplete() ? 1 : 0) - (a.isComplete() ? 1 : 0); |
163 } | 163 } |
164 }; | 164 }; |
165 | 165 |
166 /** Every origin can call canMakeActivePayment() every 30 minutes. */ | 166 /** Every origin can call canMakePayment() every 30 minutes. */ |
167 private static final int CAN_MAKE_ACTIVE_PAYMENT_QUERY_PERIOD_MS = 30 * 60 *
1000; | 167 private static final int CAN_MAKE_PAYMENT_QUERY_PERIOD_MS = 30 * 60 * 1000; |
168 | 168 |
169 private static PaymentRequestServiceObserverForTest sObserverForTest; | 169 private static PaymentRequestServiceObserverForTest sObserverForTest; |
170 | 170 |
171 /** True if show() was called in any PaymentRequestImpl object. */ | 171 /** True if show() was called in any PaymentRequestImpl object. */ |
172 private static boolean sIsShowing; | 172 private static boolean sIsShowing; |
173 | 173 |
174 /** | 174 /** |
175 * In-memory mapping of the origins of websites that have recently called ca
nMakeActivePayment() | 175 * In-memory mapping of the origins of websites that have recently called ca
nMakePayment() |
176 * to the list of the payment methods that were been queried. Used for throt
tling the usage of | 176 * to the list of the payment methods that were been queried. Used for throt
tling the usage of |
177 * this call. The mapping is shared among all instances of PaymentRequestImp
l in the browser | 177 * this call. The mapping is shared among all instances of PaymentRequestImp
l in the browser |
178 * process on UI thread. The user can reset the throttling mechanism by rest
arting the browser. | 178 * process on UI thread. The user can reset the throttling mechanism by rest
arting the browser. |
179 */ | 179 */ |
180 private static Map<String, ActivePaymentQuery> sCanMakeActivePaymentQueries; | 180 private static Map<String, CanMakePaymentQuery> sCanMakePaymentQueries; |
181 | 181 |
182 /** Monitors changes in the TabModelSelector. */ | 182 /** Monitors changes in the TabModelSelector. */ |
183 private final TabModelSelectorObserver mSelectorObserver = new EmptyTabModel
SelectorObserver() { | 183 private final TabModelSelectorObserver mSelectorObserver = new EmptyTabModel
SelectorObserver() { |
184 @Override | 184 @Override |
185 public void onTabModelSelected(TabModel newModel, TabModel oldModel) { | 185 public void onTabModelSelected(TabModel newModel, TabModel oldModel) { |
186 onDismiss(); | 186 onDismiss(); |
187 } | 187 } |
188 }; | 188 }; |
189 | 189 |
190 /** Monitors changes in the current TabModel. */ | 190 /** Monitors changes in the current TabModel. */ |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 private List<PaymentApp> mPendingApps; | 243 private List<PaymentApp> mPendingApps; |
244 private List<PaymentInstrument> mPendingInstruments; | 244 private List<PaymentInstrument> mPendingInstruments; |
245 private List<PaymentInstrument> mPendingAutofillInstruments; | 245 private List<PaymentInstrument> mPendingAutofillInstruments; |
246 private SectionInformation mPaymentMethodsSection; | 246 private SectionInformation mPaymentMethodsSection; |
247 private PaymentRequestUI mUI; | 247 private PaymentRequestUI mUI; |
248 private Callback<PaymentInformation> mPaymentInformationCallback; | 248 private Callback<PaymentInformation> mPaymentInformationCallback; |
249 private boolean mPaymentAppRunning; | 249 private boolean mPaymentAppRunning; |
250 private boolean mMerchantSupportsAutofillPaymentInstruments; | 250 private boolean mMerchantSupportsAutofillPaymentInstruments; |
251 private ContactEditor mContactEditor; | 251 private ContactEditor mContactEditor; |
252 private boolean mHasRecordedAbortReason; | 252 private boolean mHasRecordedAbortReason; |
253 private boolean mQueriedCanMakeActivePayment; | 253 private boolean mQueriedCanMakePayment; |
254 private CurrencyStringFormatter mFormatter; | 254 private CurrencyStringFormatter mFormatter; |
255 | 255 |
256 /** True if any of the requested payment methods are supported. */ | 256 /** True if any of the requested payment methods are supported. */ |
257 private boolean mArePaymentMethodsSupported; | 257 private boolean mArePaymentMethodsSupported; |
258 | 258 |
259 /** The helper to create and fill the response to send to the merchant. */ | 259 /** The helper to create and fill the response to send to the merchant. */ |
260 private PaymentResponseHelper mPaymentResponseHelper; | 260 private PaymentResponseHelper mPaymentResponseHelper; |
261 | 261 |
262 /** | 262 /** |
263 * Builds the PaymentRequest service implementation. | 263 * Builds the PaymentRequest service implementation. |
(...skipping 28 matching lines...) Expand all Loading... |
292 } | 292 } |
293 mUI.setTitleBitmap(bitmap); | 293 mUI.setTitleBitmap(bitmap); |
294 } | 294 } |
295 }); | 295 }); |
296 | 296 |
297 mApps = PaymentAppFactory.create(mContext, webContents); | 297 mApps = PaymentAppFactory.create(mContext, webContents); |
298 | 298 |
299 mAddressEditor = new AddressEditor(); | 299 mAddressEditor = new AddressEditor(); |
300 mCardEditor = new CardEditor(webContents, mAddressEditor, sObserverForTe
st); | 300 mCardEditor = new CardEditor(webContents, mAddressEditor, sObserverForTe
st); |
301 | 301 |
302 if (sCanMakeActivePaymentQueries == null) sCanMakeActivePaymentQueries =
new ArrayMap<>(); | 302 if (sCanMakePaymentQueries == null) sCanMakePaymentQueries = new ArrayMa
p<>(); |
303 | 303 |
304 recordSuccessFunnelHistograms("Initiated"); | 304 recordSuccessFunnelHistograms("Initiated"); |
305 } | 305 } |
306 | 306 |
307 /** | 307 /** |
308 * Called by the merchant website to initialize the payment request data. | 308 * Called by the merchant website to initialize the payment request data. |
309 */ | 309 */ |
310 @Override | 310 @Override |
311 public void init(PaymentRequestClient client, PaymentMethodData[] methodData
, | 311 public void init(PaymentRequestClient client, PaymentMethodData[] methodData
, |
312 PaymentDetails details, PaymentOptions options) { | 312 PaymentDetails details, PaymentOptions options) { |
(...skipping 722 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1035 public void complete(int result) { | 1035 public void complete(int result) { |
1036 if (mClient == null) return; | 1036 if (mClient == null) return; |
1037 recordSuccessFunnelHistograms("Completed"); | 1037 recordSuccessFunnelHistograms("Completed"); |
1038 closeUI(PaymentComplete.FAIL != result); | 1038 closeUI(PaymentComplete.FAIL != result); |
1039 } | 1039 } |
1040 | 1040 |
1041 /** | 1041 /** |
1042 * Called by the merchant website to check if the user has complete payment
instruments. | 1042 * Called by the merchant website to check if the user has complete payment
instruments. |
1043 */ | 1043 */ |
1044 @Override | 1044 @Override |
1045 public void canMakeActivePayment() { | 1045 public void canMakePayment() { |
1046 if (mClient == null) return; | 1046 if (mClient == null) return; |
1047 | 1047 |
1048 ActivePaymentQuery query = sCanMakeActivePaymentQueries.get(mOrigin); | 1048 CanMakePaymentQuery query = sCanMakePaymentQueries.get(mOrigin); |
1049 if (query == null) { | 1049 if (query == null) { |
1050 query = new ActivePaymentQuery(mMethodData.keySet()); | 1050 query = new CanMakePaymentQuery(mMethodData.keySet()); |
1051 sCanMakeActivePaymentQueries.put(mOrigin, query); | 1051 sCanMakePaymentQueries.put(mOrigin, query); |
1052 mHandler.postDelayed(new Runnable() { | 1052 mHandler.postDelayed(new Runnable() { |
1053 @Override | 1053 @Override |
1054 public void run() { | 1054 public void run() { |
1055 sCanMakeActivePaymentQueries.remove(mOrigin); | 1055 sCanMakePaymentQueries.remove(mOrigin); |
1056 } | 1056 } |
1057 }, CAN_MAKE_ACTIVE_PAYMENT_QUERY_PERIOD_MS); | 1057 }, CAN_MAKE_PAYMENT_QUERY_PERIOD_MS); |
1058 } | 1058 } |
1059 | 1059 |
1060 if (!query.matchesPaymentMethods(mMethodData.keySet())) { | 1060 if (!query.matchesPaymentMethods(mMethodData.keySet())) { |
1061 mClient.onCanMakeActivePayment(ActivePaymentQueryResult.QUERY_QUOTA_
EXCEEDED); | 1061 mClient.onCanMakePayment(CanMakePaymentQueryResult.QUERY_QUOTA_EXCEE
DED); |
1062 if (sObserverForTest != null) { | 1062 if (sObserverForTest != null) { |
1063 sObserverForTest.onPaymentRequestServiceActivePaymentQueryRespon
ded(); | 1063 sObserverForTest.onPaymentRequestServiceCanMakePaymentQueryRespo
nded(); |
1064 } | 1064 } |
1065 return; | 1065 return; |
1066 } | 1066 } |
1067 | 1067 |
1068 if (query.getPreviousResponse() != null) { | 1068 if (query.getPreviousResponse() != null) { |
1069 respondActivePaymentQuery(query.getPreviousResponse().booleanValue()
); | 1069 respondCanMakePaymentQuery(query.getPreviousResponse().booleanValue(
)); |
1070 return; | 1070 return; |
1071 } | 1071 } |
1072 | 1072 |
1073 query.addObserver(this); | 1073 query.addObserver(this); |
1074 if (mPendingApps.isEmpty() && mPendingInstruments.isEmpty()) { | 1074 if (mPendingApps.isEmpty() && mPendingInstruments.isEmpty()) { |
1075 query.setResponse(mPaymentMethodsSection != null | 1075 query.setResponse(mPaymentMethodsSection != null |
1076 && mPaymentMethodsSection.getSelectedItem() != null); | 1076 && mPaymentMethodsSection.getSelectedItem() != null); |
1077 } | 1077 } |
1078 } | 1078 } |
1079 | 1079 |
1080 private void respondActivePaymentQuery(boolean response) { | 1080 private void respondCanMakePaymentQuery(boolean response) { |
1081 mClient.onCanMakeActivePayment(response | 1081 mClient.onCanMakePayment(response |
1082 ? ActivePaymentQueryResult.CAN_MAKE_ACTIVE_PAYMENT | 1082 ? CanMakePaymentQueryResult.CAN_MAKE_PAYMENT |
1083 : ActivePaymentQueryResult.CANNOT_MAKE_ACTIVE_PAYMENT); | 1083 : CanMakePaymentQueryResult.CANNOT_MAKE_PAYMENT); |
1084 if (sObserverForTest != null) { | 1084 if (sObserverForTest != null) { |
1085 sObserverForTest.onPaymentRequestServiceActivePaymentQueryResponded(
); | 1085 sObserverForTest.onPaymentRequestServiceCanMakePaymentQueryResponded
(); |
1086 } | 1086 } |
1087 } | 1087 } |
1088 | 1088 |
1089 /** | 1089 /** |
1090 * Called when the renderer closes the Mojo connection. | 1090 * Called when the renderer closes the Mojo connection. |
1091 */ | 1091 */ |
1092 @Override | 1092 @Override |
1093 public void close() { | 1093 public void close() { |
1094 if (mClient == null) return; | 1094 if (mClient == null) return; |
1095 closeClient(); | 1095 closeClient(); |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1167 // Pre-select the first instrument on the list, if it is complete. | 1167 // Pre-select the first instrument on the list, if it is complete. |
1168 int selection = SectionInformation.NO_SELECTION; | 1168 int selection = SectionInformation.NO_SELECTION; |
1169 if (!mPendingInstruments.isEmpty()) { | 1169 if (!mPendingInstruments.isEmpty()) { |
1170 PaymentInstrument first = mPendingInstruments.get(0); | 1170 PaymentInstrument first = mPendingInstruments.get(0); |
1171 if (!(first instanceof AutofillPaymentInstrument) | 1171 if (!(first instanceof AutofillPaymentInstrument) |
1172 || ((AutofillPaymentInstrument) first).isComplete()) { | 1172 || ((AutofillPaymentInstrument) first).isComplete()) { |
1173 selection = 0; | 1173 selection = 0; |
1174 } | 1174 } |
1175 } | 1175 } |
1176 | 1176 |
1177 ActivePaymentQuery query = sCanMakeActivePaymentQueries.get(mOrigin); | 1177 CanMakePaymentQuery query = sCanMakePaymentQueries.get(mOrigin); |
1178 if (query != null) query.setResponse(selection == 0); | 1178 if (query != null) query.setResponse(selection == 0); |
1179 | 1179 |
1180 // The list of payment instruments is ready to display. | 1180 // The list of payment instruments is ready to display. |
1181 mPaymentMethodsSection = new SectionInformation(PaymentRequestUI.TYPE_PA
YMENT_METHODS, | 1181 mPaymentMethodsSection = new SectionInformation(PaymentRequestUI.TYPE_PA
YMENT_METHODS, |
1182 selection, mPendingInstruments); | 1182 selection, mPendingInstruments); |
1183 | 1183 |
1184 mPendingInstruments.clear(); | 1184 mPendingInstruments.clear(); |
1185 | 1185 |
1186 updateInstrumentModifiedTotals(); | 1186 updateInstrumentModifiedTotals(); |
1187 | 1187 |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1381 "PaymentRequest.CheckoutFunnel.Aborted", abortReason, | 1381 "PaymentRequest.CheckoutFunnel.Aborted", abortReason, |
1382 PaymentRequestMetrics.ABORT_REASON_MAX); | 1382 PaymentRequestMetrics.ABORT_REASON_MAX); |
1383 | 1383 |
1384 if (abortReason == PaymentRequestMetrics.ABORT_REASON_ABORTED_BY_USER) { | 1384 if (abortReason == PaymentRequestMetrics.ABORT_REASON_ABORTED_BY_USER) { |
1385 mJourneyLogger.recordJourneyStatsHistograms("UserAborted"); | 1385 mJourneyLogger.recordJourneyStatsHistograms("UserAborted"); |
1386 } else { | 1386 } else { |
1387 mJourneyLogger.recordJourneyStatsHistograms("OtherAborted"); | 1387 mJourneyLogger.recordJourneyStatsHistograms("OtherAborted"); |
1388 } | 1388 } |
1389 } | 1389 } |
1390 } | 1390 } |
OLD | NEW |