(android) fix: respect requested location accuracy when checking/requesting permissions on Android 12+
Handle bug on API < 32 when requesting COARSE permission results in TIMEOUT error.
diff --git a/src/android/Geolocation.java b/src/android/Geolocation.java
index 6452170..d8cae0e 100644
--- a/src/android/Geolocation.java
+++ b/src/android/Geolocation.java
@@ -23,7 +23,6 @@
import android.os.Build;
import org.apache.cordova.CallbackContext;
-import org.apache.cordova.CordovaArgs;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PermissionHelper;
import org.apache.cordova.PluginResult;
@@ -31,14 +30,17 @@
import org.json.JSONArray;
import org.json.JSONException;
-import javax.security.auth.callback.Callback;
public class Geolocation extends CordovaPlugin {
String TAG = "GeolocationPlugin";
CallbackContext context;
- String [] permissions = { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION };
+
+ String [] highAccuracyPermissions = { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION };
+ String [] lowAccuracyPermissions = { Manifest.permission.ACCESS_COARSE_LOCATION };
+ String [] permissionsToRequest;
+ String[] permissionsToCheck;
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
@@ -46,14 +48,21 @@
context = callbackContext;
if(action.equals("getPermission"))
{
- if(hasPermisssion())
+ boolean highAccuracy = args.getBoolean(0);
+ permissionsToCheck = highAccuracy ? highAccuracyPermissions : lowAccuracyPermissions;
+
+ // Always request both FINE & COARSE permissions on API <= 31 due to bug in WebView that manifests on these versions
+ // See https://bugs.chromium.org/p/chromium/issues/detail?id=1269362
+ permissionsToRequest = Build.VERSION.SDK_INT <= 31 ? highAccuracyPermissions : permissionsToCheck;
+
+ if(hasPermisssion(permissionsToCheck))
{
- PluginResult r = new PluginResult(PluginResult.Status.OK);
+ PluginResult r = new PluginResult(PluginResult.Status.OK, Build.VERSION.SDK_INT);
context.sendPluginResult(r);
return true;
}
else {
- PermissionHelper.requestPermissions(this, 0, permissions);
+ PermissionHelper.requestPermissions(this, 0, permissionsToRequest);
}
return true;
}
@@ -67,8 +76,10 @@
PluginResult result;
//This is important if we're using Cordova without using Cordova, but we have the geolocation plugin installed
if(context != null) {
- for (int r : grantResults) {
- if (r == PackageManager.PERMISSION_DENIED) {
+ for (int i=0; i<grantResults.length; i++) {
+ int r = grantResults[i];
+ String p = permissions[i];
+ if (r == PackageManager.PERMISSION_DENIED && arrayContains(permissionsToCheck, p)) {
LOG.d(TAG, "Permission Denied!");
result = new PluginResult(PluginResult.Status.ILLEGAL_ACCESS_EXCEPTION);
context.sendPluginResult(result);
@@ -81,7 +92,7 @@
}
}
- public boolean hasPermisssion() {
+ public boolean hasPermisssion(String[] permissions) {
for(String p : permissions)
{
if(!PermissionHelper.hasPermission(this, p))
@@ -99,9 +110,23 @@
public void requestPermissions(int requestCode)
{
- PermissionHelper.requestPermissions(this, requestCode, permissions);
+ PermissionHelper.requestPermissions(this, requestCode, permissionsToRequest);
}
+ //https://stackoverflow.com/a/12635769/777265
+ private <T> boolean arrayContains(final T[] array, final T v) {
+ if (v == null) {
+ for (final T e : array)
+ if (e == null)
+ return true;
+ }
+ else {
+ for (final T e : array)
+ if (e == v || v.equals(e))
+ return true;
+ }
+ return false;
+ }
}
diff --git a/www/android/geolocation.js b/www/android/geolocation.js
index c02940b..2d66809 100644
--- a/www/android/geolocation.js
+++ b/www/android/geolocation.js
@@ -29,7 +29,12 @@
module.exports = {
getCurrentPosition: function (success, error, args) {
- var win = function () {
+ var win = function (deviceApiLevel) {
+ // 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;
+ }
var geo = cordova.require('cordova/modulemapper').getOriginalSymbol(window, 'navigator.geolocation'); // eslint-disable-line no-undef
geo.getCurrentPosition(success, error, args);
};
@@ -38,13 +43,19 @@
error(new PositionError(PositionError.PERMISSION_DENIED, 'Illegal Access'));
}
};
- exec(win, fail, 'Geolocation', 'getPermission', []);
+ var enableHighAccuracy = typeof args === 'object' && !!args.enableHighAccuracy;
+ exec(win, fail, 'Geolocation', 'getPermission', [enableHighAccuracy]);
},
watchPosition: function (success, error, args) {
var pluginWatchId = utils.createUUID();
- var win = function () {
+ var win = function (deviceApiLevel) {
+ // 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;
+ }
var geo = cordova.require('cordova/modulemapper').getOriginalSymbol(window, 'navigator.geolocation'); // eslint-disable-line no-undef
pluginToNativeWatchMap[pluginWatchId] = geo.watchPosition(success, error, args);
};
@@ -54,18 +65,15 @@
error(new PositionError(PositionError.PERMISSION_DENIED, 'Illegal Access'));
}
};
- exec(win, fail, 'Geolocation', 'getPermission', []);
+ var enableHighAccuracy = typeof args === 'object' && !!args.enableHighAccuracy;
+ exec(win, fail, 'Geolocation', 'getPermission', [enableHighAccuracy]);
return pluginWatchId;
},
clearWatch: function (pluginWatchId) {
- var win = function () {
- var nativeWatchId = pluginToNativeWatchMap[pluginWatchId];
- var geo = cordova.require('cordova/modulemapper').getOriginalSymbol(window, 'navigator.geolocation'); // eslint-disable-line no-undef
- geo.clearWatch(nativeWatchId);
- };
-
- exec(win, null, 'Geolocation', 'getPermission', []);
+ var nativeWatchId = pluginToNativeWatchMap[pluginWatchId];
+ var geo = cordova.require('cordova/modulemapper').getOriginalSymbol(window, 'navigator.geolocation'); // eslint-disable-line no-undef
+ geo.clearWatch(nativeWatchId);
}
};