Commit d0244453 authored by Jordan Demeulenaere's avatar Jordan Demeulenaere Committed by Commit Bot

[Autofill Assistant] Implement Autofill fallback in case validation failed.

Bug: 806868
Change-Id: I64212a92405c2021e42b37f7c8b60ae28cc86aca
Reviewed-on: https://chromium-review.googlesource.com/1233699Reviewed-by: default avatarGanggui Tang <gogerald@chromium.org>
Commit-Queue: Ganggui Tang <gogerald@chromium.org>
Cr-Commit-Position: refs/heads/master@{#592841}
parent fb46cf46
...@@ -10,6 +10,10 @@ ...@@ -10,6 +10,10 @@
#include "base/callback_forward.h" #include "base/callback_forward.h"
namespace autofill {
class AutofillProfile;
}
namespace autofill_assistant { namespace autofill_assistant {
class ClientMemory; class ClientMemory;
...@@ -71,6 +75,19 @@ class ActionDelegate { ...@@ -71,6 +75,19 @@ class ActionDelegate {
const std::vector<std::vector<std::string>>& selectors_list, const std::vector<std::vector<std::string>>& selectors_list,
base::OnceCallback<void(const std::vector<std::string>&)> callback) = 0; base::OnceCallback<void(const std::vector<std::string>&)> callback) = 0;
// Set the |values| of all fields in |selectors_list| and return the result
// through |callback|. Selectors and values are one on one matched, i.e. the
// value of selectors_list[i] should be set to values[i] (therefore, this
// method requires that selectors_list.size() == values.size()).
virtual void SetFieldsValue(
const std::vector<std::vector<std::string>>& selectors_list,
const std::vector<std::string>& values,
base::OnceCallback<void(bool)> callback) = 0;
// Get the AutofillProfile with ID |guid|, or nullptr if it doesn't exist.
virtual const autofill::AutofillProfile* GetAutofillProfile(
const std::string& guid) = 0;
// Return the current ClientMemory. // Return the current ClientMemory.
virtual ClientMemory* GetClientMemory() = 0; virtual ClientMemory* GetClientMemory() = 0;
......
...@@ -9,46 +9,30 @@ ...@@ -9,46 +9,30 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/callback.h" #include "base/callback.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_profile.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill_assistant/browser/actions/action_delegate.h" #include "components/autofill_assistant/browser/actions/action_delegate.h"
#include "components/autofill_assistant/browser/client_memory.h" #include "components/autofill_assistant/browser/client_memory.h"
namespace autofill_assistant { namespace autofill_assistant {
AutofillAction::Data::Data() = default;
AutofillAction::Data::~Data() = default;
AutofillAction::AutofillAction(const ActionProto& proto) AutofillAction::AutofillAction(const ActionProto& proto)
: Action(proto), weak_ptr_factory_(this) { : Action(proto), weak_ptr_factory_(this) {
if (proto.has_use_address()) { if (proto.has_use_address()) {
data_.prompt = proto.use_address().prompt(); prompt_ = proto.use_address().prompt();
data_.name = proto.use_address().name(); name_ = proto.use_address().name();
for (const auto& selector : for (const auto& selector :
proto.use_address().form_field_element().selectors()) { proto.use_address().form_field_element().selectors()) {
data_.selectors.emplace_back(selector); selectors_.emplace_back(selector);
}
for (const auto& required_address_field :
proto.use_address().required_fields()) {
// Some UseAddressProto::RequiredField don't have a selector to only
// specify an address_field, in which case we ignore it.
if (required_address_field.element().selectors().empty()) {
continue;
}
data_.required_fields_selectors.emplace_back(std::vector<std::string>());
for (const auto& selector :
required_address_field.element().selectors()) {
data_.required_fields_selectors.back().emplace_back(selector);
}
} }
} else { } else {
// TODO(crbug.com/806868): Also read the required fields when filling a
// credit card form.
DCHECK(proto.has_use_card()); DCHECK(proto.has_use_card());
data_.is_autofill_card = true; is_autofill_card_ = true;
data_.prompt = proto.use_card().prompt(); prompt_ = proto.use_card().prompt();
for (const auto& selector : for (const auto& selector :
proto.use_card().form_field_element().selectors()) { proto.use_card().form_field_element().selectors()) {
data_.selectors.emplace_back(selector); selectors_.emplace_back(selector);
} }
} }
} }
...@@ -60,14 +44,14 @@ void AutofillAction::ProcessAction(ActionDelegate* delegate, ...@@ -60,14 +44,14 @@ void AutofillAction::ProcessAction(ActionDelegate* delegate,
processed_action_proto_ = std::make_unique<ProcessedActionProto>(); processed_action_proto_ = std::make_unique<ProcessedActionProto>();
// Check data already selected in a previous action. // Check data already selected in a previous action.
base::Optional<std::string> selected_data; base::Optional<std::string> selected_data;
if (data_.is_autofill_card) { if (is_autofill_card_) {
selected_data = delegate->GetClientMemory()->selected_card(); selected_data = delegate->GetClientMemory()->selected_card();
} else { } else {
selected_data = delegate->GetClientMemory()->selected_address(data_.name); selected_data = delegate->GetClientMemory()->selected_address(name_);
} }
if (selected_data) { if (selected_data) {
std::string guid = selected_data.value(); const std::string& guid = selected_data.value();
if (guid.empty()) { if (guid.empty()) {
// User selected 'Fill manually'. // User selected 'Fill manually'.
// TODO(crbug.com/806868): We need to differentiate between action failure // TODO(crbug.com/806868): We need to differentiate between action failure
...@@ -77,7 +61,7 @@ void AutofillAction::ProcessAction(ActionDelegate* delegate, ...@@ -77,7 +61,7 @@ void AutofillAction::ProcessAction(ActionDelegate* delegate,
return; return;
} }
if (data_.selectors.empty()) { if (selectors_.empty()) {
// If there is no selector, finish the action directly. // If there is no selector, finish the action directly.
UpdateProcessedAction(true); UpdateProcessedAction(true);
std::move(action_callback).Run(std::move(processed_action_proto_)); std::move(action_callback).Run(std::move(processed_action_proto_));
...@@ -89,9 +73,8 @@ void AutofillAction::ProcessAction(ActionDelegate* delegate, ...@@ -89,9 +73,8 @@ void AutofillAction::ProcessAction(ActionDelegate* delegate,
} }
// Show prompt. // Show prompt.
std::string prompt = data_.prompt; if (!prompt_.empty()) {
if (!prompt.empty()) { delegate->ShowStatusMessage(prompt_);
delegate->ShowStatusMessage(prompt);
} }
// Ask user to select the data. // Ask user to select the data.
...@@ -99,7 +82,7 @@ void AutofillAction::ProcessAction(ActionDelegate* delegate, ...@@ -99,7 +82,7 @@ void AutofillAction::ProcessAction(ActionDelegate* delegate,
base::BindOnce(&AutofillAction::OnDataSelected, base::BindOnce(&AutofillAction::OnDataSelected,
weak_ptr_factory_.GetWeakPtr(), delegate, weak_ptr_factory_.GetWeakPtr(), delegate,
std::move(action_callback)); std::move(action_callback));
if (data_.is_autofill_card) { if (is_autofill_card_) {
delegate->ChooseCard(std::move(selection_callback)); delegate->ChooseCard(std::move(selection_callback));
return; return;
} }
...@@ -111,10 +94,10 @@ void AutofillAction::OnDataSelected(ActionDelegate* delegate, ...@@ -111,10 +94,10 @@ void AutofillAction::OnDataSelected(ActionDelegate* delegate,
ProcessActionCallback action_callback, ProcessActionCallback action_callback,
const std::string& guid) { const std::string& guid) {
// Remember the selection. // Remember the selection.
if (data_.is_autofill_card) { if (is_autofill_card_) {
delegate->GetClientMemory()->set_selected_card(guid); delegate->GetClientMemory()->set_selected_card(guid);
} else { } else {
delegate->GetClientMemory()->set_selected_address(data_.name, guid); delegate->GetClientMemory()->set_selected_address(name_, guid);
} }
if (guid.empty()) { if (guid.empty()) {
...@@ -126,7 +109,7 @@ void AutofillAction::OnDataSelected(ActionDelegate* delegate, ...@@ -126,7 +109,7 @@ void AutofillAction::OnDataSelected(ActionDelegate* delegate,
return; return;
} }
if (data_.selectors.empty()) { if (selectors_.empty()) {
// If there is no selector, finish the action directly. This can be the case // If there is no selector, finish the action directly. This can be the case
// when we want to trigger the selection of address or card at the beginning // when we want to trigger the selection of address or card at the beginning
// of the script and use it later. // of the script and use it later.
...@@ -139,25 +122,27 @@ void AutofillAction::OnDataSelected(ActionDelegate* delegate, ...@@ -139,25 +122,27 @@ void AutofillAction::OnDataSelected(ActionDelegate* delegate,
FillFormWithData(guid, delegate, std::move(action_callback)); FillFormWithData(guid, delegate, std::move(action_callback));
} }
void AutofillAction::FillFormWithData(std::string guid, void AutofillAction::FillFormWithData(const std::string& guid,
ActionDelegate* delegate, ActionDelegate* delegate,
ProcessActionCallback action_callback) { ProcessActionCallback action_callback) {
DCHECK(!data_.selectors.empty()); DCHECK(!selectors_.empty());
if (data_.is_autofill_card) { if (is_autofill_card_) {
delegate->FillAddressForm( delegate->FillAddressForm(
guid, data_.selectors, guid, selectors_,
base::BindOnce(&AutofillAction::OnFormFilled, base::BindOnce(&AutofillAction::OnFormFilled,
weak_ptr_factory_.GetWeakPtr(), delegate, weak_ptr_factory_.GetWeakPtr(), guid, delegate,
std::move(action_callback))); std::move(action_callback)));
return; return;
} }
delegate->FillCardForm(guid, data_.selectors,
delegate->FillCardForm(guid, selectors_,
base::BindOnce(&AutofillAction::OnFormFilled, base::BindOnce(&AutofillAction::OnFormFilled,
weak_ptr_factory_.GetWeakPtr(), weak_ptr_factory_.GetWeakPtr(), guid,
delegate, std::move(action_callback))); delegate, std::move(action_callback)));
} }
void AutofillAction::OnFormFilled(ActionDelegate* delegate, void AutofillAction::OnFormFilled(const std::string& guid,
ActionDelegate* delegate,
ProcessActionCallback action_callback, ProcessActionCallback action_callback,
bool successful) { bool successful) {
// In case Autofill failed, we stop the action. // In case Autofill failed, we stop the action.
...@@ -168,37 +153,170 @@ void AutofillAction::OnFormFilled(ActionDelegate* delegate, ...@@ -168,37 +153,170 @@ void AutofillAction::OnFormFilled(ActionDelegate* delegate,
return; return;
} }
CheckRequiredFields(guid, delegate, std::move(action_callback),
/* allow_fallback */ true);
}
void AutofillAction::CheckRequiredFields(const std::string& guid,
ActionDelegate* delegate,
ProcessActionCallback action_callback,
bool allow_fallback) {
if (is_autofill_card_) {
// TODO(crbug.com/806868): Implement required fields checking for cards.
UpdateProcessedAction(true);
std::move(action_callback).Run(std::move(processed_action_proto_));
return;
}
// If there are no required fields, finish the action successfully. // If there are no required fields, finish the action successfully.
if (data_.required_fields_selectors.empty()) { if (proto_.use_address().required_fields().empty()) {
UpdateProcessedAction(true); UpdateProcessedAction(true);
std::move(action_callback).Run(std::move(processed_action_proto_)); std::move(action_callback).Run(std::move(processed_action_proto_));
return; return;
} }
// Otherwise, we check that all required fields have a value. std::vector<std::vector<std::string>> selectors_list;
for (const auto& required_address_field :
proto_.use_address().required_fields()) {
selectors_list.emplace_back(std::vector<std::string>());
DCHECK(required_address_field.has_address_field());
DCHECK(!required_address_field.element().selectors().empty());
for (const auto& selector : required_address_field.element().selectors()) {
selectors_list.back().emplace_back(selector);
}
}
delegate->GetFieldsValue( delegate->GetFieldsValue(
data_.required_fields_selectors, selectors_list,
base::BindOnce(&AutofillAction::OnGetRequiredFieldsValue, base::BindOnce(&AutofillAction::OnGetRequiredFieldsValue,
weak_ptr_factory_.GetWeakPtr(), weak_ptr_factory_.GetWeakPtr(), guid, delegate,
std::move(action_callback))); std::move(action_callback), allow_fallback));
} }
void AutofillAction::OnGetRequiredFieldsValue( void AutofillAction::OnGetRequiredFieldsValue(
const std::string& guid,
ActionDelegate* delegate,
ProcessActionCallback action_callback, ProcessActionCallback action_callback,
bool allow_fallback,
const std::vector<std::string>& values) { const std::vector<std::string>& values) {
for (const std::string& value : values) { DCHECK(!is_autofill_card_);
if (value.empty()) { DCHECK_EQ(proto_.use_address().required_fields_size(),
// Validation failed: at least one required field is empty. static_cast<int>(values.size()));
// TODO(crbug.com/806868): Tell the user to fill the form manually.
// TODO(crbug.com/806868): Use fallback and retry validation. const autofill::AutofillProfile* profile = delegate->GetAutofillProfile(guid);
DCHECK(profile);
// We process all fields with an empty value in order to perform the fallback
// on all those fields, if any.
bool validation_successful = true;
std::vector<std::vector<std::string>> failed_selectors;
std::vector<std::string> fallback_values;
for (size_t i = 0; i < values.size(); i++) {
if (values[i].empty()) {
if (!allow_fallback) {
// Validation failed and we don't want to try the fallback, so we fail
// the action.
UpdateProcessedAction(false); UpdateProcessedAction(false);
std::move(action_callback).Run(std::move(processed_action_proto_)); std::move(action_callback).Run(std::move(processed_action_proto_));
// TODO(crbug.com/806868): Tell the user to fill the form manually.
return; return;
} }
validation_successful = false;
std::string fallback_value = base::UTF16ToUTF8(GetAddressFieldValue(
profile, proto_.use_address().required_fields(i).address_field()));
if (fallback_value.empty()) {
// If there is no fallback value, we skip this failed field.
continue;
} }
fallback_values.emplace_back(fallback_value);
failed_selectors.emplace_back(std::vector<std::string>());
for (const auto& selector :
proto_.use_address().required_fields(i).element().selectors()) {
failed_selectors.back().emplace_back(selector);
}
}
}
DCHECK_EQ(failed_selectors.size(), fallback_values.size());
if (validation_successful) {
UpdateProcessedAction(true); UpdateProcessedAction(true);
std::move(action_callback).Run(std::move(processed_action_proto_)); std::move(action_callback).Run(std::move(processed_action_proto_));
return;
}
if (fallback_values.empty()) {
// One or more required fields is empty but there is no fallback value, so
// we fail the action.
UpdateProcessedAction(false);
std::move(action_callback).Run(std::move(processed_action_proto_));
// TODO(crbug.com/806868): Tell the user to fill the form manually.
return;
}
delegate->SetFieldsValue(
failed_selectors, fallback_values,
base::BindOnce(&AutofillAction::OnSetFieldsValue,
weak_ptr_factory_.GetWeakPtr(), guid, delegate,
std::move(action_callback)));
}
base::string16 AutofillAction::GetAddressFieldValue(
const autofill::AutofillProfile* profile,
const UseAddressProto::RequiredField::AddressField& address_field) {
// TODO(crbug.com/806868): Get the actual application locale.
std::string app_locale = "en-US";
switch (address_field) {
case UseAddressProto::RequiredField::FIRST_NAME:
return profile->GetInfo(autofill::NAME_FIRST, app_locale);
case UseAddressProto::RequiredField::LAST_NAME:
return profile->GetInfo(autofill::NAME_LAST, app_locale);
case UseAddressProto::RequiredField::FULL_NAME:
return profile->GetInfo(autofill::NAME_FULL, app_locale);
case UseAddressProto::RequiredField::PHONE_NUMBER:
return profile->GetInfo(autofill::PHONE_HOME_WHOLE_NUMBER, app_locale);
case UseAddressProto::RequiredField::EMAIL:
return profile->GetInfo(autofill::EMAIL_ADDRESS, app_locale);
case UseAddressProto::RequiredField::ORGANIZATION:
return profile->GetInfo(autofill::COMPANY_NAME, app_locale);
case UseAddressProto::RequiredField::COUNTRY_CODE:
return profile->GetInfo(autofill::ADDRESS_HOME_COUNTRY, app_locale);
case UseAddressProto::RequiredField::REGION:
return profile->GetInfo(autofill::ADDRESS_HOME_STATE, app_locale);
case UseAddressProto::RequiredField::STREET_ADDRESS:
return profile->GetInfo(autofill::ADDRESS_HOME_STREET_ADDRESS,
app_locale);
case UseAddressProto::RequiredField::LOCALITY:
return profile->GetInfo(autofill::ADDRESS_HOME_CITY, app_locale);
case UseAddressProto::RequiredField::DEPENDANT_LOCALITY:
return profile->GetInfo(autofill::ADDRESS_HOME_DEPENDENT_LOCALITY,
app_locale);
case UseAddressProto::RequiredField::POSTAL_CODE:
return profile->GetInfo(autofill::ADDRESS_HOME_ZIP, app_locale);
case UseAddressProto::RequiredField::UNDEFINED:
NOTREACHED();
return base::string16();
}
}
void AutofillAction::OnSetFieldsValue(const std::string& guid,
ActionDelegate* delegate,
ProcessActionCallback action_callback,
bool successful) {
if (!successful) {
// Fallback failed: we fail the action without checking the fields.
UpdateProcessedAction(false);
std::move(action_callback).Run(std::move(processed_action_proto_));
// TODO(crbug.com/806868): Tell the user to fill the form manually.
return;
}
// We check the required fields again, but this time we don't want to try the
// fallback in case if failure.
CheckRequiredFields(guid, delegate, std::move(action_callback),
/* allow_fallback */ false);
} }
} // namespace autofill_assistant. } // namespace autofill_assistant.
...@@ -13,7 +13,10 @@ ...@@ -13,7 +13,10 @@
#include "base/callback_forward.h" #include "base/callback_forward.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/optional.h"
namespace autofill {
class AutofillProfile;
}
namespace autofill_assistant { namespace autofill_assistant {
// An action to autofill a form using a local address or credit card. // An action to autofill a form using a local address or credit card.
...@@ -27,20 +30,6 @@ class AutofillAction : public Action { ...@@ -27,20 +30,6 @@ class AutofillAction : public Action {
ProcessActionCallback callback) override; ProcessActionCallback callback) override;
private: private:
struct Data {
Data();
~Data();
// Name of the address to use. Ignored if autofilling a card.
std::string name;
std::string prompt;
std::vector<std::string> selectors;
std::vector<std::vector<std::string>> required_fields_selectors;
// True if autofilling a card, otherwise we are autofilling an address.
bool is_autofill_card;
};
// Called when the user selected the data. // Called when the user selected the data.
void OnDataSelected(ActionDelegate* delegate, void OnDataSelected(ActionDelegate* delegate,
ProcessActionCallback callback, ProcessActionCallback callback,
...@@ -48,20 +37,52 @@ class AutofillAction : public Action { ...@@ -48,20 +37,52 @@ class AutofillAction : public Action {
// Fill the form using data with GUID |guid|. Return whether filling succeeded // Fill the form using data with GUID |guid|. Return whether filling succeeded
// or not through |callback|. // or not through |callback|.
void FillFormWithData(std::string guid, void FillFormWithData(const std::string& guid,
ActionDelegate* delegate, ActionDelegate* delegate,
ProcessActionCallback action_callback); ProcessActionCallback action_callback);
// Called when the form has been filled. // Called when the form has been filled.
void OnFormFilled(ActionDelegate* delegate, void OnFormFilled(const std::string& guid,
ActionDelegate* delegate,
ProcessActionCallback action_callback, ProcessActionCallback action_callback,
bool successful); bool successful);
// Check whether all required fields have a non-empty value. If it is the
// case, finish the action successfully. If it's not and |allow_fallback|
// false, fail the action. If |allow_fallback| is true, try again by filling
// the failed fields without Autofill.
void CheckRequiredFields(const std::string& guid,
ActionDelegate* delegate,
ProcessActionCallback action_callback,
bool allow_fallback);
// Called when we get the value of the required fields. // Called when we get the value of the required fields.
void OnGetRequiredFieldsValue(ProcessActionCallback action_callback, void OnGetRequiredFieldsValue(const std::string& guid,
ActionDelegate* delegate,
ProcessActionCallback action_callback,
bool allow_fallback,
const std::vector<std::string>& values); const std::vector<std::string>& values);
Data data_; // Get the value of |address_field| associated to profile |profile|. Return
// empty string if there is no data available.
base::string16 GetAddressFieldValue(
const autofill::AutofillProfile* profile,
const UseAddressProto::RequiredField::AddressField& address_field);
// Called after trying to set form values without Autofill in case of fallback
// after failed validation.
void OnSetFieldsValue(const std::string& guid,
ActionDelegate* delegate,
ProcessActionCallback action_callback,
bool successful);
// Usage of the autofilled address. Ignored if autofilling a card.
std::string name_;
std::string prompt_;
std::vector<std::string> selectors_;
// True if autofilling a card, otherwise we are autofilling an address.
bool is_autofill_card_;
base::WeakPtrFactory<AutofillAction> weak_ptr_factory_; base::WeakPtrFactory<AutofillAction> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(AutofillAction); DISALLOW_COPY_AND_ASSIGN(AutofillAction);
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/callback.h" #include "base/callback.h"
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "components/autofill/core/browser/autofill_profile.h"
#include "components/autofill_assistant/browser/protocol_utils.h" #include "components/autofill_assistant/browser/protocol_utils.h"
#include "components/autofill_assistant/browser/service.h" #include "components/autofill_assistant/browser/service.h"
#include "components/autofill_assistant/browser/ui_controller.h" #include "components/autofill_assistant/browser/ui_controller.h"
...@@ -91,6 +92,20 @@ void ScriptExecutor::GetFieldsValue( ...@@ -91,6 +92,20 @@ void ScriptExecutor::GetFieldsValue(
std::move(callback)); std::move(callback));
} }
void ScriptExecutor::SetFieldsValue(
const std::vector<std::vector<std::string>>& selectors_list,
const std::vector<std::string>& values,
base::OnceCallback<void(bool)> callback) {
delegate_->GetWebController()->SetFieldsValue(selectors_list, values,
std::move(callback));
}
const autofill::AutofillProfile* ScriptExecutor::GetAutofillProfile(
const std::string& guid) {
// TODO(crbug.com/806868): Implement GetAutofillProfile.
return nullptr;
}
ClientMemory* ScriptExecutor::GetClientMemory() { ClientMemory* ScriptExecutor::GetClientMemory() {
return delegate_->GetClientMemory(); return delegate_->GetClientMemory();
} }
......
...@@ -55,6 +55,12 @@ class ScriptExecutor : public ActionDelegate { ...@@ -55,6 +55,12 @@ class ScriptExecutor : public ActionDelegate {
const std::vector<std::vector<std::string>>& selectors_list, const std::vector<std::vector<std::string>>& selectors_list,
base::OnceCallback<void(const std::vector<std::string>&)> callback) base::OnceCallback<void(const std::vector<std::string>&)> callback)
override; override;
void SetFieldsValue(
const std::vector<std::vector<std::string>>& selectors_list,
const std::vector<std::string>& values,
base::OnceCallback<void(bool)> callback) override;
const autofill::AutofillProfile* GetAutofillProfile(
const std::string& guid) override;
ClientMemory* GetClientMemory() override; ClientMemory* GetClientMemory() override;
private: private:
......
...@@ -233,8 +233,29 @@ message FocusElementProto { ...@@ -233,8 +233,29 @@ message FocusElementProto {
// Fill a form with an address if there is, otherwise fail this action. // Fill a form with an address if there is, otherwise fail this action.
message UseAddressProto { message UseAddressProto {
// Message used to indicate which form fields should be filled. // Message used to indicate what form fields should be filled with what
message RequiredField { optional ElementReferenceProto element = 2; } // information coming from the address.
message RequiredField {
enum AddressField {
UNDEFINED = 0;
FIRST_NAME = 1;
LAST_NAME = 2;
FULL_NAME = 3;
PHONE_NUMBER = 4;
EMAIL = 5;
ORGANIZATION = 6;
COUNTRY_CODE = 7;
REGION = 8; // e.g. state
STREET_ADDRESS = 9;
LOCALITY = 10; // e.g. city
DEPENDANT_LOCALITY = 11;
POSTAL_CODE = 12;
}
optional AddressField address_field = 1;
optional ElementReferenceProto element = 2;
}
// An optional name to allow to handle multiple addresses selection (for // An optional name to allow to handle multiple addresses selection (for
// instance a billing and a delivery address). // instance a billing and a delivery address).
......
...@@ -581,4 +581,13 @@ void WebController::GetFieldsValue( ...@@ -581,4 +581,13 @@ void WebController::GetFieldsValue(
std::move(callback).Run(values); std::move(callback).Run(values);
} }
} // namespace autofill_assistant void WebController::SetFieldsValue(
const std::vector<std::vector<std::string>>& selectors_list,
const std::vector<std::string>& values,
base::OnceCallback<void(bool)> callback) {
DCHECK_EQ(selectors_list.size(), values.size());
// TODO(crbug.com/806868): Implement set fields value operation.
std::move(callback).Run(true);
}
} // namespace autofill_assistant.
...@@ -84,6 +84,15 @@ class WebController { ...@@ -84,6 +84,15 @@ class WebController {
const std::vector<std::vector<std::string>>& selectors_list, const std::vector<std::vector<std::string>>& selectors_list,
base::OnceCallback<void(const std::vector<std::string>&)> callback); base::OnceCallback<void(const std::vector<std::string>&)> callback);
// Set the |values| of all fields in |selectors_list| and return the result
// through |callback|. Selectors and values are one on one matched, i.e. the
// value of selectors_list[i] should be set to values[i] (therefore, this
// method requires that selectors_list.size() == values.size()).
virtual void SetFieldsValue(
const std::vector<std::vector<std::string>>& selectors_list,
const std::vector<std::string>& values,
base::OnceCallback<void(bool)> callback);
private: private:
friend class WebControllerBrowserTest; friend class WebControllerBrowserTest;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment