Commit 8c864f18 authored by Alexey Baskakov's avatar Alexey Baskakov Committed by Commit Bot

WebApp: Add local name, theme_color and is_sync_placeholder fields.

According to go/chrome-bmo design doc sync data model,
we should have two copies of app's name and theme_color fields.

Rename specifics to sync_data.
Rename proto to local_data.

Add is_sync_placeholder flag.

Add comments.

All these fields will be used in WebAppSyncBridge implementation:
https://chromium-review.googlesource.com/c/chromium/src/+/1830494

Bug: 860583
Change-Id: Idce95b5fdd4843cf9a8e290fe61293bffb938bc5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1833347
Commit-Queue: Alexey Baskakov <loyso@chromium.org>
Reviewed-by: default avatarMarc Treib <treib@chromium.org>
Reviewed-by: default avatarAlan Cutter <alancutter@chromium.org>
Cr-Commit-Position: refs/heads/master@{#702713}
parent de9c4bee
...@@ -28,19 +28,27 @@ message SourcesProto { ...@@ -28,19 +28,27 @@ message SourcesProto {
required bool default = 5; required bool default = 5;
} }
// Full WebApp object data. Note on database identities: // Full WebApp object data. See detailed comments in
// chrome/browser/web_applications/web_app.h. Note on database identities:
// app_id is a hash of launch_url. app_id is the client tag for sync system. // app_id is a hash of launch_url. app_id is the client tag for sync system.
// app_id is the storage key in ModelTypeStore. // app_id is the storage key in ModelTypeStore.
message WebAppProto { message WebAppProto {
// Synced data. // Synced data. It is replicated across all devices with WEB_APPS.
required sync_pb.WebAppSpecifics specifics = 1; //
// |sync_data.name| and |sync_data.theme_color| are read by a device to
// generate a placeholder icon. Any device may write new values to synced
// |name| and |theme_color|. A random last update wins.
required sync_pb.WebAppSpecifics sync_data = 1;
// Local data. Not to be synced. // Local data. May vary across devices. Not to be synced.
// //
optional string description = 2; required string name = 2;
optional string scope = 3; optional uint32 theme_color = 3;
required SourcesProto sources = 4; optional string description = 4;
required bool is_locally_installed = 5; optional string scope = 5;
required SourcesProto sources = 6;
required bool is_locally_installed = 7;
optional bool is_sync_placeholder = 8;
// A list of icon infos. // A list of icon infos.
repeated WebAppIconInfoProto icons = 6; repeated WebAppIconInfoProto icons = 9;
} }
...@@ -65,18 +65,35 @@ void WebApp::SetIsLocallyInstalled(bool is_locally_installed) { ...@@ -65,18 +65,35 @@ void WebApp::SetIsLocallyInstalled(bool is_locally_installed) {
is_locally_installed_ = is_locally_installed; is_locally_installed_ = is_locally_installed;
} }
void WebApp::SetIsSyncPlaceholder(bool is_sync_placeholder) {
is_sync_placeholder_ = is_sync_placeholder;
}
void WebApp::SetIcons(Icons icons) { void WebApp::SetIcons(Icons icons) {
icons_ = std::move(icons); icons_ = std::move(icons);
} }
void WebApp::SetSyncData(const SyncData& sync_data) {
sync_data_ = sync_data;
}
WebApp::SyncData::SyncData() = default;
WebApp::SyncData::~SyncData() = default;
std::ostream& operator<<(std::ostream& out, const WebApp& app) { std::ostream& operator<<(std::ostream& out, const WebApp& app) {
const std::string theme_color = const std::string theme_color =
app.theme_color() app.theme_color_.has_value()
? color_utils::SkColorToRgbaString(app.theme_color().value()) ? color_utils::SkColorToRgbaString(app.theme_color_.value())
: "none";
const std::string sync_theme_color =
app.sync_data_.theme_color.has_value()
? color_utils::SkColorToRgbaString(app.sync_data_.theme_color.value())
: "none"; : "none";
const char* launch_container = const char* launch_container =
LaunchContainerEnumToStr(app.launch_container()); LaunchContainerEnumToStr(app.launch_container_);
const bool is_locally_installed = app.is_locally_installed(); const bool is_locally_installed = app.is_locally_installed_;
const bool is_sync_placeholder = app.is_sync_placeholder_;
return out << "app_id: " << app.app_id_ << std::endl return out << "app_id: " << app.app_id_ << std::endl
<< " name: " << app.name_ << std::endl << " name: " << app.name_ << std::endl
...@@ -84,8 +101,11 @@ std::ostream& operator<<(std::ostream& out, const WebApp& app) { ...@@ -84,8 +101,11 @@ std::ostream& operator<<(std::ostream& out, const WebApp& app) {
<< " scope: " << app.scope_ << std::endl << " scope: " << app.scope_ << std::endl
<< " theme_color: " << theme_color << std::endl << " theme_color: " << theme_color << std::endl
<< " launch_container: " << launch_container << std::endl << " launch_container: " << launch_container << std::endl
<< " sources: " << app.sources_ << std::endl << " sources: " << app.sources_.to_string() << std::endl
<< " is_locally_installed: " << is_locally_installed << std::endl << " is_locally_installed: " << is_locally_installed << std::endl
<< " is_sync_placeholder: " << is_sync_placeholder << std::endl
<< " sync_data.name: " << app.sync_data_.name << std::endl
<< " sync_data.theme_color: " << sync_theme_color << std::endl
<< " description: " << app.description_; << " description: " << app.description_;
} }
...@@ -95,15 +115,23 @@ bool operator==(const WebApp::IconInfo& icon_info1, ...@@ -95,15 +115,23 @@ bool operator==(const WebApp::IconInfo& icon_info1,
std::tie(icon_info2.url, icon_info2.size_in_px); std::tie(icon_info2.url, icon_info2.size_in_px);
} }
bool operator==(const WebApp::SyncData& sync_data1,
const WebApp::SyncData& sync_data2) {
return std::tie(sync_data1.name, sync_data1.theme_color) ==
std::tie(sync_data2.name, sync_data2.theme_color);
}
bool operator==(const WebApp& app1, const WebApp& app2) { bool operator==(const WebApp& app1, const WebApp& app2) {
return std::tie(app1.app_id_, app1.sources_, app1.name_, app1.launch_url_, return std::tie(app1.app_id_, app1.sources_, app1.name_, app1.launch_url_,
app1.description_, app1.scope_, app1.theme_color_, app1.description_, app1.scope_, app1.theme_color_,
app1.icons_, app1.launch_container_, app1.icons_, app1.launch_container_,
app1.is_locally_installed_) == app1.is_locally_installed_, app1.is_sync_placeholder_,
app1.sync_data_) ==
std::tie(app2.app_id_, app2.sources_, app2.name_, app2.launch_url_, std::tie(app2.app_id_, app2.sources_, app2.name_, app2.launch_url_,
app2.description_, app2.scope_, app2.theme_color_, app2.description_, app2.scope_, app2.theme_color_,
app2.icons_, app2.launch_container_, app2.icons_, app2.launch_container_,
app2.is_locally_installed_); app2.is_locally_installed_, app2.is_sync_placeholder_,
app2.sync_data_);
} }
bool operator!=(const WebApp& app1, const WebApp& app2) { bool operator!=(const WebApp& app1, const WebApp& app2) {
......
...@@ -35,6 +35,12 @@ class WebApp { ...@@ -35,6 +35,12 @@ class WebApp {
const base::Optional<SkColor>& theme_color() const { return theme_color_; } const base::Optional<SkColor>& theme_color() const { return theme_color_; }
LaunchContainer launch_container() const { return launch_container_; } LaunchContainer launch_container() const { return launch_container_; }
bool is_locally_installed() const { return is_locally_installed_; } bool is_locally_installed() const { return is_locally_installed_; }
// Sync-initiated installation produces a sync placeholder app awaiting for
// full installation process. The sync placeholder app has only app_id,
// launch_url and sync_data fields defined, no icons. If online install
// succeeds, icons get downloaded and all the fields get their values. If
// install fails, icons get generated using |sync_data| fields.
bool is_sync_placeholder() const { return is_sync_placeholder_; }
struct IconInfo { struct IconInfo {
GURL url; GURL url;
...@@ -43,7 +49,19 @@ class WebApp { ...@@ -43,7 +49,19 @@ class WebApp {
using Icons = std::vector<IconInfo>; using Icons = std::vector<IconInfo>;
const Icons& icons() const { return icons_; } const Icons& icons() const { return icons_; }
// A Web App can be installed from multiple sources simulateneously. Installs // While local |name| and |theme_color| may vary from device to device, the
// synced copies of these fields are replicated to all devices. The synced
// copies are read by a device to generate a placeholder icon (if needed). Any
// device may write new values to |sync_data|, random last update wins.
struct SyncData {
SyncData();
~SyncData();
std::string name;
base::Optional<SkColor> theme_color;
};
const SyncData& sync_data() const { return sync_data_; }
// A Web App can be installed from multiple sources simultaneously. Installs
// add a source to the app. Uninstalls remove a source from the app. // add a source to the app. Uninstalls remove a source from the app.
void AddSource(Source::Type source); void AddSource(Source::Type source);
void RemoveSource(Source::Type source); void RemoveSource(Source::Type source);
...@@ -58,8 +76,11 @@ class WebApp { ...@@ -58,8 +76,11 @@ class WebApp {
void SetThemeColor(base::Optional<SkColor> theme_color); void SetThemeColor(base::Optional<SkColor> theme_color);
void SetLaunchContainer(LaunchContainer launch_container); void SetLaunchContainer(LaunchContainer launch_container);
void SetIsLocallyInstalled(bool is_locally_installed); void SetIsLocallyInstalled(bool is_locally_installed);
void SetIsSyncPlaceholder(bool is_sync_placeholder);
void SetIcons(Icons icons); void SetIcons(Icons icons);
void SetSyncData(const SyncData& sync_data);
private: private:
friend class WebAppDatabase; friend class WebAppDatabase;
friend bool operator==(const WebApp&, const WebApp&); friend bool operator==(const WebApp&, const WebApp&);
...@@ -80,8 +101,11 @@ class WebApp { ...@@ -80,8 +101,11 @@ class WebApp {
base::Optional<SkColor> theme_color_; base::Optional<SkColor> theme_color_;
LaunchContainer launch_container_; LaunchContainer launch_container_;
bool is_locally_installed_ = true; bool is_locally_installed_ = true;
bool is_sync_placeholder_ = false;
Icons icons_; Icons icons_;
SyncData sync_data_;
DISALLOW_COPY_AND_ASSIGN(WebApp); DISALLOW_COPY_AND_ASSIGN(WebApp);
}; };
...@@ -91,6 +115,9 @@ std::ostream& operator<<(std::ostream& out, const WebApp& app); ...@@ -91,6 +115,9 @@ std::ostream& operator<<(std::ostream& out, const WebApp& app);
bool operator==(const WebApp::IconInfo& icon_info1, bool operator==(const WebApp::IconInfo& icon_info1,
const WebApp::IconInfo& icon_info2); const WebApp::IconInfo& icon_info2);
bool operator==(const WebApp::SyncData& sync_data1,
const WebApp::SyncData& sync_data2);
bool operator==(const WebApp& app1, const WebApp& app2); bool operator==(const WebApp& app1, const WebApp& app2);
bool operator!=(const WebApp& app1, const WebApp& app2); bool operator!=(const WebApp& app1, const WebApp& app2);
......
...@@ -86,7 +86,7 @@ void WebAppDatabase::CancelTransaction() { ...@@ -86,7 +86,7 @@ void WebAppDatabase::CancelTransaction() {
// static // static
std::unique_ptr<WebAppProto> WebAppDatabase::CreateWebAppProto( std::unique_ptr<WebAppProto> WebAppDatabase::CreateWebAppProto(
const WebApp& web_app) { const WebApp& web_app) {
auto proto = std::make_unique<WebAppProto>(); auto local_data = std::make_unique<WebAppProto>();
// Required fields: // Required fields:
const GURL launch_url = web_app.launch_url(); const GURL launch_url = web_app.launch_url();
...@@ -95,55 +95,64 @@ std::unique_ptr<WebAppProto> WebAppDatabase::CreateWebAppProto( ...@@ -95,55 +95,64 @@ std::unique_ptr<WebAppProto> WebAppDatabase::CreateWebAppProto(
DCHECK(!web_app.app_id().empty()); DCHECK(!web_app.app_id().empty());
DCHECK_EQ(web_app.app_id(), GenerateAppIdFromURL(launch_url)); DCHECK_EQ(web_app.app_id(), GenerateAppIdFromURL(launch_url));
sync_pb::WebAppSpecifics* specifics = proto->mutable_specifics(); sync_pb::WebAppSpecifics* sync_data = local_data->mutable_sync_data();
specifics->set_launch_url(launch_url.spec()); sync_data->set_launch_url(launch_url.spec());
specifics->set_name(web_app.name()); local_data->set_name(web_app.name());
DCHECK_NE(LaunchContainer::kDefault, web_app.launch_container()); DCHECK_NE(LaunchContainer::kDefault, web_app.launch_container());
specifics->set_launch_container(web_app.launch_container() == sync_data->set_launch_container(web_app.launch_container() ==
LaunchContainer::kWindow LaunchContainer::kWindow
? sync_pb::WebAppSpecifics::WINDOW ? sync_pb::WebAppSpecifics::WINDOW
: sync_pb::WebAppSpecifics::TAB); : sync_pb::WebAppSpecifics::TAB);
DCHECK(web_app.sources_.any()); DCHECK(web_app.sources_.any());
proto->mutable_sources()->set_system(web_app.sources_[Source::kSystem]); local_data->mutable_sources()->set_system(web_app.sources_[Source::kSystem]);
proto->mutable_sources()->set_policy(web_app.sources_[Source::kPolicy]); local_data->mutable_sources()->set_policy(web_app.sources_[Source::kPolicy]);
proto->mutable_sources()->set_web_app_store( local_data->mutable_sources()->set_web_app_store(
web_app.sources_[Source::kWebAppStore]); web_app.sources_[Source::kWebAppStore]);
proto->mutable_sources()->set_sync(web_app.sources_[Source::kSync]); local_data->mutable_sources()->set_sync(web_app.sources_[Source::kSync]);
proto->mutable_sources()->set_default_(web_app.sources_[Source::kDefault]); local_data->mutable_sources()->set_default_(
web_app.sources_[Source::kDefault]);
proto->set_is_locally_installed(web_app.is_locally_installed()); local_data->set_is_locally_installed(web_app.is_locally_installed());
// Optional fields: // Optional fields:
proto->set_description(web_app.description()); local_data->set_description(web_app.description());
if (!web_app.scope().is_empty()) if (!web_app.scope().is_empty())
proto->set_scope(web_app.scope().spec()); local_data->set_scope(web_app.scope().spec());
if (web_app.theme_color().has_value()) if (web_app.theme_color().has_value())
specifics->set_theme_color(web_app.theme_color().value()); local_data->set_theme_color(web_app.theme_color().value());
local_data->set_is_sync_placeholder(web_app.is_sync_placeholder());
// Set sync_data to sync proto.
sync_data->set_name(web_app.sync_data().name);
if (web_app.sync_data().theme_color.has_value())
sync_data->set_theme_color(web_app.sync_data().theme_color.value());
for (const WebApp::IconInfo& icon : web_app.icons()) { for (const WebApp::IconInfo& icon : web_app.icons()) {
WebAppIconInfoProto* icon_proto = proto->add_icons(); WebAppIconInfoProto* icon_proto = local_data->add_icons();
icon_proto->set_url(icon.url.spec()); icon_proto->set_url(icon.url.spec());
icon_proto->set_size_in_px(icon.size_in_px); icon_proto->set_size_in_px(icon.size_in_px);
} }
return proto; return local_data;
} }
// static // static
std::unique_ptr<WebApp> WebAppDatabase::CreateWebApp(const WebAppProto& proto) { std::unique_ptr<WebApp> WebAppDatabase::CreateWebApp(
if (!proto.has_specifics()) { const WebAppProto& local_data) {
DLOG(ERROR) << "WebApp proto parse error: no specifics field"; if (!local_data.has_sync_data()) {
DLOG(ERROR) << "WebApp proto parse error: no sync_data field";
return nullptr; return nullptr;
} }
const sync_pb::WebAppSpecifics& specifics = proto.specifics(); const sync_pb::WebAppSpecifics& sync_data = local_data.sync_data();
// AppId is a hash of launch_url. Read launch_url first: // AppId is a hash of launch_url. Read launch_url first:
GURL launch_url(specifics.launch_url()); GURL launch_url(sync_data.launch_url());
if (launch_url.is_empty() || !launch_url.is_valid()) { if (launch_url.is_empty() || !launch_url.is_valid()) {
DLOG(ERROR) << "WebApp proto launch_url parse error: " DLOG(ERROR) << "WebApp proto launch_url parse error: "
<< launch_url.possibly_invalid_spec(); << launch_url.possibly_invalid_spec();
...@@ -156,50 +165,50 @@ std::unique_ptr<WebApp> WebAppDatabase::CreateWebApp(const WebAppProto& proto) { ...@@ -156,50 +165,50 @@ std::unique_ptr<WebApp> WebAppDatabase::CreateWebApp(const WebAppProto& proto) {
web_app->SetLaunchUrl(launch_url); web_app->SetLaunchUrl(launch_url);
// Required fields: // Required fields:
if (!proto.has_sources()) { if (!local_data.has_sources()) {
DLOG(ERROR) << "WebApp proto parse error: no sources field"; DLOG(ERROR) << "WebApp proto parse error: no sources field";
return nullptr; return nullptr;
} }
WebApp::Sources sources; WebApp::Sources sources;
sources[Source::kSystem] = proto.sources().system(); sources[Source::kSystem] = local_data.sources().system();
sources[Source::kPolicy] = proto.sources().policy(); sources[Source::kPolicy] = local_data.sources().policy();
sources[Source::kWebAppStore] = proto.sources().web_app_store(); sources[Source::kWebAppStore] = local_data.sources().web_app_store();
sources[Source::kSync] = proto.sources().sync(); sources[Source::kSync] = local_data.sources().sync();
sources[Source::kDefault] = proto.sources().default_(); sources[Source::kDefault] = local_data.sources().default_();
if (!sources.any()) { if (!sources.any()) {
DLOG(ERROR) << "WebApp proto parse error: no any source in sources field"; DLOG(ERROR) << "WebApp proto parse error: no any source in sources field";
return nullptr; return nullptr;
} }
web_app->sources_ = sources; web_app->sources_ = sources;
if (!specifics.has_name()) { if (!local_data.has_name()) {
DLOG(ERROR) << "WebApp proto parse error: no name field"; DLOG(ERROR) << "WebApp proto parse error: no name field";
return nullptr; return nullptr;
} }
web_app->SetName(specifics.name()); web_app->SetName(local_data.name());
if (!specifics.has_launch_container()) { if (!sync_data.has_launch_container()) {
DLOG(ERROR) << "WebApp proto parse error: no launch_container field"; DLOG(ERROR) << "WebApp proto parse error: no launch_container field";
return nullptr; return nullptr;
} }
web_app->SetLaunchContainer(specifics.launch_container() == web_app->SetLaunchContainer(sync_data.launch_container() ==
sync_pb::WebAppSpecifics::WINDOW sync_pb::WebAppSpecifics::WINDOW
? LaunchContainer::kWindow ? LaunchContainer::kWindow
: LaunchContainer::kTab); : LaunchContainer::kTab);
if (!proto.has_is_locally_installed()) { if (!local_data.has_is_locally_installed()) {
DLOG(ERROR) << "WebApp proto parse error: no is_locally_installed field"; DLOG(ERROR) << "WebApp proto parse error: no is_locally_installed field";
return nullptr; return nullptr;
} }
web_app->SetIsLocallyInstalled(proto.is_locally_installed()); web_app->SetIsLocallyInstalled(local_data.is_locally_installed());
// Optional fields: // Optional fields:
if (proto.has_description()) if (local_data.has_description())
web_app->SetDescription(proto.description()); web_app->SetDescription(local_data.description());
if (proto.has_scope()) { if (local_data.has_scope()) {
GURL scope(proto.scope()); GURL scope(local_data.scope());
if (scope.is_empty() || !scope.is_valid()) { if (scope.is_empty() || !scope.is_valid()) {
DLOG(ERROR) << "WebApp proto scope parse error: " DLOG(ERROR) << "WebApp proto scope parse error: "
<< scope.possibly_invalid_spec(); << scope.possibly_invalid_spec();
...@@ -208,12 +217,23 @@ std::unique_ptr<WebApp> WebAppDatabase::CreateWebApp(const WebAppProto& proto) { ...@@ -208,12 +217,23 @@ std::unique_ptr<WebApp> WebAppDatabase::CreateWebApp(const WebAppProto& proto) {
web_app->SetScope(scope); web_app->SetScope(scope);
} }
if (specifics.has_theme_color()) if (local_data.has_theme_color())
web_app->SetThemeColor(specifics.theme_color()); web_app->SetThemeColor(local_data.theme_color());
if (local_data.has_is_sync_placeholder())
web_app->SetIsSyncPlaceholder(local_data.is_sync_placeholder());
// Parse sync_data from sync proto.
WebApp::SyncData parsed_sync_data;
if (sync_data.has_name())
parsed_sync_data.name = sync_data.name();
if (sync_data.has_theme_color())
parsed_sync_data.theme_color = sync_data.theme_color();
web_app->SetSyncData(parsed_sync_data);
WebApp::Icons icons; WebApp::Icons icons;
for (int i = 0; i < proto.icons_size(); ++i) { for (int i = 0; i < local_data.icons_size(); ++i) {
const WebAppIconInfoProto& icon_proto = proto.icons(i); const WebAppIconInfoProto& icon_proto = local_data.icons(i);
GURL icon_url(icon_proto.url()); GURL icon_url(icon_proto.url());
if (icon_url.is_empty() || !icon_url.is_valid()) { if (icon_url.is_empty() || !icon_url.is_valid()) {
......
...@@ -58,7 +58,7 @@ class WebAppDatabase { ...@@ -58,7 +58,7 @@ class WebAppDatabase {
const std::string& value); const std::string& value);
private: private:
static std::unique_ptr<WebApp> CreateWebApp(const WebAppProto& proto); static std::unique_ptr<WebApp> CreateWebApp(const WebAppProto& local_data);
void OnDatabaseOpened(RegistryOpenedCallback callback, void OnDatabaseOpened(RegistryOpenedCallback callback,
const base::Optional<syncer::ModelError>& error, const base::Optional<syncer::ModelError>& error,
......
...@@ -46,6 +46,7 @@ class WebAppDatabaseTest : public WebAppTest { ...@@ -46,6 +46,7 @@ class WebAppDatabaseTest : public WebAppTest {
const std::string scope = const std::string scope =
base_url + "/scope" + base::NumberToString(suffix); base_url + "/scope" + base::NumberToString(suffix);
const base::Optional<SkColor> theme_color = suffix; const base::Optional<SkColor> theme_color = suffix;
const base::Optional<SkColor> synced_theme_color = suffix ^ UINT_MAX;
auto app = std::make_unique<WebApp>(app_id); auto app = std::make_unique<WebApp>(app_id);
...@@ -69,6 +70,7 @@ class WebAppDatabaseTest : public WebAppTest { ...@@ -69,6 +70,7 @@ class WebAppDatabaseTest : public WebAppTest {
app->SetScope(GURL(scope)); app->SetScope(GURL(scope));
app->SetThemeColor(theme_color); app->SetThemeColor(theme_color);
app->SetIsLocallyInstalled(!(suffix & 2)); app->SetIsLocallyInstalled(!(suffix & 2));
app->SetIsSyncPlaceholder(!(suffix & 4));
app->SetLaunchContainer((suffix & 1) ? LaunchContainer::kTab app->SetLaunchContainer((suffix & 1) ? LaunchContainer::kTab
: LaunchContainer::kWindow); : LaunchContainer::kWindow);
...@@ -81,6 +83,11 @@ class WebAppDatabaseTest : public WebAppTest { ...@@ -81,6 +83,11 @@ class WebAppDatabaseTest : public WebAppTest {
app->SetIcons(std::move(icons)); app->SetIcons(std::move(icons));
WebApp::SyncData sync_data;
sync_data.name = "Sync" + name;
sync_data.theme_color = synced_theme_color;
app->SetSyncData(sync_data);
return app; return app;
} }
...@@ -263,6 +270,9 @@ TEST_F(WebAppDatabaseTest, WebAppWithoutOptionalFields) { ...@@ -263,6 +270,9 @@ TEST_F(WebAppDatabaseTest, WebAppWithoutOptionalFields) {
EXPECT_TRUE(app->scope().is_empty()); EXPECT_TRUE(app->scope().is_empty());
EXPECT_FALSE(app->theme_color().has_value()); EXPECT_FALSE(app->theme_color().has_value());
EXPECT_TRUE(app->icons().empty()); EXPECT_TRUE(app->icons().empty());
EXPECT_FALSE(app->is_sync_placeholder());
EXPECT_TRUE(app->sync_data().name.empty());
EXPECT_FALSE(app->sync_data().theme_color.has_value());
controller().RegisterApp(std::move(app)); controller().RegisterApp(std::move(app));
Registry registry = database_factory().ReadRegistry(); Registry registry = database_factory().ReadRegistry();
...@@ -288,6 +298,9 @@ TEST_F(WebAppDatabaseTest, WebAppWithoutOptionalFields) { ...@@ -288,6 +298,9 @@ TEST_F(WebAppDatabaseTest, WebAppWithoutOptionalFields) {
EXPECT_TRUE(app_copy->scope().is_empty()); EXPECT_TRUE(app_copy->scope().is_empty());
EXPECT_FALSE(app_copy->theme_color().has_value()); EXPECT_FALSE(app_copy->theme_color().has_value());
EXPECT_TRUE(app_copy->icons().empty()); EXPECT_TRUE(app_copy->icons().empty());
EXPECT_FALSE(app_copy->is_sync_placeholder());
EXPECT_TRUE(app_copy->sync_data().name.empty());
EXPECT_FALSE(app_copy->sync_data().theme_color.has_value());
} }
TEST_F(WebAppDatabaseTest, WebAppWithManyIcons) { TEST_F(WebAppDatabaseTest, WebAppWithManyIcons) {
......
...@@ -129,6 +129,12 @@ void WebAppInstallFinalizer::FinalizeInstall( ...@@ -129,6 +129,12 @@ void WebAppInstallFinalizer::FinalizeInstall(
SetIcons(web_app_info, web_app.get()); SetIcons(web_app_info, web_app.get());
web_app->SetIsSyncPlaceholder(false);
WebApp::SyncData sync_data;
sync_data.name = base::UTF16ToUTF8(web_app_info.title);
sync_data.theme_color = web_app_info.theme_color;
web_app->SetSyncData(sync_data);
icon_manager_->WriteData( icon_manager_->WriteData(
std::move(app_id), std::make_unique<WebApplicationInfo>(web_app_info), std::move(app_id), std::make_unique<WebApplicationInfo>(web_app_info),
base::BindOnce(&WebAppInstallFinalizer::OnIconsDataWritten, base::BindOnce(&WebAppInstallFinalizer::OnIconsDataWritten,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment