checkpoint

master
voussoir 2023-03-12 22:09:58 -07:00
parent 8cbfa729f0
commit aca4cf20c0
7 changed files with 52 additions and 57 deletions

View File

@ -6,9 +6,8 @@ import android.util.Log
import java.io.File import java.io.File
import java.util.* import java.util.*
class Database(trackbook: Trackbook) class Database(val trackbook: Trackbook)
{ {
val trackbook = trackbook
var ready: Boolean = false var ready: Boolean = false
lateinit var file: File lateinit var file: File
lateinit var connection: SQLiteDatabase lateinit var connection: SQLiteDatabase
@ -96,8 +95,12 @@ class Database(trackbook: Trackbook)
fun update_homepoint(id: Long, name: String, radius: Double) fun update_homepoint(id: Long, name: String, radius: Double)
{ {
Log.i("VOUSSOIR", "Database.update_homepoint") Log.i("VOUSSOIR", "Database.update_homepoint")
val values = ContentValues().apply {
put("name", name)
put("radius", radius)
}
begin_transaction() begin_transaction()
connection.rawQuery("UPDATE homepoints SET name = ?, radius = ? WHERE id = ?", arrayOf(name, radius.toString(), id.toString())) connection.update("homepoints", values, "id = ?", arrayOf(id.toString()))
commit() commit()
} }
@ -107,6 +110,7 @@ class Database(trackbook: Trackbook)
this.connection.execSQL("CREATE TABLE IF NOT EXISTS meta(name TEXT PRIMARY KEY, value TEXT)") this.connection.execSQL("CREATE TABLE IF NOT EXISTS meta(name TEXT PRIMARY KEY, value TEXT)")
this.connection.execSQL("CREATE TABLE IF NOT EXISTS trkpt(lat REAL NOT NULL, lon REAL NOT NULL, time INTEGER NOT NULL, accuracy REAL, device_id INTEGER NOT NULL, ele INTEGER, sat INTEGER, PRIMARY KEY(lat, lon, time, device_id))") this.connection.execSQL("CREATE TABLE IF NOT EXISTS trkpt(lat REAL NOT NULL, lon REAL NOT NULL, time INTEGER NOT NULL, accuracy REAL, device_id INTEGER NOT NULL, ele INTEGER, sat INTEGER, PRIMARY KEY(lat, lon, time, device_id))")
this.connection.execSQL("CREATE TABLE IF NOT EXISTS homepoints(id INTEGER PRIMARY KEY, lat REAL NOT NULL, lon REAL NOT NULL, radius REAL NOT NULL, name TEXT)") this.connection.execSQL("CREATE TABLE IF NOT EXISTS homepoints(id INTEGER PRIMARY KEY, lat REAL NOT NULL, lon REAL NOT NULL, radius REAL NOT NULL, name TEXT)")
this.connection.execSQL("PRAGMA user_version = ${Keys.CURRENT_TRACKLIST_FORMAT_VERSION}")
this.connection.setTransactionSuccessful() this.connection.setTransactionSuccessful()
this.connection.endTransaction() this.connection.endTransaction()
} }

View File

