const char kLastUsedShippingAddressGuid[] = "last_used_shipping";
const char kLastUsedCreditCardGuid[] = "last_used_card";
+// Constructs |inputs| for the SECTION_CC_BILLING section.
+void BuildCcBillingInputs(DetailInputs* inputs) {
+ const DetailInput kCcBillingInputs[] = {
+ { DetailInput::LONG, NAME_BILLING_FULL },
+ { DetailInput::LONG, ADDRESS_BILLING_STREET_ADDRESS },
+ { DetailInput::LONG, ADDRESS_BILLING_CITY },
+ { DetailInput::LONG, ADDRESS_BILLING_DEPENDENT_LOCALITY },
+ { DetailInput::LONG, ADDRESS_BILLING_STATE },
+ { DetailInput::LONG, ADDRESS_BILLING_ZIP },
+ { DetailInput::LONG, ADDRESS_BILLING_SORTING_CODE },
+ { DetailInput::LONG, ADDRESS_BILLING_COUNTRY },
+ { DetailInput::LONG, PHONE_BILLING_WHOLE_NUMBER },
+ { DetailInput::LONG, CREDIT_CARD_NUMBER },
+ { DetailInput::LONG, CREDIT_CARD_EXP_MONTH },
+ { DetailInput::LONG, CREDIT_CARD_EXP_4_DIGIT_YEAR },
+ { DetailInput::LONG, CREDIT_CARD_VERIFICATION_CODE },
+ };
+ common::BuildInputs(kCcBillingInputs, arraysize(kCcBillingInputs), inputs);
+}
+
+// Constructs |inputs| for the SECTION_SHIPPING section.
+void BuildShippingInputs(DetailInputs* inputs) {
+ const DetailInput kShippingInputs[] = {
+ { DetailInput::LONG, NAME_FULL },
+ { DetailInput::LONG, ADDRESS_HOME_STREET_ADDRESS },
+ { DetailInput::LONG, ADDRESS_HOME_CITY },
+ { DetailInput::LONG, ADDRESS_HOME_DEPENDENT_LOCALITY },
+ { DetailInput::LONG, ADDRESS_HOME_STATE },
+ { DetailInput::LONG, ADDRESS_HOME_ZIP },
+ { DetailInput::LONG, ADDRESS_HOME_SORTING_CODE },
+ { DetailInput::LONG, ADDRESS_HOME_COUNTRY },
+ { DetailInput::LONG, PHONE_HOME_WHOLE_NUMBER },
+ };
+ common::BuildInputs(kShippingInputs, arraysize(kShippingInputs), inputs);
+}
+
base::string16 NullGetInfo(const AutofillType& type) {
return base::string16();
}
FormStructure& form_structure,
FullWallet* full_wallet,
const base::string16& email_address) {
+ DCHECK(section == SECTION_CC_BILLING || section == SECTION_SHIPPING);
DetailInputs inputs;
- common::BuildInputsForSection(section, "US", &inputs);
+ if (section == SECTION_CC_BILLING)
+ BuildCcBillingInputs(&inputs);
+ else
+ BuildShippingInputs(&inputs);
FillOutputForSectionWithComparator(
section, inputs,
content::WebContents* contents,
const FormData& form_structure,
const GURL& source_url,
- const base::Callback<void(const FormStructure*)>& callback) {
+ const AutofillManagerDelegate::ResultCallback& callback) {
// AutofillDialogControllerAndroid owns itself.
AutofillDialogControllerAndroid* autofill_dialog_controller =
new AutofillDialogControllerAndroid(contents,
content::WebContents* contents,
const FormData& form_structure,
const GURL& source_url,
- const base::Callback<void(const FormStructure*)>& callback) {
+ const AutofillManagerDelegate::ResultCallback& callback) {
return AutofillDialogControllerAndroid::Create(contents,
form_structure,
source_url,
JNIEnv* env = base::android::AttachCurrentThread();
dialog_shown_timestamp_ = base::Time::Now();
+ // The Autofill dialog is shown in response to a message from the renderer and
+ // as such, it can only be made in the context of the current document. A call
+ // to GetActiveEntry would return a pending entry, if there was one, which
+ // would be a security bug. Therefore, we use the last committed URL for the
+ // access checks.
const GURL& current_url = contents_->GetLastCommittedURL();
invoked_from_same_origin_ =
current_url.GetOrigin() == source_url_.GetOrigin();
+ // Fail if the dialog factory (e.g. SDK) doesn't support cross-origin calls.
+ if (!Java_AutofillDialogControllerAndroid_isDialogAllowed(
+ env,
+ invoked_from_same_origin_)) {
+ callback_.Run(
+ AutofillManagerDelegate::AutocompleteResultErrorDisabled,
+ base::ASCIIToUTF16("Cross-origin form invocations are not supported."),
+ NULL);
+ delete this;
+ return;
+ }
+
// Determine what field types should be included in the dialog.
bool has_types = false;
bool has_sections = false;
// Fail if the author didn't specify autocomplete types, or
// if the dialog shouldn't be shown in a given circumstances.
- if (!has_types ||
- !Java_AutofillDialogControllerAndroid_isDialogAllowed(
- env,
- invoked_from_same_origin_)) {
- callback_.Run(NULL);
+ if (!has_types) {
+ callback_.Run(
+ AutofillManagerDelegate::AutocompleteResultErrorDisabled,
+ base::ASCIIToUTF16("Form is missing autocomplete attributes."),
+ NULL);
+ delete this;
+ return;
+ }
+
+ // Fail if the author didn't ask for at least some kind of credit card
+ // information.
+ bool has_credit_card_field = false;
+ for (size_t i = 0; i < form_structure_.field_count(); ++i) {
+ AutofillType type = form_structure_.field(i)->Type();
+ if (type.html_type() != HTML_TYPE_UNKNOWN && type.group() == CREDIT_CARD) {
+ has_credit_card_field = true;
+ break;
+ }
+ }
+
+ if (!has_credit_card_field) {
+ callback_.Run(
+ AutofillManagerDelegate::AutocompleteResultErrorDisabled,
+ base::ASCIIToUTF16("Form is not a payment form (must contain "
+ "some autocomplete=\"cc-*\" fields). "),
+ NULL);
delete this;
return;
}
const ServerFieldType full_billing_is_necessary_if[] = {
ADDRESS_BILLING_LINE1,
ADDRESS_BILLING_LINE2,
+ ADDRESS_BILLING_APT_NUM,
ADDRESS_BILLING_CITY,
ADDRESS_BILLING_STATE,
+ // ADDRESS_BILLING_ZIP, // Postal code alone is a short form.
+ ADDRESS_BILLING_COUNTRY,
+ ADDRESS_BILLING_STREET_ADDRESS,
+ ADDRESS_BILLING_DEPENDENT_LOCALITY,
+ ADDRESS_BILLING_SORTING_CODE,
PHONE_BILLING_WHOLE_NUMBER
};
+ const ServerFieldType billing_phone_number_is_necessary_if[] = {
+ PHONE_BILLING_WHOLE_NUMBER
+ };
+ const ServerFieldType shipping_phone_number_is_necessary_if[] = {
+ PHONE_HOME_WHOLE_NUMBER
+ };
const bool request_full_billing_address =
IsSectionInputsUsedInFormStructure(
SECTION_BILLING,
arraysize(full_billing_is_necessary_if),
form_structure_);
const bool request_phone_numbers =
- IsSectionInputUsedInFormStructure(
+ IsSectionInputsUsedInFormStructure(
SECTION_BILLING,
- PHONE_BILLING_WHOLE_NUMBER,
+ billing_phone_number_is_necessary_if,
+ arraysize(billing_phone_number_is_necessary_if),
form_structure_) ||
- IsSectionInputUsedInFormStructure(
+ IsSectionInputsUsedInFormStructure(
SECTION_SHIPPING,
- PHONE_HOME_WHOLE_NUMBER,
+ shipping_phone_number_is_necessary_if,
+ arraysize(shipping_phone_number_is_necessary_if),
form_structure_);
bool request_shipping_address = false;
{
DetailInputs inputs;
- common::BuildInputsForSection(SECTION_SHIPPING, "US", &inputs);
+ BuildShippingInputs(&inputs);
request_shipping_address = form_structure_.FillFields(
common::TypesFromInputs(inputs),
base::Bind(common::ServerTypeMatchesField, SECTION_SHIPPING),
ScopedJavaLocalRef<jstring> jmerchant_domain =
base::android::ConvertUTF8ToJavaString(
env, source_url_.GetOrigin().spec());
+ const std::set<base::string16> availableShippingCountriesSet =
+ form_structure_.PossibleValues(ADDRESS_HOME_COUNTRY);
+ ScopedJavaLocalRef<jobjectArray> jshipping_countries =
+ base::android::ToJavaArrayOfStrings(
+ env,
+ std::vector<base::string16>(availableShippingCountriesSet.begin(),
+ availableShippingCountriesSet.end()));
+
java_object_.Reset(Java_AutofillDialogControllerAndroid_create(
env,
reinterpret_cast<intptr_t>(this),
last_used_choice_is_autofill, jlast_used_account_name.obj(),
jlast_used_billing.obj(), jlast_used_shipping.obj(),
jlast_used_card.obj(),
- jmerchant_domain.obj()));
+ jmerchant_domain.obj(),
+ jshipping_countries.obj()));
}
void AutofillDialogControllerAndroid::Hide() {
void AutofillDialogControllerAndroid::DialogCancel(JNIEnv* env,
jobject obj) {
LogOnCancelMetrics();
- callback_.Run(NULL);
+ callback_.Run(AutofillManagerDelegate::AutocompleteResultErrorCancel,
+ base::string16(),
+ NULL);
}
void AutofillDialogControllerAndroid::DialogContinue(
if (!last_used_card.empty())
defaults->SetString(kLastUsedCreditCardGuid, last_used_card);
} else {
- LOG(ERROR) << "Failed to save AutofillDialog preferences";
+ DLOG(ERROR) << "Failed to save AutofillDialog preferences";
}
}
LogOnFinishSubmitMetrics();
// Callback should be called as late as possible.
- callback_.Run(&form_structure_);
+ callback_.Run(AutofillManagerDelegate::AutocompleteResultSuccess,
+ base::string16(),
+ &form_structure_);
// This might delete us.
Hide();
content::WebContents* contents,
const FormData& form_structure,
const GURL& source_url,
- const base::Callback<void(const FormStructure*)>& callback)
+ const AutofillManagerDelegate::ResultCallback& callback)
: profile_(Profile::FromBrowserContext(contents->GetBrowserContext())),
contents_(contents),
initial_user_state_(AutofillMetrics::DIALOG_USER_STATE_UNKNOWN),