summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-01 01:56:43 +0000
committerkalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-01 01:56:43 +0000
commit27cc73365fd33c212faaf346e42c276daa3b494b (patch)
tree8e54461f1890c746f913c053dfcc03492958829f
parent288c9c8dc1fb8dcb875c40751bb67ec10f2749df (diff)
downloadchromium_src-27cc73365fd33c212faaf346e42c276daa3b494b.zip
chromium_src-27cc73365fd33c212faaf346e42c276daa3b494b.tar.gz
chromium_src-27cc73365fd33c212faaf346e42c276daa3b494b.tar.bz2
Separate the syncing of extension settings and app settings into separate data
types. This adds syncable::APP_SETTINGS on top of the existing syncable::EXTENSION_SETTINGS, and restructures code accordingly to accommodate. This is so they can each be synced independently, and eventually tied to their respective (EXTENSIONS or APPS) sync settings. BUG=98488 TEST=ExtensionSettings* Review URL: http://codereview.chromium.org/8375047 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@108055 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/extensions/extension_data_deleter.cc12
-rw-r--r--chrome/browser/extensions/extension_data_deleter.h5
-rw-r--r--chrome/browser/extensions/extension_service.cc4
-rw-r--r--chrome/browser/extensions/extension_service.h6
-rw-r--r--chrome/browser/extensions/extension_settings_api.cc56
-rw-r--r--chrome/browser/extensions/extension_settings_api.h17
-rw-r--r--chrome/browser/extensions/extension_settings_apitest.cc36
-rw-r--r--chrome/browser/extensions/extension_settings_backend.cc41
-rw-r--r--chrome/browser/extensions/extension_settings_backend.h12
-rw-r--r--chrome/browser/extensions/extension_settings_frontend.cc182
-rw-r--r--chrome/browser/extensions/extension_settings_frontend.h27
-rw-r--r--chrome/browser/extensions/extension_settings_frontend_unittest.cc62
-rw-r--r--chrome/browser/extensions/extension_settings_observer.h4
-rw-r--r--chrome/browser/extensions/extension_settings_sync_unittest.cc214
-rw-r--r--chrome/browser/extensions/extension_settings_test_util.cc95
-rw-r--r--chrome/browser/extensions/extension_settings_test_util.h66
-rw-r--r--chrome/browser/extensions/syncable_extension_settings_storage.cc24
-rw-r--r--chrome/browser/extensions/syncable_extension_settings_storage.h6
-rw-r--r--chrome/browser/sync/glue/data_type_manager_impl.cc1
-rw-r--r--chrome/browser/sync/glue/extension_setting_data_type_controller.cc29
-rw-r--r--chrome/browser/sync/glue/extension_setting_data_type_controller.h15
-rw-r--r--chrome/browser/sync/profile_sync_factory.h9
-rw-r--r--chrome/browser/sync/profile_sync_factory_impl.cc19
-rw-r--r--chrome/browser/sync/profile_sync_factory_impl.h7
-rw-r--r--chrome/browser/sync/profile_sync_factory_mock.h7
-rw-r--r--chrome/browser/sync/protocol/app_setting_specifics.proto29
-rw-r--r--chrome/browser/sync/protocol/nigori_specifics.proto2
-rw-r--r--chrome/browser/sync/protocol/proto_value_conversions.cc14
-rw-r--r--chrome/browser/sync/protocol/proto_value_conversions.h4
-rw-r--r--chrome/browser/sync/protocol/proto_value_conversions_unittest.cc8
-rw-r--r--chrome/browser/sync/protocol/sync_proto.gyp1
-rw-r--r--chrome/browser/sync/sync_prefs.cc2
-rw-r--r--chrome/browser/sync/syncable/model_type.cc26
-rw-r--r--chrome/browser/sync/syncable/model_type.h4
-rw-r--r--chrome/browser/sync/util/cryptographer.cc4
-rw-r--r--chrome/browser/ui/cocoa/extensions/extension_popup_controller_unittest.mm4
-rw-r--r--chrome/chrome_tests.gypi2
-rw-r--r--chrome/common/pref_names.cc3
-rw-r--r--chrome/common/pref_names.h1
-rwxr-xr-xnet/tools/testserver/chromiumsync.py12
40 files changed, 784 insertions, 288 deletions
diff --git a/chrome/browser/extensions/extension_data_deleter.cc b/chrome/browser/extensions/extension_data_deleter.cc
index 41f4cb9..968ebfb 100644
--- a/chrome/browser/extensions/extension_data_deleter.cc
+++ b/chrome/browser/extensions/extension_data_deleter.cc
@@ -8,7 +8,6 @@
#include "base/file_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_settings_backend.h"
#include "chrome/browser/extensions/extension_settings_frontend.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/extensions/extension.h"
@@ -65,9 +64,8 @@ void ExtensionDataDeleter::StartDeleting(
base::Bind(
&ExtensionDataDeleter::DeleteAppcachesOnIOThread, deleter));
- profile->GetExtensionService()->extension_settings_frontend()->RunWithBackend(
- base::Bind(
- &ExtensionDataDeleter::DeleteExtensionSettingsOnFileThread, deleter));
+ profile->GetExtensionService()->extension_settings_frontend()->
+ DeleteStorageSoon(extension_id);
}
ExtensionDataDeleter::ExtensionDataDeleter(
@@ -143,9 +141,3 @@ void ExtensionDataDeleter::DeleteAppcachesOnIOThread() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
appcache_service_->DeleteAppCachesForOrigin(storage_origin_, NULL);
}
-
-void ExtensionDataDeleter::DeleteExtensionSettingsOnFileThread(
- ExtensionSettingsBackend* backend) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- backend->DeleteExtensionData(extension_id_);
-}
diff --git a/chrome/browser/extensions/extension_data_deleter.h b/chrome/browser/extensions/extension_data_deleter.h
index 546c0d0..a08090a 100644
--- a/chrome/browser/extensions/extension_data_deleter.h
+++ b/chrome/browser/extensions/extension_data_deleter.h
@@ -25,7 +25,6 @@ class URLRequestContextGetter;
}
class ChromeAppCacheService;
-class ExtensionSettingsBackend;
class Profile;
class WebKitContext;
@@ -81,10 +80,6 @@ class ExtensionDataDeleter
// thread.
void DeleteAppcachesOnIOThread();
- // Deletes extension settings for the extension. Will be called on the FILE
- // thread via the ExtensionSettingsFrontend.
- void DeleteExtensionSettingsOnFileThread(ExtensionSettingsBackend* backend);
-
// The ID of the extension being deleted.
const std::string extension_id_;
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index c71801f..d4db48a 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -246,7 +246,9 @@ ExtensionService::NaClModuleInfo::~NaClModuleInfo() {
// ExtensionService.
const char* ExtensionService::kInstallDirectoryName = "Extensions";
-const char* ExtensionService::kSettingsDirectoryName = "Extension Settings";
+const char* ExtensionService::kExtensionSettingsDirectoryName =
+ "Extension Settings";
+const char* ExtensionService::kAppSettingsDirectoryName = "App Settings";
// Implements IO for the ExtensionService.
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index 7e5e9f6..52cfa2f 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -145,7 +145,11 @@ class ExtensionService
// The name of the directory inside the profile where per-extension settings
// are stored.
- static const char* kSettingsDirectoryName;
+ static const char* kExtensionSettingsDirectoryName;
+
+ // The name of the directory inside the profile where per-app settings
+ // are stored.
+ static const char* kAppSettingsDirectoryName;
// Determine if a given extension download should be treated as if it came
// from the gallery. Note that this is requires *both* that the download_url
diff --git a/chrome/browser/extensions/extension_settings_api.cc b/chrome/browser/extensions/extension_settings_api.cc
index 27b6be1..0113c86 100644
--- a/chrome/browser/extensions/extension_settings_api.cc
+++ b/chrome/browser/extensions/extension_settings_api.cc
@@ -16,16 +16,25 @@ const char* kUnsupportedArgumentType = "Unsupported argument type";
// SettingsFunction
bool SettingsFunction::RunImpl() {
- profile()->GetExtensionService()->extension_settings_frontend()->
- RunWithBackend(
- base::Bind(&SettingsFunction::RunWithBackendOnFileThread, this));
+ ExtensionSettingsFrontend* frontend =
+ profile()->GetExtensionService()->extension_settings_frontend();
+ frontend->RunWithStorage(
+ extension_id(),
+ base::Bind(
+ &SettingsFunction::RunWithStorageOnFileThread,
+ this,
+ frontend->GetObservers()));
return true;
}
-void SettingsFunction::RunWithBackendOnFileThread(
- ExtensionSettingsBackend* backend) {
+void SettingsFunction::RunWithStorageOnFileThread(
+ scoped_refptr<ExtensionSettingsObserverList> observers,
+ ExtensionSettingsStorage* storage) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- bool success = RunWithStorage(backend, backend->GetStorage(extension_id()));
+ bool success = false;
+ if (storage) {
+ success = RunWithStorage(observers.get(), storage);
+ }
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
@@ -33,7 +42,7 @@ void SettingsFunction::RunWithBackendOnFileThread(
}
bool SettingsFunction::UseResult(
- ExtensionSettingsBackend* backend,
+ scoped_refptr<ExtensionSettingsObserverList> observers,
const ExtensionSettingsStorage::Result& storage_result) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
if (storage_result.HasError()) {
@@ -58,8 +67,11 @@ bool SettingsFunction::UseResult(
old_value ? old_value->DeepCopy() : NULL,
new_value ? new_value->DeepCopy() : NULL);
}
- backend->TriggerOnSettingsChanged(
- profile(), extension_id(), changes.Build());
+ observers->Notify(
+ &ExtensionSettingsObserver::OnSettingsChanged,
+ profile(),
+ extension_id(),
+ changes.Build());
}
return true;
@@ -80,7 +92,7 @@ static void AddAllStringValues(
}
bool GetSettingsFunction::RunWithStorage(
- ExtensionSettingsBackend* backend,
+ scoped_refptr<ExtensionSettingsObserverList> observers,
ExtensionSettingsStorage* storage) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
Value *input;
@@ -88,29 +100,29 @@ bool GetSettingsFunction::RunWithStorage(
std::string as_string;
ListValue* as_list;
if (input->IsType(Value::TYPE_NULL)) {
- return UseResult(backend, storage->Get());
+ return UseResult(observers, storage->Get());
} else if (input->GetAsString(&as_string)) {
- return UseResult(backend, storage->Get(as_string));
+ return UseResult(observers, storage->Get(as_string));
} else if (input->GetAsList(&as_list)) {
std::vector<std::string> string_list;
AddAllStringValues(*as_list, &string_list);
- return UseResult(backend, storage->Get(string_list));
+ return UseResult(observers, storage->Get(string_list));
}
return UseResult(
- backend, ExtensionSettingsStorage::Result(kUnsupportedArgumentType));
+ observers, ExtensionSettingsStorage::Result(kUnsupportedArgumentType));
}
bool SetSettingsFunction::RunWithStorage(
- ExtensionSettingsBackend* backend,
+ scoped_refptr<ExtensionSettingsObserverList> observers,
ExtensionSettingsStorage* storage) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
DictionaryValue *input;
EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &input));
- return UseResult(backend, storage->Set(*input));
+ return UseResult(observers, storage->Set(*input));
}
bool RemoveSettingsFunction::RunWithStorage(
- ExtensionSettingsBackend* backend,
+ scoped_refptr<ExtensionSettingsObserverList> observers,
ExtensionSettingsStorage* storage) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
Value *input;
@@ -118,19 +130,19 @@ bool RemoveSettingsFunction::RunWithStorage(
std::string as_string;
ListValue* as_list;
if (input->GetAsString(&as_string)) {
- return UseResult(backend, storage->Remove(as_string));
+ return UseResult(observers, storage->Remove(as_string));
} else if (input->GetAsList(&as_list)) {
std::vector<std::string> string_list;
AddAllStringValues(*as_list, &string_list);
- return UseResult(backend, storage->Remove(string_list));
+ return UseResult(observers, storage->Remove(string_list));
}
return UseResult(
- backend, ExtensionSettingsStorage::Result(kUnsupportedArgumentType));
+ observers, ExtensionSettingsStorage::Result(kUnsupportedArgumentType));
}
bool ClearSettingsFunction::RunWithStorage(
- ExtensionSettingsBackend* backend,
+ scoped_refptr<ExtensionSettingsObserverList> observers,
ExtensionSettingsStorage* storage) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- return UseResult(backend, storage->Clear());
+ return UseResult(observers, storage->Clear());
}
diff --git a/chrome/browser/extensions/extension_settings_api.h b/chrome/browser/extensions/extension_settings_api.h
index 15f3fcb..6893ddd 100644
--- a/chrome/browser/extensions/extension_settings_api.h
+++ b/chrome/browser/extensions/extension_settings_api.h
@@ -7,6 +7,7 @@
#pragma once
#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
#include "chrome/browser/extensions/extension_function.h"
#include "chrome/browser/extensions/extension_settings_backend.h"
#include "chrome/browser/extensions/extension_settings_storage.h"
@@ -22,19 +23,21 @@ class SettingsFunction : public AsyncExtensionFunction {
// Implementations should fill in args themselves, though (like RunImpl)
// may return false to imply failure.
virtual bool RunWithStorage(
- ExtensionSettingsBackend* backend,
+ scoped_refptr<ExtensionSettingsObserverList> observers,
ExtensionSettingsStorage* storage) = 0;
// Sets error_ or result_ depending on the value of a storage Result, and
// returns whether the Result implies success (i.e. !error).
bool UseResult(
- ExtensionSettingsBackend* backend,
+ scoped_refptr<ExtensionSettingsObserverList> observers,
const ExtensionSettingsStorage::Result& storage_result);
private:
// Called via PostTask from RunImpl. Calls RunWithStorage and then
// SendReponse with its success value.
- void RunWithBackendOnFileThread(ExtensionSettingsBackend* backend);
+ void RunWithStorageOnFileThread(
+ scoped_refptr<ExtensionSettingsObserverList> observers,
+ ExtensionSettingsStorage* storage);
};
class GetSettingsFunction : public SettingsFunction {
@@ -43,7 +46,7 @@ class GetSettingsFunction : public SettingsFunction {
protected:
virtual bool RunWithStorage(
- ExtensionSettingsBackend* backend,
+ scoped_refptr<ExtensionSettingsObserverList> observers,
ExtensionSettingsStorage* storage) OVERRIDE;
};
@@ -53,7 +56,7 @@ class SetSettingsFunction : public SettingsFunction {
protected:
virtual bool RunWithStorage(
- ExtensionSettingsBackend* backend,
+ scoped_refptr<ExtensionSettingsObserverList> observers,
ExtensionSettingsStorage* storage) OVERRIDE;
};
@@ -63,7 +66,7 @@ class RemoveSettingsFunction : public SettingsFunction {
protected:
virtual bool RunWithStorage(
- ExtensionSettingsBackend* backend,
+ scoped_refptr<ExtensionSettingsObserverList> observers,
ExtensionSettingsStorage* storage) OVERRIDE;
};
@@ -73,7 +76,7 @@ class ClearSettingsFunction : public SettingsFunction {
protected:
virtual bool RunWithStorage(
- ExtensionSettingsBackend* backend,
+ scoped_refptr<ExtensionSettingsObserverList> observers,
ExtensionSettingsStorage* storage) OVERRIDE;
};
diff --git a/chrome/browser/extensions/extension_settings_apitest.cc b/chrome/browser/extensions/extension_settings_apitest.cc
index 6b7f8a7..a2dc5e1 100644
--- a/chrome/browser/extensions/extension_settings_apitest.cc
+++ b/chrome/browser/extensions/extension_settings_apitest.cc
@@ -7,7 +7,6 @@
#include "base/json/json_writer.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/extensions/extension_settings_backend.h"
#include "chrome/browser/extensions/extension_settings_sync_util.h"
#include "chrome/browser/extensions/extension_test_message_listener.h"
#include "chrome/browser/profiles/profile.h"
@@ -57,19 +56,25 @@ class ExtensionSettingsApiTest : public ExtensionApiTest {
void InitSync(SyncChangeProcessor* sync_processor) {
browser()->profile()->GetExtensionService()->
- extension_settings_frontend()->RunWithBackend(base::Bind(
- &ExtensionSettingsApiTest::InitSyncWithBackend,
- this,
- sync_processor));
+ extension_settings_frontend()->RunWithSyncableService(
+ // TODO(kalman): test both EXTENSION_SETTINGS and APP_SETTINGS.
+ syncable::EXTENSION_SETTINGS,
+ base::Bind(
+ &ExtensionSettingsApiTest::InitSyncWithSyncableService,
+ this,
+ sync_processor));
MessageLoop::current()->RunAllPending();
}
void SendChanges(const SyncChangeList& change_list) {
browser()->profile()->GetExtensionService()->
- extension_settings_frontend()->RunWithBackend(base::Bind(
- &ExtensionSettingsApiTest::SendChangesToBackend,
- this,
- change_list));
+ extension_settings_frontend()->RunWithSyncableService(
+ // TODO(kalman): test both EXTENSION_SETTINGS and APP_SETTINGS.
+ syncable::EXTENSION_SETTINGS,
+ base::Bind(
+ &ExtensionSettingsApiTest::SendChangesToSyncableService,
+ this,
+ change_list));
MessageLoop::current()->RunAllPending();
}
@@ -109,17 +114,18 @@ class ExtensionSettingsApiTest : public ExtensionApiTest {
return message_json;
}
- void InitSyncWithBackend(
- SyncChangeProcessor* sync_processor, ExtensionSettingsBackend* backend) {
- EXPECT_FALSE(backend->MergeDataAndStartSyncing(
+ void InitSyncWithSyncableService(
+ SyncChangeProcessor* sync_processor, SyncableService* settings_service) {
+ EXPECT_FALSE(settings_service->MergeDataAndStartSyncing(
syncable::EXTENSION_SETTINGS,
SyncDataList(),
sync_processor).IsSet());
}
- void SendChangesToBackend(
- const SyncChangeList& change_list, ExtensionSettingsBackend* backend) {
- EXPECT_FALSE(backend->ProcessSyncChanges(FROM_HERE, change_list).IsSet());
+ void SendChangesToSyncableService(
+ const SyncChangeList& change_list, SyncableService* settings_service) {
+ EXPECT_FALSE(
+ settings_service->ProcessSyncChanges(FROM_HERE, change_list).IsSet());
}
};
diff --git a/chrome/browser/extensions/extension_settings_backend.cc b/chrome/browser/extensions/extension_settings_backend.cc
index 63d8f32..ffaa828 100644
--- a/chrome/browser/extensions/extension_settings_backend.cc
+++ b/chrome/browser/extensions/extension_settings_backend.cc
@@ -38,10 +38,10 @@ const size_t kMaxSettingKeys = 512;
ExtensionSettingsBackend::ExtensionSettingsBackend(
const FilePath& base_path,
- const scoped_refptr<ObserverListThreadSafe<ExtensionSettingsObserver> >&
- observers)
+ const scoped_refptr<ExtensionSettingsObserverList>& observers)
: base_path_(base_path),
observers_(observers),
+ sync_type_(syncable::UNSPECIFIED),
sync_processor_(NULL) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
}
@@ -93,15 +93,15 @@ ExtensionSettingsBackend::GetOrCreateStorageWithSyncData(
storage));
if (sync_processor_) {
// TODO(kalman): do something if StartSyncing fails.
- ignore_result(syncable_storage->StartSyncing(sync_data, sync_processor_));
+ ignore_result(syncable_storage->StartSyncing(
+ sync_type_, sync_data, sync_processor_));
}
storage_objs_[extension_id] = syncable_storage;
return syncable_storage.get();
}
-void ExtensionSettingsBackend::DeleteExtensionData(
- const std::string& extension_id) {
+void ExtensionSettingsBackend::DeleteStorage(const std::string& extension_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
StorageObjMap::iterator maybe_storage = storage_objs_.find(extension_id);
if (maybe_storage == storage_objs_.end()) {
@@ -130,10 +130,6 @@ std::set<std::string> ExtensionSettingsBackend::GetKnownExtensionIDs() const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
std::set<std::string> result;
- // TODO(kalman): we will need to do something to disambiguate between app
- // settings and extension settings, since settings for apps should be synced
- // iff app sync is turned on, ditto for extensions.
-
// Extension IDs live in-memory and/or on disk. The cache will contain all
// that are in-memory.
for (StorageObjMap::iterator it = storage_objs_.begin();
@@ -162,11 +158,13 @@ std::set<std::string> ExtensionSettingsBackend::GetKnownExtensionIDs() const {
SyncDataList ExtensionSettingsBackend::GetAllSyncData(
syncable::ModelType type) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- DCHECK_EQ(type, syncable::EXTENSION_SETTINGS);
+ // Ignore the type, it's just for sanity checking; assume that whatever base
+ // path we're constructed with is correct for the sync type.
+ DCHECK(type == syncable::EXTENSION_SETTINGS ||
+ type == syncable::APP_SETTINGS);
- // For all extensions, get all their settings.
- // This has the effect of bringing in the entire state of extension settings
- // in memory; sad.
+ // For all extensions, get all their settings. This has the effect
+ // of bringing in the entire state of extension settings in memory; sad.
SyncDataList all_sync_data;
std::set<std::string> known_extension_ids(GetKnownExtensionIDs());
@@ -197,8 +195,12 @@ SyncError ExtensionSettingsBackend::MergeDataAndStartSyncing(
const SyncDataList& initial_sync_data,
SyncChangeProcessor* sync_processor) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- DCHECK_EQ(type, syncable::EXTENSION_SETTINGS);
+ DCHECK(type == syncable::EXTENSION_SETTINGS ||
+ type == syncable::APP_SETTINGS);
+ DCHECK_EQ(sync_type_, syncable::UNSPECIFIED);
DCHECK(!sync_processor_);
+
+ sync_type_ = type;
sync_processor_ = sync_processor;
// Group the initial sync data by extension id.
@@ -226,12 +228,13 @@ SyncError ExtensionSettingsBackend::MergeDataAndStartSyncing(
if (maybe_sync_data != grouped_sync_data.end()) {
// TODO(kalman): do something if StartSyncing fails.
ignore_result(
- it->second->StartSyncing(*maybe_sync_data->second, sync_processor));
+ it->second->StartSyncing(
+ type, *maybe_sync_data->second, sync_processor));
grouped_sync_data.erase(it->first);
} else {
DictionaryValue empty;
// TODO(kalman): do something if StartSyncing fails.
- ignore_result(it->second->StartSyncing(empty, sync_processor));
+ ignore_result(it->second->StartSyncing(type, empty, sync_processor));
}
}
@@ -260,6 +263,7 @@ SyncError ExtensionSettingsBackend::ProcessSyncChanges(
grouped_sync_data[data.extension_id()].push_back(data);
}
+ // Create any storage areas that don't exist yet but have sync data.
DictionaryValue empty;
for (std::map<std::string, ExtensionSettingSyncDataList>::iterator
it = grouped_sync_data.begin(); it != grouped_sync_data.end(); ++it) {
@@ -274,7 +278,12 @@ SyncError ExtensionSettingsBackend::ProcessSyncChanges(
void ExtensionSettingsBackend::StopSyncing(syncable::ModelType type) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK(type == syncable::EXTENSION_SETTINGS ||
+ type == syncable::APP_SETTINGS);
+ DCHECK_EQ(type, sync_type_);
DCHECK(sync_processor_);
+
+ sync_type_ = syncable::UNSPECIFIED;
sync_processor_ = NULL;
for (StorageObjMap::iterator it = storage_objs_.begin();
diff --git a/chrome/browser/extensions/extension_settings_backend.h b/chrome/browser/extensions/extension_settings_backend.h
index 81c1067..3a0229d 100644
--- a/chrome/browser/extensions/extension_settings_backend.h
+++ b/chrome/browser/extensions/extension_settings_backend.h
@@ -26,8 +26,7 @@ class ExtensionSettingsBackend : public SyncableService {
// |observers| is the list of observers to settings changes.
explicit ExtensionSettingsBackend(
const FilePath& base_path,
- const scoped_refptr<ObserverListThreadSafe<ExtensionSettingsObserver> >&
- observers);
+ const scoped_refptr<ExtensionSettingsObserverList>& observers);
virtual ~ExtensionSettingsBackend();
@@ -41,7 +40,7 @@ class ExtensionSettingsBackend : public SyncableService {
const std::string& extension_id) const;
// Deletes all setting data for an extension. Call on the FILE thread.
- void DeleteExtensionData(const std::string& extension_id);
+ void DeleteStorage(const std::string& extension_id);
// Sends a change event to the observer list. |profile| is the profile which
// generated the change. Must be called on the FILE thread.
@@ -78,8 +77,7 @@ class ExtensionSettingsBackend : public SyncableService {
const FilePath base_path_;
// The list of observers to settings changes.
- const scoped_refptr<ObserverListThreadSafe<ExtensionSettingsObserver> >
- observers_;
+ const scoped_refptr<ExtensionSettingsObserverList> observers_;
// A cache of ExtensionSettingsStorage objects that have already been created.
// Ensure that there is only ever one created per extension.
@@ -87,6 +85,10 @@ class ExtensionSettingsBackend : public SyncableService {
StorageObjMap;
mutable StorageObjMap storage_objs_;
+ // Current sync model type. Will be UNSPECIFIED if sync hasn't been enabled
+ // yet, and either EXTENSION_SETTINGS or APP_SETTINGS if it has been.
+ syncable::ModelType sync_type_;
+
// Current sync processor, if any.
SyncChangeProcessor* sync_processor_;
diff --git a/chrome/browser/extensions/extension_settings_frontend.cc b/chrome/browser/extensions/extension_settings_frontend.cc
index 38cdca4..f9233e4 100644
--- a/chrome/browser/extensions/extension_settings_frontend.cc
+++ b/chrome/browser/extensions/extension_settings_frontend.cc
@@ -14,6 +14,70 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
+namespace {
+
+struct Backends {
+ Backends(
+ const FilePath& profile_path,
+ const scoped_refptr<ExtensionSettingsObserverList>& observers)
+ : extensions_backend_(
+ profile_path.AppendASCII(
+ ExtensionService::kExtensionSettingsDirectoryName),
+ observers),
+ apps_backend_(
+ profile_path.AppendASCII(
+ ExtensionService::kAppSettingsDirectoryName),
+ observers) {}
+
+ ExtensionSettingsBackend extensions_backend_;
+ ExtensionSettingsBackend apps_backend_;
+};
+
+static void CallbackWithExtensionsBackend(
+ const ExtensionSettingsFrontend::SyncableServiceCallback& callback,
+ Backends* backends) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ callback.Run(&backends->extensions_backend_);
+}
+
+void CallbackWithAppsBackend(
+ const ExtensionSettingsFrontend::SyncableServiceCallback& callback,
+ Backends* backends) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ callback.Run(&backends->apps_backend_);
+}
+
+void CallbackWithExtensionsStorage(
+ const std::string& extension_id,
+ const ExtensionSettingsFrontend::StorageCallback& callback,
+ Backends* backends) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ callback.Run(backends->extensions_backend_.GetStorage(extension_id));
+}
+
+void CallbackWithAppsStorage(
+ const std::string& extension_id,
+ const ExtensionSettingsFrontend::StorageCallback& callback,
+ Backends* backends) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ callback.Run(backends->apps_backend_.GetStorage(extension_id));
+}
+
+void CallbackWithNullStorage(
+ const ExtensionSettingsFrontend::StorageCallback& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ callback.Run(NULL);
+}
+
+void DeleteStorageOnFileThread(
+ const std::string& extension_id, Backends* backends) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ backends->extensions_backend_.DeleteStorage(extension_id);
+ backends->apps_backend_.DeleteStorage(extension_id);
+}
+
+} // namespace
+
class ExtensionSettingsFrontend::DefaultObserver
: public ExtensionSettingsObserver {
public:
@@ -44,34 +108,47 @@ class ExtensionSettingsFrontend::Core
: public base::RefCountedThreadSafe<Core> {
public:
explicit Core(
- const scoped_refptr<ObserverListThreadSafe<ExtensionSettingsObserver> >&
- observers)
- : observers_(observers), backend_(NULL) {
+ const scoped_refptr<ExtensionSettingsObserverList>& observers)
+ : observers_(observers), backends_(NULL) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}
+ typedef base::Callback<void(Backends*)> BackendsCallback;
+
// Does any FILE thread specific initialization, such as construction of
// |backend_|. Must be called before any call to
// RunWithBackendOnFileThread().
- void InitOnFileThread(const FilePath& base_path) {
+ void InitOnFileThread(const FilePath& profile_path) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- DCHECK(!backend_);
- backend_ = new ExtensionSettingsBackend(base_path, observers_);
+ DCHECK(!backends_);
+ backends_ = new Backends(profile_path, observers_);
}
- // Runs |callback| with the extension backend.
- void RunWithBackendOnFileThread(const BackendCallback& callback) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- DCHECK(backend_);
- callback.Run(backend_);
+ // Runs |callback| with both the extensions and apps settings on the FILE
+ // thread.
+ void RunWithBackends(const BackendsCallback& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ BrowserThread::PostTask(
+ BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(
+ &ExtensionSettingsFrontend::Core::RunWithBackendsOnFileThread,
+ this,
+ callback));
}
private:
+ void RunWithBackendsOnFileThread(const BackendsCallback& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK(backends_);
+ callback.Run(backends_);
+ }
+
virtual ~Core() {
if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
- delete backend_;
+ delete backends_;
} else if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
- BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, backend_);
+ BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, backends_);
} else {
NOTREACHED();
}
@@ -80,19 +157,18 @@ class ExtensionSettingsFrontend::Core
friend class base::RefCountedThreadSafe<Core>;
// Observers to settings changes (thread safe).
- scoped_refptr<ObserverListThreadSafe<ExtensionSettingsObserver> >
- observers_;
+ scoped_refptr<ExtensionSettingsObserverList> observers_;
- // Lives on the FILE thread.
- ExtensionSettingsBackend* backend_;
+ // Backends for extensions and apps settings. Lives on FILE thread.
+ Backends* backends_;
DISALLOW_COPY_AND_ASSIGN(Core);
};
ExtensionSettingsFrontend::ExtensionSettingsFrontend(Profile* profile)
: profile_(profile),
- observers_(new ObserverListThreadSafe<ExtensionSettingsObserver>()),
- core_(new ExtensionSettingsFrontend::Core(observers_.get())) {
+ observers_(new ExtensionSettingsObserverList()),
+ core_(new ExtensionSettingsFrontend::Core(observers_)) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!profile->IsOffTheRecord());
@@ -111,34 +187,64 @@ ExtensionSettingsFrontend::ExtensionSettingsFrontend(Profile* profile)
base::Bind(
&ExtensionSettingsFrontend::Core::InitOnFileThread,
core_.get(),
- profile->GetPath().AppendASCII(
- ExtensionService::kSettingsDirectoryName)));
+ profile->GetPath()));
}
ExtensionSettingsFrontend::~ExtensionSettingsFrontend() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}
-void ExtensionSettingsFrontend::RunWithBackend(
- const BackendCallback& callback) {
+void ExtensionSettingsFrontend::RunWithSyncableService(
+ syncable::ModelType model_type, const SyncableServiceCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- BrowserThread::PostTask(
- BrowserThread::FILE,
- FROM_HERE,
- base::Bind(
- &ExtensionSettingsFrontend::Core::RunWithBackendOnFileThread,
- core_.get(),
- callback));
+ switch (model_type) {
+ case syncable::EXTENSION_SETTINGS:
+ core_->RunWithBackends(
+ base::Bind(&CallbackWithExtensionsBackend, callback));
+ break;
+ case syncable::APP_SETTINGS:
+ core_->RunWithBackends(
+ base::Bind(&CallbackWithAppsBackend, callback));
+ break;
+ default:
+ NOTREACHED();
+ }
+}
+
+void ExtensionSettingsFrontend::RunWithStorage(
+ const std::string& extension_id,
+ const StorageCallback& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ const Extension* extension =
+ profile_->GetExtensionService()->GetExtensionById(extension_id, true);
+ if (!extension) {
+ BrowserThread::PostTask(
+ BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&CallbackWithNullStorage, callback));
+ return;
+ }
+
+ if (extension->is_app()) {
+ core_->RunWithBackends(
+ base::Bind(&CallbackWithAppsStorage, extension_id, callback));
+ } else {
+ core_->RunWithBackends(
+ base::Bind(&CallbackWithExtensionsStorage, extension_id, callback));
+ }
}
-void ExtensionSettingsFrontend::AddObserver(
- ExtensionSettingsObserver* observer) {
- observers_->AddObserver(observer);
+void ExtensionSettingsFrontend::DeleteStorageSoon(
+ const std::string& extension_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ core_->RunWithBackends(base::Bind(&DeleteStorageOnFileThread, extension_id));
}
-void ExtensionSettingsFrontend::RemoveObserver(
- ExtensionSettingsObserver* observer) {
- observers_->RemoveObserver(observer);
+scoped_refptr<ExtensionSettingsObserverList>
+ExtensionSettingsFrontend::GetObservers() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ return observers_;
}
void ExtensionSettingsFrontend::Observe(
@@ -184,13 +290,13 @@ void ExtensionSettingsFrontend::SetDefaultObserver(
Profile* profile, scoped_ptr<DefaultObserver>* observer) {
DCHECK(!observer->get());
observer->reset(new DefaultObserver(profile));
- AddObserver(observer->get());
+ observers_->AddObserver(observer->get());
}
void ExtensionSettingsFrontend::ClearDefaultObserver(
scoped_ptr<DefaultObserver>* observer) {
if (observer->get()) {
- RemoveObserver(observer->get());
+ observers_->RemoveObserver(observer->get());
observer->reset();
}
}
diff --git a/chrome/browser/extensions/extension_settings_frontend.h b/chrome/browser/extensions/extension_settings_frontend.h
index 104da18..ab63f18 100644
--- a/chrome/browser/extensions/extension_settings_frontend.h
+++ b/chrome/browser/extensions/extension_settings_frontend.h
@@ -18,26 +18,35 @@
class FilePath;
class Profile;
-class ExtensionSettingsBackend;
class ExtensionSettingsStorage;
// The component of extension settings which runs on the UI thread, as opposed
// to ExtensionSettingsBackend which lives on the FILE thread.
+// All public methods must be called on the UI thread.
class ExtensionSettingsFrontend : public content::NotificationObserver {
public:
explicit ExtensionSettingsFrontend(Profile* profile);
virtual ~ExtensionSettingsFrontend();
- typedef base::Callback<void(ExtensionSettingsBackend*)> BackendCallback;
+ typedef base::Callback<void(SyncableService*)> SyncableServiceCallback;
+ typedef base::Callback<void(ExtensionSettingsStorage*)> StorageCallback;
- // Runs |callback| on the FILE thread with the extension settings.
- void RunWithBackend(const BackendCallback& callback);
+ // Runs |callback| on the FILE thread with the SyncableService for
+ // |model_type|, either EXTENSION_SETTINGS or APP_SETTINGS.
+ void RunWithSyncableService(
+ syncable::ModelType model_type, const SyncableServiceCallback& callback);
- // Adds an observer to settings changes.
- void AddObserver(ExtensionSettingsObserver* observer);
+ // Runs |callback| on the FILE thread with the storage area for
+ // |extension_id|. If there is no extension with that ID, the storage area
+ // will be NULL.
+ void RunWithStorage(
+ const std::string& extension_id, const StorageCallback& callback);
- // Removes an observer to settings changes.
- void RemoveObserver(ExtensionSettingsObserver* observer);
+ // Deletes the settings for an extension (on the FILE thread).
+ void DeleteStorageSoon(const std::string& extension_id);
+
+ // Gets the thread-safe observer list.
+ scoped_refptr<ExtensionSettingsObserverList> GetObservers();
// NotificationObserver implementation.
virtual void Observe(
@@ -70,7 +79,7 @@ class ExtensionSettingsFrontend : public content::NotificationObserver {
Profile* const profile_;
// List of observers to settings changes.
- scoped_refptr<ObserverListThreadSafe<ExtensionSettingsObserver> > observers_;
+ scoped_refptr<ExtensionSettingsObserverList> observers_;
// The default original and incognito mode profile observers.
scoped_ptr<DefaultObserver> original_profile_observer;
diff --git a/chrome/browser/extensions/extension_settings_frontend_unittest.cc b/chrome/browser/extensions/extension_settings_frontend_unittest.cc
index 0fca900..8a9c427 100644
--- a/chrome/browser/extensions/extension_settings_frontend_unittest.cc
+++ b/chrome/browser/extensions/extension_settings_frontend_unittest.cc
@@ -9,13 +9,14 @@
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "base/scoped_temp_dir.h"
-#include "chrome/browser/extensions/extension_settings_backend.h"
#include "chrome/browser/extensions/extension_settings_frontend.h"
#include "chrome/browser/extensions/extension_settings_storage.h"
+#include "chrome/browser/extensions/extension_settings_test_util.h"
#include "chrome/common/chrome_notification_types.h"
-#include "chrome/test/base/testing_profile.h"
#include "content/test/test_browser_thread.h"
+using namespace extension_settings_test_util;
+
class ExtensionSettingsFrontendTest : public testing::Test {
public:
ExtensionSettingsFrontendTest()
@@ -24,7 +25,7 @@ class ExtensionSettingsFrontendTest : public testing::Test {
virtual void SetUp() OVERRIDE {
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- profile_.reset(new TestingProfile(temp_dir_.path()));
+ profile_.reset(new MockProfile(temp_dir_.path()));
frontend_.reset(new ExtensionSettingsFrontend(profile_.get()));
}
@@ -34,39 +35,26 @@ class ExtensionSettingsFrontendTest : public testing::Test {
}
protected:
- // Puts the settings backend in |backend|.
- void GetBackend(ExtensionSettingsBackend** backend) {
- frontend_->RunWithBackend(
- base::Bind(
- &ExtensionSettingsFrontendTest::AssignBackend,
- base::Unretained(this),
- backend));
- MessageLoop::current()->RunAllPending();
- ASSERT_TRUE(*backend);
- }
-
ScopedTempDir temp_dir_;
- scoped_ptr<TestingProfile> profile_;
+ scoped_ptr<MockProfile> profile_;
scoped_ptr<ExtensionSettingsFrontend> frontend_;
private:
- // Intended as a ExtensionSettingsFrontend::BackendCallback from GetBackend.
- void AssignBackend(
- ExtensionSettingsBackend** dst, ExtensionSettingsBackend* src) {
- *dst = src;
- }
-
MessageLoop message_loop_;
content::TestBrowserThread ui_thread_;
content::TestBrowserThread file_thread_;
};
-TEST_F(ExtensionSettingsFrontendTest, SettingsPreservedAcrossReconstruction) {
- ExtensionSettingsBackend* backend;
- GetBackend(&backend);
+// Get a semblance of coverage for both extension and app settings by
+// alternating in each test.
+// TODO(kalman): explicitly test the two interact correctly.
+TEST_F(ExtensionSettingsFrontendTest, SettingsPreservedAcrossReconstruction) {
const std::string id = "ext";
- ExtensionSettingsStorage* storage = backend->GetStorage(id);
+ profile_->GetMockExtensionService()->AddExtension(
+ id, Extension::TYPE_EXTENSION);
+
+ ExtensionSettingsStorage* storage = GetStorage(id, frontend_.get());
// The correctness of Get/Set/Remove/Clear is tested elsewhere so no need to
// be too rigorous.
@@ -79,8 +67,7 @@ TEST_F(ExtensionSettingsFrontendTest, SettingsPreservedAcrossReconstruction) {
EXPECT_FALSE(result.GetSettings()->empty());
frontend_.reset(new ExtensionSettingsFrontend(profile_.get()));
- GetBackend(&backend);
- storage = backend->GetStorage(id);
+ storage = GetStorage(id, frontend_.get());
result = storage->Get();
ASSERT_FALSE(result.HasError());
@@ -88,32 +75,33 @@ TEST_F(ExtensionSettingsFrontendTest, SettingsPreservedAcrossReconstruction) {
}
TEST_F(ExtensionSettingsFrontendTest, SettingsClearedOnUninstall) {
- ExtensionSettingsBackend* backend;
- GetBackend(&backend);
-
const std::string id = "ext";
- ExtensionSettingsStorage* storage = backend->GetStorage(id);
+ profile_->GetMockExtensionService()->AddExtension(
+ id, Extension::TYPE_PACKAGED_APP);
+
+ ExtensionSettingsStorage* storage = GetStorage(id, frontend_.get());
StringValue bar("bar");
ExtensionSettingsStorage::Result result = storage->Set("foo", bar);
ASSERT_FALSE(result.HasError());
// This would be triggered by extension uninstall via an ExtensionDataDeleter.
- backend->DeleteExtensionData(id);
+ frontend_->DeleteStorageSoon(id);
+ MessageLoop::current()->RunAllPending();
// The storage area may no longer be valid post-uninstall, so re-request.
- storage = backend->GetStorage(id);
+ storage = GetStorage(id, frontend_.get());
result = storage->Get();
ASSERT_FALSE(result.HasError());
EXPECT_TRUE(result.GetSettings()->empty());
}
TEST_F(ExtensionSettingsFrontendTest, LeveldbDatabaseDeletedFromDiskOnClear) {
- ExtensionSettingsBackend* backend;
- GetBackend(&backend);
-
const std::string id = "ext";
- ExtensionSettingsStorage* storage = backend->GetStorage(id);
+ profile_->GetMockExtensionService()->AddExtension(
+ id, Extension::TYPE_EXTENSION);
+
+ ExtensionSettingsStorage* storage = GetStorage(id, frontend_.get());
StringValue bar("bar");
ExtensionSettingsStorage::Result result = storage->Set("foo", bar);
diff --git a/chrome/browser/extensions/extension_settings_observer.h b/chrome/browser/extensions/extension_settings_observer.h
index 7cc2461..5acb049 100644
--- a/chrome/browser/extensions/extension_settings_observer.h
+++ b/chrome/browser/extensions/extension_settings_observer.h
@@ -6,6 +6,7 @@
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_SETTINGS_OBSERVER_H_
#pragma once
+#include "base/observer_list_threadsafe.h"
#include "chrome/browser/extensions/extension_setting_changes.h"
class Profile;
@@ -28,4 +29,7 @@ class ExtensionSettingsObserver {
virtual ~ExtensionSettingsObserver();
};
+typedef ObserverListThreadSafe<ExtensionSettingsObserver>
+ ExtensionSettingsObserverList;
+
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_SETTINGS_OBSERVER_H_
diff --git a/chrome/browser/extensions/extension_settings_sync_unittest.cc b/chrome/browser/extensions/extension_settings_sync_unittest.cc
index 2bc2995..07418de 100644
--- a/chrome/browser/extensions/extension_settings_sync_unittest.cc
+++ b/chrome/browser/extensions/extension_settings_sync_unittest.cc
@@ -11,17 +11,18 @@
#include "base/message_loop.h"
#include "base/scoped_temp_dir.h"
#include "base/task.h"
-#include "chrome/browser/extensions/extension_settings_backend.h"
#include "chrome/browser/extensions/extension_settings_frontend.h"
#include "chrome/browser/extensions/extension_settings_storage_cache.h"
#include "chrome/browser/extensions/extension_settings_sync_util.h"
#include "chrome/browser/extensions/syncable_extension_settings_storage.h"
+#include "chrome/browser/extensions/extension_settings_test_util.h"
#include "chrome/browser/sync/api/sync_change_processor.h"
-#include "chrome/test/base/testing_profile.h"
#include "content/test/test_browser_thread.h"
// TODO(kalman): Integration tests for sync.
+using namespace extension_settings_test_util;
+
namespace {
// Gets the pretty-printed JSON for a value.
@@ -119,9 +120,7 @@ class MockSyncChangeProcessor : public SyncChangeProcessor {
ExtensionSettingSyncDataList changes_;
};
-// To be called as a callback from ExtensionSettingsFrontend::RunWithSettings.
-void AssignSettings(
- ExtensionSettingsBackend** dst, ExtensionSettingsBackend* src) {
+void AssignSettingsService(SyncableService** dst, SyncableService* src) {
*dst = src;
}
@@ -131,31 +130,43 @@ class ExtensionSettingsSyncTest : public testing::Test {
public:
ExtensionSettingsSyncTest()
: ui_thread_(BrowserThread::UI, MessageLoop::current()),
- file_thread_(BrowserThread::FILE, MessageLoop::current()),
- frontend_(&profile_),
- backend_(NULL) {
- }
+ file_thread_(BrowserThread::FILE, MessageLoop::current()) {}
virtual void SetUp() OVERRIDE {
- frontend_.RunWithBackend(base::Bind(&AssignSettings, &backend_));
- MessageLoop::current()->RunAllPending();
- ASSERT_TRUE(backend_ != NULL);
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ profile_.reset(new MockProfile(temp_dir_.path()));
+ frontend_.reset(new ExtensionSettingsFrontend(profile_.get()));
+ }
+
+ virtual void TearDown() OVERRIDE {
+ frontend_.reset();
+ profile_.reset();
}
protected:
- // Creates a new extension storage object and adds a record of the extension
- // to the extension service.
- SyncableExtensionSettingsStorage* GetStorage(
- const std::string& extension_id) {
- return static_cast<SyncableExtensionSettingsStorage*>(
- backend_->GetStorage(extension_id));
+ // Adds a record of an extension or app to the extension service, then returns
+ // its storage area.
+ ExtensionSettingsStorage* AddExtensionAndGetStorage(
+ const std::string& id, Extension::Type type) {
+ profile_->GetMockExtensionService()->AddExtension(id, type);
+ return GetStorage(id, frontend_.get());
}
- // Gets all the sync data from |backend_| as a map from extension id to its
- // sync data.
- std::map<std::string, ExtensionSettingSyncDataList> GetAllSyncData() {
+ // Gets the SyncableService for the given sync type.
+ SyncableService* GetSyncableService(syncable::ModelType model_type) {
+ SyncableService* settings_service = NULL;
+ frontend_->RunWithSyncableService(
+ model_type, base::Bind(&AssignSettingsService, &settings_service));
+ MessageLoop::current()->RunAllPending();
+ return settings_service;
+ }
+
+ // Gets all the sync data from the SyncableService for a sync type as a map
+ // from extension id to its sync data.
+ std::map<std::string, ExtensionSettingSyncDataList> GetAllSyncData(
+ syncable::ModelType model_type) {
SyncDataList as_list =
- backend_->GetAllSyncData(syncable::EXTENSION_SETTINGS);
+ GetSyncableService(model_type)->GetAllSyncData(model_type);
std::map<std::string, ExtensionSettingSyncDataList> as_map;
for (SyncDataList::iterator it = as_list.begin();
it != as_list.end(); ++it) {
@@ -170,48 +181,53 @@ class ExtensionSettingsSyncTest : public testing::Test {
content::TestBrowserThread ui_thread_;
content::TestBrowserThread file_thread_;
+ ScopedTempDir temp_dir_;
MockSyncChangeProcessor sync_;
- TestingProfile profile_;
- ExtensionSettingsFrontend frontend_;
-
- // Get from frontend_->RunWithBackend, so weak reference.
- ExtensionSettingsBackend* backend_;
+ scoped_ptr<MockProfile> profile_;
+ scoped_ptr<ExtensionSettingsFrontend> frontend_;
};
+// Get a semblance of coverage for both EXTENSION_SETTINGS and APP_SETTINGS
+// sync by roughly alternative which one to test.
+
TEST_F(ExtensionSettingsSyncTest, NoDataDoesNotInvokeSync) {
- ASSERT_EQ(0u, GetAllSyncData().size());
+ syncable::ModelType model_type = syncable::EXTENSION_SETTINGS;
+ Extension::Type type = Extension::TYPE_EXTENSION;
+
+ ASSERT_EQ(0u, GetAllSyncData(model_type).size());
// Have one extension created before sync is set up, the other created after.
- GetStorage("s1");
- ASSERT_EQ(0u, GetAllSyncData().size());
+ AddExtensionAndGetStorage("s1", type);
+ ASSERT_EQ(0u, GetAllSyncData(model_type).size());
- backend_->MergeDataAndStartSyncing(
- syncable::EXTENSION_SETTINGS,
- SyncDataList(),
- &sync_);
+ GetSyncableService(model_type)->MergeDataAndStartSyncing(
+ model_type, SyncDataList(), &sync_);
- GetStorage("s2");
- ASSERT_EQ(0u, GetAllSyncData().size());
+ AddExtensionAndGetStorage("s2", type);
+ ASSERT_EQ(0u, GetAllSyncData(model_type).size());
- backend_->StopSyncing(syncable::EXTENSION_SETTINGS);
+ GetSyncableService(model_type)->StopSyncing(model_type);
ASSERT_EQ(0u, sync_.changes().size());
- ASSERT_EQ(0u, GetAllSyncData().size());
+ ASSERT_EQ(0u, GetAllSyncData(model_type).size());
}
TEST_F(ExtensionSettingsSyncTest, InSyncDataDoesNotInvokeSync) {
+ syncable::ModelType model_type = syncable::APP_SETTINGS;
+ Extension::Type type = Extension::TYPE_PACKAGED_APP;
+
StringValue value1("fooValue");
ListValue value2;
value2.Append(StringValue::CreateStringValue("barValue"));
- SyncableExtensionSettingsStorage* storage1 = GetStorage("s1");
- SyncableExtensionSettingsStorage* storage2 = GetStorage("s2");
+ ExtensionSettingsStorage* storage1 = AddExtensionAndGetStorage("s1", type);
+ ExtensionSettingsStorage* storage2 = AddExtensionAndGetStorage("s2", type);
storage1->Set("foo", value1);
storage2->Set("bar", value2);
std::map<std::string, ExtensionSettingSyncDataList> all_sync_data =
- GetAllSyncData();
+ GetAllSyncData(model_type);
ASSERT_EQ(2u, all_sync_data.size());
ASSERT_EQ(1u, all_sync_data["s1"].size());
ASSERT_PRED_FORMAT2(ValuesEq, &value1, &all_sync_data["s1"][0].value());
@@ -224,8 +240,8 @@ TEST_F(ExtensionSettingsSyncTest, InSyncDataDoesNotInvokeSync) {
sync_data.push_back(extension_settings_sync_util::CreateData(
"s2", "bar", value2));
- backend_->MergeDataAndStartSyncing(
- syncable::EXTENSION_SETTINGS, sync_data, &sync_);
+ GetSyncableService(model_type)->MergeDataAndStartSyncing(
+ model_type, sync_data, &sync_);
// Already in sync, so no changes.
ASSERT_EQ(0u, sync_.changes().size());
@@ -241,22 +257,25 @@ TEST_F(ExtensionSettingsSyncTest, InSyncDataDoesNotInvokeSync) {
ASSERT_EQ(SyncChange::ACTION_UPDATE, change.change_type());
ASSERT_TRUE(value2.Equals(&change.value()));
- backend_->StopSyncing(syncable::EXTENSION_SETTINGS);
+ GetSyncableService(model_type)->StopSyncing(model_type);
}
TEST_F(ExtensionSettingsSyncTest, LocalDataWithNoSyncDataIsPushedToSync) {
+ syncable::ModelType model_type = syncable::EXTENSION_SETTINGS;
+ Extension::Type type = Extension::TYPE_EXTENSION;
+
StringValue value1("fooValue");
ListValue value2;
value2.Append(StringValue::CreateStringValue("barValue"));
- SyncableExtensionSettingsStorage* storage1 = GetStorage("s1");
- SyncableExtensionSettingsStorage* storage2 = GetStorage("s2");
+ ExtensionSettingsStorage* storage1 = AddExtensionAndGetStorage("s1", type);
+ ExtensionSettingsStorage* storage2 = AddExtensionAndGetStorage("s2", type);
storage1->Set("foo", value1);
storage2->Set("bar", value2);
- backend_->MergeDataAndStartSyncing(
- syncable::EXTENSION_SETTINGS, SyncDataList(), &sync_);
+ GetSyncableService(model_type)->MergeDataAndStartSyncing(
+ model_type, SyncDataList(), &sync_);
// All settings should have been pushed to sync.
ASSERT_EQ(2u, sync_.changes().size());
@@ -267,10 +286,13 @@ TEST_F(ExtensionSettingsSyncTest, LocalDataWithNoSyncDataIsPushedToSync) {
ASSERT_EQ(SyncChange::ACTION_ADD, change.change_type());
ASSERT_TRUE(value2.Equals(&change.value()));
- backend_->StopSyncing(syncable::EXTENSION_SETTINGS);
+ GetSyncableService(model_type)->StopSyncing(model_type);
}
TEST_F(ExtensionSettingsSyncTest, AnySyncDataOverwritesLocalData) {
+ syncable::ModelType model_type = syncable::APP_SETTINGS;
+ Extension::Type type = Extension::TYPE_PACKAGED_APP;
+
StringValue value1("fooValue");
ListValue value2;
value2.Append(StringValue::CreateStringValue("barValue"));
@@ -280,7 +302,7 @@ TEST_F(ExtensionSettingsSyncTest, AnySyncDataOverwritesLocalData) {
DictionaryValue expected1, expected2;
// Pre-populate one of the storage areas.
- SyncableExtensionSettingsStorage* storage1 = GetStorage("s1");
+ ExtensionSettingsStorage* storage1 = AddExtensionAndGetStorage("s1", type);
storage1->Set("overwriteMe", value1);
SyncDataList sync_data;
@@ -288,12 +310,12 @@ TEST_F(ExtensionSettingsSyncTest, AnySyncDataOverwritesLocalData) {
"s1", "foo", value1));
sync_data.push_back(extension_settings_sync_util::CreateData(
"s2", "bar", value2));
- backend_->MergeDataAndStartSyncing(
- syncable::EXTENSION_SETTINGS, sync_data, &sync_);
+ GetSyncableService(model_type)->MergeDataAndStartSyncing(
+ model_type, sync_data, &sync_);
expected1.Set("foo", value1.DeepCopy());
expected2.Set("bar", value2.DeepCopy());
- SyncableExtensionSettingsStorage* storage2 = GetStorage("s2");
+ ExtensionSettingsStorage* storage2 = AddExtensionAndGetStorage("s2", type);
// All changes should be local, so no sync changes.
ASSERT_EQ(0u, sync_.changes().size());
@@ -302,10 +324,13 @@ TEST_F(ExtensionSettingsSyncTest, AnySyncDataOverwritesLocalData) {
ASSERT_PRED_FORMAT2(SettingsEq, &expected1, storage1->Get());
ASSERT_PRED_FORMAT2(SettingsEq, &expected2, storage2->Get());
- backend_->StopSyncing(syncable::EXTENSION_SETTINGS);
+ GetSyncableService(model_type)->StopSyncing(model_type);
}
TEST_F(ExtensionSettingsSyncTest, ProcessSyncChanges) {
+ syncable::ModelType model_type = syncable::EXTENSION_SETTINGS;
+ Extension::Type type = Extension::TYPE_EXTENSION;
+
StringValue value1("fooValue");
ListValue value2;
value2.Append(StringValue::CreateStringValue("barValue"));
@@ -315,8 +340,8 @@ TEST_F(ExtensionSettingsSyncTest, ProcessSyncChanges) {
DictionaryValue expected1, expected2;
// Make storage1 initialised from local data, storage2 initialised from sync.
- SyncableExtensionSettingsStorage* storage1 = GetStorage("s1");
- SyncableExtensionSettingsStorage* storage2 = GetStorage("s2");
+ ExtensionSettingsStorage* storage1 = AddExtensionAndGetStorage("s1", type);
+ ExtensionSettingsStorage* storage2 = AddExtensionAndGetStorage("s2", type);
storage1->Set("foo", value1);
expected1.Set("foo", value1.DeepCopy());
@@ -325,8 +350,8 @@ TEST_F(ExtensionSettingsSyncTest, ProcessSyncChanges) {
sync_data.push_back(extension_settings_sync_util::CreateData(
"s2", "bar", value2));
- backend_->MergeDataAndStartSyncing(
- syncable::EXTENSION_SETTINGS, sync_data, &sync_);
+ GetSyncableService(model_type)->MergeDataAndStartSyncing(
+ model_type, sync_data, &sync_);
expected2.Set("bar", value2.DeepCopy());
// Make sync add some settings.
@@ -335,7 +360,7 @@ TEST_F(ExtensionSettingsSyncTest, ProcessSyncChanges) {
"s1", "bar", value2));
change_list.push_back(extension_settings_sync_util::CreateAdd(
"s2", "foo", value1));
- backend_->ProcessSyncChanges(FROM_HERE, change_list);
+ GetSyncableService(model_type)->ProcessSyncChanges(FROM_HERE, change_list);
expected1.Set("bar", value2.DeepCopy());
expected2.Set("foo", value1.DeepCopy());
@@ -349,7 +374,7 @@ TEST_F(ExtensionSettingsSyncTest, ProcessSyncChanges) {
"s1", "bar", value2));
change_list.push_back(extension_settings_sync_util::CreateUpdate(
"s2", "bar", value1));
- backend_->ProcessSyncChanges(FROM_HERE, change_list);
+ GetSyncableService(model_type)->ProcessSyncChanges(FROM_HERE, change_list);
expected1.Set("bar", value2.DeepCopy());
expected2.Set("bar", value1.DeepCopy());
@@ -363,27 +388,30 @@ TEST_F(ExtensionSettingsSyncTest, ProcessSyncChanges) {
"s1", "foo"));
change_list.push_back(extension_settings_sync_util::CreateDelete(
"s2", "foo"));
- backend_->ProcessSyncChanges(FROM_HERE, change_list);
+ GetSyncableService(model_type)->ProcessSyncChanges(FROM_HERE, change_list);
expected1.Remove("foo", NULL);
expected2.Remove("foo", NULL);
ASSERT_PRED_FORMAT2(SettingsEq, &expected1, storage1->Get());
ASSERT_PRED_FORMAT2(SettingsEq, &expected2, storage2->Get());
- backend_->StopSyncing(syncable::EXTENSION_SETTINGS);
+ GetSyncableService(model_type)->StopSyncing(model_type);
}
TEST_F(ExtensionSettingsSyncTest, PushToSync) {
+ syncable::ModelType model_type = syncable::APP_SETTINGS;
+ Extension::Type type = Extension::TYPE_PACKAGED_APP;
+
StringValue value1("fooValue");
ListValue value2;
value2.Append(StringValue::CreateStringValue("barValue"));
// Make storage1/2 initialised from local data, storage3/4 initialised from
// sync.
- SyncableExtensionSettingsStorage* storage1 = GetStorage("s1");
- SyncableExtensionSettingsStorage* storage2 = GetStorage("s2");
- SyncableExtensionSettingsStorage* storage3 = GetStorage("s3");
- SyncableExtensionSettingsStorage* storage4 = GetStorage("s4");
+ ExtensionSettingsStorage* storage1 = AddExtensionAndGetStorage("s1", type);
+ ExtensionSettingsStorage* storage2 = AddExtensionAndGetStorage("s2", type);
+ ExtensionSettingsStorage* storage3 = AddExtensionAndGetStorage("s3", type);
+ ExtensionSettingsStorage* storage4 = AddExtensionAndGetStorage("s4", type);
storage1->Set("foo", value1);
storage2->Set("foo", value1);
@@ -394,8 +422,8 @@ TEST_F(ExtensionSettingsSyncTest, PushToSync) {
sync_data.push_back(extension_settings_sync_util::CreateData(
"s4", "bar", value2));
- backend_->MergeDataAndStartSyncing(
- syncable::EXTENSION_SETTINGS, sync_data, &sync_);
+ GetSyncableService(model_type)->MergeDataAndStartSyncing(
+ model_type, sync_data, &sync_);
// Add something locally.
storage1->Set("bar", value2);
@@ -507,5 +535,53 @@ TEST_F(ExtensionSettingsSyncTest, PushToSync) {
SyncChange::ACTION_DELETE,
sync_.GetOnlyChange("s4", "bar").change_type());
- backend_->StopSyncing(syncable::EXTENSION_SETTINGS);
+ GetSyncableService(model_type)->StopSyncing(model_type);
+}
+
+TEST_F(ExtensionSettingsSyncTest, ExtensionAndAppSettingsSyncSeparately) {
+ StringValue value1("fooValue");
+ ListValue value2;
+ value2.Append(StringValue::CreateStringValue("barValue"));
+
+ // storage1 is an extension, storage2 is an app.
+ ExtensionSettingsStorage* storage1 = AddExtensionAndGetStorage(
+ "s1", Extension::TYPE_EXTENSION);
+ ExtensionSettingsStorage* storage2 = AddExtensionAndGetStorage(
+ "s2", Extension::TYPE_PACKAGED_APP);
+
+ storage1->Set("foo", value1);
+ storage2->Set("bar", value2);
+
+ std::map<std::string, ExtensionSettingSyncDataList> extension_sync_data =
+ GetAllSyncData(syncable::EXTENSION_SETTINGS);
+ ASSERT_EQ(1u, extension_sync_data.size());
+ ASSERT_EQ(1u, extension_sync_data["s1"].size());
+ ASSERT_PRED_FORMAT2(ValuesEq, &value1, &extension_sync_data["s1"][0].value());
+
+ std::map<std::string, ExtensionSettingSyncDataList> app_sync_data =
+ GetAllSyncData(syncable::APP_SETTINGS);
+ ASSERT_EQ(1u, app_sync_data.size());
+ ASSERT_EQ(1u, app_sync_data["s2"].size());
+ ASSERT_PRED_FORMAT2(ValuesEq, &value2, &app_sync_data["s2"][0].value());
+
+ // Stop each separately, there should be no changes either time.
+ SyncDataList sync_data;
+ sync_data.push_back(extension_settings_sync_util::CreateData(
+ "s1", "foo", value1));
+
+ GetSyncableService(syncable::EXTENSION_SETTINGS)->
+ MergeDataAndStartSyncing(syncable::EXTENSION_SETTINGS, sync_data, &sync_);
+ GetSyncableService(syncable::EXTENSION_SETTINGS)->
+ StopSyncing(syncable::EXTENSION_SETTINGS);
+ ASSERT_EQ(0u, sync_.changes().size());
+
+ sync_data.clear();
+ sync_data.push_back(extension_settings_sync_util::CreateData(
+ "s2", "bar", value2));
+
+ GetSyncableService(syncable::APP_SETTINGS)->
+ MergeDataAndStartSyncing(syncable::APP_SETTINGS, sync_data, &sync_);
+ GetSyncableService(syncable::APP_SETTINGS)->
+ StopSyncing(syncable::APP_SETTINGS);
+ ASSERT_EQ(0u, sync_.changes().size());
}
diff --git a/chrome/browser/extensions/extension_settings_test_util.cc b/chrome/browser/extensions/extension_settings_test_util.cc
new file mode 100644
index 0000000..8ed7cdc
--- /dev/null
+++ b/chrome/browser/extensions/extension_settings_test_util.cc
@@ -0,0 +1,95 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/extension_settings_test_util.h"
+
+#include "base/file_path.h"
+#include "chrome/common/extensions/extension.h"
+
+namespace extension_settings_test_util {
+
+// Intended as a StorageCallback from GetStorage.
+static void AssignStorage(
+ ExtensionSettingsStorage** dst, ExtensionSettingsStorage* src) {
+ *dst = src;
+}
+
+ExtensionSettingsStorage* GetStorage(
+ const std::string& extension_id, ExtensionSettingsFrontend* frontend) {
+ ExtensionSettingsStorage* storage = NULL;
+ frontend->RunWithStorage(
+ extension_id,
+ base::Bind(&AssignStorage, &storage));
+ MessageLoop::current()->RunAllPending();
+ return storage;
+}
+
+MockExtensionService::MockExtensionService() {}
+
+MockExtensionService::~MockExtensionService() {}
+
+const Extension* MockExtensionService::GetExtensionById(
+ const std::string& id, bool include_disabled) const {
+ std::map<std::string, scoped_refptr<Extension> >::const_iterator
+ maybe_extension = extensions_.find(id);
+ return maybe_extension == extensions_.end() ?
+ NULL : maybe_extension->second.get();
+}
+
+void MockExtensionService::AddExtension(
+ const std::string& id, Extension::Type type) {
+ DictionaryValue manifest;
+ manifest.SetString("name", std::string("Test extension ") + id);
+ manifest.SetString("version", "1.0");
+
+ switch (type) {
+ case Extension::TYPE_EXTENSION:
+ break;
+
+ case Extension::TYPE_PACKAGED_APP: {
+ DictionaryValue* app = new DictionaryValue();
+ DictionaryValue* app_launch = new DictionaryValue();
+ app_launch->SetString("local_path", "fake.html");
+ app->Set("launch", app_launch);
+ manifest.Set("app", app);
+ break;
+ }
+
+ default:
+ NOTREACHED();
+ }
+
+ std::string error;
+ extensions_[id] = Extension::CreateWithId(
+ FilePath(),
+ Extension::INTERNAL,
+ manifest,
+ Extension::NO_FLAGS,
+ id,
+ &error);
+ DCHECK(error.empty());
+}
+
+MockProfile::MockProfile(const FilePath& file_path)
+ : TestingProfile(file_path) {
+ event_router_.reset(new ExtensionEventRouter(this));
+}
+
+MockProfile::~MockProfile() {}
+
+MockExtensionService* MockProfile::GetMockExtensionService() {
+ return &extension_service_;
+}
+
+ExtensionService* MockProfile::GetExtensionService() {
+ ExtensionServiceInterface* as_interface =
+ static_cast<ExtensionServiceInterface*>(&extension_service_);
+ return static_cast<ExtensionService*>(as_interface);
+}
+
+ExtensionEventRouter* MockProfile::GetExtensionEventRouter() {
+ return event_router_.get();
+}
+
+} // namespace extension_settings_test_util
diff --git a/chrome/browser/extensions/extension_settings_test_util.h b/chrome/browser/extensions/extension_settings_test_util.h
new file mode 100644
index 0000000..a7bc9d0
--- /dev/null
+++ b/chrome/browser/extensions/extension_settings_test_util.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2011 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.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_SETTINGS_TEST_UTIL_H_
+#define CHROME_BROWSER_EXTENSIONS_EXTENSION_SETTINGS_TEST_UTIL_H_
+#pragma once
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "chrome/browser/extensions/extension_event_router.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/test_extension_service.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/test/base/testing_profile.h"
+
+class ExtensionSettingsFrontend;
+
+// Utilities for extension settings API tests.
+namespace extension_settings_test_util {
+
+// Synchronously gets the storage area for an extension from |frontend|.
+ExtensionSettingsStorage* GetStorage(
+ const std::string& extension_id, ExtensionSettingsFrontend* frontend);
+
+// An ExtensionService which allows extensions to be hand-added to be returned
+// by GetExtensionById.
+class MockExtensionService : public TestExtensionService {
+ public:
+ MockExtensionService();
+ virtual ~MockExtensionService();
+
+ // Adds an extension with id |id| to be returned by GetExtensionById.
+ void AddExtension(const std::string& id, Extension::Type type);
+
+ virtual const Extension* GetExtensionById(
+ const std::string& id, bool include_disabled) const OVERRIDE;
+
+ private:
+ std::map<std::string, scoped_refptr<Extension> > extensions_;
+};
+
+// A Profile which returns ExtensionService and ExtensionEventRouters with
+// enough functionality for the tests.
+class MockProfile : public TestingProfile {
+ public:
+ explicit MockProfile(const FilePath& file_path);
+ virtual ~MockProfile();
+
+ // Returns the same object as GetExtensionService, but not coaxed into an
+ // ExtensionService; use this method from tests.
+ MockExtensionService* GetMockExtensionService();
+
+ virtual ExtensionService* GetExtensionService() OVERRIDE;
+ virtual ExtensionEventRouter* GetExtensionEventRouter() OVERRIDE;
+
+ private:
+ MockExtensionService extension_service_;
+ scoped_ptr<ExtensionEventRouter> event_router_;
+};
+
+} // namespace extension_settings_test_util
+
+#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_SETTINGS_TEST_UTIL_H_
diff --git a/chrome/browser/extensions/syncable_extension_settings_storage.cc b/chrome/browser/extensions/syncable_extension_settings_storage.cc
index e6e9fe5..bd5f3d1 100644
--- a/chrome/browser/extensions/syncable_extension_settings_storage.cc
+++ b/chrome/browser/extensions/syncable_extension_settings_storage.cc
@@ -18,6 +18,7 @@ SyncableExtensionSettingsStorage::SyncableExtensionSettingsStorage(
: observers_(observers),
extension_id_(extension_id),
delegate_(delegate),
+ sync_type_(syncable::UNSPECIFIED),
sync_processor_(NULL) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
}
@@ -110,10 +111,17 @@ ExtensionSettingsStorage::Result SyncableExtensionSettingsStorage::Clear() {
// Sync-related methods.
SyncError SyncableExtensionSettingsStorage::StartSyncing(
- const DictionaryValue& sync_state, SyncChangeProcessor* sync_processor) {
+ syncable::ModelType type,
+ const DictionaryValue& sync_state,
+ SyncChangeProcessor* sync_processor) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK(type == syncable::EXTENSION_SETTINGS ||
+ type == syncable::APP_SETTINGS);
+ DCHECK_EQ(sync_type_, syncable::UNSPECIFIED);
DCHECK(!sync_processor_);
DCHECK(synced_keys_.empty());
+
+ sync_type_ = type;
sync_processor_ = sync_processor;
Result maybe_settings = delegate_->Get();
@@ -121,7 +129,7 @@ SyncError SyncableExtensionSettingsStorage::StartSyncing(
return SyncError(
FROM_HERE,
std::string("Failed to get settings: ") + maybe_settings.GetError(),
- syncable::EXTENSION_SETTINGS);
+ type);
}
const DictionaryValue* settings = maybe_settings.GetSettings();
@@ -221,7 +229,11 @@ SyncError SyncableExtensionSettingsStorage::OverwriteLocalSettingsWithSync(
void SyncableExtensionSettingsStorage::StopSyncing() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK(sync_type_ == syncable::EXTENSION_SETTINGS ||
+ sync_type_ == syncable::APP_SETTINGS);
DCHECK(sync_processor_);
+
+ sync_type_ = syncable::UNSPECIFIED;
sync_processor_ = NULL;
synced_keys_.clear();
}
@@ -250,7 +262,7 @@ std::vector<SyncError> SyncableExtensionSettingsStorage::ProcessSyncChanges(
FROM_HERE,
std::string("Error getting current sync state for ") +
extension_id_ + "/" + key + ": " + maybe_settings.GetError(),
- syncable::EXTENSION_SETTINGS));
+ sync_type_));
continue;
}
const DictionaryValue* settings = maybe_settings.GetSettings();
@@ -397,7 +409,7 @@ SyncError SyncableExtensionSettingsStorage::OnSyncAdd(
FROM_HERE,
std::string("Error pushing sync add to local settings: ") +
result.GetError(),
- syncable::EXTENSION_SETTINGS);
+ sync_type_);
}
changes->AppendChange(key, NULL, new_value);
return SyncError();
@@ -416,7 +428,7 @@ SyncError SyncableExtensionSettingsStorage::OnSyncUpdate(
FROM_HERE,
std::string("Error pushing sync update to local settings: ") +
result.GetError(),
- syncable::EXTENSION_SETTINGS);
+ sync_type_);
}
changes->AppendChange(key, old_value, new_value);
return SyncError();
@@ -434,7 +446,7 @@ SyncError SyncableExtensionSettingsStorage::OnSyncDelete(
FROM_HERE,
std::string("Error pushing sync remove to local settings: ") +
result.GetError(),
- syncable::EXTENSION_SETTINGS);
+ sync_type_);
}
changes->AppendChange(key, old_value, NULL);
return SyncError();
diff --git a/chrome/browser/extensions/syncable_extension_settings_storage.h b/chrome/browser/extensions/syncable_extension_settings_storage.h
index 499d89c..d222987 100644
--- a/chrome/browser/extensions/syncable_extension_settings_storage.h
+++ b/chrome/browser/extensions/syncable_extension_settings_storage.h
@@ -41,6 +41,8 @@ class SyncableExtensionSettingsStorage : public ExtensionSettingsStorage {
// Sync-related methods, analogous to those on SyncableService (handled by
// ExtensionSettings).
SyncError StartSyncing(
+ // Either EXTENSION_SETTINGS or APP_SETTINGS.
+ syncable::ModelType type,
const DictionaryValue& sync_state,
// Must NOT be NULL. Ownership NOT taken.
SyncChangeProcessor* sync_processor);
@@ -92,6 +94,10 @@ class SyncableExtensionSettingsStorage : public ExtensionSettingsStorage {
// Storage area to sync.
const scoped_ptr<ExtensionSettingsStorage> delegate_;
+ // Sync model type. Either EXTENSION_SETTINGS or APP_SETTINGS while sync is
+ // enabled (between calls to Start/StopSyncing), or UNSPECIFIED while not.
+ syncable::ModelType sync_type_;
+
// Sync processor. Non-NULL while sync is enabled (between calls to
// StartSyncing and StopSyncing).
SyncChangeProcessor* sync_processor_;
diff --git a/chrome/browser/sync/glue/data_type_manager_impl.cc b/chrome/browser/sync/glue/data_type_manager_impl.cc
index 6ea458a..be3ebf7 100644
--- a/chrome/browser/sync/glue/data_type_manager_impl.cc
+++ b/chrome/browser/sync/glue/data_type_manager_impl.cc
@@ -34,6 +34,7 @@ static const syncable::ModelType kStartOrder[] = {
syncable::AUTOFILL_PROFILE,
syncable::EXTENSION_SETTINGS,
syncable::EXTENSIONS,
+ syncable::APP_SETTINGS,
syncable::APPS,
syncable::THEMES,
syncable::TYPED_URLS,
diff --git a/chrome/browser/sync/glue/extension_setting_data_type_controller.cc b/chrome/browser/sync/glue/extension_setting_data_type_controller.cc
index 03e6a3d..8fbe849 100644
--- a/chrome/browser/sync/glue/extension_setting_data_type_controller.cc
+++ b/chrome/browser/sync/glue/extension_setting_data_type_controller.cc
@@ -16,21 +16,25 @@
namespace browser_sync {
ExtensionSettingDataTypeController::ExtensionSettingDataTypeController(
+ syncable::ModelType type,
ProfileSyncFactory* profile_sync_factory,
Profile* profile,
ProfileSyncService* profile_sync_service)
: NonFrontendDataTypeController(profile_sync_factory, profile),
+ type_(type),
extension_settings_frontend_(
profile->GetExtensionService()->extension_settings_frontend()),
profile_sync_service_(profile_sync_service),
- extension_settings_backend_(NULL) {
+ settings_service_(NULL) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DCHECK(type == syncable::EXTENSION_SETTINGS ||
+ type == syncable::APP_SETTINGS);
}
ExtensionSettingDataTypeController::~ExtensionSettingDataTypeController() {}
syncable::ModelType ExtensionSettingDataTypeController::type() const {
- return syncable::EXTENSION_SETTINGS;
+ return type_;
}
browser_sync::ModelSafeGroup
@@ -45,31 +49,32 @@ bool ExtensionSettingDataTypeController::StartModels() {
bool ExtensionSettingDataTypeController::StartAssociationAsync() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK_EQ(state(), ASSOCIATING);
- extension_settings_frontend_->RunWithBackend(
+ extension_settings_frontend_->RunWithSyncableService(
+ type_,
base::Bind(
&ExtensionSettingDataTypeController::
- StartAssociationWithExtensionSettingsBackend,
+ StartAssociationWithExtensionSettingsService,
this));
return true;
}
void ExtensionSettingDataTypeController::
- StartAssociationWithExtensionSettingsBackend(
- ExtensionSettingsBackend* extension_settings_backend) {
+ StartAssociationWithExtensionSettingsService(
+ SyncableService* settings_service) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
- extension_settings_backend_ = extension_settings_backend;
- // Calls CreateSyncComponents, which expects extension_settings_backend_ to
- // be non-NULL.
+ settings_service_ = settings_service;
+ // Calls CreateSyncComponents, which expects settings_service_ to be
+ // non-NULL.
StartAssociation();
}
void ExtensionSettingDataTypeController::CreateSyncComponents() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
DCHECK_EQ(state(), ASSOCIATING);
- DCHECK(extension_settings_backend_);
+ DCHECK(settings_service_);
ProfileSyncFactory::SyncComponents sync_components =
- profile_sync_factory()->CreateExtensionSettingSyncComponents(
- extension_settings_backend_, profile_sync_service_, this);
+ profile_sync_factory()->CreateExtensionOrAppSettingSyncComponents(
+ type_, settings_service_, profile_sync_service_, this);
set_model_associator(sync_components.model_associator);
set_change_processor(sync_components.change_processor);
}
diff --git a/chrome/browser/sync/glue/extension_setting_data_type_controller.h b/chrome/browser/sync/glue/extension_setting_data_type_controller.h
index 44227f7..9b027fe 100644
--- a/chrome/browser/sync/glue/extension_setting_data_type_controller.h
+++ b/chrome/browser/sync/glue/extension_setting_data_type_controller.h
@@ -11,11 +11,11 @@
#include "base/compiler_specific.h"
#include "chrome/browser/sync/glue/non_frontend_data_type_controller.h"
-class ExtensionSettingsBackend;
class ExtensionSettingsFrontend;
class Profile;
class ProfileSyncFactory;
class ProfileSyncService;
+class SyncableService;
namespace browser_sync {
@@ -23,6 +23,8 @@ class ExtensionSettingDataTypeController
: public NonFrontendDataTypeController {
public:
ExtensionSettingDataTypeController(
+ // Either EXTENSION_SETTINGS or APP_SETTINGS.
+ syncable::ModelType type,
ProfileSyncFactory* profile_sync_factory,
Profile* profile,
ProfileSyncService* profile_sync_service);
@@ -44,17 +46,20 @@ class ExtensionSettingDataTypeController
virtual void RecordAssociationTime(base::TimeDelta time) OVERRIDE;
virtual void RecordStartFailure(StartResult result) OVERRIDE;
- // Starts sync association with |extension_settings|. Callback from
+ // Starts sync association with |settings_service|. Callback from
// RunWithSettings of |extension_settings_ui_wrapper_| on FILE thread.
- void StartAssociationWithExtensionSettingsBackend(
- ExtensionSettingsBackend* extension_settings_backend);
+ void StartAssociationWithExtensionSettingsService(
+ SyncableService* settings_service);
+
+ // Either EXTENSION_SETTINGS or APP_SETTINGS.
+ syncable::ModelType type_;
// These only used on the UI thread.
ExtensionSettingsFrontend* extension_settings_frontend_;
ProfileSyncService* profile_sync_service_;
// Only used on the FILE thread.
- ExtensionSettingsBackend* extension_settings_backend_;
+ SyncableService* settings_service_;
DISALLOW_COPY_AND_ASSIGN(ExtensionSettingDataTypeController);
};
diff --git a/chrome/browser/sync/profile_sync_factory.h b/chrome/browser/sync/profile_sync_factory.h
index d956d3c..8e60f08 100644
--- a/chrome/browser/sync/profile_sync_factory.h
+++ b/chrome/browser/sync/profile_sync_factory.h
@@ -15,7 +15,6 @@
#include "chrome/browser/sync/glue/model_associator.h"
#include "chrome/browser/sync/unrecoverable_error_handler.h"
-class ExtensionSettingsBackend;
class PasswordStore;
class PersonalDataManager;
class ProfileSyncService;
@@ -115,10 +114,12 @@ class ProfileSyncFactory {
browser_sync::UnrecoverableErrorHandler* error_handler) = 0;
// Instantiates both a model associator and change processor for the
- // extension setting data type. The pointers in the return struct are
+ // extension or app setting data type. The pointers in the return struct are
// owned by the caller.
- virtual SyncComponents CreateExtensionSettingSyncComponents(
- ExtensionSettingsBackend* extension_settings_backend_,
+ virtual SyncComponents CreateExtensionOrAppSettingSyncComponents(
+ // Either EXTENSION_SETTINGS or APP_SETTINGS.
+ syncable::ModelType type,
+ SyncableService* settings_service,
ProfileSyncService* profile_sync_service,
browser_sync::UnrecoverableErrorHandler* error_handler) = 0;
diff --git a/chrome/browser/sync/profile_sync_factory_impl.cc b/chrome/browser/sync/profile_sync_factory_impl.cc
index 007acbb..169eb0e 100644
--- a/chrome/browser/sync/profile_sync_factory_impl.cc
+++ b/chrome/browser/sync/profile_sync_factory_impl.cc
@@ -166,7 +166,11 @@ void ProfileSyncFactoryImpl::RegisterDataTypes(ProfileSyncService* pss) {
// explicitly enabled.
if (command_line_->HasSwitch(switches::kEnableSyncExtensionSettings)) {
pss->RegisterDataTypeController(
- new ExtensionSettingDataTypeController(this, profile_, pss));
+ new ExtensionSettingDataTypeController(
+ syncable::EXTENSION_SETTINGS, this, profile_, pss));
+ pss->RegisterDataTypeController(
+ new ExtensionSettingDataTypeController(
+ syncable::APP_SETTINGS, this, profile_, pss));
}
if (!command_line_->HasSwitch(switches::kDisableSyncAutofillProfile)) {
@@ -269,19 +273,22 @@ ProfileSyncFactoryImpl::CreateBookmarkSyncComponents(
}
ProfileSyncFactory::SyncComponents
-ProfileSyncFactoryImpl::CreateExtensionSettingSyncComponents(
- ExtensionSettingsBackend* extension_settings_backend,
+ProfileSyncFactoryImpl::CreateExtensionOrAppSettingSyncComponents(
+ syncable::ModelType type,
+ SyncableService* settings_service,
ProfileSyncService* profile_sync_service,
UnrecoverableErrorHandler* error_handler) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ DCHECK(type == syncable::EXTENSION_SETTINGS ||
+ type == syncable::APP_SETTINGS);
sync_api::UserShare* user_share = profile_sync_service->GetUserShare();
GenericChangeProcessor* change_processor =
new GenericChangeProcessor(error_handler,
- extension_settings_backend->AsWeakPtr(),
+ settings_service->AsWeakPtr(),
user_share);
browser_sync::SyncableServiceAdapter* sync_service_adapter =
- new browser_sync::SyncableServiceAdapter(syncable::EXTENSION_SETTINGS,
- extension_settings_backend,
+ new browser_sync::SyncableServiceAdapter(type,
+ settings_service,
change_processor);
return SyncComponents(sync_service_adapter, change_processor);
}
diff --git a/chrome/browser/sync/profile_sync_factory_impl.h b/chrome/browser/sync/profile_sync_factory_impl.h
index f7e7494..8d962f1f3 100644
--- a/chrome/browser/sync/profile_sync_factory_impl.h
+++ b/chrome/browser/sync/profile_sync_factory_impl.h
@@ -12,7 +12,6 @@
#include "chrome/browser/sync/profile_sync_factory.h"
class CommandLine;
-class ExtensionSettingsBackend;
class Profile;
class ProfileSyncFactoryImpl : public ProfileSyncFactory {
@@ -53,8 +52,10 @@ class ProfileSyncFactoryImpl : public ProfileSyncFactory {
ProfileSyncService* profile_sync_service,
browser_sync::UnrecoverableErrorHandler* error_handler);
- virtual SyncComponents CreateExtensionSettingSyncComponents(
- ExtensionSettingsBackend* extension_settings_backend,
+ virtual SyncComponents CreateExtensionOrAppSettingSyncComponents(
+ // Either EXTENSION_SETTING or APP_SETTING.
+ syncable::ModelType type,
+ SyncableService* settings_service,
ProfileSyncService* profile_sync_service,
browser_sync::UnrecoverableErrorHandler* error_handler);
diff --git a/chrome/browser/sync/profile_sync_factory_mock.h b/chrome/browser/sync/profile_sync_factory_mock.h
index 0d184d1..3065aa1 100644
--- a/chrome/browser/sync/profile_sync_factory_mock.h
+++ b/chrome/browser/sync/profile_sync_factory_mock.h
@@ -11,8 +11,6 @@
#include "chrome/browser/sync/profile_sync_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
-class ExtensionSettingsBackend;
-
namespace browser_sync {
class AssociatorInterface;
class ChangeProcessor;
@@ -57,8 +55,9 @@ class ProfileSyncFactoryMock : public ProfileSyncFactory {
MOCK_METHOD2(CreateExtensionSyncComponents,
SyncComponents(ProfileSyncService* profile_sync_service,
browser_sync::UnrecoverableErrorHandler* error_handler));
- MOCK_METHOD3(CreateExtensionSettingSyncComponents,
- SyncComponents(ExtensionSettingsBackend* extension_settings_backend,
+ MOCK_METHOD4(CreateExtensionOrAppSettingSyncComponents,
+ SyncComponents(syncable::ModelType model_type,
+ SyncableService* settings_service,
ProfileSyncService* profile_sync_service,
browser_sync::UnrecoverableErrorHandler* error_handler));
MOCK_METHOD3(CreatePasswordSyncComponents,
diff --git a/chrome/browser/sync/protocol/app_setting_specifics.proto b/chrome/browser/sync/protocol/app_setting_specifics.proto
new file mode 100644
index 0000000..0d9e25d
--- /dev/null
+++ b/chrome/browser/sync/protocol/app_setting_specifics.proto
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 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 an app setting.
+// This is the same as for an extension setting, but uses a separate datatype
+// in order to control syncability separately.
+
+// Update proto_value_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;
+
+import "sync.proto";
+import "extension_setting_specifics.proto";
+
+// Properties of app setting sync objects; just an extension setting.
+message AppSettingSpecifics {
+ optional ExtensionSettingSpecifics extension_setting = 1;
+}
+
+extend EntitySpecifics {
+ optional AppSettingSpecifics app_setting = 103656;
+}
diff --git a/chrome/browser/sync/protocol/nigori_specifics.proto b/chrome/browser/sync/protocol/nigori_specifics.proto
index d43576b..6780783 100644
--- a/chrome/browser/sync/protocol/nigori_specifics.proto
+++ b/chrome/browser/sync/protocol/nigori_specifics.proto
@@ -67,8 +67,8 @@ message NigoriSpecifics {
optional bool encrypt_everything = 24;
optional bool encrypt_extension_settings = 25;
-
optional bool encrypt_app_notifications = 26;
+ optional bool encrypt_app_settings = 27;
}
extend EntitySpecifics {
diff --git a/chrome/browser/sync/protocol/proto_value_conversions.cc b/chrome/browser/sync/protocol/proto_value_conversions.cc
index 82e7364..0201a9c 100644
--- a/chrome/browser/sync/protocol/proto_value_conversions.cc
+++ b/chrome/browser/sync/protocol/proto_value_conversions.cc
@@ -12,6 +12,7 @@
#include "base/string_number_conversions.h"
#include "base/values.h"
#include "chrome/browser/sync/protocol/app_notification_specifics.pb.h"
+#include "chrome/browser/sync/protocol/app_setting_specifics.pb.h"
#include "chrome/browser/sync/protocol/app_specifics.pb.h"
#include "chrome/browser/sync/protocol/autofill_specifics.pb.h"
#include "chrome/browser/sync/protocol/bookmark_specifics.pb.h"
@@ -186,6 +187,13 @@ DictionaryValue* AppNotificationSpecificsToValue(
return value;
}
+DictionaryValue* AppSettingSpecificsToValue(
+ const sync_pb::AppSettingSpecifics& proto) {
+ DictionaryValue* value = new DictionaryValue();
+ SET(extension_setting, ExtensionSettingSpecificsToValue);
+ return value;
+}
+
DictionaryValue* AppSpecificsToValue(
const sync_pb::AppSpecifics& proto) {
DictionaryValue* value = new DictionaryValue();
@@ -269,13 +277,14 @@ DictionaryValue* NigoriSpecificsToValue(
SET_BOOL(encrypt_autofill);
SET_BOOL(encrypt_themes);
SET_BOOL(encrypt_typed_urls);
+ SET_BOOL(encrypt_extension_settings);
SET_BOOL(encrypt_extensions);
SET_BOOL(encrypt_sessions);
+ SET_BOOL(encrypt_app_settings);
SET_BOOL(encrypt_apps);
SET_BOOL(encrypt_search_engines);
SET_BOOL(sync_tabs);
SET_BOOL(encrypt_everything);
- SET_BOOL(encrypt_extension_settings);
return value;
}
@@ -349,8 +358,9 @@ DictionaryValue* TypedUrlSpecificsToValue(
DictionaryValue* EntitySpecificsToValue(
const sync_pb::EntitySpecifics& specifics) {
DictionaryValue* value = new DictionaryValue();
- SET_EXTENSION(sync_pb, app_notification, AppNotificationSpecificsToValue);
SET_EXTENSION(sync_pb, app, AppSpecificsToValue);
+ SET_EXTENSION(sync_pb, app_notification, AppNotificationSpecificsToValue);
+ SET_EXTENSION(sync_pb, app_setting, AppSettingSpecificsToValue);
SET_EXTENSION(sync_pb, autofill, AutofillSpecificsToValue);
SET_EXTENSION(sync_pb, autofill_profile, AutofillProfileSpecificsToValue);
SET_EXTENSION(sync_pb, bookmark, BookmarkSpecificsToValue);
diff --git a/chrome/browser/sync/protocol/proto_value_conversions.h b/chrome/browser/sync/protocol/proto_value_conversions.h
index 82b636f..1bd7427 100644
--- a/chrome/browser/sync/protocol/proto_value_conversions.h
+++ b/chrome/browser/sync/protocol/proto_value_conversions.h
@@ -15,6 +15,7 @@ class DictionaryValue;
namespace sync_pb {
class AppNotificationSettings;
class AppNotificationSpecifics;
+class AppSettingSpecifics;
class AppSpecifics;
class AutofillProfileSpecifics;
class AutofillSpecifics;
@@ -83,6 +84,9 @@ base::DictionaryValue* PasswordSpecificsDataToValue(
base::DictionaryValue* AppNotificationSpecificsToValue(
const sync_pb::AppNotificationSpecifics& app_notification_specifics);
+base::DictionaryValue* AppSettingSpecificsToValue(
+ const sync_pb::AppSettingSpecifics& app_setting_specifics);
+
base::DictionaryValue* AppSpecificsToValue(
const sync_pb::AppSpecifics& app_specifics);
diff --git a/chrome/browser/sync/protocol/proto_value_conversions_unittest.cc b/chrome/browser/sync/protocol/proto_value_conversions_unittest.cc
index d8ef628..63ada75 100644
--- a/chrome/browser/sync/protocol/proto_value_conversions_unittest.cc
+++ b/chrome/browser/sync/protocol/proto_value_conversions_unittest.cc
@@ -9,6 +9,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/values.h"
#include "chrome/browser/sync/protocol/app_notification_specifics.pb.h"
+#include "chrome/browser/sync/protocol/app_setting_specifics.pb.h"
#include "chrome/browser/sync/protocol/app_specifics.pb.h"
#include "chrome/browser/sync/protocol/autofill_specifics.pb.h"
#include "chrome/browser/sync/protocol/bookmark_specifics.pb.h"
@@ -46,7 +47,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(16, syncable::MODEL_TYPE_COUNT);
+ EXPECT_EQ(17, syncable::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
@@ -89,6 +90,10 @@ TEST_F(ProtoValueConversionsTest, AppNotificationSpecificsToValue) {
TestSpecificsToValue(AppNotificationSpecificsToValue);
}
+TEST_F(ProtoValueConversionsTest, AppSettingSpecificsToValue) {
+ TestSpecificsToValue(AppSettingSpecificsToValue);
+}
+
TEST_F(ProtoValueConversionsTest, AppSpecificsToValue) {
TestSpecificsToValue(AppSpecificsToValue);
}
@@ -151,6 +156,7 @@ TEST_F(ProtoValueConversionsTest, EntitySpecificsToValue) {
SET_EXTENSION(app);
SET_EXTENSION(app_notification);
+ SET_EXTENSION(app_setting);
SET_EXTENSION(autofill);
SET_EXTENSION(autofill_profile);
SET_EXTENSION(bookmark);
diff --git a/chrome/browser/sync/protocol/sync_proto.gyp b/chrome/browser/sync/protocol/sync_proto.gyp
index 9f5bde1..dcf302f 100644
--- a/chrome/browser/sync/protocol/sync_proto.gyp
+++ b/chrome/browser/sync/protocol/sync_proto.gyp
@@ -14,6 +14,7 @@
'sync.proto',
'encryption.proto',
'app_notification_specifics.proto',
+ 'app_setting_specifics.proto',
'app_specifics.proto',
'autofill_specifics.proto',
'bookmark_specifics.proto',
diff --git a/chrome/browser/sync/sync_prefs.cc b/chrome/browser/sync/sync_prefs.cc
index 2be149f..8987900 100644
--- a/chrome/browser/sync/sync_prefs.cc
+++ b/chrome/browser/sync/sync_prefs.cc
@@ -372,6 +372,8 @@ const char* GetPrefNameForDataType(syncable::ModelType data_type) {
return prefs::kSyncExtensionSettings;
case syncable::EXTENSIONS:
return prefs::kSyncExtensions;
+ case syncable::APP_SETTINGS:
+ return prefs::kSyncAppSettings;
case syncable::APPS:
return prefs::kSyncApps;
case syncable::SEARCH_ENGINES:
diff --git a/chrome/browser/sync/syncable/model_type.cc b/chrome/browser/sync/syncable/model_type.cc
index 77c33aa..aaf555e 100644
--- a/chrome/browser/sync/syncable/model_type.cc
+++ b/chrome/browser/sync/syncable/model_type.cc
@@ -9,6 +9,7 @@
#include "base/values.h"
#include "chrome/browser/sync/engine/syncproto.h"
#include "chrome/browser/sync/protocol/app_notification_specifics.pb.h"
+#include "chrome/browser/sync/protocol/app_setting_specifics.pb.h"
#include "chrome/browser/sync/protocol/app_specifics.pb.h"
#include "chrome/browser/sync/protocol/autofill_specifics.pb.h"
#include "chrome/browser/sync/protocol/bookmark_specifics.pb.h"
@@ -64,6 +65,9 @@ void AddDefaultExtensionValue(syncable::ModelType datatype,
case APPS:
specifics->MutableExtension(sync_pb::app);
break;
+ case APP_SETTINGS:
+ specifics->MutableExtension(sync_pb::app_setting);
+ break;
case EXTENSION_SETTINGS:
specifics->MutableExtension(sync_pb::extension_setting);
break;
@@ -123,6 +127,9 @@ int GetExtensionFieldNumberFromModelType(ModelType model_type) {
case APPS:
return sync_pb::kAppFieldNumber;
break;
+ case APP_SETTINGS:
+ return sync_pb::kAppSettingFieldNumber;
+ break;
case EXTENSION_SETTINGS:
return sync_pb::kExtensionSettingFieldNumber;
break;
@@ -206,6 +213,9 @@ ModelType GetModelTypeFromSpecifics(const sync_pb::EntitySpecifics& specifics) {
if (specifics.HasExtension(sync_pb::session))
return SESSIONS;
+ if (specifics.HasExtension(sync_pb::app_setting))
+ return APP_SETTINGS;
+
if (specifics.HasExtension(sync_pb::extension_setting))
return EXTENSION_SETTINGS;
@@ -252,6 +262,8 @@ std::string ModelTypeToString(ModelType model_type) {
return "Apps";
case AUTOFILL_PROFILE:
return "Autofill Profiles";
+ case APP_SETTINGS:
+ return "App settings";
case EXTENSION_SETTINGS:
return "Extension settings";
case APP_NOTIFICATIONS:
@@ -326,6 +338,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 settings")
+ return APP_SETTINGS;
else if (model_type_string == "Extension settings")
return EXTENSION_SETTINGS;
else if (model_type_string == "App Notifications")
@@ -422,6 +436,8 @@ std::string ModelTypeToRootTag(ModelType type) {
return "google_chrome_apps";
case AUTOFILL_PROFILE:
return "google_chrome_autofill_profiles";
+ case APP_SETTINGS:
+ return "google_chrome_app_settings";
case EXTENSION_SETTINGS:
return "google_chrome_extension_settings";
case APP_NOTIFICATIONS:
@@ -489,6 +505,10 @@ void PostTimeToTypeHistogram(ModelType model_type, base::TimeDelta time) {
SYNC_FREQ_HISTOGRAM("Sync.FreqApps", time);
return;
}
+ case APP_SETTINGS: {
+ SYNC_FREQ_HISTOGRAM("Sync.FreqAppSettings", time);
+ return;
+ }
case EXTENSION_SETTINGS: {
SYNC_FREQ_HISTOGRAM("Sync.FreqExtensionSettings", time);
return;
@@ -516,6 +536,7 @@ const char kTypedUrlNotificationType[] = "TYPED_URL";
const char kExtensionNotificationType[] = "EXTENSION";
const char kExtensionSettingNotificationType[] = "EXTENSION_SETTING";
const char kNigoriNotificationType[] = "NIGORI";
+const char kAppSettingNotificationType[] = "APP_SETTING";
const char kAppNotificationType[] = "APP";
const char kSearchEngineNotificationType[] = "SEARCH_ENGINE";
const char kSessionNotificationType[] = "SESSION";
@@ -550,6 +571,9 @@ bool RealModelTypeToNotificationType(ModelType model_type,
case NIGORI:
*notification_type = kNigoriNotificationType;
return true;
+ case APP_SETTINGS:
+ *notification_type = kAppNotificationType;
+ return true;
case APPS:
*notification_type = kAppNotificationType;
return true;
@@ -613,6 +637,8 @@ bool NotificationTypeToRealModelType(const std::string& notification_type,
} else if (notification_type == kAutofillProfileNotificationType) {
*model_type = AUTOFILL_PROFILE;
return true;
+ } else if (notification_type == kAppSettingNotificationType) {
+ *model_type = APP_SETTINGS;
} else if (notification_type == kExtensionSettingNotificationType) {
*model_type = EXTENSION_SETTINGS;
return true;
diff --git a/chrome/browser/sync/syncable/model_type.h b/chrome/browser/sync/syncable/model_type.h
index 079cdad..bfd9879 100644
--- a/chrome/browser/sync/syncable/model_type.h
+++ b/chrome/browser/sync/syncable/model_type.h
@@ -74,7 +74,9 @@ enum ModelType {
SESSIONS,
// An app folder or an app object.
APPS,
- // A setting from the extension settings API.
+ // An app setting from the extension settings API.
+ APP_SETTINGS,
+ // An extension setting from the extension settings API.
EXTENSION_SETTINGS,
// App notifications.
APP_NOTIFICATIONS,
diff --git a/chrome/browser/sync/util/cryptographer.cc b/chrome/browser/sync/util/cryptographer.cc
index 9b78901..f7ac50e 100644
--- a/chrome/browser/sync/util/cryptographer.cc
+++ b/chrome/browser/sync/util/cryptographer.cc
@@ -310,6 +310,8 @@ void Cryptographer::UpdateEncryptedTypesFromNigori(
encrypted_types.insert(syncable::SEARCH_ENGINES);
if (nigori.encrypt_sessions())
encrypted_types.insert(syncable::SESSIONS);
+ if (nigori.encrypt_app_settings())
+ encrypted_types.insert(syncable::APP_SETTINGS);
if (nigori.encrypt_apps())
encrypted_types.insert(syncable::APPS);
if (nigori.encrypt_app_notifications())
@@ -347,6 +349,8 @@ void Cryptographer::UpdateNigoriFromEncryptedTypes(
nigori->set_encrypt_search_engines(
encrypted_types_.count(syncable::SEARCH_ENGINES) > 0);
nigori->set_encrypt_sessions(encrypted_types_.count(syncable::SESSIONS) > 0);
+ nigori->set_encrypt_app_settings(
+ encrypted_types_.count(syncable::APP_SETTINGS) > 0);
nigori->set_encrypt_apps(encrypted_types_.count(syncable::APPS) > 0);
nigori->set_encrypt_app_notifications(
encrypted_types_.count(syncable::APP_NOTIFICATIONS) > 0);
diff --git a/chrome/browser/ui/cocoa/extensions/extension_popup_controller_unittest.mm b/chrome/browser/ui/cocoa/extensions/extension_popup_controller_unittest.mm
index e74e8b5..ba3c432 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_popup_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_popup_controller_unittest.mm
@@ -24,10 +24,6 @@ class ExtensionTestingProfile : public TestingProfile {
return GetPath().AppendASCII(ExtensionService::kInstallDirectoryName);
}
- FilePath GetExtensionsSettingsDir() {
- return GetPath().AppendASCII(ExtensionService::kSettingsDirectoryName);
- }
-
void InitExtensionProfile() {
DCHECK(!GetExtensionProcessManager());
DCHECK(!GetExtensionService());
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index fcbf94c..2fdb8f1 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1329,6 +1329,8 @@
'browser/extensions/extension_settings_storage_unittest.h',
'browser/extensions/extension_settings_storage_unittest.cc',
'browser/extensions/extension_settings_sync_unittest.cc',
+ 'browser/extensions/extension_settings_test_util.h',
+ 'browser/extensions/extension_settings_test_util.cc',
'browser/extensions/extension_service_unittest.cc',
'browser/extensions/extension_service_unittest.h',
'browser/extensions/extension_special_storage_policy_unittest.cc',
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 58bc373..5486c31 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1382,8 +1382,9 @@ const char kSyncKeepEverythingSynced[] = "sync.keep_everything_synced";
const char kSyncBookmarks[] = "sync.bookmarks";
const char kSyncPasswords[] = "sync.passwords";
const char kSyncPreferences[] = "sync.preferences";
-const char kSyncApps[] = "sync.apps";
const char kSyncAppNotifications[] = "sync.app_notifications";
+const char kSyncAppSettings[] = "sync.app_settings";
+const char kSyncApps[] = "sync.apps";
const char kSyncAutofill[] = "sync.autofill";
const char kSyncAutofillProfile[] = "sync.autofill_profile";
const char kSyncThemes[] = "sync.themes";
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 73a7e49..eaf4347 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -494,6 +494,7 @@ extern const char kSyncBookmarks[];
extern const char kSyncPasswords[];
extern const char kSyncPreferences[];
extern const char kSyncAppNotifications[];
+extern const char kSyncAppSettings[];
extern const char kSyncApps[];
extern const char kSyncAutofill[];
extern const char kSyncAutofillProfile[];
diff --git a/net/tools/testserver/chromiumsync.py b/net/tools/testserver/chromiumsync.py
index 1559033..9e8cb84 100755
--- a/net/tools/testserver/chromiumsync.py
+++ b/net/tools/testserver/chromiumsync.py
@@ -18,8 +18,9 @@ import sys
import threading
import urlparse
-import app_specifics_pb2
import app_notification_specifics_pb2
+import app_setting_specifics_pb2
+import app_specifics_pb2
import autofill_specifics_pb2
import bookmark_specifics_pb2
import extension_setting_specifics_pb2
@@ -41,6 +42,7 @@ ALL_TYPES = (
TOP_LEVEL, # The type of the 'Google Chrome' folder.
APPS,
APP_NOTIFICATION,
+ APP_SETTINGS,
AUTOFILL,
AUTOFILL_PROFILE,
BOOKMARK,
@@ -52,7 +54,7 @@ ALL_TYPES = (
SESSION,
THEME,
TYPED_URL,
- EXTENSION_SETTINGS) = range(15)
+ EXTENSION_SETTINGS) = range(16)
# Well-known server tag of the top level 'Google Chrome' folder.
TOP_LEVEL_FOLDER_TAG = 'google_chrome'
@@ -60,8 +62,9 @@ TOP_LEVEL_FOLDER_TAG = 'google_chrome'
# Given a sync type from ALL_TYPES, find the extension token corresponding
# to that datatype. Note that TOP_LEVEL has no such token.
SYNC_TYPE_TO_EXTENSION = {
- APPS: app_specifics_pb2.app,
APP_NOTIFICATION: app_notification_specifics_pb2.app_notification,
+ APP_SETTINGS: app_setting_specifics_pb2.app_setting,
+ APPS: app_specifics_pb2.app,
AUTOFILL: autofill_specifics_pb2.autofill,
AUTOFILL_PROFILE: autofill_specifics_pb2.autofill_profile,
BOOKMARK: bookmark_specifics_pb2.bookmark,
@@ -394,6 +397,9 @@ class SyncDataModel(object):
parent_tag='google_chrome', sync_type=AUTOFILL),
PermanentItem('google_chrome_autofill_profiles', name='Autofill Profiles',
parent_tag='google_chrome', sync_type=AUTOFILL_PROFILE),
+ PermanentItem('google_chrome_app_settings',
+ name='App Settings',
+ parent_tag='google_chrome', sync_type=APP_SETTINGS),
PermanentItem('google_chrome_extension_settings',
name='Extension Settings',
parent_tag='google_chrome', sync_type=EXTENSION_SETTINGS),