diff options
author | caitkp@chromium.org <caitkp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-06 07:12:49 +0000 |
---|---|---|
committer | caitkp@chromium.org <caitkp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-06 07:12:49 +0000 |
commit | 95d064c8127e3c5c92dfb789337b03d35d1fc066 (patch) | |
tree | 07f98e2840428ef40d60d370026beb40784b82e1 /chrome/browser/search_engines | |
parent | da2efe9d3c35968a486584a61cc862dfc9a19d8a (diff) | |
download | chromium_src-95d064c8127e3c5c92dfb789337b03d35d1fc066.zip chromium_src-95d064c8127e3c5c92dfb789337b03d35d1fc066.tar.gz chromium_src-95d064c8127e3c5c92dfb789337b03d35d1fc066.tar.bz2 |
Add overrides and fallback values to DefaultSearchManager
This patch adds support for extensions (via Settings override API) and
Policy to override Default search. As well as a fallback value if none
of these (or prefs) are available, and logic to determine which one should
be used.
BUG=365762
Review URL: https://codereview.chromium.org/255313002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@268454 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/search_engines')
6 files changed, 630 insertions, 132 deletions
diff --git a/chrome/browser/search_engines/default_search_manager.cc b/chrome/browser/search_engines/default_search_manager.cc index cd763d7..42deedc 100644 --- a/chrome/browser/search_engines/default_search_manager.cc +++ b/chrome/browser/search_engines/default_search_manager.cc @@ -7,8 +7,11 @@ #include <algorithm> #include <utility> +#include "base/bind.h" +#include "base/bind_helpers.h" #include "base/compiler_specific.h" #include "base/i18n/case_conversion.h" +#include "base/logging.h" #include "base/prefs/pref_service.h" #include "base/prefs/pref_value_map.h" #include "base/stl_util.h" @@ -19,21 +22,18 @@ #include "base/time/time.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search_engines/template_url.h" +#include "chrome/browser/search_engines/template_url_prepopulate_data.h" #include "chrome/browser/search_engines/template_url_service.h" #include "chrome/browser/search_engines/util.h" #include "chrome/common/pref_names.h" #include "components/user_prefs/pref_registry_syncable.h" -namespace { - // A dictionary to hold all data related to the Default Search Engine. // Eventually, this should replace all the data stored in the // default_search_provider.* prefs. -const char kDefaultSearchProviderData[] = +const char DefaultSearchManager::kDefaultSearchProviderDataPrefName[] = "default_search_provider_data.template_url_data"; -} // namespace - const char DefaultSearchManager::kID[] = "id"; const char DefaultSearchManager::kShortName[] = "short_name"; const char DefaultSearchManager::kKeyword[] = "keyword"; @@ -70,9 +70,25 @@ const char DefaultSearchManager::kSearchTermsReplacementKey[] = const char DefaultSearchManager::kCreatedByPolicy[] = "created_by_policy"; const char DefaultSearchManager::kDisabledByPolicy[] = "disabled_by_policy"; -DefaultSearchManager::DefaultSearchManager(PrefService* pref_service) - : pref_service_(pref_service) { - DCHECK(pref_service_); +DefaultSearchManager::DefaultSearchManager( + PrefService* pref_service, + const ObserverCallback& change_observer) + : pref_service_(pref_service), + change_observer_(change_observer), + default_search_controlled_by_policy_(false) { + if (pref_service_) { + pref_change_registrar_.Init(pref_service_); + pref_change_registrar_.Add( + kDefaultSearchProviderDataPrefName, + base::Bind(&DefaultSearchManager::OnDefaultSearchPrefChanged, + base::Unretained(this))); + pref_change_registrar_.Add( + prefs::kSearchProviderOverrides, + base::Bind(&DefaultSearchManager::OnOverridesPrefChanged, + base::Unretained(this))); + } + LoadPrepopulatedDefaultSearch(); + LoadDefaultSearchEngineFromPrefs(); } DefaultSearchManager::~DefaultSearchManager() { @@ -82,102 +98,55 @@ DefaultSearchManager::~DefaultSearchManager() { void DefaultSearchManager::RegisterProfilePrefs( user_prefs::PrefRegistrySyncable* registry) { registry->RegisterDictionaryPref( - kDefaultSearchProviderData, - user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); + kDefaultSearchProviderDataPrefName, + user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); } // static void DefaultSearchManager::AddPrefValueToMap(base::DictionaryValue* value, PrefValueMap* pref_value_map) { - pref_value_map->SetValue(kDefaultSearchProviderData, value); + pref_value_map->SetValue(kDefaultSearchProviderDataPrefName, value); } -bool DefaultSearchManager::GetDefaultSearchEngine(TemplateURLData* data) { - const base::DictionaryValue* url_dict = - pref_service_->GetDictionary(kDefaultSearchProviderData); - - if (url_dict->empty()) - return false; - - std::string search_url; - base::string16 keyword; - url_dict->GetString(kURL, &search_url); - url_dict->GetString(kKeyword, &keyword); - if (search_url.empty()) - return false; - if (keyword.empty()) - keyword = TemplateURLService::GenerateKeyword(GURL(search_url)); - data->SetKeyword(keyword); - data->SetURL(search_url); - - std::string id; - url_dict->GetString(kID, &id); - base::StringToInt64(id, &data->id); - url_dict->GetString(kShortName, &data->short_name); - url_dict->GetInteger(kPrepopulateID, &data->prepopulate_id); - url_dict->GetString(kSyncGUID, &data->sync_guid); - - url_dict->GetString(kSuggestionsURL, &data->suggestions_url); - url_dict->GetString(kInstantURL, &data->instant_url); - url_dict->GetString(kImageURL, &data->image_url); - url_dict->GetString(kNewTabURL, &data->new_tab_url); - - std::string favicon_url; - std::string originating_url; - url_dict->GetString(kFaviconURL, &favicon_url); - url_dict->GetString(kOriginatingURL, &originating_url); - data->favicon_url = GURL(favicon_url); - data->originating_url = GURL(originating_url); - - url_dict->GetString(kSearchURLPostParams, &data->search_url_post_params); - url_dict->GetString(kSuggestionsURLPostParams, - &data->suggestions_url_post_params); - url_dict->GetString(kInstantURLPostParams, &data->instant_url_post_params); - url_dict->GetString(kImageURLPostParams, &data->image_url_post_params); - - url_dict->GetBoolean(kSafeForAutoReplace, &data->safe_for_autoreplace); - - double date_created = 0.0; - double last_modified = 0.0; - url_dict->GetDouble(kDateCreated, &date_created); - url_dict->GetDouble(kLastModified, &last_modified); - data->date_created = base::Time::FromInternalValue(date_created); - data->last_modified = base::Time::FromInternalValue(last_modified); - - url_dict->GetInteger(kUsageCount, &data->usage_count); - - const base::ListValue* alternate_urls; - url_dict->GetList(kAlternateURLs, &alternate_urls); - data->alternate_urls.clear(); - for (base::ListValue::const_iterator it = alternate_urls->begin(); - it != alternate_urls->end(); ++it) { - std::string alternate_url; - if ((*it)->GetAsString(&alternate_url)) - data->alternate_urls.push_back(alternate_url); +TemplateURLData* DefaultSearchManager::GetDefaultSearchEngine( + Source* source) const { + if (default_search_controlled_by_policy_) { + if (source) + *source = FROM_POLICY; + return prefs_default_search_.get(); } - - const base::ListValue* encodings; - url_dict->GetList(kInputEncodings, &encodings); - data->input_encodings.clear(); - for (base::ListValue::const_iterator it = encodings->begin(); - it != encodings->end(); ++it) { - std::string encoding; - if ((*it)->GetAsString(&encoding)) - data->input_encodings.push_back(encoding); + if (extension_default_search_) { + if (source) + *source = FROM_EXTENSION; + return extension_default_search_.get(); + } + if (prefs_default_search_) { + if (source) + *source = FROM_USER; + return prefs_default_search_.get(); } - url_dict->GetString(kSearchTermsReplacementKey, - &data->search_terms_replacement_key); - - url_dict->GetBoolean(kCreatedByPolicy, &data->created_by_policy); - - data->show_in_default_list = true; + if (source) + *source = FROM_FALLBACK; + return fallback_default_search_.get(); +} - return true; +DefaultSearchManager::Source +DefaultSearchManager::GetDefaultSearchEngineSource() const { + Source source; + GetDefaultSearchEngine(&source); + return source; } void DefaultSearchManager::SetUserSelectedDefaultSearchEngine( const TemplateURLData& data) { + if (!pref_service_) { + prefs_default_search_.reset(new TemplateURLData(data)); + MergePrefsDataWithPrepopulated(); + NotifyObserver(); + return; + } + base::DictionaryValue url_dict; url_dict.SetString(kID, base::Int64ToString(data.id)); url_dict.SetString(kShortName, data.short_name); @@ -201,8 +170,10 @@ void DefaultSearchManager::SetUserSelectedDefaultSearchEngine( url_dict.SetBoolean(kSafeForAutoReplace, data.safe_for_autoreplace); - url_dict.SetDouble(kDateCreated, data.date_created.ToInternalValue()); - url_dict.SetDouble(kLastModified, data.last_modified.ToInternalValue()); + url_dict.SetString(kDateCreated, + base::Int64ToString(data.date_created.ToInternalValue())); + url_dict.SetString(kLastModified, + base::Int64ToString(data.last_modified.ToInternalValue())); url_dict.SetInteger(kUsageCount, data.usage_count); scoped_ptr<base::ListValue> alternate_urls(new base::ListValue); @@ -226,9 +197,209 @@ void DefaultSearchManager::SetUserSelectedDefaultSearchEngine( url_dict.SetBoolean(kCreatedByPolicy, data.created_by_policy); - pref_service_->Set(kDefaultSearchProviderData, url_dict); + pref_service_->Set(kDefaultSearchProviderDataPrefName, url_dict); +} + +void DefaultSearchManager::SetExtensionControlledDefaultSearchEngine( + const TemplateURLData& data) { + extension_default_search_.reset(new TemplateURLData(data)); + if (GetDefaultSearchEngineSource() == FROM_EXTENSION) + NotifyObserver(); +} + +void DefaultSearchManager::ClearExtensionControlledDefaultSearchEngine() { + Source old_source = GetDefaultSearchEngineSource(); + extension_default_search_.reset(); + if (old_source == FROM_EXTENSION) + NotifyObserver(); } void DefaultSearchManager::ClearUserSelectedDefaultSearchEngine() { - pref_service_->ClearPref(kDefaultSearchProviderData); + if (pref_service_) { + pref_service_->ClearPref(kDefaultSearchProviderDataPrefName); + } else { + prefs_default_search_.reset(); + NotifyObserver(); + } +} + +void DefaultSearchManager::OnDefaultSearchPrefChanged() { + Source source = GetDefaultSearchEngineSource(); + LoadDefaultSearchEngineFromPrefs(); + + // If we were/are FROM_USER or FROM_POLICY the effective DSE may have changed. + if (source != FROM_USER && source != FROM_POLICY) + source = GetDefaultSearchEngineSource(); + if (source == FROM_USER || source == FROM_POLICY) + NotifyObserver(); +} + +void DefaultSearchManager::OnOverridesPrefChanged() { + LoadPrepopulatedDefaultSearch(); + + TemplateURLData* effective_data = GetDefaultSearchEngine(NULL); + if (effective_data && effective_data->prepopulate_id) { + // A user-selected, policy-selected or fallback pre-populated engine is + // active and may have changed with this event. + NotifyObserver(); + } +} + +void DefaultSearchManager::MergePrefsDataWithPrepopulated() { + if (!prefs_default_search_ || !prefs_default_search_->prepopulate_id) + return; + + size_t default_search_index; + ScopedVector<TemplateURLData> prepopulated_urls = + TemplateURLPrepopulateData::GetPrepopulatedEngines(pref_service_, + &default_search_index); + + for (size_t i = 0; i < prepopulated_urls.size(); ++i) { + if (prepopulated_urls[i]->prepopulate_id == + prefs_default_search_->prepopulate_id) { + if (!prefs_default_search_->safe_for_autoreplace) { + prepopulated_urls[i]->safe_for_autoreplace = false; + prepopulated_urls[i]->SetKeyword(prefs_default_search_->keyword()); + prepopulated_urls[i]->short_name = prefs_default_search_->short_name; + } + prepopulated_urls[i]->id = prefs_default_search_->id; + prepopulated_urls[i]->sync_guid = prefs_default_search_->sync_guid; + prepopulated_urls[i]->date_created = prefs_default_search_->date_created; + prepopulated_urls[i]->last_modified = + prefs_default_search_->last_modified; + prefs_default_search_.reset(prepopulated_urls[i]); + prepopulated_urls.weak_erase(prepopulated_urls.begin() + i); + return; + } + } +} + +void DefaultSearchManager::LoadDefaultSearchEngineFromPrefs() { + if (!pref_service_) + return; + + prefs_default_search_.reset(); + const PrefService::Preference* pref = + pref_service_->FindPreference(kDefaultSearchProviderDataPrefName); + DCHECK(pref); + default_search_controlled_by_policy_ = pref->IsManaged(); + + const base::DictionaryValue* url_dict = + pref_service_->GetDictionary(kDefaultSearchProviderDataPrefName); + if (url_dict->empty()) + return; + + if (default_search_controlled_by_policy_) { + bool disabled_by_policy = false; + if (url_dict->GetBoolean(kDisabledByPolicy, &disabled_by_policy) && + disabled_by_policy) + return; + } + + std::string search_url; + base::string16 keyword; + url_dict->GetString(kURL, &search_url); + url_dict->GetString(kKeyword, &keyword); + if (search_url.empty() || keyword.empty()) + return; + + prefs_default_search_.reset(new TemplateURLData); + prefs_default_search_->SetKeyword(keyword); + prefs_default_search_->SetURL(search_url); + + std::string id; + url_dict->GetString(kID, &id); + base::StringToInt64(id, &prefs_default_search_->id); + url_dict->GetString(kShortName, &prefs_default_search_->short_name); + url_dict->GetInteger(kPrepopulateID, &prefs_default_search_->prepopulate_id); + url_dict->GetString(kSyncGUID, &prefs_default_search_->sync_guid); + + url_dict->GetString(kSuggestionsURL, &prefs_default_search_->suggestions_url); + url_dict->GetString(kInstantURL, &prefs_default_search_->instant_url); + url_dict->GetString(kImageURL, &prefs_default_search_->image_url); + url_dict->GetString(kNewTabURL, &prefs_default_search_->new_tab_url); + + std::string favicon_url; + std::string originating_url; + url_dict->GetString(kFaviconURL, &favicon_url); + url_dict->GetString(kOriginatingURL, &originating_url); + prefs_default_search_->favicon_url = GURL(favicon_url); + prefs_default_search_->originating_url = GURL(originating_url); + + url_dict->GetString(kSearchURLPostParams, + &prefs_default_search_->search_url_post_params); + url_dict->GetString(kSuggestionsURLPostParams, + &prefs_default_search_->suggestions_url_post_params); + url_dict->GetString(kInstantURLPostParams, + &prefs_default_search_->instant_url_post_params); + url_dict->GetString(kImageURLPostParams, + &prefs_default_search_->image_url_post_params); + + url_dict->GetBoolean(kSafeForAutoReplace, + &prefs_default_search_->safe_for_autoreplace); + + std::string date_created_str; + std::string last_modified_str; + url_dict->GetString(kDateCreated, &date_created_str); + url_dict->GetString(kLastModified, &last_modified_str); + + int64 date_created = 0; + if (base::StringToInt64(date_created_str, &date_created)) { + prefs_default_search_->date_created = + base::Time::FromInternalValue(date_created); + } + + int64 last_modified = 0; + if (base::StringToInt64(date_created_str, &last_modified)) { + prefs_default_search_->last_modified = + base::Time::FromInternalValue(last_modified); + } + + url_dict->GetInteger(kUsageCount, &prefs_default_search_->usage_count); + + const base::ListValue* alternate_urls = NULL; + if (url_dict->GetList(kAlternateURLs, &alternate_urls)) { + for (base::ListValue::const_iterator it = alternate_urls->begin(); + it != alternate_urls->end(); + ++it) { + std::string alternate_url; + if ((*it)->GetAsString(&alternate_url)) + prefs_default_search_->alternate_urls.push_back(alternate_url); + } + } + + const base::ListValue* encodings = NULL; + if (url_dict->GetList(kInputEncodings, &encodings)) { + for (base::ListValue::const_iterator it = encodings->begin(); + it != encodings->end(); + ++it) { + std::string encoding; + if ((*it)->GetAsString(&encoding)) + prefs_default_search_->input_encodings.push_back(encoding); + } + } + + url_dict->GetString(kSearchTermsReplacementKey, + &prefs_default_search_->search_terms_replacement_key); + + url_dict->GetBoolean(kCreatedByPolicy, + &prefs_default_search_->created_by_policy); + + prefs_default_search_->show_in_default_list = true; + MergePrefsDataWithPrepopulated(); +} + +void DefaultSearchManager::LoadPrepopulatedDefaultSearch() { + scoped_ptr<TemplateURLData> data = + TemplateURLPrepopulateData::GetPrepopulatedDefaultSearch(pref_service_); + fallback_default_search_ = data.Pass(); + MergePrefsDataWithPrepopulated(); +} + +void DefaultSearchManager::NotifyObserver() { + if (!change_observer_.is_null()) { + Source source = FROM_FALLBACK; + TemplateURLData* data = GetDefaultSearchEngine(&source); + change_observer_.Run(data, source); + } } diff --git a/chrome/browser/search_engines/default_search_manager.h b/chrome/browser/search_engines/default_search_manager.h index 9035564..95a5bfb 100644 --- a/chrome/browser/search_engines/default_search_manager.h +++ b/chrome/browser/search_engines/default_search_manager.h @@ -5,7 +5,10 @@ #ifndef CHROME_BROWSER_SEARCH_ENGINES_DEFAULT_SEARCH_MANAGER_H_ #define CHROME_BROWSER_SEARCH_ENGINES_DEFAULT_SEARCH_MANAGER_H_ +#include "base/callback.h" #include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/prefs/pref_change_registrar.h" namespace base { class DictionaryValue; @@ -21,9 +24,10 @@ struct TemplateURLData; // DefaultSearchManager handles the loading and writing of the user's default // search engine selection to and from prefs. - class DefaultSearchManager { public: + static const char kDefaultSearchProviderDataPrefName[]; + static const char kID[]; static const char kShortName[]; static const char kKeyword[]; @@ -55,7 +59,18 @@ class DefaultSearchManager { static const char kCreatedByPolicy[]; static const char kDisabledByPolicy[]; - explicit DefaultSearchManager(PrefService* pref_service); + enum Source { + FROM_FALLBACK = 0, + FROM_USER, + FROM_EXTENSION, + FROM_POLICY, + }; + + typedef base::Callback<void(const TemplateURLData*, Source)> ObserverCallback; + + DefaultSearchManager(PrefService* pref_service, + const ObserverCallback& change_observer); + ~DefaultSearchManager(); // Register prefs needed for tracking the default search provider. @@ -65,17 +80,78 @@ class DefaultSearchManager { static void AddPrefValueToMap(base::DictionaryValue* value, PrefValueMap* pref_value_map); - // Read default search provider data from |pref_service_|. - bool GetDefaultSearchEngine(TemplateURLData* url); + // Gets a pointer to the current Default Search Engine. If NULL, indicates + // that Default Search is explicitly disabled. |source|, if not NULL, will be + // filled in with the source of the result. + TemplateURLData* GetDefaultSearchEngine(Source* source) const; + + // Gets the source of the current Default Search Engine value. + Source GetDefaultSearchEngineSource() const; // Write default search provider data to |pref_service_|. void SetUserSelectedDefaultSearchEngine(const TemplateURLData& data); - // Clear the user's default search provider choice from |pref_service_|. + // Override the default search provider with an extension. + void SetExtensionControlledDefaultSearchEngine(const TemplateURLData& data); + + // Clear the extension-provided default search engine. Does not explicitly + // disable Default Search. The new current default search engine will be + // defined by policy, extensions, or pre-populated data. + void ClearExtensionControlledDefaultSearchEngine(); + + // Clear the user's default search provider choice from |pref_service_|. Does + // not explicitly disable Default Search. The new default search + // engine will be defined by policy, extensions, or pre-populated data. void ClearUserSelectedDefaultSearchEngine(); private: + // Handles changes to kDefaultSearchProviderData pref. This includes sync and + // policy changes. Calls LoadDefaultSearchEngineFromPrefs() and + // NotifyObserver() if the effective DSE might have changed. + void OnDefaultSearchPrefChanged(); + + // Handles changes to kSearchProviderOverrides pref. Calls + // LoadPrepopulatedDefaultSearch() and NotifyObserver() if the effective DSE + // might have changed. + void OnOverridesPrefChanged(); + + // Updates |prefs_default_search_| with values from its corresponding + // pre-populated search provider record, if any. + void MergePrefsDataWithPrepopulated(); + + // Reads default search provider data from |pref_service_|, updating + // |prefs_default_search_| and |default_search_controlled_by_policy_|. + // Invokes MergePrefsDataWithPrepopulated(). + void LoadDefaultSearchEngineFromPrefs(); + + // Reads pre-populated search providers, which will be built-in or overridden + // by kSearchProviderOverrides. Updates |fallback_default_search_|. Invoke + // MergePrefsDataWithPrepopulated(). + void LoadPrepopulatedDefaultSearch(); + + // Invokes |change_observer_| if it is not NULL. + void NotifyObserver(); + PrefService* pref_service_; + const ObserverCallback change_observer_; + PrefChangeRegistrar pref_change_registrar_; + + // Default search engine provided by pre-populated data or by the + // |kSearchProviderOverrides| pref. This will be used when no other default + // search engine has been selected. + scoped_ptr<TemplateURLData> fallback_default_search_; + + // Default search engine provided by prefs (either user prefs or policy + // prefs). This will be null if no value was set in the pref store. + scoped_ptr<TemplateURLData> extension_default_search_; + + // Default search engine provided by extension (usings Settings Override API). + // This will be null if there are no extensions installed which provide + // default search engines. + scoped_ptr<TemplateURLData> prefs_default_search_; + + // True if the default search is currently enforced by policy. + bool default_search_controlled_by_policy_; DISALLOW_COPY_AND_ASSIGN(DefaultSearchManager); }; diff --git a/chrome/browser/search_engines/default_search_manager_unittest.cc b/chrome/browser/search_engines/default_search_manager_unittest.cc index 9dd2cb5..fd6f99f 100644 --- a/chrome/browser/search_engines/default_search_manager_unittest.cc +++ b/chrome/browser/search_engines/default_search_manager_unittest.cc @@ -3,19 +3,27 @@ // found in the LICENSE file. #include "base/files/scoped_temp_dir.h" +#include "base/memory/scoped_ptr.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "chrome/browser/search_engines/default_search_manager.h" #include "chrome/browser/search_engines/template_url.h" +#include "chrome/browser/search_engines/template_url_prepopulate_data.h" +#include "chrome/common/pref_names.h" #include "chrome/test/base/testing_pref_service_syncable.h" #include "components/user_prefs/pref_registry_syncable.h" #include "testing/gtest/include/gtest/gtest.h" namespace { +// A dictionary to hold all data related to the Default Search Engine. +// Eventually, this should replace all the data stored in the +// default_search_provider.* prefs. +const char kDefaultSearchProviderData[] = + "default_search_provider_data.template_url_data"; -// Checks that the two TemplateURLs are similar. It does not check the id, the +// Checks that the two TemplateURLs are similar. Does not check the id, the // date_created or the last_modified time. Neither pointer should be NULL. void ExpectSimilar(const TemplateURLData* expected, const TemplateURLData* actual) { @@ -35,6 +43,98 @@ void ExpectSimilar(const TemplateURLData* expected, actual->search_terms_replacement_key); } +// TODO(caitkp): TemplateURLData-ify this. +void SetOverrides(TestingPrefServiceSyncable* prefs, bool update) { + prefs->SetUserPref(prefs::kSearchProviderOverridesVersion, + base::Value::CreateIntegerValue(1)); + base::ListValue* overrides = new base::ListValue; + scoped_ptr<base::DictionaryValue> entry(new base::DictionaryValue); + + entry->SetString("name", update ? "new_foo" : "foo"); + entry->SetString("keyword", update ? "new_fook" : "fook"); + entry->SetString("search_url", "http://foo.com/s?q={searchTerms}"); + entry->SetString("favicon_url", "http://foi.com/favicon.ico"); + entry->SetString("encoding", "UTF-8"); + entry->SetInteger("id", 1001); + entry->SetString("suggest_url", "http://foo.com/suggest?q={searchTerms}"); + entry->SetString("instant_url", "http://foo.com/instant?q={searchTerms}"); + base::ListValue* alternate_urls = new base::ListValue; + alternate_urls->AppendString("http://foo.com/alternate?q={searchTerms}"); + entry->Set("alternate_urls", alternate_urls); + entry->SetString("search_terms_replacement_key", "espv"); + overrides->Append(entry->DeepCopy()); + + entry.reset(new base::DictionaryValue); + entry->SetInteger("id", 1002); + entry->SetString("name", update ? "new_bar" : "bar"); + entry->SetString("keyword", update ? "new_bark" : "bark"); + entry->SetString("encoding", std::string()); + overrides->Append(entry->DeepCopy()); + entry->SetInteger("id", 1003); + entry->SetString("name", "baz"); + entry->SetString("keyword", "bazk"); + entry->SetString("encoding", "UTF-8"); + overrides->Append(entry->DeepCopy()); + prefs->SetUserPref(prefs::kSearchProviderOverrides, overrides); +} + +void SetPolicy(TestingPrefServiceSyncable* prefs, + bool enabled, + TemplateURLData* data) { + if (enabled) { + EXPECT_FALSE(data->keyword().empty()); + EXPECT_FALSE(data->url().empty()); + } + scoped_ptr<base::DictionaryValue> entry(new base::DictionaryValue); + entry->SetString(DefaultSearchManager::kShortName, data->short_name); + entry->SetString(DefaultSearchManager::kKeyword, data->keyword()); + entry->SetString(DefaultSearchManager::kURL, data->url()); + entry->SetString(DefaultSearchManager::kFaviconURL, data->favicon_url.spec()); + entry->SetString(DefaultSearchManager::kSuggestionsURL, + data->suggestions_url); + entry->SetBoolean(DefaultSearchManager::kSafeForAutoReplace, + data->safe_for_autoreplace); + scoped_ptr<base::ListValue> alternate_urls(new base::ListValue); + for (std::vector<std::string>::const_iterator it = + data->alternate_urls.begin(); + it != data->alternate_urls.end(); + ++it) { + alternate_urls->AppendString(*it); + } + entry->Set(DefaultSearchManager::kAlternateURLs, alternate_urls.release()); + + scoped_ptr<base::ListValue> encodings(new base::ListValue); + for (std::vector<std::string>::const_iterator it = + data->input_encodings.begin(); + it != data->input_encodings.end(); + ++it) { + encodings->AppendString(*it); + } + entry->Set(DefaultSearchManager::kInputEncodings, encodings.release()); + + entry->SetString(DefaultSearchManager::kSearchTermsReplacementKey, + data->search_terms_replacement_key); + entry->SetBoolean(DefaultSearchManager::kDisabledByPolicy, !enabled); + prefs->SetManagedPref(kDefaultSearchProviderData, entry.release()); +} + +scoped_ptr<TemplateURLData> GenerateDummyTemplateURLData(std::string type) { + scoped_ptr<TemplateURLData> data(new TemplateURLData()); + data->short_name = base::UTF8ToUTF16(std::string(type).append("name")); + data->SetKeyword(base::UTF8ToUTF16(std::string(type).append("key"))); + data->SetURL(std::string("http://").append(type).append("foo/{searchTerms}")); + data->suggestions_url = std::string("http://").append(type).append("sugg"); + data->alternate_urls.push_back( + std::string("http://").append(type).append("foo/alt")); + data->favicon_url = GURL("http://icon1"); + data->safe_for_autoreplace = true; + data->show_in_default_list = true; + base::SplitString("UTF-8;UTF-16", ';', &data->input_encodings); + data->date_created = base::Time(); + data->last_modified = base::Time(); + return data.Pass(); +} + } // namespace class DefaultSearchManagerTest : public testing::Test { @@ -44,9 +144,10 @@ class DefaultSearchManagerTest : public testing::Test { virtual void SetUp() OVERRIDE { pref_service_.reset(new TestingPrefServiceSyncable); DefaultSearchManager::RegisterProfilePrefs(pref_service_->registry()); + TemplateURLPrepopulateData::RegisterProfilePrefs(pref_service_->registry()); } - PrefService* pref_service() { return pref_service_.get(); } + TestingPrefServiceSyncable* pref_service() { return pref_service_.get(); } private: scoped_ptr<TestingPrefServiceSyncable> pref_service_; @@ -56,7 +157,8 @@ class DefaultSearchManagerTest : public testing::Test { // Test that a TemplateURLData object is properly written and read from Prefs. TEST_F(DefaultSearchManagerTest, ReadAndWritePref) { - DefaultSearchManager manager(pref_service()); + DefaultSearchManager manager(pref_service(), + DefaultSearchManager::ObserverCallback()); TemplateURLData data; data.short_name = base::UTF8ToUTF16("name1"); data.SetKeyword(base::UTF8ToUTF16("key1")); @@ -71,14 +173,150 @@ TEST_F(DefaultSearchManagerTest, ReadAndWritePref) { data.last_modified = base::Time(); manager.SetUserSelectedDefaultSearchEngine(data); - TemplateURLData read_data; - manager.GetDefaultSearchEngine(&read_data); - ExpectSimilar(&data, &read_data); + TemplateURLData* read_data = manager.GetDefaultSearchEngine(NULL); + ExpectSimilar(&data, read_data); +} + +// Test DefaultSearchmanager handles user-selected DSEs correctly. +TEST_F(DefaultSearchManagerTest, DefaultSearchSetByUserPref) { + size_t default_search_index = 0; + DefaultSearchManager manager(pref_service(), + DefaultSearchManager::ObserverCallback()); + ScopedVector<TemplateURLData> prepopulated_urls = + TemplateURLPrepopulateData::GetPrepopulatedEngines(pref_service(), + &default_search_index); + DefaultSearchManager::Source source = DefaultSearchManager::FROM_POLICY; + // If no user pref is set, we should use the pre-populated values. + ExpectSimilar(prepopulated_urls[default_search_index], + manager.GetDefaultSearchEngine(&source)); + EXPECT_EQ(DefaultSearchManager::FROM_FALLBACK, source); + + // Setting a user pref overrides the pre-populated values. + scoped_ptr<TemplateURLData> data = GenerateDummyTemplateURLData("user"); + manager.SetUserSelectedDefaultSearchEngine(*data.get()); + + ExpectSimilar(data.get(), manager.GetDefaultSearchEngine(&source)); + EXPECT_EQ(DefaultSearchManager::FROM_USER, source); + + // Updating the user pref (externally to this instance of + // DefaultSearchManager) triggers an update. + scoped_ptr<TemplateURLData> new_data = GenerateDummyTemplateURLData("user2"); + DefaultSearchManager other_manager(pref_service(), + DefaultSearchManager::ObserverCallback()); + other_manager.SetUserSelectedDefaultSearchEngine(*new_data.get()); + + ExpectSimilar(new_data.get(), manager.GetDefaultSearchEngine(&source)); + EXPECT_EQ(DefaultSearchManager::FROM_USER, source); + + // Clearing the user pref should cause the default search to revert to the + // prepopulated vlaues. + manager.ClearUserSelectedDefaultSearchEngine(); + ExpectSimilar(prepopulated_urls[default_search_index], + manager.GetDefaultSearchEngine(&source)); + EXPECT_EQ(DefaultSearchManager::FROM_FALLBACK, source); } -// Test that there is no default value set in the pref. -TEST_F(DefaultSearchManagerTest, ReadDefaultPref) { - DefaultSearchManager manager(pref_service()); - TemplateURLData read_data; - EXPECT_FALSE(manager.GetDefaultSearchEngine(&read_data)); +// Test that DefaultSearch manager detects changes to kSearchProviderOverrides. +TEST_F(DefaultSearchManagerTest, DefaultSearchSetByOverrides) { + SetOverrides(pref_service(), false); + size_t default_search_index = 0; + DefaultSearchManager manager(pref_service(), + DefaultSearchManager::ObserverCallback()); + ScopedVector<TemplateURLData> prepopulated_urls = + TemplateURLPrepopulateData::GetPrepopulatedEngines(pref_service(), + &default_search_index); + + DefaultSearchManager::Source source = DefaultSearchManager::FROM_POLICY; + TemplateURLData first_default(*manager.GetDefaultSearchEngine(&source)); + ExpectSimilar(prepopulated_urls[default_search_index], &first_default); + EXPECT_EQ(DefaultSearchManager::FROM_FALLBACK, source); + + // Update the overrides: + SetOverrides(pref_service(), true); + prepopulated_urls = TemplateURLPrepopulateData::GetPrepopulatedEngines( + pref_service(), &default_search_index); + + // Make sure DefaultSearchManager updated: + ExpectSimilar(prepopulated_urls[default_search_index], + manager.GetDefaultSearchEngine(&source)); + EXPECT_EQ(DefaultSearchManager::FROM_FALLBACK, source); + EXPECT_NE(manager.GetDefaultSearchEngine(NULL)->short_name, + first_default.short_name); + EXPECT_NE(manager.GetDefaultSearchEngine(NULL)->keyword(), + first_default.keyword()); +} + +// Test DefaultSearchManager handles policy-enforced DSEs correctly. +TEST_F(DefaultSearchManagerTest, DefaultSearchSetByPolicy) { + DefaultSearchManager manager(pref_service(), + DefaultSearchManager::ObserverCallback()); + scoped_ptr<TemplateURLData> data = GenerateDummyTemplateURLData("user"); + manager.SetUserSelectedDefaultSearchEngine(*data.get()); + + DefaultSearchManager::Source source = DefaultSearchManager::FROM_FALLBACK; + ExpectSimilar(data.get(), manager.GetDefaultSearchEngine(&source)); + EXPECT_EQ(DefaultSearchManager::FROM_USER, source); + + scoped_ptr<TemplateURLData> policy_data = + GenerateDummyTemplateURLData("policy"); + SetPolicy(pref_service(), true, policy_data.get()); + + ExpectSimilar(policy_data.get(), manager.GetDefaultSearchEngine(&source)); + EXPECT_EQ(DefaultSearchManager::FROM_POLICY, source); + + TemplateURLData null_policy_data; + SetPolicy(pref_service(), false, &null_policy_data); + EXPECT_EQ(NULL, manager.GetDefaultSearchEngine(&source)); + EXPECT_EQ(DefaultSearchManager::FROM_POLICY, source); + + pref_service()->RemoveManagedPref(kDefaultSearchProviderData); + ExpectSimilar(data.get(), manager.GetDefaultSearchEngine(&source)); + EXPECT_EQ(DefaultSearchManager::FROM_USER, source); +} + +// Test DefaultSearchManager handles extension-controlled DSEs correctly. +TEST_F(DefaultSearchManagerTest, DefaultSearchSetByExtension) { + DefaultSearchManager manager(pref_service(), + DefaultSearchManager::ObserverCallback()); + scoped_ptr<TemplateURLData> data = GenerateDummyTemplateURLData("user"); + manager.SetUserSelectedDefaultSearchEngine(*data); + + DefaultSearchManager::Source source = DefaultSearchManager::FROM_FALLBACK; + ExpectSimilar(data.get(), manager.GetDefaultSearchEngine(&source)); + EXPECT_EQ(DefaultSearchManager::FROM_USER, source); + + // Extension trumps prefs: + scoped_ptr<TemplateURLData> extension_data_1 = + GenerateDummyTemplateURLData("ext1"); + manager.SetExtensionControlledDefaultSearchEngine(*extension_data_1); + + ExpectSimilar(extension_data_1.get(), + manager.GetDefaultSearchEngine(&source)); + EXPECT_EQ(DefaultSearchManager::FROM_EXTENSION, source); + + // Policy trumps extension: + scoped_ptr<TemplateURLData> policy_data = + GenerateDummyTemplateURLData("policy"); + SetPolicy(pref_service(), true, policy_data.get()); + + ExpectSimilar(policy_data.get(), manager.GetDefaultSearchEngine(&source)); + EXPECT_EQ(DefaultSearchManager::FROM_POLICY, source); + pref_service()->RemoveManagedPref(kDefaultSearchProviderData); + + // Extensions trump each other: + scoped_ptr<TemplateURLData> extension_data_2 = + GenerateDummyTemplateURLData("ext2"); + scoped_ptr<TemplateURLData> extension_data_3 = + GenerateDummyTemplateURLData("ext3"); + manager.SetExtensionControlledDefaultSearchEngine(*extension_data_2); + manager.SetExtensionControlledDefaultSearchEngine(*extension_data_3); + + ExpectSimilar(extension_data_3.get(), + manager.GetDefaultSearchEngine(&source)); + EXPECT_EQ(DefaultSearchManager::FROM_EXTENSION, source); + + manager.ClearExtensionControlledDefaultSearchEngine(); + + ExpectSimilar(data.get(), manager.GetDefaultSearchEngine(&source)); + EXPECT_EQ(DefaultSearchManager::FROM_USER, source); } diff --git a/chrome/browser/search_engines/default_search_pref_migration.cc b/chrome/browser/search_engines/default_search_pref_migration.cc index 4d7625e..7516bfc 100644 --- a/chrome/browser/search_engines/default_search_pref_migration.cc +++ b/chrome/browser/search_engines/default_search_pref_migration.cc @@ -17,11 +17,13 @@ namespace { void MigrateDefaultSearchPref(PrefService* pref_service) { - DefaultSearchManager default_search_manager(pref_service); + DefaultSearchManager default_search_manager( + pref_service, DefaultSearchManager::ObserverCallback()); - TemplateURLData modern_user_dse; - if (default_search_manager.GetDefaultSearchEngine(&modern_user_dse)) + if (default_search_manager.GetDefaultSearchEngineSource() == + DefaultSearchManager::FROM_USER) { return; + } scoped_ptr<TemplateURLData> legacy_dse_from_prefs; bool legacy_is_managed = false; diff --git a/chrome/browser/search_engines/default_search_pref_migration_unittest.cc b/chrome/browser/search_engines/default_search_pref_migration_unittest.cc index 9d85c0e..5a1fa35 100644 --- a/chrome/browser/search_engines/default_search_pref_migration_unittest.cc +++ b/chrome/browser/search_engines/default_search_pref_migration_unittest.cc @@ -72,12 +72,13 @@ TEST_F(DefaultSearchPrefMigrationTest, MigrateUserSelectedValue) { test_util()->profile()->GetPrefs()); // Test that it was migrated. - TemplateURLData modern_default; - ASSERT_TRUE(DefaultSearchManager(test_util()->profile()->GetPrefs()) - .GetDefaultSearchEngine(&modern_default)); - EXPECT_EQ(t_url->short_name(), modern_default.short_name); - EXPECT_EQ(t_url->keyword(), modern_default.keyword()); - EXPECT_EQ(t_url->url(), modern_default.url()); + DefaultSearchManager manager(test_util()->profile()->GetPrefs(), + DefaultSearchManager::ObserverCallback()); + TemplateURLData* modern_default = manager.GetDefaultSearchEngine(NULL); + ASSERT_TRUE(modern_default); + EXPECT_EQ(t_url->short_name(), modern_default->short_name); + EXPECT_EQ(t_url->keyword(), modern_default->keyword()); + EXPECT_EQ(t_url->url(), modern_default->url()); } TEST_F(DefaultSearchPrefMigrationTest, ModernValuePresent) { @@ -90,7 +91,8 @@ TEST_F(DefaultSearchPrefMigrationTest, ModernValuePresent) { t_url.get(), test_util()->profile()->GetPrefs()); // Store another value in the modern location. - DefaultSearchManager(test_util()->profile()->GetPrefs()) + DefaultSearchManager(test_util()->profile()->GetPrefs(), + DefaultSearchManager::ObserverCallback()) .SetUserSelectedDefaultSearchEngine(t_url2->data()); // Run the migration. @@ -98,12 +100,13 @@ TEST_F(DefaultSearchPrefMigrationTest, ModernValuePresent) { test_util()->profile()->GetPrefs()); // Test that no migration occurred. The modern value is left intact. - TemplateURLData modern_default; - ASSERT_TRUE(DefaultSearchManager(test_util()->profile()->GetPrefs()) - .GetDefaultSearchEngine(&modern_default)); - EXPECT_EQ(t_url2->short_name(), modern_default.short_name); - EXPECT_EQ(t_url2->keyword(), modern_default.keyword()); - EXPECT_EQ(t_url2->url(), modern_default.url()); + DefaultSearchManager manager(test_util()->profile()->GetPrefs(), + DefaultSearchManager::ObserverCallback()); + TemplateURLData* modern_default = manager.GetDefaultSearchEngine(NULL); + ASSERT_TRUE(modern_default); + EXPECT_EQ(t_url2->short_name(), modern_default->short_name); + EXPECT_EQ(t_url2->keyword(), modern_default->keyword()); + EXPECT_EQ(t_url2->url(), modern_default->url()); } TEST_F(DefaultSearchPrefMigrationTest, @@ -124,9 +127,10 @@ TEST_F(DefaultSearchPrefMigrationTest, test_util()->profile()->GetPrefs()); // Test that the legacy value is not migrated, as it is not user-selected. - TemplateURLData modern_default; - ASSERT_FALSE(DefaultSearchManager(test_util()->profile()->GetPrefs()) - .GetDefaultSearchEngine(&modern_default)); + ASSERT_EQ(DefaultSearchManager::FROM_FALLBACK, + DefaultSearchManager(test_util()->profile()->GetPrefs(), + DefaultSearchManager::ObserverCallback()) + .GetDefaultSearchEngineSource()); } TEST_F(DefaultSearchPrefMigrationTest, ManagedValueIsNotMigrated) { @@ -164,8 +168,13 @@ TEST_F(DefaultSearchPrefMigrationTest, ManagedValueIsNotMigrated) { ConfigureDefaultSearchPrefMigrationToDictionaryValue( test_util()->profile()->GetPrefs()); + // TODO(caitkp/erikwright): Look into loading policy values in tests. In + // practice, the DefaultSearchEngineSource() would be FROM_POLICY in this + // case, but since we are not loading the policy here, it will be + // FROM_FALLBACK instead. // Test that the policy-defined value is not migrated. - TemplateURLData modern_default; - ASSERT_FALSE(DefaultSearchManager(test_util()->profile()->GetPrefs()) - .GetDefaultSearchEngine(&modern_default)); + ASSERT_EQ(DefaultSearchManager::FROM_FALLBACK, + DefaultSearchManager(test_util()->profile()->GetPrefs(), + DefaultSearchManager::ObserverCallback()) + .GetDefaultSearchEngineSource()); } diff --git a/chrome/browser/search_engines/template_url_service.cc b/chrome/browser/search_engines/template_url_service.cc index 817756c..10d5e95 100644 --- a/chrome/browser/search_engines/template_url_service.cc +++ b/chrome/browser/search_engines/template_url_service.cc @@ -290,7 +290,9 @@ TemplateURLService::TemplateURLService(Profile* profile) processing_syncer_changes_(false), pending_synced_default_search_(false), dsp_change_origin_(DSP_CHANGE_OTHER), - default_search_manager_(new DefaultSearchManager(GetPrefs())) { + default_search_manager_( + new DefaultSearchManager(GetPrefs(), + DefaultSearchManager::ObserverCallback())) { DCHECK(profile_); Init(NULL, 0); } |