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..628d616a0776173b8e27ad68f8588457b1332bef |
--- /dev/null |
+++ b/chrome/browser/android/search_geolocation/search_geolocation_service.cc |
@@ -0,0 +1,253 @@ |
+// 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/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; |
+ url::Origin cctld; |
+ bool setting; |
+}; |
+ |
+// 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(); |
+ EnsureDSEGeolocationSettingIsValid(); |
raymes
2017/01/09 05:47:26
It might be worth adding a comment about why this
benwells
2017/01/09 21:02:22
Done.
|
+} |
+ |
+bool SearchGeolocationService::UseDSEGeolocationSetting( |
+ const url::Origin& requesting_origin) { |
+ if (profile_->IsOffTheRecord()) |
+ return false; |
+ |
+ if (!UseConsistentSearchGeolocation()) |
+ return false; |
raymes
2017/01/09 05:47:26
nit: should this just be the first check?
benwells
2017/01/09 21:02:22
Done.
|
+ |
+ if (requesting_origin.scheme() != url::kHttpsScheme) |
+ return false; |
+ |
raymes
2017/01/09 05:47:26
I think we could just add an "IsUserSettable()" ch
benwells
2017/01/09 21:02:22
The enterprise policy could force geolocation on,
raymes
2017/01/10 03:19:32
Hmm, but wouldn't we fall back to using the enterp
benwells
2017/01/11 05:35:32
After our discussion offline, I've made it so if !
|
+ return requesting_origin.IsSameOriginWith(GetDSECCTLD()); |
+} |
+ |
+bool SearchGeolocationService::GetDSEGeolocationSetting() { |
raymes
2017/01/09 05:47:26
I vaguely remember talking about ensuring validity
benwells
2017/01/09 21:02:22
I'm not sure if it's needed or not. I've added in
|
+ return GetDSEGeolocationPref().setting; |
+} |
+ |
+void SearchGeolocationService::SetDSEGeolocationSetting(bool setting) { |
+ PrefValue pref = GetDSEGeolocationPref(); |
+ if (setting == pref.setting) |
+ return; |
+ |
raymes
2017/01/09 05:47:26
As mentioned, I think I'd prefer having
if (!IsUs
benwells
2017/01/09 21:02:22
Done.
|
+ pref.setting = setting; |
+ SetDSEGeolocationPref(pref); |
+ |
+ ResetContentSetting(); |
+ |
+ // The UI layer currently (January 2017) has no knowledge of enterprise |
+ // policy, and allows users to edit settings in this state. If the user does |
+ // this they may change their DSE geolocation setting when they shouldn't be |
+ // able to, so we make sure the state is valid now. |
+ EnsureDSEGeolocationSettingIsValid(); |
+} |
+ |
+void SearchGeolocationService::Shutdown() { |
+ if (UseConsistentSearchGeolocation()) |
+ template_url_service_->RemoveObserver(this); |
+} |
+ |
+// 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()) {} |
+ |
+SearchGeolocationService::Factory::~Factory() {} |
+ |
+bool SearchGeolocationService::Factory::ServiceIsCreatedWithBrowserContext() |
+ const { |
+ return true; |
+} |
+ |
+KeyedService* SearchGeolocationService::Factory::BuildServiceInstanceFor( |
+ content::BrowserContext* context) const { |
+ return new SearchGeolocationService(Profile::FromBrowserContext(context)); |
+} |
+ |
+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 initialize yet. |
raymes
2017/01/09 05:47:26
nit: initialized
benwells
2017/01/09 21:02:22
Done.
|
+ 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; |
raymes
2017/01/09 05:47:26
I think the struct will be uninitialized? We could
benwells
2017/01/09 21:02:22
Done (via default values).
|
+} |
+ |
+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() { |
+ content_settings::SettingInfo info; |
+ url::Origin origin = GetDSECCTLD(); |
+ std::unique_ptr<base::Value> value = |
+ host_content_settings_map_->GetWebsiteSetting( |
raymes
2017/01/09 05:47:26
Since you're not using "info" here, you can just c
benwells
2017/01/09 21:02:22
Done.
|
+ origin.GetURL(), origin.GetURL(), CONTENT_SETTINGS_TYPE_GEOLOCATION, |
+ std::string(), &info); |
+ return content_settings::ValueToContentSetting(value.get()); |
+} |
+ |
+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::UseConsistentSearchGeolocation() { |
+ return base::FeatureList::IsEnabled(features::kConsistentOmniboxGeolocation); |
+} |