Skip to content

Commit 52b52c4

Browse files
author
Vivek Maskara
authored
Merge branch 'master' into dependency-injection
2 parents fb30a34 + f8b389e commit 52b52c4

File tree

21 files changed

+186
-89
lines changed

21 files changed

+186
-89
lines changed

app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ android {
8383

8484
defaultConfig {
8585
applicationId 'fr.free.nrw.commons'
86-
8786
versionCode 76
8887
versionName '2.6.1'
8988
setProperty("archivesBaseName", "app-commons-v$versionName-" + getBranchName())
@@ -104,6 +103,7 @@ android {
104103
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
105104
}
106105
debug {
106+
applicationIdSuffix ".debug"
107107
testCoverageEnabled true
108108
versionNameSuffix "-debug-" + getBranchName() + "~" + getBuildVersion()
109109
}

app/src/main/AndroidManifest.xml

Lines changed: 3 additions & 0 deletions
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

Lines changed: 7 additions & 0 deletions
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

Lines changed: 109 additions & 32 deletions
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;
@@ -16,58 +20,135 @@
1620
import timber.log.Timber;
1721

1822
public class LocationServiceManager implements LocationListener {
23+
public static final int LOCATION_REQUEST = 1;
1924

20-
private String provider;
25+
private static final long MIN_LOCATION_UPDATE_REQUEST_TIME_IN_MILLIS = 2 * 60 * 1000;
26+
private static final long MIN_LOCATION_UPDATE_REQUEST_DISTANCE_IN_METERS = 10;
27+
28+
private Context context;
2129
private LocationManager locationManager;
22-
private LatLng lastLocation;
23-
private Float latestLocationAccuracy;
30+
private Location lastLocation;
2431
private final List<LocationUpdateListener> locationListeners = new CopyOnWriteArrayList<>();
32+
private boolean isLocationManagerRegistered = false;
2533

2634
public LocationServiceManager(Context context) {
35+
this.context = context;
2736
this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
28-
provider = locationManager.getBestProvider(new Criteria(), true);
2937
}
3038

3139
public boolean isProviderEnabled() {
3240
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
3341
}
3442

35-
public LatLng getLastLocation() {
36-
return lastLocation;
43+
public boolean isLocationPermissionGranted() {
44+
return ContextCompat.checkSelfPermission(context,
45+
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
3746
}
3847

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

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

68148
/** Unregisters location manager.
69149
*/
70150
public void unregisterLocationManager() {
151+
isLocationManagerRegistered = false;
71152
try {
72153
locationManager.removeUpdates(this);
73154
} catch (SecurityException e) {
@@ -87,15 +168,11 @@ public void removeLocationListener(LocationUpdateListener listener) {
87168

88169
@Override
89170
public void onLocationChanged(Location location) {
90-
double currentLatitude = location.getLatitude();
91-
double currentLongitude = location.getLongitude();
92-
latestLocationAccuracy = location.getAccuracy();
93-
Timber.d("Latitude: %f Longitude: %f Accuracy %f",
94-
currentLatitude, currentLongitude, latestLocationAccuracy);
95-
lastLocation = new LatLng(currentLatitude, currentLongitude, latestLocationAccuracy);
96-
97-
for (LocationUpdateListener listener : locationListeners) {
98-
listener.onLocationChanged(lastLocation);
171+
if (isBetterLocation(location, lastLocation)) {
172+
lastLocation = location;
173+
for (LocationUpdateListener listener : locationListeners) {
174+
listener.onLocationChanged(LatLng.from(lastLocation));
175+
}
99176
}
100177
}
101178

0 commit comments

Comments
 (0)