OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "content/browser/geolocation/geolocation_service_impl.h" | |
6 | |
7 #include <utility> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/metrics/histogram.h" | |
11 #include "content/browser/geolocation/geolocation_service_context.h" | |
12 | |
13 namespace content { | |
14 | |
15 namespace { | |
16 | |
17 // Geoposition error codes for reporting in UMA. | |
18 enum GeopositionErrorCode { | |
19 // NOTE: Do not renumber these as that would confuse interpretation of | |
20 // previously logged data. When making changes, also update the enum list | |
21 // in tools/metrics/histograms/histograms.xml to keep it in sync. | |
22 | |
23 // There was no error. | |
24 GEOPOSITION_ERROR_CODE_NONE = 0, | |
25 | |
26 // User denied use of geolocation. | |
27 GEOPOSITION_ERROR_CODE_PERMISSION_DENIED = 1, | |
28 | |
29 // Geoposition could not be determined. | |
30 GEOPOSITION_ERROR_CODE_POSITION_UNAVAILABLE = 2, | |
31 | |
32 // Timeout. | |
33 GEOPOSITION_ERROR_CODE_TIMEOUT = 3, | |
34 | |
35 // NOTE: Add entries only immediately above this line. | |
36 GEOPOSITION_ERROR_CODE_COUNT = 4 | |
37 }; | |
38 | |
39 void RecordGeopositionErrorCode(Geoposition::ErrorCode error_code) { | |
40 GeopositionErrorCode code = GEOPOSITION_ERROR_CODE_NONE; | |
41 switch (error_code) { | |
42 case Geoposition::ERROR_CODE_NONE: | |
43 code = GEOPOSITION_ERROR_CODE_NONE; | |
44 break; | |
45 case Geoposition::ERROR_CODE_PERMISSION_DENIED: | |
46 code = GEOPOSITION_ERROR_CODE_PERMISSION_DENIED; | |
47 break; | |
48 case Geoposition::ERROR_CODE_POSITION_UNAVAILABLE: | |
49 code = GEOPOSITION_ERROR_CODE_POSITION_UNAVAILABLE; | |
50 break; | |
51 case Geoposition::ERROR_CODE_TIMEOUT: | |
52 code = GEOPOSITION_ERROR_CODE_TIMEOUT; | |
53 break; | |
54 } | |
55 UMA_HISTOGRAM_ENUMERATION("Geolocation.LocationUpdate.ErrorCode", | |
56 code, | |
57 GEOPOSITION_ERROR_CODE_COUNT); | |
58 } | |
59 | |
60 } // namespace | |
61 | |
62 GeolocationServiceImpl::GeolocationServiceImpl( | |
63 mojo::InterfaceRequest<GeolocationService> request, | |
64 GeolocationServiceContext* context, | |
65 const base::Closure& update_callback) | |
66 : binding_(this, std::move(request)), | |
67 context_(context), | |
68 update_callback_(update_callback), | |
69 high_accuracy_(false), | |
70 has_position_to_report_(false) { | |
71 DCHECK(context_); | |
72 binding_.set_connection_error_handler( | |
73 base::Bind(&GeolocationServiceImpl::OnConnectionError, | |
74 base::Unretained(this))); | |
75 } | |
76 | |
77 GeolocationServiceImpl::~GeolocationServiceImpl() { | |
78 // Make sure to respond to any pending callback even without a valid position. | |
79 if (!position_callback_.is_null()) { | |
80 if (!current_position_.valid) { | |
81 current_position_.error_code = blink::mojom::Geoposition::ErrorCode( | |
82 GEOPOSITION_ERROR_CODE_POSITION_UNAVAILABLE); | |
83 current_position_.error_message = mojo::String(""); | |
84 } | |
85 ReportCurrentPosition(); | |
86 } | |
87 } | |
88 | |
89 void GeolocationServiceImpl::PauseUpdates() { | |
90 geolocation_subscription_.reset(); | |
91 } | |
92 | |
93 void GeolocationServiceImpl::ResumeUpdates() { | |
94 if (position_override_.Validate()) { | |
95 OnLocationUpdate(position_override_); | |
96 return; | |
97 } | |
98 | |
99 StartListeningForUpdates(); | |
100 } | |
101 | |
102 void GeolocationServiceImpl::StartListeningForUpdates() { | |
103 geolocation_subscription_ = | |
104 GeolocationProvider::GetInstance()->AddLocationUpdateCallback( | |
105 base::Bind(&GeolocationServiceImpl::OnLocationUpdate, | |
106 base::Unretained(this)), | |
107 high_accuracy_); | |
108 } | |
109 | |
110 void GeolocationServiceImpl::SetHighAccuracy(bool high_accuracy) { | |
111 UMA_HISTOGRAM_BOOLEAN( | |
112 "Geolocation.GeolocationDispatcherHostImpl.EnableHighAccuracy", | |
113 high_accuracy); | |
114 high_accuracy_ = high_accuracy; | |
115 | |
116 if (position_override_.Validate()) { | |
117 OnLocationUpdate(position_override_); | |
118 return; | |
119 } | |
120 | |
121 StartListeningForUpdates(); | |
122 } | |
123 | |
124 void GeolocationServiceImpl::QueryNextPosition( | |
125 const QueryNextPositionCallback& callback) { | |
126 if (!position_callback_.is_null()) { | |
127 DVLOG(1) << "Overlapped call to QueryNextPosition!"; | |
128 OnConnectionError(); // Simulate a connection error. | |
129 return; | |
130 } | |
131 | |
132 position_callback_ = callback; | |
133 | |
134 if (has_position_to_report_) | |
135 ReportCurrentPosition(); | |
136 } | |
137 | |
138 void GeolocationServiceImpl::SetOverride(const Geoposition& position) { | |
139 position_override_ = position; | |
140 if (!position_override_.Validate()) { | |
141 ResumeUpdates(); | |
142 } | |
143 | |
144 geolocation_subscription_.reset(); | |
145 | |
146 OnLocationUpdate(position_override_); | |
147 } | |
148 | |
149 void GeolocationServiceImpl::ClearOverride() { | |
150 position_override_ = Geoposition(); | |
151 StartListeningForUpdates(); | |
152 } | |
153 | |
154 void GeolocationServiceImpl::OnConnectionError() { | |
155 context_->ServiceHadConnectionError(this); | |
156 | |
157 // The above call deleted this instance, so the only safe thing to do is | |
158 // return. | |
159 } | |
160 | |
161 void GeolocationServiceImpl::OnLocationUpdate(const Geoposition& position) { | |
162 RecordGeopositionErrorCode(position.error_code); | |
163 DCHECK(context_); | |
164 | |
165 if (context_->paused()) | |
166 return; | |
167 | |
168 update_callback_.Run(); | |
169 | |
170 current_position_.valid = position.Validate(); | |
171 current_position_.latitude = position.latitude; | |
172 current_position_.longitude = position.longitude; | |
173 current_position_.altitude = position.altitude; | |
174 current_position_.accuracy = position.accuracy; | |
175 current_position_.altitude_accuracy = position.altitude_accuracy; | |
176 current_position_.heading = position.heading; | |
177 current_position_.speed = position.speed; | |
178 current_position_.timestamp = position.timestamp.ToDoubleT(); | |
179 current_position_.error_code = | |
180 blink::mojom::Geoposition::ErrorCode(position.error_code); | |
181 current_position_.error_message = position.error_message; | |
182 | |
183 has_position_to_report_ = true; | |
184 | |
185 if (!position_callback_.is_null()) | |
186 ReportCurrentPosition(); | |
187 } | |
188 | |
189 void GeolocationServiceImpl::ReportCurrentPosition() { | |
190 position_callback_.Run(current_position_.Clone()); | |
191 position_callback_.Reset(); | |
192 has_position_to_report_ = false; | |
193 } | |
194 | |
195 } // namespace content | |
OLD | NEW |