blob: 90c81ad033be2639b46f7e17964793b4c25271c2 [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.
#include "chrome/browser/ash/browser_delegate/browser_controller_impl.h"
#include <memory>
#include <unordered_map>
#include "base/check.h"
#include "chrome/browser/ash/browser_delegate/browser_delegate_impl.h"
#include "chrome/browser/ash/browser_delegate/browser_type.h"
#include "chrome/browser/ash/browser_delegate/browser_type_conversion.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/autofill/chrome_autofill_client.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.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/browser_window.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
#include "chrome/browser/web_applications/web_app_helpers.h"
#include "chromeos/ash/components/browser_context_helper/browser_context_helper.h"
#include "components/account_id/account_id.h"
#include "ui/aura/window.h"
namespace {
bool BrowserMatchesURL(Browser* browser, const GURL& url) {
return browser->tab_strip_model()
->GetActiveWebContents()
->GetVisibleURL()
.EqualsIgnoringRef(url);
}
bool BrowserMatches(Browser* browser,
Profile* profile,
webapps::AppId app_id,
Browser::Type type,
const GURL& url) {
return browser->profile() == profile && browser->type() == type &&
web_app::GetAppIdFromApplicationName(browser->app_name()) == app_id &&
(url.is_empty() || BrowserMatchesURL(browser, url));
}
} // namespace
namespace ash {
BrowserControllerImpl::BrowserControllerImpl() {
observation_.Observe(BrowserList::GetInstance());
}
BrowserControllerImpl::~BrowserControllerImpl() = default;
BrowserDelegate* BrowserControllerImpl::GetDelegate(Browser* browser) {
if (browser == nullptr) {
return nullptr;
}
auto it = browsers_.find(browser);
if (it == browsers_.end()) {
it = browsers_
.insert({browser, std::make_unique<BrowserDelegateImpl>(browser)})
.first;
}
return it->second.get();
}
BrowserDelegate* BrowserControllerImpl::GetLastUsedBrowser() {
return GetDelegate(BrowserList::GetInstance()->GetLastActive());
}
BrowserDelegate* BrowserControllerImpl::GetLastUsedVisibleBrowser() {
for (Browser* browser : BrowserList::GetInstance()->OrderedByActivation()) {
if (browser->window()->IsVisible()) {
return GetDelegate(browser);
}
}
return nullptr;
}
BrowserDelegate* BrowserControllerImpl::GetLastUsedVisibleOnTheRecordBrowser() {
for (Browser* browser : BrowserList::GetInstance()->OrderedByActivation()) {
if (!browser->profile()->IsOffTheRecord() &&
browser->window()->IsVisible()) {
return GetDelegate(browser);
}
}
return nullptr;
}
void BrowserControllerImpl::ForEachBrowser(
BrowserOrder order,
base::FunctionRef<IterationDirective(BrowserDelegate&)> callback) {
switch (order) {
case BrowserOrder::kAscendingCreationTime:
for (Browser* browser : *BrowserList::GetInstance()) {
if (callback(*GetDelegate(browser)) == kBreakIteration) {
break;
}
}
break;
case BrowserOrder::kAscendingActivationTime:
for (Browser* browser :
BrowserList::GetInstance()->OrderedByActivation()) {
if (callback(*GetDelegate(browser)) == kBreakIteration) {
break;
}
}
break;
}
}
BrowserDelegate* BrowserControllerImpl::GetBrowserForWindow(
aura::Window* window) {
BrowserView* browser_view =
BrowserView::GetBrowserViewForNativeWindow(window);
return GetDelegate(browser_view ? browser_view->browser() : nullptr);
}
BrowserDelegate* BrowserControllerImpl::FindWebApp(const AccountId& account_id,
webapps::AppId app_id,
BrowserType browser_type,
const GURL& url) {
Profile* profile = Profile::FromBrowserContext(
BrowserContextHelper::Get()->GetBrowserContextByAccountId(account_id));
CHECK(profile);
CHECK(browser_type == BrowserType::kApp ||
browser_type == BrowserType::kAppPopup);
Browser::Type internal_type = ToInternalBrowserType(browser_type);
for (Browser* browser : BrowserList::GetInstance()->OrderedByActivation()) {
if (!browser->is_delete_scheduled() &&
BrowserMatches(browser, profile, app_id, internal_type, url)) {
return GetDelegate(browser);
}
}
return nullptr;
}
BrowserDelegate* BrowserControllerImpl::NewTabWithPostData(
const AccountId& account_id,
const GURL& url,
base::span<const uint8_t> post_data,
std::string_view extra_headers) {
Profile* profile = Profile::FromBrowserContext(
BrowserContextHelper::Get()->GetBrowserContextByAccountId(account_id));
CHECK(profile);
NavigateParams navigate_params(
profile, url,
// TODO(crbug.com/369688254): The page transition was chosen to satisfy
// some obsolete condition and should be revisited.
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
ui::PAGE_TRANSITION_FROM_API |
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR));
navigate_params.window_action = NavigateParams::SHOW_WINDOW;
navigate_params.post_data =
network::ResourceRequestBody::CreateFromCopyOfBytes(post_data);
navigate_params.extra_headers = std::string(extra_headers);
navigate_params.browser = chrome::FindTabbedBrowser(profile, false);
if (!navigate_params.browser &&
Browser::GetCreationStatusForProfile(profile) ==
Browser::CreationStatus::kOk) {
Browser::CreateParams create_params(profile, navigate_params.user_gesture);
create_params.should_trigger_session_restore = false;
navigate_params.browser = Browser::Create(create_params);
}
Navigate(&navigate_params);
return GetDelegate(navigate_params.browser);
}
BrowserDelegate* BrowserControllerImpl::CreateWebApp(
const AccountId& account_id,
webapps::AppId app_id,
BrowserType browser_type,
const CreateParams& params) {
CHECK(browser_type == BrowserType::kApp ||
browser_type == BrowserType::kAppPopup)
<< "Unexpected BrowserType: " << static_cast<int>(browser_type);
const bool popup = browser_type == BrowserType::kAppPopup;
Profile* profile = Profile::FromBrowserContext(
BrowserContextHelper::Get()->GetBrowserContextByAccountId(account_id));
CHECK(profile);
if (Browser::GetCreationStatusForProfile(profile) !=
Browser::CreationStatus::kOk) {
LOG(WARNING) << "Cannot create browser for given profile";
return nullptr;
}
Browser::CreateParams cparams =
web_app::CreateParamsForApp(app_id, popup,
/*trusted_source=*/true,
/*window_bounds=*/gfx::Rect(), profile,
/*user_gesture=*/true);
cparams.restore_id = params.restore_id;
cparams.omit_from_session_restore = true;
cparams.initial_show_state = ui::mojom::WindowShowState::kDefault;
cparams.can_resize = params.allow_resize;
cparams.can_maximize = params.allow_maximize;
cparams.can_fullscreen = params.allow_fullscreen;
return GetDelegate(
web_app::CreateWebAppWindowMaybeWithHomeTab(app_id, cparams));
}
BrowserDelegate* BrowserControllerImpl::CreateCustomTab(
const AccountId& account_id,
std::unique_ptr<content::WebContents> contents) {
Profile* profile = Profile::FromBrowserContext(
BrowserContextHelper::Get()->GetBrowserContextByAccountId(account_id));
CHECK(profile);
if (Browser::GetCreationStatusForProfile(profile) !=
Browser::CreationStatus::kOk) {
return nullptr;
}
Browser::CreateParams params(Browser::TYPE_CUSTOM_TAB, profile,
/*user_gesture=*/true);
params.omit_from_session_restore = true;
Browser* browser = Browser::Create(params);
browser->tab_strip_model()->AppendWebContents(std::move(contents),
/*foreground=*/true);
return GetDelegate(browser);
}
void BrowserControllerImpl::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void BrowserControllerImpl::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
void BrowserControllerImpl::OnBrowserRemoved(Browser* browser) {
if (BrowserList::GetInstance()->empty()) {
for (auto& observer : observers_) {
observer.OnLastBrowserClosed();
}
}
browsers_.erase(browser);
// The corresponding BrowserDelegateImpl, if any, is now dead.
}
void BrowserControllerImpl::CreateAutofillClientForWebContents(
content::WebContents* web_contents) {
autofill::ChromeAutofillClient::CreateForWebContents(web_contents);
}
} // namespace ash