| 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) {
|
| + 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);
|
| +}
|
|
|