blob: f25854eda16a1a7848bafa7e0427b6821805fdc6 [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_ACTOR_TOOLS_OBSERVATION_DELAY_CONTROLLER_H_
#define CHROME_BROWSER_ACTOR_TOOLS_OBSERVATION_DELAY_CONTROLLER_H_
#include <ostream>
#include <string_view>
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ref.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "chrome/browser/actor/aggregated_journal.h"
#include "chrome/common/actor.mojom.h"
#include "chrome/common/actor/task_id.h"
#include "components/tabs/public/tab_interface.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents_observer.h"
#include "mojo/public/cpp/bindings/remote.h"
namespace content {
class RenderFrameHost;
} // namespace content
namespace actor {
// Observes a page during tool-use and determines when the page has settled
// after an action and is ready for for an observation.
//
// This class will watch for any document loads in the web contents. When the
// tool completes, this class delays until the load also finishes and then a new
// frame is generated and presented.
class ObservationDelayController : public content::WebContentsObserver {
public:
using ReadyCallback = base::OnceClosure;
// Configuration for general page stability if enabled.
struct PageStabilityConfig {
// Whether to include paint stability in page stability heuristics.
bool supports_paint_stability = false;
// The amount of time to wait when observing tool execution before starting
// to wait for page stability.
base::TimeDelta start_delay;
};
// This will create a PageStabilityMonitor in the renderer and wait for page
// stability.
ObservationDelayController(content::RenderFrameHost& target_frame,
TaskId task_id,
AggregatedJournal& journal,
PageStabilityConfig page_stability_config);
// Constructor for when we're not watching for page stability and do not have
// a target RenderFrameHost available.
ObservationDelayController(TaskId task_id, AggregatedJournal& journal);
~ObservationDelayController() override;
// Note: Callback will always be executed asynchronously. It may be run after
// this object is deleted so must manage its own lifetime.
// Note: If a RenderFrame was provided in the constructor, `target_tab` should
// contain it.
//
// `target_tab`: The tab on which to wait. The WebContents of this tab will be
// observed by this controller, overwriting any previously observed
// WebContents.
void Wait(tabs::TabInterface& target_tab, ReadyCallback callback);
// content::WebContentsObserver
void DidStopLoading() override;
// Public for tests
enum class State {
kInitial,
kWaitForPageStability,
kPageStabilityMonitorDisconnected,
kWaitForLoadCompletion,
kWaitForVisualStateUpdate,
kMaybeDelayForLcp,
kDidTimeout,
kDone
};
static std::string_view StateToString(State state);
protected:
// Protected so tests can hook into state changes and some internal state.
virtual void SetState(State state);
State state_ = State::kInitial;
mojo::Remote<mojom::PageStabilityMonitor> page_stability_monitor_remote_;
private:
friend std::ostream& operator<<(
std::ostream& o,
const ObservationDelayController::State& state);
void OnMonitorDisconnected();
void DCheckStateTransition(State old_state, State new_state);
void MoveToState(State state);
base::OnceClosure MoveToStateClosure(State new_state);
base::OnceClosure PostMoveToStateClosure(
State new_state,
base::TimeDelta delay = base::TimeDelta());
ReadyCallback ready_callback_;
base::raw_ref<AggregatedJournal> journal_;
TaskId task_id_;
// Async entry for entire duration after Wait is called.
std::unique_ptr<AggregatedJournal::PendingAsyncEntry> wait_journal_entry_;
// Async entry for nested inner states. Note that this is only created for
// states after PageStability to avoid nesting issues - PageStabilityMonitor
// provides its own async entries.
std::unique_ptr<AggregatedJournal::PendingAsyncEntry> inner_journal_entry_;
base::TimeDelta page_stability_start_delay_;
base::WeakPtrFactory<ObservationDelayController> weak_ptr_factory_{this};
};
} // namespace actor
#endif // CHROME_BROWSER_ACTOR_TOOLS_OBSERVATION_DELAY_CONTROLLER_H_