diff --git a/chrome/browser/sync/glue/model_association_manager.cc b/chrome/browser/sync/glue/model_association_manager.cc index dfb2ee208bc918..1dbdc85653c417 100644 --- a/chrome/browser/sync/glue/model_association_manager.cc +++ b/chrome/browser/sync/glue/model_association_manager.cc @@ -45,6 +45,7 @@ static const syncer::ModelType kStartOrder[] = { syncer::FAVICON_IMAGES, syncer::FAVICON_TRACKING, syncer::MANAGED_USER_SETTINGS, + syncer::ARTICLES, syncer::AUTOFILL, // Non-UI thread datatypes. syncer::AUTOFILL_PROFILE, syncer::EXTENSION_SETTINGS, diff --git a/chrome/browser/sync/profile_sync_components_factory_impl.cc b/chrome/browser/sync/profile_sync_components_factory_impl.cc index b89217e424ac5d..e734a1e726424c 100644 --- a/chrome/browser/sync/profile_sync_components_factory_impl.cc +++ b/chrome/browser/sync/profile_sync_components_factory_impl.cc @@ -196,6 +196,11 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes( pss->RegisterDataTypeController( new PasswordDataTypeController(this, profile_, pss)); } + // Article sync is disabled by default. Register only if explicitly enabled. + if (command_line_->HasSwitch(switches::kEnableSyncArticles)) { + pss->RegisterDataTypeController( + new UIDataTypeController(syncer::ARTICLES, this, profile_, pss)); + } } void ProfileSyncComponentsFactoryImpl::RegisterDesktopDataTypes( @@ -397,6 +402,9 @@ base::WeakPtr ProfileSyncComponentsFactoryImpl:: return ManagedUserSyncServiceFactory::GetForProfile(profile_)-> AsWeakPtr(); #endif + case syncer::ARTICLES: + // TODO(nyquist) Hook up real syncer::SyncableService API here. + return base::WeakPtr(); 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 38a4feed3f8a05..cdcb655ac8c8b5 100644 --- a/chrome/browser/sync/profile_sync_service.cc +++ b/chrome/browser/sync/profile_sync_service.cc @@ -1538,7 +1538,7 @@ const browser_sync::user_selectable_type::UserSelectableSyncType browser_sync::user_selectable_type::PROXY_TABS }; - COMPILE_ASSERT(28 == syncer::MODEL_TYPE_COUNT, UpdateCustomConfigHistogram); + COMPILE_ASSERT(29 == syncer::MODEL_TYPE_COUNT, UpdateCustomConfigHistogram); if (!sync_everything) { const syncer::ModelTypeSet current_types = GetPreferredDataTypes(); diff --git a/chrome/browser/sync/sync_prefs.cc b/chrome/browser/sync/sync_prefs.cc index a36d8b96003ae0..eeab7c304e14ab 100644 --- a/chrome/browser/sync/sync_prefs.cc +++ b/chrome/browser/sync/sync_prefs.cc @@ -127,6 +127,7 @@ void SyncPrefs::RegisterProfilePrefs( model_set.Put(syncer::APPS); model_set.Put(syncer::TYPED_URLS); model_set.Put(syncer::SESSIONS); + model_set.Put(syncer::ARTICLES); registry->RegisterListPref(prefs::kSyncAcknowledgedSyncTypes, syncer::ModelTypeSetToValue(model_set), user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); @@ -346,6 +347,8 @@ const char* SyncPrefs::GetPrefNameForDataType(syncer::ModelType data_type) { return prefs::kSyncPriorityPreferences; case syncer::MANAGED_USERS: return prefs::kSyncManagedUsers; + case syncer::ARTICLES: + return prefs::kSyncArticles; default: break; } diff --git a/chrome/browser/sync/user_selectable_sync_type.h b/chrome/browser/sync/user_selectable_sync_type.h index 141e72fcea2ccf..be854f0e4f77d1 100644 --- a/chrome/browser/sync/user_selectable_sync_type.h +++ b/chrome/browser/sync/user_selectable_sync_type.h @@ -50,6 +50,7 @@ enum UserSelectableSyncType { // HISTORY_DELETE_DIRECTIVES, // FAVICON_IMAGES, // FAVICON_TRACKING, + // ARTICLE, // Number of sync datatypes exposed to the user via checboxes in the UI. SELECTABLE_DATATYPE_COUNT = 10, diff --git a/chrome/browser/ui/webui/sync_setup_handler.cc b/chrome/browser/ui/webui/sync_setup_handler.cc index 1a7b7c1e85195a..7602d1e65f0929 100644 --- a/chrome/browser/ui/webui/sync_setup_handler.cc +++ b/chrome/browser/ui/webui/sync_setup_handler.cc @@ -94,7 +94,7 @@ const char* kDataTypeNames[] = { "tabs" }; -COMPILE_ASSERT(28 == syncer::MODEL_TYPE_COUNT, +COMPILE_ASSERT(29 == syncer::MODEL_TYPE_COUNT, update_kDataTypeNames_to_match_UserSelectableTypes); typedef std::map ModelTypeNameMap; diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index d7a930cea3829c..95b5a661de24c9 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -756,6 +756,9 @@ const char kEnableSuggestionsTabPage[] = "enable-suggestions-ntp"; const char kEnableSyncSyncedNotifications[] = "enable-sync-synced-notifications"; +// Enables synced articles. +const char kEnableSyncArticles[] = "enable-sync-articles"; + // Enables context menu for selecting groups of tabs. const char kEnableTabGroupsContextMenu[] = "enable-tab-groups-context-menu"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index e6dcc08633a186..c36c9f7999c360 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -214,6 +214,7 @@ extern const char kEnableSpellingAutoCorrect[]; extern const char kEnableSpellingServiceFeedback[]; extern const char kEnableStackedTabStrip[]; extern const char kEnableSuggestionsTabPage[]; +extern const char kEnableSyncArticles[]; extern const char kEnableSyncSyncedNotifications[]; extern const char kEnableTabGroupsContextMenu[]; extern const char kEnableThumbnailRetargeting[]; diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 1ff7bdea70add9..96db1229df9832 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -1782,6 +1782,7 @@ const char kSyncFaviconTracking[] = "sync.favicon_tracking"; const char kSyncHistoryDeleteDirectives[] = "sync.history_delete_directives"; const char kSyncManagedUserSettings[] = "sync.managed_user_settings"; const char kSyncManagedUsers[] = "sync.managed_users"; +const char kSyncArticles[] = "sync.articles"; const char kSyncPasswords[] = "sync.passwords"; const char kSyncPreferences[] = "sync.preferences"; const char kSyncPriorityPreferences[] = "sync.priority_preferences"; diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 3aa63fb769440c..178199849bcd99 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -624,6 +624,7 @@ extern const char kSyncFaviconTracking[]; extern const char kSyncHistoryDeleteDirectives[]; extern const char kSyncManagedUserSettings[]; extern const char kSyncManagedUsers[]; +extern const char kSyncArticles[]; extern const char kSyncPasswords[]; extern const char kSyncPreferences[]; extern const char kSyncPriorityPreferences[]; diff --git a/sync/internal_api/public/base/model_type.h b/sync/internal_api/public/base/model_type.h index 247d351375d7e1..4f512b40627b1c 100644 --- a/sync/internal_api/public/base/model_type.h +++ b/sync/internal_api/public/base/model_type.h @@ -99,6 +99,8 @@ enum ModelType { // by this user and can have restrictions applied. MANAGED_USERS and // MANAGED_USER_SETTINGS can not be encrypted. MANAGED_USERS, + // Distilled articles. + ARTICLES, // ---- Proxy types ---- // Proxy types are excluded from the sync protocol, but are still considered diff --git a/sync/protocol/article_specifics.proto b/sync/protocol/article_specifics.proto new file mode 100644 index 00000000000000..00631fd16ece78 --- /dev/null +++ b/sync/protocol/article_specifics.proto @@ -0,0 +1,29 @@ +// Copyright 2013 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 the article. + +syntax = "proto2"; + +option optimize_for = LITE_RUNTIME; +option retain_unknown_fields = true; + +package sync_pb; + +// Properties of Article objects. +message ArticleSpecifics { + // Next ID to use: 4 + + optional string entry_id = 1; + + optional string title = 2; + + repeated ArticlePage pages = 3; +} + +message ArticlePage { + // Next ID to use: 2 + + optional string url = 1; +} diff --git a/sync/protocol/nigori_specifics.proto b/sync/protocol/nigori_specifics.proto index 6e72ae1493688d..662b94af95e5ff 100644 --- a/sync/protocol/nigori_specifics.proto +++ b/sync/protocol/nigori_specifics.proto @@ -120,5 +120,8 @@ message NigoriSpecifics { // Boolean corresponding to Whether to encrypt favicons data or not. optional bool encrypt_favicon_images = 35; optional bool encrypt_favicon_tracking = 36; + + // Boolean corresponding to whether articles should be encrypted. + optional bool encrypt_articles = 37; } diff --git a/sync/protocol/proto_value_conversions.cc b/sync/protocol/proto_value_conversions.cc index 245f6b4a563c54..1f5a72648a7e5a 100644 --- a/sync/protocol/proto_value_conversions.cc +++ b/sync/protocol/proto_value_conversions.cc @@ -564,6 +564,7 @@ base::DictionaryValue* NigoriSpecificsToValue( SET_BOOL(encrypt_apps); SET_BOOL(encrypt_search_engines); SET_BOOL(encrypt_dictionary); + SET_BOOL(encrypt_articles); SET_BOOL(encrypt_everything); SET_BOOL(sync_tab_favicons); SET_ENUM(passphrase_type, PassphraseTypeString); @@ -573,6 +574,22 @@ base::DictionaryValue* NigoriSpecificsToValue( return value; } +base::DictionaryValue* ArticlePageToValue( + const sync_pb::ArticlePage& proto) { + base::DictionaryValue* value = new base::DictionaryValue(); + SET_STR(url); + return value; +} + +base::DictionaryValue* ArticleSpecificsToValue( + const sync_pb::ArticleSpecifics& proto) { + base::DictionaryValue* value = new base::DictionaryValue(); + SET_STR(entry_id); + SET_STR(title); + SET_REP(pages, ArticlePageToValue); + return value; +} + base::DictionaryValue* PasswordSpecificsToValue( const sync_pb::PasswordSpecifics& proto) { base::DictionaryValue* value = new base::DictionaryValue(); @@ -672,6 +689,7 @@ base::DictionaryValue* EntitySpecificsToValue( SET_FIELD(app, AppSpecificsToValue); SET_FIELD(app_notification, AppNotificationToValue); SET_FIELD(app_setting, AppSettingSpecificsToValue); + SET_FIELD(article, ArticleSpecificsToValue); SET_FIELD(autofill, AutofillSpecificsToValue); SET_FIELD(autofill_profile, AutofillProfileSpecificsToValue); SET_FIELD(bookmark, BookmarkSpecificsToValue); diff --git a/sync/protocol/proto_value_conversions.h b/sync/protocol/proto_value_conversions.h index c7c6cef690ce0a..ee40e2bab15214 100644 --- a/sync/protocol/proto_value_conversions.h +++ b/sync/protocol/proto_value_conversions.h @@ -18,6 +18,7 @@ class AppNotification; class AppNotificationSettings; class AppSettingSpecifics; class AppSpecifics; +class ArticleSpecifics; class AutofillProfileSpecifics; class AutofillSpecifics; class BookmarkSpecifics; @@ -178,6 +179,9 @@ base::DictionaryValue* AppSettingSpecificsToValue( SYNC_EXPORT_PRIVATE base::DictionaryValue* AppSpecificsToValue( const sync_pb::AppSpecifics& app_specifics); +SYNC_EXPORT_PRIVATE base::DictionaryValue* ArticleSpecificsToValue( + const sync_pb::ArticleSpecifics& article_specifics); + SYNC_EXPORT_PRIVATE base::DictionaryValue* AutofillSpecificsToValue( const sync_pb::AutofillSpecifics& autofill_specifics); diff --git a/sync/protocol/proto_value_conversions_unittest.cc b/sync/protocol/proto_value_conversions_unittest.cc index 718a78a60b22ae..3275eb0cd70a03 100644 --- a/sync/protocol/proto_value_conversions_unittest.cc +++ b/sync/protocol/proto_value_conversions_unittest.cc @@ -53,7 +53,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(28, MODEL_TYPE_COUNT); + EXPECT_EQ(29, 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 @@ -219,6 +219,10 @@ TEST_F(ProtoValueConversionsTest, DictionarySpecificsToValue) { TestSpecificsToValue(DictionarySpecificsToValue); } +TEST_F(ProtoValueConversionsTest, ArticleSpecificsToValue) { + TestSpecificsToValue(ArticleSpecificsToValue); +} + // TODO(akalin): Figure out how to better test EntitySpecificsToValue. TEST_F(ProtoValueConversionsTest, EntitySpecificsToValue) { @@ -230,6 +234,7 @@ TEST_F(ProtoValueConversionsTest, EntitySpecificsToValue) { SET_FIELD(app); SET_FIELD(app_notification); SET_FIELD(app_setting); + SET_FIELD(article); SET_FIELD(autofill); SET_FIELD(autofill_profile); SET_FIELD(bookmark); diff --git a/sync/protocol/sync.proto b/sync/protocol/sync.proto index 445fa413840370..5b0c175d9976c2 100644 --- a/sync/protocol/sync.proto +++ b/sync/protocol/sync.proto @@ -17,6 +17,7 @@ package sync_pb; import "app_notification_specifics.proto"; import "app_setting_specifics.proto"; import "app_specifics.proto"; +import "article_specifics.proto"; import "autofill_specifics.proto"; import "bookmark_specifics.proto"; import "client_commands.proto"; @@ -118,6 +119,7 @@ message EntitySpecifics { optional FaviconImageSpecifics favicon_image = 182019; optional ManagedUserSettingSpecifics managed_user_setting = 186662; optional ManagedUserSpecifics managed_user = 194582; + optional ArticleSpecifics article = 223759; } message SyncEntity { diff --git a/sync/sync_proto.gypi b/sync/sync_proto.gypi index bb79b4b4cc763e..4b90525a453f35 100644 --- a/sync/sync_proto.gypi +++ b/sync/sync_proto.gypi @@ -13,6 +13,7 @@ 'protocol/app_notification_specifics.proto', 'protocol/app_setting_specifics.proto', 'protocol/app_specifics.proto', + 'protocol/article_specifics.proto', 'protocol/autofill_specifics.proto', 'protocol/bookmark_specifics.proto', 'protocol/client_commands.proto', diff --git a/sync/syncable/model_type.cc b/sync/syncable/model_type.cc index b9dacbecf155d6..35764131be0d0c 100644 --- a/sync/syncable/model_type.cc +++ b/sync/syncable/model_type.cc @@ -107,6 +107,9 @@ void AddDefaultFieldValue(ModelType datatype, case MANAGED_USERS: specifics->mutable_managed_user(); break; + case ARTICLES: + specifics->mutable_article(); + break; default: NOTREACHED() << "No known extension for model type."; } @@ -197,6 +200,8 @@ int GetSpecificsFieldNumberFromModelType(ModelType model_type) { return sync_pb::EntitySpecifics::kManagedUserSettingFieldNumber; case MANAGED_USERS: return sync_pb::EntitySpecifics::kManagedUserFieldNumber; + case ARTICLES: + return sync_pb::EntitySpecifics::kArticleFieldNumber; default: NOTREACHED() << "No known extension for model type."; return 0; @@ -319,6 +324,9 @@ ModelType GetModelTypeFromSpecifics(const sync_pb::EntitySpecifics& specifics) { if (specifics.has_managed_user()) return MANAGED_USERS; + if (specifics.has_article()) + return ARTICLES; + return UNSPECIFIED; } @@ -484,6 +492,8 @@ const char* ModelTypeToString(ModelType model_type) { return "Managed User Settings"; case MANAGED_USERS: return "Managed Users"; + case ARTICLES: + return "Articles"; case PROXY_TABS: return "Tabs"; default: @@ -555,6 +565,8 @@ int ModelTypeToHistogramInt(ModelType model_type) { return 26; case MANAGED_USERS: return 27; + case ARTICLES: + return 28; // Silence a compiler warning. case MODEL_TYPE_COUNT: return 0; @@ -640,6 +652,8 @@ ModelType ModelTypeFromString(const std::string& model_type_string) { return MANAGED_USER_SETTINGS; else if (model_type_string == "Managed Users") return MANAGED_USERS; + else if (model_type_string == "Articles") + return ARTICLES; else if (model_type_string == "Tabs") return PROXY_TABS; else @@ -732,6 +746,8 @@ std::string ModelTypeToRootTag(ModelType type) { return "google_chrome_managed_user_settings"; case MANAGED_USERS: return "google_chrome_managed_users"; + case ARTICLES: + return "google_chrome_articles"; case PROXY_TABS: return std::string(); default: @@ -771,6 +787,7 @@ const char kFaviconImageNotificationType[] = "FAVICON_IMAGE"; const char kFaviconTrackingNotificationType[] = "FAVICON_TRACKING"; const char kManagedUserSettingNotificationType[] = "MANAGED_USER_SETTING"; const char kManagedUserNotificationType[] = "MANAGED_USER"; +const char kArticleNotificationType[] = "ARTICLE"; } // namespace bool RealModelTypeToNotificationType(ModelType model_type, @@ -851,6 +868,9 @@ bool RealModelTypeToNotificationType(ModelType model_type, case MANAGED_USERS: *notification_type = kManagedUserNotificationType; return true; + case ARTICLES: + *notification_type = kArticleNotificationType; + return true; default: break; } @@ -935,6 +955,9 @@ bool NotificationTypeToRealModelType(const std::string& notification_type, } else if (notification_type == kManagedUserNotificationType) { *model_type = MANAGED_USERS; return true; + } else if (notification_type == kArticleNotificationType) { + *model_type = ARTICLES; + return true; } *model_type = UNSPECIFIED; return false; diff --git a/sync/syncable/nigori_util.cc b/sync/syncable/nigori_util.cc index 9100e9d4fad76b..fbdd9a556847f4 100644 --- a/sync/syncable/nigori_util.cc +++ b/sync/syncable/nigori_util.cc @@ -242,7 +242,7 @@ void UpdateNigoriFromEncryptedTypes(ModelTypeSet encrypted_types, bool encrypt_everything, sync_pb::NigoriSpecifics* nigori) { nigori->set_encrypt_everything(encrypt_everything); - COMPILE_ASSERT(28 == MODEL_TYPE_COUNT, UpdateEncryptedTypes); + COMPILE_ASSERT(29 == MODEL_TYPE_COUNT, UpdateEncryptedTypes); nigori->set_encrypt_bookmarks( encrypted_types.Has(BOOKMARKS)); nigori->set_encrypt_preferences( @@ -268,6 +268,7 @@ void UpdateNigoriFromEncryptedTypes(ModelTypeSet encrypted_types, nigori->set_encrypt_dictionary(encrypted_types.Has(DICTIONARY)); nigori->set_encrypt_favicon_images(encrypted_types.Has(FAVICON_IMAGES)); nigori->set_encrypt_favicon_tracking(encrypted_types.Has(FAVICON_TRACKING)); + nigori->set_encrypt_articles(encrypted_types.Has(ARTICLES)); } ModelTypeSet GetEncryptedTypesFromNigori( @@ -276,7 +277,7 @@ ModelTypeSet GetEncryptedTypesFromNigori( return ModelTypeSet::All(); ModelTypeSet encrypted_types; - COMPILE_ASSERT(28 == MODEL_TYPE_COUNT, UpdateEncryptedTypes); + COMPILE_ASSERT(29 == MODEL_TYPE_COUNT, UpdateEncryptedTypes); if (nigori.encrypt_bookmarks()) encrypted_types.Put(BOOKMARKS); if (nigori.encrypt_preferences()) @@ -309,6 +310,8 @@ ModelTypeSet GetEncryptedTypesFromNigori( encrypted_types.Put(FAVICON_IMAGES); if (nigori.encrypt_favicon_tracking()) encrypted_types.Put(FAVICON_TRACKING); + if (nigori.encrypt_articles()) + encrypted_types.Put(ARTICLES); return encrypted_types; } diff --git a/sync/tools/testserver/chromiumsync.py b/sync/tools/testserver/chromiumsync.py index b95c6be6e4b80f..d8074868c8b70a 100644 --- a/sync/tools/testserver/chromiumsync.py +++ b/sync/tools/testserver/chromiumsync.py @@ -22,6 +22,7 @@ import app_notification_specifics_pb2 import app_setting_specifics_pb2 import app_specifics_pb2 +import article_specifics_pb2 import autofill_specifics_pb2 import bookmark_specifics_pb2 import dictionary_specifics_pb2 @@ -54,6 +55,7 @@ APPS, APP_NOTIFICATION, APP_SETTINGS, + ARTICLE, AUTOFILL, AUTOFILL_PROFILE, BOOKMARK, @@ -75,7 +77,7 @@ TYPED_URL, EXTENSION_SETTINGS, FAVICON_IMAGES, - FAVICON_TRACKING) = range(26) + FAVICON_TRACKING) = range(27) # 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. @@ -95,6 +97,7 @@ APP_NOTIFICATION: SYNC_TYPE_FIELDS['app_notification'], APP_SETTINGS: SYNC_TYPE_FIELDS['app_setting'], APPS: SYNC_TYPE_FIELDS['app'], + ARTICLE: SYNC_TYPE_FIELDS['article'], AUTOFILL: SYNC_TYPE_FIELDS['autofill'], AUTOFILL_PROFILE: SYNC_TYPE_FIELDS['autofill_profile'], BOOKMARK: SYNC_TYPE_FIELDS['bookmark'], @@ -530,6 +533,8 @@ class SyncDataModel(object): parent_tag=ROOT_ID, sync_type=TYPED_URL), PermanentItem('google_chrome_dictionary', name='Dictionary', parent_tag=ROOT_ID, sync_type=DICTIONARY), + PermanentItem('google_chrome_articles', name='Articles', + parent_tag=ROOT_ID, sync_type=ARTICLE), ] def __init__(self): diff --git a/sync/util/data_type_histogram.h b/sync/util/data_type_histogram.h index 5c8e840a74e103..01a2ba0155123f 100644 --- a/sync/util/data_type_histogram.h +++ b/sync/util/data_type_histogram.h @@ -111,6 +111,9 @@ case ::syncer::MANAGED_USERS: \ PER_DATA_TYPE_MACRO("ManagedUser"); \ break; \ + case ::syncer::ARTICLES: \ + PER_DATA_TYPE_MACRO("Article"); \ + break; \ case ::syncer::PROXY_TABS: \ PER_DATA_TYPE_MACRO("Tabs"); \ break; \