Chromium Code Reviews| Index: chrome/android/java/src/org/chromium/chrome/browser/payments/ui/ContactDetailsSection.java |
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/ContactDetailsSection.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/ContactDetailsSection.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4ebfb3a870a5d52becab78f786523dc698ccab04 |
| --- /dev/null |
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/ContactDetailsSection.java |
| @@ -0,0 +1,177 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +package org.chromium.chrome.browser.payments.ui; |
| + |
| +import android.content.Context; |
| +import android.text.TextUtils; |
| + |
| +import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile; |
| +import org.chromium.chrome.browser.payments.AutofillAddress; |
| +import org.chromium.chrome.browser.payments.AutofillContact; |
| +import org.chromium.chrome.browser.payments.ContactEditor; |
| +import org.chromium.chrome.browser.payments.PaymentRequestImpl; |
| +import org.chromium.chrome.browser.payments.PaymentRequestJourneyLogger; |
| + |
| +import java.util.ArrayList; |
| +import java.util.Collection; |
| +import java.util.Collections; |
| +import java.util.Comparator; |
| +import java.util.List; |
| + |
| +import javax.annotation.Nullable; |
| + |
| +/** |
| + * The data to show in the contact details section where the user can select something. |
| + */ |
| +public class ContactDetailsSection extends SectionInformation { |
| + private final Context mContext; |
| + private final ContactEditor mContactEditor; |
| + private final PaymentRequestJourneyLogger mJourneyLogger = new PaymentRequestJourneyLogger(); |
| + |
| + private List<AutofillProfile> mProfiles; |
| + |
| + /** |
| + * Builds a Contact section from a list of AutofillProfile. |
| + * |
| + * @param context Context |
| + * @param autofillProfiles The list of profiles to build from. |
|
please use gerrit instead
2017/01/09 15:35:55
JavaDoc @param name should match the code.
Mathieu
2017/01/09 17:10:32
Done.
|
| + * @param contactEditor The Contact Editor associated with this flow. |
| + */ |
| + public ContactDetailsSection(Context context, Collection<AutofillProfile> unmodifiableProfiles, |
| + ContactEditor contactEditor) { |
| + // Initially no items are selected, but they are updated later in the constructor. |
| + super(PaymentRequestUI.TYPE_CONTACT_DETAILS, null); |
| + |
| + mContext = context; |
| + mContactEditor = contactEditor; |
| + // Copy the profiles from which this section is derived. |
| + mProfiles = new ArrayList<AutofillProfile>(unmodifiableProfiles); |
| + |
| + // Refresh the contact section items and selection. |
| + createContactListFromAutofillProfiles(); |
| + } |
| + |
| + /** |
| + * Add (or update) an address in the contact details section. |
| + * |
| + * @param editedAddress the new or edited address with which to update the contacts section. |
| + */ |
| + public void addOrUpdateWithAutofillAddress(AutofillAddress editedAddress) { |
| + if (editedAddress == null) return; |
| + |
| + boolean contactExisted = false; |
| + // If the profile is currently being displayed, update the items in anticipation of the |
| + // contacts section refresh. |
| + AutofillContact updatedContact = |
| + createAutofillContactFromProfile(editedAddress.getProfile()); |
| + if (mItems != null) { |
| + for (int i = 0; i < mItems.size(); i++) { |
| + AutofillContact existingContact = (AutofillContact) mItems.get(i); |
| + if (existingContact.getProfile().getGUID().equals( |
| + editedAddress.getProfile().getGUID())) { |
| + // We need to replace |existingContact| with |updatedContact|. |
| + mItems.remove(i); |
| + mItems.add(i, updatedContact); |
| + contactExisted = true; |
| + break; |
|
please use gerrit instead
2017/01/09 15:35:55
You can return instead of break. This also removes
Mathieu
2017/01/09 17:10:32
Done.
|
| + } |
| + } |
| + } |
| + if (!contactExisted) { |
| + // Add the new address to |mItems| to the end of the list, in anticipation of the |
| + // contacts section refresh. |
| + if (mItems == null) mItems = new ArrayList<>(); |
| + mItems.add(updatedContact); |
| + } |
| + // The selection is not updated. |
| + } |
| + |
| + /** Recomputes the list of displayed contacts and possibly updates the selection. */ |
| + private void createContactListFromAutofillProfiles() { |
| + List<AutofillContact> contacts = new ArrayList<>(); |
| + List<AutofillContact> uniqueContacts = new ArrayList<>(); |
| + |
| + // Add the profile's valid request values to the editor's autocomplete list and convert |
| + // relevant profiles to AutofillContacts, to be deduped later. |
| + for (int i = 0; i < mProfiles.size(); ++i) { |
| + AutofillContact contact = createAutofillContactFromProfile(mProfiles.get(i)); |
| + |
| + // Only create a contact if the profile has relevant information for the merchant. |
| + if (contact != null) { |
| + mContactEditor.addPayerNameIfValid(contact.getPayerName()); |
| + mContactEditor.addPhoneNumberIfValid(contact.getPayerPhone()); |
| + mContactEditor.addEmailAddressIfValid(contact.getPayerEmail()); |
| + |
| + contacts.add(contact); |
| + } |
| + } |
| + |
| + // Order the contacts so the ones that have most of the required information are put first. |
| + // The sort is stable, so contacts with the same relevance score are sorted by frecency. |
| + Collections.sort(contacts, new Comparator<AutofillContact>() { |
| + @Override |
| + public int compare(AutofillContact a, AutofillContact b) { |
| + return b.getRelevanceScore() - a.getRelevanceScore(); |
| + } |
| + }); |
| + |
| + // This algorithm is quadratic, but since the number of contacts is generally very small |
| + // ( < 10) a faster but more complicated algorithm would be overkill. |
| + for (int i = 0; i < contacts.size(); i++) { |
| + AutofillContact contact = contacts.get(i); |
| + |
| + // Different contacts can have identical info. Do not add the same contact info or a |
| + // subset of it twice. It's important that the profiles be sorted by the quantity of |
| + // required info they have. |
| + boolean isNewSuggestion = true; |
| + for (int j = 0; j < uniqueContacts.size(); ++j) { |
| + if (uniqueContacts.get(j).isEqualOrSupersetOf(contact)) { |
| + isNewSuggestion = false; |
| + break; |
| + } |
| + } |
| + if (isNewSuggestion) uniqueContacts.add(contact); |
| + |
| + // Limit the number of suggestions. |
| + if (uniqueContacts.size() == PaymentRequestImpl.SUGGESTIONS_LIMIT) break; |
| + } |
| + |
| + // Log the number of suggested contact infos. |
| + mJourneyLogger.setNumberOfSuggestionsShown( |
| + PaymentRequestJourneyLogger.SECTION_CONTACT_INFO, uniqueContacts.size()); |
| + |
| + // Automatically select the first address if it is complete. |
| + int firstCompleteContactIndex = SectionInformation.NO_SELECTION; |
| + if (!uniqueContacts.isEmpty() && uniqueContacts.get(0).isComplete()) { |
| + firstCompleteContactIndex = 0; |
| + } |
| + |
| + updateItemsWithCollection(firstCompleteContactIndex, uniqueContacts); |
| + } |
| + |
| + @Nullable |
| + private AutofillContact createAutofillContactFromProfile(AutofillProfile profile) { |
| + boolean requestPayerName = mContactEditor.getRequestPayerName(); |
| + boolean requestPayerPhone = mContactEditor.getRequestPayerPhone(); |
| + boolean requestPayerEmail = mContactEditor.getRequestPayerEmail(); |
| + String name = requestPayerName && !TextUtils.isEmpty(profile.getFullName()) |
| + ? profile.getFullName() |
| + : null; |
| + String phone = requestPayerPhone && !TextUtils.isEmpty(profile.getPhoneNumber()) |
| + ? profile.getPhoneNumber() |
| + : null; |
| + String email = requestPayerEmail && !TextUtils.isEmpty(profile.getEmailAddress()) |
| + ? profile.getEmailAddress() |
| + : null; |
| + |
| + if (name != null || phone != null || email != null) { |
| + @ContactEditor.CompletionStatus |
| + int completionStatus = mContactEditor.checkContactCompletionStatus(name, phone, email); |
| + return new AutofillContact(mContext, profile, name, phone, email, completionStatus, |
| + requestPayerName, requestPayerPhone, requestPayerEmail); |
| + } |
| + return null; |
| + } |
| +} |