| // 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_ |