Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / browser / geolocation / geolocation_service_impl.cc
blobaae95ac01b6bf465564048bee3e7b197d2cc70b8
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"
7 #include "base/bind.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"
12 namespace content {
14 namespace {
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,
31 // Timeout.
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;
40 switch (error_code) {
41 case Geoposition::ERROR_CODE_NONE:
42 code = GEOPOSITION_ERROR_CODE_NONE;
43 break;
44 case Geoposition::ERROR_CODE_PERMISSION_DENIED:
45 code = GEOPOSITION_ERROR_CODE_PERMISSION_DENIED;
46 break;
47 case Geoposition::ERROR_CODE_POSITION_UNAVAILABLE:
48 code = GEOPOSITION_ERROR_CODE_POSITION_UNAVAILABLE;
49 break;
50 case Geoposition::ERROR_CODE_TIMEOUT:
51 code = GEOPOSITION_ERROR_CODE_TIMEOUT;
52 break;
54 UMA_HISTOGRAM_ENUMERATION("Geolocation.LocationUpdate.ErrorCode",
55 code,
56 GEOPOSITION_ERROR_CODE_COUNT);
59 } // namespace
61 GeolocationServiceImpl::GeolocationServiceImpl(
62 mojo::InterfaceRequest<GeolocationService> request,
63 GeolocationServiceContext* context,
64 const base::Closure& update_callback)
65 : binding_(this, request.Pass()),
66 context_(context),
67 update_callback_(update_callback),
68 high_accuracy_(false),
69 has_position_to_report_(false) {
70 DCHECK(context_);
71 binding_.set_connection_error_handler(
72 base::Bind(&GeolocationServiceImpl::OnConnectionError,
73 base::Unretained(this)));
76 GeolocationServiceImpl::~GeolocationServiceImpl() {
77 // Make sure to respond to any pending callback even without a valid position.
78 if (!position_callback_.is_null()) {
79 if (!current_position_.valid) {
80 current_position_.error_code = MojoGeoposition::ErrorCode(
81 GEOPOSITION_ERROR_CODE_POSITION_UNAVAILABLE);
82 current_position_.error_message = mojo::String("");
84 ReportCurrentPosition();
88 void GeolocationServiceImpl::PauseUpdates() {
89 geolocation_subscription_.reset();
92 void GeolocationServiceImpl::ResumeUpdates() {
93 if (position_override_.Validate()) {
94 OnLocationUpdate(position_override_);
95 return;
98 StartListeningForUpdates();
101 void GeolocationServiceImpl::StartListeningForUpdates() {
102 geolocation_subscription_ =
103 GeolocationProvider::GetInstance()->AddLocationUpdateCallback(
104 base::Bind(&GeolocationServiceImpl::OnLocationUpdate,
105 base::Unretained(this)),
106 high_accuracy_);
109 void GeolocationServiceImpl::SetHighAccuracy(bool high_accuracy) {
110 UMA_HISTOGRAM_BOOLEAN(
111 "Geolocation.GeolocationDispatcherHostImpl.EnableHighAccuracy",
112 high_accuracy);
113 high_accuracy_ = high_accuracy;
115 if (position_override_.Validate()) {
116 OnLocationUpdate(position_override_);
117 return;
120 StartListeningForUpdates();
123 void GeolocationServiceImpl::QueryNextPosition(
124 const PositionCallback& callback) {
125 if (!position_callback_.is_null()) {
126 DVLOG(1) << "Overlapped call to QueryNextPosition!";
127 OnConnectionError(); // Simulate a connection error.
128 return;
131 position_callback_ = callback;
133 if (has_position_to_report_)
134 ReportCurrentPosition();
137 void GeolocationServiceImpl::SetOverride(const Geoposition& position) {
138 position_override_ = position;
139 if (!position_override_.Validate()) {
140 ResumeUpdates();
143 geolocation_subscription_.reset();
145 OnLocationUpdate(position_override_);
148 void GeolocationServiceImpl::ClearOverride() {
149 position_override_ = Geoposition();
150 StartListeningForUpdates();
153 void GeolocationServiceImpl::OnConnectionError() {
154 context_->ServiceHadConnectionError(this);
156 // The above call deleted this instance, so the only safe thing to do is
157 // return.
160 void GeolocationServiceImpl::OnLocationUpdate(const Geoposition& position) {
161 RecordGeopositionErrorCode(position.error_code);
162 DCHECK(context_);
164 if (context_->paused())
165 return;
167 update_callback_.Run();
169 current_position_.valid = position.Validate();
170 current_position_.latitude = position.latitude;
171 current_position_.longitude = position.longitude;
172 current_position_.altitude = position.altitude;
173 current_position_.accuracy = position.accuracy;
174 current_position_.altitude_accuracy = position.altitude_accuracy;
175 current_position_.heading = position.heading;
176 current_position_.speed = position.speed;
177 current_position_.timestamp = position.timestamp.ToDoubleT();
178 current_position_.error_code =
179 MojoGeoposition::ErrorCode(position.error_code);
180 current_position_.error_message = position.error_message;
182 has_position_to_report_ = true;
184 if (!position_callback_.is_null())
185 ReportCurrentPosition();
188 void GeolocationServiceImpl::ReportCurrentPosition() {
189 position_callback_.Run(current_position_.Clone());
190 position_callback_.reset();
191 has_position_to_report_ = false;
194 } // namespace content