Index: chrome/browser/android/search_geolocation/search_geolocation_service.cc |
diff --git a/chrome/browser/android/search_geolocation/search_geolocation_service.cc b/chrome/browser/android/search_geolocation/search_geolocation_service.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..952dbc76e42a013ee3deb0aed66b87abf005d5e9 |
--- /dev/null |
+++ b/chrome/browser/android/search_geolocation/search_geolocation_service.cc |
@@ -0,0 +1,283 @@ |
+// Copyright 2017 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/android/search_geolocation/search_geolocation_service.h" |
+ |
+#include "base/feature_list.h" |
+#include "base/values.h" |
+#include "chrome/browser/android/search_geolocation/search_geolocation_disclosure_tab_helper.h" |
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h" |
+#include "chrome/browser/profiles/profile.h" |
+#include "chrome/browser/search_engines/template_url_service_factory.h" |
+#include "chrome/browser/search_engines/ui_thread_search_terms_data.h" |
+#include "chrome/common/chrome_features.h" |
+#include "chrome/common/pref_names.h" |
+#include "components/content_settings/core/browser/content_settings_utils.h" |
+#include "components/content_settings/core/browser/host_content_settings_map.h" |
+#include "components/content_settings/core/common/content_settings_types.h" |
+#include "components/keyed_service/content/browser_context_dependency_manager.h" |
+#include "components/pref_registry/pref_registry_syncable.h" |
+#include "components/prefs/pref_service.h" |
+#include "components/search_engines/template_url.h" |
+#include "components/search_engines/template_url_service.h" |
+#include "url/gurl.h" |
+#include "url/url_constants.h" |
+ |
+namespace { |
+ |
+const char kIsGoogleSearchEngineKey[] = "is_google_search_engine"; |
+const char kCCTLDKey[] = "cctld"; |
+const char kDSESettingKey[] = "dse_setting"; |
+ |
+} // namespace |
+ |
+struct SearchGeolocationService::PrefValue { |
+ bool is_google_search_engine = false; |
+ url::Origin cctld; |
+ bool setting = false; |
+}; |
+ |
+// static |
+SearchGeolocationService* |
+SearchGeolocationService::Factory::GetForBrowserContext( |
+ content::BrowserContext* context) { |
+ return static_cast<SearchGeolocationService*>(GetInstance() |
+ ->GetServiceForBrowserContext(context, true)); |
+} |
+ |
+// static |
+SearchGeolocationService::Factory* |
+SearchGeolocationService::Factory::GetInstance() { |
+ return base::Singleton<SearchGeolocationService::Factory>::get(); |
+} |
+ |
+SearchGeolocationService::Factory::Factory() |
+ : BrowserContextKeyedServiceFactory( |
+ "SearchGeolocationService", |
+ BrowserContextDependencyManager::GetInstance()) { |
+ DependsOn(HostContentSettingsMapFactory::GetInstance()); |
+ DependsOn(TemplateURLServiceFactory::GetInstance()); |
+} |
+ |
+SearchGeolocationService::Factory::~Factory() {} |
+ |
+bool SearchGeolocationService::Factory::ServiceIsCreatedWithBrowserContext() |
+ const { |
+ return true; |
+} |
+ |
+KeyedService* SearchGeolocationService::Factory::BuildServiceInstanceFor( |
+ content::BrowserContext* context) const { |
+ return new SearchGeolocationService(Profile::FromBrowserContext(context)); |
+} |
+ |
+// static |
+void SearchGeolocationService::RegisterProfilePrefs( |
+ user_prefs::PrefRegistrySyncable* registry) { |
+ registry->RegisterDictionaryPref(prefs::kGoogleDSEGeolocationSetting); |
+} |
+ |
+SearchGeolocationService::SearchGeolocationService(Profile* profile) |
+ : profile_(profile), |
+ pref_service_(profile_->GetPrefs()), |
+ host_content_settings_map_( |
+ HostContentSettingsMapFactory::GetForProfile(profile_)), |
+ template_url_service_( |
+ TemplateURLServiceFactory::GetForProfile(profile_)) { |
+ if (!UseConsistentSearchGeolocation()) |
+ return; |
+ |
+ template_url_service_->AddObserver(this); |
+ |
+ InitializeDSEGeolocationSettingIfNeeded(); |
+ |
+ // Make sure the setting is valid now. It's possible that the setting has |
+ // become invalid either by changes being made to enterprise policy, or while |
+ // the flag to enable consistent search geolocation was off. |
+ EnsureDSEGeolocationSettingIsValid(); |
+} |
+ |
+bool SearchGeolocationService::UseDSEGeolocationSetting( |
+ const url::Origin& requesting_origin) { |
+ if (!UseConsistentSearchGeolocation()) |
+ return false; |
+ |
+ if (profile_->IsOffTheRecord()) |
+ return false; |
+ |
+ if (requesting_origin.scheme() != url::kHttpsScheme) |
+ return false; |
+ |
+ if (!requesting_origin.IsSameOriginWith(GetDSECCTLD())) |
+ return false; |
+ |
+ // If the content setting for the DSE CCTLD is controlled by policy, and is st |
+ // to ASK, don't use the DSE geolocation setting. |
+ if (!IsContentSettingUserSettable() && |
+ GetCurrentContentSetting() == CONTENT_SETTING_ASK) { |
raymes
2017/01/11 08:30:12
I'm not sure if the check for ASK is actually need
benwells
2017/01/11 09:26:11
We can chat about it more tomorrow. I think it is
|
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
+bool SearchGeolocationService::GetDSEGeolocationSetting() { |
+ // Make sure the setting is valid, in case enterprise policy has changed. |
+ // TODO(benwells): Check if enterprise policy can change while Chrome is |
+ // running. If it can't this call is probably not needed. |
+ EnsureDSEGeolocationSettingIsValid(); |
+ |
+ return GetDSEGeolocationPref().setting; |
+} |
+ |
+void SearchGeolocationService::SetDSEGeolocationSetting(bool setting) { |
+ PrefValue pref = GetDSEGeolocationPref(); |
+ if (setting == pref.setting) |
+ return; |
+ |
+ // If the user cannot change their geolocation content setting (e.g. due to |
+ // enterprise policy), they also can't change this preference so just bail |
+ // out. |
+ if (!IsContentSettingUserSettable()) |
+ return; |
+ |
+ pref.setting = setting; |
+ SetDSEGeolocationPref(pref); |
+ |
+ ResetContentSetting(); |
+} |
+ |
+void SearchGeolocationService::Shutdown() { |
+ if (UseConsistentSearchGeolocation()) |
+ template_url_service_->RemoveObserver(this); |
+} |
+ |
+SearchGeolocationService::~SearchGeolocationService() {} |
+ |
+void SearchGeolocationService::OnTemplateURLServiceChanged() { |
+ bool is_now_google_search_engine = IsGoogleSearchEngine(); |
+ PrefValue pref = GetDSEGeolocationPref(); |
+ ContentSetting content_setting = GetCurrentContentSetting(); |
+ |
+ if (is_now_google_search_engine) { |
+ if (content_setting == CONTENT_SETTING_BLOCK && pref.setting) { |
+ pref.setting = false; |
+ } else if (content_setting == CONTENT_SETTING_ALLOW && !pref.setting) { |
+ ResetContentSetting(); |
+ } |
+ } |
+ |
+ if (is_now_google_search_engine && !pref.is_google_search_engine && |
+ pref.setting) { |
+ SearchGeolocationDisclosureTabHelper::ResetDisclosure(profile_); |
+ } |
+ |
+ pref.is_google_search_engine = is_now_google_search_engine; |
+ pref.cctld = GetDSECCTLD(); |
+ SetDSEGeolocationPref(pref); |
+} |
+ |
+void SearchGeolocationService::InitializeDSEGeolocationSettingIfNeeded() { |
+ // Initialize the pref if it hasn't been initialized yet. |
+ if (!pref_service_->HasPrefPath(prefs::kGoogleDSEGeolocationSetting)) { |
+ ContentSetting content_setting = GetCurrentContentSetting(); |
+ |
+ PrefValue pref; |
+ pref.is_google_search_engine = IsGoogleSearchEngine(); |
+ pref.cctld = GetDSECCTLD(); |
+ pref.setting = content_setting != CONTENT_SETTING_BLOCK; |
+ SetDSEGeolocationPref(pref); |
+ |
+ SearchGeolocationDisclosureTabHelper::ResetDisclosure(profile_); |
+ } |
+} |
+ |
+void SearchGeolocationService::EnsureDSEGeolocationSettingIsValid() { |
+ PrefValue pref = GetDSEGeolocationPref(); |
+ ContentSetting content_setting = GetCurrentContentSetting(); |
+ bool new_setting = pref.setting; |
+ |
+ if (pref.setting && content_setting == CONTENT_SETTING_BLOCK) { |
+ new_setting = false; |
+ } else if (!pref.setting && content_setting == CONTENT_SETTING_ALLOW) { |
+ new_setting = true; |
+ } |
+ |
+ if (pref.setting != new_setting) { |
+ pref.setting = new_setting; |
+ SetDSEGeolocationPref(pref); |
+ } |
+} |
+ |
+bool SearchGeolocationService::IsGoogleSearchEngine() { |
+ const TemplateURL* template_url = |
+ template_url_service_->GetDefaultSearchProvider(); |
+ return template_url && |
+ template_url->HasGoogleBaseURLs(UIThreadSearchTermsData(profile_)); |
+} |
+ |
+url::Origin SearchGeolocationService::GetDSECCTLD() { |
+ if (!IsGoogleSearchEngine()) |
+ return url::Origin(); |
+ |
+ GURL origin_url(UIThreadSearchTermsData(profile_).GoogleBaseURLValue()); |
+ return url::Origin(origin_url); |
+} |
+ |
+SearchGeolocationService::PrefValue |
+SearchGeolocationService::GetDSEGeolocationPref() { |
+ const base::DictionaryValue* dict = |
+ pref_service_->GetDictionary(prefs::kGoogleDSEGeolocationSetting); |
+ |
+ PrefValue pref; |
+ bool is_google_search_engine; |
+ std::string cctld_string; |
+ bool setting; |
+ if (dict->GetBoolean(kIsGoogleSearchEngineKey, &is_google_search_engine) && |
+ dict->GetString(kCCTLDKey, &cctld_string) && |
+ dict->GetBoolean(kDSESettingKey, &setting)) { |
+ pref.is_google_search_engine = is_google_search_engine; |
+ pref.cctld = url::Origin(GURL(cctld_string)); |
+ pref.setting = setting; |
+ } |
+ |
+ return pref; |
+} |
+ |
+void SearchGeolocationService::SetDSEGeolocationPref( |
+ const SearchGeolocationService::PrefValue& pref) { |
+ base::DictionaryValue dict; |
+ dict.SetBoolean(kIsGoogleSearchEngineKey, pref.is_google_search_engine); |
+ dict.SetString(kCCTLDKey, pref.cctld.Serialize()); |
+ dict.SetBoolean(kDSESettingKey, pref.setting); |
+ pref_service_->Set(prefs::kGoogleDSEGeolocationSetting, dict); |
+} |
+ |
+ContentSetting SearchGeolocationService::GetCurrentContentSetting() { |
+ url::Origin origin = GetDSECCTLD(); |
+ return host_content_settings_map_->GetContentSetting( |
+ origin.GetURL(), origin.GetURL(), CONTENT_SETTINGS_TYPE_GEOLOCATION, |
+ std::string()); |
+} |
+ |
+void SearchGeolocationService::ResetContentSetting() { |
+ url::Origin origin = GetDSECCTLD(); |
+ host_content_settings_map_->SetContentSettingDefaultScope( |
+ origin.GetURL(), origin.GetURL(), CONTENT_SETTINGS_TYPE_GEOLOCATION, |
+ std::string(), CONTENT_SETTING_DEFAULT); |
+} |
+ |
+bool SearchGeolocationService::IsContentSettingUserSettable() { |
+ content_settings::SettingInfo info; |
+ url::Origin origin = GetDSECCTLD(); |
+ std::unique_ptr<base::Value> value = |
+ host_content_settings_map_->GetWebsiteSetting( |
+ origin.GetURL(), origin.GetURL(), CONTENT_SETTINGS_TYPE_GEOLOCATION, |
+ std::string(), &info); |
+ return info.source == content_settings::SETTING_SOURCE_USER; |
+} |
+ |
+bool SearchGeolocationService::UseConsistentSearchGeolocation() { |
+ return base::FeatureList::IsEnabled(features::kConsistentOmniboxGeolocation); |
+} |