From 5206b0dedb0a004a1113c7cb713e448a1dc20b91 Mon Sep 17 00:00:00 2001 From: kumo01GitHub Date: Sun, 1 Dec 2024 00:27:09 +0900 Subject: [PATCH 1/3] fix: #285 --- www/android/geolocation.js | 45 +++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/www/android/geolocation.js b/www/android/geolocation.js index 76192edd..eec58fd2 100644 --- a/www/android/geolocation.js +++ b/www/android/geolocation.js @@ -27,8 +27,27 @@ const PositionError = require('./PositionError'); // So we use additional map and own ids to return watch id synchronously. const pluginToNativeWatchMap = {}; +const timers = {}; // list of timers in use + +// Returns a timeout failure, closed over a specified timeout value and error callback. +function createTimeout (errorCallback, timeout) { + let t = setTimeout(function () { + clearTimeout(t); + t = null; + errorCallback({ + code: PositionError.TIMEOUT, + message: 'Position retrieval timed out.' + }); + }, timeout); + return t; +} + module.exports = { getCurrentPosition: function (success, error, args) { + // Timer var that will fire an error callback if no position is retrieved from native + // before the "timeout" param provided expires + const timeoutTimer = { timer: null }; + const win = function (deviceApiLevel) { // Workaround for bug specific to API 31 where requesting `enableHighAccuracy: false` results in TIMEOUT error. if (deviceApiLevel === 31) { @@ -36,15 +55,39 @@ module.exports = { args.enableHighAccuracy = true; } const geo = cordova.require('cordova/modulemapper').getOriginalSymbol(window, 'navigator.geolocation'); // eslint-disable-line no-undef - geo.getCurrentPosition(success, error, args); + geo.getCurrentPosition((position) => { + clearTimeout(timeoutTimer.timer); + if (!timeoutTimer.timer) { + // Timeout already happened, or native fired error callback for + // this geo request. + // Don't continue with success callback. + return; + } + success(position); + }, error, args); }; const fail = function () { + clearTimeout(timeoutTimer.timer); + timeoutTimer.timer = null; if (error) { error(new PositionError(PositionError.PERMISSION_DENIED, 'Illegal Access')); } }; + + 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.timer = createTimeout(fail, 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.timer = true; + } const enableHighAccuracy = typeof args === 'object' && !!args.enableHighAccuracy; exec(win, fail, 'Geolocation', 'getPermission', [enableHighAccuracy]); + return timeoutTimer; }, watchPosition: function (success, error, args) { From 3f377982eeca630eee6ca57a563d9bf8e552d533 Mon Sep 17 00:00:00 2001 From: kumo01GitHub Date: Sun, 1 Dec 2024 01:29:11 +0900 Subject: [PATCH 2/3] fix: timeout error --- www/android/geolocation.js | 57 ++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/www/android/geolocation.js b/www/android/geolocation.js index eec58fd2..01dae03f 100644 --- a/www/android/geolocation.js +++ b/www/android/geolocation.js @@ -27,8 +27,6 @@ const PositionError = require('./PositionError'); // So we use additional map and own ids to return watch id synchronously. const pluginToNativeWatchMap = {}; -const timers = {}; // list of timers in use - // Returns a timeout failure, closed over a specified timeout value and error callback. function createTimeout (errorCallback, timeout) { let t = setTimeout(function () { @@ -42,8 +40,37 @@ function createTimeout (errorCallback, timeout) { return t; } +// Returns default params, overrides if provided with values +function parseParameters (options) { + const opt = { + maximumAge: 0, + enableHighAccuracy: false, + timeout: Infinity + }; + + if (options) { + 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 && !isNaN(options.timeout)) { + if (options.timeout < 0) { + opt.timeout = 0; + } else { + opt.timeout = options.timeout; + } + } + } + + return opt; +} + module.exports = { getCurrentPosition: function (success, error, args) { + args = parseParameters(args); + // Timer var that will fire an error callback if no position is retrieved from native // before the "timeout" param provided expires const timeoutTimer = { timer: null }; @@ -54,17 +81,19 @@ module.exports = { if (typeof args === 'undefined') args = {}; args.enableHighAccuracy = true; } - const geo = cordova.require('cordova/modulemapper').getOriginalSymbol(window, 'navigator.geolocation'); // eslint-disable-line no-undef - geo.getCurrentPosition((position) => { - clearTimeout(timeoutTimer.timer); - if (!timeoutTimer.timer) { - // Timeout already happened, or native fired error callback for - // this geo request. + // Timeout already happened, or native fired error callback for this geo request. + // Don't continue with success callback. + if (timeoutTimer.timer) { + const geo = cordova.require('cordova/modulemapper').getOriginalSymbol(window, 'navigator.geolocation'); // eslint-disable-line no-undef + geo.getCurrentPosition((position) => { + clearTimeout(timeoutTimer.timer); + // Timeout already happened, or native fired error callback for this geo request. // Don't continue with success callback. - return; - } - success(position); - }, error, args); + if (timeoutTimer.timer) { + success(position); + } + }, error, args); + } }; const fail = function () { clearTimeout(timeoutTimer.timer); @@ -74,11 +103,11 @@ module.exports = { } }; - if (options.timeout !== Infinity) { + if (args.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.timer = createTimeout(fail, options.timeout); + timeoutTimer.timer = createTimeout(error, args.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 From fdf38e826f07a6e3273d5ec515bfbbf6a0433724 Mon Sep 17 00:00:00 2001 From: kumo01GitHub Date: Sun, 1 Dec 2024 16:50:00 +0900 Subject: [PATCH 3/3] fix: bugfix --- www/android/geolocation.js | 55 ++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/www/android/geolocation.js b/www/android/geolocation.js index 01dae03f..d6ab27b1 100644 --- a/www/android/geolocation.js +++ b/www/android/geolocation.js @@ -27,17 +27,20 @@ const PositionError = require('./PositionError'); // So we use additional map and own ids to return watch id synchronously. const pluginToNativeWatchMap = {}; +// list of timers in use +const timers = {}; + // Returns a timeout failure, closed over a specified timeout value and error callback. -function createTimeout (errorCallback, timeout) { - let t = setTimeout(function () { - clearTimeout(t); - t = null; +function createTimeout (errorCallback, timeout, id) { + timers[id].timer = setTimeout(function () { + clearTimeout(timers[id].timer); + timers[id].timer = null; errorCallback({ code: PositionError.TIMEOUT, message: 'Position retrieval timed out.' }); }, timeout); - return t; + return timers[id].timer; } // Returns default params, overrides if provided with values @@ -71,33 +74,39 @@ module.exports = { getCurrentPosition: function (success, error, args) { args = parseParameters(args); + const id = utils.createUUID(); + // Timer var that will fire an error callback if no position is retrieved from native // before the "timeout" param provided expires - const timeoutTimer = { timer: null }; + timers[id] = { timer: null }; const win = function (deviceApiLevel) { + if (!timers[id].timer) { + // Timeout already happened, or native fired error callback for + // this geo request. + // Don't continue with success callback. + return; + } // Workaround for bug specific to API 31 where requesting `enableHighAccuracy: false` results in TIMEOUT error. if (deviceApiLevel === 31) { if (typeof args === 'undefined') args = {}; args.enableHighAccuracy = true; } - // Timeout already happened, or native fired error callback for this geo request. - // Don't continue with success callback. - if (timeoutTimer.timer) { - const geo = cordova.require('cordova/modulemapper').getOriginalSymbol(window, 'navigator.geolocation'); // eslint-disable-line no-undef - geo.getCurrentPosition((position) => { - clearTimeout(timeoutTimer.timer); - // Timeout already happened, or native fired error callback for this geo request. + const geo = cordova.require('cordova/modulemapper').getOriginalSymbol(window, 'navigator.geolocation'); // eslint-disable-line no-undef + geo.getCurrentPosition((position) => { + clearTimeout(timers[id].timer); + if (!timers[id].timer) { + // Timeout already happened, or native fired error callback for + // this geo request. // Don't continue with success callback. - if (timeoutTimer.timer) { - success(position); - } - }, error, args); - } + return; + } + success(position); + }, error, args); }; const fail = function () { - clearTimeout(timeoutTimer.timer); - timeoutTimer.timer = null; + clearTimeout(timers[id].timer); + timers[id].timer = null; if (error) { error(new PositionError(PositionError.PERMISSION_DENIED, 'Illegal Access')); } @@ -107,16 +116,16 @@ module.exports = { // 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.timer = createTimeout(error, args.timeout); + timers[id].timer = createTimeout(error, args.timeout, id); } 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.timer = true; + timers[id].timer = true; } const enableHighAccuracy = typeof args === 'object' && !!args.enableHighAccuracy; exec(win, fail, 'Geolocation', 'getPermission', [enableHighAccuracy]); - return timeoutTimer; + return timers[id]; }, watchPosition: function (success, error, args) {