blob: f1c5cd3bfe1e8c5f6c4861f4066dd3b8e71ddd9d [file] [log] [blame]
// Copyright 2024 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_GLIC_PUBLIC_GLIC_KEYED_SERVICE_H_
#define CHROME_BROWSER_GLIC_PUBLIC_GLIC_KEYED_SERVICE_H_
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "base/callback_list.h"
#include "base/containers/flat_set.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/memory/raw_ptr.h"
#include "chrome/browser/glic/glic_metrics.h"
#include "chrome/browser/glic/glic_zero_state_suggestions_manager.h"
#include "chrome/browser/glic/host/context/glic_sharing_manager_provider.h"
#include "chrome/browser/glic/host/glic.mojom.h"
#include "chrome/browser/glic/host/glic_web_client_access.h"
#include "chrome/browser/glic/host/host.h"
#include "chrome/browser/glic/public/context/glic_sharing_manager.h"
#include "chrome/browser/glic/public/glic_enabling.h"
#include "chrome/browser/glic/public/glic_instance.h"
#include "chrome/common/actor.mojom-forward.h"
#include "chrome/common/actor/task_id.h"
#include "chrome/common/actor_webui.mojom-forward.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/tabs/public/tab_interface.h"
#include "content/public/browser/web_contents.h"
#include "mojo/public/cpp/bindings/remote.h"
class BrowserWindowInterface;
class Profile;
class ProfileManager;
namespace actor {
class ActorKeyedService;
class ActorTaskDelegate;
} // namespace actor
namespace contextual_cueing {
class ContextualCueingService;
} // namespace contextual_cueing
namespace signin {
class IdentityManager;
} // namespace signin
namespace glic {
class AuthController;
class GlicEnabling;
class GlicFreController;
class GlicMetrics;
class GlicOcclusionNotifier;
class GlicProfileManager;
class GlicRegionCaptureController;
class GlicScreenshotCapturer;
class GlicShareImageHandler;
class GlicWindowController;
class HostManager;
class GlicActorTaskManager;
enum class GlicPrewarmingChecksResult;
// LINT.IfChange(GlicPrewarmingFreSource)
enum class GlicPrewarmingFreSource {
kWhatsNew = 0,
kNudge = 1,
kIph = 2,
kTest = 3,
kBrowserCommand = 4,
kMaxValue = kBrowserCommand,
};
// LINT.ThenChange(//tools/metrics/histograms/metadata/glic/enums.xml:GlicPrewarmingFreSource)
// The GlicKeyedService is created for each eligible (i.e. non-incognito,
// non-system, etc.) browser profile if Glic flags are enabled, regardless
// of whether the profile is enabled or disabled at runtime (currently
// possible via enterprise policy). This is required on disabled profiles
// since pieces of this service are the ones that monitor this runtime
// preference for changes and cause the UI to respond to it.
class GlicKeyedService : public KeyedService,
public GlicSharingManagerProvider,
public Host::InstanceDelegate,
public base::MemoryPressureListener {
public:
explicit GlicKeyedService(
Profile* profile,
signin::IdentityManager* identity_manager,
ProfileManager* profile_manager,
GlicProfileManager* glic_profile_manager,
contextual_cueing::ContextualCueingService* contextual_cueing_service,
actor::ActorKeyedService* actor_keyed_service);
GlicKeyedService(const GlicKeyedService&) = delete;
GlicKeyedService& operator=(const GlicKeyedService&) = delete;
~GlicKeyedService() override;
// Convenience method, may return nullptr.
static GlicKeyedService* Get(content::BrowserContext* context);
// KeyedService
void Shutdown() override;
// Show, summon or activate the panel, or close it if it's already active and
// prevent_close is false. If glic_button_view is non-null, attach the panel
// to that view's Browser.
// TODO(b:448888544): remove `prevent_close` in favor of a Show method.
void ToggleUI(BrowserWindowInterface* bwi,
bool prevent_close,
mojom::InvocationSource source,
std::optional<std::string> prompt_suggestion = std::nullopt);
void OpenFreDialogInNewTab(BrowserWindowInterface* bwi,
mojom::InvocationSource source);
// Forcibly close the UI. This is similar to Shutdown in that it causes the
// window controller to shutdown (and clear cached state), but unlike
// Shutdown, it doesn't unregister as the "active glic" with the profile
// manager.
// TODO(crbug.com/454112198): Remove when multi-instance launches.
void CloseAndShutdown();
// Close the panel. Virtual for testing.
// TODO(crbug.com/448406730): Remove testing logic that relies on
// GKS::CloseFloatingPanel since close panel is now being handled by
// EmbedderDelegate.
virtual void CloseFloatingPanel();
GlicEnabling& enabling() { return *enabling_.get(); }
GlicMetrics* metrics() { return metrics_.get(); }
GlicFreController& fre_controller();
GlicWindowController& window_controller() const;
GlicWindowControllerInterface& GetSingleInstanceWindowController() const;
GlicSharingManager& sharing_manager() override;
// Called when a webview guest is created within a chrome://glic WebUI.
void GuestAdded(content::WebContents* guest_contents);
// Virtual for testing.
virtual bool IsWindowShowing() const;
// Returns true if `bwi` has a glic panel showing for its active tab.
bool IsPanelShowingForBrowser(const BrowserWindowInterface& bwi) const;
// Virtual for testing.
virtual bool IsWindowDetached() const;
bool IsWindowOrFreShowing() const;
// Private API for the glic WebUI.
void SetContextAccessIndicator(bool show);
// Callback for changes to the context access indicator status.
using ContextAccessIndicatorChangedCallback =
base::RepeatingCallback<void(bool)>;
// Registers a callback to be called any time the context access indicator
// status changes. This is used to update UI effects on the focused tab
// depending on whether the client has requested the indicators or not.
base::CallbackListSubscription AddContextAccessIndicatorStatusChangedCallback(
ContextAccessIndicatorChangedCallback callback);
// Returns whether the context access indicator should be shown for the web
// contents. True iff the web contents is considered focused by
// GlicFocusedTabManager and the web client has enabled the context access
// indicator.
bool IsContextAccessIndicatorShown(const content::WebContents* contents);
bool is_context_access_indicator_enabled() const {
return is_context_access_indicator_enabled_;
}
// Host::InstanceDelegate:
// CreateTab is used by both the FRE page and the glic web client to open a
// URL in a new tab. The source is the RenderFrameHost of the Glic
// instance that is requesting the navigation - this gets set as the
// navigation handle's opener param.
tabs::TabInterface* CreateTab(
const ::GURL& url,
bool open_in_background,
const std::optional<int32_t>& window_id,
glic::mojom::WebClientHandler::CreateTabCallback callback) override;
void CreateTask(
base::WeakPtr<actor::ActorTaskDelegate> delegate,
actor::webui::mojom::TaskOptionsPtr options,
mojom::WebClientHandler::CreateTaskCallback callback) override;
void PerformActions(
const std::vector<uint8_t>& actions_proto,
mojom::WebClientHandler::PerformActionsCallback callback) override;
void StopActorTask(actor::TaskId task_id,
mojom::ActorTaskStopReason stop_reason) override;
void PauseActorTask(actor::TaskId task_id,
mojom::ActorTaskPauseReason pause_reason,
tabs::TabInterface::Handle tab_handle) override;
// TODO(crbug.com/446696379) - The ResumeActorTask Glic API should, like the
// rest of actor observations, operate in terms of TabObservation rather than
// TabContext.
void ResumeActorTask(
actor::TaskId task_id,
const mojom::GetTabContextOptions& context_options,
glic::mojom::WebClientHandler::ResumeActorTaskCallback callback) override;
void InterruptActorTask(actor::TaskId task_id) override;
void UninterruptActorTask(actor::TaskId task_id) override;
void FetchZeroStateSuggestions(
bool is_first_run,
std::optional<std::vector<std::string>> supported_tools,
glic::mojom::WebClientHandler::
GetZeroStateSuggestionsForFocusedTabCallback callback) override;
void GetZeroStateSuggestionsAndSubscribe(
bool has_active_subscription,
const mojom::ZeroStateSuggestionsOptions& options,
mojom::WebClientHandler::GetZeroStateSuggestionsAndSubscribeCallback
callback) override;
void RegisterConversation(
glic::mojom::ConversationInfoPtr info,
mojom::WebClientHandler::RegisterConversationCallback callback) override;
void OnWebClientCleared() override;
void PrepareForOpen() override;
void OnInteractionModeChange(mojom::WebClientMode new_mode) override;
void OnUserInputSubmitted(glic::mojom::WebClientMode mode);
// Registers a callback to be called any time user input is submitted in the
// client. This is used to update UI effects on tabs that are being shared
// with glic.
base::CallbackListSubscription AddUserInputSubmittedCallback(
base::RepeatingClosure callback);
void CaptureRegion(
content::WebContents* web_contents,
mojo::PendingRemote<mojom::CaptureRegionObserver> observer);
// Fetches the image for the context menu item (if possible, and potentially
// scaling and reencoding) and sends the result to the web client as
// additional data.
void ShareContextImage(tabs::TabInterface* tab,
content::RenderFrameHost* frame,
const ::GURL& src_url);
AuthController& GetAuthController() { return *auth_controller_; }
GlicRegionCaptureController& region_capture_controller();
bool IsActiveWebContents(content::WebContents* contents);
void AddPreloadCallback(base::OnceCallback<void()> callback);
virtual void TryPreload();
void TryPreloadAfterDelay();
virtual void TryPreloadFre(GlicPrewarmingFreSource source);
void Reload(content::RenderFrameHost* render_frame_host);
// Close the active embedder for an instance associated with this render frame
// host.
void Close(content::RenderFrameHost* outermost_render_frame_host);
Profile* profile() const { return profile_; }
// Used only for testing purposes.
void reset_profile_for_test() { profile_ = nullptr; }
base::WeakPtr<GlicKeyedService> GetWeakPtr();
void OnMemoryPressure(base::MemoryPressureLevel level) override;
HostManager& host_manager();
// Null in multi-instance mode.
GlicZeroStateSuggestionsManager* zero_state_suggestions_manager() {
return zero_state_suggestions_manager_.get();
}
// Returns whether this process host is either the Glic FRE WebUI or the Glic
// main WebUI.
bool IsProcessHostForGlic(content::RenderProcessHost* process_host);
// Returns whether this web contents contains the Chrome glic WebUI,
// chrome://glic.
bool IsGlicWebUi(content::WebContents* web_contents);
// Get the GlicInstance associated with the given browser's active tab, or
// null if there is none. `bwi` can be null if preloaded with no browser open.
GlicInstance* GetInstanceForActiveTab(BrowserWindowInterface* bwi);
// Get the GlicInstance for a provided tab, or null if there is none.
GlicInstance* GetInstanceForTab(tabs::TabInterface* tab);
// Sends additional context to the web client associated with the given tab.
// If no web client exists for the tab, then this method does nothing. It is
// the responsibility of the caller to ensure that a host exists before
// calling this method.
void SendAdditionalContext(tabs::TabHandle tab_handle,
mojom::AdditionalContextPtr context);
private:
// A helper function to route GetZeroStateSuggestionsForFocusedTabCallback
// callbacks.
void OnZeroStateSuggestionsFetched(
glic::mojom::ZeroStateSuggestionsPtr suggestions,
glic::mojom::WebClientHandler::
GetZeroStateSuggestionsForFocusedTabCallback callback,
std::vector<std::string> returned_suggestions);
void FinishPreload(GlicPrewarmingChecksResult reason);
void FinishPreloadFre(GlicPrewarmingFreSource source, bool should_preload);
// List of callbacks to be notified when the client requests a change to the
// context access indicator status.
base::RepeatingCallbackList<void(bool)>
context_access_indicator_callback_list_;
// The state of the context access indicator as set by the client.
bool is_context_access_indicator_enabled_ = false;
// List of callbacks to be notified when user input has been submitted.
base::RepeatingClosureList user_input_submitted_callback_list_;
raw_ptr<Profile> profile_;
std::unique_ptr<GlicEnabling> enabling_;
std::unique_ptr<GlicMetrics> metrics_;
std::unique_ptr<GlicFreController> fre_controller_;
// Is either a GlicWindowControllerImpl or GlicPanelCoordinatorImpl.
std::unique_ptr<GlicWindowController> window_controller_;
std::unique_ptr<GlicSharingManager> sharing_manager_;
std::unique_ptr<GlicShareImageHandler> share_image_handler_;
std::unique_ptr<GlicScreenshotCapturer> screenshot_capturer_;
std::unique_ptr<GlicRegionCaptureController> region_capture_controller_;
std::unique_ptr<AuthController> auth_controller_;
std::unique_ptr<base::MemoryPressureListenerRegistration>
memory_pressure_listener_registration_;
// Null in multi-instance mode.
std::unique_ptr<GlicOcclusionNotifier> occlusion_notifier_;
std::unique_ptr<GlicZeroStateSuggestionsManager>
zero_state_suggestions_manager_;
base::OnceCallback<void()> preload_callback_;
std::unique_ptr<GlicActorTaskManager> actor_task_manager_;
// Unowned
raw_ptr<contextual_cueing::ContextualCueingService>
contextual_cueing_service_;
base::WeakPtrFactory<GlicKeyedService> weak_ptr_factory_{this};
};
} // namespace glic
#endif // CHROME_BROWSER_GLIC_PUBLIC_GLIC_KEYED_SERVICE_H_