blob: db1fe7ee7014e3ce6b9586d0bebdf748aa5b99bf [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/web_applications/app_browser_controller.h"
#include "base/feature_list.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ssl/security_state_tab_helper.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/extensions/hosted_app_browser_controller.h"
#include "chrome/browser/ui/manifest_web_app_browser_controller.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/web_applications/system_web_app_ui_utils.h"
#include "chrome/browser/ui/web_applications/web_app_browser_controller.h"
#include "chrome/browser/web_applications/components/app_registrar.h"
#include "chrome/browser/web_applications/components/web_app_helpers.h"
#include "chrome/browser/web_applications/system_web_app_manager.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/common/chrome_features.h"
#include "components/security_state/core/security_state.h"
#include "components/url_formatter/url_formatter.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/extension_registry.h"
#include "net/base/escape.h"
#include "url/gurl.h"
namespace web_app {
// static
std::unique_ptr<web_app::AppBrowserController>
AppBrowserController::MaybeCreateWebAppController(Browser* browser) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
const AppId app_id =
web_app::GetAppIdFromApplicationName(browser->app_name());
if (base::FeatureList::IsEnabled(features::kDesktopPWAsWithoutExtensions)) {
auto* provider = web_app::WebAppProvider::Get(browser->profile());
if (provider && provider->registrar().IsInstalled(app_id))
return std::make_unique<web_app::WebAppBrowserController>(browser);
}
const extensions::Extension* extension =
extensions::ExtensionRegistry::Get(browser->profile())
->GetExtensionById(app_id, extensions::ExtensionRegistry::EVERYTHING);
if (extension && extension->is_hosted_app()) {
if (base::FeatureList::IsEnabled(
features::kDesktopPWAsUnifiedUiController) &&
extension->from_bookmark()) {
return std::make_unique<web_app::WebAppBrowserController>(browser);
}
return std::make_unique<extensions::HostedAppBrowserController>(browser);
}
#endif
if (browser->is_focus_mode())
return std::make_unique<ManifestWebAppBrowserController>(browser);
return nullptr;
}
// static
bool AppBrowserController::IsForWebAppBrowser(const Browser* browser) {
return browser && browser->app_controller();
}
// static
base::string16 AppBrowserController::FormatUrlOrigin(const GURL& url) {
return url_formatter::FormatUrl(
url.GetOrigin(),
url_formatter::kFormatUrlOmitUsernamePassword |
url_formatter::kFormatUrlOmitHTTPS |
url_formatter::kFormatUrlOmitHTTP |
url_formatter::kFormatUrlOmitTrailingSlashOnBareHostname |
url_formatter::kFormatUrlOmitTrivialSubdomains,
net::UnescapeRule::SPACES, nullptr, nullptr, nullptr);
}
AppBrowserController::AppBrowserController(Browser* browser)
: content::WebContentsObserver(nullptr), browser_(browser) {
browser->tab_strip_model()->AddObserver(this);
}
AppBrowserController::~AppBrowserController() {
browser()->tab_strip_model()->RemoveObserver(this);
}
bool AppBrowserController::CreatedForInstalledPwa() const {
return false;
}
bool AppBrowserController::HasTabStrip() const {
// Show tabs for Terminal only.
// TODO(crbug.com/846546): Generalise this as a SystemWebApp capability.
return GetAppIdForSystemWebApp(browser()->profile(),
SystemAppType::TERMINAL) == GetAppId();
}
bool AppBrowserController::HasTitlebarToolbar() const {
// Show titlebar toolbar for Terminal System App, but not other system apps.
// TODO(crbug.com/846546): Generalise this as a SystemWebApp capability.
if (IsForSystemWebApp()) {
return GetAppIdForSystemWebApp(browser()->profile(),
SystemAppType::TERMINAL) == GetAppId();
}
// Show for all other apps.
return true;
}
bool AppBrowserController::HasTitlebarAppOriginText() const {
// Do not show origin text for System Apps.
return !IsForSystemWebApp();
}
bool AppBrowserController::HasTitlebarContentSettings() const {
// Do not show content settings for System Apps.
return !IsForSystemWebApp();
}
bool AppBrowserController::IsInstalled() const {
return false;
}
bool AppBrowserController::IsHostedApp() const {
return false;
}
bool AppBrowserController::CanUninstall() const {
return false;
}
void AppBrowserController::Uninstall() {
NOTREACHED();
return;
}
void AppBrowserController::UpdateCustomTabBarVisibility(bool animate) const {
browser()->window()->UpdateCustomTabBarVisibility(ShouldShowCustomTabBar(),
animate);
}
bool AppBrowserController::IsForSystemWebApp() const {
if (!GetAppId())
return false;
return web_app::WebAppProvider::Get(browser()->profile())
->system_web_app_manager()
.IsSystemWebApp(*GetAppId());
}
void AppBrowserController::DidStartNavigation(
content::NavigationHandle* navigation_handle) {
if (!initial_url().is_empty())
return;
if (!navigation_handle->IsInMainFrame())
return;
if (navigation_handle->GetURL().is_empty())
return;
SetInitialURL(navigation_handle->GetURL());
}
void AppBrowserController::DidChangeThemeColor(
base::Optional<SkColor> theme_color) {
browser_->window()->UpdateFrameColor();
}
base::Optional<SkColor> AppBrowserController::GetThemeColor() const {
base::Optional<SkColor> result;
// HTML meta theme-color tag overrides manifest theme_color, see spec:
// https://www.w3.org/TR/appmanifest/#theme_color-member
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
if (web_contents) {
base::Optional<SkColor> color = web_contents->GetThemeColor();
if (color)
result = color;
}
if (!result)
return base::nullopt;
// The frame/tabstrip code expects an opaque color.
return SkColorSetA(*result, SK_AlphaOPAQUE);
}
base::string16 AppBrowserController::GetTitle() const {
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
if (!web_contents)
return base::string16();
content::NavigationEntry* entry =
web_contents->GetController().GetVisibleEntry();
return entry ? entry->GetTitle() : base::string16();
}
void AppBrowserController::OnTabStripModelChanged(
TabStripModel* tab_strip_model,
const TabStripModelChange& change,
const TabStripSelectionChange& selection) {
if (change.type() == TabStripModelChange::kInserted) {
for (const auto& contents : change.GetInsert()->contents)
OnTabInserted(contents.contents);
} else if (change.type() == TabStripModelChange::kRemoved) {
for (const auto& contents : change.GetRemove()->contents)
OnTabRemoved(contents.contents);
}
if (selection.active_tab_changed()) {
content::WebContentsObserver::Observe(selection.new_contents);
DidChangeThemeColor(GetThemeColor());
}
// WebContents should be null when the last tab is closed.
DCHECK_EQ(web_contents() == nullptr, tab_strip_model->empty());
}
void AppBrowserController::OnTabInserted(content::WebContents* contents) {
if (!contents->GetVisibleURL().is_empty() && initial_url_.is_empty())
SetInitialURL(contents->GetVisibleURL());
}
void AppBrowserController::OnTabRemoved(content::WebContents* contents) {}
void AppBrowserController::SetInitialURL(const GURL& initial_url) {
DCHECK(initial_url_.is_empty());
initial_url_ = initial_url;
OnReceivedInitialURL();
}
} // namespace web_app