Skip to content

Commit dd74a99

Browse files
authored
Merge pull request #3495 from dimagi/copyLocationImprovements
[Hotfix] Discard stale locations based on an App Setting
2 parents 01def49 + 4f0b903 commit dd74a99

File tree

6 files changed

+68
-9
lines changed

6 files changed

+68
-9
lines changed

app/src/org/commcare/activities/GeoPointActivity.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package org.commcare.activities;
22

3+
import static org.commcare.location.CommCareLocationControllerKt.DEFAULT_TIME_THRESHOLD;
4+
import static org.commcare.location.CommCareLocationControllerKt.isLocationFresh;
5+
import static org.commcare.location.CommCareLocationControllerKt.logStaleLocationSaved;
6+
37
import android.Manifest;
48
import android.content.DialogInterface;
59
import android.content.Intent;
@@ -27,6 +31,7 @@
2731
import org.commcare.views.dialogs.CommCareAlertDialog;
2832
import org.commcare.views.dialogs.DialogCreationHelpers;
2933
import org.commcare.views.dialogs.GeoProgressDialog;
34+
import org.javarosa.core.services.Logger;
3035
import org.javarosa.core.services.locale.Localization;
3136
import org.jetbrains.annotations.NotNull;
3237

@@ -182,6 +187,7 @@ private void setupLocationDialog() {
182187

183188
private void returnLocation() {
184189
if (location != null) {
190+
logStaleLocationSaved(location);
185191
Intent i = new Intent();
186192
i.putExtra(FormEntryConstants.LOCATION_RESULT, GeoUtils.locationToString(location));
187193
setResult(RESULT_OK, i);

app/src/org/commcare/android/javarosa/PollSensorAction.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package org.commcare.android.javarosa;
22

3+
import static org.commcare.location.CommCareLocationControllerKt.DEFAULT_TIME_THRESHOLD;
4+
import static org.commcare.location.CommCareLocationControllerKt.isLocationFresh;
5+
import static org.commcare.location.CommCareLocationControllerKt.logStaleLocationSaved;
6+
37
import android.content.Context;
48
import android.content.Intent;
59
import android.location.Location;
@@ -14,6 +18,7 @@
1418
import org.javarosa.core.model.data.IAnswerData;
1519
import org.javarosa.core.model.instance.AbstractTreeElement;
1620
import org.javarosa.core.model.instance.TreeReference;
21+
import org.javarosa.core.services.Logger;
1722
import org.javarosa.core.util.externalizable.DeserializationException;
1823
import org.javarosa.core.util.externalizable.ExtUtil;
1924
import org.javarosa.core.util.externalizable.ExtWrapNullable;
@@ -64,6 +69,7 @@ public TreeReference processAction(FormDef model, TreeReference contextRef) {
6469

6570
void updateReference(Location location) {
6671
if (target != null) {
72+
logStaleLocationSaved(location);
6773
String result = GeoUtils.locationToString(location);
6874
TreeReference qualifiedReference = contextRef == null ? target : target.contextualize(contextRef);
6975
EvaluationContext context = new EvaluationContext(formDef.getEvaluationContext(), qualifiedReference);

app/src/org/commcare/location/CommCareFusedLocationController.kt

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.commcare.location
22

3+
import android.annotation.SuppressLint
34
import android.content.BroadcastReceiver
45
import android.content.Context
56
import android.content.Intent
@@ -12,7 +13,10 @@ import com.google.android.gms.location.LocationRequest
1213
import com.google.android.gms.location.LocationResult
1314
import com.google.android.gms.location.LocationServices
1415
import com.google.android.gms.location.LocationSettingsRequest
16+
import com.google.android.gms.location.Priority
17+
import org.commcare.util.LogTypes
1518
import org.commcare.utils.GeoUtils.locationServicesEnabledGlobally
19+
import org.javarosa.core.services.Logger
1620

1721
/**
1822
* @author $|-|!˅@M
@@ -25,15 +29,18 @@ class CommCareFusedLocationController(
2529
private val settingsClient = LocationServices.getSettingsClient(mContext!!)
2630
private val mLocationServiceChangeReceiver = LocationChangeReceiverBroadcast()
2731
private val mLocationRequest =
28-
LocationRequest.create().apply {
29-
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
30-
interval = LOCATION_UPDATE_INTERVAL
31-
}
32+
LocationRequest
33+
.Builder(Priority.PRIORITY_HIGH_ACCURACY, LOCATION_UPDATE_INTERVAL)
34+
.build()
3235
private var mCurrentLocation: Location? = null
3336
private val mLocationCallback =
3437
object : LocationCallback() {
3538
override fun onLocationResult(result: LocationResult) {
36-
result ?: return
39+
result.lastLocation ?: return
40+
Logger.log(LogTypes.TYPE_MAINTENANCE, "Received location update")
41+
if (shouldDiscardLocation(result.lastLocation!!)) {
42+
return
43+
}
3744
mCurrentLocation = result.lastLocation
3845
mListener?.onLocationResult(mCurrentLocation!!)
3946
}
@@ -43,6 +50,7 @@ class CommCareFusedLocationController(
4350
const val LOCATION_UPDATE_INTERVAL = 5000L
4451
}
4552

53+
@SuppressLint("MissingPermission")
4654
private fun requestUpdates() {
4755
if (isLocationPermissionGranted(mContext)) {
4856
mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallback, null)

app/src/org/commcare/location/CommCareLocationController.kt

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import android.content.pm.PackageManager
66
import android.location.Location
77
import androidx.core.content.ContextCompat
88
import org.commcare.CommCareApplication
9+
import org.commcare.preferences.HiddenPreferences
10+
import org.javarosa.core.services.Logger
911

1012
/**
1113
* @author $|-|!˅@M
@@ -17,8 +19,34 @@ interface CommCareLocationController {
1719
fun destroy()
1820
}
1921

20-
fun CommCareLocationController.isLocationPermissionGranted(mContext: Context?): Boolean {
22+
const val DEFAULT_TIME_THRESHOLD = 2 * 60 * 1000L // 2 minutes in milliseconds
23+
24+
fun isLocationPermissionGranted(mContext: Context?): Boolean {
2125
val context = mContext ?: CommCareApplication.instance()
2226
return ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
2327
ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
2428
}
29+
30+
fun isLocationFresh(location: Location, maxAgeMs: Long = DEFAULT_TIME_THRESHOLD): Boolean {
31+
return System.currentTimeMillis() - location.time <= maxAgeMs
32+
}
33+
34+
fun shouldDiscardLocation(location: Location): Boolean {
35+
if(!isLocationFresh(location)) {
36+
Logger.exception("Received a stale location", getStaleLocationException(location))
37+
return HiddenPreferences.shouldDiscardStaleLocations()
38+
}
39+
return false
40+
}
41+
42+
fun getStaleLocationException(location: Location): Throwable =
43+
Exception(
44+
"Stale location with accuracy ${location.accuracy}" +
45+
" with time ${location.time}" + " and current device time ${System.currentTimeMillis()}"
46+
)
47+
48+
fun logStaleLocationSaved(location: Location) {
49+
if (!isLocationFresh(location, DEFAULT_TIME_THRESHOLD)) {
50+
Logger.exception("Stale location saved in GPS capture", getStaleLocationException(location))
51+
}
52+
}

app/src/org/commcare/location/CommCareProviderLocationController.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ import android.location.LocationListener
99
import android.location.LocationManager
1010
import android.os.Build
1111
import android.os.Bundle
12-
import androidx.annotation.RequiresApi
12+
import org.commcare.util.LogTypes
1313
import org.commcare.utils.GeoUtils
14+
import org.javarosa.core.services.Logger
1415

1516
/**
1617
* @author $|-|!˅@M
@@ -25,7 +26,10 @@ class CommCareProviderLocationController(private var mContext: Context?,
2526
private var mLocationRequestStarted = false
2627
private val mLocationListener = object: LocationListener {
2728
override fun onLocationChanged(location: Location) {
28-
location ?: return
29+
Logger.log(LogTypes.TYPE_MAINTENANCE, "Received location update")
30+
if (shouldDiscardLocation(location)) {
31+
return
32+
}
2933
mCurrentLocation = location
3034
mListener?.onLocationResult(mCurrentLocation!!)
3135
}
@@ -105,4 +109,4 @@ class CommCareProviderLocationController(private var mContext: Context?,
105109
}
106110
}
107111

108-
}
112+
}

app/src/org/commcare/preferences/HiddenPreferences.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ public class HiddenPreferences {
110110
private static final String ENABLE_BACKGROUND_SYNC = "cc-enable-background-sync";
111111

112112
private static final String ENABLE_CUSTOM_MAP_MARKER = "cc-enable-custom-map-marker";
113+
private static final String DISCARD_STALE_LOCATIONS = "cc-discard-stale-locations";
113114

114115
/**
115116
* The domain name in the application profile file comes in the <domain>.commcarehq.org form,
@@ -670,4 +671,10 @@ public static void clearInterruptedFormState() {
670671
.remove(INTERRUPTED_FORM_INDEX + currentUserId)
671672
.apply();
672673
}
674+
675+
public static boolean shouldDiscardStaleLocations() {
676+
SharedPreferences properties = CommCareApplication.instance().getCurrentApp().getAppPreferences();
677+
return properties.getString(DISCARD_STALE_LOCATIONS, PrefValues.NO).equals(PrefValues.YES);
678+
}
679+
673680
}

0 commit comments

Comments
 (0)