Skip to content

Commit

Permalink
FIX: Ensure permission denied in geolocation.getCurrentPosition rejec…
Browse files Browse the repository at this point in the history
…ts the Promise

fixes facebook/react-native#22535

Moves the permission request logic on Android M and above to Native side to mimic IOS behavior.

Changelog:
----------

[Android] [Fixed] - Ensure permission denied in geolocation.getCurrentPosition rejects the promise

Test Plan:
----------

Was originally reviewed and accepted as facebook/react-native#22843 as part
of core react-native. That PR was verified via my test project which requested location via
Geolocation service. If the permission request was denied by the user the promise was rejected as well.

https://github.com/Jyrno42/rn-geoloctest
  • Loading branch information
Jyrno42 committed Mar 30, 2019
1 parent d529831 commit fe48699
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package com.reactnativecommunity.geolocation;

import android.annotation.SuppressLint;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
Expand All @@ -21,6 +22,7 @@
import com.facebook.common.logging.FLog;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.PromiseImpl;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
Expand All @@ -30,6 +32,7 @@
import com.facebook.react.common.SystemClock;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter;
import com.facebook.react.modules.permissions.PermissionsModule;
import javax.annotation.Nullable;

/**
Expand Down Expand Up @@ -110,13 +113,74 @@ private static LocationOptions fromReactMap(ReadableMap map) {

/**
* Get the current position. This can return almost immediately if the location is cached or
* request an update, which might take a while.
* request an update, which might take a while. This method also requests location
* permissions on API level 23 and above when needed.
*
* @param options map containing optional arguments: timeout (millis), maximumAge (millis) and
* highAccuracy (boolean)
*/
@ReactMethod
public void getCurrentPosition(
final ReadableMap options,
final Callback success,
final Callback error) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
final PermissionsModule perms = getReactApplicationContext().getNativeModule(PermissionsModule.class);

final Callback onPermissionGranted = new Callback() {
@Override
public void invoke(Object... args) {
String result = (String) args[0];
if (result == "granted") {
getCurrentLocationData(options, success, error);
} else {
error.invoke(PositionError.buildError(PositionError.PERMISSION_DENIED, "Location permission was not granted."));
}
}
};

final Callback onPermissionDenied = new Callback() {
@Override
public void invoke(Object... args) {
error.invoke(PositionError.buildError(PositionError.PERMISSION_DENIED, "Failed to request location permission."));
}
};

Callback onPermissionCheckFailed = new Callback() {
@Override
public void invoke(Object... args) {
error.invoke(PositionError.buildError(PositionError.PERMISSION_DENIED, "Failed to check location permission."));
}
};

Callback onPermissionChecked = new Callback() {
@Override
public void invoke(Object... args) {
boolean hasPermission = (boolean) args[0];

if (!hasPermission) {
perms.requestPermission(Manifest.permission.ACCESS_FINE_LOCATION, new PromiseImpl(onPermissionGranted, onPermissionDenied));
} else {
getCurrentLocationData(options, success, error);
}
}
};

perms.checkPermission(Manifest.permission.ACCESS_FINE_LOCATION, new PromiseImpl(onPermissionChecked, onPermissionCheckFailed));
return;
}

getCurrentLocationData(options, success, error);
}

/**
* Get the current position. This can return almost immediately if the location is cached or
* request an update, which might take a while.
*
* @param options map containing optional arguments: timeout (millis), maximumAge (millis) and
* highAccuracy (boolean)
*/
public void getCurrentLocationData(
ReadableMap options,
final Callback success,
Callback error) {
Expand Down
28 changes: 7 additions & 21 deletions js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,27 +72,13 @@ const Geolocation = {
typeof geo_success === 'function',
'Must provide a valid geo_success callback.',
);
let hasPermission = true;
// Supports Android's new permission model. For Android older devices,
// it's always on.
if (Platform.OS === 'android' && Platform.Version >= 23) {
hasPermission = await PermissionsAndroid.check(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
);
if (!hasPermission) {
const status = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
);
hasPermission = status === PermissionsAndroid.RESULTS.GRANTED;
}
}
if (hasPermission) {
RNCGeolocation.getCurrentPosition(
geo_options || {},
geo_success,
geo_error || logError,
);
}

// Permission checks/requests are done on the native side
RNCGeolocation.getCurrentPosition(
geo_options || {},
geo_success,
geo_error || logError,
);
},

/*
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
"description": "React Native Geolocation Module for iOS and Android",
"main": "js/index.js",
"author": "Janic Duplessis <[email protected]>",
"contributors": [],
"contributors": [
"Jyrno Ader <[email protected]>"
],
"homepage": "https://github.com/react-native-community/react-native-geolocation#README.md",
"license": "MIT",
"scripts": {
Expand Down

0 comments on commit fe48699

Please sign in to comment.