blob: 4429abaeb7819c7f7e8d1742bc99c2730bdde722 [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_app_locally_command.h"
#include <memory>
#include <utility>
#include "base/containers/flat_set.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/time/time.h"
#include "base/values.h"
#include "chrome/browser/web_applications/commands/web_app_command.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_constants.h"
#include "chrome/browser/web_applications/web_app_id.h"
#include "chrome/browser/web_applications/web_app_install_manager.h"
#include "chrome/browser/web_applications/web_app_registrar.h"
#include "chrome/browser/web_applications/web_app_registry_update.h"
#include "chrome/browser/web_applications/web_app_sync_bridge.h"
namespace web_app {
InstallAppLocallyCommand::InstallAppLocallyCommand(
const AppId& app_id,
base::OnceClosure install_callback)
: WebAppCommandTemplate<AppLock>("InstallAppLocallyCommand"),
app_lock_description_(std::make_unique<AppLockDescription>(app_id)),
app_id_(app_id),
install_callback_(std::move(install_callback)) {
debug_log_.Set("app_id", app_id_);
}
InstallAppLocallyCommand::~InstallAppLocallyCommand() = default;
const LockDescription& InstallAppLocallyCommand::lock_description() const {
return *app_lock_description_;
}
void InstallAppLocallyCommand::StartWithLock(
std::unique_ptr<AppLock> app_lock) {
app_lock_ = std::move(app_lock);
if (!app_lock_->registrar().IsInstalled(app_id_)) {
debug_log_.Set("command_result", "app_not_in_registry");
ReportResultAndShutdown(CommandResult::kSuccess);
return;
}
// Setting app to be locally installed before calling Synchronize() helps
// trigger the OS integration.
if (!app_lock_->registrar().IsLocallyInstalled(app_id_)) {
ScopedRegistryUpdate update = app_lock_->sync_bridge().BeginUpdate();
WebApp* web_app_to_update = update->UpdateApp(app_id_);
if (web_app_to_update) {
web_app_to_update->SetIsLocallyInstalled(/*is_locally_installed=*/true);
}
}
// Install OS hooks first.
InstallOsHooksOptions options;
options.add_to_desktop = true;
options.add_to_quick_launch_bar = false;
options.os_hooks[OsHookType::kShortcuts] = true;
options.os_hooks[OsHookType::kShortcutsMenu] = true;
options.os_hooks[OsHookType::kFileHandlers] = true;
options.os_hooks[OsHookType::kProtocolHandlers] = true;
options.os_hooks[OsHookType::kRunOnOsLogin] =
(app_lock_->registrar().GetAppRunOnOsLoginMode(app_id_).value ==
RunOnOsLoginMode::kWindowed);
// Installed WebApp here is user uninstallable app, but it needs to
// check user uninstall-ability if there are apps with different source types.
// WebApp::CanUserUninstallApp will handles it.
const web_app::WebApp* web_app = app_lock_->registrar().GetAppById(app_id_);
options.os_hooks[OsHookType::kUninstallationViaOsSettings] =
web_app->CanUserUninstallWebApp();
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || \
(BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS))
options.os_hooks[web_app::OsHookType::kUrlHandlers] = true;
#else
options.os_hooks[web_app::OsHookType::kUrlHandlers] = false;
#endif
auto os_hooks_barrier = OsIntegrationManager::GetBarrierForSynchronize(
base::BindOnce(&InstallAppLocallyCommand::OnOsHooksInstalled,
weak_factory_.GetWeakPtr()));
app_lock_->os_integration_manager().InstallOsHooks(
app_id_, os_hooks_barrier, /*web_app_info=*/nullptr, options);
SynchronizeOsOptions synchronize_options;
synchronize_options.add_shortcut_to_desktop = options.add_to_desktop;
synchronize_options.add_to_quick_launch_bar = options.add_to_quick_launch_bar;
synchronize_options.reason = options.reason;
app_lock_->os_integration_manager().Synchronize(
app_id_, base::BindOnce(os_hooks_barrier, OsHooksErrors()),
synchronize_options);
}
void InstallAppLocallyCommand::OnOsHooksInstalled(
const OsHooksErrors os_hooks_errors) {
const base::Time& install_time = base::Time::Now();
{
// Updating install time on app.
ScopedRegistryUpdate update = app_lock_->sync_bridge().BeginUpdate();
WebApp* web_app_to_update = update->UpdateApp(app_id_);
if (web_app_to_update) {
web_app_to_update->SetInstallTime(install_time);
}
}
app_lock_->install_manager().NotifyWebAppInstalledWithOsHooks(app_id_);
app_lock_->registrar().NotifyWebAppInstallTimeChanged(app_id_, install_time);
debug_log_.Set("command_result", "success");
ReportResultAndShutdown(CommandResult::kSuccess);
}
void InstallAppLocallyCommand::OnShutdown() {
ReportResultAndShutdown(CommandResult::kShutdown);
}
base::Value InstallAppLocallyCommand::ToDebugValue() const {
base::Value::Dict value = debug_log_.Clone();
return base::Value(std::move(value));
}
void InstallAppLocallyCommand::ReportResultAndShutdown(CommandResult result) {
DCHECK(!install_callback_.is_null());
SignalCompletionAndSelfDestruct(result, std::move(install_callback_));
}
} // namespace web_app