You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by fi...@apache.org on 2012/05/07 22:52:06 UTC

[4/8] js commit: start of geolocation rewrite to conform with Geolocation W3C API spec.

start of geolocation rewrite to conform with Geolocation W3C API spec.


Project: http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/commit/95d979d6
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/tree/95d979d6
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/diff/95d979d6

Branch: refs/heads/master
Commit: 95d979d69e306517c5487f431b0140da0886806f
Parents: 34f5fec
Author: Fil Maj <ma...@gmail.com>
Authored: Thu Mar 22 15:26:08 2012 -0700
Committer: Fil Maj <ma...@gmail.com>
Committed: Mon May 7 13:51:05 2012 -0700

----------------------------------------------------------------------
 lib/common/plugin/Position.js    |    8 +++-
 lib/common/plugin/geolocation.js |   77 ++++++++++++++++++++++++++++----
 test/test.geolocation.js         |   40 +++++++++++++----
 3 files changed, 104 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/95d979d6/lib/common/plugin/Position.js
----------------------------------------------------------------------
diff --git a/lib/common/plugin/Position.js b/lib/common/plugin/Position.js
index 33c5be9..deb7c49 100644
--- a/lib/common/plugin/Position.js
+++ b/lib/common/plugin/Position.js
@@ -1,8 +1,12 @@
 var Coordinates = require('cordova/plugin/Coordinates');
 
 var Position = function(coords, timestamp) {
-    this.coords = new Coordinates(coords.latitude, coords.longitude, coords.altitude, coords.accuracy, coords.heading, coords.velocity, coords.altitudeAccuracy);
+    if (coords) {
+        this.coords = new Coordinates(coords.latitude, coords.longitude, coords.altitude, coords.accuracy, coords.heading, coords.velocity, coords.altitudeAccuracy);
+    } else {
+        this.coords = new Coordinates();
+    }
     this.timestamp = (timestamp !== undefined) ? timestamp : new Date().getTime();
 };
 
