blob: 4c855f27046541b5ede834728846617cbd5b07b2 [file] [log] [blame]
// Copyright 2014 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 "content/browser/geolocation/geolocation_service_impl.h"
#include "base/bind.h"
#include "base/metrics/histogram.h"
#include "content/browser/geolocation/geolocation_service_context.h"
#include "content/public/common/mojo_geoposition.mojom.h"
namespace content {
namespace {
// Geoposition error codes for reporting in UMA.
enum GeopositionErrorCode {
// NOTE: Do not renumber these as that would confuse interpretation of
// previously logged data. When making changes, also update the enum list
// in tools/metrics/histograms/histograms.xml to keep it in sync.
// There was no error.
GEOPOSITION_ERROR_CODE_NONE = 0,
// User denied use of geolocation.
GEOPOSITION_ERROR_CODE_PERMISSION_DENIED = 1,
// Geoposition could not be determined.
GEOPOSITION_ERROR_CODE_POSITION_UNAVAILABLE = 2,
// Timeout.
GEOPOSITION_ERROR_CODE_TIMEOUT = 3,
// NOTE: Add entries only immediately above this line.
GEOPOSITION_ERROR_CODE_COUNT = 4
};
void RecordGeopositionErrorCode(Geoposition::ErrorCode error_code) {
GeopositionErrorCode code = GEOPOSITION_ERROR_CODE_NONE;
switch (error_code) {
case Geoposition::ERROR_CODE_NONE:
code = GEOPOSITION_ERROR_CODE_NONE;
break;
case Geoposition::ERROR_CODE_PERMISSION_DENIED:
code = GEOPOSITION_ERROR_CODE_PERMISSION_DENIED;
break;
case Geoposition::ERROR_CODE_POSITION_UNAVAILABLE:
code = GEOPOSITION_ERROR_CODE_POSITION_UNAVAILABLE;
break;
case Geoposition::ERROR_CODE_TIMEOUT:
code = GEOPOSITION_ERROR_CODE_TIMEOUT;
break;
}
UMA_HISTOGRAM_ENUMERATION("Geolocation.LocationUpdate.ErrorCode",
code,
GEOPOSITION_ERROR_CODE_COUNT);
}
} // namespace
GeolocationServiceImpl::GeolocationServiceImpl(
GeolocationServiceContext* context,
const base::Closure& update_callback)
: context_(context),
update_callback_(update_callback),
high_accuracy_(false) {
DCHECK(context_);
}
GeolocationServiceImpl::~GeolocationServiceImpl() {
}
void GeolocationServiceImpl::PauseUpdates() {
geolocation_subscription_.reset();
}
void GeolocationServiceImpl::ResumeUpdates() {
if (position_override_.Validate()) {
OnLocationUpdate(position_override_);
return;
}
StartListeningForUpdates();
}
void GeolocationServiceImpl::StartListeningForUpdates() {
geolocation_subscription_ =
GeolocationProvider::GetInstance()->AddLocationUpdateCallback(
base::Bind(&GeolocationServiceImpl::OnLocationUpdate,
base::Unretained(this)),
high_accuracy_);
}
void GeolocationServiceImpl::SetHighAccuracy(bool high_accuracy) {
UMA_HISTOGRAM_BOOLEAN(
"Geolocation.GeolocationDispatcherHostImpl.EnableHighAccuracy",
high_accuracy);
high_accuracy_ = high_accuracy;
if (position_override_.Validate()) {
OnLocationUpdate(position_override_);
return;
}
StartListeningForUpdates();
}
void GeolocationServiceImpl::SetOverride(const Geoposition& position) {
position_override_ = position;
if (!position_override_.Validate()) {
ResumeUpdates();
}
geolocation_subscription_.reset();
OnLocationUpdate(position_override_);
}
void GeolocationServiceImpl::ClearOverride() {
position_override_ = Geoposition();
StartListeningForUpdates();
}
void GeolocationServiceImpl::OnConnectionError() {
context_->ServiceHadConnectionError(this);
// The above call deleted this instance, so the only safe thing to do is
// return.
}
void GeolocationServiceImpl::OnLocationUpdate(const Geoposition& position) {
RecordGeopositionErrorCode(position.error_code);
DCHECK(context_);
if (context_->paused())
return;
MojoGeopositionPtr geoposition(MojoGeoposition::New());
geoposition->valid = position.Validate();
geoposition->latitude = position.latitude;
geoposition->longitude = position.longitude;
geoposition->altitude = position.altitude;
geoposition->accuracy = position.accuracy;
geoposition->altitude_accuracy = position.altitude_accuracy;
geoposition->heading = position.heading;
geoposition->speed = position.speed;
geoposition->timestamp = position.timestamp.ToDoubleT();
geoposition->error_code = MojoGeoposition::ErrorCode(position.error_code);
geoposition->error_message = position.error_message;
update_callback_.Run();
client()->OnLocationUpdate(geoposition.Pass());
}
} // namespace content