1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file. 4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/extensions/api/location/location_manager.h" 6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <math.h> 8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <vector> 9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 10b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/bind.h" 11a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)#include "base/lazy_instance.h" 12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h" 13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/extensions/api/location.h" 147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "content/public/browser/browser_thread.h" 15b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "content/public/browser/geolocation_provider.h" 16b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "content/public/common/geoposition.h" 17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/browser/event_router.h" 186d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "extensions/browser/extension_registry.h" 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h" 20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h" 211e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "extensions/common/permissions/permission_set.h" 2246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "extensions/common/permissions/permissions_data.h" 23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)using content::BrowserThread; 257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles) 26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// TODO(vadimt): Add tests. 27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace extensions { 28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace location = api::location; 30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace updatepolicy { 32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Base class for all update policies for sending a location. 34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass UpdatePolicy : public base::RefCounted<UpdatePolicy> { 35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public: 36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch explicit UpdatePolicy() {} 37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // True if the caller should send an update based off of this policy. 39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual bool ShouldSendUpdate(const content::Geoposition&) const = 0; 40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Updates any policy state on reporting a position. 42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual void OnPositionReported(const content::Geoposition&) = 0; 43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch protected: 45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual ~UpdatePolicy() {} 46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private: 48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch friend class base::RefCounted<UpdatePolicy>; 49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DISALLOW_COPY_AND_ASSIGN(UpdatePolicy); 50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}; 51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// A policy that controls sending an update below a distance threshold. 53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass DistanceBasedUpdatePolicy : public UpdatePolicy { 54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public: 55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch explicit DistanceBasedUpdatePolicy(double distance_update_threshold_meters) : 56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch distance_update_threshold_meters_(distance_update_threshold_meters) 57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch {} 58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // UpdatePolicy Implementation 60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual bool ShouldSendUpdate(const content::Geoposition& position) const 61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch OVERRIDE { 62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return !last_updated_position_.Validate() || 63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch Distance(position.latitude, 64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch position.longitude, 65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch last_updated_position_.latitude, 66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch last_updated_position_.longitude) > 67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch distance_update_threshold_meters_; 68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual void OnPositionReported(const content::Geoposition& position) 71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch OVERRIDE { 72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch last_updated_position_ = position; 73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 74eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private: 76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual ~DistanceBasedUpdatePolicy() {} 77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Calculates the distance between two latitude and longitude points. 79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch static double Distance(const double latitude1, 80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const double longitude1, 81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const double latitude2, 82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const double longitude2) { 83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // The earth has a radius of about 6371 km. 84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const double kRadius = 6371000; 85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const double kPi = 3.14159265358979323846; 86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const double kDegreesToRadians = kPi / 180.0; 87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Conversions 89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const double latitude1Rad = latitude1 * kDegreesToRadians; 90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const double latitude2Rad = latitude2 * kDegreesToRadians; 91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const double latitudeDistRad = latitude2Rad - latitude1Rad; 92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const double longitudeDistRad = (longitude2 - longitude1) * 93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch kDegreesToRadians; 94eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 95eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // The Haversine Formula determines the great circle distance 96eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // between two points on a sphere. 97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const double chordLengthSquared = pow(sin(latitudeDistRad / 2.0), 2) + 98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch (pow(sin(longitudeDistRad / 2.0), 2) * 99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch cos(latitude1Rad) * 100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch cos(latitude2Rad)); 101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const double angularDistance = 2.0 * atan2(sqrt(chordLengthSquared), 102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch sqrt(1.0 - chordLengthSquared)); 103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return kRadius * angularDistance; 104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const double distance_update_threshold_meters_; 107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch content::Geoposition last_updated_position_; 108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DISALLOW_COPY_AND_ASSIGN(DistanceBasedUpdatePolicy); 110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}; 111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// A policy that controls sending an update above a time threshold. 113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass TimeBasedUpdatePolicy : public UpdatePolicy { 114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch public: 115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch explicit TimeBasedUpdatePolicy(double time_between_updates_ms) : 116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch time_between_updates_ms_(time_between_updates_ms) 117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch {} 118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // UpdatePolicy Implementation 120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual bool ShouldSendUpdate(const content::Geoposition&) const OVERRIDE { 121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return (base::Time::Now() - last_update_time_).InMilliseconds() > 122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch time_between_updates_ms_; 123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual void OnPositionReported(const content::Geoposition&) OVERRIDE { 126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch last_update_time_ = base::Time::Now(); 127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private: 130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch virtual ~TimeBasedUpdatePolicy() {} 131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::Time last_update_time_; 133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const double time_between_updates_ms_; 134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DISALLOW_COPY_AND_ASSIGN(TimeBasedUpdatePolicy); 136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}; 137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} // namespace updatepolicy 139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 140c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Request created by chrome.location.watchLocation() call. 141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)class LocationRequest : public base::RefCounted<LocationRequest> { 142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public: 143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) LocationRequest( 144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) LocationManager* location_manager, 145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& extension_id, 146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string& request_name, 147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const double* distance_update_threshold_meters, 148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const double* time_between_updates_ms); 149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 150c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& request_name() const { return request_name_; } 151c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private: 153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) friend class base::RefCounted<LocationRequest>; 154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) ~LocationRequest(); 155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 156b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) void OnLocationUpdate(const content::Geoposition& position); 157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Determines if all policies say to send a position update. 159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // If there are no policies, this always says yes. 160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool ShouldSendUpdate(const content::Geoposition& position); 161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Updates the policies on sending a position update. 163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch void OnPositionReported(const content::Geoposition& position); 164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Request name. 166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string request_name_; 167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Id of the owner extension. 169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string extension_id_; 170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 171c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Owning location manager. 172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) LocationManager* location_manager_; 173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Holds Update Policies. 175eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch typedef std::vector<scoped_refptr<updatepolicy::UpdatePolicy> > 176eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch UpdatePolicyVector; 177eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch UpdatePolicyVector update_policies_; 178eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_ptr<content::GeolocationProvider::Subscription> 180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) geolocation_subscription_; 181b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(LocationRequest); 183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)LocationRequest::LocationRequest( 186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) LocationManager* location_manager, 187c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& extension_id, 188eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string& request_name, 189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const double* distance_update_threshold_meters, 190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const double* time_between_updates_ms) 191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : request_name_(request_name), 192c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) extension_id_(extension_id), 193c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) location_manager_(location_manager) { 194c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // TODO(vadimt): use request_info. 195eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (time_between_updates_ms) { 196eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch update_policies_.push_back( 197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch new updatepolicy::TimeBasedUpdatePolicy( 198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch *time_between_updates_ms)); 199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (distance_update_threshold_meters) { 202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch update_policies_.push_back( 203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch new updatepolicy::DistanceBasedUpdatePolicy( 204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch *distance_update_threshold_meters)); 205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // TODO(vadimt): This can get a location cached by GeolocationProvider, 208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // contrary to the API definition which says that creating a location watch 209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // will get new location. 210cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) geolocation_subscription_ = content::GeolocationProvider::GetInstance()-> 211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) AddLocationUpdateCallback( 212cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Bind(&LocationRequest::OnLocationUpdate, 213cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::Unretained(this)), 214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) true); 215cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 216cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 217cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)LocationRequest::~LocationRequest() { 218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 219c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 220c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void LocationRequest::OnLocationUpdate(const content::Geoposition& position) { 221eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (ShouldSendUpdate(position)) { 222eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch OnPositionReported(position); 223cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) location_manager_->SendLocationUpdate( 224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) extension_id_, request_name_, position); 225eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 226eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 228eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool LocationRequest::ShouldSendUpdate(const content::Geoposition& position) { 229eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (UpdatePolicyVector::iterator it = update_policies_.begin(); 230eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch it != update_policies_.end(); 231eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ++it) { 232eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!((*it)->ShouldSendUpdate(position))) { 233eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return false; 234eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 235eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 236eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return true; 237eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 238eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 239eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid LocationRequest::OnPositionReported(const content::Geoposition& position) { 240eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch for (UpdatePolicyVector::iterator it = update_policies_.begin(); 241eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch it != update_policies_.end(); 242eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch ++it) { 243eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch (*it)->OnPositionReported(position); 244eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 245c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 246c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 247a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)LocationManager::LocationManager(content::BrowserContext* context) 2486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) : browser_context_(context), extension_registry_observer_(this) { 2496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); 250c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 251c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 252eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid LocationManager::AddLocationRequest( 253eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string& extension_id, 254eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::string& request_name, 255eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const double* distance_update_threshold_meters, 256eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const double* time_between_updates_ms) { 257effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(BrowserThread::UI); 258c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // TODO(vadimt): Consider resuming requests after restarting the browser. 259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 260c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Override any old request with the same name. 26190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) RemoveLocationRequest(extension_id, request_name); 262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 263eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch LocationRequestPointer location_request = 264cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) new LocationRequest(this, 265eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch extension_id, 266eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch request_name, 267eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch distance_update_threshold_meters, 268eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch time_between_updates_ms); 26990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) location_requests_.insert( 27090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) LocationRequestMap::value_type(extension_id, location_request)); 271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void LocationManager::RemoveLocationRequest(const std::string& extension_id, 274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& name) { 275effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(BrowserThread::UI); 276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 27790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::pair<LocationRequestMap::iterator, LocationRequestMap::iterator> 27890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) extension_range = location_requests_.equal_range(extension_id); 279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 28090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) for (LocationRequestMap::iterator it = extension_range.first; 28190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) it != extension_range.second; 28290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ++it) { 28390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (it->second->request_name() == name) { 28490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) location_requests_.erase(it); 28590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return; 28690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 28790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 288c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 289c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 290c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)LocationManager::~LocationManager() { 291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 292c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void LocationManager::GeopositionToApiCoordinates( 294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const content::Geoposition& position, 295c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) location::Coordinates* coordinates) { 296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) coordinates->latitude = position.latitude; 297c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) coordinates->longitude = position.longitude; 298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (position.altitude > -10000.) 299c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) coordinates->altitude.reset(new double(position.altitude)); 300c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) coordinates->accuracy = position.accuracy; 301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (position.altitude_accuracy >= 0.) { 302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) coordinates->altitude_accuracy.reset( 303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) new double(position.altitude_accuracy)); 304c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 305c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (position.heading >= 0. && position.heading <= 360.) 306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) coordinates->heading.reset(new double(position.heading)); 307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (position.speed >= 0.) 308c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) coordinates->speed.reset(new double(position.speed)); 309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void LocationManager::SendLocationUpdate( 312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& extension_id, 313c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const std::string& request_name, 314c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const content::Geoposition& position) { 315effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(BrowserThread::UI); 316c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch scoped_ptr<base::ListValue> args(new base::ListValue()); 318c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) std::string event_name; 319c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 320c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (position.Validate() && 321c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) position.error_code == content::Geoposition::ERROR_CODE_NONE) { 322c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Set data for onLocationUpdate event. 323c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) location::Location location; 324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) location.name = request_name; 325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) GeopositionToApiCoordinates(position, &location.coords); 326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) location.timestamp = position.timestamp.ToJsTime(); 327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) args->Append(location.ToValue().release()); 3293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) event_name = location::OnLocationUpdate::kEventName; 330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Set data for onLocationError event. 332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // TODO(vadimt): Set name. 333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) args->AppendString(position.error_message); 3343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) event_name = location::OnLocationError::kEventName; 335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_ptr<Event> event(new Event(event_name, args.Pass())); 338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 3396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) EventRouter::Get(browser_context_) 3400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch ->DispatchEventToExtension(extension_id, event.Pass()); 341c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 3436d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void LocationManager::OnExtensionLoaded( 3446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) content::BrowserContext* browser_context, 3456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const Extension* extension) { 3466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // Grants permission to use geolocation once an extension with "location" 3476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // permission is loaded. 3486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if (extension->permissions_data()->HasAPIPermission( 3496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) APIPermission::kLocation)) { 3506d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) content::GeolocationProvider::GetInstance() 3516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) ->UserDidOptIntoLocationServices(); 352c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 354c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 3556d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)void LocationManager::OnExtensionUnloaded( 3566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) content::BrowserContext* browser_context, 3576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) const Extension* extension, 3586d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) UnloadedExtensionInfo::Reason reason) { 3596d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) // Delete all requests from the unloaded extension. 3606d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) location_requests_.erase(extension->id()); 3616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)} 3626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 363a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)static base::LazyInstance<BrowserContextKeyedAPIFactory<LocationManager> > 364a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) g_factory = LAZY_INSTANCE_INITIALIZER; 365a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 366a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)// static 367a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)BrowserContextKeyedAPIFactory<LocationManager>* 368a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)LocationManager::GetFactoryInstance() { 3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return g_factory.Pointer(); 370a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)} 371a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 3726d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)// static 373a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)LocationManager* LocationManager::Get(content::BrowserContext* context) { 374a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) return BrowserContextKeyedAPIFactory<LocationManager>::Get(context); 375a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)} 376a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} // namespace extensions 378