@ -77,18 +77,9 @@ object Keys {
const val DIALOG_EMPTY_PAYLOAD_STRING: String = "" const val DIALOG_EMPTY_PAYLOAD_STRING: String = ""
const val DIALOG_EMPTY_PAYLOAD_INT: Int = -1 const val DIALOG_EMPTY_PAYLOAD_INT: Int = -1
// folder names
const val FOLDER_TEMP: String = "temp"
const val FOLDER_TRACKS: String = "tracks"
const val FOLDER_GPX: String = "gpx"
// file names and extensions // file names and extensions
const val MIME_TYPE_GPX: String = "application/gpx+xml" const val MIME_TYPE_GPX: String = "application/gpx+xml"
const val GPX_FILE_EXTENSION: String = ".gpx" const val GPX_FILE_EXTENSION: String = ".gpx"
const val TRACKBOOK_LEGACY_FILE_EXTENSION: String = ".trackbook"
const val TRACKBOOK_FILE_EXTENSION: String = ".json"
const val TEMP_FILE: String = "temp.json"
const val TRACKLIST_FILE: String = "tracklist.json"
// view types // view types
const val VIEW_TYPE_STATISTICS: Int = 1 const val VIEW_TYPE_STATISTICS: Int = 1
@ -96,13 +87,11 @@ object Keys {
// default values // default values
val DEFAULT_DATE: Date = Date(0L) val DEFAULT_DATE: Date = Date(0L)
const val DEFAULT_RFC2822_DATE: String = "Thu, 01 Jan 1970 01:00:00 +0100" // --> Date(0)
const val ONE_SECOND_IN_MILLISECONDS: Long = 1000 const val ONE_SECOND_IN_MILLISECONDS: Long = 1000
const val ONE_MINUTE_IN_MILLISECONDS: Long = 60 * ONE_SECOND_IN_MILLISECONDS const val ONE_MINUTE_IN_MILLISECONDS: Long = 60 * ONE_SECOND_IN_MILLISECONDS
const val ONE_HOUR_IN_MILLISECONDS: Long = 60 * ONE_MINUTE_IN_MILLISECONDS const val ONE_HOUR_IN_MILLISECONDS: Long = 60 * ONE_MINUTE_IN_MILLISECONDS
const val EMPTY_STRING_RESOURCE: Int = 0 const val EMPTY_STRING_RESOURCE: Int = 0
const val REQUEST_CURRENT_LOCATION_INTERVAL: Long = 1 * ONE_SECOND_IN_MILLISECONDS const val REQUEST_CURRENT_LOCATION_INTERVAL: Long = 1 * ONE_SECOND_IN_MILLISECONDS
const val TRACKING_INTERVAL: Long = 1 * ONE_SECOND_IN_MILLISECONDS
const val SAVE_TEMP_TRACK_INTERVAL: Long = 30 * ONE_SECOND_IN_MILLISECONDS const val SAVE_TEMP_TRACK_INTERVAL: Long = 30 * ONE_SECOND_IN_MILLISECONDS
const val SIGNIFICANT_TIME_DIFFERENCE: Long = 1 * ONE_MINUTE_IN_MILLISECONDS const val SIGNIFICANT_TIME_DIFFERENCE: Long = 1 * ONE_MINUTE_IN_MILLISECONDS
const val STOP_OVER_THRESHOLD: Long = 5 * ONE_MINUTE_IN_MILLISECONDS const val STOP_OVER_THRESHOLD: Long = 5 * ONE_MINUTE_IN_MILLISECONDS
@ -113,7 +102,6 @@ object Keys {
const val DEFAULT_ALTITUDE: Double = 0.0 const val DEFAULT_ALTITUDE: Double = 0.0
const val DEFAULT_TIME: Long = 0L const val DEFAULT_TIME: Long = 0L
const val COMMIT_INTERVAL: Int = 30 const val COMMIT_INTERVAL: Int = 30
const val DEFAULT_ALTITUDE_SMOOTHING_VALUE: Int = 13
const val DEFAULT_THRESHOLD_LOCATION_ACCURACY: Int = 30 // 30 meters 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_LOCATION_AGE: Long = 5_000_000_000L // 5s in nanoseconds
const val DEFAULT_THRESHOLD_DISTANCE: Float = 15f // 15 meters const val DEFAULT_THRESHOLD_DISTANCE: Float = 15f // 15 meters

View File

@ -138,6 +138,7 @@ class MapFragment : Fragment()
// basic map setup // basic map setup
controller = mapView.controller controller = mapView.controller
mapView.isTilesScaledToDpi = true mapView.isTilesScaledToDpi = true
mapView.isVerticalMapRepetitionEnabled = false
mapView.setTileSource(TileSourceFactory.MAPNIK) mapView.setTileSource(TileSourceFactory.MAPNIK)
mapView.setMultiTouchControls(true) mapView.setMultiTouchControls(true)
mapView.zoomController.setVisibility(org.osmdroid.views.CustomZoomButtonsController.Visibility.NEVER) mapView.zoomController.setVisibility(org.osmdroid.views.CustomZoomButtonsController.Visibility.NEVER)
@ -538,7 +539,8 @@ class MapFragment : Fragment()
dialog.dismiss() dialog.dismiss()
} }
save_button.setOnClickListener { save_button.setOnClickListener {
trackbook.database.update_homepoint(homepoint.id, name=name_input.text.toString(), radius=radius_input.text.toString().toDouble()) val radius = radius_input.text.toString().toDoubleOrNull() ?: 25.0
trackbook.database.update_homepoint(homepoint.id, name=name_input.text.toString(), radius=radius)
trackbook.load_homepoints() trackbook.load_homepoints()
create_homepoint_overlays(requireContext(), mapView, trackbook.homepoints) create_homepoint_overlays(requireContext(), mapView, trackbook.homepoints)
dialog.dismiss() dialog.dismiss()
@ -568,8 +570,8 @@ class MapFragment : Fragment()
mapView.overlays.remove(currentTrackSpecialMarkerOverlay) mapView.overlays.remove(currentTrackSpecialMarkerOverlay)
} }
if (trkpts.isNotEmpty()) { if (trkpts.isNotEmpty()) {
createTrackOverlay(requireContext(), mapView, trkpts, trackingState) currentTrackOverlay = createTrackOverlay(requireContext(), mapView, trkpts, trackingState)
createSpecialMakersTrackOverlay(requireContext(), mapView, trkpts, trackingState) currentTrackSpecialMarkerOverlay = createSpecialMakersTrackOverlay(requireContext(), mapView, trkpts, trackingState)
} }
} }

