1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/geolocation/geolocation_service_impl.h"
8 #include "base/metrics/histogram.h"
9 #include "content/browser/geolocation/geolocation_service_context.h"
10 #include "content/public/common/mojo_geoposition.mojom.h"
16 // Geoposition error codes for reporting in UMA.
17 enum GeopositionErrorCode
{
18 // NOTE: Do not renumber these as that would confuse interpretation of
19 // previously logged data. When making changes, also update the enum list
20 // in tools/metrics/histograms/histograms.xml to keep it in sync.
22 // There was no error.
23 GEOPOSITION_ERROR_CODE_NONE
= 0,
25 // User denied use of geolocation.
26 GEOPOSITION_ERROR_CODE_PERMISSION_DENIED
= 1,
28 // Geoposition could not be determined.
29 GEOPOSITION_ERROR_CODE_POSITION_UNAVAILABLE
= 2,
32 GEOPOSITION_ERROR_CODE_TIMEOUT
= 3,
34 // NOTE: Add entries only immediately above this line.
35 GEOPOSITION_ERROR_CODE_COUNT
= 4
38 void RecordGeopositionErrorCode(Geoposition::ErrorCode error_code
) {
39 GeopositionErrorCode code
= GEOPOSITION_ERROR_CODE_NONE
;
41 case Geoposition::ERROR_CODE_NONE
:
42 code
= GEOPOSITION_ERROR_CODE_NONE
;
44 case Geoposition::ERROR_CODE_PERMISSION_DENIED
:
45 code
= GEOPOSITION_ERROR_CODE_PERMISSION_DENIED
;
47 case Geoposition::ERROR_CODE_POSITION_UNAVAILABLE
:
48 code
= GEOPOSITION_ERROR_CODE_POSITION_UNAVAILABLE
;
50 case Geoposition::ERROR_CODE_TIMEOUT
:
51 code
= GEOPOSITION_ERROR_CODE_TIMEOUT
;
54 UMA_HISTOGRAM_ENUMERATION("Geolocation.LocationUpdate.ErrorCode",
56 GEOPOSITION_ERROR_CODE_COUNT
);
61 GeolocationServiceImpl::GeolocationServiceImpl(
62 GeolocationServiceContext
* context
,
63 const base::Closure
& update_callback
)
65 update_callback_(update_callback
),
66 high_accuracy_(false),
67 has_position_to_report_(false) {
71 GeolocationServiceImpl::~GeolocationServiceImpl() {
74 void GeolocationServiceImpl::PauseUpdates() {
75 geolocation_subscription_
.reset();
78 void GeolocationServiceImpl::ResumeUpdates() {
79 if (position_override_
.Validate()) {
80 OnLocationUpdate(position_override_
);
84 StartListeningForUpdates();
87 void GeolocationServiceImpl::StartListeningForUpdates() {
88 geolocation_subscription_
=
89 GeolocationProvider::GetInstance()->AddLocationUpdateCallback(
90 base::Bind(&GeolocationServiceImpl::OnLocationUpdate
,
91 base::Unretained(this)),
95 void GeolocationServiceImpl::SetHighAccuracy(bool high_accuracy
) {
96 UMA_HISTOGRAM_BOOLEAN(
97 "Geolocation.GeolocationDispatcherHostImpl.EnableHighAccuracy",
99 high_accuracy_
= high_accuracy
;
101 if (position_override_
.Validate()) {
102 OnLocationUpdate(position_override_
);
106 StartListeningForUpdates();
109 void GeolocationServiceImpl::QueryNextPosition(
110 const PositionCallback
& callback
) {
111 position_callbacks_
.push_back(callback
);
113 if (has_position_to_report_
)
114 ReportCurrentPosition();
117 void GeolocationServiceImpl::SetOverride(const Geoposition
& position
) {
118 position_override_
= position
;
119 if (!position_override_
.Validate()) {
123 geolocation_subscription_
.reset();
125 OnLocationUpdate(position_override_
);
128 void GeolocationServiceImpl::ClearOverride() {
129 position_override_
= Geoposition();
130 StartListeningForUpdates();
133 void GeolocationServiceImpl::OnConnectionError() {
134 context_
->ServiceHadConnectionError(this);
136 // The above call deleted this instance, so the only safe thing to do is
140 void GeolocationServiceImpl::OnLocationUpdate(const Geoposition
& position
) {
141 RecordGeopositionErrorCode(position
.error_code
);
144 if (context_
->paused())
147 update_callback_
.Run();
149 current_position_
.valid
= position
.Validate();
150 current_position_
.latitude
= position
.latitude
;
151 current_position_
.longitude
= position
.longitude
;
152 current_position_
.altitude
= position
.altitude
;
153 current_position_
.accuracy
= position
.accuracy
;
154 current_position_
.altitude_accuracy
= position
.altitude_accuracy
;
155 current_position_
.heading
= position
.heading
;
156 current_position_
.speed
= position
.speed
;
157 current_position_
.timestamp
= position
.timestamp
.ToDoubleT();
158 current_position_
.error_code
=
159 MojoGeoposition::ErrorCode(position
.error_code
);
160 current_position_
.error_message
= position
.error_message
;
162 has_position_to_report_
= true;
164 if (!position_callbacks_
.empty())
165 ReportCurrentPosition();
168 void GeolocationServiceImpl::ReportCurrentPosition() {
169 for (const auto& callback
: position_callbacks_
)
170 callback
.Run(current_position_
.Clone());
171 position_callbacks_
.clear();
172 has_position_to_report_
= false;
175 } // namespace content