blob: 0a165a17e8297f80f1cbc4a51d1df0017a079b3e [file] [log] [blame]
// Copyright 2021 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_STARTER_H_
#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_STARTER_H_
#include <memory>
#include "base/containers/mru_cache.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "components/autofill_assistant/browser/controller.h"
#include "components/autofill_assistant/browser/metrics.h"
#include "components/autofill_assistant/browser/public/runtime_manager_impl.h"
#include "components/autofill_assistant/browser/service.pb.h"
#include "components/autofill_assistant/browser/starter_heuristic.h"
#include "components/autofill_assistant/browser/starter_platform_delegate.h"
#include "components/autofill_assistant/browser/startup_util.h"
#include "components/autofill_assistant/browser/trigger_scripts/trigger_script_coordinator.h"
#include "content/public/browser/web_contents_observer.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace autofill_assistant {
// Starts autofill-assistant flows. Uses a platform delegate to show UI and
// access platform-dependent features.
class Starter : public content::WebContentsObserver {
public:
explicit Starter(content::WebContents* web_contents,
StarterPlatformDelegate* platform_delegate,
ukm::UkmRecorder* ukm_recorder,
base::WeakPtr<RuntimeManagerImpl> runtime_manager,
const base::TickClock* tick_clock);
~Starter() override;
Starter(const Starter&) = delete;
Starter& operator=(const Starter&) = delete;
// Entry-point for all non-direct-action flows. This method will perform the
// overall startup procedure, which is roughly as follows:
// - Check parameters/features/settings and determine startup mode
// - Install feature module if necessary
// - Run and wait for trigger script to finish if necessary
// - Show onboarding if necessary
// - Request the platform_delegate to start the regular script.
// TODO(mcarlen): client startup should also be handled here, rather than in
// the platform_delegate.
//
// Only one call to |Start| can be processed at any time. If this method is
// called before the previous call has finished, the previous call is
// cancelled.
void Start(std::unique_ptr<TriggerContext> trigger_context);
// content::WebContentsObserver:
void DidStartNavigation(
content::NavigationHandle* navigation_handle) override;
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
// Invoked when the tab interactability has changed.
void OnTabInteractabilityChanged(bool is_interactable);
// Re-check settings. This may cancel ongoing startup requests if the required
// settings are no longer enabled.
void CheckSettings();
private:
friend class StarterTest;
// Starts a flow for |url| if possible. Will fail (do nothing) if the feature
// is disabled or if there is already a pending startup.
void MaybeStartImplicitlyForUrl(const GURL& url);
// Cancels the currently pending startup request, if any. If a trigger script
// is currently running, this will record |state| as the reason for stopping.
// This will also hide any currently shown UI (such as a trigger script or the
// onboarding).
void CancelPendingStartup(
absl::optional<Metrics::TriggerScriptFinishedState> state);
// Installs the feature module if necessary, otherwise directly invokes
// |OnFeatureModuleInstalled|.
void MaybeInstallFeatureModule(StartupUtil::StartupMode startup_mode);
// Stops the startup if the installation failed. Otherwise, proceeds with the
// next step of the startup process.
void OnFeatureModuleInstalled(StartupUtil::StartupMode startup_mode,
Metrics::FeatureModuleInstallation result);
// Starts a trigger script and waits for it to finish in
// |OnTriggerScriptFinished|.
void StartTriggerScript();
// Stops the startup if the trigger script failed or was user-cancelled.
// Otherwise, proceeds with the start of the regular script.
void OnTriggerScriptFinished(
Metrics::TriggerScriptFinishedState state,
std::unique_ptr<TriggerContext> trigger_context,
absl::optional<TriggerScriptProto> trigger_script);
// Shows the onboarding if necessary, otherwise directly invokes
// |OnOnboardingFinished|.
void MaybeShowOnboarding(
absl::optional<TriggerScriptProto> trigger_script = absl::nullopt);
// Starts the regular script if onboarding was accepted. Stops the startup
// process if onboarding was rejected.
void OnOnboardingFinished(absl::optional<TriggerScriptProto> trigger_script,
bool shown,
OnboardingResult result);
// Called at the end of each |Start| invocation.
void OnStartDone(
bool start_regular_script,
absl::optional<TriggerScriptProto> trigger_script = absl::nullopt);
// Called when the heuristic result for |url| is available.
void OnHeuristicMatch(const GURL& url, absl::optional<std::string> intent);
// Returns whether there is a currently pending call to |Start| or not.
bool IsStartupPending() const;
// Deletes the trigger script coordinator.
void DeleteTriggerScriptCoordinator();
// Returns a pointer to the currently pending trigger context, or nullptr.
// Use this method instead of directly accessing |pending_trigger_context_| in
// cases where the context could be temporarily owned by
// |trigger_script_coordinator_|.
TriggerContext* GetPendingTriggerContext() const;
// The UKM source id to use for UKM metrics. This usually points to the last
// committed URL, except during navigations, in which case it will point to
// the source id that the finished navigation will eventually have.
ukm::SourceId next_ukm_source_id_ = ukm::kInvalidSourceId;
// Pointer to the global cache of trigger script requests that failed (one
// entry per organization-identifying domain), along with the time of entry.
// This is used to limit network traffic incurred for in-chrome triggering
// only. This cache does not affect explicit startup requests.
//
// This cache is shared across all tabs. It is size-limited and entries only
// last for a limited amount of time before they go stale. Made available in
// the header for easier unit-testing.
base::HashingMRUCache<std::string, base::TimeTicks>*
cached_failed_trigger_script_fetches_;
// The list of organization-identifying domains that a user has temporarily
// opted out of for receiving implicit autofill-assistant prompts, along
// with the time of entry.
//
// This is a per-tab cache. This cache does not affect explicit startup
// requests. The cache is size-limited and entries only last for a limited
// amount of time before they go stale.
base::HashingMRUCache<std::string, base::TimeTicks> user_denylisted_domains_;
// Debug parameters for in-CCT and in-Tab trigger scenarios. This is populated
// from the command line and intended only for debugging and testing.
ImplicitTriggeringDebugParametersProto implicit_triggering_debug_parameters_;
bool waiting_for_onboarding_ = false;
bool waiting_for_deeplink_navigation_ = false;
bool is_custom_tab_ = false;
StarterPlatformDelegate* platform_delegate_ = nullptr;
ukm::UkmRecorder* ukm_recorder_ = nullptr;
base::WeakPtr<RuntimeManagerImpl> runtime_manager_;
bool fetch_trigger_scripts_on_navigation_ = false;
std::unique_ptr<TriggerContext> pending_trigger_context_;
std::unique_ptr<TriggerScriptCoordinator> trigger_script_coordinator_;
const scoped_refptr<StarterHeuristic> starter_heuristic_;
const base::TickClock* tick_clock_;
base::WeakPtrFactory<Starter> weak_ptr_factory_{this};
};
} // namespace autofill_assistant
#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_STARTER_H_