View File

@ -85,7 +85,7 @@ data class Track (
var previous: Trkpt? = null var previous: Trkpt? = null
for (trkpt in trkpt_generator()) for (trkpt in trkpt_generator())
{ {
if (previous != null && (trkpt.time - previous.time) > (5 * Keys.ONE_MINUTE_IN_MILLISECONDS)) if (previous != null && (trkpt.time - previous.time) > (Keys.STOP_OVER_THRESHOLD))
{ {
write("\t\t</trkseg>") write("\t\t</trkseg>")
write("\t\t<trkseg>") write("\t\t<trkseg>")

View File

@ -57,7 +57,7 @@ class TrackerService: Service(), SensorEventListener
var recording_started: Date = GregorianCalendar.getInstance().time var recording_started: Date = GregorianCalendar.getInstance().time
var commitInterval: Int = Keys.COMMIT_INTERVAL var commitInterval: Int = Keys.COMMIT_INTERVAL
var currentBestLocation: Location = getDefaultLocation() var currentBestLocation: Location = getDefaultLocation()
var lastCommit: Date = Keys.DEFAULT_DATE var lastCommit: Long = 0
var location_min_time_ms: Long = 0 var location_min_time_ms: Long = 0
private val RECENT_TRKPT_COUNT = 7200 private val RECENT_TRKPT_COUNT = 7200
var stepCountOffset: Float = 0f var stepCountOffset: Float = 0f
@ -150,9 +150,36 @@ class TrackerService: Service(), SensorEventListener
return object : LocationListener { return object : LocationListener {
override fun onLocationChanged(location: Location) override fun onLocationChanged(location: Location)
{ {
if (isBetterLocation(location, currentBestLocation)) { if (! isBetterLocation(location, currentBestLocation))
currentBestLocation = location {
return
} }
currentBestLocation = location
if (trackingState != Keys.STATE_TRACKING_ACTIVE)
{
return
}
Log.i("VOUSSOIR", "Processing point ${location.latitude}, ${location.longitude} ${location.time}.")
if (should_keep_point((location)))
{
val now: Long = location.time
// val now: Date = GregorianCalendar.getInstance().time
val trkpt = Trkpt(location=location)
trackbook.database.insert_trkpt(device_id, trkpt)
recent_trkpts.add(trkpt)
while (recent_trkpts.size > RECENT_TRKPT_COUNT)
{
recent_trkpts.removeFirst()
}
if (now - lastCommit > Keys.SAVE_TEMP_TRACK_INTERVAL)
{
trackbook.database.commit()
lastCommit = now
}
}
displayNotification()
} }
override fun onProviderEnabled(provider: String) override fun onProviderEnabled(provider: String)
{ {
@ -353,7 +380,6 @@ class TrackerService: Service(), SensorEventListener
} }
PreferencesHelper.saveTrackingState(trackingState) PreferencesHelper.saveTrackingState(trackingState)
startStepCounter() startStepCounter()
handler.postDelayed(periodicTrackUpdate, 0)
startForeground(Keys.TRACKER_SERVICE_NOTIFICATION_ID, displayNotification()) startForeground(Keys.TRACKER_SERVICE_NOTIFICATION_ID, displayNotification())
} }
@ -365,7 +391,6 @@ class TrackerService: Service(), SensorEventListener
PreferencesHelper.saveTrackingState(trackingState) PreferencesHelper.saveTrackingState(trackingState)
sensorManager.unregisterListener(this) sensorManager.unregisterListener(this)
handler.removeCallbacks(periodicTrackUpdate)
displayNotification() displayNotification()
stopForeground(STOP_FOREGROUND_DETACH) stopForeground(STOP_FOREGROUND_DETACH)
@ -452,31 +477,4 @@ class TrackerService: Service(), SensorEventListener
} }
return true return true
} }
private val periodicTrackUpdate: Runnable = object : Runnable
{
override fun run() {
val now: Date = GregorianCalendar.getInstance().time
val trkpt = Trkpt(location=currentBestLocation)
Log.i("VOUSSOIR", "Processing point ${currentBestLocation.latitude}, ${currentBestLocation.longitude} ${now.time}.")
if (should_keep_point((currentBestLocation)))
{
trackbook.database.insert_trkpt(device_id, trkpt)
recent_trkpts.add(trkpt)
while (recent_trkpts.size > RECENT_TRKPT_COUNT)
{
recent_trkpts.removeFirst()
}
if (now.time - lastCommit.time > Keys.SAVE_TEMP_TRACK_INTERVAL)
{
trackbook.database.commit()
lastCommit = now
}
}
displayNotification()
handler.postDelayed(this, Keys.TRACKING_INTERVAL)
}
}
} }

