diff options
author | kalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-01 01:56:43 +0000 |
---|---|---|
committer | kalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-01 01:56:43 +0000 |
commit | 27cc73365fd33c212faaf346e42c276daa3b494b (patch) | |
tree | 8e54461f1890c746f913c053dfcc03492958829f | |
parent | 288c9c8dc1fb8dcb875c40751bb67ec10f2749df (diff) | |
download | chromium_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
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), |