Skip to content

Commit f8b389e

Browse files
authored
Merge pull request #983 from maskaravivek/nearbyRefactoring
Fix issues around location in nearby activity
2 parents 7273604 + d6b7af3 commit f8b389e

File tree

7 files changed

+184
-96
lines changed

7 files changed

+184
-96
lines changed

app/build.gradle

-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ android {
7878

7979
defaultConfig {
8080
applicationId 'fr.free.nrw.commons'
81-
8281
versionCode 76
8382
versionName '2.6.1'
8483
setProperty("archivesBaseName", "app-commons-v$versionName-" + getBranchName())

app/src/main/AndroidManifest.xml

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
<uses-permission android:name="com.google.android.apps.photos.permission.GOOGLE_PHOTOS"/>
1717
<uses-permission android:name="android.permission.READ_LOGS"/>
1818

19+
<!-- Needed only if your app targets Android 5.0 (API level 21) or higher. -->
20+
<uses-feature android:name="android.hardware.location.gps" />
21+
1922
<application
2023
android:name=".CommonsApplication"
2124
android:icon="@drawable/ic_launcher"

app/src/main/java/fr/free/nrw/commons/location/LatLng.java

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package fr.free.nrw.commons.location;
22

3+
import android.location.Location;
4+
import android.support.annotation.NonNull;
5+
36
public class LatLng {
47

58
private final double latitude;
@@ -22,6 +25,10 @@ public LatLng(double latitude, double longitude, float accuracy) {
2225
this.accuracy = accuracy;
2326
}
2427

28+
public static LatLng from(@NonNull Location location) {
29+
return new LatLng(location.getLatitude(), location.getLongitude(), location.getAccuracy());
30+
}
31+
2532
public int hashCode() {
2633
boolean var1 = true;
2734
byte var2 = 1;

app/src/main/java/fr/free/nrw/commons/location/LocationServiceManager.java

+109-32
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
package fr.free.nrw.commons.location;
22

3+
import android.Manifest;
4+
import android.app.Activity;
35
import android.content.Context;
4-
import android.location.Criteria;
6+
import android.content.pm.PackageManager;
57
import android.location.Location;
68
import android.location.LocationListener;
79
import android.location.LocationManager;
810
import android.os.Bundle;
11+
import android.support.v4.app.ActivityCompat;
12+
import android.support.v4.content.ContextCompat;
913

1014
import java.util.List;
1115
import java.util.concurrent.CopyOnWriteArrayList;
@@ -17,59 +21,136 @@
1721

1822
@Singleton
1923
public class LocationServiceManager implements LocationListener {
24+
public static final int LOCATION_REQUEST = 1;
2025

21-
private String provider;
26+
private static final long MIN_LOCATION_UPDATE_REQUEST_TIME_IN_MILLIS = 2 * 60 * 1000;
27+
private static final long MIN_LOCATION_UPDATE_REQUEST_DISTANCE_IN_METERS = 10;
28+
29+
private Context context;
2230
private LocationManager locationManager;
23-
private LatLng lastLocation;
24-
private Float latestLocationAccuracy;
31+
private Location lastLocation;
2532
private final List<LocationUpdateListener> locationListeners = new CopyOnWriteArrayList<>();
33+
private boolean isLocationManagerRegistered = false;
2634

2735
@Inject
2836
public LocationServiceManager(Context context) {
37+
this.context = context;
2938
this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
30-
provider = locationManager.getBestProvider(new Criteria(), true);
3139
}
3240

3341
public boolean isProviderEnabled() {
3442
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
3543
}
3644

37-
public LatLng getLastLocation() {
38-
return lastLocation;
45+
public boolean isLocationPermissionGranted() {
46+
return ContextCompat.checkSelfPermission(context,
47+
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
3948
}
4049

41-
/**
42-
* Returns the accuracy of the location. The measurement is
43-
* given as a radius in meter of 68 % confidence.
44-
*
45-
* @return Float
46-
*/
47-
public Float getLatestLocationAccuracy() {
48-
return latestLocationAccuracy;
50+
public void requestPermissions(Activity activity) {
51+
if (activity.isFinishing()) {
52+
return;
53+
}
54+
ActivityCompat.requestPermissions(activity,
55+
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
56+
LOCATION_REQUEST);
57+
}
58+
59+
public boolean isPermissionExplanationRequired(Activity activity) {
60+
if (activity.isFinishing()) {
61+
return false;
62+
}
63+
return ActivityCompat.shouldShowRequestPermissionRationale(activity,
64+
Manifest.permission.ACCESS_FINE_LOCATION);
65+
}
66+
67+
public LatLng getLastLocation() {
68+
if (lastLocation == null) {
69+
return null;
70+
}
71+
return LatLng.from(lastLocation);
4972
}
5073

5174
/** Registers a LocationManager to listen for current location.
5275
*/
5376
public void registerLocationManager() {
77+
if (!isLocationManagerRegistered)
78+
isLocationManagerRegistered = requestLocationUpdatesFromProvider(LocationManager.NETWORK_PROVIDER)
79+
&& requestLocationUpdatesFromProvider(LocationManager.GPS_PROVIDER);
80+
}
81+
82+
private boolean requestLocationUpdatesFromProvider(String locationProvider) {
5483
try {
55-
locationManager.requestLocationUpdates(provider, 400, 1, this);
56-
Location location = locationManager.getLastKnownLocation(provider);
57-
//Location works, just need to 'send' GPS coords
58-
// via emulator extended controls if testing on emulator
59-
Timber.d("Checking for location...");
60-
if (location != null) {
61-
this.onLocationChanged(location);
62-
}
84+
locationManager.requestLocationUpdates(locationProvider,
85+
MIN_LOCATION_UPDATE_REQUEST_TIME_IN_MILLIS,
86+
MIN_LOCATION_UPDATE_REQUEST_DISTANCE_IN_METERS,
87+
this);
88+
return true;
6389
} catch (IllegalArgumentException e) {
6490
Timber.e(e, "Illegal argument exception");
91+
return false;
6592
} catch (SecurityException e) {
6693
Timber.e(e, "Security exception");
94+
return false;
95+
}
96+
}
97+
98+
protected boolean isBetterLocation(Location location, Location currentBestLocation) {
99+
if (currentBestLocation == null) {
100+
// A new location is always better than no location
101+
return true;
102+
}
103+
104+
// Check whether the new location fix is newer or older
105+
long timeDelta = location.getTime() - currentBestLocation.getTime();
106+
boolean isSignificantlyNewer = timeDelta > MIN_LOCATION_UPDATE_REQUEST_TIME_IN_MILLIS;
107+
boolean isSignificantlyOlder = timeDelta < -MIN_LOCATION_UPDATE_REQUEST_TIME_IN_MILLIS;
108+
boolean isNewer = timeDelta > 0;
109+
110+
// If it's been more than two minutes since the current location, use the new location
111+
// because the user has likely moved
112+
if (isSignificantlyNewer) {
113+
return true;
114+
// If the new location is more than two minutes older, it must be worse
115+
} else if (isSignificantlyOlder) {
116+
return false;
117+
}
118+
119+
// Check whether the new location fix is more or less accurate
120+
int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation.getAccuracy());
121+
boolean isLessAccurate = accuracyDelta > 0;
122+
boolean isMoreAccurate = accuracyDelta < 0;
123+
boolean isSignificantlyLessAccurate = accuracyDelta > 200;
124+
125+
// Check if the old and new location are from the same provider
126+
boolean isFromSameProvider = isSameProvider(location.getProvider(),
127+
currentBestLocation.getProvider());
128+
129+
// Determine location quality using a combination of timeliness and accuracy
130+
if (isMoreAccurate) {
131+
return true;
132+
} else if (isNewer && !isLessAccurate) {
133+
return true;
134+
} else if (isNewer && !isSignificantlyLessAccurate && isFromSameProvider) {
135+
return true;
67136
}
137+
return false;
138+
}
139+
140+
/**
141+
* Checks whether two providers are the same
142+
*/
143+
private boolean isSameProvider(String provider1, String provider2) {
144+
if (provider1 == null) {
145+
return provider2 == null;
146+
}
147+
return provider1.equals(provider2);
68148
}
69149

70150
/** Unregisters location manager.
71151
*/
72152
public void unregisterLocationManager() {
153+
isLocationManagerRegistered = false;
73154
try {
74155
locationManager.removeUpdates(this);
75156
} catch (SecurityException e) {
@@ -89,15 +170,11 @@ public void removeLocationListener(LocationUpdateListener listener) {
89170

90171
@Override
91172
public void onLocationChanged(Location location) {
92-
double currentLatitude = location.getLatitude();
93-
double currentLongitude = location.getLongitude();
94-
latestLocationAccuracy = location.getAccuracy();
95-
Timber.d("Latitude: %f Longitude: %f Accuracy %f",
96-
currentLatitude, currentLongitude, latestLocationAccuracy);
97-
lastLocation = new LatLng(currentLatitude, currentLongitude, latestLocationAccuracy);
98-
99-
for (LocationUpdateListener listener : locationListeners) {
100-
listener.onLocationChanged(lastLocation);
173+
if (isBetterLocation(location, lastLocation)) {
174+
lastLocation = location;
175+
for (LocationUpdateListener listener : locationListeners) {
176+
listener.onLocationChanged(LatLng.from(lastLocation));
177+
}
101178
}
102179
}
103180

0 commit comments

Comments
 (0)