Skip to content

Commit 362bf80

Browse files
Fix the support for coarse location (#207)
* fix(android): Fix the support for coarse location * fix(android): Remove comment
1 parent 34ed332 commit 362bf80

File tree

6 files changed

+108
-38
lines changed

6 files changed

+108
-38
lines changed

android/src/main/java/com/reactnativecommunity/geolocation/GeolocationModule.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.google.android.gms.common.GoogleApiAvailability;
2424

2525
import java.util.ArrayList;
26+
import java.util.Objects;
2627

2728
public class GeolocationModule extends ReactContextBaseJavaModule {
2829

@@ -49,13 +50,13 @@ public String getName() {
4950

5051
public void setConfiguration(ReadableMap config) {
5152
mConfiguration = Configuration.fromReactMap(config);
52-
onConfigutationChange(mConfiguration);
53+
onConfigurationChange(mConfiguration);
5354
}
5455

55-
private void onConfigutationChange(Configuration config) {
56-
if (config.locationProvider == "android" && mLocationManager instanceof PlayServicesLocationManager) {
56+
private void onConfigurationChange(Configuration config) {
57+
if (Objects.equals(config.locationProvider, "android") && mLocationManager instanceof PlayServicesLocationManager) {
5758
mLocationManager = new AndroidLocationManager(mLocationManager.mReactContext);
58-
} else if (config.locationProvider == "playServices" && mLocationManager instanceof AndroidLocationManager) {
59+
} else if (Objects.equals(config.locationProvider, "playServices") && mLocationManager instanceof AndroidLocationManager) {
5960
mLocationManager = new PlayServicesLocationManager(mLocationManager.mReactContext);
6061
}
6162
}
@@ -68,7 +69,7 @@ public void requestAuthorization(final Callback success, final Callback error) {
6869
final PermissionsModule perms = getReactApplicationContext().getNativeModule(PermissionsModule.class);
6970
ArrayList<String> permissions = new ArrayList<>();
7071
permissions.add(Manifest.permission.ACCESS_COARSE_LOCATION);
71-
permissions.add( Manifest.permission.ACCESS_FINE_LOCATION);
72+
permissions.add(Manifest.permission.ACCESS_FINE_LOCATION);
7273
ReadableArray permissionsArray = JavaOnlyArray.from(permissions);
7374

7475
final Callback onPermissionGranted = args -> {
@@ -94,7 +95,7 @@ public void requestAuthorization(final Callback success, final Callback error) {
9495
}
9596
};
9697

97-
perms.checkPermission(Manifest.permission.ACCESS_FINE_LOCATION, new PromiseImpl(onPermissionChecked, onPermissionCheckFailed));
98+
perms.checkPermission(Manifest.permission.ACCESS_FINE_LOCATION, new PromiseImpl(onPermissionChecked, args -> perms.checkPermission(Manifest.permission.ACCESS_COARSE_LOCATION, new PromiseImpl(onPermissionChecked, onPermissionCheckFailed))));
9899
return;
99100
}
100101

android/src/main/java/com/reactnativecommunity/geolocation/PlayServicesLocationManager.java

Lines changed: 96 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,58 +2,89 @@
22

33
import android.annotation.SuppressLint;
44
import android.location.Location;
5+
import android.os.Build;
56
import android.os.Looper;
7+
import android.util.Log;
8+
9+
import androidx.annotation.RequiresApi;
610

711
import com.facebook.react.bridge.Callback;
812
import com.facebook.react.bridge.ReactApplicationContext;
913
import com.facebook.react.bridge.ReadableMap;
1014
import com.facebook.react.common.SystemClock;
1115
import com.facebook.react.modules.core.DeviceEventManagerModule;
1216
import com.google.android.gms.location.FusedLocationProviderClient;
17+
import com.google.android.gms.location.LocationAvailability;
1318
import com.google.android.gms.location.LocationCallback;
1419
import com.google.android.gms.location.LocationRequest;
1520
import com.google.android.gms.location.LocationResult;
1621
import com.google.android.gms.location.LocationServices;
22+
import com.google.android.gms.location.LocationSettingsRequest;
23+
import com.google.android.gms.location.LocationSettingsResponse;
1724
import com.google.android.gms.location.Priority;
25+
import com.google.android.gms.location.SettingsClient;
26+
import com.google.android.gms.tasks.OnSuccessListener;
27+
28+
import java.util.function.Consumer;
29+
import java.util.function.Function;
1830

1931
@SuppressLint("MissingPermission")
2032
public class PlayServicesLocationManager extends BaseLocationManager {
2133
private FusedLocationProviderClient mFusedLocationClient;
2234
private LocationCallback mLocationCallback;
35+
private LocationCallback mSingleLocationCallback;
36+
private SettingsClient mLocationServicesSettingsClient;
2337

2438
protected PlayServicesLocationManager(ReactApplicationContext reactContext) {
2539
super(reactContext);
26-
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(reactContext.getCurrentActivity());
27-
mLocationCallback = new LocationCallback() {
28-
@Override
29-
public void onLocationResult(LocationResult locationResult) {
30-
if (locationResult == null) {
31-
emitError(PositionError.POSITION_UNAVAILABLE, "No location provided by FusedLocationProviderClient.");
32-
return;
33-
}
34-
for (Location location : locationResult.getLocations()) {
35-
mReactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
36-
.emit("geolocationDidChange", locationToMap(location));
37-
}
38-
}
39-
};
40+
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(reactContext);
41+
mLocationServicesSettingsClient = LocationServices.getSettingsClient(reactContext);
4042
}
4143

4244
@Override
4345
public void getCurrentLocationData(ReadableMap options, Callback success, Callback error) {
4446
AndroidLocationManager.LocationOptions locationOptions = AndroidLocationManager.LocationOptions.fromReactMap(options);
4547

4648
try {
47-
mFusedLocationClient.getCurrentLocation(locationOptions.highAccuracy ? Priority.PRIORITY_HIGH_ACCURACY : Priority.PRIORITY_LOW_POWER, null)
49+
mFusedLocationClient.getLastLocation()
4850
.addOnSuccessListener(mReactContext.getCurrentActivity(), location -> {
4951
if (location != null) {
5052
if ((SystemClock.currentTimeMillis() - location.getTime()) < locationOptions.maximumAge) {
5153
success.invoke(locationToMap(location));
54+
} else {
55+
error.invoke(PositionError.buildError(
56+
PositionError.POSITION_UNAVAILABLE, "Last found location is older than maximumAge (FusedLocationProvider/lastLocation).")
57+
);
5258
}
5359
} else {
54-
error.invoke(PositionError.buildError(
55-
PositionError.POSITION_UNAVAILABLE, "No location provided by FusedLocationProviderClient.")
56-
);
60+
mSingleLocationCallback = new LocationCallback() {
61+
@Override
62+
public void onLocationResult(LocationResult locationResult) {
63+
if (locationResult == null) {
64+
emitError(PositionError.POSITION_UNAVAILABLE, "No location provided (FusedLocationProvider/lastLocation).");
65+
return;
66+
}
67+
68+
AndroidLocationManager.LocationOptions locationOptions = AndroidLocationManager.LocationOptions.fromReactMap(options);
69+
Location location = locationResult.getLastLocation();
70+
if ((SystemClock.currentTimeMillis() - location.getTime()) < locationOptions.maximumAge) {
71+
success.invoke(locationToMap(location));
72+
} else {
73+
emitError(PositionError.POSITION_UNAVAILABLE, "Last found location is older than maximumAge (FusedLocationProvider/lastLocation).");
74+
}
75+
76+
mFusedLocationClient.removeLocationUpdates(mSingleLocationCallback);
77+
mSingleLocationCallback = null;
78+
}
79+
80+
@Override
81+
public void onLocationAvailability(LocationAvailability locationAvailability) {
82+
if (!locationAvailability.isLocationAvailable()) {
83+
emitError(PositionError.POSITION_UNAVAILABLE, "Location not available (FusedLocationProvider/lastLocation).");
84+
}
85+
}
86+
};
87+
checkLocationSettings(options, mSingleLocationCallback);
5788
}
5889
});
5990
} catch (SecurityException e) {
@@ -63,6 +94,41 @@ public void getCurrentLocationData(ReadableMap options, Callback success, Callba
6394

6495
@Override
6596
public void startObserving(ReadableMap options) {
97+
mLocationCallback = new LocationCallback() {
98+
@Override
99+
public void onLocationResult(LocationResult locationResult) {
100+
if (locationResult == null) {
101+
emitError(PositionError.POSITION_UNAVAILABLE, "No location provided (FusedLocationProvider/observer).");
102+
return;
103+
}
104+
105+
AndroidLocationManager.LocationOptions locationOptions = AndroidLocationManager.LocationOptions.fromReactMap(options);
106+
Location location = locationResult.getLastLocation();
107+
if ((SystemClock.currentTimeMillis() - location.getTime()) < locationOptions.maximumAge) {
108+
mReactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
109+
.emit("geolocationDidChange", locationToMap(locationResult.getLastLocation()));
110+
} else {
111+
emitError(PositionError.POSITION_UNAVAILABLE, "Last found location is older than maximumAge (FusedLocationProvider/observer).");
112+
}
113+
}
114+
115+
@Override
116+
public void onLocationAvailability(LocationAvailability locationAvailability) {
117+
if (!locationAvailability.isLocationAvailable()) {
118+
emitError(PositionError.POSITION_UNAVAILABLE, "Location not available (FusedLocationProvider).");
119+
}
120+
}
121+
};
122+
123+
checkLocationSettings(options, mLocationCallback);
124+
}
125+
126+
@Override
127+
public void stopObserving() {
128+
mFusedLocationClient.removeLocationUpdates(mLocationCallback);
129+
}
130+
131+
private void checkLocationSettings(ReadableMap options, LocationCallback locationCallback) {
66132
LocationOptions locationOptions = LocationOptions.fromReactMap(options);
67133
LocationRequest locationRequest = LocationRequest.create();
68134
locationRequest.setInterval(locationOptions.interval);
@@ -74,15 +140,21 @@ public void startObserving(ReadableMap options) {
74140
locationRequest.setPriority(
75141
locationOptions.highAccuracy ? LocationRequest.PRIORITY_HIGH_ACCURACY : LocationRequest.PRIORITY_LOW_POWER
76142
);
143+
144+
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
145+
builder.addLocationRequest(locationRequest);
146+
LocationSettingsRequest locationSettingsRequest = builder.build();
147+
148+
mLocationServicesSettingsClient.checkLocationSettings(locationSettingsRequest)
149+
.addOnSuccessListener(locationSettingsResponse -> requestLocationUpdates(locationRequest, locationCallback))
150+
.addOnFailureListener(err -> emitError(PositionError.POSITION_UNAVAILABLE, "Location not available (FusedLocationProvider/settings)."));
151+
}
152+
153+
private void requestLocationUpdates(LocationRequest locationRequest, LocationCallback locationCallback) {
77154
try {
78-
mFusedLocationClient.requestLocationUpdates(locationRequest, mLocationCallback, Looper.getMainLooper());
155+
mFusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper());
79156
} catch (SecurityException e) {
80157
throw e;
81158
}
82159
}
83-
84-
@Override
85-
public void stopObserving() {
86-
mFusedLocationClient.removeLocationUpdates(mLocationCallback);
87-
}
88160
}

example/android/app/build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ import org.apache.tools.ant.taskdefs.condition.Os
7979
*/
8080

8181
project.ext.react = [
82-
enableHermes: false, // clean and rebuild if changing
82+
enableHermes: true, // clean and rebuild if changing
83+
entryFile: "index.tsx"
8384
]
8485

8586
apply from: "../../node_modules/react-native/react.gradle"

example/src/configs/SetConfiguration.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ export default function SetConfigurationExample() {
4444
Geolocation.setRNConfiguration({
4545
skipPermissionRequests,
4646
authorizationLevel,
47+
locationProvider,
4748
});
48-
}, [skipPermissionRequests, authorizationLevel]);
49+
}, [skipPermissionRequests, authorizationLevel, locationProvider]);
4950

5051
return (
5152
<View>

example/src/examples/GetCurrentLocation.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
'use strict';
1111

12-
import React, { useState, useEffect } from 'react';
12+
import React, { useState } from 'react';
1313
import { StyleSheet, Text, View, Alert, Button } from 'react-native';
1414
import Geolocation from '@react-native-community/geolocation';
1515

@@ -25,9 +25,6 @@ export default function GetCurrentLocationExample() {
2525
};
2626

2727
const [position, setPosition] = useState<string | null>(null);
28-
useEffect(() => {
29-
getCurrentPosition();
30-
}, []);
3128

3229
return (
3330
<View>

example/src/examples/WatchPosition.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@ export default function WatchPositionExample() {
3737
const [position, setPosition] = useState<string | null>(null);
3838
const [subscriptionId, setSubscriptionId] = useState<number | null>(null);
3939
useEffect(() => {
40-
watchPosition();
41-
4240
return () => {
4341
clearWatch();
4442
};

0 commit comments

Comments
 (0)