OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/extensions/api/location/location_manager.h" | 5 #include "chrome/browser/extensions/api/location/location_manager.h" |
6 | 6 |
7 #include <math.h> | 7 #include <math.h> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
133 | 133 |
134 base::Time last_update_time_; | 134 base::Time last_update_time_; |
135 const double time_between_updates_ms_; | 135 const double time_between_updates_ms_; |
136 | 136 |
137 DISALLOW_COPY_AND_ASSIGN(TimeBasedUpdatePolicy); | 137 DISALLOW_COPY_AND_ASSIGN(TimeBasedUpdatePolicy); |
138 }; | 138 }; |
139 | 139 |
140 } // namespace updatepolicy | 140 } // namespace updatepolicy |
141 | 141 |
142 // Request created by chrome.location.watchLocation() call. | 142 // Request created by chrome.location.watchLocation() call. |
143 // Lives in the IO thread, except for the constructor. | 143 class LocationRequest : public base::RefCounted<LocationRequest> { |
144 class LocationRequest | |
145 : public base::RefCountedThreadSafe<LocationRequest, | |
146 BrowserThread::DeleteOnIOThread> { | |
147 public: | 144 public: |
148 LocationRequest( | 145 LocationRequest( |
149 const base::WeakPtr<LocationManager>& location_manager, | 146 LocationManager* location_manager, |
150 const std::string& extension_id, | 147 const std::string& extension_id, |
151 const std::string& request_name, | 148 const std::string& request_name, |
152 const double* distance_update_threshold_meters, | 149 const double* distance_update_threshold_meters, |
153 const double* time_between_updates_ms); | 150 const double* time_between_updates_ms); |
154 | 151 |
155 // Finishes the necessary setup for this object. | |
156 // Call this method immediately after taking a strong reference | |
157 // to this object. | |
158 // | |
159 // Ideally, we would do this at construction time, but currently | |
160 // our refcount starts at zero. BrowserThread::PostTask will take a ref | |
161 // and potentially release it before we are done, destroying us in the | |
162 // constructor. | |
163 void Initialize(); | |
164 | |
165 const std::string& request_name() const { return request_name_; } | 152 const std::string& request_name() const { return request_name_; } |
166 | 153 |
167 // Grants permission for using geolocation. | |
168 static void GrantPermission(); | |
169 | |
170 private: | 154 private: |
171 friend class base::DeleteHelper<LocationRequest>; | 155 friend class base::RefCounted<LocationRequest>; |
172 friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>; | 156 ~LocationRequest(); |
173 | |
174 virtual ~LocationRequest(); | |
175 | |
176 void AddObserverOnIOThread(); | |
177 | 157 |
178 void OnLocationUpdate(const content::Geoposition& position); | 158 void OnLocationUpdate(const content::Geoposition& position); |
179 | 159 |
180 // Determines if all policies say to send a position update. | 160 // Determines if all policies say to send a position update. |
181 // If there are no policies, this always says yes. | 161 // If there are no policies, this always says yes. |
182 bool ShouldSendUpdate(const content::Geoposition& position); | 162 bool ShouldSendUpdate(const content::Geoposition& position); |
183 | 163 |
184 // Updates the policies on sending a position update. | 164 // Updates the policies on sending a position update. |
185 void OnPositionReported(const content::Geoposition& position); | 165 void OnPositionReported(const content::Geoposition& position); |
186 | 166 |
187 // Request name. | 167 // Request name. |
188 const std::string request_name_; | 168 const std::string request_name_; |
189 | 169 |
190 // Id of the owner extension. | 170 // Id of the owner extension. |
191 const std::string extension_id_; | 171 const std::string extension_id_; |
192 | 172 |
193 // Owning location manager. | 173 // Owning location manager. |
194 const base::WeakPtr<LocationManager> location_manager_; | 174 LocationManager* location_manager_; |
195 | 175 |
196 // Holds Update Policies. | 176 // Holds Update Policies. |
197 typedef std::vector<scoped_refptr<updatepolicy::UpdatePolicy> > | 177 typedef std::vector<scoped_refptr<updatepolicy::UpdatePolicy> > |
198 UpdatePolicyVector; | 178 UpdatePolicyVector; |
199 UpdatePolicyVector update_policies_; | 179 UpdatePolicyVector update_policies_; |
200 | 180 |
201 content::GeolocationProvider::LocationUpdateCallback callback_; | 181 scoped_ptr<content::GeolocationProvider::Subscription> |
| 182 geolocation_subscription_; |
202 | 183 |
203 DISALLOW_COPY_AND_ASSIGN(LocationRequest); | 184 DISALLOW_COPY_AND_ASSIGN(LocationRequest); |
204 }; | 185 }; |
205 | 186 |
206 LocationRequest::LocationRequest( | 187 LocationRequest::LocationRequest( |
207 const base::WeakPtr<LocationManager>& location_manager, | 188 LocationManager* location_manager, |
208 const std::string& extension_id, | 189 const std::string& extension_id, |
209 const std::string& request_name, | 190 const std::string& request_name, |
210 const double* distance_update_threshold_meters, | 191 const double* distance_update_threshold_meters, |
211 const double* time_between_updates_ms) | 192 const double* time_between_updates_ms) |
212 : request_name_(request_name), | 193 : request_name_(request_name), |
213 extension_id_(extension_id), | 194 extension_id_(extension_id), |
214 location_manager_(location_manager) { | 195 location_manager_(location_manager) { |
215 // TODO(vadimt): use request_info. | 196 // TODO(vadimt): use request_info. |
216 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
217 | |
218 if (time_between_updates_ms) { | 197 if (time_between_updates_ms) { |
219 update_policies_.push_back( | 198 update_policies_.push_back( |
220 new updatepolicy::TimeBasedUpdatePolicy( | 199 new updatepolicy::TimeBasedUpdatePolicy( |
221 *time_between_updates_ms)); | 200 *time_between_updates_ms)); |
222 } | 201 } |
223 | 202 |
224 if (distance_update_threshold_meters) { | 203 if (distance_update_threshold_meters) { |
225 update_policies_.push_back( | 204 update_policies_.push_back( |
226 new updatepolicy::DistanceBasedUpdatePolicy( | 205 new updatepolicy::DistanceBasedUpdatePolicy( |
227 *distance_update_threshold_meters)); | 206 *distance_update_threshold_meters)); |
228 } | 207 } |
229 } | |
230 | |
231 void LocationRequest::Initialize() { | |
232 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
233 callback_ = base::Bind(&LocationRequest::OnLocationUpdate, | |
234 base::Unretained(this)); | |
235 | |
236 BrowserThread::PostTask( | |
237 BrowserThread::IO, | |
238 FROM_HERE, | |
239 base::Bind(&LocationRequest::AddObserverOnIOThread, | |
240 this)); | |
241 } | |
242 | |
243 void LocationRequest::GrantPermission() { | |
244 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
245 content::GeolocationProvider::GetInstance()->UserDidOptIntoLocationServices(); | |
246 } | |
247 | |
248 LocationRequest::~LocationRequest() { | |
249 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
250 content::GeolocationProvider::GetInstance()->RemoveLocationUpdateCallback( | |
251 callback_); | |
252 } | |
253 | |
254 void LocationRequest::AddObserverOnIOThread() { | |
255 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
256 | 208 |
257 // TODO(vadimt): This can get a location cached by GeolocationProvider, | 209 // TODO(vadimt): This can get a location cached by GeolocationProvider, |
258 // contrary to the API definition which says that creating a location watch | 210 // contrary to the API definition which says that creating a location watch |
259 // will get new location. | 211 // will get new location. |
260 content::GeolocationProvider::GetInstance()->AddLocationUpdateCallback( | 212 geolocation_subscription_ = content::GeolocationProvider::GetInstance()-> |
261 callback_, true); | 213 AddLocationUpdateCallback( |
| 214 base::Bind(&LocationRequest::OnLocationUpdate, |
| 215 base::Unretained(this)), |
| 216 true); |
| 217 } |
| 218 |
| 219 LocationRequest::~LocationRequest() { |
262 } | 220 } |
263 | 221 |
264 void LocationRequest::OnLocationUpdate(const content::Geoposition& position) { | 222 void LocationRequest::OnLocationUpdate(const content::Geoposition& position) { |
265 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
266 if (ShouldSendUpdate(position)) { | 223 if (ShouldSendUpdate(position)) { |
267 OnPositionReported(position); | 224 OnPositionReported(position); |
268 BrowserThread::PostTask( | 225 location_manager_->SendLocationUpdate( |
269 BrowserThread::UI, | 226 extension_id_, request_name_, position); |
270 FROM_HERE, | |
271 base::Bind(&LocationManager::SendLocationUpdate, | |
272 location_manager_, | |
273 extension_id_, | |
274 request_name_, | |
275 position)); | |
276 } | 227 } |
277 } | 228 } |
278 | 229 |
279 bool LocationRequest::ShouldSendUpdate(const content::Geoposition& position) { | 230 bool LocationRequest::ShouldSendUpdate(const content::Geoposition& position) { |
280 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
281 for (UpdatePolicyVector::iterator it = update_policies_.begin(); | 231 for (UpdatePolicyVector::iterator it = update_policies_.begin(); |
282 it != update_policies_.end(); | 232 it != update_policies_.end(); |
283 ++it) { | 233 ++it) { |
284 if (!((*it)->ShouldSendUpdate(position))) { | 234 if (!((*it)->ShouldSendUpdate(position))) { |
285 return false; | 235 return false; |
286 } | 236 } |
287 } | 237 } |
288 return true; | 238 return true; |
289 } | 239 } |
290 | 240 |
291 void LocationRequest::OnPositionReported(const content::Geoposition& position) { | 241 void LocationRequest::OnPositionReported(const content::Geoposition& position) { |
292 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
293 for (UpdatePolicyVector::iterator it = update_policies_.begin(); | 242 for (UpdatePolicyVector::iterator it = update_policies_.begin(); |
294 it != update_policies_.end(); | 243 it != update_policies_.end(); |
295 ++it) { | 244 ++it) { |
296 (*it)->OnPositionReported(position); | 245 (*it)->OnPositionReported(position); |
297 } | 246 } |
298 } | 247 } |
299 | 248 |
300 LocationManager::LocationManager(content::BrowserContext* context) | 249 LocationManager::LocationManager(content::BrowserContext* context) |
301 : profile_(Profile::FromBrowserContext(context)) { | 250 : profile_(Profile::FromBrowserContext(context)) { |
302 registrar_.Add(this, | 251 registrar_.Add(this, |
303 chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED, | 252 chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED, |
304 content::Source<Profile>(profile_)); | 253 content::Source<Profile>(profile_)); |
305 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED, | 254 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED, |
306 content::Source<Profile>(profile_)); | 255 content::Source<Profile>(profile_)); |
307 } | 256 } |
308 | 257 |
309 void LocationManager::AddLocationRequest( | 258 void LocationManager::AddLocationRequest( |
310 const std::string& extension_id, | 259 const std::string& extension_id, |
311 const std::string& request_name, | 260 const std::string& request_name, |
312 const double* distance_update_threshold_meters, | 261 const double* distance_update_threshold_meters, |
313 const double* time_between_updates_ms) { | 262 const double* time_between_updates_ms) { |
314 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 263 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
315 // TODO(vadimt): Consider resuming requests after restarting the browser. | 264 // TODO(vadimt): Consider resuming requests after restarting the browser. |
316 | 265 |
317 // Override any old request with the same name. | 266 // Override any old request with the same name. |
318 RemoveLocationRequest(extension_id, request_name); | 267 RemoveLocationRequest(extension_id, request_name); |
319 | 268 |
320 LocationRequestPointer location_request = | 269 LocationRequestPointer location_request = |
321 new LocationRequest(AsWeakPtr(), | 270 new LocationRequest(this, |
322 extension_id, | 271 extension_id, |
323 request_name, | 272 request_name, |
324 distance_update_threshold_meters, | 273 distance_update_threshold_meters, |
325 time_between_updates_ms); | 274 time_between_updates_ms); |
326 location_request->Initialize(); | |
327 location_requests_.insert( | 275 location_requests_.insert( |
328 LocationRequestMap::value_type(extension_id, location_request)); | 276 LocationRequestMap::value_type(extension_id, location_request)); |
329 } | 277 } |
330 | 278 |
331 void LocationManager::RemoveLocationRequest(const std::string& extension_id, | 279 void LocationManager::RemoveLocationRequest(const std::string& extension_id, |
332 const std::string& name) { | 280 const std::string& name) { |
333 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 281 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
334 | 282 |
335 std::pair<LocationRequestMap::iterator, LocationRequestMap::iterator> | 283 std::pair<LocationRequestMap::iterator, LocationRequestMap::iterator> |
336 extension_range = location_requests_.equal_range(extension_id); | 284 extension_range = location_requests_.equal_range(extension_id); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
404 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 352 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
405 | 353 |
406 switch (type) { | 354 switch (type) { |
407 case chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED: { | 355 case chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED: { |
408 // Grants permission to use geolocation once an extension with "location" | 356 // Grants permission to use geolocation once an extension with "location" |
409 // permission is loaded. | 357 // permission is loaded. |
410 const Extension* extension = | 358 const Extension* extension = |
411 content::Details<const Extension>(details).ptr(); | 359 content::Details<const Extension>(details).ptr(); |
412 | 360 |
413 if (extension->HasAPIPermission(APIPermission::kLocation)) { | 361 if (extension->HasAPIPermission(APIPermission::kLocation)) { |
414 BrowserThread::PostTask( | 362 content::GeolocationProvider::GetInstance()-> |
415 BrowserThread::IO, | 363 UserDidOptIntoLocationServices(); |
416 FROM_HERE, | |
417 base::Bind(&LocationRequest::GrantPermission)); | |
418 } | 364 } |
419 break; | 365 break; |
420 } | 366 } |
421 case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: { | 367 case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: { |
422 // Delete all requests from the unloaded extension. | 368 // Delete all requests from the unloaded extension. |
423 const Extension* extension = | 369 const Extension* extension = |
424 content::Details<const UnloadedExtensionInfo>(details)->extension; | 370 content::Details<const UnloadedExtensionInfo>(details)->extension; |
425 location_requests_.erase(extension->id()); | 371 location_requests_.erase(extension->id()); |
426 break; | 372 break; |
427 } | 373 } |
(...skipping 11 matching lines...) Expand all Loading... |
439 LocationManager::GetFactoryInstance() { | 385 LocationManager::GetFactoryInstance() { |
440 return g_factory.Pointer(); | 386 return g_factory.Pointer(); |
441 } | 387 } |
442 | 388 |
443 // static | 389 // static |
444 LocationManager* LocationManager::Get(content::BrowserContext* context) { | 390 LocationManager* LocationManager::Get(content::BrowserContext* context) { |
445 return BrowserContextKeyedAPIFactory<LocationManager>::Get(context); | 391 return BrowserContextKeyedAPIFactory<LocationManager>::Get(context); |
446 } | 392 } |
447 | 393 |
448 } // namespace extensions | 394 } // namespace extensions |
OLD | NEW |