blob: f8d2a9adad4b80ae65b2f6e7b911df8f358c7a37 [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.
#include "chrome/browser/glic/glic_keyed_service.h"
#include "chrome/browser/glic/glic_enabling.h"
#include "chrome/browser/glic/glic_focused_tab_manager.h"
#include "chrome/browser/glic/glic_page_context_fetcher.h"
#include "chrome/browser/glic/glic_profile_manager.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/browser_navigator_params.h"
#include "chrome/browser/ui/views/glic/border/border_view.h"
#include "chrome/browser/ui/webui/glic/glic.mojom.h"
#include "content/public/browser/browser_context.h"
#include "content/public/common/url_constants.h"
#include "ui/base/page_transition_types.h"
#include "url/gurl.h"
namespace glic {
GlicKeyedService::GlicKeyedService(content::BrowserContext* browser_context,
GlicProfileManager* profile_manager)
: browser_context_(browser_context),
window_controller_(Profile::FromBrowserContext(browser_context)),
focused_tab_manager_(Profile::FromBrowserContext(browser_context),
window_controller_),
profile_manager_(profile_manager) {
focused_tab_changed_subscription_ =
focused_tab_manager_.AddFocusedTabChangedCallback(base::BindRepeating(
&GlicKeyedService::OnFocusedTabChanged, GetWeakPtr()));
}
GlicKeyedService::~GlicKeyedService() = default;
void GlicKeyedService::LaunchUI(views::View* glic_button_view) {
// Glic may be disabled for certain user profiles (the user is browsing in
// incognito or guest mode, policy, etc). In those cases, the entry points to
// this method should already have been removed.
CHECK(GlicEnabling::IsEnabledForProfile(
Profile::FromBrowserContext(browser_context_)));
profile_manager_->OnUILaunching(this);
window_controller_.Show(glic_button_view);
auto* web_contents = GetFocusedTab();
if (web_contents) {
if (BorderView* border =
BorderView::FindBorderForWebContents(web_contents)) {
border->StartAnimation();
}
} else {
// TODO(crbug.com/384740189): Find out if/how to start the border animation
// when web_contents is not available yet.
}
}
base::CallbackListSubscription GlicKeyedService::AddFocusedTabChangedCallback(
FocusedTabChangedCallback callback) {
return focused_tab_manager_.AddFocusedTabChangedCallback(callback);
}
void GlicKeyedService::CreateTab(
const ::GURL& url,
bool open_in_background,
const std::optional<int32_t>& window_id,
glic::mojom::WebClientHandler::CreateTabCallback callback) {
// If we need to open other URL types, it should be done in a more specific
// function.
if (!url.SchemeIsHTTPOrHTTPS()) {
std::move(callback).Run(nullptr);
return;
}
// TODO(crbug.com/379931179): This is a placeholder implementation. Implement
// createTab() correctly. It should consider which window to use, and observe
// the `open_in_background` flag. It should return actual data using the
// callback.
NavigateParams params(Profile::FromBrowserContext(browser_context_), url,
ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
Navigate(&params);
std::move(callback).Run(glic::mojom::TabData::New());
}
void GlicKeyedService::ClosePanel() {
window_controller_.Close();
BorderView::CancelAllAnimationsForProfile(
Profile::FromBrowserContext(browser_context_));
}
std::optional<gfx::Size> GlicKeyedService::ResizePanel(const gfx::Size& size) {
if (!window_controller_.Resize(size)) {
return std::nullopt;
}
return window_controller_.GetSize();
}
void GlicKeyedService::SetPanelDraggableAreas(
const std::vector<gfx::Rect>& draggable_areas) {
window_controller_.SetDraggableAreas(draggable_areas);
}
void GlicKeyedService::GetContextFromFocusedTab(
bool include_inner_text,
bool include_viewport_screenshot,
mojom::WebClientHandler::GetContextFromFocusedTabCallback callback) {
content::WebContents* web_contents = GetFocusedTab();
if (!web_contents) {
// TODO(crbug.com/379773651): Clean up logspam when it's no longer useful.
LOG(ERROR) << "GetContextFromFocusedTab: No web contents";
std::move(callback).Run(mojom::GetContextResult::NewErrorReason(
mojom::GetTabContextErrorReason::kWebContentsChanged));
return;
}
auto fetcher = std::make_unique<glic::GlicPageContextFetcher>();
fetcher->Fetch(
web_contents, include_inner_text, include_viewport_screenshot,
base::BindOnce(
// Bind `fetcher` to the callback to keep it in scope until it
// returns.
// TODO(harringtond): Consider adding throttling of how often we fetch
// context.
// TODO(harringtond): Consider deleting the fetcher if the page
// handler is unbound before the fetch completes.
[](std::unique_ptr<glic::GlicPageContextFetcher> fetcher,
mojom::WebClientHandler::GetContextFromFocusedTabCallback callback,
mojom::GetContextResultPtr result) {
std::move(callback).Run(std::move(result));
},
std::move(fetcher), std::move(callback)));
}
void GlicKeyedService::OnFocusedTabChanged(
const content::WebContents* focused_tab) {
CHECK_EQ(focused_tab, GetFocusedTab());
// TODO(crbug.com/385382048): We shouldn't cancel and restart the animation.
// Instead we should transit the current animation state from the previous
// browser window to the currently focused browser window.
BorderView::CancelAllAnimationsForProfile(
Profile::FromBrowserContext(browser_context_));
if (focused_tab && window_controller_.HasWindow()) {
if (BorderView* border =
BorderView::FindBorderForWebContents(focused_tab)) {
border->StartAnimation();
}
}
}
content::WebContents* GlicKeyedService::GetFocusedTab() {
return focused_tab_manager_.GetWebContentsForFocusedTab();
}
base::WeakPtr<GlicKeyedService> GlicKeyedService::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
} // namespace glic