2
2
3
3
import android .annotation .SuppressLint ;
4
4
import android .location .Location ;
5
+ import android .os .Build ;
5
6
import android .os .Looper ;
7
+ import android .util .Log ;
8
+
9
+ import androidx .annotation .RequiresApi ;
6
10
7
11
import com .facebook .react .bridge .Callback ;
8
12
import com .facebook .react .bridge .ReactApplicationContext ;
9
13
import com .facebook .react .bridge .ReadableMap ;
10
14
import com .facebook .react .common .SystemClock ;
11
15
import com .facebook .react .modules .core .DeviceEventManagerModule ;
12
16
import com .google .android .gms .location .FusedLocationProviderClient ;
17
+ import com .google .android .gms .location .LocationAvailability ;
13
18
import com .google .android .gms .location .LocationCallback ;
14
19
import com .google .android .gms .location .LocationRequest ;
15
20
import com .google .android .gms .location .LocationResult ;
16
21
import com .google .android .gms .location .LocationServices ;
22
+ import com .google .android .gms .location .LocationSettingsRequest ;
23
+ import com .google .android .gms .location .LocationSettingsResponse ;
17
24
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 ;
18
30
19
31
@ SuppressLint ("MissingPermission" )
20
32
public class PlayServicesLocationManager extends BaseLocationManager {
21
33
private FusedLocationProviderClient mFusedLocationClient ;
22
34
private LocationCallback mLocationCallback ;
35
+ private LocationCallback mSingleLocationCallback ;
36
+ private SettingsClient mLocationServicesSettingsClient ;
23
37
24
38
protected PlayServicesLocationManager (ReactApplicationContext reactContext ) {
25
39
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 );
40
42
}
41
43
42
44
@ Override
43
45
public void getCurrentLocationData (ReadableMap options , Callback success , Callback error ) {
44
46
AndroidLocationManager .LocationOptions locationOptions = AndroidLocationManager .LocationOptions .fromReactMap (options );
45
47
46
48
try {
47
- mFusedLocationClient .getCurrentLocation ( locationOptions . highAccuracy ? Priority . PRIORITY_HIGH_ACCURACY : Priority . PRIORITY_LOW_POWER , null )
49
+ mFusedLocationClient .getLastLocation ( )
48
50
.addOnSuccessListener (mReactContext .getCurrentActivity (), location -> {
49
51
if (location != null ) {
50
52
if ((SystemClock .currentTimeMillis () - location .getTime ()) < locationOptions .maximumAge ) {
51
53
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
+ );
52
58
}
53
59
} 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 );
57
88
}
58
89
});
59
90
} catch (SecurityException e ) {
@@ -63,6 +94,41 @@ public void getCurrentLocationData(ReadableMap options, Callback success, Callba
63
94
64
95
@ Override
65
96
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 ) {
66
132
LocationOptions locationOptions = LocationOptions .fromReactMap (options );
67
133
LocationRequest locationRequest = LocationRequest .create ();
68
134
locationRequest .setInterval (locationOptions .interval );
@@ -74,15 +140,21 @@ public void startObserving(ReadableMap options) {
74
140
locationRequest .setPriority (
75
141
locationOptions .highAccuracy ? LocationRequest .PRIORITY_HIGH_ACCURACY : LocationRequest .PRIORITY_LOW_POWER
76
142
);
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 ) {
77
154
try {
78
- mFusedLocationClient .requestLocationUpdates (locationRequest , mLocationCallback , Looper .getMainLooper ());
155
+ mFusedLocationClient .requestLocationUpdates (locationRequest , locationCallback , Looper .getMainLooper ());
79
156
} catch (SecurityException e ) {
80
157
throw e ;
81
158
}
82
159
}
83
-
84
- @ Override
85
- public void stopObserving () {
86
- mFusedLocationClient .removeLocationUpdates (mLocationCallback );
87
- }
88
160
}
0 commit comments