Commit a3d36e9f authored by gogerald's avatar gogerald Committed by Commit Bot

[Autofill Asiistant] Implement wait for dom action

Rename protocols as well

Bug: 806868
Change-Id: Ib24e4d4f8821451a9ee56d27efd1c142a4f2d60b
Reviewed-on: https://chromium-review.googlesource.com/1179966Reviewed-by: default avatarRouslan Solomakhin <rouslan@chromium.org>
Commit-Queue: Ganggui Tang <gogerald@chromium.org>
Cr-Commit-Position: refs/heads/master@{#584176}
parent eab3b960
...@@ -17,6 +17,7 @@ class AssistantAction { ...@@ -17,6 +17,7 @@ class AssistantAction {
virtual ~AssistantAction() = default; virtual ~AssistantAction() = default;
// Callback returns whether process action is succeed or not. // Callback returns whether process action is succeed or not.
// Delegate should outlive this object.
using ProcessActionCallback = base::OnceCallback<void(bool)>; using ProcessActionCallback = base::OnceCallback<void(bool)>;
virtual void ProcessAction(AssistantActionDelegate* delegate, virtual void ProcessAction(AssistantActionDelegate* delegate,
ProcessActionCallback callback) = 0; ProcessActionCallback callback) = 0;
......
...@@ -23,6 +23,10 @@ class AssistantActionDelegate { ...@@ -23,6 +23,10 @@ class AssistantActionDelegate {
virtual void ClickElement(const std::vector<std::string>& selectors, virtual void ClickElement(const std::vector<std::string>& selectors,
base::OnceCallback<void(bool)> callback) = 0; base::OnceCallback<void(bool)> callback) = 0;
// Check whether the element given by |selectors| exists on the web page.
virtual void ElementExists(const std::vector<std::string>& selectors,
base::OnceCallback<void(bool)> callback) = 0;
protected: protected:
AssistantActionDelegate() = default; AssistantActionDelegate() = default;
}; };
......
...@@ -4,7 +4,20 @@ ...@@ -4,7 +4,20 @@
#include "components/autofill_assistant/browser/actions/assistant_wait_for_dom_action.h" #include "components/autofill_assistant/browser/actions/assistant_wait_for_dom_action.h"
#include <cmath>
#include "base/bind.h"
#include "base/callback.h"
#include "base/time/time.h"
#include "components/autofill_assistant/browser/actions/assistant_action_delegate.h" #include "components/autofill_assistant/browser/actions/assistant_action_delegate.h"
#include "content/public/browser/browser_thread.h"
namespace {
int kCheckPeriodInMilliseconds = 100;
// So it takes about 150*100 milliseconds.
int kDefaultCheckRounds = 150;
} // namespace
namespace autofill_assistant { namespace autofill_assistant {
...@@ -12,13 +25,62 @@ AssistantWaitForDomAction::AssistantWaitForDomAction( ...@@ -12,13 +25,62 @@ AssistantWaitForDomAction::AssistantWaitForDomAction(
int timeout_ms, int timeout_ms,
const std::vector<std::string>& selectors, const std::vector<std::string>& selectors,
bool for_absence) bool for_absence)
: target_element_selectors_(selectors) {} : timeout_ms_(timeout_ms),
target_element_selectors_(selectors),
for_absence_(for_absence),
weak_ptr_factory_(this) {}
AssistantWaitForDomAction::~AssistantWaitForDomAction() {} AssistantWaitForDomAction::~AssistantWaitForDomAction() {}
void AssistantWaitForDomAction::ProcessAction(AssistantActionDelegate* delegate, void AssistantWaitForDomAction::ProcessAction(AssistantActionDelegate* delegate,
ProcessActionCallback callback) { ProcessActionCallback callback) {
NOTIMPLEMENTED(); int check_rounds = kDefaultCheckRounds;
if (timeout_ms_ > 0)
check_rounds = std::ceil(timeout_ms_ / kCheckPeriodInMilliseconds);
CheckElementExists(delegate, check_rounds, std::move(callback));
}
void AssistantWaitForDomAction::CheckElementExists(
AssistantActionDelegate* delegate,
int rounds,
ProcessActionCallback callback) {
DCHECK(rounds > 0);
delegate->ElementExists(
target_element_selectors_,
base::BindOnce(&AssistantWaitForDomAction::OnCheckElementExists,
weak_ptr_factory_.GetWeakPtr(), delegate, rounds,
std::move(callback)));
}
void AssistantWaitForDomAction::OnCheckElementExists(
AssistantActionDelegate* delegate,
int rounds,
ProcessActionCallback callback,
bool result) {
if (for_absence_ && !result) {
std::move(callback).Run(true);
return;
}
if (!for_absence_ && result) {
std::move(callback).Run(true);
return;
}
if (rounds == 0) {
std::move(callback).Run(false);
return;
}
--rounds;
content::BrowserThread::PostDelayedTask(
content::BrowserThread::UI, FROM_HERE,
base::BindOnce(&AssistantWaitForDomAction::CheckElementExists,
weak_ptr_factory_.GetWeakPtr(), delegate, rounds,
std::move(callback)),
base::TimeDelta::FromMilliseconds(kCheckPeriodInMilliseconds));
} }
} // namespace autofill_assistant. } // namespace autofill_assistant.
...@@ -10,7 +10,9 @@ ...@@ -10,7 +10,9 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include "base/callback_forward.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h"
namespace autofill_assistant { namespace autofill_assistant {
// An action to ask Chrome to wait for a DOM element to process next action. // An action to ask Chrome to wait for a DOM element to process next action.
...@@ -29,8 +31,19 @@ class AssistantWaitForDomAction : public AssistantAction { ...@@ -29,8 +31,19 @@ class AssistantWaitForDomAction : public AssistantAction {
ProcessActionCallback callback) override; ProcessActionCallback callback) override;
private: private:
void CheckElementExists(AssistantActionDelegate* delegate,
int rounds,
ProcessActionCallback callback);
void OnCheckElementExists(AssistantActionDelegate* delegate,
int rounds,
ProcessActionCallback callback,
bool result);
int timeout_ms_;
std::vector<std::string> target_element_selectors_; std::vector<std::string> target_element_selectors_;
bool for_absence_;
base::WeakPtrFactory<AssistantWaitForDomAction> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(AssistantWaitForDomAction); DISALLOW_COPY_AND_ASSIGN(AssistantWaitForDomAction);
}; };
......
...@@ -85,11 +85,11 @@ message ActionsResponseProto { ...@@ -85,11 +85,11 @@ message ActionsResponseProto {
message AssistantActionProto { message AssistantActionProto {
// Next action id: 3. // Next action id: 3.
oneof action_info { oneof action_info {
ClickSpecificationProto click_specification = 1; ClickProto click = 1;
TellSpecificationProto tell_specification = 2; TellProto tell = 2;
UseAddressSpecificationProto use_address_specification = 3; UseAddressProto use_address = 3;
UseCreditCardSpecificationProto use_card_specification = 4; UseCreditCardProto use_card = 4;
WaitForDomSpecificationProto wait_for_dom_specification = 5; WaitForDomProto wait_for_dom = 5;
} }
} }
...@@ -104,19 +104,19 @@ message ElementReferenceProto { ...@@ -104,19 +104,19 @@ message ElementReferenceProto {
} }
// Contain all arguments to perform a click. // Contain all arguments to perform a click.
message ClickSpecificationProto { message ClickProto {
required ElementReferenceProto element_to_click = 1; required ElementReferenceProto element_to_click = 1;
} }
// Contain a message to tell the user. // Contain a message to tell the user.
message TellSpecificationProto { message TellProto {
required string message = 1; required string message = 1;
} }
// TODO(crbug.com/806868): Handle it better when there is no local address. // TODO(crbug.com/806868): Handle it better when there is no local address.
// Ask user to fill a form with a local address if there is, otherwise fail this // Ask user to fill a form with a local address if there is, otherwise fail this
// action. // action.
message UseAddressSpecificationProto { message UseAddressProto {
// Optional message to show usage of the address, like billing or shipping // Optional message to show usage of the address, like billing or shipping
// address. // address.
optional string usage = 1; optional string usage = 1;
...@@ -128,19 +128,19 @@ message UseAddressSpecificationProto { ...@@ -128,19 +128,19 @@ message UseAddressSpecificationProto {
// TODO(crbug.com/806868): Handle it better when there is no local credit card. // TODO(crbug.com/806868): Handle it better when there is no local credit card.
// Ask user to fill a form with a local credit card if there is, otherwise fail // Ask user to fill a form with a local credit card if there is, otherwise fail
// this action. // this action.
message UseCreditCardSpecificationProto { 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 = 1; optional ElementReferenceProto form_field_element = 1;
} }
// 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
// proceed to the next action once the page is ready. // proceed to the next action once the page is ready.
message WaitForDomSpecificationProto { message WaitForDomProto {
// Fail after waiting this amount of time.
required int32 timeout_ms = 1;
// The element to wait. // The element to wait.
required ElementReferenceProto element = 2; required ElementReferenceProto element = 1;
// Fail after waiting this amount of time.
optional int32 timeout_ms = 2;
// If true, wait for the given element to be absent, otherwise wait for // If true, wait for the given element to be absent, otherwise wait for
// existence. // existence.
......
...@@ -129,11 +129,11 @@ bool AssistantProtocolUtils::ParseAssistantActions( ...@@ -129,11 +129,11 @@ bool AssistantProtocolUtils::ParseAssistantActions(
for (const auto& action : response_proto.actions()) { for (const auto& action : response_proto.actions()) {
switch (action.action_info_case()) { switch (action.action_info_case()) {
case AssistantActionProto::ActionInfoCase::kClickSpecification: { case AssistantActionProto::ActionInfoCase::kClick: {
DCHECK(action.has_click_specification()); DCHECK(action.has_click());
std::vector<std::string> selectors; std::vector<std::string> selectors;
for (const auto& selector : for (const auto& selector :
action.click_specification().element_to_click().selectors()) { action.click().element_to_click().selectors()) {
selectors.emplace_back(selector); selectors.emplace_back(selector);
} }
DCHECK(!selectors.empty()); DCHECK(!selectors.empty());
...@@ -141,34 +141,32 @@ bool AssistantProtocolUtils::ParseAssistantActions( ...@@ -141,34 +141,32 @@ bool AssistantProtocolUtils::ParseAssistantActions(
std::make_unique<AssistantClickAction>(selectors)); std::make_unique<AssistantClickAction>(selectors));
break; break;
} }
case AssistantActionProto::ActionInfoCase::kTellSpecification: { case AssistantActionProto::ActionInfoCase::kTell: {
DCHECK(action.has_tell_specification()); DCHECK(action.has_tell());
assistant_actions->emplace_back(std::make_unique<AssistantTellAction>( assistant_actions->emplace_back(
action.tell_specification().message())); std::make_unique<AssistantTellAction>(action.tell().message()));
break; break;
} }
case AssistantActionProto::ActionInfoCase::kUseAddressSpecification: { case AssistantActionProto::ActionInfoCase::kUseAddress: {
DCHECK(action.has_use_address_specification()); DCHECK(action.has_use_address());
std::vector<std::string> selectors; std::vector<std::string> selectors;
for (const auto& selector : action.use_address_specification() for (const auto& selector :
.form_field_element() action.use_address().form_field_element().selectors()) {
.selectors()) {
selectors.emplace_back(selector); selectors.emplace_back(selector);
} }
DCHECK(!selectors.empty()); DCHECK(!selectors.empty());
assistant_actions->emplace_back( assistant_actions->emplace_back(
std::make_unique<AssistantUseAddressAction>( std::make_unique<AssistantUseAddressAction>(
action.use_address_specification().has_usage() action.use_address().has_usage() ? action.use_address().usage()
? action.use_address_specification().usage() : "",
: "",
selectors)); selectors));
break; break;
} }
case AssistantActionProto::ActionInfoCase::kUseCardSpecification: { case AssistantActionProto::ActionInfoCase::kUseCard: {
DCHECK(action.has_use_card_specification()); DCHECK(action.has_use_card());
std::vector<std::string> selectors; std::vector<std::string> selectors;
for (const auto& selector : for (const auto& selector :
action.use_card_specification().form_field_element().selectors()) { action.use_card().form_field_element().selectors()) {
selectors.emplace_back(selector); selectors.emplace_back(selector);
} }
DCHECK(!selectors.empty()); DCHECK(!selectors.empty());
...@@ -176,19 +174,22 @@ bool AssistantProtocolUtils::ParseAssistantActions( ...@@ -176,19 +174,22 @@ bool AssistantProtocolUtils::ParseAssistantActions(
std::make_unique<AssistantUseCardAction>(selectors)); std::make_unique<AssistantUseCardAction>(selectors));
break; break;
} }
case AssistantActionProto::ActionInfoCase::kWaitForDomSpecification: { case AssistantActionProto::ActionInfoCase::kWaitForDom: {
DCHECK(action.has_wait_for_dom_specification()); DCHECK(action.has_wait_for_dom());
std::vector<std::string> selectors; std::vector<std::string> selectors;
for (const auto& selector : for (const auto& selector :
action.wait_for_dom_specification().element().selectors()) { action.wait_for_dom().element().selectors()) {
selectors.emplace_back(selector); selectors.emplace_back(selector);
} }
DCHECK(!selectors.empty()); DCHECK(!selectors.empty());
assistant_actions->emplace_back( assistant_actions->emplace_back(
std::make_unique<AssistantWaitForDomAction>( std::make_unique<AssistantWaitForDomAction>(
action.wait_for_dom_specification().timeout_ms(), selectors, action.wait_for_dom().has_timeout_ms()
action.wait_for_dom_specification().has_check_for_absence() && ? action.wait_for_dom().timeout_ms()
action.wait_for_dom_specification().check_for_absence())); : 0,
selectors,
action.wait_for_dom().has_check_for_absence() &&
action.wait_for_dom().check_for_absence()));
break; break;
} }
case AssistantActionProto::ActionInfoCase::ACTION_INFO_NOT_SET: { case AssistantActionProto::ActionInfoCase::ACTION_INFO_NOT_SET: {
......
...@@ -42,6 +42,13 @@ void AssistantScriptExecutor::ClickElement( ...@@ -42,6 +42,13 @@ void AssistantScriptExecutor::ClickElement(
std::move(callback)); std::move(callback));
} }
void AssistantScriptExecutor::ElementExists(
const std::vector<std::string>& selectors,
base::OnceCallback<void(bool)> callback) {
delegate_->GetAssistantWebController()->ElementExists(selectors,
std::move(callback));
}
void AssistantScriptExecutor::OnGetAssistantActions( void AssistantScriptExecutor::OnGetAssistantActions(
bool result, bool result,
const std::string& response) { const std::string& response) {
......
...@@ -29,6 +29,8 @@ class AssistantScriptExecutor : public AssistantActionDelegate { ...@@ -29,6 +29,8 @@ class AssistantScriptExecutor : public AssistantActionDelegate {
void ShowStatusMessage(const std::string& message) override; void ShowStatusMessage(const std::string& message) override;
void ClickElement(const std::vector<std::string>& selectors, void ClickElement(const std::vector<std::string>& selectors,
base::OnceCallback<void(bool)> callback) override; base::OnceCallback<void(bool)> callback) override;
void ElementExists(const std::vector<std::string>& selectors,
base::OnceCallback<void(bool)> callback) override;
private: private:
void OnGetAssistantActions(bool result, const std::string& response); void OnGetAssistantActions(bool result, const std::string& response);
......
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