[slightlyoff/ServiceWorker] Additional PositionOptions required for ServiceWorker background GeoLocation (#898)

[[[Sorry, I would have put this in https://github.com/w3c/geolocation-api/issues/new but I've been censored there]]]

Currently the functionality provided by the proposed options can be implemented by the Javascript developer in the foreground (see example below) but in order to minimize the number of ServiceWorker instances required these options must be homed and managed by the User-Agent. (And it would be useful in the foreground anyway.)

1) unsigned long timeDetent - This specifies the minimum number of nano-seconds that must elapse between GPS readings. If watchPosition() delivers new Position information before said time has elapsed then it must be suspended until a) timeDetent has elapsed or b) another fresher position update overwrites it. When any deferred Position update is delivered, its timestamp must reflect the current time.
2) unsigned long distanceDetent - This specifies the minimum number of metres that must have been traversed before the new Position details will be "interesting" enough to spin-up a ServiceWorker for.

As you can also see from the code below there are other suggestions for PositionOptions: -
3) unsigned long maxSilence - The maximum number of nanoseconds that can elapse between watchPosition(success) calls. This serves as a heartbeat/sanity-check.
4) unsigned long loiterDetent - Number of nanoseconds to elapse since the last Position update before the device is deemed to be at-rest/stationery. TravelManager subscription option?

Once again, this functionality becomes essential once the UA assumes the role of Location Throttle/Filter in order to protect battery life by limiting SW instances.

` Tier3Toolbox.prototype.LocationThrottle = 
  
  function(initHndlr, moveHndlr, standHndlr, errorHndlr, userOptions)
  {
   if(!navigator.geolocation) {
    throw new Error("Unsupported browser - No Geolocation support");
   }

   if (arguments.length < 4) {
    throw new Error("Insufficient call arguments");
   }
   
   if (typeof initHndlr  != "function" ||
    typeof moveHndlr  != "function" || 
    typeof standHndlr != "function" ||
    typeof errorHndlr != "function") {
    throw new Error("The Init, Move, Stand, and Error handler parameters must be functions");
   }
   
   var lastPos, trackerId, loiterTimer, deltaMetres,
    recalibrateTimer, lastOptions, lastDrop, replayTimer
    ;
   
   var MAXSILENCE    = 30;
   var watchCount    = 1;
   var acceptCount   = 1;
   var lastUpdate    = 0;
   
   var initHndlr     = initHndlr;
   var moveHndlr     = moveHndlr;
   var standHndlr    = standHndlr;
   var errorHndlr    = errorHndlr;
   
   var options, defMaxSilence, timeDetent, spaceDetent,
    loiterDetent, maxLocAge, accurate, maxSilence, lastOptions
    ;
       
   function moveReplay()
   {
    replayTimer = null;
    
    if ((lastDrop.timestamp > lastPos.timestamp)) {
     lastDrop.timestamp = Date.now();
     filterLocation(lastDrop);
    }      
   }
   
   function loiterLimit()
   {
    loiterTimer = null;
    standHndlr.call(null);
   }
   
   var recalibrate = 
    function()
    {
     if (window.console) console.log("recalibrating");
     
     recalibrateTimer = null;
     
     if (trackerId) navigator.geolocation.clearWatch(trackerId);
     
     getCurrent(initAcc);
    }
   
   var getCurrent = 
    function(success) 
    {
     navigator.geolocation.getCurrentPosition(success,locError,{
        enableHighAccuracy: false,
        maximumAge: Number.POSITIVE_INFINITY,
        timeout: 10000
       });        
    }
    
   var initLoc = 
    function(position) 
    {
     lastPos = position;  
     initHndlr.call(null, position); 
    }
   
   var initAcc = 
    function(position) 
    {
     watchCount++;
     
     trackerId = navigator.geolocation.watchPosition(filterLocation, locError, {
        enableHighAccuracy: accurate,
        maximumAge: maxLocAge
       });
       
     recalibrateTimer = setTimeout(recalibrate, maxSilence);     
    }
    
   var start =
    function(userOptions)
    {
     parseOptions(userOptions);
     
     trackerId = navigator.geolocation.watchPosition(filterLocation, locError, {
        enableHighAccuracy: accurate,
        maximumAge: maxLocAge,
        timeout: Number.POSITIVE_INFINITY
       });
     
     loiterTimer = setTimeout(loiterLimit, loiterDetent);
     recalibrateTimer = setTimeout(recalibrate, maxSilence);
    }
    
   var parseOptions =
    function(userOptions)
    {
     options       = userOptions || lastOptions; 
   
     defMaxSilence = (("maxSilence"  in options) ? options.maxSilence        : MAXSILENCE    );
     timeDetent    = (("minSilence"  in options) ? options.minSilence  :     0 ) * 1000;
     spaceDetent   = (("minProgress" in options) ? options.minProgress   :      0 );
     loiterDetent  = (("maxSnail"    in options) ? options.maxSnail          : defMaxSilence ) * 1000;
     maxLocAge     = (("maxAge"      in options) ? options.maxAge        :     0 );
     if (maxLocAge != Number.POSITIVE_INFINITY) maxLocAge *= 1000;
     accurate      = (("accurate"    in options) ? options.accurate      : true          );
     maxSilence    = defMaxSilence * 1000;
   
     lastOptions   = options;
    }
   
   var locError = 
    function(error) 
    {
     errorHndlr.call(null, error);
    }
    
   var filterLocation = 
    function(position) 
    {
     if (!lastPos) return;
     
     watchCount++;

     if (position.timestamp <= lastPos.timestamp)
      return;

     var currTime = Date.now();     
     var dropping = false;
      
     if (((position.timestamp - lastPos.timestamp) < timeDetent) ||
      ((currTime           - lastUpdate       ) < timeDetent)) {
      dropping = true;
     } else {       
      clearTimeout(recalibrateTimer);
      recalibrateTimer = setTimeout(recalibrate, maxSilence);
     }
      
     deltaMetres = Tier3Toolbox.calculateDistance(
         position.coords.latitude,
         position.coords.longitude,
         lastPos.coords.latitude,
         lastPos.coords.longitude)
         
     if (deltaMetres.toFixed() < spaceDetent) {
      return;
     }
     
     if (dropping) {
      lastDrop = position;
      clearTimeout(replayTimer);
      replayTimer = setTimeout(moveReplay, timeDetent);
      return;
     }
     
     acceptCount++;
     lastPos = position;
     lastUpdate = currTime;
     
     clearTimeout(loiterTimer);
     loiterTimer = setTimeout(loiterLimit, loiterDetent);
     
     moveHndlr.call(null, position, deltaMetres);   
    }
    
   var stop = 
    function()
    {
     if (trackerId) navigator.geolocation.clearWatch(trackerId);
     
     clearTimeout(recalibrateTimer);
     clearTimeout(loiterTimer);
     clearTimeout(replayTimer);
    }
    
   parseOptions(userOptions);          
   getCurrent(initLoc);
   
   return {start : start, stop : stop};
  };
`  


---
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/slightlyoff/ServiceWorker/issues/898

Received on Friday, 13 May 2016 06:31:08 UTC