From 2063678b7ca882a05bb341b860b8ae6a13441637 Mon Sep 17 00:00:00 2001 From: Binnette Date: Tue, 10 Jun 2025 12:35:57 +0200 Subject: [PATCH 1/3] Update nightly.yml set action-gh-release to v2.2 --- .github/workflows/nightly.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index bddb3fdef..88ced6287 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -51,7 +51,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Create GitHub Nightly Release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@v2.2 with: tag_name: 'nightly' name: 'Nightly Build' From 0b956e01bec3aee9da37793e6e38f0265d887dcd Mon Sep 17 00:00:00 2001 From: Binnette Date: Tue, 10 Jun 2025 13:44:34 +0200 Subject: [PATCH 2/3] Update nightly.yml use softprops/action-gh-release@v2.2.2 --- .github/workflows/nightly.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 88ced6287..52930e6de 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -51,7 +51,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Create GitHub Nightly Release - uses: softprops/action-gh-release@v2.2 + uses: softprops/action-gh-release@v2.2.2 with: tag_name: 'nightly' name: 'Nightly Build' From afdc7d10f3822ed00b8cb3b1e6ec42f5a84bd49a Mon Sep 17 00:00:00 2001 From: Alain Knaff Date: Fri, 15 Aug 2025 18:45:45 +0200 Subject: [PATCH 3/3] Create multiple track segments when tracking is stopped and later resumed to avoid criss-crossing lines on map --- .../osmtracker/activity/DisplayTrackMap.java | 31 ++++++---- .../java/net/osmtracker/db/DataHelper.java | 4 +- .../net/osmtracker/db/DatabaseHelper.java | 8 ++- .../osmtracker/db/TrackContentProvider.java | 8 ++- .../java/net/osmtracker/db/model/Track.java | 12 +++- .../net/osmtracker/gpx/ExportTrackTask.java | 10 ++- .../net/osmtracker/overlay/Polylines.java | 61 +++++++++++++++++++ .../net/osmtracker/service/gps/GPSLogger.java | 40 +++++++++++- 8 files changed, 153 insertions(+), 21 deletions(-) create mode 100644 app/src/main/java/net/osmtracker/overlay/Polylines.java diff --git a/app/src/main/java/net/osmtracker/activity/DisplayTrackMap.java b/app/src/main/java/net/osmtracker/activity/DisplayTrackMap.java index 707fefbc2..16f72794e 100644 --- a/app/src/main/java/net/osmtracker/activity/DisplayTrackMap.java +++ b/app/src/main/java/net/osmtracker/activity/DisplayTrackMap.java @@ -22,6 +22,7 @@ import net.osmtracker.R; import net.osmtracker.db.TrackContentProvider; import net.osmtracker.overlay.WayPointsOverlay; +import net.osmtracker.overlay.Polylines; import org.osmdroid.api.IMapController; import org.osmdroid.config.Configuration; @@ -29,7 +30,6 @@ import org.osmdroid.util.GeoPoint; import org.osmdroid.views.CustomZoomButtonsController; import org.osmdroid.views.MapView; -import org.osmdroid.views.overlay.Polyline; import org.osmdroid.views.overlay.ScaleBarOverlay; import org.osmdroid.views.overlay.mylocation.SimpleLocationOverlay; @@ -114,7 +114,7 @@ public class DisplayTrackMap extends Activity { /** * OSM view overlay that displays current path */ - private Polyline polyline; + private Polylines polylines; /** * OSM view overlay that displays waypoints @@ -154,6 +154,11 @@ public class DisplayTrackMap extends Activity { */ private Integer lastTrackPointIdProcessed = null; + /** + * The id of the last segment + */ + private int prevSegmentId=-1; + /** * Observes changes on track points */ @@ -291,6 +296,7 @@ private void resumeActivity() { // This ensures that all waypoints for the track will be reloaded // from the database to populate the path layout lastTrackPointIdProcessed = null; + prevSegmentId = -1; // Reload path pathChanged(); @@ -309,7 +315,7 @@ protected void onPause() { getContentResolver().unregisterContentObserver(trackpointContentObserver); // Clear the points list. - polyline.setPoints(new ArrayList<>()); + polylines.clear(); super.onPause(); } @@ -375,12 +381,8 @@ private void createOverlays() { this.getWindowManager().getDefaultDisplay().getMetrics(metrics); // set with to hopefully DPI independent 0.5mm - polyline = new Polyline(); - Paint paint = polyline.getOutlinePaint(); - paint.setColor(Color.BLUE); - paint.setStrokeWidth((float) (metrics.densityDpi / 25.4 / 2)); - osmView.getOverlayManager().add(polyline); - + polylines = new Polylines(Color.BLUE, (float)(metrics.densityDpi / 25.4 / 2), osmView); + myLocationOverlay = new SimpleLocationOverlay(this); osmView.getOverlays().add(myLocationOverlay); @@ -427,7 +429,7 @@ private void pathChanged() { // Projection: The columns to retrieve. Here, we want the latitude, // longitude and primary key only - String[] projection = {TrackContentProvider.Schema.COL_LATITUDE, TrackContentProvider.Schema.COL_LONGITUDE, TrackContentProvider.Schema.COL_ID}; + String[] projection = {TrackContentProvider.Schema.COL_LATITUDE, TrackContentProvider.Schema.COL_LONGITUDE, TrackContentProvider.Schema.COL_ID, TrackContentProvider.Schema.COL_SEG_ID }; // Selection: The where clause to use String selection = null; // SelectionArgs: The parameter replacements to use for the '?' in the selection @@ -458,13 +460,20 @@ private void pathChanged() { int primaryKeyColumnIndex = c.getColumnIndex(TrackContentProvider.Schema.COL_ID); int latitudeColumnIndex = c.getColumnIndex(TrackContentProvider.Schema.COL_LATITUDE); int longitudeColumnIndex = c.getColumnIndex(TrackContentProvider.Schema.COL_LONGITUDE); + int segmentIdColumnIndex = c.getColumnIndex(TrackContentProvider.Schema.COL_SEG_ID); // Add each new point to the track while (!c.isAfterLast()) { lastLat = c.getDouble(latitudeColumnIndex); lastLon = c.getDouble(longitudeColumnIndex); lastTrackPointIdProcessed = c.getInt(primaryKeyColumnIndex); - polyline.addPoint(new GeoPoint(lastLat, lastLon)); + int segmentId = c.getInt(segmentIdColumnIndex); + if(segmentId != prevSegmentId) { + polylines.nextSegment(); + } + prevSegmentId = segmentId; + + polylines.addPoint(new GeoPoint(lastLat, lastLon)); if (doInitialBoundsCalc) { if (lastLat < minLat) minLat = lastLat; if (lastLon < minLon) minLon = lastLon; diff --git a/app/src/main/java/net/osmtracker/db/DataHelper.java b/app/src/main/java/net/osmtracker/db/DataHelper.java index aafdbb751..de86ac1e8 100644 --- a/app/src/main/java/net/osmtracker/db/DataHelper.java +++ b/app/src/main/java/net/osmtracker/db/DataHelper.java @@ -127,7 +127,7 @@ public DataHelper(Context c) { * @param pressure * atmospheric pressure */ - public void track(long trackId, Location location, float azimuth, int accuracy, float pressure) { + public void track(long trackId, Location location, float azimuth, int accuracy, float pressure, boolean newSeg, long segId) { Log.v(TAG, "Tracking (trackId=" + trackId + ") location: " + location + " azimuth: " + azimuth + ", accuracy: " + accuracy); ContentValues values = new ContentValues(); values.put(TrackContentProvider.Schema.COL_TRACK_ID, trackId); @@ -161,6 +161,8 @@ public void track(long trackId, Location location, float azimuth, int accuracy, values.put(TrackContentProvider.Schema.COL_ATMOSPHERIC_PRESSURE, pressure); } + values.put(TrackContentProvider.Schema.COL_SEG_ID, segId); + Uri trackUri = ContentUris.withAppendedId(TrackContentProvider.CONTENT_URI_TRACK, trackId); contentResolver.insert(Uri.withAppendedPath(trackUri, TrackContentProvider.Schema.TBL_TRACKPOINT + "s"), values); } diff --git a/app/src/main/java/net/osmtracker/db/DatabaseHelper.java b/app/src/main/java/net/osmtracker/db/DatabaseHelper.java index 45775608c..39fd0582c 100644 --- a/app/src/main/java/net/osmtracker/db/DatabaseHelper.java +++ b/app/src/main/java/net/osmtracker/db/DatabaseHelper.java @@ -39,7 +39,9 @@ public class DatabaseHelper extends SQLiteOpenHelper { + TrackContentProvider.Schema.COL_TIMESTAMP + " long not null," + TrackContentProvider.Schema.COL_COMPASS + " double null," + TrackContentProvider.Schema.COL_COMPASS_ACCURACY + " integer null," - + TrackContentProvider.Schema.COL_ATMOSPHERIC_PRESSURE + " double null" + ")"; + + TrackContentProvider.Schema.COL_ATMOSPHERIC_PRESSURE + " double null," + + TrackContentProvider.Schema.COL_SEG_ID + " integer not null default 0" + + ")"; /** * SQL for creating index TRACKPOINT_idx (track id) @@ -125,7 +127,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { * v17: add TBL_TRACKPOINT.COL_ATMOSPHERIC_PRESSURE and TBL_WAYPOINT.COL_ATMOSPHERIC_PRESSURE * */ - private static final int DB_VERSION = 17; + private static final int DB_VERSION = 18; private Context context; @@ -181,6 +183,8 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { case 16: db.execSQL("alter table " + TrackContentProvider.Schema.TBL_TRACKPOINT + " add column " + TrackContentProvider.Schema.COL_ATMOSPHERIC_PRESSURE + " double null"); db.execSQL("alter table " + TrackContentProvider.Schema.TBL_WAYPOINT + " add column " + TrackContentProvider.Schema.COL_ATMOSPHERIC_PRESSURE + " double null"); + case 17: + db.execSQL("alter table "+TrackContentProvider.Schema.TBL_TRACKPOINT + " add column " + TrackContentProvider.Schema.COL_SEG_ID + " integer default 0"); } } diff --git a/app/src/main/java/net/osmtracker/db/TrackContentProvider.java b/app/src/main/java/net/osmtracker/db/TrackContentProvider.java index 38f344221..e54fc3529 100644 --- a/app/src/main/java/net/osmtracker/db/TrackContentProvider.java +++ b/app/src/main/java/net/osmtracker/db/TrackContentProvider.java @@ -76,7 +76,8 @@ public class TrackContentProvider extends ContentProvider { Schema.COL_OSM_VISIBILITY, Schema.COL_START_DATE, "count(" + Schema.TBL_TRACKPOINT + "." + Schema.COL_ID + ") as " + Schema.COL_TRACKPOINT_COUNT, - "(SELECT count("+Schema.TBL_WAYPOINT+"."+Schema.COL_TRACK_ID+") FROM "+Schema.TBL_WAYPOINT+" WHERE "+Schema.TBL_WAYPOINT+"."+Schema.COL_TRACK_ID+" = " + Schema.TBL_TRACK + "." + Schema.COL_ID + ") as " + Schema.COL_WAYPOINT_COUNT + "(SELECT count("+Schema.TBL_WAYPOINT+"."+Schema.COL_TRACK_ID+") FROM "+Schema.TBL_WAYPOINT+" WHERE "+Schema.TBL_WAYPOINT+"."+Schema.COL_TRACK_ID+" = " + Schema.TBL_TRACK + "." + Schema.COL_ID + ") as " + Schema.COL_WAYPOINT_COUNT, + "(SELECT max("+Schema.TBL_TRACKPOINT+"."+Schema.COL_SEG_ID+") FROM "+Schema.TBL_TRACKPOINT+" WHERE "+Schema.TBL_TRACKPOINT+"."+Schema.COL_TRACK_ID+" = " + Schema.TBL_TRACK + "." + Schema.COL_ID + ") as " + Schema.COL_MAX_SEG_ID }; /** @@ -495,10 +496,13 @@ public static final class Schema { public static final String COL_COMPASS = "compass_heading"; public static final String COL_COMPASS_ACCURACY = "compass_accuracy"; public static final String COL_ATMOSPHERIC_PRESSURE = "atmospheric_pressure"; - + + public static final String COL_SEG_ID = "segment_id"; + // virtual colums that are used in some sqls but dont exist in database public static final String COL_TRACKPOINT_COUNT = "tp_count"; public static final String COL_WAYPOINT_COUNT = "wp_count"; + public static final String COL_MAX_SEG_ID = "max_segment_id"; // Codes for UriMatcher public static final int URI_CODE_TRACK = 3; diff --git a/app/src/main/java/net/osmtracker/db/model/Track.java b/app/src/main/java/net/osmtracker/db/model/Track.java index b74fcfe3d..366316375 100644 --- a/app/src/main/java/net/osmtracker/db/model/Track.java +++ b/app/src/main/java/net/osmtracker/db/model/Track.java @@ -51,7 +51,7 @@ public static OSMVisibility fromPosition(int position) { private String description; private OSMVisibility visibility; private List tags = new ArrayList(); - private int tpCount, wpCount; + private int tpCount, wpCount, maxSegId; private long trackDate; private long trackId; @@ -93,6 +93,8 @@ public static Track build(final long trackId, Cursor tc, ContentResolver cr, boo out.wpCount = tc.getInt(tc.getColumnIndex(TrackContentProvider.Schema.COL_WAYPOINT_COUNT)); + int maxSegIdIdx = tc.getColumnIndex(TrackContentProvider.Schema.COL_MAX_SEG_ID); + out.maxSegId = tc.isNull(maxSegIdIdx) ? 0 :tc.getInt(maxSegIdIdx); if(withExtraInformation){ out.readExtraInformation(); } @@ -145,6 +147,10 @@ public void setWpCount(int wpCount) { this.wpCount = wpCount; } + public void setMaxSegId(int maxSegId) { + this.maxSegId = maxSegId; + } + public void setTracktDate(long tracktDate) { this.trackDate = tracktDate; } @@ -187,6 +193,10 @@ public Integer getWpCount() { return wpCount; } + public Integer getMaxSegId() { + return maxSegId; + } + public Integer getTpCount() { return tpCount; } diff --git a/app/src/main/java/net/osmtracker/gpx/ExportTrackTask.java b/app/src/main/java/net/osmtracker/gpx/ExportTrackTask.java index a9dec64da..fed664e5c 100644 --- a/app/src/main/java/net/osmtracker/gpx/ExportTrackTask.java +++ b/app/src/main/java/net/osmtracker/gpx/ExportTrackTask.java @@ -347,8 +347,16 @@ private void writeTrackPoints(String trackName, Writer fw, Cursor c, boolean fil fw.write("\t\t" + "" + "\n"); int i=0; + int prevSegId=-1; for(c.moveToFirst(); !c.isAfterLast(); c.moveToNext(),i++) { StringBuffer out = new StringBuffer(); + int segId = c.getInt(c.getColumnIndex(TrackContentProvider.Schema.COL_SEG_ID)); + if(prevSegId != -1 && segId != prevSegId) { + fw.write("\t\t" + "" + "\n"); + fw.write("\t\t" + "" + "\n"); + } + prevSegId = segId; + out.append("\t\t\t" + "" + "\n"); @@ -625,4 +633,4 @@ public String sanitizeTrackName(String trackName){ public String getErrorMsg() { return errorMsg; } -} \ No newline at end of file +} diff --git a/app/src/main/java/net/osmtracker/overlay/Polylines.java b/app/src/main/java/net/osmtracker/overlay/Polylines.java new file mode 100644 index 000000000..d695d2324 --- /dev/null +++ b/app/src/main/java/net/osmtracker/overlay/Polylines.java @@ -0,0 +1,61 @@ +package net.osmtracker.overlay; + +import java.util.ArrayList; +import java.util.List; + +import org.osmdroid.util.GeoPoint; +import org.osmdroid.views.MapView; +import org.osmdroid.views.overlay.Polyline; + +import android.graphics.Paint; + +/** + * Collection of Polylines, useful to draw interrupted paths + */ +public class Polylines { + private int color; + private float width; + private MapView osmView; + private boolean havePoint; + + private int curIdx=0; + + private List polylines = new ArrayList(); + + private void addPolyline() { + Polyline polyline = new Polyline(); + Paint paint = polyline.getOutlinePaint(); + paint.setColor(color); + paint.setStrokeWidth(width); + + polylines.add(polyline); + osmView.getOverlayManager().add(polyline); + } + + public void clear() { + for(Polyline polyline : polylines) + polyline.setPoints(new ArrayList<>()); + curIdx=0; + } + + public Polylines(int color, float width, MapView osmView) { + this.color=color; + this.width=width; + this.osmView = osmView; + addPolyline(); + havePoint=false; + } + + public void addPoint(GeoPoint gp) { + if(curIdx >= polylines.size()) + addPolyline(); + polylines.get(curIdx).addPoint(gp); + havePoint=true; + } + + public void nextSegment() { + if(havePoint) + curIdx++; + havePoint=false; + } +} diff --git a/app/src/main/java/net/osmtracker/service/gps/GPSLogger.java b/app/src/main/java/net/osmtracker/service/gps/GPSLogger.java index fb785d279..a765ce99f 100644 --- a/app/src/main/java/net/osmtracker/service/gps/GPSLogger.java +++ b/app/src/main/java/net/osmtracker/service/gps/GPSLogger.java @@ -6,6 +6,8 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; +import android.content.ContentResolver; +import android.content.ContentUris; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -24,11 +26,14 @@ import androidx.core.app.NotificationCompat; import androidx.core.content.ContextCompat; +import android.database.Cursor; + import net.osmtracker.OSMTracker; import net.osmtracker.R; import net.osmtracker.activity.TrackLogger; import net.osmtracker.db.DataHelper; import net.osmtracker.db.TrackContentProvider; +import net.osmtracker.db.model.Track; import net.osmtracker.listener.PressureListener; import net.osmtracker.listener.SensorListener; @@ -83,6 +88,11 @@ public class GPSLogger extends Service implements LocationListener { */ private long currentTrackId = -1; + /** + * Current Segment ID + */ + private long currentSegmentId = -1; + /** * the timestamp of the last GPS fix we used */ @@ -104,6 +114,8 @@ public class GPSLogger extends Service implements LocationListener { */ private PressureListener pressureListener = new PressureListener(); + private boolean newSeg = false; + /** * Receives Intent for way point tracking, and stop/start logging. */ @@ -130,7 +142,8 @@ public void onReceive(Context context, Intent intent) { dataHelper.wayPoint(trackId, lastLocation, name, link, uuid, sensorListener.getAzimuth(), sensorListener.getAccuracy(), pressureListener.getPressure()); // If there is a waypoint in the track, there should also be a trackpoint - dataHelper.track(currentTrackId, lastLocation, sensorListener.getAzimuth(), sensorListener.getAccuracy(), pressureListener.getPressure()); + dataHelper.track(currentTrackId, lastLocation, sensorListener.getAzimuth(), sensorListener.getAccuracy(), pressureListener.getPressure(), newSeg, currentSegmentId); + newSeg = false; } } } @@ -159,6 +172,7 @@ public void onReceive(Context context, Intent intent) { dataHelper.deleteWayPoint(uuid, filePath); } } else if (OSMTracker.INTENT_START_TRACKING.equals(intent.getAction())) { + newSeg = true; Bundle extras = intent.getExtras(); if (extras != null) { Long trackId = extras.getLong(TrackContentProvider.Schema.COL_TRACK_ID); @@ -284,12 +298,31 @@ public void onDestroy() { super.onDestroy(); } + private long getSegIdFor(long trackId) { + ContentResolver cr = getContentResolver(); + try(Cursor cursor = + cr.query(ContentUris.withAppendedId(TrackContentProvider.CONTENT_URI_TRACK, trackId), + null, null, null, null)) { + + if (! cursor.moveToFirst()) { + Log.v(TAG, "Track "+trackId+" not found"); + return 0; // <--- Early return --- + } + + return Track + .build(trackId, cursor, cr, true) + .getMaxSegId(); + } + } + /** * Start GPS tracking. */ private void startTracking(long trackId) { currentTrackId = trackId; - Log.v(TAG, "Starting track logging for track #" + trackId); + currentSegmentId = getSegIdFor(trackId)+1; + Log.v(TAG, "Starting track logging for track #" + trackId + + "/" + currentSegmentId); // Refresh notification with correct Track ID NotificationManager nmgr = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); nmgr.notify(NOTIFICATION_ID, getNotification()); @@ -318,7 +351,8 @@ public void onLocationChanged(Location location) { lastLocation = location; if (isTracking) { - dataHelper.track(currentTrackId, location, sensorListener.getAzimuth(), sensorListener.getAccuracy(), pressureListener.getPressure()); + dataHelper.track(currentTrackId, location, sensorListener.getAzimuth(), sensorListener.getAccuracy(), pressureListener.getPressure(), newSeg, currentSegmentId); + newSeg = false; } } }