View File

@ -37,7 +37,7 @@ import java.text.SimpleDateFormat
import java.util.* import java.util.*
/* Creates icon overlay for track */ /* Creates icon overlay for track */
fun createTrackOverlay(context: Context, map_view: MapView, trkpts: Collection<Trkpt>, trackingState: Int) fun createTrackOverlay(context: Context, map_view: MapView, trkpts: Collection<Trkpt>, trackingState: Int): SimpleFastPointOverlay
{ {
val color = if (trackingState == Keys.STATE_TRACKING_ACTIVE) context.getColor(R.color.default_red) else context.getColor(R.color.default_blue) val color = if (trackingState == Keys.STATE_TRACKING_ACTIVE) context.getColor(R.color.default_red) else context.getColor(R.color.default_blue)
val points: MutableList<IGeoPoint> = mutableListOf() val points: MutableList<IGeoPoint> = mutableListOf()
@ -64,10 +64,11 @@ fun createTrackOverlay(context: Context, map_view: MapView, trkpts: Collection<T
.setCellSize(12) // Sets the grid cell size used for indexing, in pixels. Larger cells result in faster rendering speed, but worse fidelity. Default is 10 pixels, for large datasets (>10k points), use 15. .setCellSize(12) // Sets the grid cell size used for indexing, in pixels. Larger cells result in faster rendering speed, but worse fidelity. Default is 10 pixels, for large datasets (>10k points), use 15.
val overlay = SimpleFastPointOverlay(pointTheme, overlayOptions) val overlay = SimpleFastPointOverlay(pointTheme, overlayOptions)
map_view.overlays.add(overlay) map_view.overlays.add(overlay)
return overlay
} }
/* Creates overlay containing start, stop, stopover and starred markers for track */ /* Creates overlay containing start, stop, stopover and starred markers for track */
fun createSpecialMakersTrackOverlay(context: Context, map_view: MapView, trkpts: Collection<Trkpt>, trackingState: Int, displayStartEndMarker: Boolean = false) fun createSpecialMakersTrackOverlay(context: Context, map_view: MapView, trkpts: Collection<Trkpt>, trackingState: Int, displayStartEndMarker: Boolean = false): ItemizedIconOverlay<OverlayItem>
{ {
val overlayItems: ArrayList<OverlayItem> = ArrayList<OverlayItem>() val overlayItems: ArrayList<OverlayItem> = ArrayList<OverlayItem>()
val trackingActive: Boolean = trackingState == Keys.STATE_TRACKING_ACTIVE val trackingActive: Boolean = trackingState == Keys.STATE_TRACKING_ACTIVE
@ -110,7 +111,9 @@ fun createSpecialMakersTrackOverlay(context: Context, map_view: MapView, trkpts:
overlayItems.add(overlayItem) overlayItems.add(overlayItem)
} }
} }
map_view.overlays.add(createOverlay(context, overlayItems)) val overlay: ItemizedIconOverlay<OverlayItem> = createOverlay(context, overlayItems)
map_view.overlays.add(overlay)
return overlay
} }
fun createOverlayItem(context: Context, latitude: Double, longitude: Double, accuracy: Float, provider: String, time: Long): OverlayItem fun createOverlayItem(context: Context, latitude: Double, longitude: Double, accuracy: Float, provider: String, time: Long): OverlayItem

