diff options
author | robliao@chromium.org <robliao@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-28 05:17:36 +0000 |
---|---|---|
committer | robliao@chromium.org <robliao@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-28 05:17:36 +0000 |
commit | e5d16f19d3015e8c5e36c72b6012a611de08e404 (patch) | |
tree | f06dbbd224a98ea31dbdc80f4a508887f7ac2aaf /chrome/browser | |
parent | 1ce88e878e0462082a24f60c3e4a8bc9c694eb49 (diff) | |
download | chromium_src-e5d16f19d3015e8c5e36c72b6012a611de08e404.zip chromium_src-e5d16f19d3015e8c5e36c72b6012a611de08e404.tar.gz chromium_src-e5d16f19d3015e8c5e36c72b6012a611de08e404.tar.bz2 |
Implement chrome.location.watchLocation Request Info minDistanceInMeters and minTimeInMilliseconds
This change pipes down minDistanceInMeters and minTimeInMilliseconds
from JS land to native code.
Each property creates a policy that indicates if a location update
should be sent to the client.
BUG=230943
Review URL: https://chromiumcodereview.appspot.com/17467004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@209097 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
3 files changed, 222 insertions, 19 deletions
diff --git a/chrome/browser/extensions/api/location/location_api.cc b/chrome/browser/extensions/api/location/location_api.cc index d547879..41a9917 100644 --- a/chrome/browser/extensions/api/location/location_api.cc +++ b/chrome/browser/extensions/api/location/location_api.cc @@ -6,6 +6,7 @@ #include "chrome/browser/extensions/api/location/location_manager.h" #include "chrome/common/extensions/api/location.h" +#include "extensions/common/error_utils.h" // TODO(vadimt): add tests. @@ -15,14 +16,43 @@ namespace ClearWatch = location::ClearWatch; namespace extensions { +const char kMustBePositive[] = "'*' must be 0 or greater."; +const char kMinDistanceInMeters[] = "minDistanceInMeters"; +const char kMinTimeInMilliseconds[] = "minTimeInMilliseconds"; + +bool IsNegative(double* value) { + return value && *value < 0.0; +} + bool LocationWatchLocationFunction::RunImpl() { scoped_ptr<WatchLocation::Params> params( WatchLocation::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get()); - // TODO(vadimt): validate and use params->request_info. + double* min_distance_in_meters = + params->request_info.min_distance_in_meters.get(); + if (IsNegative(min_distance_in_meters)) { + error_ = ErrorUtils::FormatErrorMessage( + kMustBePositive, + kMinDistanceInMeters); + return false; + } + + double* min_time_in_milliseconds = + params->request_info.min_time_in_milliseconds.get(); + if (IsNegative(min_time_in_milliseconds)) { + error_ = ErrorUtils::FormatErrorMessage( + kMustBePositive, + kMinTimeInMilliseconds); + return false; + } + + // TODO(vadimt): validate and use params->request_info.maximumAge LocationManager::Get(profile())->AddLocationRequest( - extension_id(), params->name); + extension_id(), + params->name, + min_distance_in_meters, + min_time_in_milliseconds); return true; } diff --git a/chrome/browser/extensions/api/location/location_manager.cc b/chrome/browser/extensions/api/location/location_manager.cc index fe37965..77da5a0 100644 --- a/chrome/browser/extensions/api/location/location_manager.cc +++ b/chrome/browser/extensions/api/location/location_manager.cc @@ -4,8 +4,12 @@ #include "chrome/browser/extensions/api/location/location_manager.h" +#include <math.h> +#include <vector> + #include "base/bind.h" #include "base/lazy_instance.h" +#include "base/time.h" #include "chrome/browser/extensions/event_router.h" #include "chrome/browser/extensions/extension_system.h" #include "chrome/common/chrome_notification_types.h" @@ -25,6 +29,115 @@ namespace extensions { namespace location = api::location; +namespace updatepolicy { + +// Base class for all update policies for sending a location. +class UpdatePolicy : public base::RefCounted<UpdatePolicy> { + public: + explicit UpdatePolicy() {} + + // True if the caller should send an update based off of this policy. + virtual bool ShouldSendUpdate(const content::Geoposition&) const = 0; + + // Updates any policy state on reporting a position. + virtual void OnPositionReported(const content::Geoposition&) = 0; + + protected: + virtual ~UpdatePolicy() {} + + private: + friend class base::RefCounted<UpdatePolicy>; + DISALLOW_COPY_AND_ASSIGN(UpdatePolicy); +}; + +// A policy that controls sending an update below a distance threshold. +class DistanceBasedUpdatePolicy : public UpdatePolicy { + public: + explicit DistanceBasedUpdatePolicy(double distance_update_threshold_meters) : + distance_update_threshold_meters_(distance_update_threshold_meters) + {} + + // UpdatePolicy Implementation + virtual bool ShouldSendUpdate(const content::Geoposition& position) const + OVERRIDE { + return !last_updated_position_.Validate() || + Distance(position.latitude, + position.longitude, + last_updated_position_.latitude, + last_updated_position_.longitude) > + distance_update_threshold_meters_; + } + + virtual void OnPositionReported(const content::Geoposition& position) + OVERRIDE { + last_updated_position_ = position; + } + + private: + virtual ~DistanceBasedUpdatePolicy() {} + + // Calculates the distance between two latitude and longitude points. + static double Distance(const double latitude1, + const double longitude1, + const double latitude2, + const double longitude2) { + // The earth has a radius of about 6371 km. + const double kRadius = 6371000; + const double kPi = 3.14159265358979323846; + const double kDegreesToRadians = kPi / 180.0; + + // Conversions + const double latitude1Rad = latitude1 * kDegreesToRadians; + const double latitude2Rad = latitude2 * kDegreesToRadians; + const double latitudeDistRad = latitude2Rad - latitude1Rad; + const double longitudeDistRad = (longitude2 - longitude1) * + kDegreesToRadians; + + // The Haversine Formula determines the great circle distance + // between two points on a sphere. + const double chordLengthSquared = pow(sin(latitudeDistRad / 2.0), 2) + + (pow(sin(longitudeDistRad / 2.0), 2) * + cos(latitude1Rad) * + cos(latitude2Rad)); + const double angularDistance = 2.0 * atan2(sqrt(chordLengthSquared), + sqrt(1.0 - chordLengthSquared)); + return kRadius * angularDistance; + } + + const double distance_update_threshold_meters_; + content::Geoposition last_updated_position_; + + DISALLOW_COPY_AND_ASSIGN(DistanceBasedUpdatePolicy); +}; + +// A policy that controls sending an update above a time threshold. +class TimeBasedUpdatePolicy : public UpdatePolicy { + public: + explicit TimeBasedUpdatePolicy(double time_between_updates_ms) : + time_between_updates_ms_(time_between_updates_ms) + {} + + // UpdatePolicy Implementation + virtual bool ShouldSendUpdate(const content::Geoposition&) const OVERRIDE { + return (base::Time::Now() - last_update_time_).InMilliseconds() > + time_between_updates_ms_; + } + + virtual void OnPositionReported(const content::Geoposition&) OVERRIDE { + last_update_time_ = base::Time::Now(); + } + + private: + virtual ~TimeBasedUpdatePolicy() {} + + base::Time last_update_time_; + const double time_between_updates_ms_; + + DISALLOW_COPY_AND_ASSIGN(TimeBasedUpdatePolicy); +}; + +} // namespace updatepolicy + // Request created by chrome.location.watchLocation() call. // Lives in the IO thread, except for the constructor. class LocationRequest @@ -34,7 +147,9 @@ class LocationRequest LocationRequest( const base::WeakPtr<LocationManager>& location_manager, const std::string& extension_id, - const std::string& request_name); + const std::string& request_name, + const double* distance_update_threshold_meters, + const double* time_between_updates_ms); // Finishes the necessary setup for this object. // Call this method immediately after taking a strong reference @@ -61,6 +176,13 @@ class LocationRequest void OnLocationUpdate(const content::Geoposition& position); + // Determines if all policies say to send a position update. + // If there are no policies, this always says yes. + bool ShouldSendUpdate(const content::Geoposition& position); + + // Updates the policies on sending a position update. + void OnPositionReported(const content::Geoposition& position); + // Request name. const std::string request_name_; @@ -70,6 +192,11 @@ class LocationRequest // Owning location manager. const base::WeakPtr<LocationManager> location_manager_; + // Holds Update Policies. + typedef std::vector<scoped_refptr<updatepolicy::UpdatePolicy> > + UpdatePolicyVector; + UpdatePolicyVector update_policies_; + content::GeolocationProvider::LocationUpdateCallback callback_; DISALLOW_COPY_AND_ASSIGN(LocationRequest); @@ -78,12 +205,26 @@ class LocationRequest LocationRequest::LocationRequest( const base::WeakPtr<LocationManager>& location_manager, const std::string& extension_id, - const std::string& request_name) + const std::string& request_name, + const double* distance_update_threshold_meters, + const double* time_between_updates_ms) : request_name_(request_name), extension_id_(extension_id), location_manager_(location_manager) { // TODO(vadimt): use request_info. DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + if (time_between_updates_ms) { + update_policies_.push_back( + new updatepolicy::TimeBasedUpdatePolicy( + *time_between_updates_ms)); + } + + if (distance_update_threshold_meters) { + update_policies_.push_back( + new updatepolicy::DistanceBasedUpdatePolicy( + *distance_update_threshold_meters)); + } } void LocationRequest::Initialize() { @@ -121,15 +262,38 @@ void LocationRequest::AddObserverOnIOThread() { void LocationRequest::OnLocationUpdate(const content::Geoposition& position) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + if (ShouldSendUpdate(position)) { + OnPositionReported(position); + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind(&LocationManager::SendLocationUpdate, + location_manager_, + extension_id_, + request_name_, + position)); + } +} - BrowserThread::PostTask( - BrowserThread::UI, - FROM_HERE, - base::Bind(&LocationManager::SendLocationUpdate, - location_manager_, - extension_id_, - request_name_, - position)); +bool LocationRequest::ShouldSendUpdate(const content::Geoposition& position) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + for (UpdatePolicyVector::iterator it = update_policies_.begin(); + it != update_policies_.end(); + ++it) { + if (!((*it)->ShouldSendUpdate(position))) { + return false; + } + } + return true; +} + +void LocationRequest::OnPositionReported(const content::Geoposition& position) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + for (UpdatePolicyVector::iterator it = update_policies_.begin(); + it != update_policies_.end(); + ++it) { + (*it)->OnPositionReported(position); + } } LocationManager::LocationManager(Profile* profile) @@ -140,17 +304,23 @@ LocationManager::LocationManager(Profile* profile) content::Source<Profile>(profile_)); } -void LocationManager::AddLocationRequest(const std::string& extension_id, - const std::string& request_name) { +void LocationManager::AddLocationRequest( + const std::string& extension_id, + const std::string& request_name, + const double* distance_update_threshold_meters, + const double* time_between_updates_ms) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); // TODO(vadimt): Consider resuming requests after restarting the browser. // Override any old request with the same name. RemoveLocationRequest(extension_id, request_name); - LocationRequestPointer location_request = new LocationRequest(AsWeakPtr(), - extension_id, - request_name); + LocationRequestPointer location_request = + new LocationRequest(AsWeakPtr(), + extension_id, + request_name, + distance_update_threshold_meters, + time_between_updates_ms); location_request->Initialize(); location_requests_.insert( LocationRequestMap::value_type(extension_id, location_request)); diff --git a/chrome/browser/extensions/api/location/location_manager.h b/chrome/browser/extensions/api/location/location_manager.h index 5b24685..6983b17 100644 --- a/chrome/browser/extensions/api/location/location_manager.h +++ b/chrome/browser/extensions/api/location/location_manager.h @@ -43,8 +43,11 @@ class LocationManager // Adds location request for the given extension, and starts the location // tracking. - void AddLocationRequest(const std::string& extension_id, - const std::string& request_name); + void AddLocationRequest( + const std::string& extension_id, + const std::string& request_name, + const double* distance_update_threshold_meters, + const double* time_between_updates_ms); // Cancels and removes the request with the given |name| for the given // extension. |