blob: b06bb4743c988c67dca634d4efc549cb258fda7e [file] [log] [blame]
// 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 "components/language/content/browser/geo_language_provider.h"
#include "base/memory/singleton.h"
#include "base/task_scheduler/post_task.h"
#include "base/time/time.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "services/device/public/interfaces/constants.mojom.h"
#include "services/device/public/interfaces/public_ip_address_geolocation_provider.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
namespace language {
namespace {
// Don't start requesting updates to IP-based approximation geolocation until
// this long after receiving the last one.
constexpr base::TimeDelta kMinUpdatePeriod = base::TimeDelta::FromDays(1);
} // namespace
GeoLanguageProvider::GeoLanguageProvider()
: languages_(),
creation_task_runner_(base::SequencedTaskRunnerHandle::Get()),
background_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
{base::MayBlock(), base::TaskPriority::BACKGROUND,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})) {
// Constructor is not required to run on |background_task_runner_|:
DETACH_FROM_SEQUENCE(background_sequence_checker_);
}
GeoLanguageProvider::GeoLanguageProvider(
scoped_refptr<base::SequencedTaskRunner> background_task_runner)
: languages_(),
creation_task_runner_(base::SequencedTaskRunnerHandle::Get()),
background_task_runner_(background_task_runner) {
// Constructor is not required to run on |background_task_runner_|:
DETACH_FROM_SEQUENCE(background_sequence_checker_);
}
GeoLanguageProvider::~GeoLanguageProvider() = default;
/* static */
GeoLanguageProvider* GeoLanguageProvider::GetInstance() {
return base::Singleton<GeoLanguageProvider, base::LeakySingletonTraits<
GeoLanguageProvider>>::get();
}
void GeoLanguageProvider::StartUp(
std::unique_ptr<service_manager::Connector> service_manager_connector) {
DCHECK_CALLED_ON_VALID_SEQUENCE(creation_sequence_checker_);
service_manager_connector_ = std::move(service_manager_connector);
// Continue startup in the background.
background_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&GeoLanguageProvider::BackgroundStartUp,
base::Unretained(this)));
}
std::vector<std::string> GeoLanguageProvider::CurrentGeoLanguages() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(creation_sequence_checker_);
return languages_;
}
void GeoLanguageProvider::BackgroundStartUp() {
// This binds background_sequence_checker_.
DCHECK_CALLED_ON_VALID_SEQUENCE(background_sequence_checker_);
// Initialize location->language lookup library.
language_code_locator_ = std::make_unique<language::LanguageCodeLocator>();
// Make initial query.
QueryNextPosition();
}
void GeoLanguageProvider::BindIpGeolocationService() {
DCHECK_CALLED_ON_VALID_SEQUENCE(background_sequence_checker_);
DCHECK(!geolocation_provider_.is_bound());
// Bind a PublicIpAddressGeolocationProvider.
device::mojom::PublicIpAddressGeolocationProviderPtr ip_geolocation_provider;
service_manager_connector_->BindInterface(
device::mojom::kServiceName, mojo::MakeRequest(&ip_geolocation_provider));
net::PartialNetworkTrafficAnnotationTag partial_traffic_annotation =
net::DefinePartialNetworkTrafficAnnotation("geo_language_provider",
"network_location_request",
R"(
semantics {
sender: "GeoLanguage Provider"
}
policy {
setting:
"Users can control this feature via the translation settings "
"'Languages', 'Language', 'Offer to translate'."
chrome_policy {
DefaultGeolocationSetting {
DefaultGeolocationSetting: 2
}
}
})");
// Use the PublicIpAddressGeolocationProvider to bind ip_geolocation_service_.
ip_geolocation_provider->CreateGeolocation(
static_cast<net::MutablePartialNetworkTrafficAnnotationTag>(
partial_traffic_annotation),
mojo::MakeRequest(&geolocation_provider_));
// No error handler required: If the connection is broken, QueryNextPosition
// will bind it again.
}
void GeoLanguageProvider::QueryNextPosition() {
DCHECK_CALLED_ON_VALID_SEQUENCE(background_sequence_checker_);
if (geolocation_provider_.encountered_error())
geolocation_provider_.reset();
if (!geolocation_provider_.is_bound())
BindIpGeolocationService();
geolocation_provider_->QueryNextPosition(base::BindOnce(
&GeoLanguageProvider::OnIpGeolocationResponse, base::Unretained(this)));
}
void GeoLanguageProvider::OnIpGeolocationResponse(
device::mojom::GeopositionPtr geoposition) {
DCHECK_CALLED_ON_VALID_SEQUENCE(background_sequence_checker_);
const std::vector<std::string> languages =
language_code_locator_->GetLanguageCode(geoposition->latitude,
geoposition->longitude);
// Update current languages on UI thread.
creation_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&GeoLanguageProvider::SetGeoLanguages,
base::Unretained(this), languages));
// Post a task to request a fresh lookup after |kMinUpdatePeriod|.
background_task_runner_->PostDelayedTask(
FROM_HERE,
base::BindOnce(&GeoLanguageProvider::QueryNextPosition,
base::Unretained(this)),
kMinUpdatePeriod);
}
void GeoLanguageProvider::SetGeoLanguages(
const std::vector<std::string>& languages) {
DCHECK_CALLED_ON_VALID_SEQUENCE(creation_sequence_checker_);
languages_ = languages;
}
} // namespace language