| 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..ed3bc15b6f6c727f099174dd8cd913abda1e8bba
|
| --- /dev/null
|
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/ContactDetailsSection.java
|
| @@ -0,0 +1,174 @@
|
| +// 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 unmodifiableProfiles The list of profiles to build from.
|
| + * @param mContactEditor 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;
|
| +
|
| + // 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);
|
| + return;
|
| + }
|
| + }
|
| + }
|
| + // The contact didn't exist. 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;
|
| + }
|
| +}
|
|
|