-module.exports = Position;
\ No newline at end of file
+module.exports = Position;

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/95d979d6/lib/common/plugin/geolocation.js
----------------------------------------------------------------------
diff --git a/lib/common/plugin/geolocation.js b/lib/common/plugin/geolocation.js
index 1b86f02..443fb61 100644
--- a/lib/common/plugin/geolocation.js
+++ b/lib/common/plugin/geolocation.js
@@ -8,20 +8,24 @@ var timers = {};   // list of timers in use
 // Returns default params, overrides if provided with values
 function parseParameters(options) {
     var opt = {
-        maximumAge: 10000,
+        maximumAge: 0,
         enableHighAccuracy: false,
-        timeout: 10000
+        timeout: Infinity
     };
 
     if (options) {
-        if (options.maximumAge !== undefined) {
+        if (options.maximumAge !== undefined && !isNaN(options.maximumAge) && options.maximumAge > 0) {
             opt.maximumAge = options.maximumAge;
         }
         if (options.enableHighAccuracy !== undefined) {
             opt.enableHighAccuracy = options.enableHighAccuracy;
         }
-        if (options.timeout !== undefined) {
-            opt.timeout = options.timeout;
+        if (options.timeout !== undefined && !isNaN(options.timeout)) {
+            if (options.timeout < 0) {
+                opt.timeout = 0;
+            } else {
+                opt.timeout = options.timeout;
+            }
         }
     }
 
@@ -29,6 +33,7 @@ function parseParameters(options) {
 }
 
 var geolocation = {
+    lastPosition:null, // reference to last known (cached) position returned
     /**
    * Asynchronously aquires the current position.
    *
@@ -37,10 +42,24 @@ var geolocation = {
    * @param {PositionOptions} options     The options for getting the position data. (OPTIONAL)
    */
     getCurrentPosition:function(successCallback, errorCallback, options) {
+        if (arguments.length === 0) {
+            throw new Error("getCurrentPosition must be called with at least one argument.");
+        }
         options = parseParameters(options);
 
+        // Timer var that will fire an error callback if no position is retrieved from native
+        // before the "timeout" param provided expires
+        var timeoutTimer = null;
+
         var win = function(p) {
-            successCallback(new Position(
+            clearTimeout(timeoutTimer);
+            if (!timeoutTimer) {
+                // Timeout already happened, or native fired error callback for
+                // this geo request.
+                // Don't continue with success callback.
+                return;
+            }
+            var pos = new Position(
                 {
                     latitude:p.latitude,
                     longitude:p.longitude,
@@ -51,13 +70,51 @@ var geolocation = {
                     altitudeAccuracy:p.altitudeAccuracy
                 },
                 p.timestamp || new Date()
-            ));
+            );
+            geolocation.lastPosition = pos;
+            successCallback(pos);
         };
         var fail = function(e) {
-            errorCallback(new PositionError(e.code, e.message));
+            clearTimeout(timeoutTimer);
+            timeoutTimer = null;
+            var err = new PositionError(e.code, e.message);
+            if (errorCallback) {
+                errorCallback(err);
+            }
         };
 
-        exec(win, fail, "Geolocation", "getLocation", [options.enableHighAccuracy, options.timeout, options.maximumAge]);
+        // Check our cached position, if its timestamp difference with current time is less than the timeout, then just
+        // fire the success callback with the cached position.
+        if (geolocation.lastPosition && options.timeout && ((new Date()).getTime() - geolocation.lastPosition.timestamp.getTime() <= options.timeout)) {
+            successCallback(cachedPosition);
+        // If the cached position check failed and the timeout was set to 0, error out with a TIMEOUT error object.
+        } else if (options.timeout === 0) {
+            fail({
+                code:PositionError.TIMEOUT,
+                message:"timeout value in PositionOptions set to 0 and no cached Position object available, or cached Position object's age exceed's provided PositionOptions' maximumAge parameter."
+            });
+        // Otherwise we have to call into native to retrieve a position.
+        } else {
+            if (options.timeout !== Infinity) {
+                // If the timeout value was not set to Infinity (default), then
+                // set up a timeout function that will fire the error callback 
+                // if no successful position was retrieved before timeout expired.
+                timeoutTimer = setTimeout(function() {
+                    clearTimeout(timeoutTimer);
+                    timeoutTimer = null;
+                    fail({
+                        code:PositionError.TIMEOUT,
+                        message:"Position retrieval timed out."
+                    });
+                }, options.timeout);
+            } else {
+                // This is here so the check in the win function doesn't mess stuff up
+                // may seem weird but this guarantees timeoutTimer is 
+                // always truthy before we call into native
+                timeoutTimer = true; 
+            }
+            exec(win, fail, "Geolocation", "getLocation", [options.enableHighAccuracy, options.timeout, options.maximumAge]); 
+        }
     },
     /**
      * Asynchronously watches the geolocation for changes to geolocation.  When a change occurs,
@@ -91,4 +148,4 @@ var geolocation = {
     }
 };
 
-module.exports = geolocation;
\ No newline at end of file
+module.exports = geolocation;

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/95d979d6/test/test.geolocation.js
----------------------------------------------------------------------
diff --git a/test/test.geolocation.js b/test/test.geolocation.js
index a24059c..e5fe4f2 100644
--- a/test/test.geolocation.js
+++ b/test/test.geolocation.js
@@ -1,32 +1,54 @@
 describe("geolocation", function () {
     var geo = require('cordova/plugin/geolocation'),
+        Position = require('cordova/plugin/Position'),
+        PositionError = require('cordova/plugin/PositionError'),
         s, e;
         exec = require('cordova/exec');
 
     beforeEach(function () {
         s = jasmine.createSpy("success");
         e = jasmine.createSpy("error");
+        exec.reset();
     });
 
     describe("when getting the current position", function () {
-        it("uses the default values", function () {
+        beforeEach(function() {
+            geo.lastPosition = null; // reset the cached position
+        });
+
+        it("uses default PositionOptions if none are specified", function () {
             geo.getCurrentPosition(s, e);
-            expect(exec).toHaveBeenCalledWith(jasmine.any(Function), jasmine.any(Function), "Geolocation", "getLocation", [false, 10000, 10000]);
+            expect(exec).toHaveBeenCalledWith(jasmine.any(Function), jasmine.any(Function), "Geolocation", "getLocation", [false, Infinity, 0]);
         });
 
-        it("uses the maximumAge option", function () {
+        it("uses the maximumAge option if specified", function () {
             geo.getCurrentPosition(s, e, {maximumAge: 10});
-            expect(exec).toHaveBeenCalledWith(jasmine.any(Function), jasmine.any(Function), "Geolocation", "getLocation", [false, 10000, 10]);
+            expect(exec).toHaveBeenCalledWith(jasmine.any(Function), jasmine.any(Function), "Geolocation", "getLocation", [false, Infinity, 10]);
         });
 
-        it("uses the enableHighAccuracy option", function () {
+        it("uses the enableHighAccuracy option if specified", function () {
             geo.getCurrentPosition(s, e, {enableHighAccuracy: true, maximumAge: 100});
-            expect(exec).toHaveBeenCalledWith(jasmine.any(Function), jasmine.any(Function), "Geolocation", "getLocation", [true, 10000, 100]);
+            expect(exec).toHaveBeenCalledWith(jasmine.any(Function), jasmine.any(Function), "Geolocation", "getLocation", [true, Infinity, 100]);
         });
 
-        it("uses the timeout option", function () {
+        it("uses the timeout option if specified and positive", function () {
             geo.getCurrentPosition(s, e, {timeout: 1000});
-            expect(exec).toHaveBeenCalledWith(jasmine.any(Function), jasmine.any(Function), "Geolocation", "getLocation", [false, 1000, 10000]);
+            expect(exec).toHaveBeenCalledWith(jasmine.any(Function), jasmine.any(Function), "Geolocation", "getLocation", [false, 1000, 0]);
+        });
+        it("uses a timeout value of 0 if specified and negative, which should call the error callback immediately (since we have no cached position)", function () {
+            geo.getCurrentPosition(s, e, {timeout: -1000});
+            expect(e).toHaveBeenCalledWith({
+                code:PositionError.TIMEOUT,
+                message:"timeout value in PositionOptions set to 0 and no cached Position object available, or cached Position object's age exceed's provided PositionOptions' maximumAge parameter."
+            });
+        });
+        it("can be used with one, two or three arguments", function() {
+            expect(function() { geo.getCurrentPosition(s); }).not.toThrow();
+            expect(function() { geo.getCurrentPosition(s,e); }).not.toThrow();
+            expect(function() { geo.getCurrentPosition(s,e,{}); }).not.toThrow();
+        });
+        it("should throw an exception if used with no arguments", function() {
+            expect(function() { geo.getCurrentPosition();}).toThrow("getCurrentPosition must be called with at least one argument.");
         });
     });
 
@@ -46,7 +68,7 @@ describe("geolocation", function () {
 
         it("sets an interval for the default timeout", function () {
             geo.watchPosition(s, e);
-            expect(window.setInterval).toHaveBeenCalledWith(jasmine.any(Function), 10000);
+            expect(window.setInterval).toHaveBeenCalledWith(jasmine.any(Function), Infinity);
         });
 
         it("sets an interval for the provided timeout", function () {