blob: 73996f27163f912efb5bfdbe87b20b8c1ced350f [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 <utility>
#include "chrome/browser/web_applications/web_app_install_manager.h"
#include "base/callback.h"
#include "base/logging.h"
#include "chrome/browser/web_applications/components/install_finalizer.h"
#include "chrome/browser/web_applications/components/web_app_constants.h"
#include "chrome/browser/web_applications/components/web_app_data_retriever.h"
#include "chrome/browser/web_applications/components/web_app_icon_generator.h"
#include "chrome/browser/web_applications/web_app_utils.h"
#include "chrome/common/web_application_info.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
#include "third_party/blink/public/common/manifest/manifest.h"
namespace web_app {
WebAppInstallManager::WebAppInstallManager(
Profile* profile,
std::unique_ptr<InstallFinalizer> install_finalizer)
: data_retriever_(std::make_unique<WebAppDataRetriever>()),
install_finalizer_(std::move(install_finalizer)) {
DCHECK(AllowWebAppInstallation(profile));
}
WebAppInstallManager::~WebAppInstallManager() = default;
bool WebAppInstallManager::CanInstallWebApp(
content::WebContents* web_contents) {
return IsValidWebAppUrl(web_contents->GetURL());
}
void WebAppInstallManager::InstallWebApp(content::WebContents* contents,
bool force_shortcut_app,
OnceInstallCallback install_callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Concurrent calls are not allowed.
DCHECK(!web_contents());
CHECK(!install_callback_);
Observe(contents);
install_callback_ = std::move(install_callback);
data_retriever_->GetWebApplicationInfo(
web_contents(),
base::BindOnce(&WebAppInstallManager::OnGetWebApplicationInfo,
weak_ptr_factory_.GetWeakPtr(), force_shortcut_app));
}
void WebAppInstallManager::WebContentsDestroyed() {
ReturnError(InstallResultCode::kWebContentsDestroyed);
}
void WebAppInstallManager::SetDataRetrieverForTesting(
std::unique_ptr<WebAppDataRetriever> data_retriever) {
data_retriever_ = std::move(data_retriever);
}
void WebAppInstallManager::SetInstallFinalizerForTesting(
std::unique_ptr<InstallFinalizer> install_finalizer) {
install_finalizer_ = std::move(install_finalizer);
}
void WebAppInstallManager::CallInstallCallback(const AppId& app_id,
InstallResultCode code) {
Observe(nullptr);
DCHECK(install_callback_);
std::move(install_callback_).Run(app_id, code);
}
void WebAppInstallManager::ReturnError(InstallResultCode code) {
CallInstallCallback(AppId(), code);
}
bool WebAppInstallManager::InstallInterrupted() const {
// Interrupt early if WebContents is being destroyed.
// WebContentsDestroyed will get called eventually and the callback will be
// invoked at that point.
if (!web_contents() || web_contents()->IsBeingDestroyed())
return true;
return false;
}
void WebAppInstallManager::OnGetWebApplicationInfo(
bool force_shortcut_app,
std::unique_ptr<WebApplicationInfo> web_app_info) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// If interrupted, install_callback_ is already invoked or may invoke later.
if (InstallInterrupted())
return;
if (!web_app_info)
return ReturnError(InstallResultCode::kGetWebApplicationInfoFailed);
data_retriever_->CheckInstallabilityAndRetrieveManifest(
web_contents(),
base::BindOnce(&WebAppInstallManager::OnDidPerformInstallableCheck,
weak_ptr_factory_.GetWeakPtr(), std::move(web_app_info),
force_shortcut_app));
}
void WebAppInstallManager::OnDidPerformInstallableCheck(
std::unique_ptr<WebApplicationInfo> web_app_info,
bool force_shortcut_app,
const blink::Manifest& manifest,
bool is_installable) {
// If interrupted, install_callback_ is already invoked or may invoke later.
if (InstallInterrupted())
return;
DCHECK(web_app_info);
const ForInstallableSite for_installable_site =
is_installable && !force_shortcut_app ? ForInstallableSite::kYes
: ForInstallableSite::kNo;
// TODO(loyso): Implement UpdateShareTargetInPrefs installation logic.
UpdateWebAppInfoFromManifest(manifest, web_app_info.get(),
for_installable_site);
std::vector<GURL> icon_urls;
for (auto& icon_info : web_app_info->icons) {
if (icon_info.url.is_valid())
icon_urls.push_back(icon_info.url);
}
// If the manifest specified icons, don't use the page icons.
const bool skip_page_fav_icons = !manifest.icons.empty();
data_retriever_->GetIcons(
web_contents(), icon_urls, skip_page_fav_icons,
base::BindOnce(&WebAppInstallManager::OnIconsRetrieved,
weak_ptr_factory_.GetWeakPtr(), std::move(web_app_info)));
}
void WebAppInstallManager::OnIconsRetrieved(
std::unique_ptr<WebApplicationInfo> web_app_info,
IconsMap icons_map) {
// If interrupted, install_callback_ is already invoked or may invoke later.
if (InstallInterrupted())
return;
DCHECK(web_app_info);
std::vector<BitmapAndSource> downloaded_icons =
FilterSquareIcons(icons_map, *web_app_info);
ResizeDownloadedIconsGenerateMissing(std::move(downloaded_icons),
web_app_info.get());
install_finalizer_->FinalizeInstall(
std::move(web_app_info),
base::BindOnce(&WebAppInstallManager::OnInstallFinalized,
weak_ptr_factory_.GetWeakPtr()));
}
void WebAppInstallManager::OnInstallFinalized(const AppId& app_id,
InstallResultCode code) {
CallInstallCallback(app_id, code);
}
} // namespace web_app