summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorrobliao@chromium.org <robliao@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-28 05:17:36 +0000
committerrobliao@chromium.org <robliao@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-06-28 05:17:36 +0000
commite5d16f19d3015e8c5e36c72b6012a611de08e404 (patch)
treef06dbbd224a98ea31dbdc80f4a508887f7ac2aaf /chrome/browser
parent1ce88e878e0462082a24f60c3e4a8bc9c694eb49 (diff)
downloadchromium_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')
-rw-r--r--chrome/browser/extensions/api/location/location_api.cc34
-rw-r--r--chrome/browser/extensions/api/location/location_manager.cc200
-rw-r--r--chrome/browser/extensions/api/location/location_manager.h7
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.