Commit 86128e7b authored by Clemens Arbesser's avatar Clemens Arbesser Committed by Commit Bot

[Autofill Assistant] Implement TriggerScripts and basic file structure.

This CL adds the basic file structure for trigger scripts. Most classes
are only stubs, but the TriggerScript condition checking is already in
place. Subsequent CLs will replace the stubs to make this fully
functional.

Bug: b/171776026
Change-Id: Ic6b687242048c3f6ebf665d7611ff115a9a91ccd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2513595
Commit-Queue: Clemens Arbesser <arbesser@google.com>
Reviewed-by: default avatarMarian Fechete <marianfe@google.com>
Cr-Commit-Position: refs/heads/master@{#823523}
parent e8d25d87
......@@ -183,6 +183,14 @@ static_library("browser") {
"top_padding.h",
"trigger_context.cc",
"trigger_context.h",
"trigger_scripts/dynamic_trigger_conditions.cc",
"trigger_scripts/dynamic_trigger_conditions.h",
"trigger_scripts/static_trigger_conditions.cc",
"trigger_scripts/static_trigger_conditions.h",
"trigger_scripts/trigger_script.cc",
"trigger_scripts/trigger_script.h",
"trigger_scripts/trigger_script_coordinator.cc",
"trigger_scripts/trigger_script_coordinator.h",
"ui_delegate.h",
"user_action.cc",
"user_action.h",
......@@ -341,6 +349,8 @@ source_set("unit_tests") {
"test_util.cc",
"test_util.h",
"trigger_context_unittest.cc",
"trigger_scripts/trigger_script_coordinator_unittest.cc",
"trigger_scripts/trigger_script_unittest.cc",
"user_data_util_unittest.cc",
"user_model_unittest.cc",
"value_util_unittest.cc",
......
......@@ -495,8 +495,8 @@ message TriggerScriptConditionProto {
// The condition matches if none of these conditions match.
TriggerScriptConditionsProto none_of = 3;
// The condition matches if the element matches the specified condition.
ElementConditionProto element_condition = 4;
// The condition matches if the specified selector matches the current DOM..
SelectorProto selector = 8;
// The condition matches if the user has stored login credentials for the
// domain.
Empty stored_login_credentials = 5;
......@@ -505,6 +505,8 @@ message TriggerScriptConditionProto {
// The condition matches if the client is in the specified experiment.
int32 experiment_id = 7;
}
reserved 4;
}
message TriggerScriptConditionsProto {
......
// Copyright 2020 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_assistant/browser/trigger_scripts/dynamic_trigger_conditions.h"
namespace autofill_assistant {
DynamicTriggerConditions::DynamicTriggerConditions() = default;
DynamicTriggerConditions::~DynamicTriggerConditions() = default;
base::Optional<bool> DynamicTriggerConditions::GetSelectorMatches(
const Selector& selector) const {
return false;
}
void DynamicTriggerConditions::Update(WebController* web_controller,
base::OnceCallback<void(void)> callback) {
}
} // namespace autofill_assistant
// Copyright 2020 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.
#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_DYNAMIC_TRIGGER_CONDITIONS_H_
#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_DYNAMIC_TRIGGER_CONDITIONS_H_
#include "base/optional.h"
#include "components/autofill_assistant/browser/web/web_controller.h"
namespace autofill_assistant {
// Provides easy access to the values of dynamic trigger conditions. Dynamic
// trigger conditions depend on the current state of the DOM tree and need to be
// repeatedly re-evaluated.
class DynamicTriggerConditions {
public:
DynamicTriggerConditions();
~DynamicTriggerConditions();
// TODO(b/171776026): implement this stub.
virtual base::Optional<bool> GetSelectorMatches(
const Selector& selector) const;
virtual void Update(WebController* web_controller,
base::OnceCallback<void(void)> callback);
};
} // namespace autofill_assistant
#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_DYNAMIC_TRIGGER_CONDITIONS_H_
// Copyright 2020 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_assistant/browser/trigger_scripts/static_trigger_conditions.h"
namespace autofill_assistant {
StaticTriggerConditions::StaticTriggerConditions() = default;
StaticTriggerConditions::~StaticTriggerConditions() = default;
bool StaticTriggerConditions::is_first_time_user() const {
return false;
}
bool StaticTriggerConditions::has_stored_login_credentials() const {
return false;
}
bool StaticTriggerConditions::is_in_experiment(int experiment_id) const {
return false;
}
} // namespace autofill_assistant
// Copyright 2020 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.
#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_STATIC_TRIGGER_CONDITIONS_H_
#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_STATIC_TRIGGER_CONDITIONS_H_
#include "components/autofill_assistant/browser/client.h"
namespace autofill_assistant {
// Provides easy access to the values of static trigger conditions. Static
// trigger conditions do not depend on the current state of the DOM, as opposed
// to dynamic element conditions.
class StaticTriggerConditions {
public:
StaticTriggerConditions();
~StaticTriggerConditions();
// TODO(b/171776026): implement this stub.
virtual void Init(Client* client) {}
virtual bool is_first_time_user() const;
virtual bool has_stored_login_credentials() const;
virtual bool is_in_experiment(int experiment_id) const;
};
} // namespace autofill_assistant
#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_STATIC_TRIGGER_CONDITIONS_H_
// Copyright 2020 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_assistant/browser/trigger_scripts/trigger_script.h"
namespace autofill_assistant {
namespace {
bool EvaluateTriggerCondition(
const TriggerScriptConditionProto& proto,
const StaticTriggerConditions& static_trigger_conditions,
const DynamicTriggerConditions& dynamic_trigger_conditions) {
switch (proto.type_case()) {
case TriggerScriptConditionProto::kAllOf: {
for (const auto& condition : proto.all_of().conditions()) {
if (!EvaluateTriggerCondition(condition, static_trigger_conditions,
dynamic_trigger_conditions)) {
return false;
}
}
return true;
}
case TriggerScriptConditionProto::kAnyOf: {
for (const auto& condition : proto.any_of().conditions()) {
if (EvaluateTriggerCondition(condition, static_trigger_conditions,
dynamic_trigger_conditions)) {
return true;
}
}
return false;
}
case TriggerScriptConditionProto::kNoneOf: {
for (const auto& condition : proto.none_of().conditions()) {
if (EvaluateTriggerCondition(condition, static_trigger_conditions,
dynamic_trigger_conditions)) {
return false;
}
}
return true;
}
case TriggerScriptConditionProto::kSelector: {
auto selector_matches = dynamic_trigger_conditions.GetSelectorMatches(
Selector(proto.selector()));
DCHECK(selector_matches.has_value());
return selector_matches.value();
}
case TriggerScriptConditionProto::kStoredLoginCredentials:
return static_trigger_conditions.has_stored_login_credentials();
case TriggerScriptConditionProto::kIsFirstTimeUser:
return static_trigger_conditions.is_first_time_user();
case TriggerScriptConditionProto::kExperimentId:
return static_trigger_conditions.is_in_experiment(proto.experiment_id());
case TriggerScriptConditionProto::TYPE_NOT_SET:
return true;
}
}
} // namespace
TriggerScript::TriggerScript(const TriggerScriptProto& proto) : proto_(proto) {}
TriggerScript::~TriggerScript() = default;
bool TriggerScript::EvaluateTriggerConditions(
const StaticTriggerConditions& static_trigger_conditions,
const DynamicTriggerConditions& dynamic_trigger_conditions) const {
if (!proto_.has_trigger_condition()) {
return true;
}
return EvaluateTriggerCondition(proto_.trigger_condition(),
static_trigger_conditions,
dynamic_trigger_conditions);
}
} // namespace autofill_assistant
// Copyright 2020 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.
#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_TRIGGER_SCRIPT_H_
#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_TRIGGER_SCRIPT_H_
#include "components/autofill_assistant/browser/service.pb.h"
#include "components/autofill_assistant/browser/trigger_scripts/dynamic_trigger_conditions.h"
#include "components/autofill_assistant/browser/trigger_scripts/static_trigger_conditions.h"
namespace autofill_assistant {
// C++ class for a particular proto instance of |TriggerScriptProto|.
class TriggerScript {
public:
TriggerScript(const TriggerScriptProto& proto);
~TriggerScript();
TriggerScript(const TriggerScript&) = delete;
TriggerScript& operator=(const TriggerScript&) = delete;
// Evaluates the trigger conditions of this trigger script. Expects all
// trigger conditions to already be evaluated and cached in
// |static_trigger_conditions| and |dynamic_trigger_conditions|.
bool EvaluateTriggerConditions(
const StaticTriggerConditions& static_trigger_conditions,
const DynamicTriggerConditions& dynamic_trigger_conditions) const;
private:
friend class TriggerScriptTest;
TriggerScriptProto proto_;
};
} // namespace autofill_assistant
#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_TRIGGER_SCRIPT_H_
// Copyright 2020 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_assistant/browser/trigger_scripts/trigger_script_coordinator.h"
namespace autofill_assistant {
// TODO(b/171776026): implement this stub.
TriggerScriptCoordinator::TriggerScriptCoordinator(
Client* client,
std::unique_ptr<WebController> web_controller,
std::unique_ptr<ServiceRequestSender> request_sender,
const GURL& get_trigger_scripts_server)
: content::WebContentsObserver(client->GetWebContents()) {}
TriggerScriptCoordinator::~TriggerScriptCoordinator() = default;
void TriggerScriptCoordinator::Start(const GURL& url) {}
void TriggerScriptCoordinator::PerformTriggerScriptAction(
TriggerScriptProto::TriggerScriptAction action) {}
void TriggerScriptCoordinator::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void TriggerScriptCoordinator::RemoveObserver(const Observer* observer) {
observers_.RemoveObserver(observer);
}
void TriggerScriptCoordinator::OnVisibilityChanged(
content::Visibility visibility) {}
} // namespace autofill_assistant
// Copyright 2020 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.
#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_TRIGGER_SCRIPT_COORDINATOR_H_
#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_TRIGGER_SCRIPT_COORDINATOR_H_
#include <memory>
#include <string>
#include <vector>
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "components/autofill_assistant/browser/client.h"
#include "components/autofill_assistant/browser/service.pb.h"
#include "components/autofill_assistant/browser/service/service_request_sender.h"
#include "components/autofill_assistant/browser/trigger_scripts/trigger_script.h"
#include "components/autofill_assistant/browser/web/web_controller.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "url/gurl.h"
namespace autofill_assistant {
// Fetches and coordinates trigger scripts for a specific url. Similar in scope
// and responsibility to a regular |controller|, but for trigger scripts instead
// of regular scripts.
class TriggerScriptCoordinator : public content::WebContentsObserver {
public:
// Observer interface for listeners interested in status updates of this
// coordinator.
class Observer : public base::CheckedObserver {
public:
Observer() = default;
~Observer() override = default;
virtual void OnTriggerScriptShown(const TriggerScriptUIProto& proto) = 0;
virtual void OnTriggerScriptHidden() = 0;
virtual void OnTriggerScriptFinished(int state) = 0;
};
// |client| and |web_contents| must outlive this instance.
TriggerScriptCoordinator(Client* client,
std::unique_ptr<WebController> web_controller,
std::unique_ptr<ServiceRequestSender> request_sender,
const GURL& get_trigger_scripts_server);
~TriggerScriptCoordinator() override;
TriggerScriptCoordinator(const TriggerScriptCoordinator&) = delete;
TriggerScriptCoordinator& operator=(const TriggerScriptCoordinator&) = delete;
// Retrieves all trigger scripts for |url| and starts evaluating their
// preconditions. Observers will be notified of all relevant status updates.
void Start(const GURL& url);
// Performs |action|. This is usually invoked by the UI as a result of user
// interactions.
void PerformTriggerScriptAction(
TriggerScriptProto::TriggerScriptAction action);
void AddObserver(Observer* observer);
void RemoveObserver(const Observer* observer);
private:
struct PendingTriggerScript {
TriggerScript trigger_script;
bool waiting_for_precondition_no_longer_true = false;
};
// From content::WebContentsObserver.
void OnVisibilityChanged(content::Visibility visibility) override;
// The list of currently registered observers.
base::ObserverList<Observer> observers_;
base::WeakPtrFactory<TriggerScriptCoordinator> weak_ptr_factory_{this};
};
} // namespace autofill_assistant
#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_TRIGGER_SCRIPTS_TRIGGER_SCRIPT_COORDINATOR_H_
// Copyright 2020 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_assistant/browser/trigger_scripts/trigger_script_coordinator.h"
#include "components/autofill_assistant/browser/mock_client.h"
#include "components/autofill_assistant/browser/service/mock_service_request_sender.h"
#include "components/autofill_assistant/browser/web/mock_web_controller.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/mock_callback.h"
#include "content/public/test/test_renderer_host.h"
#include "content/public/test/web_contents_tester.h"
#include "net/http/http_status_code.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace autofill_assistant {
using ::testing::NiceMock;
using ::testing::Return;
namespace {
class MockObserver : public TriggerScriptCoordinator::Observer {
public:
MOCK_METHOD1(OnTriggerScriptShown, void(const TriggerScriptUIProto& proto));
MOCK_METHOD0(OnTriggerScriptHidden, void());
MOCK_METHOD1(OnTriggerScriptFinished, void(int state));
};
const char kFakeServerUrl[] =
"https://www.fake.backend.com/trigger_script_server";
class TriggerScriptCoordinatorTest : public content::RenderViewHostTestHarness {
public:
TriggerScriptCoordinatorTest() = default;
~TriggerScriptCoordinatorTest() override = default;
void SetUp() override {
RenderViewHostTestHarness::SetUp();
ON_CALL(mock_client_, GetWebContents).WillByDefault(Return(web_contents()));
auto mock_request_sender =
std::make_unique<NiceMock<MockServiceRequestSender>>();
mock_request_sender_ = mock_request_sender.get();
auto mock_web_controller = std::make_unique<NiceMock<MockWebController>>();
mock_web_controller_ = mock_web_controller.get();
coordinator_ = std::make_unique<TriggerScriptCoordinator>(
&mock_client_, std::move(mock_web_controller),
std::move(mock_request_sender), GURL(kFakeServerUrl));
coordinator_->AddObserver(&mock_observer_);
}
void TearDown() override { coordinator_->RemoveObserver(&mock_observer_); }
protected:
NiceMock<MockServiceRequestSender>* mock_request_sender_;
NiceMock<MockWebController>* mock_web_controller_;
NiceMock<MockClient> mock_client_;
NiceMock<MockObserver> mock_observer_;
std::unique_ptr<TriggerScriptCoordinator> coordinator_;
};
TEST_F(TriggerScriptCoordinatorTest, SmokeTest) {
// stub
}
} // namespace
} // namespace autofill_assistant
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