blob: 9b127af5ed58ced8d152f596652ed7931d881f31 [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.h"
#include <ostream>
#include <tuple>
#include <utility>
#include "base/check_op.h"
#include "base/notreached.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "chrome/browser/web_applications/components/web_app_chromeos_data.h"
#include "chrome/browser/web_applications/components/web_app_constants.h"
#include "chrome/browser/web_applications/components/web_app_utils.h"
#include "components/sync/base/time.h"
#include "third_party/blink/public/common/manifest/manifest_util.h"
#include "ui/gfx/color_utils.h"
namespace {
std::string ColorToString(base::Optional<SkColor> color) {
return color.has_value() ? color_utils::SkColorToRgbaString(color.value())
: "none";
}
} // namespace
namespace web_app {
WebApp::WebApp(const AppId& app_id)
: app_id_(app_id),
display_mode_(DisplayMode::kUndefined),
user_display_mode_(DisplayMode::kUndefined),
chromeos_data_(IsChromeOs() ? base::make_optional<WebAppChromeOsData>()
: base::nullopt) {}
WebApp::~WebApp() = default;
WebApp::WebApp(const WebApp& web_app) = default;
WebApp& WebApp::operator=(WebApp&& web_app) = default;
const SortedSizesPx& WebApp::downloaded_icon_sizes(IconPurpose purpose) const {
switch (purpose) {
case IconPurpose::ANY:
return downloaded_icon_sizes_any_;
case IconPurpose::MONOCHROME:
// TODO (crbug.com/1114638): Download monochrome icons.
NOTREACHED();
return downloaded_icon_sizes_monochrome_;
case IconPurpose::MASKABLE:
return downloaded_icon_sizes_maskable_;
}
}
void WebApp::AddSource(Source::Type source) {
sources_[source] = true;
}
void WebApp::RemoveSource(Source::Type source) {
sources_[source] = false;
}
bool WebApp::HasAnySources() const {
return sources_.any();
}
bool WebApp::HasOnlySource(Source::Type source) const {
Sources specified_sources;
specified_sources[source] = true;
return HasAnySpecifiedSourcesAndNoOtherSources(specified_sources);
}
bool WebApp::IsSynced() const {
return sources_[Source::kSync];
}
bool WebApp::IsPreinstalledApp() const {
return sources_[Source::kDefault];
}
bool WebApp::IsPolicyInstalledApp() const {
return sources_[Source::kPolicy];
}
bool WebApp::IsSystemApp() const {
return sources_[Source::kSystem];
}
bool WebApp::CanUserUninstallWebApp() const {
Sources specified_sources;
specified_sources[Source::kDefault] = true;
specified_sources[Source::kSync] = true;
specified_sources[Source::kWebAppStore] = true;
return HasAnySpecifiedSourcesAndNoOtherSources(specified_sources);
}
bool WebApp::HasAnySpecifiedSourcesAndNoOtherSources(
Sources specified_sources) const {
bool has_any_specified_sources = (sources_ & specified_sources).any();
bool has_no_other_sources = (sources_ & ~specified_sources).none();
return has_any_specified_sources && has_no_other_sources;
}
bool WebApp::WasInstalledByUser() const {
return sources_[Source::kSync] || sources_[Source::kWebAppStore];
}
Source::Type WebApp::GetHighestPrioritySource() const {
// Enumerators in Source enum are declaretd in the order of priority.
// Top priority sources are declared first.
for (int i = Source::kMinValue; i <= Source::kMaxValue; ++i) {
auto source = static_cast<Source::Type>(i);
if (sources_[source])
return source;
}
NOTREACHED();
return Source::kMaxValue;
}
void WebApp::SetName(const std::string& name) {
name_ = name;
}
void WebApp::SetDescription(const std::string& description) {
description_ = description;
}
void WebApp::SetStartUrl(const GURL& start_url) {
DCHECK(start_url.is_valid());
start_url_ = start_url;
}
void WebApp::SetScope(const GURL& scope) {
DCHECK(scope.is_empty() || scope.is_valid());
scope_ = scope;
}
void WebApp::SetNoteTakingNewNoteUrl(const GURL& note_taking_new_note_url) {
DCHECK(note_taking_new_note_url.is_empty() ||
note_taking_new_note_url.is_valid());
note_taking_new_note_url_ = note_taking_new_note_url;
}
void WebApp::SetThemeColor(base::Optional<SkColor> theme_color) {
theme_color_ = theme_color;
}
void WebApp::SetBackgroundColor(base::Optional<SkColor> background_color) {
background_color_ = background_color;
}
void WebApp::SetDisplayMode(DisplayMode display_mode) {
DCHECK_NE(DisplayMode::kUndefined, display_mode);
display_mode_ = display_mode;
}
void WebApp::SetUserDisplayMode(DisplayMode user_display_mode) {
switch (user_display_mode) {
case DisplayMode::kBrowser:
user_display_mode_ = DisplayMode::kBrowser;
break;
case DisplayMode::kUndefined:
case DisplayMode::kMinimalUi:
case DisplayMode::kFullscreen:
case DisplayMode::kWindowControlsOverlay:
NOTREACHED();
FALLTHROUGH;
case DisplayMode::kStandalone:
user_display_mode_ = DisplayMode::kStandalone;
break;
}
}
void WebApp::SetDisplayModeOverride(
std::vector<DisplayMode> display_mode_override) {
display_mode_override_ = std::move(display_mode_override);
}
void WebApp::SetUserPageOrdinal(syncer::StringOrdinal page_ordinal) {
user_page_ordinal_ = std::move(page_ordinal);
}
void WebApp::SetUserLaunchOrdinal(syncer::StringOrdinal launch_ordinal) {
user_launch_ordinal_ = std::move(launch_ordinal);
}
void WebApp::SetWebAppChromeOsData(
base::Optional<WebAppChromeOsData> chromeos_data) {
chromeos_data_ = std::move(chromeos_data);
}
void WebApp::SetIsLocallyInstalled(bool is_locally_installed) {
is_locally_installed_ = is_locally_installed;
}
void WebApp::SetIsInSyncInstall(bool is_in_sync_install) {
is_in_sync_install_ = is_in_sync_install;
}
void WebApp::SetIsUninstalling(bool is_uninstalling) {
is_uninstalling_ = is_uninstalling;
}
void WebApp::SetIconInfos(std::vector<WebApplicationIconInfo> icon_infos) {
icon_infos_ = std::move(icon_infos);
}
void WebApp::SetDownloadedIconSizes(IconPurpose purpose, SortedSizesPx sizes) {
switch (purpose) {
case IconPurpose::ANY:
downloaded_icon_sizes_any_ = std::move(sizes);
break;
case IconPurpose::MONOCHROME:
// TODO (crbug.com/1114638): Add monochrome icons support.
NOTREACHED();
break;
case IconPurpose::MASKABLE:
downloaded_icon_sizes_maskable_ = std::move(sizes);
break;
}
}
void WebApp::SetIsGeneratedIcon(bool is_generated_icon) {
is_generated_icon_ = is_generated_icon;
}
void WebApp::SetFileHandlers(apps::FileHandlers file_handlers) {
file_handlers_ = std::move(file_handlers);
}
void WebApp::SetShareTarget(base::Optional<apps::ShareTarget> share_target) {
share_target_ = std::move(share_target);
}
void WebApp::SetAdditionalSearchTerms(
std::vector<std::string> additional_search_terms) {
additional_search_terms_ = std::move(additional_search_terms);
}
void WebApp::SetProtocolHandlers(
std::vector<apps::ProtocolHandlerInfo> handlers) {
protocol_handlers_ = std::move(handlers);
}
void WebApp::SetUrlHandlers(apps::UrlHandlers url_handlers) {
url_handlers_ = std::move(url_handlers);
}
void WebApp::SetShortcutsMenuItemInfos(
std::vector<WebApplicationShortcutsMenuItemInfo>
shortcuts_menu_item_infos) {
shortcuts_menu_item_infos_ = std::move(shortcuts_menu_item_infos);
}
void WebApp::SetDownloadedShortcutsMenuIconsSizes(
std::vector<IconSizes> sizes) {
downloaded_shortcuts_menu_icons_sizes_ = std::move(sizes);
}
void WebApp::SetLastBadgingTime(const base::Time& time) {
last_badging_time_ = time;
}
void WebApp::SetLastLaunchTime(const base::Time& time) {
last_launch_time_ = time;
}
void WebApp::SetInstallTime(const base::Time& time) {
install_time_ = time;
}
void WebApp::SetRunOnOsLoginMode(RunOnOsLoginMode mode) {
run_on_os_login_mode_ = mode;
}
void WebApp::SetSyncFallbackData(SyncFallbackData sync_fallback_data) {
sync_fallback_data_ = std::move(sync_fallback_data);
}
void WebApp::SetCaptureLinks(blink::mojom::CaptureLinks capture_links) {
capture_links_ = capture_links;
}
void WebApp::SetLaunchQueryParams(
base::Optional<std::string> launch_query_params) {
launch_query_params_ = std::move(launch_query_params);
}
void WebApp::SetManifestUrl(const GURL& manifest_url) {
manifest_url_ = manifest_url;
}
void WebApp::SetManifestId(const base::Optional<std::string>& manifest_id) {
manifest_id_ = manifest_id;
}
void WebApp::SetFileHandlerPermissionBlocked(bool permission_blocked) {
file_handler_permission_blocked_ = permission_blocked;
}
WebApp::ClientData::ClientData() = default;
WebApp::ClientData::~ClientData() = default;
WebApp::ClientData::ClientData(const ClientData& client_data) = default;
WebApp::SyncFallbackData::SyncFallbackData() = default;
WebApp::SyncFallbackData::~SyncFallbackData() = default;
WebApp::SyncFallbackData::SyncFallbackData(
const SyncFallbackData& sync_fallback_data) = default;
WebApp::SyncFallbackData& WebApp::SyncFallbackData::operator=(
SyncFallbackData&& sync_fallback_data) = default;
template <typename T>
std::ostream& operator<<(std::ostream& out, const base::Optional<T>& optional) {
if (optional.has_value())
return out << optional.value();
return out << "nullopt";
}
template <typename T>
std::string Indent(const T& value) {
std::stringstream ss;
ss << value;
std::vector<std::string> lines = base::SplitString(
ss.str(), "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
for (std::string& line : lines)
line = " " + line;
return base::JoinString(lines, "\n");
}
std::ostream& operator<<(std::ostream& out,
const WebApp::SyncFallbackData& sync_fallback_data) {
out << "name: " << sync_fallback_data.name << std::endl;
out << "theme_color: " << ColorToString(sync_fallback_data.theme_color)
<< std::endl;
out << "scope: " << sync_fallback_data.scope << std::endl;
out << "icon_infos:" << std::endl;
for (const WebApplicationIconInfo& icon : sync_fallback_data.icon_infos)
out << Indent(icon) << std::endl;
return out;
}
std::ostream& operator<<(std::ostream& out, const WebApp& app) {
out << "app_id: " << app.app_id_ << std::endl;
out << "manifest_url: " << app.manifest_url_ << std::endl;
out << "manifest_id: " << app.manifest_id_ << std::endl;
out << "name: " << app.name_ << std::endl;
out << "start_url: " << app.start_url_ << std::endl;
out << "launch_query_params: " << app.launch_query_params_ << std::endl;
out << "scope: " << app.scope_ << std::endl;
out << "theme_color: " << ColorToString(app.theme_color_) << std::endl;
out << "background_color: " << ColorToString(app.background_color_)
<< std::endl;
out << "display_mode: " << blink::DisplayModeToString(app.display_mode_)
<< std::endl;
out << "display_override:";
for (const DisplayMode& mode : app.display_mode_override_)
out << " " << blink::DisplayModeToString(mode);
out << std::endl;
out << "user_display_mode: "
<< blink::DisplayModeToString(app.user_display_mode_) << std::endl;
out << "user_page_ordinal: " << app.user_page_ordinal_.ToDebugString()
<< std::endl;
out << "user_launch_ordinal: " << app.user_launch_ordinal_.ToDebugString()
<< std::endl;
out << "sources:";
for (int i = Source::Type::kMinValue; i <= Source::Type::kMaxValue; ++i) {
if (app.sources_[i])
out << " " << static_cast<Source::Type>(i);
}
out << std::endl;
out << "is_locally_installed: " << app.is_locally_installed_ << std::endl;
out << "is_in_sync_install: " << app.is_in_sync_install_ << std::endl;
out << "sync_fallback_data:" << std::endl
<< Indent(app.sync_fallback_data_) << std::endl;
out << "description: " << app.description_ << std::endl;
out << "last_badging_time: " << app.last_badging_time_ << std::endl;
out << "last_launch_time: " << app.last_launch_time_ << std::endl;
out << "install_time: " << app.install_time_ << std::endl;
out << "is_generated_icon: " << app.is_generated_icon_ << std::endl;
out << "run_on_os_login_mode: "
<< RunOnOsLoginModeToString(app.run_on_os_login_mode_) << std::endl;
out << "icon_infos:" << std::endl;
for (const WebApplicationIconInfo& icon : app.icon_infos_)
out << Indent(icon) << std::endl;
out << "downloaded_icon_sizes_any:";
for (SquareSizePx size : app.downloaded_icon_sizes_any_)
out << " " << size;
out << std::endl;
out << "downloaded_icon_sizes_monochrome:";
for (SquareSizePx size : app.downloaded_icon_sizes_monochrome_)
out << " " << size;
out << std::endl;
out << "downloaded_icon_sizes_maskable:";
for (SquareSizePx size : app.downloaded_icon_sizes_maskable_)
out << " " << size;
out << std::endl;
out << "shortcuts_menu_item_infos:" << std::endl;
for (const WebApplicationShortcutsMenuItemInfo& info :
app.shortcuts_menu_item_infos_) {
out << Indent(info) << std::endl;
}
out << "downloaded_shortcuts_menu_icons_sizes:" << std::endl;
for (size_t i = 0; i < app.downloaded_shortcuts_menu_icons_sizes_.size();
++i) {
out << " index: " << i << ":" << std::endl;
const IconSizes& icon_sizes = app.downloaded_shortcuts_menu_icons_sizes_[i];
out << " any:";
for (SquareSizePx size : icon_sizes.any)
out << " " << size;
out << std::endl;
out << " maskable:";
for (SquareSizePx size : icon_sizes.maskable)
out << " " << size;
out << std::endl;
}
out << "file_handlers:" << std::endl;
for (const apps::FileHandler& file_handler : app.file_handlers_)
out << Indent(file_handler) << std::endl;
out << "file_handler_permission_blocked:"
<< app.file_handler_permission_blocked_ << std::endl;
out << "share_target:" << std::endl << Indent(app.share_target_) << std::endl;
out << "additional_search_terms:" << std::endl;
for (const std::string& additional_search_term : app.additional_search_terms_)
out << " " << additional_search_term << std::endl;
out << "protocol_handlers:" << std::endl;
for (const apps::ProtocolHandlerInfo& protocol_handler :
app.protocol_handlers_) {
out << " " << protocol_handler << std::endl;
}
out << "note_taking_new_note_url: " << app.note_taking_new_note_url_
<< std::endl;
out << "url_handlers:" << std::endl;
for (const apps::UrlHandlerInfo& url_handler : app.url_handlers_)
out << Indent(url_handler) << std::endl;
out << "capture_links: " << app.capture_links_ << std::endl;
out << "chromeos_data:" << std::endl
<< Indent(app.chromeos_data_) << std::endl;
out << "system_web_app:" << std::endl
<< Indent(app.client_data_.system_web_app_data) << std::endl;
return out;
}
bool operator==(const WebApp::SyncFallbackData& sync_fallback_data1,
const WebApp::SyncFallbackData& sync_fallback_data2) {
return std::tie(sync_fallback_data1.name, sync_fallback_data1.theme_color,
sync_fallback_data1.scope, sync_fallback_data1.icon_infos) ==
std::tie(sync_fallback_data2.name, sync_fallback_data2.theme_color,
sync_fallback_data2.scope, sync_fallback_data2.icon_infos);
}
bool operator!=(const WebApp::SyncFallbackData& sync_fallback_data1,
const WebApp::SyncFallbackData& sync_fallback_data2) {
return !(sync_fallback_data1 == sync_fallback_data2);
}
bool WebApp::operator==(const WebApp& other) const {
auto AsTuple = [](const WebApp& app) {
// Keep in order declared in web_app.h.
return std::tie(
// Disable clang-format so diffs are clearer when fields are added.
// clang-format off
app.app_id_,
app.sources_,
app.name_,
app.description_,
app.start_url_,
app.launch_query_params_,
app.scope_,
app.theme_color_,
app.background_color_,
app.display_mode_,
app.user_display_mode_,
app.display_mode_override_,
app.user_page_ordinal_,
app.user_launch_ordinal_,
app.chromeos_data_,
app.is_locally_installed_,
app.is_in_sync_install_,
app.icon_infos_,
app.downloaded_icon_sizes_any_,
app.downloaded_icon_sizes_monochrome_,
app.downloaded_icon_sizes_maskable_,
app.is_generated_icon_,
app.shortcuts_menu_item_infos_,
app.downloaded_shortcuts_menu_icons_sizes_,
app.file_handlers_,
app.share_target_,
app.additional_search_terms_,
app.protocol_handlers_,
app.note_taking_new_note_url_,
app.last_badging_time_,
app.last_launch_time_,
app.install_time_,
app.run_on_os_login_mode_,
app.sync_fallback_data_,
app.url_handlers_,
app.capture_links_,
app.manifest_url_,
app.manifest_id_,
app.client_data_.system_web_app_data,
app.file_handler_permission_blocked_
// clang-format on
);
};
return AsTuple(*this) == AsTuple(other);
}
bool WebApp::operator!=(const WebApp& other) const {
return !(*this == other);
}
} // namespace web_app