summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Wittman <wittman@chromium.org>2014-10-01 14:56:57 -0700
committerMike Wittman <wittman@chromium.org>2014-10-01 21:59:55 +0000
commit72520cfbda25e457da26113b568c76171d716a3f (patch)
treeada572d1f49255980811a20eb452a7f7e6423d6b
parent438a0d63964342acd2b50f12cb69fa4ae93254c0 (diff)
downloadchromium_src-72520cfbda25e457da26113b568c76171d716a3f.zip
chromium_src-72520cfbda25e457da26113b568c76171d716a3f.tar.gz
chromium_src-72520cfbda25e457da26113b568c76171d716a3f.tar.bz2
Add enhanced bookmarks sync datatype
Adds a new sync datatype to handle the enhanced bookmarks representation. BUG=415822 R=mpearson@chromium.org, sky@chromium.org, zea@chromium.org Review URL: https://codereview.chromium.org/583863002 Cr-Commit-Position: refs/heads/master@{#297718}
-rw-r--r--chrome/browser/bookmarks/enhanced_bookmarks_features.cc7
-rw-r--r--chrome/browser/bookmarks/enhanced_bookmarks_features.h3
-rw-r--r--chrome/browser/sync/profile_sync_components_factory_impl.cc14
-rw-r--r--chrome/browser/sync/profile_sync_service.cc2
-rw-r--r--chrome/browser/ui/webui/sync_setup_handler.cc2
-rw-r--r--chrome/common/chrome_switches.cc3
-rw-r--r--chrome/common/chrome_switches.h2
-rw-r--r--components/sync_driver/model_association_manager.cc1
-rw-r--r--components/sync_driver/pref_names.cc1
-rw-r--r--components/sync_driver/pref_names.h1
-rw-r--r--components/sync_driver/sync_prefs.cc2
-rw-r--r--sync/internal_api/public/base/model_type.h2
-rw-r--r--sync/protocol/BUILD.gn1
-rw-r--r--sync/protocol/enhanced_bookmark_specifics.proto124
-rw-r--r--sync/protocol/proto_enum_conversions.cc24
-rw-r--r--sync/protocol/proto_enum_conversions.h7
-rw-r--r--sync/protocol/proto_value_conversions.cc76
-rw-r--r--sync/protocol/proto_value_conversions.h4
-rw-r--r--sync/protocol/proto_value_conversions_unittest.cc246
-rw-r--r--sync/protocol/sync.proto2
-rw-r--r--sync/sync.gyp1
-rw-r--r--sync/syncable/model_type.cc25
-rw-r--r--sync/syncable/nigori_util.cc4
-rw-r--r--sync/tools/testserver/chromiumsync.py8
-rw-r--r--sync/util/data_type_histogram.h3
-rw-r--r--tools/metrics/histograms/histograms.xml1
26 files changed, 559 insertions, 7 deletions
diff --git a/chrome/browser/bookmarks/enhanced_bookmarks_features.cc b/chrome/browser/bookmarks/enhanced_bookmarks_features.cc
index a7bca68..d519600 100644
--- a/chrome/browser/bookmarks/enhanced_bookmarks_features.cc
+++ b/chrome/browser/bookmarks/enhanced_bookmarks_features.cc
@@ -259,3 +259,10 @@ bool IsEnableSyncArticlesSet() {
return false;
}
+
+bool IsEnhancedBookmarksSyncEnabled() {
+ // Gate by command line flag during development. Ultimately this should check
+ // whether the user is using the enhanced bookmarks extension.
+ return CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableEnhancedBookmarksSync);
+}
diff --git a/chrome/browser/bookmarks/enhanced_bookmarks_features.h b/chrome/browser/bookmarks/enhanced_bookmarks_features.h
index a0c09c4..8b88d47 100644
--- a/chrome/browser/bookmarks/enhanced_bookmarks_features.h
+++ b/chrome/browser/bookmarks/enhanced_bookmarks_features.h
@@ -77,4 +77,7 @@ bool IsEnableDomDistillerSet();
// Returns true when flag enable-sync-articles is set or enabled from Finch.
bool IsEnableSyncArticlesSet();
+// Returns true if sync of enhanced bookmarks is enabled.
+bool IsEnhancedBookmarksSyncEnabled();
+
#endif // CHROME_BROWSER_BOOKMARKS_ENHANCED_BOOKMARKS_FEATURES_H_
diff --git a/chrome/browser/sync/profile_sync_components_factory_impl.cc b/chrome/browser/sync/profile_sync_components_factory_impl.cc
index a85b2a1..345845c 100644
--- a/chrome/browser/sync/profile_sync_components_factory_impl.cc
+++ b/chrome/browser/sync/profile_sync_components_factory_impl.cc
@@ -289,6 +289,15 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
this,
profile_));
#endif
+
+ // Enhanced bookmark sync is disabled by default. Register only if explicitly
+ // enabled.
+ if (IsEnhancedBookmarksSyncEnabled()) {
+ pss->RegisterDataTypeController(new UIDataTypeController(
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
+ base::Bind(&ChromeReportUnrecoverableError),
+ syncer::ENHANCED_BOOKMARKS, this));
+ }
}
void ProfileSyncComponentsFactoryImpl::RegisterDesktopDataTypes(
@@ -557,6 +566,11 @@ base::WeakPtr<syncer::SyncableService> ProfileSyncComponentsFactoryImpl::
return base::WeakPtr<syncer::SyncableService>();
#endif
}
+ case syncer::ENHANCED_BOOKMARKS: {
+ // TODO(wittman): Return enhanced bookmarks SyncableService once
+ // implemented.
+ return base::WeakPtr<syncer::SyncableService>();
+ }
default:
// The following datatypes still need to be transitioned to the
// syncer::SyncableService API:
diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc
index eb76001..3acb432 100644
--- a/chrome/browser/sync/profile_sync_service.cc
+++ b/chrome/browser/sync/profile_sync_service.cc
@@ -1719,7 +1719,7 @@ void ProfileSyncService::UpdateSelectedTypesHistogram(
sync_driver::user_selectable_type::PROXY_TABS
};
- COMPILE_ASSERT(32 == syncer::MODEL_TYPE_COUNT, UpdateCustomConfigHistogram);
+ COMPILE_ASSERT(33 == syncer::MODEL_TYPE_COUNT, UpdateCustomConfigHistogram);
if (!sync_everything) {
const syncer::ModelTypeSet current_types = GetPreferredDataTypes();
diff --git a/chrome/browser/ui/webui/sync_setup_handler.cc b/chrome/browser/ui/webui/sync_setup_handler.cc
index 0218d61..f5f1b1d 100644
--- a/chrome/browser/ui/webui/sync_setup_handler.cc
+++ b/chrome/browser/ui/webui/sync_setup_handler.cc
@@ -106,7 +106,7 @@ const char* kDataTypeNames[] = {
"tabs"
};
-COMPILE_ASSERT(32 == syncer::MODEL_TYPE_COUNT,
+COMPILE_ASSERT(33 == syncer::MODEL_TYPE_COUNT,
update_kDataTypeNames_to_match_UserSelectableTypes);
typedef std::map<syncer::ModelType, const char*> ModelTypeNameMap;
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 35d3d8b..9d35d23 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -433,6 +433,9 @@ const char kEnableDomainReliability[] = "enable-domain-reliability";
// Enable Enhanced Bookmarks.
const char kEnhancedBookmarksExperiment[] = "enhanced-bookmarks-experiment";
+// Enable Enhanced Bookmarks sync.
+const char kEnableEnhancedBookmarksSync[] = "enable-enhanced-bookmarks-sync";
+
// Enables experimentation with ephemeral apps, which are launched without
// installing in Chrome.
const char kEnableEphemeralApps[] = "enable-ephemeral-apps";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index f8d3531..9bde5f5 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -127,7 +127,7 @@ extern const char kEnableDeviceDiscoveryNotifications[];
extern const char kEnableDomDistiller[];
extern const char kEnhancedBookmarksExperiment[];
extern const char kEnableDomainReliability[];
-extern const char kEnableEnhancedBookmarks[];
+extern const char kEnableEnhancedBookmarksSync[];
extern const char kEnableEphemeralApps[];
extern const char kEnableExperimentalHotwording[];
extern const char kEnableExtensionActivityLogging[];
diff --git a/components/sync_driver/model_association_manager.cc b/components/sync_driver/model_association_manager.cc
index 6706c4c..2fa90ab 100644
--- a/components/sync_driver/model_association_manager.cc
+++ b/components/sync_driver/model_association_manager.cc
@@ -39,6 +39,7 @@ static const syncer::ModelType kStartOrder[] = {
// UI thread data types.
syncer::BOOKMARKS,
+ syncer::ENHANCED_BOOKMARKS,
syncer::SUPERVISED_USERS, // Syncing supervised users on initial login
// might block creating a new supervised user,
// so we want to do it early.
diff --git a/components/sync_driver/pref_names.cc b/components/sync_driver/pref_names.cc
index 5ecf5c8..bf3de10 100644
--- a/components/sync_driver/pref_names.cc
+++ b/components/sync_driver/pref_names.cc
@@ -40,6 +40,7 @@ const char kSyncAutofill[] = "sync.autofill";
const char kSyncBookmarks[] = "sync.bookmarks";
const char kSyncDeviceInfo[] = "sync.device_info";
const char kSyncDictionary[] = "sync.dictionary";
+const char kSyncEnhancedBookmarks[] = "sync.enhanced_bookmarks";
const char kSyncExtensionSettings[] = "sync.extension_settings";
const char kSyncExtensions[] = "sync.extensions";
const char kSyncFaviconImages[] = "sync.favicon_images";
diff --git a/components/sync_driver/pref_names.h b/components/sync_driver/pref_names.h
index 54710fb..a386504 100644
--- a/components/sync_driver/pref_names.h
+++ b/components/sync_driver/pref_names.h
@@ -28,6 +28,7 @@ extern const char kSyncAutofill[];
extern const char kSyncBookmarks[];
extern const char kSyncDeviceInfo[];
extern const char kSyncDictionary[];
+extern const char kSyncEnhancedBookmarks[];
extern const char kSyncExtensionSettings[];
extern const char kSyncExtensions[];
extern const char kSyncFaviconImages[];
diff --git a/components/sync_driver/sync_prefs.cc b/components/sync_driver/sync_prefs.cc
index cc7914d..c28ec27 100644
--- a/components/sync_driver/sync_prefs.cc
+++ b/components/sync_driver/sync_prefs.cc
@@ -301,6 +301,8 @@ const char* SyncPrefs::GetPrefNameForDataType(syncer::ModelType data_type) {
return prefs::kSyncThemes;
case syncer::TYPED_URLS:
return prefs::kSyncTypedUrls;
+ case syncer::ENHANCED_BOOKMARKS:
+ return prefs::kSyncEnhancedBookmarks;
case syncer::EXTENSION_SETTINGS:
return prefs::kSyncExtensionSettings;
case syncer::EXTENSIONS:
diff --git a/sync/internal_api/public/base/model_type.h b/sync/internal_api/public/base/model_type.h
index 61bcbd0..305c385 100644
--- a/sync/internal_api/public/base/model_type.h
+++ b/sync/internal_api/public/base/model_type.h
@@ -110,6 +110,8 @@ enum ModelType {
ARTICLES,
// App List items
APP_LIST,
+ // Enhanced bookmarks clips or folios.
+ ENHANCED_BOOKMARKS,
// ---- Proxy types ----
// Proxy types are excluded from the sync protocol, but are still considered
diff --git a/sync/protocol/BUILD.gn b/sync/protocol/BUILD.gn
index d6e233b..88685d8 100644
--- a/sync/protocol/BUILD.gn
+++ b/sync/protocol/BUILD.gn
@@ -19,6 +19,7 @@ proto_library("protocol") {
"device_info_specifics.proto",
"dictionary_specifics.proto",
"encryption.proto",
+ "enhanced_bookmark_specifics.proto",
"experiments_specifics.proto",
"extension_setting_specifics.proto",
"extension_specifics.proto",
diff --git a/sync/protocol/enhanced_bookmark_specifics.proto b/sync/protocol/enhanced_bookmark_specifics.proto
new file mode 100644
index 0000000..8da5467
--- /dev/null
+++ b/sync/protocol/enhanced_bookmark_specifics.proto
@@ -0,0 +1,124 @@
+// Copyright (c) 2012 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.
+//
+// Sync protocol datatype extension for enhanced bookmarks.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+option retain_unknown_fields = true;
+
+package sync_pb;
+
+import "bookmark_specifics.proto";
+
+message ChromeSyncFolioInfo {
+ // Client-generated id. This is opaque to Chrome and unique across all
+ // EnhancedBookmarkSpecifics for a given user.
+ optional string folio_id = 1;
+ // Computed as per enhanced_bookmarks::ItemPosition.
+ optional string position = 2;
+
+ // The size the clip should be displayed in Folio view (i.e. which images
+ // should be large in hero layout).
+ enum DisplaySize {
+ SMALL = 0;
+ MEDIUM = 1;
+ };
+ optional DisplaySize display_size = 3 [default = SMALL];
+}
+
+message ChromeSyncImageData {
+ message ImageInfo {
+ // The (normalized) URL this image can be found at.
+ optional string url = 1;
+
+ // The dimensions in pixels.
+ optional int32 width = 2;
+ optional int32 height = 3;
+ }
+
+ // Information about the original image.
+ optional ImageInfo original_info = 2;
+
+ // Information about the hosted thumbnail.
+ optional ImageInfo thumbnail_info = 3;
+
+ // The expiration timestamp of the served thumbnail, in microseconds since
+ // the Linux epoch. The thumbnail is only guaranteed until this time,
+ // afterwards the URL may be broken.
+ optional int64 expiration_timestamp_us = 4;
+}
+
+message ChromeSyncClip {
+ // Client-generated id. This is opaque to Chrome and unique across all
+ // EnhancedBookmarkSpecifics for a given user.
+ optional string id = 1;
+ optional string note = 2;
+ repeated ChromeSyncFolioInfo folio_info = 3;
+ optional string url = 4;
+ optional string title = 5;
+ optional string snippet = 6;
+ optional ChromeSyncImageData image = 7;
+ // Corresponds to BookmarkNode::date_added() and is the internal value from
+ // base::Time, in microseconds since the Windows epoch.
+ optional int64 created_timestamp_us = 8;
+
+ // True if url points to a site that may serve malware. Allows warnings to be
+ // displayed to user.
+ optional bool is_malware = 9;
+
+ // Reasons for failed fetches.
+ enum FetchErrorReason {
+ UNKNOWN = 0;
+ LIKELY_404 = 1;
+ UNREACHABLE = 2;
+ }
+
+ // Reason that fetching this page failed. This field is populated only if
+ // the most recent fetch attempt failed.
+ optional FetchErrorReason fetch_error_reason = 10;
+
+ // Bookmark manager or mobile client extension version, for logging and
+ // debugging purposes.
+ optional string client_version = 11;
+
+ message LegacyBookmarkData {
+ optional bytes favicon = 1;
+ optional string icon_url = 2;
+ }
+
+ optional LegacyBookmarkData bookmark_data = 12;
+
+ repeated MetaInfo meta_info = 13;
+}
+
+message ChromeSyncFolio {
+ // Client-generated id.
+ optional string id = 1;
+ // If set, is the Folio id that corresponds to a Chrome bookmarks folder. As a
+ // special case, the root folder is assigned an empty string.
+ optional string parent_id = 2;
+ optional string title = 3;
+ optional string description = 4;
+ optional bool is_public = 5;
+ // Corresponds to BookmarkNode::date_added() and is the internal value from
+ // base::Time, in microseconds since the Windows epoch.
+ optional int64 created_timestamp_us = 6;
+ // Set if parent_id is set. The position of this folio in its
+ // parent folio. This is the analog of ChromeSyncFolioInfo.position in clips.
+ optional string position = 7;
+ // Bookmark manager or mobile client extension version, for logging and
+ // debugging purposes.
+ optional string client_version = 13;
+
+ repeated MetaInfo meta_info = 14;
+}
+
+// Properties of enhanced bookmark sync objects.
+message EnhancedBookmarkSpecifics {
+ // Exactly one of clip or folio is set.
+ optional ChromeSyncClip clip = 1;
+ optional ChromeSyncFolio folio = 2;
+}
diff --git a/sync/protocol/proto_enum_conversions.cc b/sync/protocol/proto_enum_conversions.cc
index 4c43983..d8c1f0b 100644
--- a/sync/protocol/proto_enum_conversions.cc
+++ b/sync/protocol/proto_enum_conversions.cc
@@ -263,6 +263,30 @@ const char* GetBlockedStateString(
return "";
}
+const char* GetDisplaySizeString(
+ sync_pb::ChromeSyncFolioInfo::DisplaySize display_size) {
+ ASSERT_ENUM_BOUNDS(sync_pb::ChromeSyncFolioInfo, DisplaySize, SMALL, MEDIUM);
+ switch (display_size) {
+ ENUM_CASE(sync_pb::ChromeSyncFolioInfo, SMALL);
+ ENUM_CASE(sync_pb::ChromeSyncFolioInfo, MEDIUM);
+ }
+ NOTREACHED();
+ return "";
+}
+
+const char* GetFetchErrorReasonString(
+ sync_pb::ChromeSyncClip::FetchErrorReason fetch_error_reason) {
+ ASSERT_ENUM_BOUNDS(
+ sync_pb::ChromeSyncClip, FetchErrorReason, UNKNOWN, UNREACHABLE);
+ switch (fetch_error_reason) {
+ ENUM_CASE(sync_pb::ChromeSyncClip, UNKNOWN);
+ ENUM_CASE(sync_pb::ChromeSyncClip, LIKELY_404);
+ ENUM_CASE(sync_pb::ChromeSyncClip, UNREACHABLE);
+ }
+ NOTREACHED();
+ return "";
+}
+
#undef ASSERT_ENUM_BOUNDS
#undef ENUM_CASE
diff --git a/sync/protocol/proto_enum_conversions.h b/sync/protocol/proto_enum_conversions.h
index 57a7b5c..b73cff4 100644
--- a/sync/protocol/proto_enum_conversions.h
+++ b/sync/protocol/proto_enum_conversions.h
@@ -11,6 +11,7 @@
#include "sync/protocol/app_list_specifics.pb.h"
#include "sync/protocol/app_specifics.pb.h"
#include "sync/protocol/client_debug_info.pb.h"
+#include "sync/protocol/enhanced_bookmark_specifics.pb.h"
#include "sync/protocol/session_specifics.pb.h"
#include "sync/protocol/sync.pb.h"
@@ -65,6 +66,12 @@ const char* SingletonDebugEventTypeString(
const char* GetBlockedStateString(sync_pb::TabNavigation::BlockedState state);
+const char* GetDisplaySizeString(
+ sync_pb::ChromeSyncFolioInfo::DisplaySize display_size);
+
+const char* GetFetchErrorReasonString(
+ sync_pb::ChromeSyncClip::FetchErrorReason fetch_error_reason);
+
} // namespace syncer
#endif // SYNC_PROTOCOL_PROTO_ENUM_CONVERSIONS_H_
diff --git a/sync/protocol/proto_value_conversions.cc b/sync/protocol/proto_value_conversions.cc
index bb37081..3d281c0 100644
--- a/sync/protocol/proto_value_conversions.cc
+++ b/sync/protocol/proto_value_conversions.cc
@@ -513,6 +513,81 @@ base::DictionaryValue* DictionarySpecificsToValue(
return value;
}
+base::DictionaryValue* FolioInfoToValue(
+ const sync_pb::ChromeSyncFolioInfo& proto) {
+ base::DictionaryValue* value = new base::DictionaryValue();
+ SET_STR(folio_id);
+ SET_STR(position);
+ SET_ENUM(display_size, GetDisplaySizeString);
+ return value;
+}
+
+base::DictionaryValue* ImageInfoToValue(
+ const sync_pb::ChromeSyncImageData::ImageInfo& proto) {
+ base::DictionaryValue* value = new base::DictionaryValue();
+ SET_STR(url);
+ SET_INT32(width);
+ SET_INT32(height);
+ return value;
+}
+
+base::DictionaryValue* ImageDataToValue(
+ const sync_pb::ChromeSyncImageData& proto) {
+ base::DictionaryValue* value = new base::DictionaryValue();
+ SET(original_info, ImageInfoToValue);
+ SET(thumbnail_info, ImageInfoToValue);
+ SET_INT64(expiration_timestamp_us);
+ return value;
+}
+
+base::DictionaryValue* LegacyBookmarkDataToValue(
+ const sync_pb::ChromeSyncClip::LegacyBookmarkData& proto) {
+ base::DictionaryValue* value = new base::DictionaryValue();
+ SET_BYTES(favicon);
+ SET_STR(icon_url);
+ return value;
+}
+
+base::DictionaryValue* ClipToValue(const sync_pb::ChromeSyncClip& proto) {
+ base::DictionaryValue* value = new base::DictionaryValue();
+ SET_STR(id);
+ SET_STR(note);
+ SET_REP(folio_info, &FolioInfoToValue);
+ SET_STR(url);
+ SET_STR(title);
+ SET_STR(snippet);
+ SET(image, ImageDataToValue);
+ SET_INT64(created_timestamp_us);
+ SET_BOOL(is_malware);
+ SET_ENUM(fetch_error_reason, GetFetchErrorReasonString);
+ SET_STR(client_version);
+ SET(bookmark_data, LegacyBookmarkDataToValue);
+ SET_REP(meta_info, &MetaInfoToValue);
+ return value;
+}
+
+base::DictionaryValue* FolioToValue(const sync_pb::ChromeSyncFolio& proto) {
+ base::DictionaryValue* value = new base::DictionaryValue();
+ SET_STR(id);
+ SET_STR(parent_id);
+ SET_STR(title);
+ SET_STR(description);
+ SET_BOOL(is_public);
+ SET_INT64(created_timestamp_us);
+ SET_STR(position);
+ SET_STR(client_version);
+ SET_REP(meta_info, &MetaInfoToValue);
+ return value;
+}
+
+base::DictionaryValue* EnhancedBookmarkSpecificsToValue(
+ const sync_pb::EnhancedBookmarkSpecifics& proto) {
+ base::DictionaryValue* value = new base::DictionaryValue();
+ SET(clip, ClipToValue);
+ SET(folio, FolioToValue);
+ return value;
+}
+
namespace {
base::DictionaryValue* FaviconSyncFlagsToValue(
@@ -797,6 +872,7 @@ base::DictionaryValue* EntitySpecificsToValue(
SET_FIELD(bookmark, BookmarkSpecificsToValue);
SET_FIELD(device_info, DeviceInfoSpecificsToValue);
SET_FIELD(dictionary, DictionarySpecificsToValue);
+ SET_FIELD(enhanced_bookmark, EnhancedBookmarkSpecificsToValue);
SET_FIELD(experiments, ExperimentsSpecificsToValue);
SET_FIELD(extension, ExtensionSpecificsToValue);
SET_FIELD(extension_setting, ExtensionSettingSpecificsToValue);
diff --git a/sync/protocol/proto_value_conversions.h b/sync/protocol/proto_value_conversions.h
index 2a3c1ae..cde44de 100644
--- a/sync/protocol/proto_value_conversions.h
+++ b/sync/protocol/proto_value_conversions.h
@@ -36,6 +36,7 @@ class DeviceInfoSpecifics;
class DeviceInformation;
class DictionarySpecifics;
class EncryptedData;
+class EnhancedBookmarkSpecifics;
class EntitySpecifics;
class EverythingDirective;
class ExperimentsSpecifics;
@@ -211,6 +212,9 @@ SYNC_EXPORT_PRIVATE base::DictionaryValue* DeviceInfoSpecificsToValue(
SYNC_EXPORT_PRIVATE base::DictionaryValue* DictionarySpecificsToValue(
const sync_pb::DictionarySpecifics& dictionary_specifics);
+SYNC_EXPORT_PRIVATE base::DictionaryValue* EnhancedBookmarkSpecificsToValue(
+ const sync_pb::EnhancedBookmarkSpecifics& enhanced_bookmark_specifics);
+
SYNC_EXPORT_PRIVATE base::DictionaryValue* ExperimentsSpecificsToValue(
const sync_pb::ExperimentsSpecifics& proto);
diff --git a/sync/protocol/proto_value_conversions_unittest.cc b/sync/protocol/proto_value_conversions_unittest.cc
index 664a6ab..cace83b 100644
--- a/sync/protocol/proto_value_conversions_unittest.cc
+++ b/sync/protocol/proto_value_conversions_unittest.cc
@@ -6,6 +6,7 @@
#include "sync/protocol/proto_value_conversions.h"
+#include "base/base64.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
@@ -18,6 +19,7 @@
#include "sync/protocol/bookmark_specifics.pb.h"
#include "sync/protocol/device_info_specifics.pb.h"
#include "sync/protocol/encryption.pb.h"
+#include "sync/protocol/enhanced_bookmark_specifics.pb.h"
#include "sync/protocol/experiments_specifics.pb.h"
#include "sync/protocol/extension_setting_specifics.pb.h"
#include "sync/protocol/extension_specifics.pb.h"
@@ -35,6 +37,7 @@
#include "sync/protocol/sync.pb.h"
#include "sync/protocol/theme_specifics.pb.h"
#include "sync/protocol/typed_url_specifics.pb.h"
+#include "sync/util/time.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace syncer {
@@ -55,7 +58,7 @@ TEST_F(ProtoValueConversionsTest, ProtoChangeCheck) {
// If this number changes, that means we added or removed a data
// type. Don't forget to add a unit test for {New
// type}SpecificsToValue below.
- EXPECT_EQ(32, MODEL_TYPE_COUNT);
+ EXPECT_EQ(33, MODEL_TYPE_COUNT);
// We'd also like to check if we changed any field in our messages.
// However, that's hard to do: sizeof could work, but it's
@@ -184,6 +187,246 @@ TEST_F(ProtoValueConversionsTest, DeviceInfoSpecificsToValue) {
TestSpecificsToValue(DeviceInfoSpecificsToValue);
}
+TEST_F(ProtoValueConversionsTest, EnhancedBookmarkSpecificsToValue) {
+ TestSpecificsToValue(EnhancedBookmarkSpecificsToValue);
+}
+
+TEST_F(ProtoValueConversionsTest, EnhancedBookmarkSpecificsClipData) {
+ sync_pb::EnhancedBookmarkSpecifics specifics;
+ sync_pb::ChromeSyncClip* clip = specifics.mutable_clip();
+ clip->set_id("id1");
+ clip->set_note("note1");
+
+ sync_pb::ChromeSyncFolioInfo* folio_info1 = clip->add_folio_info();
+ folio_info1->set_folio_id("folio id1");
+ folio_info1->set_position("position1");
+ folio_info1->set_display_size(sync_pb::ChromeSyncFolioInfo::SMALL);
+ sync_pb::ChromeSyncFolioInfo* folio_info2 = clip->add_folio_info();
+ folio_info2->set_folio_id("folio id2");
+ folio_info2->set_position("position2");
+ folio_info2->set_display_size(sync_pb::ChromeSyncFolioInfo::MEDIUM);
+
+ clip->set_url("http://www.google.com/");
+ clip->set_title("title1");
+ clip->set_snippet("snippet1");
+
+ sync_pb::ChromeSyncImageData* image =
+ clip->mutable_image();
+ sync_pb::ChromeSyncImageData::ImageInfo* original_info =
+ image->mutable_original_info();
+ original_info->set_url("http://example.com/original");
+ original_info->set_width(1);
+ original_info->set_height(2);
+ sync_pb::ChromeSyncImageData::ImageInfo* thumbnail_info =
+ image->mutable_thumbnail_info();
+ thumbnail_info->set_url("http://example.com/thumbnail");
+ thumbnail_info->set_width(3);
+ thumbnail_info->set_height(4);
+ const base::Time expiration_time(base::Time::Now());
+ image->set_expiration_timestamp_us(syncer::TimeToProtoTime(expiration_time));
+
+ const base::Time created_time(base::Time::Now());
+ clip->set_created_timestamp_us(created_time.ToInternalValue());
+ clip->set_is_malware(true);
+ clip->set_fetch_error_reason(sync_pb::ChromeSyncClip::LIKELY_404);
+ clip->set_client_version("10");
+
+ sync_pb::ChromeSyncClip::LegacyBookmarkData* bookmark_data =
+ clip->mutable_bookmark_data();
+ bookmark_data->set_favicon("favicon data");
+ bookmark_data->set_icon_url("http://www.google.com/favicon.ico");
+
+ sync_pb::MetaInfo* meta_1 = clip->add_meta_info();
+ meta_1->set_key("key1");
+ meta_1->set_value("value1");
+ sync_pb::MetaInfo* meta_2 = clip->add_meta_info();
+ meta_2->set_key("key2");
+ meta_2->set_value("value2");
+
+ scoped_ptr<base::DictionaryValue> value(
+ EnhancedBookmarkSpecificsToValue(specifics));
+ EXPECT_FALSE(value->empty());
+ base::DictionaryValue* clip_value = nullptr;
+ ASSERT_TRUE(value->GetDictionary("clip", &clip_value));
+ EXPECT_FALSE(clip_value->empty());
+ std::string id;
+ EXPECT_TRUE(clip_value->GetString("id", &id));
+ EXPECT_EQ("id1", id);
+ std::string note;
+ EXPECT_TRUE(clip_value->GetString("note", &note));
+ EXPECT_EQ("note1", note);
+
+ base::ListValue* folio_info_list;
+ ASSERT_TRUE(clip_value->GetList("folio_info", &folio_info_list));
+ EXPECT_EQ(2u, folio_info_list->GetSize());
+ base::DictionaryValue* folio_info;
+ ASSERT_TRUE(folio_info_list->GetDictionary(0, &folio_info));
+ std::string folio_id;
+ std::string position;
+ std::string display_size;
+ EXPECT_TRUE(folio_info->GetString("folio_id", &folio_id));
+ EXPECT_TRUE(folio_info->GetString("position", &position));
+ EXPECT_TRUE(folio_info->GetString("display_size", &display_size));
+ EXPECT_EQ("folio id1", folio_id);
+ EXPECT_EQ("position1", position);
+ EXPECT_EQ("SMALL", display_size);
+ ASSERT_TRUE(folio_info_list->GetDictionary(1, &folio_info));
+ EXPECT_TRUE(folio_info->GetString("folio_id", &folio_id));
+ EXPECT_TRUE(folio_info->GetString("position", &position));
+ EXPECT_TRUE(folio_info->GetString("display_size", &display_size));
+ EXPECT_EQ("folio id2", folio_id);
+ EXPECT_EQ("position2", position);
+ EXPECT_EQ("MEDIUM", display_size);
+
+ std::string url;
+ EXPECT_TRUE(clip_value->GetString("url", &url));
+ EXPECT_EQ("http://www.google.com/", url);
+ std::string title;
+ EXPECT_TRUE(clip_value->GetString("title", &title));
+ EXPECT_EQ("title1", title);
+ std::string snippet;
+ EXPECT_TRUE(clip_value->GetString("snippet", &snippet));
+ EXPECT_EQ("snippet1", snippet);
+
+ base::DictionaryValue* image_value = nullptr;
+ ASSERT_TRUE(clip_value->GetDictionary("image", &image_value));
+ base::DictionaryValue* image_info_value = nullptr;
+ ASSERT_TRUE(image_value->GetDictionary("original_info",
+ &image_info_value));
+ EXPECT_TRUE(image_info_value->GetString("url", &url));
+ EXPECT_EQ("http://example.com/original", url);
+ std::string width;
+ std::string height;
+ EXPECT_TRUE(image_info_value->GetString("width", &width));
+ EXPECT_EQ("1", width);
+ EXPECT_TRUE(image_info_value->GetString("height", &height));
+ EXPECT_EQ("2", height);
+ ASSERT_TRUE(image_value->GetDictionary("thumbnail_info",
+ &image_info_value));
+ EXPECT_TRUE(image_info_value->GetString("url", &url));
+ EXPECT_EQ("http://example.com/thumbnail", url);
+ EXPECT_TRUE(image_info_value->GetString("width", &width));
+ EXPECT_EQ("3", width);
+ EXPECT_TRUE(image_info_value->GetString("height", &height));
+ EXPECT_EQ("4", height);
+ std::string encoded_time_str;
+ EXPECT_TRUE(image_value->GetString("expiration_timestamp_us",
+ &encoded_time_str));
+ int64 encoded_time;
+ EXPECT_TRUE(base::StringToInt64(encoded_time_str, &encoded_time));
+ EXPECT_EQ(syncer::TimeToProtoTime(expiration_time), encoded_time);
+
+ EXPECT_TRUE(clip_value->GetString("created_timestamp_us", &encoded_time_str));
+ EXPECT_EQ(base::Int64ToString(created_time.ToInternalValue()),
+ encoded_time_str);
+ bool is_malware = false;
+ EXPECT_TRUE(clip_value->GetBoolean("is_malware", &is_malware));
+ EXPECT_TRUE(is_malware);
+ std::string fetch_error_reason;
+ EXPECT_TRUE(clip_value->GetString("fetch_error_reason", &fetch_error_reason));
+ EXPECT_EQ("LIKELY_404", fetch_error_reason);
+ std::string client_version;
+ EXPECT_TRUE(clip_value->GetString("client_version", &client_version));
+ EXPECT_EQ("10", client_version);
+ base::DictionaryValue* bookmark_data_value = nullptr;
+ ASSERT_TRUE(clip_value->GetDictionary("bookmark_data", &bookmark_data_value));
+ std::string favicon_base64;
+ EXPECT_TRUE(bookmark_data_value->GetString("favicon", &favicon_base64));
+ std::string favicon;
+ EXPECT_TRUE(base::Base64Decode(favicon_base64, &favicon));
+ EXPECT_EQ("favicon data", favicon);
+ std::string icon_url;
+ EXPECT_TRUE(bookmark_data_value->GetString("icon_url", &icon_url));
+ EXPECT_EQ("http://www.google.com/favicon.ico", icon_url);
+
+ base::ListValue* meta_info_list;
+ ASSERT_TRUE(clip_value->GetList("meta_info", &meta_info_list));
+ EXPECT_EQ(2u, meta_info_list->GetSize());
+ base::DictionaryValue* meta_info;
+ std::string meta_key;
+ std::string meta_value;
+ ASSERT_TRUE(meta_info_list->GetDictionary(0, &meta_info));
+ EXPECT_TRUE(meta_info->GetString("key", &meta_key));
+ EXPECT_TRUE(meta_info->GetString("value", &meta_value));
+ EXPECT_EQ("key1", meta_key);
+ EXPECT_EQ("value1", meta_value);
+ ASSERT_TRUE(meta_info_list->GetDictionary(1, &meta_info));
+ EXPECT_TRUE(meta_info->GetString("key", &meta_key));
+ EXPECT_TRUE(meta_info->GetString("value", &meta_value));
+ EXPECT_EQ("key2", meta_key);
+ EXPECT_EQ("value2", meta_value);
+}
+
+TEST_F(ProtoValueConversionsTest, EnhancedBookmarkSpecificsFolioData) {
+ sync_pb::EnhancedBookmarkSpecifics specifics;
+ sync_pb::ChromeSyncFolio* folio = specifics.mutable_folio();
+ folio->set_id("id1");
+ folio->set_parent_id("parent id1");
+ folio->set_title("title1");
+ folio->set_description("description1");
+ folio->set_is_public(true);
+ const base::Time created_time(base::Time::Now());
+ folio->set_created_timestamp_us(created_time.ToInternalValue());
+ folio->set_position("position1");
+ folio->set_client_version("10");
+ sync_pb::MetaInfo* meta_1 = folio->add_meta_info();
+ meta_1->set_key("key1");
+ meta_1->set_value("value1");
+ sync_pb::MetaInfo* meta_2 = folio->add_meta_info();
+ meta_2->set_key("key2");
+ meta_2->set_value("value2");
+
+ scoped_ptr<base::DictionaryValue> value(
+ EnhancedBookmarkSpecificsToValue(specifics));
+ EXPECT_FALSE(value->empty());
+ base::DictionaryValue* folio_value = nullptr;
+ ASSERT_TRUE(value->GetDictionary("folio", &folio_value));
+ EXPECT_FALSE(folio_value->empty());
+ std::string id;
+ EXPECT_TRUE(folio_value->GetString("id", &id));
+ EXPECT_EQ("id1", id);
+ std::string parent_id;
+ EXPECT_TRUE(folio_value->GetString("parent_id", &id));
+ EXPECT_EQ("parent id1", id);
+ std::string title;
+ EXPECT_TRUE(folio_value->GetString("title", &title));
+ EXPECT_EQ("title1", title);
+ std::string description;
+ EXPECT_TRUE(folio_value->GetString("description", &description));
+ EXPECT_EQ("description1", description);
+ bool is_public = false;
+ EXPECT_TRUE(folio_value->GetBoolean("is_public", &is_public));
+ EXPECT_TRUE(is_public);
+ std::string encoded_time_str;
+ EXPECT_TRUE(folio_value->GetString("created_timestamp_us",
+ &encoded_time_str));
+ EXPECT_EQ(base::Int64ToString(created_time.ToInternalValue()),
+ encoded_time_str);
+ std::string position;
+ EXPECT_TRUE(folio_value->GetString("position", &position));
+ EXPECT_EQ("position1", position);
+ std::string client_version;
+ EXPECT_TRUE(folio_value->GetString("client_version", &client_version));
+ EXPECT_EQ("10", client_version);
+
+ base::ListValue* meta_info_list;
+ ASSERT_TRUE(folio_value->GetList("meta_info", &meta_info_list));
+ EXPECT_EQ(2u, meta_info_list->GetSize());
+ base::DictionaryValue* meta_info;
+ std::string meta_key;
+ std::string meta_value;
+ ASSERT_TRUE(meta_info_list->GetDictionary(0, &meta_info));
+ EXPECT_TRUE(meta_info->GetString("key", &meta_key));
+ EXPECT_TRUE(meta_info->GetString("value", &meta_value));
+ EXPECT_EQ("key1", meta_key);
+ EXPECT_EQ("value1", meta_value);
+ ASSERT_TRUE(meta_info_list->GetDictionary(1, &meta_info));
+ EXPECT_TRUE(meta_info->GetString("key", &meta_key));
+ EXPECT_TRUE(meta_info->GetString("value", &meta_value));
+ EXPECT_EQ("key2", meta_key);
+ EXPECT_EQ("value2", meta_value);
+}
+
TEST_F(ProtoValueConversionsTest, ExperimentsSpecificsToValue) {
TestSpecificsToValue(ExperimentsSpecificsToValue);
}
@@ -282,6 +525,7 @@ TEST_F(ProtoValueConversionsTest, EntitySpecificsToValue) {
SET_FIELD(bookmark);
SET_FIELD(device_info);
SET_FIELD(dictionary);
+ SET_FIELD(enhanced_bookmark);
SET_FIELD(experiments);
SET_FIELD(extension);
SET_FIELD(extension_setting);
diff --git a/sync/protocol/sync.proto b/sync/protocol/sync.proto
index 8f27850..0bf4054 100644
--- a/sync/protocol/sync.proto
+++ b/sync/protocol/sync.proto
@@ -27,6 +27,7 @@ import "client_debug_info.proto";
import "device_info_specifics.proto";
import "dictionary_specifics.proto";
import "encryption.proto";
+import "enhanced_bookmark_specifics.proto";
import "experiments_specifics.proto";
import "extension_setting_specifics.proto";
import "extension_specifics.proto";
@@ -129,6 +130,7 @@ message EntitySpecifics {
202026;
optional ArticleSpecifics article = 223759;
optional AppListSpecifics app_list = 229170;
+ optional EnhancedBookmarkSpecifics enhanced_bookmark = 294694;
}
message SyncEntity {
diff --git a/sync/sync.gyp b/sync/sync.gyp
index f01ea81..6372fb70 100644
--- a/sync/sync.gyp
+++ b/sync/sync.gyp
@@ -473,6 +473,7 @@
'protocol/device_info_specifics.proto',
'protocol/dictionary_specifics.proto',
'protocol/encryption.proto',
+ 'protocol/enhanced_bookmark_specifics.proto',
'protocol/experiments_specifics.proto',
'protocol/extension_setting_specifics.proto',
'protocol/extension_specifics.proto',
diff --git a/sync/syncable/model_type.cc b/sync/syncable/model_type.cc
index 59be6f2..ddde204 100644
--- a/sync/syncable/model_type.cc
+++ b/sync/syncable/model_type.cc
@@ -119,6 +119,9 @@ void AddDefaultFieldValue(ModelType datatype,
case ARTICLES:
specifics->mutable_article();
break;
+ case ENHANCED_BOOKMARKS:
+ specifics->mutable_enhanced_bookmark();
+ break;
default:
NOTREACHED() << "No known extension for model type.";
}
@@ -196,6 +199,8 @@ int GetSpecificsFieldNumberFromModelType(ModelType model_type) {
return sync_pb::EntitySpecifics::kManagedUserSharedSettingFieldNumber;
case ARTICLES:
return sync_pb::EntitySpecifics::kArticleFieldNumber;
+ case ENHANCED_BOOKMARKS:
+ return sync_pb::EntitySpecifics::kEnhancedBookmarkFieldNumber;
default:
NOTREACHED() << "No known extension for model type.";
return 0;
@@ -324,6 +329,9 @@ ModelType GetModelTypeFromSpecifics(const sync_pb::EntitySpecifics& specifics) {
if (specifics.has_article())
return ARTICLES;
+ if (specifics.has_enhanced_bookmark())
+ return ENHANCED_BOOKMARKS;
+
return UNSPECIFIED;
}
@@ -366,6 +374,8 @@ bool IsUserSelectableType(ModelType model_type) {
ModelTypeSet EncryptableUserTypes() {
ModelTypeSet encryptable_user_types = UserTypes();
+ // Encrypted bookmarks are handled through standard bookmark sync.
+ encryptable_user_types.Remove(ENHANCED_BOOKMARKS);
// We never encrypt history delete directives.
encryptable_user_types.Remove(HISTORY_DELETE_DIRECTIVES);
// Synced notifications are not encrypted since the server must see changes.
@@ -524,6 +534,8 @@ const char* ModelTypeToString(ModelType model_type) {
return "Managed User Shared Settings";
case ARTICLES:
return "Articles";
+ case ENHANCED_BOOKMARKS:
+ return "Enhanced Bookmarks";
case PROXY_TABS:
return "Tabs";
default:
@@ -603,6 +615,8 @@ int ModelTypeToHistogramInt(ModelType model_type) {
return 30;
case SYNCED_NOTIFICATION_APP_INFO:
return 31;
+ case ENHANCED_BOOKMARKS:
+ return 32;
// Silence a compiler warning.
case MODEL_TYPE_COUNT:
return 0;
@@ -698,6 +712,8 @@ ModelType ModelTypeFromString(const std::string& model_type_string) {
return ARTICLES;
else if (model_type_string == "Tabs")
return PROXY_TABS;
+ else if (model_type_string == "Enhanced Bookmarks")
+ return ENHANCED_BOOKMARKS;
else
NOTREACHED() << "No known model type corresponding to "
<< model_type_string << ".";
@@ -822,6 +838,8 @@ std::string ModelTypeToRootTag(ModelType type) {
return "google_chrome_articles";
case PROXY_TABS:
return std::string();
+ case ENHANCED_BOOKMARKS:
+ return "google_chrome_enhanced_bookmarks";
default:
break;
}
@@ -864,6 +882,7 @@ const char kSupervisedUserNotificationType[] = "MANAGED_USER";
const char kSupervisedUserSharedSettingNotificationType[] =
"MANAGED_USER_SHARED_SETTING";
const char kArticleNotificationType[] = "ARTICLE";
+const char kEnhancedBookmarkNotificationType[] = "ENHANCED_BOOKMARK";
} // namespace
bool RealModelTypeToNotificationType(ModelType model_type,
@@ -956,6 +975,9 @@ bool RealModelTypeToNotificationType(ModelType model_type,
case ARTICLES:
*notification_type = kArticleNotificationType;
return true;
+ case ENHANCED_BOOKMARKS:
+ *notification_type = kEnhancedBookmarkNotificationType;
+ return true;
default:
break;
}
@@ -1053,6 +1075,9 @@ bool NotificationTypeToRealModelType(const std::string& notification_type,
} else if (notification_type == kArticleNotificationType) {
*model_type = ARTICLES;
return true;
+ } else if (notification_type == kEnhancedBookmarkNotificationType) {
+ *model_type = ENHANCED_BOOKMARKS;
+ return true;
}
*model_type = UNSPECIFIED;
return false;
diff --git a/sync/syncable/nigori_util.cc b/sync/syncable/nigori_util.cc
index 63dbcac..eaf9eca 100644
--- a/sync/syncable/nigori_util.cc
+++ b/sync/syncable/nigori_util.cc
@@ -243,7 +243,7 @@ void UpdateNigoriFromEncryptedTypes(ModelTypeSet encrypted_types,
bool encrypt_everything,
sync_pb::NigoriSpecifics* nigori) {
nigori->set_encrypt_everything(encrypt_everything);
- COMPILE_ASSERT(32 == MODEL_TYPE_COUNT, UpdateEncryptedTypes);
+ COMPILE_ASSERT(33 == MODEL_TYPE_COUNT, UpdateEncryptedTypes);
nigori->set_encrypt_bookmarks(
encrypted_types.Has(BOOKMARKS));
nigori->set_encrypt_preferences(
@@ -279,7 +279,7 @@ ModelTypeSet GetEncryptedTypesFromNigori(
return ModelTypeSet::All();
ModelTypeSet encrypted_types;
- COMPILE_ASSERT(32 == MODEL_TYPE_COUNT, UpdateEncryptedTypes);
+ COMPILE_ASSERT(33 == MODEL_TYPE_COUNT, UpdateEncryptedTypes);
if (nigori.encrypt_bookmarks())
encrypted_types.Put(BOOKMARKS);
if (nigori.encrypt_preferences())
diff --git a/sync/tools/testserver/chromiumsync.py b/sync/tools/testserver/chromiumsync.py
index 2930059..2dcee1b 100644
--- a/sync/tools/testserver/chromiumsync.py
+++ b/sync/tools/testserver/chromiumsync.py
@@ -33,6 +33,7 @@ import bookmark_specifics_pb2
import client_commands_pb2
import dictionary_specifics_pb2
import get_updates_caller_info_pb2
+import enhanced_bookmark_specifics_pb2
import extension_setting_specifics_pb2
import extension_specifics_pb2
import favicon_image_specifics_pb2
@@ -72,6 +73,7 @@ ALL_TYPES = (
BOOKMARK,
DEVICE_INFO,
DICTIONARY,
+ ENHANCED_BOOKMARK,
EXPERIMENTS,
EXTENSIONS,
HISTORY_DELETE_DIRECTIVE,
@@ -90,7 +92,7 @@ ALL_TYPES = (
TYPED_URL,
EXTENSION_SETTINGS,
FAVICON_IMAGES,
- FAVICON_TRACKING) = range(30)
+ FAVICON_TRACKING) = range(31)
# An enumeration on the frequency at which the server should send errors
# to the client. This would be specified by the url that triggers the error.
@@ -117,6 +119,7 @@ SYNC_TYPE_TO_DESCRIPTOR = {
BOOKMARK: SYNC_TYPE_FIELDS['bookmark'],
DEVICE_INFO: SYNC_TYPE_FIELDS['device_info'],
DICTIONARY: SYNC_TYPE_FIELDS['dictionary'],
+ ENHANCED_BOOKMARK: SYNC_TYPE_FIELDS['enhanced_bookmark'],
EXPERIMENTS: SYNC_TYPE_FIELDS['experiments'],
EXTENSION_SETTINGS: SYNC_TYPE_FIELDS['extension_setting'],
EXTENSIONS: SYNC_TYPE_FIELDS['extension'],
@@ -509,6 +512,9 @@ class SyncDataModel(object):
parent_tag=ROOT_ID, sync_type=AUTOFILL_PROFILE),
PermanentItem('google_chrome_device_info', name='Device Info',
parent_tag=ROOT_ID, sync_type=DEVICE_INFO),
+ PermanentItem('google_chrome_enhanced_bookmarks',
+ name='Enhanced_Bookmarks',
+ parent_tag=ROOT_ID, sync_type=ENHANCED_BOOKMARK),
PermanentItem('google_chrome_experiments', name='Experiments',
parent_tag=ROOT_ID, sync_type=EXPERIMENTS),
PermanentItem('google_chrome_extension_settings',
diff --git a/sync/util/data_type_histogram.h b/sync/util/data_type_histogram.h
index b5e0eda..980d3cc 100644
--- a/sync/util/data_type_histogram.h
+++ b/sync/util/data_type_histogram.h
@@ -126,6 +126,9 @@
case ::syncer::PROXY_TABS: \
PER_DATA_TYPE_MACRO("Tabs"); \
break; \
+ case ::syncer::ENHANCED_BOOKMARKS: \
+ PER_DATA_TYPE_MACRO("EnhancedBookmarks"); \
+ break; \
default: \
NOTREACHED() << "Unknown datatype " \
<< ::syncer::ModelTypeToString(datatype); \
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index f2740b9..88857ba 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -52052,6 +52052,7 @@ To add a new entry, add it with any value and run test to compute valid value.
<int value="29" label="App list"/>
<int value="30" label="Managed User Shared Settings"/>
<int value="31" label="Synced Notification App Info"/>
+ <int value="32" label="Enhanced Bookmarks"/>
</enum>
<enum name="SyncNigoriMigrationResult" type="int">