diff --git a/app/src/main/java/net/voussoir/trkpt/Database.kt b/app/src/main/java/net/voussoir/trkpt/Database.kt index 44a2b43..3833da6 100644 --- a/app/src/main/java/net/voussoir/trkpt/Database.kt +++ b/app/src/main/java/net/voussoir/trkpt/Database.kt @@ -95,21 +95,31 @@ class Database(val trackbook: Trackbook) } } - fun select_trkpt_start_end(device_id: String, start_time: Long, end_time: Long, order: String="ASC"): Iterator + fun select_trkpt_start_end(device_id: String, start_time: Long, end_time: Long, max_accuracy: Float=Keys.DEFAULT_MAX_ACCURACY, order: String="ASC"): Iterator { Log.i("VOUSSOIR", "Track.trkpt_generator: Querying points between ${start_time} -- ${end_time}.") return _trkpt_generator(this.connection.rawQuery( - "SELECT device_id, lat, lon, time, provider, ele, accuracy, sat FROM trkpt WHERE device_id = ? AND time >= ? AND time <= ? ORDER BY time ${order}", - arrayOf(device_id, start_time.toString(), end_time.toString()) + """ + SELECT device_id, lat, lon, time, provider, ele, accuracy, sat + FROM trkpt + WHERE device_id = ? AND time >= ? AND time <= ? AND accuracy <= ? + ORDER BY time ${order} + """, + arrayOf(device_id, start_time.toString(), end_time.toString(), max_accuracy.toString()) )) } - fun select_trkpt_bounding_box(device_id: String, north: Double, south: Double, east: Double, west: Double): Iterator + fun select_trkpt_bounding_box(device_id: String, north: Double, south: Double, east: Double, west: Double, max_accuracy: Float=Keys.DEFAULT_MAX_ACCURACY): Iterator { Log.i("VOUSSOIR", "Track.trkpt_generator: Querying points between $north, $south, $east, $west.") return _trkpt_generator(this.connection.rawQuery( - "SELECT device_id, lat, lon, time, provider, ele, accuracy, sat FROM trkpt WHERE device_id = ? AND lat >= ? AND lat <= ? AND lon >= ? AND lon <= ? ORDER BY time ASC", - arrayOf(device_id, south.toString(), north.toString(), west.toString(), east.toString()) + """ + SELECT device_id, lat, lon, time, provider, ele, accuracy, sat + FROM trkpt + WHERE device_id = ? AND lat >= ? AND lat <= ? AND lon >= ? AND lon <= ? AND accuracy <= ? + ORDER BY time ASC + """, + arrayOf(device_id, south.toString(), north.toString(), west.toString(), east.toString(), max_accuracy.toString()) )) } diff --git a/app/src/main/java/net/voussoir/trkpt/Keys.kt b/app/src/main/java/net/voussoir/trkpt/Keys.kt index 9929c00..98abd5f 100644 --- a/app/src/main/java/net/voussoir/trkpt/Keys.kt +++ b/app/src/main/java/net/voussoir/trkpt/Keys.kt @@ -64,6 +64,7 @@ object Keys { const val PREF_SHOW_DEBUG: String = "prefShowDebug" const val PREF_DEVICE_ID: String = "prefDeviceID" const val PREF_DATABASE_DIRECTORY: String = "prefDatabaseDirectory" + const val PREF_MAX_ACCURACY: String = "prefMaxAccuracy" // states const val STATE_TRACKING_STOPPED: Int = 0 @@ -102,13 +103,13 @@ object Keys { const val DEFAULT_ALTITUDE: Double = 0.0 const val DEFAULT_TIME: Long = 0L const val COMMIT_INTERVAL: Long = 30 * ONE_SECOND_IN_MILLISECONDS - const val DEFAULT_THRESHOLD_LOCATION_ACCURACY: Int = 30 // 30 meters const val DEFAULT_THRESHOLD_LOCATION_AGE: Long = 5_000_000_000L // 5s in nanoseconds const val DEFAULT_THRESHOLD_DISTANCE: Float = 15f // 15 meters const val DEFAULT_ZOOM_LEVEL: Double = 16.0 const val DEFAULT_OMIT_RESTS: Boolean = true const val DEFAULT_ALLOW_SLEEP: Boolean = true const val DEFAULT_SHOW_DEBUG: Boolean = false + const val DEFAULT_MAX_ACCURACY: Float = 30f // notification const val TRACKER_SERVICE_NOTIFICATION_ID: Int = 1 diff --git a/app/src/main/java/net/voussoir/trkpt/SettingsFragment.kt b/app/src/main/java/net/voussoir/trkpt/SettingsFragment.kt index e8e5ad4..68d1df5 100644 --- a/app/src/main/java/net/voussoir/trkpt/SettingsFragment.kt +++ b/app/src/main/java/net/voussoir/trkpt/SettingsFragment.kt @@ -32,13 +32,7 @@ import android.provider.Settings import android.util.Log import android.view.View import androidx.activity.result.contract.ActivityResultContracts -import androidx.preference.EditTextPreference -import androidx.preference.ListPreference -import androidx.preference.Preference -import androidx.preference.PreferenceCategory -import androidx.preference.PreferenceFragmentCompat -import androidx.preference.SwitchPreferenceCompat -import androidx.preference.contains +import androidx.preference.* import get_path_from_uri import net.voussoir.trkpt.helpers.AppThemeHelper import net.voussoir.trkpt.helpers.LengthUnitHelper @@ -139,6 +133,23 @@ class SettingsFragment : PreferenceFragmentCompat() preferenceCategoryGeneral.contains(prefAllowSleep) screen.addPreference(prefAllowSleep) + val prefMaxAccuracy = SeekBarPreference(activity as Context) + prefMaxAccuracy.title = getString(R.string.pref_max_accuracy_title) + prefMaxAccuracy.setIcon(R.drawable.ic_bullseye_24dp) + prefMaxAccuracy.key = Keys.PREF_MAX_ACCURACY + prefMaxAccuracy.summary = getString(R.string.pref_max_accuracy_summary) + "\n${PreferencesHelper.load_max_accuracy()} m" + prefMaxAccuracy.showSeekBarValue = true + prefMaxAccuracy.min = 0 + prefMaxAccuracy.max = 500 + prefMaxAccuracy.setDefaultValue((Keys.DEFAULT_MAX_ACCURACY * 10).toInt()) + prefMaxAccuracy.setOnPreferenceChangeListener { preference, newValue -> + val floated = (newValue as Int) / 10f + prefMaxAccuracy.summary = getString(R.string.pref_max_accuracy_summary) + "\n${floated} m" + return@setOnPreferenceChangeListener true + } + preferenceCategoryGeneral.contains(prefMaxAccuracy) + screen.addPreference(prefMaxAccuracy) + val prefShowDebug = SwitchPreferenceCompat(activity as Context) prefShowDebug.isSingleLineTitle = false prefShowDebug.title = getString(R.string.pref_show_debug_title) diff --git a/app/src/main/java/net/voussoir/trkpt/TrackFragment.kt b/app/src/main/java/net/voussoir/trkpt/TrackFragment.kt index e031fb6..113409e 100644 --- a/app/src/main/java/net/voussoir/trkpt/TrackFragment.kt +++ b/app/src/main/java/net/voussoir/trkpt/TrackFragment.kt @@ -154,6 +154,7 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener device_id= this.requireArguments().getString(Keys.ARG_TRACK_DEVICE_ID, ""), start_time=requested_start_time, end_time=requested_end_time, + max_accuracy=PreferencesHelper.load_max_accuracy(), )) rootView = inflater.inflate(R.layout.fragment_track, container, false) mapView = rootView.findViewById(R.id.map) @@ -285,8 +286,9 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener set_datetime(track_query_start_date, track_query_start_time, Date(selected.time), _ending=false) track.load_trkpts(trackbook.database.select_trkpt_start_end( track.device_id, - selected.time, - track.trkpts.last().time, + start_time=selected.time, + end_time=track.trkpts.last().time, + max_accuracy=PreferencesHelper.load_max_accuracy(), )) deselect_trkpt() render_track() @@ -302,8 +304,9 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener set_datetime(track_query_end_date, track_query_end_time, Date(selected.time), _ending=true) track.load_trkpts(trackbook.database.select_trkpt_start_end( track.device_id, - track.trkpts.first().time, - selected.time, + start_time=track.trkpts.first().time, + end_time=selected.time, + max_accuracy=PreferencesHelper.load_max_accuracy(), )) deselect_trkpt() render_track() @@ -321,8 +324,9 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener { track.load_trkpts(trackbook.database.select_trkpt_start_end( track.device_id, - (polyline.actualPoints.first() as Trkpt).time, - (polyline.actualPoints.last() as Trkpt).time, + start_time=(polyline.actualPoints.first() as Trkpt).time, + end_time=(polyline.actualPoints.last() as Trkpt).time, + max_accuracy=PreferencesHelper.load_max_accuracy(), )) track.expand_to_trkseg_bounds() @@ -342,6 +346,7 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener south=mapView.boundingBox.actualSouth, east=mapView.boundingBox.lonEast, west=mapView.boundingBox.lonWest, + max_accuracy=PreferencesHelper.load_max_accuracy(), )) set_datetimes_from_track() render_track() @@ -776,6 +781,7 @@ class TrackFragment : Fragment(), MapListener, YesNoDialog.YesNoDialogListener track.device_id, start_time=get_datetime(track_query_start_date, track_query_start_time, seconds=0).time, end_time=get_datetime(track_query_end_date, track_query_end_time, seconds=59).time, + max_accuracy=PreferencesHelper.load_max_accuracy(), )) Log.i("VOUSSOIR", "TrackFragment.requery_and_render: Reloaded ${track.trkpts.size} trkpts.") render_track() diff --git a/app/src/main/java/net/voussoir/trkpt/TrackerService.kt b/app/src/main/java/net/voussoir/trkpt/TrackerService.kt index fa3f28c..a9aa837 100644 --- a/app/src/main/java/net/voussoir/trkpt/TrackerService.kt +++ b/app/src/main/java/net/voussoir/trkpt/TrackerService.kt @@ -28,8 +28,6 @@ import android.hardware.* import android.location.Location import android.location.LocationListener import android.location.LocationManager -import android.media.AudioManager -import android.media.ToneGenerator import android.os.* import android.util.Log import androidx.annotation.RequiresApi @@ -48,6 +46,7 @@ class TrackerService: Service() var trackingState: Int = Keys.STATE_TRACKING_STOPPED var useImperial: Boolean = false var omitRests: Boolean = true + var max_accuracy: Float = Keys.DEFAULT_MAX_ACCURACY var allow_sleep: Boolean = true var device_id: String = random_device_id() var currentBestLocation: Location = getDefaultLocation() @@ -318,11 +317,6 @@ class TrackerService: Service() Log.i("VOUSSOIR", "Omitting due to not recent enough.") return } - if (! isAccurateEnough(location, Keys.DEFAULT_THRESHOLD_LOCATION_ACCURACY)) - { - Log.i("VOUSSOIR", "Omitting due to not accurate enough.") - return - } if (recent_displacement_locations.isEmpty()) { // pass @@ -341,7 +335,10 @@ class TrackerService: Service() val trkpt = Trkpt(device_id=device_id, location=location) trackbook.database.insert_trkpt(trkpt, commit=false) - recent_trackpoints_for_mapview.add(trkpt) + if (trkpt.accuracy <= max_accuracy) + { + recent_trackpoints_for_mapview.add(trkpt) + } while (recent_trackpoints_for_mapview.size > RECENT_TRKPT_COUNT) { recent_trackpoints_for_mapview.removeFirst() @@ -679,6 +676,10 @@ class TrackerService: Service() { omitRests = PreferencesHelper.loadOmitRests() } + Keys.PREF_MAX_ACCURACY -> + { + max_accuracy = PreferencesHelper.load_max_accuracy() + } Keys.PREF_ALLOW_SLEEP -> { allow_sleep = PreferencesHelper.loadAllowSleep() diff --git a/app/src/main/java/net/voussoir/trkpt/helpers/PreferencesHelper.kt b/app/src/main/java/net/voussoir/trkpt/helpers/PreferencesHelper.kt index 08b9e6a..ee2626c 100644 --- a/app/src/main/java/net/voussoir/trkpt/helpers/PreferencesHelper.kt +++ b/app/src/main/java/net/voussoir/trkpt/helpers/PreferencesHelper.kt @@ -106,6 +106,10 @@ object PreferencesHelper return sharedPreferences.getBoolean(Keys.PREF_SHOW_DEBUG, Keys.DEFAULT_SHOW_DEBUG) } + fun load_max_accuracy(): Float { + return sharedPreferences.getInt(Keys.PREF_MAX_ACCURACY, Keys.DEFAULT_MAX_ACCURACY.toInt() * 10) / 10f + } + /* Loads the state of a map */ fun loadCurrentBestLocation(): Location { val provider: String = sharedPreferences.getString(Keys.PREF_CURRENT_BEST_LOCATION_PROVIDER, LocationManager.NETWORK_PROVIDER) ?: LocationManager.NETWORK_PROVIDER diff --git a/app/src/main/res/drawable/ic_bullseye_24dp.xml b/app/src/main/res/drawable/ic_bullseye_24dp.xml new file mode 100644 index 0000000..6e8dcf7 --- /dev/null +++ b/app/src/main/res/drawable/ic_bullseye_24dp.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 97cd37e..f310bb2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -125,6 +125,8 @@ Thank you y20k. Map data © OpenStreetMap contributors. + Filter inaccurate points + Points with accuracy worse than this will be hidden (but still saved). Small numbers are highly accurate. hrs