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.text.TextUtils; | 10 import android.text.TextUtils; |
(...skipping 11 matching lines...) Expand all Loading... | |
22 import org.chromium.chrome.browser.preferences.PreferencesLauncher; | 22 import org.chromium.chrome.browser.preferences.PreferencesLauncher; |
23 import org.chromium.chrome.browser.preferences.autofill.AutofillCreditCardEditor ; | 23 import org.chromium.chrome.browser.preferences.autofill.AutofillCreditCardEditor ; |
24 import org.chromium.chrome.browser.preferences.autofill.AutofillProfileEditor; | 24 import org.chromium.chrome.browser.preferences.autofill.AutofillProfileEditor; |
25 import org.chromium.chrome.browser.profiles.Profile; | 25 import org.chromium.chrome.browser.profiles.Profile; |
26 import org.chromium.chrome.browser.util.UrlUtilities; | 26 import org.chromium.chrome.browser.util.UrlUtilities; |
27 import org.chromium.content.browser.ContentViewCore; | 27 import org.chromium.content.browser.ContentViewCore; |
28 import org.chromium.content_public.browser.WebContents; | 28 import org.chromium.content_public.browser.WebContents; |
29 import org.chromium.mojo.system.MojoException; | 29 import org.chromium.mojo.system.MojoException; |
30 import org.chromium.mojom.payments.PaymentDetails; | 30 import org.chromium.mojom.payments.PaymentDetails; |
31 import org.chromium.mojom.payments.PaymentItem; | 31 import org.chromium.mojom.payments.PaymentItem; |
32 import org.chromium.mojom.payments.PaymentMethodData; | |
32 import org.chromium.mojom.payments.PaymentOptions; | 33 import org.chromium.mojom.payments.PaymentOptions; |
33 import org.chromium.mojom.payments.PaymentRequest; | 34 import org.chromium.mojom.payments.PaymentRequest; |
34 import org.chromium.mojom.payments.PaymentRequestClient; | 35 import org.chromium.mojom.payments.PaymentRequestClient; |
35 import org.chromium.mojom.payments.PaymentResponse; | 36 import org.chromium.mojom.payments.PaymentResponse; |
36 import org.chromium.mojom.payments.ShippingOption; | 37 import org.chromium.mojom.payments.ShippingOption; |
37 import org.chromium.ui.base.WindowAndroid; | 38 import org.chromium.ui.base.WindowAndroid; |
38 import org.json.JSONException; | 39 import org.json.JSONException; |
39 import org.json.JSONObject; | 40 import org.json.JSONObject; |
40 | 41 |
41 import java.util.ArrayList; | 42 import java.util.ArrayList; |
42 import java.util.Arrays; | 43 import java.util.Arrays; |
43 import java.util.HashSet; | 44 import java.util.HashMap; |
44 import java.util.Iterator; | |
45 import java.util.List; | 45 import java.util.List; |
46 import java.util.Locale; | 46 import java.util.Locale; |
47 import java.util.Set; | 47 import java.util.Set; |
48 import java.util.regex.Pattern; | 48 import java.util.regex.Pattern; |
49 | 49 |
50 /** | 50 /** |
51 * Android implementation of the PaymentRequest service defined in | 51 * Android implementation of the PaymentRequest service defined in |
52 * third_party/WebKit/public/platform/modules/payments/payment_request.mojom. | 52 * third_party/WebKit/public/platform/modules/payments/payment_request.mojom. |
53 */ | 53 */ |
54 public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie nt, | 54 public class PaymentRequestImpl implements PaymentRequest, PaymentRequestUI.Clie nt, |
55 PaymentApp.InstrumentsCallback, PaymentInstrument.DetailsCallback { | 55 PaymentApp.InstrumentsCallback, PaymentInstrument.DetailsCallback { |
56 /** | 56 /** |
57 * The size for the favicon in density-independent pixels. | 57 * The size for the favicon in density-independent pixels. |
58 */ | 58 */ |
59 private static final int FAVICON_SIZE_DP = 24; | 59 private static final int FAVICON_SIZE_DP = 24; |
60 | 60 |
61 private static final String TAG = "cr_PaymentRequest"; | 61 private static final String TAG = "cr_PaymentRequest"; |
62 | 62 |
63 private final Handler mHandler = new Handler(); | 63 private final Handler mHandler = new Handler(); |
64 | 64 |
65 private Activity mContext; | 65 private Activity mContext; |
66 private String mMerchantName; | 66 private String mMerchantName; |
67 private String mOrigin; | 67 private String mOrigin; |
68 private Bitmap mFavicon; | 68 private Bitmap mFavicon; |
69 private List<PaymentApp> mApps; | 69 private List<PaymentApp> mApps; |
70 private PaymentRequestClient mClient; | 70 private PaymentRequestClient mClient; |
71 private Set<String> mSupportedMethods; | 71 private HashMap<String, JSONObject> mMethodData; |
72 private List<LineItem> mLineItems; | 72 private List<LineItem> mLineItems; |
73 private List<PaymentItem> mDisplayItems; | 73 private List<PaymentItem> mDisplayItems; |
74 private List<ShippingOption> mShippingOptions; | 74 private List<ShippingOption> mShippingOptions; |
75 private SectionInformation mShippingOptionsSection; | 75 private SectionInformation mShippingOptionsSection; |
76 private JSONObject mData; | |
77 private SectionInformation mShippingAddressesSection; | 76 private SectionInformation mShippingAddressesSection; |
78 private List<PaymentApp> mPendingApps; | 77 private List<PaymentApp> mPendingApps; |
79 private List<PaymentInstrument> mPendingInstruments; | 78 private List<PaymentInstrument> mPendingInstruments; |
80 private SectionInformation mPaymentMethodsSection; | 79 private SectionInformation mPaymentMethodsSection; |
81 private PaymentRequestUI mUI; | 80 private PaymentRequestUI mUI; |
82 private Callback<PaymentInformation> mPaymentInformationCallback; | 81 private Callback<PaymentInformation> mPaymentInformationCallback; |
83 private Pattern mRegionCodePattern; | 82 private Pattern mRegionCodePattern; |
84 private boolean mMerchantNeedsShippingAddress; | 83 private boolean mMerchantNeedsShippingAddress; |
85 | 84 |
86 /** | 85 /** |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
138 | 137 |
139 if (mContext == null) { | 138 if (mContext == null) { |
140 disconnectFromClientWithDebugMessage("Web contents don't have associ ated activity"); | 139 disconnectFromClientWithDebugMessage("Web contents don't have associ ated activity"); |
141 } | 140 } |
142 } | 141 } |
143 | 142 |
144 /** | 143 /** |
145 * Called by the merchant website to show the payment request to the user. | 144 * Called by the merchant website to show the payment request to the user. |
146 */ | 145 */ |
147 @Override | 146 @Override |
148 public void show(String[] supportedMethods, PaymentDetails details, PaymentO ptions options, | 147 public void show(PaymentMethodData[] methodData, PaymentDetails details, |
149 String stringifiedData) { | 148 PaymentOptions options) { |
150 if (mClient == null) return; | 149 if (mClient == null) return; |
151 | 150 |
152 if (mSupportedMethods != null) { | 151 if (mMethodData != null) { |
153 disconnectFromClientWithDebugMessage("PaymentRequest.show() called m ore than once."); | 152 disconnectFromClientWithDebugMessage("PaymentRequest.show() called m ore than once."); |
154 return; | 153 return; |
155 } | 154 } |
156 | 155 |
157 mSupportedMethods = getValidatedSupportedMethods(supportedMethods); | 156 mMethodData = getValidatedMethodData(methodData); |
158 if (mSupportedMethods == null) { | 157 if (mMethodData == null) { |
159 disconnectFromClientWithDebugMessage("Invalid payment methods"); | 158 disconnectFromClientWithDebugMessage("Invalid payment methods or dat a"); |
160 return; | 159 return; |
161 } | 160 } |
162 | 161 |
163 if (!setLineItemsAndShippingOptionsOrDisconnectFromClient(details)) retu rn; | 162 if (!setLineItemsAndShippingOptionsOrDisconnectFromClient(details)) retu rn; |
164 | 163 |
165 // If the merchant requests shipping and does not provide shipping optio ns here, then the | 164 // If the merchant requests shipping and does not provide shipping optio ns here, then the |
166 // merchant needs the shipping address to calculate shipping price and a vailability. | 165 // merchant needs the shipping address to calculate shipping price and a vailability. |
167 boolean requestShipping = options != null && options.requestShipping; | 166 boolean requestShipping = options != null && options.requestShipping; |
168 mMerchantNeedsShippingAddress = requestShipping && mShippingOptionsSecti on.isEmpty(); | 167 mMerchantNeedsShippingAddress = requestShipping && mShippingOptionsSecti on.isEmpty(); |
169 | 168 |
170 mData = getValidatedData(mSupportedMethods, stringifiedData); | |
171 if (mData == null) { | |
172 disconnectFromClientWithDebugMessage("Invalid payment method specifi c data"); | |
173 return; | |
174 } | |
175 | |
176 List<AutofillAddress> addresses = new ArrayList<>(); | 169 List<AutofillAddress> addresses = new ArrayList<>(); |
177 List<AutofillProfile> profiles = PersonalDataManager.getInstance().getAd dressOnlyProfiles(); | 170 List<AutofillProfile> profiles = PersonalDataManager.getInstance().getAd dressOnlyProfiles(); |
178 for (int i = 0; i < profiles.size(); i++) { | 171 for (int i = 0; i < profiles.size(); i++) { |
179 AutofillProfile profile = profiles.get(i); | 172 AutofillProfile profile = profiles.get(i); |
180 if (profile.getCountryCode() != null | 173 if (profile.getCountryCode() != null |
181 && mRegionCodePattern.matcher(profile.getCountryCode()).matc hes() | 174 && mRegionCodePattern.matcher(profile.getCountryCode()).matc hes() |
182 && profile.getStreetAddress() != null && profile.getRegion() != null | 175 && profile.getStreetAddress() != null && profile.getRegion() != null |
183 && profile.getLocality() != null && profile.getDependentLoca lity() != null | 176 && profile.getLocality() != null && profile.getDependentLoca lity() != null |
184 && profile.getPostalCode() != null && profile.getSortingCode () != null | 177 && profile.getPostalCode() != null && profile.getSortingCode () != null |
185 && profile.getCompanyName() != null && profile.getFullName() != null) { | 178 && profile.getCompanyName() != null && profile.getFullName() != null) { |
186 addresses.add(new AutofillAddress(profile)); | 179 addresses.add(new AutofillAddress(profile)); |
187 } | 180 } |
188 } | 181 } |
189 | 182 |
190 int selectedIndex = SectionInformation.NO_SELECTION; | 183 int selectedIndex = SectionInformation.NO_SELECTION; |
191 if (!addresses.isEmpty() && mShippingOptionsSection.getSelectedItem() != null) { | 184 if (!addresses.isEmpty() && mShippingOptionsSection.getSelectedItem() != null) { |
192 selectedIndex = 0; | 185 selectedIndex = 0; |
193 } | 186 } |
194 mShippingAddressesSection = new SectionInformation( | 187 mShippingAddressesSection = new SectionInformation( |
195 PaymentRequestUI.TYPE_SHIPPING_ADDRESSES, selectedIndex, address es); | 188 PaymentRequestUI.TYPE_SHIPPING_ADDRESSES, selectedIndex, address es); |
196 | 189 |
197 mPendingApps = new ArrayList<>(mApps); | 190 mPendingApps = new ArrayList<>(mApps); |
198 mPendingInstruments = new ArrayList<>(); | 191 mPendingInstruments = new ArrayList<>(); |
199 boolean isGettingInstruments = false; | 192 boolean isGettingInstruments = false; |
200 | 193 |
201 for (int i = 0; i < mApps.size(); i++) { | 194 for (int i = 0; i < mApps.size(); i++) { |
202 PaymentApp app = mApps.get(i); | 195 PaymentApp app = mApps.get(i); |
203 Set<String> appMethods = app.getSupportedMethodNames(); | 196 Set<String> appMethods = app.getSupportedMethodNames(); |
204 appMethods.retainAll(mSupportedMethods); | 197 appMethods.retainAll(mMethodData.keySet()); |
205 if (appMethods.isEmpty()) { | 198 if (appMethods.isEmpty()) { |
206 mPendingApps.remove(app); | 199 mPendingApps.remove(app); |
207 } else { | 200 } else { |
208 isGettingInstruments = true; | 201 isGettingInstruments = true; |
209 app.getInstruments(mDisplayItems, this); | 202 app.getInstruments(mDisplayItems, this); |
210 } | 203 } |
211 } | 204 } |
212 | 205 |
213 if (!isGettingInstruments) { | 206 if (!isGettingInstruments) { |
214 mPaymentMethodsSection = new SectionInformation(PaymentRequestUI.TYP E_PAYMENT_METHODS); | 207 mPaymentMethodsSection = new SectionInformation(PaymentRequestUI.TYP E_PAYMENT_METHODS); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
258 getValidatedShippingOptions(details.displayItems[0].amount.curre ncyCode, details); | 251 getValidatedShippingOptions(details.displayItems[0].amount.curre ncyCode, details); |
259 if (mShippingOptionsSection == null) { | 252 if (mShippingOptionsSection == null) { |
260 disconnectFromClientWithDebugMessage("Invalid shipping options"); | 253 disconnectFromClientWithDebugMessage("Invalid shipping options"); |
261 return false; | 254 return false; |
262 } | 255 } |
263 mShippingOptions = Arrays.asList(details.shippingOptions); | 256 mShippingOptions = Arrays.asList(details.shippingOptions); |
264 | 257 |
265 return true; | 258 return true; |
266 } | 259 } |
267 | 260 |
268 private HashSet<String> getValidatedSupportedMethods(String[] methods) { | 261 private HashMap<String, JSONObject> getValidatedMethodData(PaymentMethodData [] methodData) { |
269 // Payment methods are required. | 262 // Payment methodData are required. |
270 if (methods == null || methods.length == 0) return null; | 263 if (methodData == null || methodData.length == 0) return null; |
264 HashMap<String, JSONObject> result = new HashMap<>(); | |
265 for (int i = 0; i < methodData.length; i++) { | |
266 JSONObject data; | |
please use gerrit instead
2016/06/03 18:22:28
Simpler:
JSONObject data = null;
if (!TextUtils.i
zino
2016/06/04 00:48:46
Done.
| |
267 if (TextUtils.isEmpty(methodData[i].data)) { | |
268 data = null; | |
269 } else { | |
270 try { | |
271 data = new JSONObject(methodData[i].data); | |
272 } catch (JSONException e) { | |
273 // Payment method specific data should be a JSON object. | |
274 return null; | |
275 } | |
276 } | |
271 | 277 |
272 HashSet<String> result = new HashSet<>(); | 278 String[] methods = methodData[i].supportedMethods; |
273 for (int i = 0; i < methods.length; i++) { | 279 |
274 // Payment methods should be non-empty. | 280 // Payment methods are required. |
275 if (TextUtils.isEmpty(methods[i])) return null; | 281 if (methods == null || methods.length == 0) return null; |
276 result.add(methods[i]); | 282 |
283 for (int j = 0; j < methods.length; j++) { | |
284 // Payment methods should be non-empty. | |
285 if (TextUtils.isEmpty(methods[j])) return null; | |
286 result.put(methods[j], data); | |
287 } | |
277 } | 288 } |
278 | 289 |
279 return result; | 290 return result; |
280 } | 291 } |
281 | 292 |
282 private List<LineItem> getValidatedLineItems(PaymentDetails details) { | 293 private List<LineItem> getValidatedLineItems(PaymentDetails details) { |
283 // Line items are required. | 294 // Line items are required. |
284 if (details == null || details.displayItems == null || details.displayIt ems.length == 0) { | 295 if (details == null || details.displayItems == null || details.displayIt ems.length == 0) { |
285 return null; | 296 return null; |
286 } | 297 } |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
370 for (int i = 0; i < details.shippingOptions.length; i++) { | 381 for (int i = 0; i < details.shippingOptions.length; i++) { |
371 ShippingOption option = details.shippingOptions[i]; | 382 ShippingOption option = details.shippingOptions[i]; |
372 result.add(new PaymentOption(option.id, option.label, | 383 result.add(new PaymentOption(option.id, option.label, |
373 formatter.format(option.amount.value), PaymentOption.NO_ICON )); | 384 formatter.format(option.amount.value), PaymentOption.NO_ICON )); |
374 } | 385 } |
375 | 386 |
376 return new SectionInformation(PaymentRequestUI.TYPE_SHIPPING_OPTIONS, | 387 return new SectionInformation(PaymentRequestUI.TYPE_SHIPPING_OPTIONS, |
377 result.size() == 1 ? 0 : SectionInformation.NO_SELECTION, result ); | 388 result.size() == 1 ? 0 : SectionInformation.NO_SELECTION, result ); |
378 } | 389 } |
379 | 390 |
380 private JSONObject getValidatedData(Set<String> supportedMethods, String str ingifiedData) { | |
381 if (TextUtils.isEmpty(stringifiedData)) return new JSONObject(); | |
382 | |
383 JSONObject result; | |
384 try { | |
385 result = new JSONObject(stringifiedData); | |
386 } catch (JSONException e) { | |
387 // Payment method specific data should be a JSON object. | |
388 return null; | |
389 } | |
390 | |
391 Iterator<String> it = result.keys(); | |
392 while (it.hasNext()) { | |
393 String name = it.next(); | |
394 // Each key should be one of the supported payment methods. | |
395 if (!supportedMethods.contains(name)) return null; | |
396 // Each value should be a JSON object. | |
397 if (result.optJSONObject(name) == null) return null; | |
398 } | |
399 | |
400 return result; | |
401 } | |
402 | |
403 /** | 391 /** |
404 * Called to retrieve the data to show in the initial PaymentRequest UI. | 392 * Called to retrieve the data to show in the initial PaymentRequest UI. |
405 */ | 393 */ |
406 @Override | 394 @Override |
407 public void getDefaultPaymentInformation(Callback<PaymentInformation> callba ck) { | 395 public void getDefaultPaymentInformation(Callback<PaymentInformation> callba ck) { |
408 mPaymentInformationCallback = callback; | 396 mPaymentInformationCallback = callback; |
409 | 397 |
410 if (mPaymentMethodsSection == null) return; | 398 if (mPaymentMethodsSection == null) return; |
411 | 399 |
412 mHandler.post(new Runnable() { | 400 mHandler.post(new Runnable() { |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
484 mContext, AutofillCreditCardEditor.class.getName()); | 472 mContext, AutofillCreditCardEditor.class.getName()); |
485 } | 473 } |
486 } | 474 } |
487 | 475 |
488 @Override | 476 @Override |
489 public void onPayClicked(PaymentOption selectedShippingAddress, | 477 public void onPayClicked(PaymentOption selectedShippingAddress, |
490 PaymentOption selectedShippingOption, PaymentOption selectedPaymentM ethod) { | 478 PaymentOption selectedShippingOption, PaymentOption selectedPaymentM ethod) { |
491 assert selectedPaymentMethod instanceof PaymentInstrument; | 479 assert selectedPaymentMethod instanceof PaymentInstrument; |
492 PaymentInstrument instrument = (PaymentInstrument) selectedPaymentMethod ; | 480 PaymentInstrument instrument = (PaymentInstrument) selectedPaymentMethod ; |
493 instrument.getDetails(mMerchantName, mOrigin, mDisplayItems, | 481 instrument.getDetails(mMerchantName, mOrigin, mDisplayItems, |
494 mData.optJSONObject(instrument.getMethodName()), this); | 482 mMethodData.get(instrument.getMethodName()), this); |
495 } | 483 } |
496 | 484 |
497 @Override | 485 @Override |
498 public void onDismiss() { | 486 public void onDismiss() { |
499 disconnectFromClientWithDebugMessage("Dialog dismissed"); | 487 disconnectFromClientWithDebugMessage("Dialog dismissed"); |
500 closeUI(false); | 488 closeUI(false); |
501 } | 489 } |
502 | 490 |
503 /** | 491 /** |
504 * Called by the merchant website to abort the payment. | 492 * Called by the merchant website to abort the payment. |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
538 /** | 526 /** |
539 * Called after retrieving the list of payment instruments in an app. | 527 * Called after retrieving the list of payment instruments in an app. |
540 */ | 528 */ |
541 @Override | 529 @Override |
542 public void onInstrumentsReady(PaymentApp app, List<PaymentInstrument> instr uments) { | 530 public void onInstrumentsReady(PaymentApp app, List<PaymentInstrument> instr uments) { |
543 mPendingApps.remove(app); | 531 mPendingApps.remove(app); |
544 | 532 |
545 if (instruments != null) { | 533 if (instruments != null) { |
546 for (int i = 0; i < instruments.size(); i++) { | 534 for (int i = 0; i < instruments.size(); i++) { |
547 PaymentInstrument instrument = instruments.get(i); | 535 PaymentInstrument instrument = instruments.get(i); |
548 if (mSupportedMethods.contains(instrument.getMethodName())) { | 536 if (mMethodData.containsKey(instrument.getMethodName())) { |
549 mPendingInstruments.add(instrument); | 537 mPendingInstruments.add(instrument); |
550 } else { | 538 } else { |
551 instrument.dismiss(); | 539 instrument.dismiss(); |
552 } | 540 } |
553 } | 541 } |
554 } | 542 } |
555 | 543 |
556 if (mPendingApps.isEmpty()) { | 544 if (mPendingApps.isEmpty()) { |
557 mPaymentMethodsSection = new SectionInformation( | 545 mPaymentMethodsSection = new SectionInformation( |
558 PaymentRequestUI.TYPE_PAYMENT_METHODS, 0, mPendingInstrument s); | 546 PaymentRequestUI.TYPE_PAYMENT_METHODS, 0, mPendingInstrument s); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
626 } | 614 } |
627 mPaymentMethodsSection = null; | 615 mPaymentMethodsSection = null; |
628 } | 616 } |
629 } | 617 } |
630 | 618 |
631 private void closeClient() { | 619 private void closeClient() { |
632 if (mClient != null) mClient.close(); | 620 if (mClient != null) mClient.close(); |
633 mClient = null; | 621 mClient = null; |
634 } | 622 } |
635 } | 623 } |
OLD | NEW |