| 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 27 matching lines...) Expand all Loading... |
| 38 import org.chromium.mojom.payments.PaymentRequestClient; | 38 import org.chromium.mojom.payments.PaymentRequestClient; |
| 39 import org.chromium.mojom.payments.PaymentResponse; | 39 import org.chromium.mojom.payments.PaymentResponse; |
| 40 import org.chromium.mojom.payments.PaymentShippingOption; | 40 import org.chromium.mojom.payments.PaymentShippingOption; |
| 41 import org.chromium.ui.base.WindowAndroid; | 41 import org.chromium.ui.base.WindowAndroid; |
| 42 import org.json.JSONException; | 42 import org.json.JSONException; |
| 43 import org.json.JSONObject; | 43 import org.json.JSONObject; |
| 44 | 44 |
| 45 import java.io.IOException; | 45 import java.io.IOException; |
| 46 import java.util.ArrayList; | 46 import java.util.ArrayList; |
| 47 import java.util.Arrays; | 47 import java.util.Arrays; |
| 48 import java.util.Collections; |
| 49 import java.util.Comparator; |
| 48 import java.util.HashMap; | 50 import java.util.HashMap; |
| 49 import java.util.HashSet; | 51 import java.util.HashSet; |
| 50 import java.util.List; | 52 import java.util.List; |
| 51 import java.util.Locale; | 53 import java.util.Locale; |
| 52 import java.util.Set; | 54 import java.util.Set; |
| 53 | 55 |
| 54 /** | 56 /** |
| 55 * Android implementation of the PaymentRequest service defined in | 57 * Android implementation of the PaymentRequest service defined in |
| 56 * third_party/WebKit/public/platform/modules/payments/payment_request.mojom. | 58 * third_party/WebKit/public/platform/modules/payments/payment_request.mojom. |
| 57 */ | 59 */ |
| (...skipping 10 matching lines...) Expand all Loading... |
| 68 void onPaymentRequestServiceUnableToAbort(); | 70 void onPaymentRequestServiceUnableToAbort(); |
| 69 } | 71 } |
| 70 | 72 |
| 71 /** | 73 /** |
| 72 * The size for the favicon in density-independent pixels. | 74 * The size for the favicon in density-independent pixels. |
| 73 */ | 75 */ |
| 74 private static final int FAVICON_SIZE_DP = 24; | 76 private static final int FAVICON_SIZE_DP = 24; |
| 75 | 77 |
| 76 private static final String TAG = "cr_PaymentRequest"; | 78 private static final String TAG = "cr_PaymentRequest"; |
| 77 | 79 |
| 80 private static final int SUGGESTIONS_LIMIT = 4; |
| 81 |
| 78 private static PaymentRequestServiceObserverForTest sObserverForTest; | 82 private static PaymentRequestServiceObserverForTest sObserverForTest; |
| 79 | 83 |
| 80 private final Handler mHandler = new Handler(); | 84 private final Handler mHandler = new Handler(); |
| 81 | 85 |
| 82 private Activity mContext; | 86 private Activity mContext; |
| 83 private String mMerchantName; | 87 private String mMerchantName; |
| 84 private String mOrigin; | 88 private String mOrigin; |
| 85 private Bitmap mFavicon; | 89 private Bitmap mFavicon; |
| 86 private List<PaymentApp> mApps; | 90 private List<PaymentApp> mApps; |
| 87 private PaymentRequestClient mClient; | 91 private PaymentRequestClient mClient; |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 201 } | 205 } |
| 202 | 206 |
| 203 mMethodData = getValidatedMethodData(methodData); | 207 mMethodData = getValidatedMethodData(methodData); |
| 204 if (mMethodData == null) { | 208 if (mMethodData == null) { |
| 205 disconnectFromClientWithDebugMessage("Invalid payment methods or dat
a"); | 209 disconnectFromClientWithDebugMessage("Invalid payment methods or dat
a"); |
| 206 return; | 210 return; |
| 207 } | 211 } |
| 208 | 212 |
| 209 if (!parseAndValidateDetailsOrDisconnectFromClient(details)) return; | 213 if (!parseAndValidateDetailsOrDisconnectFromClient(details)) return; |
| 210 | 214 |
| 215 // Create a comparator to sort the suggestions by completeness. |
| 216 Comparator<Completable> completenessComparator = new Comparator<Completa
ble>() { |
| 217 @Override |
| 218 public int compare(Completable a, Completable b) { |
| 219 if (a.isComplete() == b.isComplete()) { |
| 220 return 0; |
| 221 } else if (a.isComplete()) { |
| 222 return -1; |
| 223 } else { |
| 224 return 1; |
| 225 } |
| 226 } |
| 227 }; |
| 228 |
| 211 // If the merchant requests shipping and does not provide a selected shi
pping option, then | 229 // If the merchant requests shipping and does not provide a selected shi
pping option, then |
| 212 // the merchant needs the shipping address to calculate the shipping pri
ce and availability. | 230 // the merchant needs the shipping address to calculate the shipping pri
ce and availability. |
| 213 boolean requestShipping = options != null && options.requestShipping; | 231 boolean requestShipping = options != null && options.requestShipping; |
| 214 mMerchantNeedsShippingAddress = | 232 mMerchantNeedsShippingAddress = |
| 215 requestShipping && mUiShippingOptions.getSelectedItem() == null; | 233 requestShipping && mUiShippingOptions.getSelectedItem() == null; |
| 216 | 234 |
| 217 boolean requestPayerPhone = options != null && options.requestPayerPhone
; | 235 boolean requestPayerPhone = options != null && options.requestPayerPhone
; |
| 218 boolean requestPayerEmail = options != null && options.requestPayerEmail
; | 236 boolean requestPayerEmail = options != null && options.requestPayerEmail
; |
| 219 | 237 |
| 220 List<AutofillProfile> profiles = null; | 238 List<AutofillProfile> profiles = null; |
| 221 if (requestShipping || requestPayerPhone || requestPayerEmail) { | 239 if (requestShipping || requestPayerPhone || requestPayerEmail) { |
| 222 profiles = PersonalDataManager.getInstance().getProfilesToSuggest(); | 240 profiles = PersonalDataManager.getInstance().getProfilesToSuggest(); |
| 223 } | 241 } |
| 224 | 242 |
| 225 if (requestShipping) { | 243 if (requestShipping) { |
| 226 mAddressEditor = new AddressEditor(); | 244 mAddressEditor = new AddressEditor(); |
| 227 List<AutofillAddress> addresses = new ArrayList<>(); | 245 List<AutofillAddress> addresses = new ArrayList<>(); |
| 228 int firstCompleteAddressIndex = SectionInformation.NO_SELECTION; | |
| 229 | 246 |
| 230 for (int i = 0; i < profiles.size(); i++) { | 247 for (int i = 0; i < profiles.size(); i++) { |
| 231 AutofillProfile profile = profiles.get(i); | 248 AutofillProfile profile = profiles.get(i); |
| 232 mAddressEditor.addPhoneNumberIfValid(profile.getPhoneNumber()); | 249 mAddressEditor.addPhoneNumberIfValid(profile.getPhoneNumber()); |
| 233 | 250 |
| 234 boolean isComplete = mAddressEditor.isProfileComplete(profile); | 251 boolean isComplete = mAddressEditor.isProfileComplete(profile); |
| 235 addresses.add(new AutofillAddress(profile, isComplete)); | 252 addresses.add(new AutofillAddress(profile, isComplete)); |
| 236 if (isComplete && firstCompleteAddressIndex == SectionInformatio
n.NO_SELECTION | |
| 237 && !mMerchantNeedsShippingAddress) { | |
| 238 firstCompleteAddressIndex = i; | |
| 239 } | |
| 240 } | 253 } |
| 241 | 254 |
| 242 // The shipping address section automatically selects the first comp
lete entry. | 255 // Suggest complete addresses first. |
| 256 Collections.sort(addresses, completenessComparator); |
| 257 |
| 258 // Limit the number of suggestions. |
| 259 addresses = addresses.subList(0, Math.min(addresses.size(), SUGGESTI
ONS_LIMIT)); |
| 260 |
| 261 // Automatically select the first address if one is complete and if
the merchant does |
| 262 // not require a shipping address to calculate shipping costs. |
| 263 int firstCompleteAddressIndex = SectionInformation.NO_SELECTION; |
| 264 if (!mMerchantNeedsShippingAddress && !addresses.isEmpty() |
| 265 && addresses.get(0).isComplete()) { |
| 266 firstCompleteAddressIndex = 0; |
| 267 } |
| 268 |
| 243 mShippingAddressesSection = | 269 mShippingAddressesSection = |
| 244 new SectionInformation(PaymentRequestUI.TYPE_SHIPPING_ADDRES
SES, | 270 new SectionInformation(PaymentRequestUI.TYPE_SHIPPING_ADDRES
SES, |
| 245 firstCompleteAddressIndex, addresses); | 271 firstCompleteAddressIndex, addresses); |
| 246 } | 272 } |
| 247 | 273 |
| 248 if (requestPayerPhone || requestPayerEmail) { | 274 if (requestPayerPhone || requestPayerEmail) { |
| 249 Set<String> uniqueContactInfos = new HashSet<>(); | 275 Set<String> uniqueContactInfos = new HashSet<>(); |
| 250 mContactEditor = new ContactEditor(requestPayerPhone, requestPayerEm
ail); | 276 mContactEditor = new ContactEditor(requestPayerPhone, requestPayerEm
ail); |
| 251 List<AutofillContact> contacts = new ArrayList<>(); | 277 List<AutofillContact> contacts = new ArrayList<>(); |
| 252 int firstCompleteContactIndex = SectionInformation.NO_SELECTION; | |
| 253 | 278 |
| 254 for (int i = 0; i < profiles.size(); i++) { | 279 for (int i = 0; i < profiles.size(); i++) { |
| 255 AutofillProfile profile = profiles.get(i); | 280 AutofillProfile profile = profiles.get(i); |
| 256 String phone = requestPayerPhone && !TextUtils.isEmpty(profile.g
etPhoneNumber()) | 281 String phone = requestPayerPhone && !TextUtils.isEmpty(profile.g
etPhoneNumber()) |
| 257 ? profile.getPhoneNumber() : null; | 282 ? profile.getPhoneNumber() : null; |
| 258 String email = requestPayerEmail && !TextUtils.isEmpty(profile.g
etEmailAddress()) | 283 String email = requestPayerEmail && !TextUtils.isEmpty(profile.g
etEmailAddress()) |
| 259 ? profile.getEmailAddress() : null; | 284 ? profile.getEmailAddress() : null; |
| 260 mContactEditor.addPhoneNumberIfValid(phone); | 285 mContactEditor.addPhoneNumberIfValid(phone); |
| 261 mContactEditor.addEmailAddressIfValid(email); | 286 mContactEditor.addEmailAddressIfValid(email); |
| 262 | 287 |
| 263 if (phone != null || email != null) { | 288 if (phone != null || email != null) { |
| 264 // Different profiles can have identical contact info. Do no
t add the same | 289 // Different profiles can have identical contact info. Do no
t add the same |
| 265 // contact info to the list twice. | 290 // contact info to the list twice. |
| 266 String uniqueContactInfo = phone + email; | 291 String uniqueContactInfo = phone + email; |
| 267 if (!uniqueContactInfos.contains(uniqueContactInfo)) { | 292 if (!uniqueContactInfos.contains(uniqueContactInfo)) { |
| 268 uniqueContactInfos.add(uniqueContactInfo); | 293 uniqueContactInfos.add(uniqueContactInfo); |
| 269 | 294 |
| 270 boolean isComplete = | 295 boolean isComplete = |
| 271 mContactEditor.isContactInformationComplete(phon
e, email); | 296 mContactEditor.isContactInformationComplete(phon
e, email); |
| 272 contacts.add(new AutofillContact(profile, phone, email,
isComplete)); | 297 contacts.add(new AutofillContact(profile, phone, email,
isComplete)); |
| 273 if (isComplete | |
| 274 && firstCompleteContactIndex == SectionInformati
on.NO_SELECTION) { | |
| 275 firstCompleteContactIndex = i; | |
| 276 } | |
| 277 } | 298 } |
| 278 } | 299 } |
| 279 } | 300 } |
| 280 | 301 |
| 281 // The contact section automatically selects the first complete entr
y. | 302 // Suggest complete contact infos first. |
| 303 Collections.sort(contacts, completenessComparator); |
| 304 |
| 305 // Limit the number of suggestions. |
| 306 contacts = contacts.subList(0, Math.min(contacts.size(), SUGGESTIONS
_LIMIT)); |
| 307 |
| 308 // Automatically select the first address if it is complete. |
| 309 int firstCompleteContactIndex = SectionInformation.NO_SELECTION; |
| 310 if (!contacts.isEmpty() && contacts.get(0).isComplete()) { |
| 311 firstCompleteContactIndex = 0; |
| 312 } |
| 313 |
| 282 mContactSection = new SectionInformation( | 314 mContactSection = new SectionInformation( |
| 283 PaymentRequestUI.TYPE_CONTACT_DETAILS, firstCompleteContactI
ndex, contacts); | 315 PaymentRequestUI.TYPE_CONTACT_DETAILS, firstCompleteContactI
ndex, contacts); |
| 284 } | 316 } |
| 285 | 317 |
| 286 mPendingApps = new ArrayList<>(mApps); | 318 mPendingApps = new ArrayList<>(mApps); |
| 287 mPendingInstruments = new ArrayList<>(); | 319 mPendingInstruments = new ArrayList<>(); |
| 288 boolean isGettingInstruments = false; | 320 boolean isGettingInstruments = false; |
| 289 | 321 |
| 290 for (int i = 0; i < mApps.size(); i++) { | 322 for (int i = 0; i < mApps.size(); i++) { |
| 291 PaymentApp app = mApps.get(i); | 323 PaymentApp app = mApps.get(i); |
| (...skipping 570 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 862 private void closeClient() { | 894 private void closeClient() { |
| 863 if (mClient != null) mClient.close(); | 895 if (mClient != null) mClient.close(); |
| 864 mClient = null; | 896 mClient = null; |
| 865 } | 897 } |
| 866 | 898 |
| 867 @VisibleForTesting | 899 @VisibleForTesting |
| 868 public static void setObserverForTest(PaymentRequestServiceObserverForTest o
bserverForTest) { | 900 public static void setObserverForTest(PaymentRequestServiceObserverForTest o
bserverForTest) { |
| 869 sObserverForTest = observerForTest; | 901 sObserverForTest = observerForTest; |
| 870 } | 902 } |
| 871 } | 903 } |
| OLD | NEW |