22
33import android .annotation .SuppressLint ;
44import android .location .Location ;
5+ import android .os .Build ;
56import android .os .Looper ;
7+ import android .util .Log ;
8+
9+ import androidx .annotation .RequiresApi ;
610
711import com .facebook .react .bridge .Callback ;
812import com .facebook .react .bridge .ReactApplicationContext ;
913import com .facebook .react .bridge .ReadableMap ;
1014import com .facebook .react .common .SystemClock ;
1115import com .facebook .react .modules .core .DeviceEventManagerModule ;
1216import com .google .android .gms .location .FusedLocationProviderClient ;
17+ import com .google .android .gms .location .LocationAvailability ;
1318import com .google .android .gms .location .LocationCallback ;
1419import com .google .android .gms .location .LocationRequest ;
1520import com .google .android .gms .location .LocationResult ;
1621import com .google .android .gms .location .LocationServices ;
22+ import com .google .android .gms .location .LocationSettingsRequest ;
23+ import com .google .android .gms .location .LocationSettingsResponse ;
1724import 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" )
2032public 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}
0 commit comments