blob: 9de5812869a8b9640ee7809008d90debdfe9261a [file] [log] [blame]
// Copyright 2023 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/generated_icon_fix_command.h"
#include <memory>
#include <string>
#include "base/check.h"
#include "base/functional/bind.h"
#include "base/functional/callback_forward.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/web_applications/generated_icon_fix_util.h"
#include "chrome/browser/web_applications/locks/shared_web_contents_with_app_lock.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/browser/web_applications/web_app_command_manager.h"
#include "chrome/browser/web_applications/web_app_icon_generator.h"
#include "chrome/browser/web_applications/web_app_install_info.h"
#include "chrome/browser/web_applications/web_app_install_manager.h"
#include "chrome/browser/web_applications/web_app_install_utils.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"
#include "chrome/browser/web_applications/web_contents/web_app_icon_downloader.h"
#include "chrome/browser/web_applications/web_contents/web_contents_manager.h"
#include "chrome/common/chrome_features.h"
#include "ui/gfx/geometry/size.h"
namespace web_app {
GeneratedIconFixCommand::GeneratedIconFixCommand(
webapps::AppId app_id,
proto::GeneratedIconFixSource source,
base::OnceCallback<void(GeneratedIconFixResult)> callback)
: WebAppCommand<SharedWebContentsWithAppLock, GeneratedIconFixResult>(
"GeneratedIconFixCommand",
SharedWebContentsWithAppLockDescription({app_id}),
std::move(callback),
GeneratedIconFixResult::kShutdown),
app_id_(std::move(app_id)),
source_(source) {
GetMutableDebugValue().Set("app_id", app_id_);
GetMutableDebugValue().Set("source", base::ToString(source_));
GetMutableDebugValue().Set("stop_location", stop_location_.ToString());
}
GeneratedIconFixCommand::~GeneratedIconFixCommand() = default;
void GeneratedIconFixCommand::StartWithLock(
std::unique_ptr<SharedWebContentsWithAppLock> lock) {
lock_ = std::move(lock);
const WebApp* app = lock_->registrar().GetAppById(app_id_);
if (!app) {
Stop(GeneratedIconFixResult::kAppUninstalled, FROM_HERE);
return;
}
// DCHECK instead of CHECK to avoid crashing at start up.
DCHECK(generated_icon_fix_util::HasRemainingAttempts(*app));
{
ScopedRegistryUpdate update = lock_->sync_bridge().BeginUpdate();
generated_icon_fix_util::RecordFixAttempt(*lock_, update, app_id_, source_);
}
// Refresh WebApp pointer as the above mutation destroys the previous one.
app = lock_->registrar().GetAppById(app_id_);
install_info_ =
std::make_unique<WebAppInstallInfo>(app->manifest_id(), app->start_url());
icon_downloader_ = lock_->web_contents_manager().CreateIconDownloader();
IconUrlSizeSet icon_urls;
install_info_->manifest_icons = app->manifest_icons();
// Set title and start_url for PopulateProductIcons() in case it tries to
// generate icons again.
install_info_->title = base::UTF8ToUTF16(app->untranslated_name());
// TODO(crbug.com/427566193) : Populate trusted_icons from the app correctly
// if the trusted icons are empty.
install_info_->trusted_icons = app->trusted_icons();
for (const apps::IconInfo& icon_info : install_info_->manifest_icons) {
icon_urls.emplace(IconUrlWithSize::CreateForUnspecifiedSize(icon_info.url));
}
icon_downloader_->Start(
&lock_->shared_web_contents(), icon_urls,
base::BindOnce(&GeneratedIconFixCommand::OnIconsDownloaded,
weak_factory_.GetWeakPtr()));
}
void GeneratedIconFixCommand::OnIconsDownloaded(
IconsDownloadedResult result,
IconsMap icons_map,
DownloadedIconsHttpResults icons_http_results) {
if (result != IconsDownloadedResult::kCompleted) {
Stop(GeneratedIconFixResult::kDownloadFailure, FROM_HERE);
return;
}
PopulateProductIcons(install_info_.get(), &icons_map);
if (install_info_->is_generated_icon) {
Stop(GeneratedIconFixResult::kStillGenerated, FROM_HERE);
return;
}
// Note: Empty params are noops, WriteData() never deletes icons.
lock_->icon_manager().WriteData(
app_id_, install_info_->icon_bitmaps, install_info_->trusted_icon_bitmaps,
/*shortcuts_menu_icons=*/{},
/*other_icons_map=*/{},
base::BindOnce(&GeneratedIconFixCommand::OnIconsWritten,
weak_factory_.GetWeakPtr()));
}
void GeneratedIconFixCommand::OnIconsWritten(bool success) {
if (!success) {
Stop(GeneratedIconFixResult::kWriteFailure, FROM_HERE);
return;
}
{
ScopedRegistryUpdate update = lock_->sync_bridge().BeginUpdate();
SetWebAppProductIconFields(*install_info_, *update->UpdateApp(app_id_));
}
lock_->install_manager().NotifyWebAppManifestUpdated(app_id_);
Stop(GeneratedIconFixResult::kSuccess, FROM_HERE);
}
void GeneratedIconFixCommand::Stop(GeneratedIconFixResult result,
base::Location location) {
CHECK(result != GeneratedIconFixResult::kShutdown);
stop_location_ = std::move(location);
// TODO(crbug.com/40185008): Record the attempt and call
// GeneratedIconFixManager::MaybeScheduleNextFix() if !success.
CompleteAndSelfDestruct(
[&] {
switch (result) {
case GeneratedIconFixResult::kDownloadFailure:
case GeneratedIconFixResult::kStillGenerated:
case GeneratedIconFixResult::kWriteFailure:
return CommandResult::kFailure;
case GeneratedIconFixResult::kAppUninstalled:
case GeneratedIconFixResult::kShutdown:
case GeneratedIconFixResult::kSuccess:
return CommandResult::kSuccess;
}
}(),
result);
}
} // namespace web_app