blob: 023334ae25c2fdde477f4c527f4723ec53c63acc [file] [log] [blame]
// Copyright 2018 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/web_applications/web_app_provider.h"
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/feature_list.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/web_applications/bookmark_apps/bookmark_app_install_manager.h"
#include "chrome/browser/web_applications/components/web_app_audio_focus_id_map.h"
#include "chrome/browser/web_applications/components/web_app_constants.h"
#include "chrome/browser/web_applications/components/web_app_helpers.h"
#include "chrome/browser/web_applications/extensions/bookmark_app_tab_helper.h"
#include "chrome/browser/web_applications/extensions/bookmark_app_util.h"
#include "chrome/browser/web_applications/extensions/pending_bookmark_app_manager.h"
#include "chrome/browser/web_applications/extensions/web_app_extension_ids_map.h"
#include "chrome/browser/web_applications/external_web_apps.h"
#include "chrome/browser/web_applications/file_utils_wrapper.h"
#include "chrome/browser/web_applications/policy/web_app_policy_manager.h"
#include "chrome/browser/web_applications/system_web_app_manager.h"
#include "chrome/browser/web_applications/web_app_database.h"
#include "chrome/browser/web_applications/web_app_database_factory.h"
#include "chrome/browser/web_applications/web_app_icon_manager.h"
#include "chrome/browser/web_applications/web_app_install_finalizer.h"
#include "chrome/browser/web_applications/web_app_install_manager.h"
#include "chrome/browser/web_applications/web_app_provider_factory.h"
#include "chrome/browser/web_applications/web_app_registrar.h"
#include "chrome/browser/web_applications/web_app_tab_helper.h"
#include "chrome/browser/web_applications/web_app_utils.h"
#include "chrome/common/chrome_features.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/one_shot_event.h"
namespace web_app {
// static
WebAppProvider* WebAppProvider::Get(Profile* profile) {
return WebAppProviderFactory::GetForProfile(profile);
}
// static
WebAppProvider* WebAppProvider::GetForWebContents(
content::WebContents* web_contents) {
Profile* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
DCHECK(profile);
return WebAppProvider::Get(profile);
}
WebAppProvider::WebAppProvider(Profile* profile) : profile_(profile) {}
WebAppProvider::~WebAppProvider() = default;
void WebAppProvider::CreateSubsystems() {
audio_focus_id_map_ = std::make_unique<WebAppAudioFocusIdMap>();
if (base::FeatureList::IsEnabled(features::kDesktopPWAsWithoutExtensions))
CreateWebAppsSubsystems(profile_);
else
CreateBookmarkAppsSubsystems(profile_);
}
void WebAppProvider::Init() {
notification_registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
content::Source<Profile>(profile_));
if (base::FeatureList::IsEnabled(features::kDesktopPWAsWithoutExtensions)) {
if (AllowWebAppInstallation(profile_)) {
registrar_->Init(base::BindOnce(&WebAppProvider::OnRegistryReady,
weak_ptr_factory_.GetWeakPtr()));
}
} else {
system_web_app_manager_->Init();
web_app::ScanForExternalWebApps(
profile_, base::BindOnce(&WebAppProvider::OnScanForExternalWebApps,
weak_ptr_factory_.GetWeakPtr()));
extensions::ExtensionSystem::Get(profile_)->ready().Post(
FROM_HERE, base::BindRepeating(&WebAppProvider::OnRegistryReady,
weak_ptr_factory_.GetWeakPtr()));
}
}
void WebAppProvider::CreateWebAppsSubsystems(Profile* profile) {
if (!AllowWebAppInstallation(profile))
return;
database_factory_ = std::make_unique<WebAppDatabaseFactory>(profile);
database_ = std::make_unique<WebAppDatabase>(database_factory_.get());
registrar_ = std::make_unique<WebAppRegistrar>(database_.get());
icon_manager_ = std::make_unique<WebAppIconManager>(
profile, std::make_unique<FileUtilsWrapper>());
auto install_finalizer = std::make_unique<WebAppInstallFinalizer>(
registrar_.get(), icon_manager_.get());
install_manager_ = std::make_unique<WebAppInstallManager>(
profile, std::move(install_finalizer));
}
void WebAppProvider::CreateBookmarkAppsSubsystems(Profile* profile) {
install_manager_ = std::make_unique<extensions::BookmarkAppInstallManager>();
pending_app_manager_ =
std::make_unique<extensions::PendingBookmarkAppManager>(profile);
if (WebAppPolicyManager::ShouldEnableForProfile(profile)) {
web_app_policy_manager_ = std::make_unique<WebAppPolicyManager>(
profile, pending_app_manager_.get());
}
system_web_app_manager_ = std::make_unique<SystemWebAppManager>(
profile, pending_app_manager_.get());
}
void WebAppProvider::OnRegistryReady() {
DCHECK(!registry_is_ready_);
registry_is_ready_ = true;
if (registry_ready_callback_)
std::move(registry_ready_callback_).Run();
}
// static
void WebAppProvider::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
ExtensionIdsMap::RegisterProfilePrefs(registry);
WebAppPolicyManager::RegisterProfilePrefs(registry);
}
// static
WebAppTabHelperBase* WebAppProvider::CreateTabHelper(
content::WebContents* web_contents) {
WebAppProvider* provider = WebAppProvider::GetForWebContents(web_contents);
if (!provider)
return nullptr;
if (base::FeatureList::IsEnabled(features::kDesktopPWAsWithoutExtensions))
WebAppTabHelper::CreateForWebContents(web_contents);
else
extensions::BookmarkAppTabHelper::CreateForWebContents(web_contents);
WebAppTabHelperBase* tab_helper =
WebAppTabHelperBase::FromWebContents(web_contents);
tab_helper->SetAudioFocusIdMap(provider->audio_focus_id_map_.get());
return tab_helper;
}
// static
bool WebAppProvider::CanInstallWebApp(content::WebContents* web_contents) {
auto* provider = WebAppProvider::GetForWebContents(web_contents);
if (!provider || !provider->install_manager_)
return false;
return provider->install_manager_->CanInstallWebApp(web_contents);
}
// static
void WebAppProvider::InstallWebApp(content::WebContents* web_contents,
bool force_shortcut_app) {
auto* provider = WebAppProvider::GetForWebContents(web_contents);
if (!provider || !provider->install_manager_)
return;
provider->install_manager_->InstallWebApp(web_contents, force_shortcut_app,
base::DoNothing());
}
void WebAppProvider::Reset() {
// TODO(loyso): Make it independent to the order of destruction via using two
// end-to-end passes:
// 1) Do Reset() for each subsystem to nullify pointers (detach subsystems).
// 2) Destroy subsystems.
// PendingAppManager is used by WebAppPolicyManager and therefore should be
// deleted after it.
web_app_policy_manager_.reset();
system_web_app_manager_.reset();
pending_app_manager_.reset();
install_manager_.reset();
icon_manager_.reset();
registrar_.reset();
database_.reset();
database_factory_.reset();
audio_focus_id_map_.reset();
}
void WebAppProvider::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& detals) {
DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type);
// KeyedService::Shutdown() gets called when the profile is being destroyed,
// but after DCHECK'ing that no RenderProcessHosts are being leaked. The
// "chrome::NOTIFICATION_PROFILE_DESTROYED" notification gets sent before the
// DCHECK so we use that to clean up RenderProcessHosts instead.
Reset();
}
void WebAppProvider::SetRegistryReadyCallback(base::OnceClosure callback) {
DCHECK(!registry_ready_callback_);
if (registry_is_ready_) {
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
std::move(callback));
} else {
registry_ready_callback_ = std::move(callback);
}
}
int WebAppProvider::CountUserInstalledApps() const {
// TODO: Implement for new Web Apps system. crbug.com/918986.
if (base::FeatureList::IsEnabled(features::kDesktopPWAsWithoutExtensions))
return 0;
return extensions::CountUserInstalledBookmarkApps(profile_);
}
void WebAppProvider::OnScanForExternalWebApps(
std::vector<web_app::PendingAppManager::AppInfo> app_infos) {
pending_app_manager_->SynchronizeInstalledApps(
std::move(app_infos), InstallSource::kExternalDefault);
}
} // namespace web_app