blob: d60819e0547c8ca4cdb679f507b8c91971da45ae [file] [log] [blame]
// Copyright 2022 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/web_applications/commands/install_from_info_command.h"
#include <memory>
#include <utility>
#include "base/check_is_test.h"
#include "base/containers/flat_set.h"
#include "base/functional/bind.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/stringprintf.h"
#include "base/strings/to_string.h"
#include "chrome/browser/web_applications/locks/app_lock.h"
#include "chrome/browser/web_applications/os_integration/os_integration_manager.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/browser/web_applications/web_app_helpers.h"
#include "chrome/browser/web_applications/web_app_id.h"
#include "chrome/browser/web_applications/web_app_install_finalizer.h"
#include "chrome/browser/web_applications/web_app_install_utils.h"
#include "chrome/browser/web_applications/web_app_uninstall_and_replace_job.h"
#include "components/webapps/browser/install_result_code.h"
#include "components/webapps/browser/installable/installable_metrics.h"
namespace web_app {
InstallFromInfoCommand::InstallFromInfoCommand(
Profile* profile,
std::unique_ptr<WebAppInstallInfo> install_info,
bool overwrite_existing_manifest_fields,
webapps::WebappInstallSource install_surface,
OnceInstallCallback install_callback)
: WebAppCommandTemplate<AppLock>("InstallFromInfoCommand"),
profile_(profile),
manifest_id_(
install_info->manifest_id.is_empty()
? GenerateManifestIdFromStartUrlOnly(install_info->start_url)
: install_info->manifest_id),
app_id_(GenerateAppIdFromManifestId(manifest_id_)),
lock_description_(std::make_unique<AppLockDescription>(app_id_)),
install_info_(std::move(install_info)),
overwrite_existing_manifest_fields_(overwrite_existing_manifest_fields),
install_surface_(install_surface),
install_callback_(base::BindOnce(
[](OnceInstallCallback install_callback,
const AppId& app_id,
webapps::InstallResultCode code,
bool _) { std::move(install_callback).Run(app_id, code); },
std::move(install_callback))) {
PopulateInitialDebugInfo();
if (install_info_->manifest_id.is_empty()) {
// TODO(b/280862254): After the manifest id constructor is required, this
// can be removed.
install_info_->manifest_id = manifest_id_;
}
CHECK(install_info_->manifest_id.is_valid());
}
InstallFromInfoCommand::InstallFromInfoCommand(
Profile* profile,
std::unique_ptr<WebAppInstallInfo> install_info,
bool overwrite_existing_manifest_fields,
webapps::WebappInstallSource install_surface,
OnceInstallCallback install_callback,
const WebAppInstallParams& install_params)
: WebAppCommandTemplate<AppLock>("InstallFromInfoCommand"),
profile_(profile),
manifest_id_(
install_info->manifest_id.is_empty()
? GenerateManifestIdFromStartUrlOnly(install_info->start_url)
: install_info->manifest_id),
app_id_(GenerateAppIdFromManifestId(manifest_id_)),
lock_description_(std::make_unique<AppLockDescription>(app_id_)),
install_info_(std::move(install_info)),
overwrite_existing_manifest_fields_(overwrite_existing_manifest_fields),
install_surface_(install_surface),
install_callback_(base::BindOnce(
[](OnceInstallCallback install_callback,
const AppId& app_id,
webapps::InstallResultCode code,
bool _) { std::move(install_callback).Run(app_id, code); },
std::move(install_callback))),
install_params_(install_params) {
if (install_info_->manifest_id.is_empty()) {
// TODO(b/280862254): After the manifest id constructor is required, this
// can be removed.
install_info_->manifest_id = manifest_id_;
}
CHECK(install_info_->manifest_id.is_valid());
if (!install_params.locally_installed) {
DCHECK(!install_params.add_to_applications_menu);
DCHECK(!install_params.add_to_desktop);
DCHECK(!install_params.add_to_quick_launch_bar);
}
DCHECK(install_info_->start_url.is_valid());
PopulateInitialDebugInfo();
}
InstallFromInfoCommand::InstallFromInfoCommand(
Profile* profile,
std::unique_ptr<WebAppInstallInfo> install_info,
bool overwrite_existing_manifest_fields,
webapps::WebappInstallSource install_surface,
InstallAndReplaceCallback install_callback,
const WebAppInstallParams& install_params,
const std::vector<AppId>& apps_or_extensions_to_uninstall)
: WebAppCommandTemplate<AppLock>("InstallFromInfoCommand"),
profile_(profile),
manifest_id_(
install_info->manifest_id.is_empty()
? GenerateManifestIdFromStartUrlOnly(install_info->start_url)
: install_info->manifest_id),
app_id_(GenerateAppIdFromManifestId(manifest_id_)),
lock_description_(std::make_unique<AppLockDescription>(app_id_)),
install_info_(std::move(install_info)),
overwrite_existing_manifest_fields_(overwrite_existing_manifest_fields),
install_surface_(install_surface),
install_callback_(std::move(install_callback)),
install_params_(install_params),
apps_or_extensions_to_uninstall_(apps_or_extensions_to_uninstall) {
if (install_info_->manifest_id.is_empty()) {
// TODO(b/280862254): After the manifest id constructor is required, this
// can be removed.
install_info_->manifest_id = manifest_id_;
}
CHECK(install_info_->manifest_id.is_valid());
if (!install_params.locally_installed) {
DCHECK(!install_params.add_to_applications_menu);
DCHECK(!install_params.add_to_desktop);
DCHECK(!install_params.add_to_quick_launch_bar);
}
DCHECK(install_info_->start_url.is_valid());
PopulateInitialDebugInfo();
}
InstallFromInfoCommand::~InstallFromInfoCommand() = default;
const LockDescription& InstallFromInfoCommand::lock_description() const {
return *lock_description_;
}
void InstallFromInfoCommand::StartWithLock(std::unique_ptr<AppLock> lock) {
lock_ = std::move(lock);
PopulateProductIcons(install_info_.get(),
/*icons_map=*/nullptr);
// No IconsMap to populate shortcut item icons from.
if (install_params_) {
ApplyParamsToWebAppInstallInfo(*install_params_, *install_info_);
}
if (webapps::InstallableMetrics::IsReportableInstallSource(
install_surface_)) {
webapps::InstallableMetrics::TrackInstallEvent(install_surface_);
}
WebAppInstallFinalizer::FinalizeOptions options(install_surface_);
options.locally_installed = true;
options.overwrite_existing_manifest_fields =
overwrite_existing_manifest_fields_;
if (install_params_) {
ApplyParamsToFinalizeOptions(*install_params_, options);
} else {
options.bypass_os_hooks = true;
}
lock_->install_finalizer().FinalizeInstall(
*install_info_, options,
base::BindOnce(&InstallFromInfoCommand::OnInstallCompleted,
weak_factory_.GetWeakPtr()));
}
void InstallFromInfoCommand::PopulateInitialDebugInfo() {
debug_value_.Set("app_id", app_id_);
debug_value_.Set("manifest_id", manifest_id_.spec());
debug_value_.Set("start_url", install_info_->start_url.spec());
debug_value_.Set("overwrite_existing_manifest_fields",
overwrite_existing_manifest_fields_);
debug_value_.Set("install_surface", static_cast<int>(install_surface_));
debug_value_.Set("has_install_params", install_params_ ? true : false);
}
void InstallFromInfoCommand::Abort(webapps::InstallResultCode code) {
debug_value_.Set("result_code", base::ToString(code));
if (!install_callback_)
return;
webapps::InstallableMetrics::TrackInstallResult(false);
SignalCompletionAndSelfDestruct(
CommandResult::kFailure,
base::BindOnce(std::move(install_callback_), app_id_, code,
/*did_uninstall_and_replace=*/false));
}
void InstallFromInfoCommand::OnInstallCompleted(const AppId& app_id,
webapps::InstallResultCode code,
OsHooksErrors os_hooks_errors) {
webapps::InstallableMetrics::TrackInstallResult(webapps::IsSuccess(code));
debug_value_.Set("result_code", base::ToString(code));
if (!webapps::IsSuccess(code)) {
OnUnintallAndReplaceFinished(app_id, code,
/*did_uninstall_and_replace=*/false);
return;
}
uninstall_and_replace_job_.emplace(
profile_, lock_->AsWeakPtr(), apps_or_extensions_to_uninstall_, app_id,
base::BindOnce(&InstallFromInfoCommand::OnUnintallAndReplaceFinished,
weak_factory_.GetWeakPtr(), app_id, std::move(code)));
uninstall_and_replace_job_->Start();
}
void InstallFromInfoCommand::OnUnintallAndReplaceFinished(
const AppId& app_id,
webapps::InstallResultCode code,
bool did_uninstall_and_replace) {
debug_value_.Set("did_uninstall_and_replace", did_uninstall_and_replace);
SignalCompletionAndSelfDestruct(
webapps::IsSuccess(code) ? CommandResult::kSuccess
: CommandResult::kFailure,
base::BindOnce(std::move(install_callback_), app_id, code,
did_uninstall_and_replace));
}
void InstallFromInfoCommand::OnShutdown() {
Abort(webapps::InstallResultCode::kCancelledOnWebAppProviderShuttingDown);
return;
}
base::Value InstallFromInfoCommand::ToDebugValue() const {
return base::Value(debug_value_.Clone());
}
} // namespace web_app