- From: Richard Maher <notifications@github.com>
- Date: Mon, 08 Feb 2016 16:41:32 -0800
- To: slightlyoff/ServiceWorker <ServiceWorker@noreply.github.com>
- Message-ID: <slightlyoff/ServiceWorker/issues/745/181645416@github.com>
I found this a useful layman's reference for hardware support of geofencing: - http://gpsworld.com/putting-the-ultra-low-power-in-geofence/ Explains a lot to me especially about power consumption, I maintain that the SW architecture, in combination with any Android support for position batching, that subsequently offloads geo-fence processing to a central server in order to determine alarm/other processing for ALL users, is a viable if not preferable alternative. Whether or not a wake-lock or cpu-lock is a retrograde step in power consumption, its implementation and availability pays homage to the user's right to self-determination. Likewise the user should be empowered to authorize GPS tracking while the phone is off. Surely a myopic cluster of GNSS ICs is a less than optimal solution for fleet management or social networking, and an instance of functionality-devolution gone too far? IMHO, other than for monitoring prisoners on probation, the current geofence solution is a textbook case of the tail wagging the dog. A Service Worker should be able to subscribe to a PositionManager optionally specifying min distance and/or seconds between updates to the position. A positionChanged event will be sufficient to re-instantiate a terminated SW. Below is how I throttle GeoLocation.watchPosition now: - 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}; }; --- Reply to this email directly or view it on GitHub: https://github.com/slightlyoff/ServiceWorker/issues/745#issuecomment-181645416
Received on Tuesday, 9 February 2016 00:42:13 UTC