blob: aaaf9ef2527b3cb67cba55125630e9c548b63cf9 [file] [log] [blame]
// Copyright 2019 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.
#include "components/autofill/core/browser/label_formatter_utils.h"
#include <algorithm>
#include <iterator>
#include <memory>
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/address_i18n.h"
#include "components/autofill/core/browser/autofill_data_util.h"
#include "components/autofill/core/browser/phone_number_i18n.h"
#include "components/autofill/core/browser/validation.h"
#include "components/grit/components_scaled_resources.h"
#include "components/strings/grit/components_strings.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_data.h"
#include "third_party/libaddressinput/src/cpp/include/libaddressinput/address_formatter.h"
#include "ui/base/l10n/l10n_util.h"
namespace autofill {
const int kStreetAddressFieldTypes[] = {
ADDRESS_HOME_LINE1, ADDRESS_HOME_LINE2,
ADDRESS_HOME_APT_NUM, ADDRESS_BILLING_LINE1,
ADDRESS_BILLING_LINE2, ADDRESS_BILLING_APT_NUM,
ADDRESS_HOME_STREET_ADDRESS, ADDRESS_BILLING_STREET_ADDRESS,
ADDRESS_HOME_LINE3, ADDRESS_BILLING_LINE3};
bool ContainsName(uint32_t groups) {
return groups & label_formatter_groups::kName;
}
bool ContainsAddress(uint32_t groups) {
return groups & label_formatter_groups::kAddress;
}
bool ContainsEmail(uint32_t groups) {
return groups & label_formatter_groups::kEmail;
}
bool ContainsPhone(uint32_t groups) {
return groups & label_formatter_groups::kPhone;
}
uint32_t DetermineGroups(const std::vector<ServerFieldType>& types) {
uint32_t group_bitmask = 0;
for (const ServerFieldType& type : types) {
const FieldTypeGroup group =
AutofillType(AutofillType(type).GetStorableType()).group();
switch (group) {
case autofill::NAME:
group_bitmask |= label_formatter_groups::kName;
break;
case autofill::ADDRESS_HOME:
group_bitmask |= label_formatter_groups::kAddress;
break;
case autofill::EMAIL:
group_bitmask |= label_formatter_groups::kEmail;
break;
case autofill::PHONE_HOME:
group_bitmask |= label_formatter_groups::kPhone;
break;
default:
break;
}
}
return group_bitmask;
}
bool IsStreetAddressPart(ServerFieldType type) {
return std::find(std::begin(kStreetAddressFieldTypes),
std::end(kStreetAddressFieldTypes),
type) != std::end(kStreetAddressFieldTypes);
}
bool HasStreetAddress(const std::vector<ServerFieldType>& types) {
return std::any_of(types.begin(), types.end(), IsStreetAddressPart);
}
std::vector<ServerFieldType> ExtractSpecifiedAddressFieldTypes(
bool extract_street_address_types,
const std::vector<ServerFieldType>& types) {
auto should_be_extracted =
[&extract_street_address_types](ServerFieldType type) -> bool {
return AutofillType(AutofillType(type).GetStorableType()).group() ==
ADDRESS_HOME &&
(extract_street_address_types ? IsStreetAddressPart(type)
: !IsStreetAddressPart(type));
};
std::vector<ServerFieldType> extracted_address_types;
std::copy_if(types.begin(), types.end(),
std::back_inserter(extracted_address_types),
should_be_extracted);
return extracted_address_types;
}
std::vector<ServerFieldType> ExtractAddressFieldTypes(
const std::vector<ServerFieldType>& types) {
std::vector<ServerFieldType> only_address_types;
// Note that GetStorableType maps billing fields to their corresponding non-
// billing fields, e.g. ADDRESS_HOME_ZIP is mapped to ADDRESS_BILLING_ZIP.
std::copy_if(
types.begin(), types.end(), std::back_inserter(only_address_types),
[](ServerFieldType type) {
return AutofillType(AutofillType(type).GetStorableType()).group() ==
ADDRESS_HOME;
});
return only_address_types;
}
void AddLabelPartIfNotEmpty(const base::string16& part,
std::vector<base::string16>* parts) {
if (!part.empty()) {
parts->push_back(part);
}
}
base::string16 ConstructLabelLine(const std::vector<base::string16>& parts) {
return base::JoinString(parts, l10n_util::GetStringUTF16(
IDS_AUTOFILL_SUGGESTION_LABEL_SEPARATOR));
}
base::string16 ConstructLabelLines(const base::string16& top_line,
const base::string16& bottom_line) {
if (top_line.empty()) {
return bottom_line;
}
if (bottom_line.empty()) {
return top_line;
}
return base::JoinString({top_line, bottom_line},
base::ASCIIToUTF16(kMultilineLabelDelimiter));
}
AutofillProfile MakeTrimmedProfile(const AutofillProfile& profile,
const std::string& app_locale,
const std::vector<ServerFieldType>& types) {
AutofillProfile trimmed_profile(profile.guid(), profile.origin());
trimmed_profile.set_language_code(profile.language_code());
const AutofillType country_code_type(HTML_TYPE_COUNTRY_CODE, HTML_MODE_NONE);
const base::string16 country_code =
profile.GetInfo(country_code_type, app_locale);
trimmed_profile.SetInfo(country_code_type, country_code, app_locale);
for (const ServerFieldType& type : types) {
trimmed_profile.SetInfo(type, profile.GetInfo(type, app_locale),
app_locale);
}
return trimmed_profile;
}
base::string16 GetLabelName(const AutofillProfile& profile,
const std::string& app_locale) {
return profile.GetInfo(AutofillType(NAME_FULL), app_locale);
}
base::string16 GetLabelForFocusedAddress(
ServerFieldType focused_field_type,
bool form_has_street_address,
const AutofillProfile& profile,
const std::string& app_locale,
const std::vector<ServerFieldType>& types) {
return GetLabelAddress(
form_has_street_address && !IsStreetAddressPart(focused_field_type),
profile, app_locale, types);
}
base::string16 GetLabelAddress(bool use_street_address,
const AutofillProfile& profile,
const std::string& app_locale,
const std::vector<ServerFieldType>& types) {
return use_street_address
? GetLabelStreetAddress(
profile, app_locale,
ExtractSpecifiedAddressFieldTypes(use_street_address, types))
: GetLabelNationalAddress(profile, app_locale,
ExtractSpecifiedAddressFieldTypes(
use_street_address, types));
}
base::string16 GetLabelNationalAddress(
const AutofillProfile& profile,
const std::string& app_locale,
const std::vector<ServerFieldType>& types) {
std::unique_ptr<::i18n::addressinput::AddressData> address_data =
i18n::CreateAddressDataFromAutofillProfile(
MakeTrimmedProfile(profile, app_locale, types), app_locale);
std::string address_line;
::i18n::addressinput::GetFormattedNationalAddressLine(*address_data,
&address_line);
return base::UTF8ToUTF16(address_line);
}
base::string16 GetLabelStreetAddress(
const AutofillProfile& profile,
const std::string& app_locale,
const std::vector<ServerFieldType>& types) {
std::unique_ptr<::i18n::addressinput::AddressData> address_data =
i18n::CreateAddressDataFromAutofillProfile(
MakeTrimmedProfile(profile, app_locale, types), app_locale);
std::string address_line;
::i18n::addressinput::GetStreetAddressLinesAsSingleLine(*address_data,
&address_line);
return base::UTF8ToUTF16(address_line);
}
base::string16 GetLabelForProfileOnFocusedNonStreetAddress(
bool form_has_street_address,
const AutofillProfile& profile,
const std::string& app_locale,
const std::vector<ServerFieldType>& types,
const base::string16& contact_info) {
std::vector<base::string16> label_parts;
AddLabelPartIfNotEmpty(
GetLabelAddress(form_has_street_address, profile, app_locale, types),
&label_parts);
AddLabelPartIfNotEmpty(contact_info, &label_parts);
return ConstructLabelLine(label_parts);
}
base::string16 GetLabelEmail(const AutofillProfile& profile,
const std::string& app_locale) {
const base::string16 email =
profile.GetInfo(AutofillType(EMAIL_ADDRESS), app_locale);
return IsValidEmailAddress(email) ? email : base::string16();
}
base::string16 GetLabelPhone(const AutofillProfile& profile,
const std::string& app_locale) {
const std::string unformatted_phone = base::UTF16ToUTF8(
profile.GetInfo(AutofillType(PHONE_HOME_WHOLE_NUMBER), app_locale));
return unformatted_phone.empty()
? base::string16()
: base::UTF8ToUTF16(i18n::FormatPhoneNationallyForDisplay(
unformatted_phone,
data_util::GetCountryCodeWithFallback(profile, app_locale)));
}
bool HaveSameEmailAddresses(const std::vector<AutofillProfile*>& profiles,
const std::string& app_locale) {
bool first_email_found = false;
base::string16 first_email;
for (const AutofillProfile* profile : profiles) {
base::string16 email_from_profile = GetLabelEmail(*profile, app_locale);
if (!first_email_found) {
// Store the first email address whether it's empty or not because we
// consider "" and "hao.le@aol.com" to be different email addresses.
first_email_found = true;
first_email = email_from_profile;
} else if (email_from_profile != first_email) {
return false;
}
}
return true;
}
bool HaveSamePhoneNumbers(const std::vector<AutofillProfile*>& profiles,
const std::string& app_locale) {
bool first_phone_found = false;
base::string16 first_phone;
for (const AutofillProfile* profile : profiles) {
base::string16 phone_from_profile = GetLabelPhone(*profile, app_locale);
if (!first_phone_found) {
// Store the first phone number whether it's empty or not because we
// consider "" and "(514) 873-1100" to be different phone numbers.
first_phone_found = true;
first_phone = phone_from_profile;
} else if (!(first_phone.empty() && phone_from_profile.empty()) &&
!i18n::PhoneNumbersMatch(first_phone, phone_from_profile,
base::UTF16ToASCII(profile->GetInfo(
ADDRESS_HOME_COUNTRY, app_locale)),
app_locale)) {
return false;
}
}
return true;
}
} // namespace autofill