View File

@ -86,7 +86,7 @@
<string name="pref_altitude_smoothing_value_title" translatable="false">Altitude Smoothing</string> <string name="pref_altitude_smoothing_value_title" translatable="false">Altitude Smoothing</string>
<string name="pref_auto_export_interval_summary">Automatically export GPX file after this many hours.</string> <string name="pref_auto_export_interval_summary">Automatically export GPX file after this many hours.</string>
<string name="pref_device_id_summary">A unique ID to distinguish tracks recorded across multiple devices:</string> <string name="pref_device_id_summary">A unique ID to distinguish tracks recorded across multiple devices:</string>
<string name="pref_database_folder_summary">Directory to contain your database file. You could use Syncthing to sync with your PC!</string> <string name="pref_database_folder_summary">Directory to contain your database file. You could use Syncthing to sync with your PC.</string>
<string name="pref_auto_export_interval_title">Auto Export Interval</string> <string name="pref_auto_export_interval_title">Auto Export Interval</string>
<string name="pref_device_id">Device ID</string> <string name="pref_device_id">Device ID</string>
<string name="pref_database_folder">Database directory</string> <string name="pref_database_folder">Database directory</string>
@ -96,8 +96,8 @@
<string name="pref_general_title">General</string> <string name="pref_general_title">General</string>
<string name="pref_maintenance_title">Maintenance</string> <string name="pref_maintenance_title">Maintenance</string>
<string name="pref_gps_only_title">Restrict to GPS</string> <string name="pref_gps_only_title">Restrict to GPS</string>
<string name="pref_gps_only_summary_gps_and_network">Currently using GPS and Network for localization.</string> <string name="pref_gps_only_summary_gps_and_network">Currently using GPS and Network for location.</string>
<string name="pref_gps_only_summary_gps_only">Currently using only GPS for localization.</string> <string name="pref_gps_only_summary_gps_only">Currently using only GPS for location.</string>
<string name="pref_imperial_measurement_units_summary_metric">Currently using metric units (Kilometer, Meter).</string> <string name="pref_imperial_measurement_units_summary_metric">Currently using metric units (Kilometer, Meter).</string>
<string name="pref_imperial_measurement_units_summary_imperial">Currently using imperial units (Miles, Feet).</string> <string name="pref_imperial_measurement_units_summary_imperial">Currently using imperial units (Miles, Feet).</string>
<string name="pref_imperial_measurement_units_title">Use Imperial Measurements</string> <string name="pref_imperial_measurement_units_title">Use Imperial Measurements</string>