summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorstevenjb@chromium.org <stevenjb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-11 20:04:58 +0000
committerstevenjb@chromium.org <stevenjb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-11 20:04:58 +0000
commit3bc627156b7c1594df0ae95407e6b9d18f5b7343 (patch)
treeb7261fda0637408bd3d404b048227310dd6f2f02
parentbcbb9b4e583a1e068871ef591ae7f8590707eca7 (diff)
downloadchromium_src-3bc627156b7c1594df0ae95407e6b9d18f5b7343.zip
chromium_src-3bc627156b7c1594df0ae95407e6b9d18f5b7343.tar.gz
chromium_src-3bc627156b7c1594df0ae95407e6b9d18f5b7343.tar.bz2
Add AppListSpecifics .proto definition and support code
This CL introduces the AppList sync type. As of patchset #7 this CL depends on https://codereview.chromium.org/106033003/ BUG=313376 Review URL: https://codereview.chromium.org/78773004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@240162 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/sync/glue/model_association_manager.cc1
-rw-r--r--chrome/browser/sync/profile_sync_components_factory_impl.cc15
-rw-r--r--chrome/browser/sync/profile_sync_service.cc2
-rw-r--r--chrome/browser/sync/sync_prefs.cc4
-rw-r--r--chrome/browser/sync/sync_prefs_unittest.cc1
-rw-r--r--chrome/browser/sync/user_selectable_sync_type.h1
-rw-r--r--chrome/browser/ui/app_list/app_list_syncable_service.cc296
-rw-r--r--chrome/browser/ui/app_list/app_list_syncable_service.h87
-rw-r--r--chrome/browser/ui/webui/sync_setup_handler.cc4
-rw-r--r--chrome/common/chrome_switches.cc5
-rw-r--r--chrome/common/chrome_switches.h1
-rw-r--r--chrome/common/pref_names.cc1
-rw-r--r--chrome/common/pref_names.h1
-rw-r--r--sync/internal_api/public/base/model_type.h2
-rw-r--r--sync/protocol/app_list_specifics.proto49
-rw-r--r--sync/protocol/nigori_specifics.proto3
-rw-r--r--sync/protocol/proto_enum_conversions.cc14
-rw-r--r--sync/protocol/proto_enum_conversions.h4
-rw-r--r--sync/protocol/proto_enum_conversions_unittest.cc7
-rw-r--r--sync/protocol/proto_value_conversions.cc16
-rw-r--r--sync/protocol/proto_value_conversions.h5
-rw-r--r--sync/protocol/proto_value_conversions_unittest.cc7
-rw-r--r--sync/protocol/sync.proto2
-rw-r--r--sync/sync_proto.gypi1
-rw-r--r--sync/syncable/model_type.cc24
-rw-r--r--sync/syncable/nigori_util.cc7
-rw-r--r--sync/tools/testserver/chromiumsync.py7
-rw-r--r--sync/util/data_type_histogram.h3
28 files changed, 557 insertions, 13 deletions
diff --git a/chrome/browser/sync/glue/model_association_manager.cc b/chrome/browser/sync/glue/model_association_manager.cc
index 1dbdc85..2d5f084 100644
--- a/chrome/browser/sync/glue/model_association_manager.cc
+++ b/chrome/browser/sync/glue/model_association_manager.cc
@@ -37,6 +37,7 @@ static const syncer::ModelType kStartOrder[] = {
syncer::PRIORITY_PREFERENCES,
syncer::EXTENSIONS,
syncer::APPS,
+ syncer::APP_LIST,
syncer::THEMES,
syncer::SEARCH_ENGINES,
syncer::SESSIONS,
diff --git a/chrome/browser/sync/profile_sync_components_factory_impl.cc b/chrome/browser/sync/profile_sync_components_factory_impl.cc
index 0026d70..f8b5eb4 100644
--- a/chrome/browser/sync/profile_sync_components_factory_impl.cc
+++ b/chrome/browser/sync/profile_sync_components_factory_impl.cc
@@ -57,6 +57,8 @@
#include "chrome/browser/themes/theme_service.h"
#include "chrome/browser/themes/theme_service_factory.h"
#include "chrome/browser/themes/theme_syncable_service.h"
+#include "chrome/browser/ui/app_list/app_list_syncable_service.h"
+#include "chrome/browser/ui/app_list/app_list_syncable_service_factory.h"
#include "chrome/browser/webdata/autocomplete_syncable_service.h"
#include "chrome/browser/webdata/autofill_profile_syncable_service.h"
#include "chrome/browser/webdata/web_data_service_factory.h"
@@ -290,6 +292,14 @@ void ProfileSyncComponentsFactoryImpl::RegisterDesktopDataTypes(
syncer::APP_SETTINGS, this, profile_, pss));
}
+#if defined(ENABLE_APP_LIST)
+ // App List sync is disabled by default. Register only if enabled.
+ if (command_line_->HasSwitch(switches::kEnableSyncAppList)) {
+ pss->RegisterDataTypeController(
+ new UIDataTypeController(syncer::APP_LIST, this, profile_, pss));
+ }
+#endif
+
// Synced Notifications are enabled by default.
pss->RegisterDataTypeController(
new UIDataTypeController(
@@ -379,6 +389,11 @@ base::WeakPtr<syncer::SyncableService> ProfileSyncComponentsFactoryImpl::
case syncer::EXTENSION_SETTINGS:
return extension_system_->extension_service()->settings_frontend()->
GetBackendForSync(type)->AsWeakPtr();
+#if defined(ENABLE_APP_LIST)
+ case syncer::APP_LIST:
+ return app_list::AppListSyncableServiceFactory::GetForProfile(profile_)->
+ AsWeakPtr();
+#endif
#if defined(ENABLE_THEMES)
case syncer::THEMES:
return ThemeServiceFactory::GetForProfile(profile_)->
diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc
index 89f5b0d9..fd81590 100644
--- a/chrome/browser/sync/profile_sync_service.cc
+++ b/chrome/browser/sync/profile_sync_service.cc
@@ -1618,7 +1618,7 @@ const browser_sync::user_selectable_type::UserSelectableSyncType
browser_sync::user_selectable_type::PROXY_TABS
};
- COMPILE_ASSERT(29 == syncer::MODEL_TYPE_COUNT, UpdateCustomConfigHistogram);
+ COMPILE_ASSERT(30 == 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 6512949..57b68a4 100644
--- a/chrome/browser/sync/sync_prefs.cc
+++ b/chrome/browser/sync/sync_prefs.cc
@@ -126,6 +126,7 @@ void SyncPrefs::RegisterProfilePrefs(
model_set.Put(syncer::NIGORI);
model_set.Put(syncer::SEARCH_ENGINES);
model_set.Put(syncer::APPS);
+ model_set.Put(syncer::APP_LIST);
model_set.Put(syncer::TYPED_URLS);
model_set.Put(syncer::SESSIONS);
model_set.Put(syncer::ARTICLES);
@@ -308,6 +309,8 @@ const char* SyncPrefs::GetPrefNameForDataType(syncer::ModelType data_type) {
return prefs::kSyncExtensionSettings;
case syncer::EXTENSIONS:
return prefs::kSyncExtensions;
+ case syncer::APP_LIST:
+ return prefs::kSyncAppList;
case syncer::APP_SETTINGS:
return prefs::kSyncAppSettings;
case syncer::APPS:
@@ -391,6 +394,7 @@ syncer::ModelTypeSet SyncPrefs::GetAcknowledgeSyncedTypesForTest() const {
void SyncPrefs::RegisterPrefGroups() {
pref_groups_[syncer::APPS].Put(syncer::APP_NOTIFICATIONS);
pref_groups_[syncer::APPS].Put(syncer::APP_SETTINGS);
+ pref_groups_[syncer::APPS].Put(syncer::APP_LIST);
pref_groups_[syncer::AUTOFILL].Put(syncer::AUTOFILL_PROFILE);
diff --git a/chrome/browser/sync/sync_prefs_unittest.cc b/chrome/browser/sync/sync_prefs_unittest.cc
index 357ae27..6356ebe 100644
--- a/chrome/browser/sync/sync_prefs_unittest.cc
+++ b/chrome/browser/sync/sync_prefs_unittest.cc
@@ -147,6 +147,7 @@ TEST_F(SyncPrefsTest, PreferredTypesNotKeepEverythingSynced) {
expected_preferred_types.Put(syncer::SEARCH_ENGINES);
}
if (it.Get() == syncer::APPS) {
+ expected_preferred_types.Put(syncer::APP_LIST);
expected_preferred_types.Put(syncer::APP_NOTIFICATIONS);
expected_preferred_types.Put(syncer::APP_SETTINGS);
}
diff --git a/chrome/browser/sync/user_selectable_sync_type.h b/chrome/browser/sync/user_selectable_sync_type.h
index be854f0..5c02372 100644
--- a/chrome/browser/sync/user_selectable_sync_type.h
+++ b/chrome/browser/sync/user_selectable_sync_type.h
@@ -40,6 +40,7 @@ enum UserSelectableSyncType {
// NIGORI,
// DICTIONARY
// SEARCH_ENGINES,
+ // APP_LIST,
// APP_SETTINGS,
// EXTENSION_SETTINGS,
// APP_NOTIFICATIONS,
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service.cc b/chrome/browser/ui/app_list/app_list_syncable_service.cc
index fd058da..2d0023a 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service.cc
+++ b/chrome/browser/ui/app_list/app_list_syncable_service.cc
@@ -11,10 +11,82 @@
#include "chrome/browser/ui/app_list/extension_app_model_builder.h"
#include "chrome/browser/ui/host_desktop.h"
#include "content/public/browser/notification_source.h"
+#include "sync/api/sync_change_processor.h"
+#include "sync/api/sync_data.h"
+#include "sync/api/sync_merge_result.h"
+#include "sync/protocol/sync.pb.h"
+#include "ui/app_list/app_list_item_model.h"
#include "ui/app_list/app_list_model.h"
+using syncer::SyncChange;
+
namespace app_list {
+namespace {
+
+void UpdateSyncItemFromSync(const sync_pb::AppListSpecifics& specifics,
+ AppListSyncableService::SyncItem* item) {
+ DCHECK_EQ(item->item_id, specifics.item_id());
+ item->item_type = specifics.item_type();
+ item->item_name = specifics.item_name();
+ item->parent_id = specifics.parent_id();
+ if (!specifics.page_ordinal().empty())
+ item->page_ordinal = syncer::StringOrdinal(specifics.page_ordinal());
+ if (!specifics.item_ordinal().empty())
+ item->item_ordinal = syncer::StringOrdinal(specifics.item_ordinal());
+}
+
+bool UpdateSyncItemFromAppItem(const AppListItemModel* app_item,
+ AppListSyncableService::SyncItem* sync_item) {
+ DCHECK_EQ(sync_item->item_id, app_item->id());
+ bool changed = false;
+ if (!sync_item->item_ordinal.IsValid() ||
+ !app_item->position().Equals(sync_item->item_ordinal)) {
+ sync_item->item_ordinal = app_item->position();
+ changed = true;
+ }
+ // TODO(stevenjb): Set parent_id and page_ordinal.
+ return changed;
+}
+
+void GetSyncSpecificsFromSyncItem(const AppListSyncableService::SyncItem* item,
+ sync_pb::AppListSpecifics* specifics) {
+ DCHECK(specifics);
+ specifics->set_item_id(item->item_id);
+ specifics->set_item_type(item->item_type);
+ specifics->set_item_name(item->item_name);
+ specifics->set_parent_id(item->parent_id);
+ if (item->page_ordinal.IsValid())
+ specifics->set_page_ordinal(item->page_ordinal.ToInternalValue());
+ if (item->item_ordinal.IsValid())
+ specifics->set_item_ordinal(item->item_ordinal.ToInternalValue());
+}
+
+syncer::SyncData GetSyncDataFromSyncItem(
+ const AppListSyncableService::SyncItem* item) {
+ sync_pb::EntitySpecifics specifics;
+ GetSyncSpecificsFromSyncItem(item, specifics.mutable_app_list());
+ return syncer::SyncData::CreateLocalData(item->item_id,
+ item->item_id,
+ specifics);
+}
+
+} // namespace
+
+// AppListSyncableService::SyncItem
+
+AppListSyncableService::SyncItem::SyncItem(
+ const std::string& id,
+ sync_pb::AppListSpecifics::AppListItemType type)
+ : item_id(id),
+ item_type(type) {
+}
+
+AppListSyncableService::SyncItem::~SyncItem() {
+}
+
+// AppListSyncableService
+
AppListSyncableService::AppListSyncableService(
Profile* profile,
ExtensionService* extension_service)
@@ -31,6 +103,7 @@ AppListSyncableService::AppListSyncableService(
}
AppListSyncableService::~AppListSyncableService() {
+ STLDeleteContainerPairSecondPointers(sync_items_.begin(), sync_items_.end());
}
void AppListSyncableService::BuildModel() {
@@ -46,7 +119,7 @@ void AppListSyncableService::BuildModel() {
apps_builder_.reset(
new ExtensionAppModelBuilder(profile_, model_.get(), controller));
DCHECK(profile_);
- VLOG(1) << "AppListSyncableService Created.";
+ DVLOG(1) << "AppListSyncableService Created.";
}
void AppListSyncableService::Observe(
@@ -59,4 +132,225 @@ void AppListSyncableService::Observe(
BuildModel();
}
+void AppListSyncableService::RemoveItem(const std::string& id) {
+ SyncItemMap::iterator iter = sync_items_.find(id);
+ if (iter == sync_items_.end())
+ return;
+ SyncItem* sync_item = iter->second;
+ if (SyncStarted()) {
+ SyncChange sync_change(FROM_HERE, SyncChange::ACTION_DELETE,
+ GetSyncDataFromSyncItem(sync_item));
+ sync_processor_->ProcessSyncChanges(
+ FROM_HERE, syncer::SyncChangeList(1, sync_change));
+ }
+ delete sync_item;
+ sync_items_.erase(iter);
+ model_->item_list()->DeleteItem(id);
+}
+
+// AppListSyncableService syncer::SyncableService
+
+syncer::SyncMergeResult AppListSyncableService::MergeDataAndStartSyncing(
+ syncer::ModelType type,
+ const syncer::SyncDataList& initial_sync_data,
+ scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
+ scoped_ptr<syncer::SyncErrorFactory> error_handler) {
+ DCHECK(!sync_processor_.get());
+ DCHECK(sync_processor.get());
+ DCHECK(error_handler.get());
+
+ sync_processor_ = sync_processor.Pass();
+ sync_error_handler_ = error_handler.Pass();
+
+ syncer::SyncMergeResult result = syncer::SyncMergeResult(type);
+ result.set_num_items_before_association(sync_items_.size());
+
+ // Copy all sync items to |unsynced_items|.
+ std::set<std::string> unsynced_items;
+ for (SyncItemMap::const_iterator iter = sync_items_.begin();
+ iter != sync_items_.end(); ++iter) {
+ unsynced_items.insert(iter->first);
+ }
+
+ // Create SyncItem entries for initial_sync_data.
+ size_t new_items = 0, updated_items = 0;
+ DVLOG(1) << "MergeDataAndStartSyncing: " << initial_sync_data.size();
+ for (syncer::SyncDataList::const_iterator iter = initial_sync_data.begin();
+ iter != initial_sync_data.end(); ++iter) {
+ const syncer::SyncData& data = *iter;
+ DCHECK_EQ(syncer::APP_LIST, data.GetDataType());
+ if (CreateOrUpdateSyncItem(data.GetSpecifics().app_list()))
+ ++new_items;
+ else
+ ++updated_items;
+ unsynced_items.erase(data.GetSpecifics().app_list().item_id());
+ }
+
+ result.set_num_items_after_association(sync_items_.size());
+ result.set_num_items_added(new_items);
+ result.set_num_items_deleted(0);
+ result.set_num_items_modified(updated_items);
+
+ // Send unsynced items. Does not affect |result|.
+ syncer::SyncChangeList change_list;
+ for (std::set<std::string>::iterator iter = unsynced_items.begin();
+ iter != unsynced_items.end(); ++iter) {
+ SyncItem* sync_item = FindSyncItem(*iter);
+ change_list.push_back(SyncChange(FROM_HERE, SyncChange::ACTION_ADD,
+ GetSyncDataFromSyncItem(sync_item)));
+ }
+ sync_processor_->ProcessSyncChanges(FROM_HERE, change_list);
+
+ return result;
+}
+
+void AppListSyncableService::StopSyncing(syncer::ModelType type) {
+ DCHECK_EQ(type, syncer::APP_LIST);
+
+ sync_processor_.reset();
+ sync_error_handler_.reset();
+}
+
+syncer::SyncDataList AppListSyncableService::GetAllSyncData(
+ syncer::ModelType type) const {
+ DCHECK_EQ(syncer::APP_LIST, type);
+
+ syncer::SyncDataList list;
+ for (SyncItemMap::const_iterator iter = sync_items_.begin();
+ iter != sync_items_.end(); ++iter) {
+ list.push_back(GetSyncDataFromSyncItem(iter->second));
+ }
+ return list;
+}
+
+syncer::SyncError AppListSyncableService::ProcessSyncChanges(
+ const tracked_objects::Location& from_here,
+ const syncer::SyncChangeList& change_list) {
+ if (!sync_processor_.get()) {
+ return syncer::SyncError(FROM_HERE,
+ syncer::SyncError::DATATYPE_ERROR,
+ "App List syncable service is not started.",
+ syncer::APP_LIST);
+ }
+
+ DVLOG(1) << "ProcessSyncChanges: " << change_list.size();
+ for (syncer::SyncChangeList::const_iterator iter = change_list.begin();
+ iter != change_list.end(); ++iter) {
+ const SyncChange& change = *iter;
+ if (change.change_type() == SyncChange::ACTION_ADD ||
+ change.change_type() == SyncChange::ACTION_UPDATE) {
+ CreateOrUpdateSyncItem(change.sync_data().GetSpecifics().app_list());
+ } else if (change.change_type() == SyncChange::ACTION_DELETE) {
+ DeleteSyncItem(change.sync_data().GetSpecifics().app_list());
+ } else {
+ LOG(WARNING) << "Invalid sync change";
+ }
+ }
+ return syncer::SyncError();
+}
+
+// AppListSyncableService private
+
+bool AppListSyncableService::SyncStarted() {
+ if (sync_processor_.get())
+ return true;
+ if (flare_.is_null()) {
+ flare_ = sync_start_util::GetFlareForSyncableService(profile_->GetPath());
+ flare_.Run(syncer::APP_LIST);
+ }
+ return false;
+}
+
+AppListSyncableService::SyncItem* AppListSyncableService::AddItem(
+ sync_pb::AppListSpecifics::AppListItemType type,
+ AppListItemModel* app_item) {
+ const std::string& item_id = app_item->id();
+ if (item_id.empty()) {
+ LOG(ERROR) << "AppListItemModel item with empty ID";
+ return NULL;
+ }
+ bool new_item = false;
+ SyncItem* sync_item = FindOrCreateSyncItem(item_id, type, &new_item);
+ DVLOG(1) << "Add AppListItemModel: " << item_id << " New: " << new_item;
+ UpdateSyncItemFromAppItem(app_item, sync_item);
+ if (SyncStarted()) {
+ SyncChange sync_change(FROM_HERE, SyncChange::ACTION_ADD,
+ GetSyncDataFromSyncItem(sync_item));
+ sync_processor_->ProcessSyncChanges(
+ FROM_HERE, syncer::SyncChangeList(1, sync_change));
+ }
+ return sync_item;
+}
+
+void AppListSyncableService::UpdateItem(AppListItemModel* item) {
+ SyncItemMap::iterator iter = sync_items_.find(item->id());
+ if (iter == sync_items_.end()) {
+ LOG(ERROR) << "UpdateItem: no sync item: " << item->id();
+ return;
+ }
+ SyncItem* sync_item = iter->second;
+ if (!UpdateSyncItemFromAppItem(item, sync_item))
+ return; // No change.
+ if (!SyncStarted())
+ return;
+ SyncChange sync_change(FROM_HERE, SyncChange::ACTION_UPDATE,
+ GetSyncDataFromSyncItem(sync_item));
+ sync_processor_->ProcessSyncChanges(
+ FROM_HERE, syncer::SyncChangeList(1, sync_change));
+}
+
+AppListSyncableService::SyncItem*
+AppListSyncableService::FindSyncItem(const std::string& item_id) {
+ SyncItemMap::iterator iter = sync_items_.find(item_id);
+ if (iter == sync_items_.end())
+ return NULL;
+ return iter->second;
+}
+
+AppListSyncableService::SyncItem* AppListSyncableService::FindOrCreateSyncItem(
+ const std::string& item_id,
+ sync_pb::AppListSpecifics::AppListItemType type,
+ bool* new_item) {
+ SyncItem* item = FindSyncItem(item_id);
+ if (item) {
+ DCHECK(type == item->item_type);
+ *new_item = false;
+ return item;
+ }
+
+ item = new SyncItem(item_id, type);
+ sync_items_[item_id] = item;
+ *new_item = true;
+ return item;
+}
+
+bool AppListSyncableService::CreateOrUpdateSyncItem(
+ const sync_pb::AppListSpecifics& specifics) {
+ const std::string& item_id = specifics.item_id();
+ if (item_id.empty()) {
+ LOG(ERROR) << "CreateOrUpdate AppList item with empty ID";
+ return false;
+ }
+ bool new_item = false;
+ SyncItem* sync_item =
+ FindOrCreateSyncItem(item_id, specifics.item_type(), &new_item);
+ UpdateSyncItemFromSync(specifics, sync_item);
+ // TODO(stevenjb): Add or update AppItem item in model.
+ return new_item;
+}
+
+void AppListSyncableService::DeleteSyncItem(
+ const sync_pb::AppListSpecifics& specifics) {
+ const std::string& item_id = specifics.item_id();
+ if (item_id.empty()) {
+ LOG(ERROR) << "Delete AppList item with empty ID";
+ return;
+ }
+ SyncItemMap::iterator iter = sync_items_.find(item_id);
+ if (iter == sync_items_.end())
+ return;
+ delete iter->second;
+ sync_items_.erase(iter);
+}
+
} // namespace app_list
diff --git a/chrome/browser/ui/app_list/app_list_syncable_service.h b/chrome/browser/ui/app_list/app_list_syncable_service.h
index 52ec423..30d3d5a 100644
--- a/chrome/browser/ui/app_list/app_list_syncable_service.h
+++ b/chrome/browser/ui/app_list/app_list_syncable_service.h
@@ -5,45 +5,124 @@
#ifndef CHROME_BROWSER_UI_APP_LIST_APP_LIST_SYNCABLE_SERVICE_H_
#define CHROME_BROWSER_UI_APP_LIST_APP_LIST_SYNCABLE_SERVICE_H_
+#include <map>
+
#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/sync/glue/sync_start_util.h"
#include "components/browser_context_keyed_service/browser_context_keyed_service.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
+#include "sync/api/string_ordinal.h"
+#include "sync/api/sync_change.h"
+#include "sync/api/sync_change_processor.h"
+#include "sync/api/sync_error_factory.h"
+#include "sync/api/syncable_service.h"
+#include "sync/protocol/app_list_specifics.pb.h"
class ExtensionAppModelBuilder;
class ExtensionService;
class Profile;
+namespace sync_pb {
+class AppListSpecifics;
+}
+
namespace app_list {
class AppListModel;
+class AppListItemModel;
// Keyed Service that owns, stores, and syncs an AppListModel for an
// ExtensionSystem and corresponding profile.
-// TODO(stevenjb): Integrate with Sync. crbug.com/305024.
-class AppListSyncableService : public BrowserContextKeyedService,
+class AppListSyncableService : public syncer::SyncableService,
+ public BrowserContextKeyedService,
public content::NotificationObserver {
public:
+ struct SyncItem {
+ SyncItem(const std::string& id,
+ sync_pb::AppListSpecifics::AppListItemType type);
+ ~SyncItem();
+ const std::string item_id;
+ sync_pb::AppListSpecifics::AppListItemType item_type;
+ std::string item_name;
+ std::string parent_id;
+ syncer::StringOrdinal page_ordinal;
+ syncer::StringOrdinal item_ordinal;
+ };
+
// Create an empty model. Then, if |extension_service| is non-NULL and ready,
// populate it. Otherwise populate the model once extensions become ready.
AppListSyncableService(Profile* profile, ExtensionService* extension_service);
virtual ~AppListSyncableService();
+ // TODO(stevenjb): Implement specific Add and Update methods for
+ // ExtensionAppItem, etc.
+
+ // Removes sync item matching |id|.
+ void RemoveItem(const std::string& id);
+
AppListModel* model() { return model_.get(); }
+ // syncer::SyncableService
+ virtual syncer::SyncMergeResult MergeDataAndStartSyncing(
+ syncer::ModelType type,
+ const syncer::SyncDataList& initial_sync_data,
+ scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
+ scoped_ptr<syncer::SyncErrorFactory> error_handler) OVERRIDE;
+ virtual void StopSyncing(syncer::ModelType type) OVERRIDE;
+ virtual syncer::SyncDataList GetAllSyncData(
+ syncer::ModelType type) const OVERRIDE;
+ virtual syncer::SyncError ProcessSyncChanges(
+ const tracked_objects::Location& from_here,
+ const syncer::SyncChangeList& change_list) OVERRIDE;
+
private:
- void BuildModel();
+ typedef std::map<std::string, SyncItem*> SyncItemMap;
- // content::NotificationObserver:
+ // content::NotificationObserver
virtual void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE;
+ // Builds the model once ExtensionService is ready.
+ void BuildModel();
+
+ // Returns true if sync has started, otherwise creates and runs |flare_|.
+ bool SyncStarted();
+
+ // Common functionality for adding items.
+ SyncItem* AddItem(sync_pb::AppListSpecifics::AppListItemType type,
+ AppListItemModel* item);
+
+ // Common functionality for updating items.
+ void UpdateItem(AppListItemModel* item);
+
+ // Returns an existing SyncItem corresponding to |item_id| or NULL.
+ SyncItem* FindSyncItem(const std::string& item_id);
+
+ // Returns a SyncItem corresponding to |item_id|. Sets |new_item| if an item
+ // was created.
+ SyncItem* FindOrCreateSyncItem(
+ const std::string& item_id,
+ sync_pb::AppListSpecifics::AppListItemType type,
+ bool* new_item);
+
+ // Creates or updates a SyncItem from |specifics|. Returns true if an item
+ // was created.
+ bool CreateOrUpdateSyncItem(const sync_pb::AppListSpecifics& specifics);
+
+ // Deletes a SyncItem matching |specifics|.
+ void DeleteSyncItem(const sync_pb::AppListSpecifics& specifics);
+
Profile* profile_;
content::NotificationRegistrar registrar_;
scoped_ptr<AppListModel> model_;
scoped_ptr<ExtensionAppModelBuilder> apps_builder_;
+ scoped_ptr<syncer::SyncChangeProcessor> sync_processor_;
+ scoped_ptr<syncer::SyncErrorFactory> sync_error_handler_;
+ SyncItemMap sync_items_;
+ syncer::SyncableService::StartSyncFlare flare_;
DISALLOW_COPY_AND_ASSIGN(AppListSyncableService);
};
diff --git a/chrome/browser/ui/webui/sync_setup_handler.cc b/chrome/browser/ui/webui/sync_setup_handler.cc
index 8d595ec..c9cab92 100644
--- a/chrome/browser/ui/webui/sync_setup_handler.cc
+++ b/chrome/browser/ui/webui/sync_setup_handler.cc
@@ -95,7 +95,7 @@ const char* kDataTypeNames[] = {
"tabs"
};
-COMPILE_ASSERT(29 == syncer::MODEL_TYPE_COUNT,
+COMPILE_ASSERT(30 == syncer::MODEL_TYPE_COUNT,
update_kDataTypeNames_to_match_UserSelectableTypes);
typedef std::map<syncer::ModelType, const char*> ModelTypeNameMap;
@@ -752,7 +752,7 @@ void SyncSetupHandler::HandleShowSetupUI(const ListValue* args) {
// On ChromeOS, we need to sign out the user session to fix an auth error, so
// the user goes through the real signin flow to generate a new auth token.
void SyncSetupHandler::HandleDoSignOutOnAuthError(const ListValue* args) {
- DLOG(INFO) << "Signing out the user to fix a sync error.";
+ DVLOG(1) << "Signing out the user to fix a sync error.";
chrome::AttemptUserExit();
}
#endif
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 3d18344..f1d3e95 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -762,8 +762,11 @@ const char kEnableSyncSyncedNotifications[] =
// Enables sync/API based session sync implementation (in favor of legacy).
const char kEnableSyncSessionsV2[] = "enable-sync-sessions-v2";
+// Enables syncing of the app list.
+const char kEnableSyncAppList[] = "enable-sync-app-list";
+
// Enables synced articles.
-const char kEnableSyncArticles[] = "enable-sync-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 6caacba..a9ac5f8 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -216,6 +216,7 @@ extern const char kEnableSpellingFeedbackFieldTrial[];
extern const char kEnableStackedTabStrip[];
extern const char kEnableStreamlinedHostedApps[];
extern const char kEnableSuggestionsTabPage[];
+extern const char kEnableSyncAppList[];
extern const char kEnableSyncArticles[];
extern const char kEnableSyncSyncedNotifications[];
extern const char kEnableSyncSessionsV2[];
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 6d16bfd..62b23ba 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1827,6 +1827,7 @@ const char kSyncKeepEverythingSynced[] = "sync.keep_everything_synced";
// Booleans specifying whether the user has selected to sync the following
// datatypes.
+const char kSyncAppList[] = "sync.app_list";
const char kSyncAppNotifications[] = "sync.app_notifications";
const char kSyncAppSettings[] = "sync.app_settings";
const char kSyncApps[] = "sync.apps";
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index b3f3651..0249ece 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -609,6 +609,7 @@ extern const char kSyncHasAuthError[];
extern const char kSyncHasSetupCompleted[];
extern const char kSyncKeepEverythingSynced[];
+extern const char kSyncAppList[];
extern const char kSyncAppNotifications[];
extern const char kSyncAppSettings[];
extern const char kSyncApps[];
diff --git a/sync/internal_api/public/base/model_type.h b/sync/internal_api/public/base/model_type.h
index 4f512b4..c618c450 100644
--- a/sync/internal_api/public/base/model_type.h
+++ b/sync/internal_api/public/base/model_type.h
@@ -101,6 +101,8 @@ enum ModelType {
MANAGED_USERS,
// Distilled articles.
ARTICLES,
+ // App List items
+ APP_LIST,
// ---- Proxy types ----
// Proxy types are excluded from the sync protocol, but are still considered
diff --git a/sync/protocol/app_list_specifics.proto b/sync/protocol/app_list_specifics.proto
new file mode 100644
index 0000000..c677a4b
--- /dev/null
+++ b/sync/protocol/app_list_specifics.proto
@@ -0,0 +1,49 @@
+// 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 app list (aka app launcher).
+
+// Update proto_{value,enum}_conversions{.h,.cc,_unittest.cc} if you change
+// any fields in this file.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+option retain_unknown_fields = true;
+
+package sync_pb;
+
+// Properties of app list objects.
+message AppListSpecifics {
+ // Unique identifier for the item:
+ // * TYPE_FOLDER: Folder id (generated)
+ // * TYPE_APP: App Id
+ // * TYPE_URL: Url
+ optional string item_id = 1;
+
+ // What type of item this is.
+ enum AppListItemType {
+ // An extension app.
+ TYPE_APP = 1;
+ // A request to remove any matching default installed apps.
+ TYPE_REMOVE_DEFAULT_APP = 2;
+ // A folder containing entries whose |parent_id| matches |item_id|.
+ TYPE_FOLDER = 3;
+ // A URL shortcut (functionally equivalent to a bookmark).
+ TYPE_URL = 4;
+ }
+ optional AppListItemType item_type = 2;
+
+ // Item name (FOLDER or URL).
+ optional string item_name = 3;
+
+ // Id of the parent (folder) item.
+ optional string parent_id = 4;
+
+ // Which page this item will appear on in the app list.
+ optional string page_ordinal = 5;
+
+ // Where on a page this item will appear.
+ optional string item_ordinal = 6;
+}
diff --git a/sync/protocol/nigori_specifics.proto b/sync/protocol/nigori_specifics.proto
index 662b94a..87e6c37 100644
--- a/sync/protocol/nigori_specifics.proto
+++ b/sync/protocol/nigori_specifics.proto
@@ -123,5 +123,8 @@ message NigoriSpecifics {
// Boolean corresponding to whether articles should be encrypted.
optional bool encrypt_articles = 37;
+
+ // Boolean corresponding to whether app list items should be encrypted.
+ optional bool encrypt_app_list = 38;
}
diff --git a/sync/protocol/proto_enum_conversions.cc b/sync/protocol/proto_enum_conversions.cc
index 3183633d..af95822 100644
--- a/sync/protocol/proto_enum_conversions.cc
+++ b/sync/protocol/proto_enum_conversions.cc
@@ -20,6 +20,20 @@ namespace syncer {
#define ENUM_CASE(enum_parent, enum_value) \
case enum_parent::enum_value: return #enum_value
+const char* GetAppListItemTypeString(
+ sync_pb::AppListSpecifics::AppListItemType item_type) {
+ ASSERT_ENUM_BOUNDS(sync_pb::AppListSpecifics, AppListItemType,
+ TYPE_APP, TYPE_URL);
+ switch (item_type) {
+ ENUM_CASE(sync_pb::AppListSpecifics, TYPE_APP);
+ ENUM_CASE(sync_pb::AppListSpecifics, TYPE_REMOVE_DEFAULT_APP);
+ ENUM_CASE(sync_pb::AppListSpecifics, TYPE_FOLDER);
+ ENUM_CASE(sync_pb::AppListSpecifics, TYPE_URL);
+ }
+ NOTREACHED();
+ return "";
+}
+
const char* GetBrowserTypeString(
sync_pb::SessionWindow::BrowserType browser_type) {
ASSERT_ENUM_BOUNDS(sync_pb::SessionWindow, BrowserType,
diff --git a/sync/protocol/proto_enum_conversions.h b/sync/protocol/proto_enum_conversions.h
index b6d84fa..6812cb7 100644
--- a/sync/protocol/proto_enum_conversions.h
+++ b/sync/protocol/proto_enum_conversions.h
@@ -8,6 +8,7 @@
// Keep this file in sync with the .proto files in this directory.
#include "sync/base/sync_export.h"
+#include "sync/protocol/app_list_specifics.pb.h"
#include "sync/protocol/client_debug_info.pb.h"
#include "sync/protocol/session_specifics.pb.h"
#include "sync/protocol/sync.pb.h"
@@ -20,6 +21,9 @@ namespace syncer {
// The returned strings (which don't have to be freed) are in ASCII.
// The result of passing in an invalid enum value is undefined.
+SYNC_EXPORT_PRIVATE const char* GetAppListItemTypeString(
+ sync_pb::AppListSpecifics::AppListItemType item_type);
+
SYNC_EXPORT_PRIVATE const char* GetBrowserTypeString(
sync_pb::SessionWindow::BrowserType browser_type);
diff --git a/sync/protocol/proto_enum_conversions_unittest.cc b/sync/protocol/proto_enum_conversions_unittest.cc
index f66d379..7b323a5 100644
--- a/sync/protocol/proto_enum_conversions_unittest.cc
+++ b/sync/protocol/proto_enum_conversions_unittest.cc
@@ -25,6 +25,13 @@ void TestEnumStringFunction(const char* (*enum_string_fn)(T),
}
}
+TEST_F(ProtoEnumConversionsTest, GetAppListItemTypeString) {
+ TestEnumStringFunction(
+ GetAppListItemTypeString,
+ sync_pb::AppListSpecifics::AppListItemType_MIN,
+ sync_pb::AppListSpecifics::AppListItemType_MAX);
+}
+
TEST_F(ProtoEnumConversionsTest, GetBrowserTypeString) {
TestEnumStringFunction(
GetBrowserTypeString,
diff --git a/sync/protocol/proto_value_conversions.cc b/sync/protocol/proto_value_conversions.cc
index cdb999e..5c8a7ab 100644
--- a/sync/protocol/proto_value_conversions.cc
+++ b/sync/protocol/proto_value_conversions.cc
@@ -14,6 +14,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/values.h"
#include "sync/internal_api/public/base/unique_position.h"
+#include "sync/protocol/app_list_specifics.pb.h"
#include "sync/protocol/app_notification_specifics.pb.h"
#include "sync/protocol/app_setting_specifics.pb.h"
#include "sync/protocol/app_specifics.pb.h"
@@ -347,6 +348,19 @@ base::DictionaryValue* CoalescedNotificationToValue(
return value;
}
+base::DictionaryValue* AppListSpecificsToValue(
+ const sync_pb::AppListSpecifics& proto) {
+ base::DictionaryValue* value = new base::DictionaryValue();
+ SET_STR(item_id);
+ SET_ENUM(item_type, GetAppListItemTypeString);
+ SET_STR(item_name);
+ SET_STR(parent_id);
+ SET_STR(page_ordinal);
+ SET_STR(item_ordinal);
+
+ return value;
+}
+
base::DictionaryValue* AppNotificationToValue(
const sync_pb::AppNotification& proto) {
base::DictionaryValue* value = new base::DictionaryValue();
@@ -572,6 +586,7 @@ base::DictionaryValue* NigoriSpecificsToValue(
SET_BOOL(encrypt_search_engines);
SET_BOOL(encrypt_dictionary);
SET_BOOL(encrypt_articles);
+ SET_BOOL(encrypt_app_list);
SET_BOOL(encrypt_everything);
SET_BOOL(sync_tab_favicons);
SET_ENUM(passphrase_type, PassphraseTypeString);
@@ -694,6 +709,7 @@ base::DictionaryValue* EntitySpecificsToValue(
const sync_pb::EntitySpecifics& specifics) {
base::DictionaryValue* value = new base::DictionaryValue();
SET_FIELD(app, AppSpecificsToValue);
+ SET_FIELD(app_list, AppListSpecificsToValue);
SET_FIELD(app_notification, AppNotificationToValue);
SET_FIELD(app_setting, AppSettingSpecificsToValue);
SET_FIELD(article, ArticleSpecificsToValue);
diff --git a/sync/protocol/proto_value_conversions.h b/sync/protocol/proto_value_conversions.h
index ee40e2b..9bf45e32 100644
--- a/sync/protocol/proto_value_conversions.h
+++ b/sync/protocol/proto_value_conversions.h
@@ -14,6 +14,7 @@ class DictionaryValue;
}
namespace sync_pb {
+class AppListSpecifics;
class AppNotification;
class AppNotificationSettings;
class AppSettingSpecifics;
@@ -91,6 +92,10 @@ namespace syncer {
SYNC_EXPORT_PRIVATE base::DictionaryValue* EncryptedDataToValue(
const sync_pb::EncryptedData& encrypted_data);
+// Sub-protocol of AppListSpecifics.
+SYNC_EXPORT_PRIVATE base::DictionaryValue* AppListSpecificsToValue(
+ const sync_pb::AppListSpecifics& proto);
+
// Sub-protocol of AppSpecifics.
SYNC_EXPORT_PRIVATE base::DictionaryValue* AppSettingsToValue(
const sync_pb::AppNotificationSettings& app_notification_settings);
diff --git a/sync/protocol/proto_value_conversions_unittest.cc b/sync/protocol/proto_value_conversions_unittest.cc
index 86eee98..1366dd5 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(29, MODEL_TYPE_COUNT);
+ EXPECT_EQ(30, 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
@@ -93,6 +93,10 @@ TEST_F(ProtoValueConversionsTest, PasswordSpecificsData) {
EXPECT_EQ("<redacted>", password_value);
}
+TEST_F(ProtoValueConversionsTest, AppListSpecificsToValue) {
+ TestSpecificsToValue(AppListSpecificsToValue);
+}
+
TEST_F(ProtoValueConversionsTest, AppNotificationToValue) {
TestSpecificsToValue(AppNotificationToValue);
}
@@ -255,6 +259,7 @@ TEST_F(ProtoValueConversionsTest, EntitySpecificsToValue) {
#define SET_FIELD(key) (void)specifics.mutable_##key()
SET_FIELD(app);
+ SET_FIELD(app_list);
SET_FIELD(app_notification);
SET_FIELD(app_setting);
SET_FIELD(article);
diff --git a/sync/protocol/sync.proto b/sync/protocol/sync.proto
index 5b0c175..ecaceef 100644
--- a/sync/protocol/sync.proto
+++ b/sync/protocol/sync.proto
@@ -14,6 +14,7 @@ option retain_unknown_fields = true;
package sync_pb;
+import "app_list_specifics.proto";
import "app_notification_specifics.proto";
import "app_setting_specifics.proto";
import "app_specifics.proto";
@@ -120,6 +121,7 @@ message EntitySpecifics {
optional ManagedUserSettingSpecifics managed_user_setting = 186662;
optional ManagedUserSpecifics managed_user = 194582;
optional ArticleSpecifics article = 223759;
+ optional AppListSpecifics app_list = 229170;
}
message SyncEntity {
diff --git a/sync/sync_proto.gypi b/sync/sync_proto.gypi
index 4b90525..968ee9dd 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/app_list_specifics.proto',
'protocol/article_specifics.proto',
'protocol/autofill_specifics.proto',
'protocol/bookmark_specifics.proto',
diff --git a/sync/syncable/model_type.cc b/sync/syncable/model_type.cc
index aac057fd..fa33118 100644
--- a/sync/syncable/model_type.cc
+++ b/sync/syncable/model_type.cc
@@ -68,6 +68,9 @@ void AddDefaultFieldValue(ModelType datatype,
case APPS:
specifics->mutable_app();
break;
+ case APP_LIST:
+ specifics->mutable_app_list();
+ break;
case APP_SETTINGS:
specifics->mutable_app_setting();
break;
@@ -167,6 +170,9 @@ int GetSpecificsFieldNumberFromModelType(ModelType model_type) {
case APPS:
return sync_pb::EntitySpecifics::kAppFieldNumber;
break;
+ case APP_LIST:
+ return sync_pb::EntitySpecifics::kAppListFieldNumber;
+ break;
case APP_SETTINGS:
return sync_pb::EntitySpecifics::kAppSettingFieldNumber;
break;
@@ -276,6 +282,9 @@ ModelType GetModelTypeFromSpecifics(const sync_pb::EntitySpecifics& specifics) {
if (specifics.has_app())
return APPS;
+ if (specifics.has_app_list())
+ return APP_LIST;
+
if (specifics.has_search_engine())
return SEARCH_ENGINES;
@@ -461,6 +470,8 @@ const char* ModelTypeToString(ModelType model_type) {
return "Sessions";
case APPS:
return "Apps";
+ case APP_LIST:
+ return "App List";
case AUTOFILL_PROFILE:
return "Autofill Profiles";
case APP_SETTINGS:
@@ -564,6 +575,8 @@ int ModelTypeToHistogramInt(ModelType model_type) {
return 27;
case ARTICLES:
return 28;
+ case APP_LIST:
+ return 29;
// Silence a compiler warning.
case MODEL_TYPE_COUNT:
return 0;
@@ -623,6 +636,8 @@ ModelType ModelTypeFromString(const std::string& model_type_string) {
return SESSIONS;
else if (model_type_string == "Apps")
return APPS;
+ else if (model_type_string == "App List")
+ return APP_LIST;
else if (model_type_string == "App settings")
return APP_SETTINGS;
else if (model_type_string == "Extension settings")
@@ -715,6 +730,8 @@ std::string ModelTypeToRootTag(ModelType type) {
return "google_chrome_sessions";
case APPS:
return "google_chrome_apps";
+ case APP_LIST:
+ return "google_chrome_app_list";
case AUTOFILL_PROFILE:
return "google_chrome_autofill_profiles";
case APP_SETTINGS:
@@ -769,6 +786,7 @@ const char kExtensionSettingNotificationType[] = "EXTENSION_SETTING";
const char kNigoriNotificationType[] = "NIGORI";
const char kAppSettingNotificationType[] = "APP_SETTING";
const char kAppNotificationType[] = "APP";
+const char kAppListNotificationType[] = "APP_LIST";
const char kSearchEngineNotificationType[] = "SEARCH_ENGINE";
const char kSessionNotificationType[] = "SESSION";
const char kAutofillProfileNotificationType[] = "AUTOFILL_PROFILE";
@@ -820,6 +838,9 @@ bool RealModelTypeToNotificationType(ModelType model_type,
case APPS:
*notification_type = kAppNotificationType;
return true;
+ case APP_LIST:
+ *notification_type = kAppListNotificationType;
+ return true;
case SEARCH_ENGINES:
*notification_type = kSearchEngineNotificationType;
return true;
@@ -904,6 +925,9 @@ bool NotificationTypeToRealModelType(const std::string& notification_type,
} else if (notification_type == kAppNotificationType) {
*model_type = APPS;
return true;
+ } else if (notification_type == kAppListNotificationType) {
+ *model_type = APP_LIST;
+ return true;
} else if (notification_type == kSearchEngineNotificationType) {
*model_type = SEARCH_ENGINES;
return true;
diff --git a/sync/syncable/nigori_util.cc b/sync/syncable/nigori_util.cc
index fbdd9a5..107a68f 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(29 == MODEL_TYPE_COUNT, UpdateEncryptedTypes);
+ COMPILE_ASSERT(30 == MODEL_TYPE_COUNT, UpdateEncryptedTypes);
nigori->set_encrypt_bookmarks(
encrypted_types.Has(BOOKMARKS));
nigori->set_encrypt_preferences(
@@ -269,6 +269,7 @@ void UpdateNigoriFromEncryptedTypes(ModelTypeSet encrypted_types,
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));
+ nigori->set_encrypt_app_list(encrypted_types.Has(APP_LIST));
}
ModelTypeSet GetEncryptedTypesFromNigori(
@@ -277,7 +278,7 @@ ModelTypeSet GetEncryptedTypesFromNigori(
return ModelTypeSet::All();
ModelTypeSet encrypted_types;
- COMPILE_ASSERT(29 == MODEL_TYPE_COUNT, UpdateEncryptedTypes);
+ COMPILE_ASSERT(30 == MODEL_TYPE_COUNT, UpdateEncryptedTypes);
if (nigori.encrypt_bookmarks())
encrypted_types.Put(BOOKMARKS);
if (nigori.encrypt_preferences())
@@ -312,6 +313,8 @@ ModelTypeSet GetEncryptedTypesFromNigori(
encrypted_types.Put(FAVICON_TRACKING);
if (nigori.encrypt_articles())
encrypted_types.Put(ARTICLES);
+ if (nigori.encrypt_app_list())
+ encrypted_types.Put(APP_LIST);
return encrypted_types;
}
diff --git a/sync/tools/testserver/chromiumsync.py b/sync/tools/testserver/chromiumsync.py
index 8b48113..496cb6a 100644
--- a/sync/tools/testserver/chromiumsync.py
+++ b/sync/tools/testserver/chromiumsync.py
@@ -23,6 +23,7 @@ import time
import urlparse
import uuid
+import app_list_specifics_pb2
import app_notification_specifics_pb2
import app_setting_specifics_pb2
import app_specifics_pb2
@@ -60,6 +61,7 @@ import typed_url_specifics_pb2
ALL_TYPES = (
TOP_LEVEL, # The type of the 'Google Chrome' folder.
APPS,
+ APP_LIST,
APP_NOTIFICATION,
APP_SETTINGS,
ARTICLE,
@@ -84,7 +86,7 @@ ALL_TYPES = (
TYPED_URL,
EXTENSION_SETTINGS,
FAVICON_IMAGES,
- FAVICON_TRACKING) = range(27)
+ FAVICON_TRACKING) = range(28)
# 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.
@@ -101,6 +103,7 @@ TOP_LEVEL_FOLDER_TAG = 'google_chrome'
# to that datatype. Note that TOP_LEVEL has no such token.
SYNC_TYPE_FIELDS = sync_pb2.EntitySpecifics.DESCRIPTOR.fields_by_name
SYNC_TYPE_TO_DESCRIPTOR = {
+ APP_LIST: SYNC_TYPE_FIELDS['app_list'],
APP_NOTIFICATION: SYNC_TYPE_FIELDS['app_notification'],
APP_SETTINGS: SYNC_TYPE_FIELDS['app_setting'],
APPS: SYNC_TYPE_FIELDS['app'],
@@ -476,6 +479,8 @@ class SyncDataModel(object):
_PERMANENT_ITEM_SPECS = [
PermanentItem('google_chrome_apps', name='Apps',
parent_tag=ROOT_ID, sync_type=APPS),
+ PermanentItem('google_chrome_app_list', name='App List',
+ parent_tag=ROOT_ID, sync_type=APP_LIST),
PermanentItem('google_chrome_app_notifications', name='App Notifications',
parent_tag=ROOT_ID, sync_type=APP_NOTIFICATION),
PermanentItem('google_chrome_app_settings',
diff --git a/sync/util/data_type_histogram.h b/sync/util/data_type_histogram.h
index 01a2ba0..e3a8d6f 100644
--- a/sync/util/data_type_histogram.h
+++ b/sync/util/data_type_histogram.h
@@ -72,6 +72,9 @@
case ::syncer::APPS: \
PER_DATA_TYPE_MACRO("Apps"); \
break; \
+ case ::syncer::APP_LIST: \
+ PER_DATA_TYPE_MACRO("AppList"); \
+ break; \
case ::syncer::APP_SETTINGS: \
PER_DATA_TYPE_MACRO("AppSettings"); \
break; \