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

Reland "[Autofill Assistant] Add StopCurrentScript() in ActionDelegate."

This is a reland of e195437f

The first version of this change was broken because ActionDelegate::StopCurrentScript() was not abstract (pure virtual).

This was fixed in this CL by adding "= 0"; at the function declaration in action_delegate.h.

Original change's description:
> [Autofill Assistant] Add StopCurrentScript() in ActionDelegate.
>
> Bug: 806868
> Change-Id: Ic3deb3353377e950fadc0d011c75f7ed91ca5366
> Reviewed-on: https://chromium-review.googlesource.com/1250923
> Commit-Queue: Rouslan Solomakhin <rouslan@chromium.org>
> Reviewed-by: Rouslan Solomakhin <rouslan@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#595445}

Bug: 806868
Change-Id: Ic57f8607844267c98d0ab5ece8a253ae853ec325
Reviewed-on: https://chromium-review.googlesource.com/1256184Reviewed-by: default avatarRouslan Solomakhin <rouslan@chromium.org>
Commit-Queue: Jordan Demeulenaere <jdemeulenaere@chromium.org>
Cr-Commit-Position: refs/heads/master@{#595826}
parent 14e1c308
...@@ -105,6 +105,9 @@ class ActionDelegate { ...@@ -105,6 +105,9 @@ class ActionDelegate {
// state. // state.
virtual void Restart() = 0; virtual void Restart() = 0;
// Stop the current script and show |message| if it is not empty .
virtual void StopCurrentScript(const std::string& message) = 0;
// Return the current ClientMemory. // Return the current ClientMemory.
virtual ClientMemory* GetClientMemory() = 0; virtual ClientMemory* GetClientMemory() = 0;
......
...@@ -97,6 +97,8 @@ AutofillAction::AutofillAction(const ActionProto& proto) ...@@ -97,6 +97,8 @@ AutofillAction::AutofillAction(const ActionProto& proto)
proto.use_address().form_field_element().selectors()) { proto.use_address().form_field_element().selectors()) {
selectors_.emplace_back(selector); selectors_.emplace_back(selector);
} }
fill_form_message_ = proto.use_address().strings().fill_form();
check_form_message_ = proto.use_address().strings().check_form();
} else { } else {
DCHECK(proto.has_use_card()); DCHECK(proto.has_use_card());
is_autofill_card_ = true; is_autofill_card_ = true;
...@@ -106,6 +108,8 @@ AutofillAction::AutofillAction(const ActionProto& proto) ...@@ -106,6 +108,8 @@ AutofillAction::AutofillAction(const ActionProto& proto)
proto.use_card().form_field_element().selectors()) { proto.use_card().form_field_element().selectors()) {
selectors_.emplace_back(selector); selectors_.emplace_back(selector);
} }
fill_form_message_ = proto.use_card().strings().fill_form();
check_form_message_ = proto.use_card().strings().check_form();
} }
} }
...@@ -127,19 +131,14 @@ void AutofillAction::ProcessAction(ActionDelegate* delegate, ...@@ -127,19 +131,14 @@ void AutofillAction::ProcessAction(ActionDelegate* delegate,
const 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 delegate->StopCurrentScript(fill_form_message_);
// and stopping an action to let the user fill a form (expected stop). EndAction(/* successful= */ true);
UpdateProcessedAction(false);
std::move(process_action_callback_)
.Run(std::move(processed_action_proto_));
return; return;
} }
if (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); EndAction(/* successful= */ true);
std::move(process_action_callback_)
.Run(std::move(processed_action_proto_));
return; return;
} }
...@@ -164,6 +163,11 @@ void AutofillAction::ProcessAction(ActionDelegate* delegate, ...@@ -164,6 +163,11 @@ void AutofillAction::ProcessAction(ActionDelegate* delegate,
delegate->ChooseAddress(std::move(selection_callback)); delegate->ChooseAddress(std::move(selection_callback));
} }
void AutofillAction::EndAction(bool successful) {
UpdateProcessedAction(successful);
std::move(process_action_callback_).Run(std::move(processed_action_proto_));
}
void AutofillAction::OnDataSelected(ActionDelegate* delegate, void AutofillAction::OnDataSelected(ActionDelegate* delegate,
const std::string& guid) { const std::string& guid) {
// Remember the selection. // Remember the selection.
...@@ -177,21 +181,17 @@ void AutofillAction::OnDataSelected(ActionDelegate* delegate, ...@@ -177,21 +181,17 @@ void AutofillAction::OnDataSelected(ActionDelegate* delegate,
// 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.
UpdateProcessedAction(true); EndAction(/* successful= */ true);
std::move(process_action_callback_).Run(std::move(processed_action_proto_));
return; return;
} }
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 delegate->StopCurrentScript(fill_form_message_);
// and stopping an action to let the user fill a form (expected stop). EndAction(/* successful= */ true);
UpdateProcessedAction(false);
std::move(process_action_callback_).Run(std::move(processed_action_proto_));
return; return;
} }
// TODO(crbug.com/806868): Validate form and use fallback if needed.
FillFormWithData(guid, delegate); FillFormWithData(guid, delegate);
} }
...@@ -238,11 +238,9 @@ void AutofillAction::OnGetFullCard(ActionDelegate* delegate, ...@@ -238,11 +238,9 @@ void AutofillAction::OnGetFullCard(ActionDelegate* delegate,
void AutofillAction::OnFormFilled(const std::string& guid, void AutofillAction::OnFormFilled(const std::string& guid,
ActionDelegate* delegate, ActionDelegate* delegate,
bool successful) { bool successful) {
// In case Autofill failed, we stop the action. // In case Autofill failed, we fail the action.
if (!successful) { if (!successful) {
UpdateProcessedAction(false); EndAction(/* successful= */ false);
std::move(process_action_callback_).Run(std::move(processed_action_proto_));
// TODO(crbug.com/806868): Tell the user to fill the form manually.
return; return;
} }
...@@ -254,15 +252,13 @@ void AutofillAction::CheckRequiredFields(const std::string& guid, ...@@ -254,15 +252,13 @@ void AutofillAction::CheckRequiredFields(const std::string& guid,
bool allow_fallback) { bool allow_fallback) {
if (is_autofill_card_) { if (is_autofill_card_) {
// TODO(crbug.com/806868): Implement required fields checking for cards. // TODO(crbug.com/806868): Implement required fields checking for cards.
UpdateProcessedAction(true); EndAction(/* successful= */ true);
std::move(process_action_callback_).Run(std::move(processed_action_proto_));
return; return;
} }
// If there are no required fields, finish the action successfully. // If there are no required fields, finish the action successfully.
if (proto_.use_address().required_fields().empty()) { if (proto_.use_address().required_fields().empty()) {
UpdateProcessedAction(true); EndAction(/* successful= */ true);
std::move(process_action_callback_).Run(std::move(processed_action_proto_));
return; return;
} }
...@@ -313,12 +309,10 @@ void AutofillAction::OnGetRequiredFieldValue( ...@@ -313,12 +309,10 @@ void AutofillAction::OnGetRequiredFieldValue(
for (size_t i = 0; i < required_fields_value_status_.size(); i++) { for (size_t i = 0; i < required_fields_value_status_.size(); i++) {
if (required_fields_value_status_[i] == EMPTY) { if (required_fields_value_status_[i] == EMPTY) {
if (!allow_fallback) { if (!allow_fallback) {
// Validation failed and we don't want to try the fallback, so we fail // Validation failed and we don't want to try the fallback, so we stop
// the action. // the script.
UpdateProcessedAction(false); delegate->StopCurrentScript(check_form_message_);
std::move(process_action_callback_) EndAction(/* successful= */ true);
.Run(std::move(processed_action_proto_));
// TODO(crbug.com/806868): Tell the user to fill the form manually.
return; return;
} }
...@@ -342,17 +336,15 @@ void AutofillAction::OnGetRequiredFieldValue( ...@@ -342,17 +336,15 @@ void AutofillAction::OnGetRequiredFieldValue(
DCHECK_EQ(failed_selectors.size(), fallback_values.size()); DCHECK_EQ(failed_selectors.size(), fallback_values.size());
if (validation_successful) { if (validation_successful) {
UpdateProcessedAction(true); EndAction(/* successful= */ true);
std::move(process_action_callback_).Run(std::move(processed_action_proto_));
return; return;
} }
if (fallback_values.empty()) { if (fallback_values.empty()) {
// One or more required fields is empty but there is no fallback value, so // One or more required fields is empty but there is no fallback value, so
// we fail the action. // we stop the script.
UpdateProcessedAction(false); delegate->StopCurrentScript(check_form_message_);
std::move(process_action_callback_).Run(std::move(processed_action_proto_)); EndAction(/* successful= */ true);
// TODO(crbug.com/806868): Tell the user to fill the form manually.
return; return;
} }
...@@ -413,12 +405,10 @@ void AutofillAction::OnSetFieldValue(const std::string& guid, ...@@ -413,12 +405,10 @@ void AutofillAction::OnSetFieldValue(const std::string& guid,
// We can ignore the other SetFieldValue callbacks given that an action is // We can ignore the other SetFieldValue callbacks given that an action is
// processed only once. // processed only once.
if (!successful) { if (!successful) {
// Fallback failed: we fail the action without checking the fields. // Fallback failed: we stop the script without checking the fields.
if (process_action_callback_) { if (process_action_callback_) {
UpdateProcessedAction(false); delegate->StopCurrentScript(check_form_message_);
std::move(process_action_callback_) EndAction(/* successful= */ true);
.Run(std::move(processed_action_proto_));
// TODO(crbug.com/806868): Tell the user to fill the form manually.
} }
return; return;
} }
......
...@@ -78,10 +78,14 @@ class AutofillAction : public Action { ...@@ -78,10 +78,14 @@ class AutofillAction : public Action {
ActionDelegate* delegate, ActionDelegate* delegate,
bool successful); bool successful);
void EndAction(bool successful);
// Usage of the autofilled address. Ignored if autofilling a card. // Usage of the autofilled address. Ignored if autofilling a card.
std::string name_; std::string name_;
std::string prompt_; std::string prompt_;
std::vector<std::string> selectors_; std::vector<std::string> selectors_;
std::string fill_form_message_;
std::string check_form_message_;
// True if autofilling a card, otherwise we are autofilling an address. // True if autofilling a card, otherwise we are autofilling an address.
bool is_autofill_card_; bool is_autofill_card_;
......
...@@ -112,19 +112,25 @@ class AutofillActionTest : public testing::Test { ...@@ -112,19 +112,25 @@ class AutofillActionTest : public testing::Test {
const char* const kFirstName = "Foo"; const char* const kFirstName = "Foo";
const char* const kLastName = "Bar"; const char* const kLastName = "Bar";
const char* const kEmail = "foobar@gmail.com"; const char* const kEmail = "foobar@gmail.com";
const char* const kFillForm = "fill_form";
const char* const kCheckForm = "check_form";
ActionProto CreateUseAddressAction() { ActionProto CreateUseAddressAction() {
ActionProto action; ActionProto action;
UseAddressProto* use_address = action.mutable_use_address(); UseAddressProto* use_address = action.mutable_use_address();
use_address->set_name(kAddressName); use_address->set_name(kAddressName);
use_address->mutable_form_field_element()->add_selectors(kFakeSelector); use_address->mutable_form_field_element()->add_selectors(kFakeSelector);
use_address->mutable_strings()->set_fill_form(kFillForm);
use_address->mutable_strings()->set_check_form(kCheckForm);
return action; return action;
} }
ActionProto CreateUseCardAction() { ActionProto CreateUseCardAction() {
ActionProto action; ActionProto action;
action.mutable_use_card()->mutable_form_field_element()->add_selectors( UseCreditCardProto* use_card = action.mutable_use_card();
kFakeSelector); use_card->mutable_form_field_element()->add_selectors(kFakeSelector);
use_card->mutable_strings()->set_fill_form(kFillForm);
use_card->mutable_strings()->set_check_form(kCheckForm);
return action; return action;
} }
...@@ -138,6 +144,15 @@ class AutofillActionTest : public testing::Test { ...@@ -138,6 +144,15 @@ class AutofillActionTest : public testing::Test {
ProcessedActionStatusProto::ACTION_APPLIED; ProcessedActionStatusProto::ACTION_APPLIED;
} }
void ExpectActionToStopScript(const ActionProto& action_proto,
const std::string& expected_message) {
EXPECT_CALL(mock_action_delegate_, StopCurrentScript(expected_message));
// The AutofillAction should finish successfully even when stopping the
// current script.
EXPECT_TRUE(ProcessAction(action_proto));
}
MockActionDelegate mock_action_delegate_; MockActionDelegate mock_action_delegate_;
MockClientMemory mock_client_memory_; MockClientMemory mock_client_memory_;
std::string autofill_profile_guid_; std::string autofill_profile_guid_;
...@@ -164,7 +179,7 @@ TEST_F(AutofillActionTest, FillManually) { ...@@ -164,7 +179,7 @@ TEST_F(AutofillActionTest, FillManually) {
// We save the selection in memory. // We save the selection in memory.
EXPECT_CALL(mock_client_memory_, set_selected_address(kAddressName, "")); EXPECT_CALL(mock_client_memory_, set_selected_address(kAddressName, ""));
EXPECT_FALSE(ProcessAction(action_proto)); ExpectActionToStopScript(action_proto, kFillForm);
} }
TEST_F(AutofillActionTest, ValidationSucceeds) { TEST_F(AutofillActionTest, ValidationSucceeds) {
...@@ -237,7 +252,7 @@ TEST_F(AutofillActionTest, FallbackFails) { ...@@ -237,7 +252,7 @@ TEST_F(AutofillActionTest, FallbackFails) {
OnSetFieldValue(ElementsAre(kFakeSelector), kFirstName, _)) OnSetFieldValue(ElementsAre(kFakeSelector), kFirstName, _))
.WillOnce(RunOnceCallback<2>(false)); .WillOnce(RunOnceCallback<2>(false));
EXPECT_FALSE(ProcessAction(action_proto)); ExpectActionToStopScript(action_proto, kCheckForm);
} }
TEST_F(AutofillActionTest, FallbackSucceeds) { TEST_F(AutofillActionTest, FallbackSucceeds) {
......
...@@ -104,6 +104,7 @@ class MockActionDelegate : public ActionDelegate { ...@@ -104,6 +104,7 @@ class MockActionDelegate : public ActionDelegate {
MOCK_METHOD0(GetClientMemory, ClientMemory*()); MOCK_METHOD0(GetClientMemory, ClientMemory*());
MOCK_METHOD0(GetPersonalDataManager, autofill::PersonalDataManager*()); MOCK_METHOD0(GetPersonalDataManager, autofill::PersonalDataManager*());
MOCK_METHOD0(GetWebContents, content::WebContents*()); MOCK_METHOD0(GetWebContents, content::WebContents*());
MOCK_METHOD1(StopCurrentScript, void(const std::string& message));
}; };
} // namespace autofill_assistant } // namespace autofill_assistant
......
...@@ -24,6 +24,7 @@ ScriptExecutor::ScriptExecutor(const std::string& script_path, ...@@ -24,6 +24,7 @@ ScriptExecutor::ScriptExecutor(const std::string& script_path,
: script_path_(script_path), : script_path_(script_path),
delegate_(delegate), delegate_(delegate),
at_end_(CONTINUE), at_end_(CONTINUE),
should_stop_script_(false),
weak_ptr_factory_(this) { weak_ptr_factory_(this) {
DCHECK(delegate_); DCHECK(delegate_);
} }
...@@ -122,6 +123,13 @@ void ScriptExecutor::Restart() { ...@@ -122,6 +123,13 @@ void ScriptExecutor::Restart() {
at_end_ = RESTART; at_end_ = RESTART;
} }
void ScriptExecutor::StopCurrentScript(const std::string& message) {
if (!message.empty()) {
delegate_->GetUiController()->ShowStatusMessage(message);
}
should_stop_script_ = true;
}
ClientMemory* ScriptExecutor::GetClientMemory() { ClientMemory* ScriptExecutor::GetClientMemory() {
return delegate_->GetClientMemory(); return delegate_->GetClientMemory();
} }
...@@ -212,6 +220,14 @@ void ScriptExecutor::OnProcessedAction( ...@@ -212,6 +220,14 @@ void ScriptExecutor::OnProcessedAction(
GetNextActions(); GetNextActions();
return; return;
} }
if (should_stop_script_) {
// Last action called StopCurrentScript(). We simulate a successful end of
// script to make sure we don't display any errors.
RunCallback(true);
return;
}
ProcessNextAction(); ProcessNextAction();
} }
......
...@@ -85,6 +85,7 @@ class ScriptExecutor : public ActionDelegate { ...@@ -85,6 +85,7 @@ class ScriptExecutor : public ActionDelegate {
ClientMemory* GetClientMemory() override; ClientMemory* GetClientMemory() override;
autofill::PersonalDataManager* GetPersonalDataManager() override; autofill::PersonalDataManager* GetPersonalDataManager() override;
content::WebContents* GetWebContents() override; content::WebContents* GetWebContents() override;
void StopCurrentScript(const std::string& message) override;
private: private:
void OnGetActions(bool result, const std::string& response); void OnGetActions(bool result, const std::string& response);
...@@ -102,6 +103,7 @@ class ScriptExecutor : public ActionDelegate { ...@@ -102,6 +103,7 @@ class ScriptExecutor : public ActionDelegate {
std::vector<ProcessedActionProto> processed_actions_; std::vector<ProcessedActionProto> processed_actions_;
std::string last_server_payload_; std::string last_server_payload_;
AtEnd at_end_; AtEnd at_end_;
bool should_stop_script_;
base::WeakPtrFactory<ScriptExecutor> weak_ptr_factory_; base::WeakPtrFactory<ScriptExecutor> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ScriptExecutor); DISALLOW_COPY_AND_ASSIGN(ScriptExecutor);
......
...@@ -289,6 +289,14 @@ message FocusElementProto { ...@@ -289,6 +289,14 @@ message FocusElementProto {
optional string title = 2; optional string title = 2;
} }
message AutofillStrings {
optional string fill_manually = 1;
optional string fill_form = 2;
optional string check_form = 3;
}
// 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 what form fields should be filled with what // Message used to indicate what form fields should be filled with what
...@@ -328,6 +336,8 @@ message UseAddressProto { ...@@ -328,6 +336,8 @@ message UseAddressProto {
// An optional list of fields that should be filled by this action. // An optional list of fields that should be filled by this action.
repeated RequiredField required_fields = 6; repeated RequiredField required_fields = 6;
optional AutofillStrings strings = 8;
} }
// Fill a form with a credit card if there is, otherwise fail this action. // Fill a form with a credit card if there is, otherwise fail this action.
...@@ -338,6 +348,8 @@ message UseCreditCardProto { ...@@ -338,6 +348,8 @@ message UseCreditCardProto {
// A reference to the card number field in the form that should be filled. // A reference to the card number field in the form that should be filled.
optional ElementReferenceProto form_field_element = 3; optional ElementReferenceProto form_field_element = 3;
optional AutofillStrings strings = 8;
} }
// Ask Chrome to wait for an element in the DOM. This can be used to only // Ask Chrome to wait for an element in the DOM. This can be used to only
......
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