blob: ea082040248a0e1961524293c92420ff5f2bb539 [file] [log] [blame]
// Copyright 2018 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.autofill_assistant.user_data;
import android.app.Activity;
import android.text.TextUtils;
import android.view.View;
import org.chromium.chrome.browser.ChromeVersionInfo;
import org.chromium.chrome.browser.autofill.PersonalDataManager;
import org.chromium.chrome.browser.payments.AddressEditor;
import org.chromium.chrome.browser.payments.AutofillPaymentApp;
import org.chromium.chrome.browser.payments.AutofillPaymentInstrument;
import org.chromium.chrome.browser.payments.BasicCardUtils;
import org.chromium.chrome.browser.payments.CardEditor;
import org.chromium.chrome.browser.payments.ContactEditor;
import org.chromium.chrome.browser.payments.PaymentInstrument;
import org.chromium.chrome.browser.widget.prefeditor.EditorDialog;
import org.chromium.components.url_formatter.UrlFormatter;
import org.chromium.content_public.browser.WebContents;
import org.chromium.payments.mojom.PaymentMethodData;
import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* This class is responsible for pushing updates to the Autofill Assistant UI for requesting user
* data. These updates are pulled from the {@link AssistantCollectUserDataModel} when a notification
* of an update is received.
*/
class AssistantCollectUserDataBinder
implements PropertyModelChangeProcessor.ViewBinder<AssistantCollectUserDataModel,
AssistantCollectUserDataBinder.ViewHolder, PropertyKey> {
/**
* Helper class that compares instances of {@link PersonalDataManager.AutofillProfile} by
* completeness in regards to the current state of the given {@link
* AssistantCollectUserDataModel}.
*/
class CompletenessComparator implements Comparator<PersonalDataManager.AutofillProfile> {
final boolean mRequestName;
final boolean mRequestShipping;
final boolean mRequestEmail;
final boolean mRequestPhone;
CompletenessComparator(AssistantCollectUserDataModel model) {
mRequestName = model.get(AssistantCollectUserDataModel.REQUEST_NAME);
mRequestShipping = model.get(AssistantCollectUserDataModel.REQUEST_SHIPPING_ADDRESS);
mRequestEmail = model.get(AssistantCollectUserDataModel.REQUEST_EMAIL);
mRequestPhone = model.get(AssistantCollectUserDataModel.REQUEST_PHONE);
}
@Override
public int compare(
PersonalDataManager.AutofillProfile a, PersonalDataManager.AutofillProfile b) {
int result = countCompleteFields(a) - countCompleteFields(b);
// Fallback, compare by name alphabetically.
if (result == 0) {
return a.getFullName().compareTo(b.getFullName());
}
return result;
}
private int countCompleteFields(PersonalDataManager.AutofillProfile profile) {
int completeFields = 0;
if (mRequestName && !TextUtils.isEmpty((profile.getFullName()))) {
completeFields++;
}
if (mRequestShipping && !TextUtils.isEmpty(profile.getStreetAddress())) {
completeFields++;
}
if (mRequestEmail && !TextUtils.isEmpty(profile.getEmailAddress())) {
completeFields++;
}
if (mRequestPhone && !TextUtils.isEmpty(profile.getPhoneNumber())) {
completeFields++;
}
return completeFields;
}
}
/**
* A wrapper class that holds the different views of the CollectUserData request.
*/
static class ViewHolder {
private final View mRootView;
private final AssistantVerticalExpanderAccordion mPaymentRequestExpanderAccordion;
private final int mSectionToSectionPadding;
private final AssistantLoginSection mLoginSection;
private final AssistantContactDetailsSection mContactDetailsSection;
private final AssistantDateSection mDateRangeStartSection;
private final AssistantDateSection mDateRangeEndSection;
private final AssistantPaymentMethodSection mPaymentMethodSection;
private final AssistantShippingAddressSection mShippingAddressSection;
private final AssistantTermsSection mTermsSection;
private final AssistantTermsSection mTermsAsCheckboxSection;
private final Object mDividerTag;
private final Activity mActivity;
private PersonalDataManager.PersonalDataManagerObserver mPersonalDataManagerObserver;
public ViewHolder(View rootView, AssistantVerticalExpanderAccordion accordion,
int sectionPadding, AssistantLoginSection loginSection,
AssistantContactDetailsSection contactDetailsSection,
AssistantDateSection dateRangeStartSection,
AssistantDateSection dateRangeEndSection,
AssistantPaymentMethodSection paymentMethodSection,
AssistantShippingAddressSection shippingAddressSection,
AssistantTermsSection termsSection, AssistantTermsSection termsAsCheckboxSection,
Object dividerTag, Activity activity) {
mRootView = rootView;
mPaymentRequestExpanderAccordion = accordion;
mSectionToSectionPadding = sectionPadding;
mLoginSection = loginSection;
mContactDetailsSection = contactDetailsSection;
mDateRangeStartSection = dateRangeStartSection;
mDateRangeEndSection = dateRangeEndSection;
mPaymentMethodSection = paymentMethodSection;
mShippingAddressSection = shippingAddressSection;
mTermsSection = termsSection;
mTermsAsCheckboxSection = termsAsCheckboxSection;
mDividerTag = dividerTag;
mActivity = activity;
}
/**
* Explicitly clean up.
*/
public void destroy() {
stopListenToPersonalDataManager();
}
private void startListenToPersonalDataManager(
PersonalDataManager.PersonalDataManagerObserver observer) {
if (mPersonalDataManagerObserver != null) {
return;
}
mPersonalDataManagerObserver = observer;
PersonalDataManager.getInstance().registerDataObserver(mPersonalDataManagerObserver);
}
private void stopListenToPersonalDataManager() {
if (mPersonalDataManagerObserver == null) {
return;
}
PersonalDataManager.getInstance().unregisterDataObserver(mPersonalDataManagerObserver);
mPersonalDataManagerObserver = null;
}
}
@Override
public void bind(
AssistantCollectUserDataModel model, ViewHolder view, PropertyKey propertyKey) {
boolean handled = updateEditors(model, propertyKey, view);
handled = updateRootVisibility(model, propertyKey, view) || handled;
handled = updateSectionVisibility(model, propertyKey, view) || handled;
handled = updateSectionTitles(model, propertyKey, view) || handled;
handled = updateSectionContents(model, propertyKey, view) || handled;
handled = updateSectionSelectedItem(model, propertyKey, view) || handled;
/* Update section paddings *after* updating section visibility. */
handled = updateSectionPaddings(model, propertyKey, view) || handled;
if (propertyKey == AssistantCollectUserDataModel.DELEGATE) {
AssistantCollectUserDataDelegate collectUserDataDelegate =
model.get(AssistantCollectUserDataModel.DELEGATE);
AssistantTermsSection.Delegate termsDelegate =
collectUserDataDelegate == null ? null : new AssistantTermsSection.Delegate() {
@Override
public void onStateChanged(@AssistantTermsAndConditionsState int state) {
collectUserDataDelegate.onTermsAndConditionsChanged(state);
}
@Override
public void onLinkClicked(int link) {
collectUserDataDelegate.onTermsAndConditionsLinkClicked(link);
}
};
AssistantDateSection.Delegate dateStartDelegate = collectUserDataDelegate == null
? null
: (year, month, day, hour, minute, second) -> {
AssistantDateTime newStartValue =
new AssistantDateTime(year, month, day, hour, minute, second);
if (newStartValue.getTimeInUtcMillis()
> view.mDateRangeEndSection.getCurrentValue().getTimeInUtcMillis()) {
view.mDateRangeEndSection.setCurrentValue(newStartValue);
}
collectUserDataDelegate.onDateTimeRangeStartChanged(
year, month, day, hour, minute, second);
};
AssistantDateSection.Delegate dateEndDelegate = collectUserDataDelegate == null
? null
: (year, month, day, hour, minute, second) -> {
AssistantDateTime newEndValue =
new AssistantDateTime(year, month, day, hour, minute, second);
if (newEndValue.getTimeInUtcMillis()
< view.mDateRangeStartSection.getCurrentValue().getTimeInUtcMillis()) {
view.mDateRangeStartSection.setCurrentValue(newEndValue);
}
collectUserDataDelegate.onDateTimeRangeEndChanged(
year, month, day, hour, minute, second);
};
view.mTermsSection.setDelegate(termsDelegate);
view.mTermsAsCheckboxSection.setDelegate(termsDelegate);
view.mContactDetailsSection.setListener(collectUserDataDelegate != null
? collectUserDataDelegate::onContactInfoChanged
: null);
view.mPaymentMethodSection.setListener(collectUserDataDelegate != null
? collectUserDataDelegate::onPaymentMethodChanged
: null);
view.mShippingAddressSection.setListener(collectUserDataDelegate != null
? collectUserDataDelegate::onShippingAddressChanged
: null);
view.mLoginSection.setListener(collectUserDataDelegate != null
? collectUserDataDelegate::onLoginChoiceChanged
: null);
view.mDateRangeStartSection.setDelegate(dateStartDelegate);
view.mDateRangeEndSection.setDelegate(dateEndDelegate);
} else if (propertyKey == AssistantCollectUserDataModel.SUPPORTED_BASIC_CARD_NETWORKS) {
updateAvailablePaymentMethods(model);
} else if (propertyKey == AssistantCollectUserDataModel.SUPPORTED_PAYMENT_METHODS) {
updateAvailableAutofillPaymentMethods(model);
} else {
assert handled : "Unhandled property detected in AssistantCollectUserDataBinder!";
}
}
private boolean shouldShowContactDetails(AssistantCollectUserDataModel model) {
return model.get(AssistantCollectUserDataModel.REQUEST_NAME)
|| model.get(AssistantCollectUserDataModel.REQUEST_PHONE)
|| model.get(AssistantCollectUserDataModel.REQUEST_EMAIL);
}
private boolean updateSectionTitles(
AssistantCollectUserDataModel model, PropertyKey propertyKey, ViewHolder view) {
if (propertyKey == AssistantCollectUserDataModel.LOGIN_SECTION_TITLE) {
view.mLoginSection.setTitle(
model.get(AssistantCollectUserDataModel.LOGIN_SECTION_TITLE));
return true;
} else if (propertyKey == AssistantCollectUserDataModel.DATE_RANGE_START_LABEL) {
view.mDateRangeStartSection.setTitle(
model.get(AssistantCollectUserDataModel.DATE_RANGE_START_LABEL));
return true;
} else if (propertyKey == AssistantCollectUserDataModel.DATE_RANGE_END_LABEL) {
view.mDateRangeEndSection.setTitle(
model.get(AssistantCollectUserDataModel.DATE_RANGE_END_LABEL));
return true;
}
return false;
}
/**
* Updates the available items for each PR section.
* @return whether the property key was handled.
*/
private boolean updateSectionContents(
AssistantCollectUserDataModel model, PropertyKey propertyKey, ViewHolder view) {
if (propertyKey == AssistantCollectUserDataModel.AVAILABLE_AUTOFILL_PAYMENT_METHODS) {
List<AutofillPaymentInstrument> availablePaymentMethods =
model.get(AssistantCollectUserDataModel.AVAILABLE_AUTOFILL_PAYMENT_METHODS);
if (availablePaymentMethods == null) availablePaymentMethods = Collections.emptyList();
view.mPaymentMethodSection.onAvailablePaymentMethodsChanged(availablePaymentMethods);
return true;
} else if (propertyKey == AssistantCollectUserDataModel.AVAILABLE_PROFILES
|| propertyKey == AssistantCollectUserDataModel.DEFAULT_EMAIL) {
List<PersonalDataManager.AutofillProfile> autofillProfiles =
model.get(AssistantCollectUserDataModel.AVAILABLE_PROFILES);
if (autofillProfiles == null) {
autofillProfiles = Collections.emptyList();
}
if (shouldShowContactDetails(model)) {
view.mContactDetailsSection.onProfilesChanged(autofillProfiles,
model.get(AssistantCollectUserDataModel.REQUEST_EMAIL),
model.get(AssistantCollectUserDataModel.REQUEST_NAME),
model.get(AssistantCollectUserDataModel.REQUEST_PHONE),
model.get(AssistantCollectUserDataModel.DEFAULT_EMAIL));
}
if (model.get(AssistantCollectUserDataModel.REQUEST_PAYMENT)) {
view.mPaymentMethodSection.onProfilesChanged(autofillProfiles);
}
if (model.get(AssistantCollectUserDataModel.REQUEST_SHIPPING_ADDRESS)) {
view.mShippingAddressSection.onProfilesChanged(autofillProfiles);
}
return true;
} else if (propertyKey == AssistantCollectUserDataModel.REQUIRE_BILLING_POSTAL_CODE
|| propertyKey == AssistantCollectUserDataModel.BILLING_POSTAL_CODE_MISSING_TEXT) {
view.mPaymentMethodSection.setRequiresBillingPostalCode(
model.get(AssistantCollectUserDataModel.REQUIRE_BILLING_POSTAL_CODE));
view.mPaymentMethodSection.setBillingPostalCodeMissingText(
model.get(AssistantCollectUserDataModel.BILLING_POSTAL_CODE_MISSING_TEXT));
return true;
} else if (propertyKey == AssistantCollectUserDataModel.AVAILABLE_LOGINS) {
if (model.get(AssistantCollectUserDataModel.REQUEST_LOGIN_CHOICE)) {
view.mLoginSection.onLoginsChanged(
model.get(AssistantCollectUserDataModel.AVAILABLE_LOGINS));
}
return true;
} else if (propertyKey == AssistantCollectUserDataModel.DATE_RANGE_START) {
view.mDateRangeStartSection.setDateChoiceOptions(
model.get(AssistantCollectUserDataModel.DATE_RANGE_START));
return true;
} else if (propertyKey == AssistantCollectUserDataModel.DATE_RANGE_END) {
view.mDateRangeEndSection.setDateChoiceOptions(
model.get(AssistantCollectUserDataModel.DATE_RANGE_END));
return true;
}
return false;
}
/**
* Updates visibility of PR sections.
* @return whether the property key was handled.
*/
private boolean updateSectionVisibility(
AssistantCollectUserDataModel model, PropertyKey propertyKey, ViewHolder view) {
if ((propertyKey == AssistantCollectUserDataModel.REQUEST_NAME)
|| (propertyKey == AssistantCollectUserDataModel.REQUEST_EMAIL)
|| (propertyKey == AssistantCollectUserDataModel.REQUEST_PHONE)) {
view.mContactDetailsSection.setVisible(shouldShowContactDetails(model));
return true;
} else if (propertyKey == AssistantCollectUserDataModel.REQUEST_SHIPPING_ADDRESS) {
view.mShippingAddressSection.setVisible(
model.get(AssistantCollectUserDataModel.REQUEST_SHIPPING_ADDRESS));
return true;
} else if (propertyKey == AssistantCollectUserDataModel.REQUEST_PAYMENT) {
view.mPaymentMethodSection.setVisible(
(model.get(AssistantCollectUserDataModel.REQUEST_PAYMENT)));
return true;
} else if (propertyKey == AssistantCollectUserDataModel.ACCEPT_TERMS_AND_CONDITIONS_TEXT) {
view.mTermsSection.setAcceptTermsAndConditionsText(
model.get(AssistantCollectUserDataModel.ACCEPT_TERMS_AND_CONDITIONS_TEXT));
view.mTermsAsCheckboxSection.setAcceptTermsAndConditionsText(
model.get(AssistantCollectUserDataModel.ACCEPT_TERMS_AND_CONDITIONS_TEXT));
return true;
} else if (propertyKey == AssistantCollectUserDataModel.SHOW_TERMS_AS_CHECKBOX) {
if (model.get(AssistantCollectUserDataModel.SHOW_TERMS_AS_CHECKBOX)) {
view.mTermsSection.getView().setVisibility(View.GONE);
view.mTermsAsCheckboxSection.getView().setVisibility(View.VISIBLE);
} else {
view.mTermsSection.getView().setVisibility(View.VISIBLE);
view.mTermsAsCheckboxSection.getView().setVisibility(View.GONE);
}
return true;
} else if (propertyKey == AssistantCollectUserDataModel.REQUEST_LOGIN_CHOICE) {
view.mLoginSection.setVisible(
model.get(AssistantCollectUserDataModel.REQUEST_LOGIN_CHOICE));
return true;
} else if (propertyKey == AssistantCollectUserDataModel.REQUEST_DATE_RANGE) {
boolean requestDateRange = model.get(AssistantCollectUserDataModel.REQUEST_DATE_RANGE);
view.mDateRangeStartSection.setVisible(requestDateRange);
view.mDateRangeEndSection.setVisible(requestDateRange);
return true;
}
return false;
}
/**
* Updates visibility of the root widget.
* @return whether the property key was handled.
*/
private boolean updateRootVisibility(
AssistantCollectUserDataModel model, PropertyKey propertyKey, ViewHolder view) {
if (propertyKey != AssistantCollectUserDataModel.VISIBLE) {
return false;
}
int visibility =
model.get(AssistantCollectUserDataModel.VISIBLE) ? View.VISIBLE : View.GONE;
if (view.mRootView.getVisibility() != visibility) {
if (visibility == View.VISIBLE) {
// Update available profiles and credit cards before PR is made visible.
updateAvailableProfiles(model, view);
updateAvailablePaymentMethods(model);
WebContents webContents = model.get(AssistantCollectUserDataModel.WEB_CONTENTS);
if (webContents != null) {
String origin = UrlFormatter.formatUrlForSecurityDisplayOmitScheme(
webContents.getLastCommittedUrl());
view.mTermsSection.setOrigin(origin);
view.mTermsAsCheckboxSection.setOrigin(origin);
}
view.startListenToPersonalDataManager(() -> {
AssistantCollectUserDataBinder.this.updateAvailableProfiles(model, view);
AssistantCollectUserDataBinder.this.updateAvailablePaymentMethods(model);
});
} else {
view.stopListenToPersonalDataManager();
}
view.mRootView.setVisibility(visibility);
}
return true;
}
/**
* Updates the currently selected item in each PR section.
* @return whether the property key was handled.
*/
private boolean updateSectionSelectedItem(
AssistantCollectUserDataModel model, PropertyKey propertyKey, ViewHolder view) {
if (propertyKey == AssistantCollectUserDataModel.SHIPPING_ADDRESS) {
view.mShippingAddressSection.addOrUpdateItem(
model.get(AssistantCollectUserDataModel.SHIPPING_ADDRESS), true);
return true;
} else if (propertyKey == AssistantCollectUserDataModel.PAYMENT_METHOD) {
view.mPaymentMethodSection.addOrUpdateItem(
model.get(AssistantCollectUserDataModel.PAYMENT_METHOD), true);
return true;
} else if (propertyKey == AssistantCollectUserDataModel.CONTACT_DETAILS) {
view.mContactDetailsSection.addOrUpdateItem(
model.get(AssistantCollectUserDataModel.CONTACT_DETAILS), true);
return true;
} else if (propertyKey == AssistantCollectUserDataModel.TERMS_STATUS) {
int termsStatus = model.get(AssistantCollectUserDataModel.TERMS_STATUS);
view.mTermsSection.setTermsStatus(termsStatus);
view.mTermsAsCheckboxSection.setTermsStatus(termsStatus);
return true;
} else if (propertyKey == AssistantCollectUserDataModel.SELECTED_LOGIN) {
view.mLoginSection.addOrUpdateItem(
model.get(AssistantCollectUserDataModel.SELECTED_LOGIN), true);
return true;
}
return false;
}
// TODO(crbug.com/806868): Move this logic to native.
private void updateAvailableProfiles(AssistantCollectUserDataModel model, ViewHolder view) {
List<PersonalDataManager.AutofillProfile> autofillProfiles =
PersonalDataManager.getInstance().getProfilesToSuggest(
/* includeNameInLabel= */ false);
// Suggest complete profiles first.
Collections.sort(autofillProfiles, new CompletenessComparator(model));
model.set(AssistantCollectUserDataModel.AVAILABLE_PROFILES, autofillProfiles);
}
/**
* Updates the paddings between sections and section dividers.
* @return whether the property key was handled.
*/
private boolean updateSectionPaddings(
AssistantCollectUserDataModel model, PropertyKey propertyKey, ViewHolder view) {
if ((propertyKey != AssistantCollectUserDataModel.REQUEST_SHIPPING_ADDRESS)
&& (propertyKey != AssistantCollectUserDataModel.REQUEST_NAME)
&& (propertyKey != AssistantCollectUserDataModel.REQUEST_EMAIL)
&& (propertyKey != AssistantCollectUserDataModel.REQUEST_PHONE)
&& (propertyKey != AssistantCollectUserDataModel.REQUEST_PAYMENT)
&& (propertyKey != AssistantCollectUserDataModel.REQUEST_LOGIN_CHOICE)
&& (propertyKey != AssistantCollectUserDataModel.REQUEST_DATE_RANGE)
&& (propertyKey != AssistantCollectUserDataModel.EXPANDED_SECTION)) {
return false;
}
// Update section paddings such that the first and last section are flush to the top/bottom,
// and all other sections have the same amount of padding in-between them.
if (model.get(AssistantCollectUserDataModel.REQUEST_LOGIN_CHOICE)) {
view.mLoginSection.setPaddings(0, view.mSectionToSectionPadding);
view.mContactDetailsSection.setPaddings(
view.mSectionToSectionPadding, view.mSectionToSectionPadding);
view.mDateRangeStartSection.setPaddings(
view.mSectionToSectionPadding, view.mSectionToSectionPadding);
view.mDateRangeEndSection.setPaddings(
view.mSectionToSectionPadding, view.mSectionToSectionPadding);
view.mPaymentMethodSection.setPaddings(
view.mSectionToSectionPadding, view.mSectionToSectionPadding);
view.mShippingAddressSection.setPaddings(
view.mSectionToSectionPadding, view.mSectionToSectionPadding);
} else if (shouldShowContactDetails(model)) {
view.mContactDetailsSection.setPaddings(0, view.mSectionToSectionPadding);
view.mDateRangeStartSection.setPaddings(
view.mSectionToSectionPadding, view.mSectionToSectionPadding);
view.mDateRangeEndSection.setPaddings(
view.mSectionToSectionPadding, view.mSectionToSectionPadding);
view.mPaymentMethodSection.setPaddings(
view.mSectionToSectionPadding, view.mSectionToSectionPadding);
view.mShippingAddressSection.setPaddings(
view.mSectionToSectionPadding, view.mSectionToSectionPadding);
} else if (model.get(AssistantCollectUserDataModel.REQUEST_DATE_RANGE)) {
view.mDateRangeStartSection.setPaddings(0, view.mSectionToSectionPadding);
view.mDateRangeEndSection.setPaddings(
view.mSectionToSectionPadding, view.mSectionToSectionPadding);
view.mPaymentMethodSection.setPaddings(
view.mSectionToSectionPadding, view.mSectionToSectionPadding);
view.mShippingAddressSection.setPaddings(
view.mSectionToSectionPadding, view.mSectionToSectionPadding);
} else if (model.get(AssistantCollectUserDataModel.REQUEST_PAYMENT)) {
view.mPaymentMethodSection.setPaddings(0, view.mSectionToSectionPadding);
view.mShippingAddressSection.setPaddings(
view.mSectionToSectionPadding, view.mSectionToSectionPadding);
} else if (model.get(AssistantCollectUserDataModel.REQUEST_SHIPPING_ADDRESS)) {
view.mShippingAddressSection.setPaddings(0, view.mSectionToSectionPadding);
}
view.mTermsSection.setPaddings(view.mSectionToSectionPadding, 0);
view.mTermsAsCheckboxSection.setPaddings(view.mSectionToSectionPadding, 0);
// Hide dividers for currently invisible sections and after the expanded section, if any.
boolean prevSectionIsExpandedOrInvisible = false;
for (int i = 0; i < view.mPaymentRequestExpanderAccordion.getChildCount(); i++) {
View child = view.mPaymentRequestExpanderAccordion.getChildAt(i);
if (child instanceof AssistantVerticalExpander) {
prevSectionIsExpandedOrInvisible = ((AssistantVerticalExpander) child).isExpanded()
|| child.getVisibility() != View.VISIBLE;
} else if (child.getTag() == view.mDividerTag) {
child.setVisibility(prevSectionIsExpandedOrInvisible ? View.GONE : View.VISIBLE);
}
}
return true;
}
/**
* Updates/recreates section editors.
* @return whether the property key was handled.
*/
private boolean updateEditors(
AssistantCollectUserDataModel model, PropertyKey propertyKey, ViewHolder view) {
if ((propertyKey != AssistantCollectUserDataModel.WEB_CONTENTS)
&& (propertyKey != AssistantCollectUserDataModel.REQUEST_NAME)
&& (propertyKey != AssistantCollectUserDataModel.REQUEST_EMAIL)
&& (propertyKey != AssistantCollectUserDataModel.REQUEST_PHONE)
&& (propertyKey
!= AssistantCollectUserDataModel.AVAILABLE_AUTOFILL_PAYMENT_METHODS)) {
return false;
}
WebContents webContents = model.get(AssistantCollectUserDataModel.WEB_CONTENTS);
if (webContents == null) {
view.mContactDetailsSection.setEditor(null);
view.mPaymentMethodSection.setEditor(null);
view.mShippingAddressSection.setEditor(null);
return true;
}
if (shouldShowContactDetails(model)) {
ContactEditor contactEditor =
new ContactEditor(model.get(AssistantCollectUserDataModel.REQUEST_NAME),
model.get(AssistantCollectUserDataModel.REQUEST_PHONE),
model.get(AssistantCollectUserDataModel.REQUEST_EMAIL),
!webContents.isIncognito());
contactEditor.setEditorDialog(new EditorDialog(view.mActivity, null,
/*deleteRunnable =*/null));
view.mContactDetailsSection.setEditor(contactEditor);
}
AddressEditor addressEditor = new AddressEditor(AddressEditor.Purpose.PAYMENT_REQUEST,
/* saveToDisk= */ !webContents.isIncognito());
addressEditor.setEditorDialog(new EditorDialog(view.mActivity, null,
/*deleteRunnable =*/null));
CardEditor cardEditor = new CardEditor(webContents, addressEditor,
/* includeOrgLabel= */ false, /* observerForTest= */ null);
Map<String, PaymentMethodData> paymentMethods =
model.get(AssistantCollectUserDataModel.SUPPORTED_PAYMENT_METHODS);
if (paymentMethods != null) {
for (Map.Entry<String, PaymentMethodData> entry : paymentMethods.entrySet()) {
cardEditor.addAcceptedPaymentMethodIfRecognized(entry.getValue());
}
}
EditorDialog cardEditorDialog = new EditorDialog(view.mActivity, null,
/*deleteRunnable =*/null);
if (ChromeVersionInfo.isBetaBuild() || ChromeVersionInfo.isStableBuild()) {
cardEditorDialog.disableScreenshots();
}
cardEditor.setEditorDialog(cardEditorDialog);
view.mShippingAddressSection.setEditor(addressEditor);
view.mPaymentMethodSection.setEditor(cardEditor);
return true;
}
/**
* Updates the map of supported payment methods (identifier -> methodData), filtered by
* |SUPPORTED_BASIC_CARD_NETWORKS|.
*/
// TODO(crbug.com/806868): Move the logic to retrieve and filter payment methods to native.
private void updateAvailablePaymentMethods(AssistantCollectUserDataModel model) {
// Only enable 'basic-card' payment method.
PaymentMethodData methodData = new PaymentMethodData();
methodData.supportedMethod = BasicCardUtils.BASIC_CARD_METHOD_NAME;
// Apply basic-card filter if specified
List<String> supportedBasicCardNetworks =
model.get(AssistantCollectUserDataModel.SUPPORTED_BASIC_CARD_NETWORKS);
if (supportedBasicCardNetworks != null && supportedBasicCardNetworks.size() > 0) {
ArrayList<Integer> filteredNetworks = new ArrayList<>();
Map<String, Integer> networks = BasicCardUtils.getNetworkIdentifiers();
for (int i = 0; i < supportedBasicCardNetworks.size(); i++) {
assert networks.containsKey(supportedBasicCardNetworks.get(i));
filteredNetworks.add(networks.get(supportedBasicCardNetworks.get(i)));
}
methodData.supportedNetworks = new int[filteredNetworks.size()];
for (int i = 0; i < filteredNetworks.size(); i++) {
methodData.supportedNetworks[i] = filteredNetworks.get(i);
}
}
Map<String, PaymentMethodData> supportedPaymentMethods = new HashMap<>();
supportedPaymentMethods.put(BasicCardUtils.BASIC_CARD_METHOD_NAME, methodData);
model.set(AssistantCollectUserDataModel.SUPPORTED_PAYMENT_METHODS, supportedPaymentMethods);
}
/**
* Updates the list of available autofill payment methods (i.e., the list of available payment
* methods available to the user as items in the UI).
*/
// TODO(crbug.com/806868): Move this logic to native.
private void updateAvailableAutofillPaymentMethods(AssistantCollectUserDataModel model) {
WebContents webContents = model.get(AssistantCollectUserDataModel.WEB_CONTENTS);
AutofillPaymentApp autofillPaymentApp = new AutofillPaymentApp(webContents);
Map<String, PaymentMethodData> supportedPaymentMethods =
model.get(AssistantCollectUserDataModel.SUPPORTED_PAYMENT_METHODS);
List<PaymentInstrument> paymentMethods = autofillPaymentApp.getInstruments(
supportedPaymentMethods != null ? supportedPaymentMethods : Collections.emptyMap(),
/*forceReturnServerCards=*/true);
List<AutofillPaymentInstrument> availablePaymentMethods = new ArrayList<>();
for (PaymentInstrument method : paymentMethods) {
if (method instanceof AutofillPaymentInstrument) {
availablePaymentMethods.add(((AutofillPaymentInstrument) method));
}
}
model.set(AssistantCollectUserDataModel.AVAILABLE_AUTOFILL_PAYMENT_METHODS,
availablePaymentMethods);
}
}