diff --git a/src/androidTest/java/de/dennisguse/opentracks/content/data/TestDataUtil.java b/src/androidTest/java/de/dennisguse/opentracks/content/data/TestDataUtil.java index 7709c20db..11416ad6b 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/content/data/TestDataUtil.java +++ b/src/androidTest/java/de/dennisguse/opentracks/content/data/TestDataUtil.java @@ -1,7 +1,6 @@ package de.dennisguse.opentracks.content.data; import android.content.Context; -import android.location.Location; import android.net.Uri; import android.util.Pair; @@ -75,9 +74,9 @@ public class TestDataUtil { ); List markers = List.of( - new Marker("Marker 1", "Marker description 1", "Marker category 3", "", trackId, 0.0, 0, trackPoints.get(1).getLocation(), null), - new Marker("Marker 2", "Marker description 2", "Marker category 3", "", trackId, 0.0, 0, trackPoints.get(4).getLocation(), null), - new Marker("Marker 3", "Marker description 3", "Marker category 3", "", trackId, 0.0, 0, trackPoints.get(5).getLocation(), null) + new Marker("Marker 1", "Marker description 1", "Marker category 3", "", trackId, 0.0, 0, trackPoints.get(1), null), + new Marker("Marker 2", "Marker description 2", "Marker category 3", "", trackId, 0.0, 0, trackPoints.get(4), null), + new Marker("Marker 3", "Marker description 3", "Marker category 3", "", trackId, 0.0, 0, trackPoints.get(5), null) ); return new TrackData(track, trackPoints, markers); @@ -143,20 +142,12 @@ public class TestDataUtil { contentProviderUtils.bulkInsertTrackPoint(trackPoints, track.getId()); } - /** - * Creates a Marker with a photo. - * - * @param context The context. - * @param trackId The track id. - * @param location The location. - * @return the Marker created. - */ - public static Marker createMarkerWithPhoto(Context context, Track.Id trackId, Location location) throws IOException { + public static Marker createMarkerWithPhoto(Context context, Track.Id trackId, TrackPoint trackPoint) throws IOException { File dstFile = new File(FileUtils.getImageUrl(context, trackId)); dstFile.createNewFile(); Uri photoUri = FileUtils.getUriForFile(context, dstFile); String photoUrl = photoUri.toString(); - return new Marker("Marker name", "Marker description", "Marker category", "", trackId, 0.0, 0, location, photoUrl); + return new Marker("Marker name", "Marker description", "Marker category", "", trackId, 0.0, 0, trackPoint, photoUrl); } } diff --git a/src/androidTest/java/de/dennisguse/opentracks/content/provider/CustomContentProviderUtilsTest.java b/src/androidTest/java/de/dennisguse/opentracks/content/provider/CustomContentProviderUtilsTest.java index ea6085017..6543969ec 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/content/provider/CustomContentProviderUtilsTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/content/provider/CustomContentProviderUtilsTest.java @@ -233,7 +233,7 @@ public class CustomContentProviderUtilsTest { Track track = TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10); TrackPoint trackPoint = contentProviderUtils.getLastValidTrackPoint(trackId); - Marker marker = TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint.getLocation()); + Marker marker = TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint); contentProviderUtils.insertMarker(marker); ContentResolver contentResolver = context.getContentResolver(); @@ -315,12 +315,12 @@ public class CustomContentProviderUtilsTest { // Insert a marker in tracks trackId and trackId + 1. TrackPoint trackPoint1 = contentProviderUtils.getLastValidTrackPoint(trackId1); - Marker marker1 = TestDataUtil.createMarkerWithPhoto(context, trackId1, trackPoint1.getLocation()); + Marker marker1 = TestDataUtil.createMarkerWithPhoto(context, trackId1, trackPoint1); contentProviderUtils.insertMarker(marker1); File dir1 = FileUtils.getPhotoDir(context, trackId1); TrackPoint trackPoint2 = contentProviderUtils.getLastValidTrackPoint(trackId2); - Marker marker2 = TestDataUtil.createMarkerWithPhoto(context, trackId2, trackPoint2.getLocation()); + Marker marker2 = TestDataUtil.createMarkerWithPhoto(context, trackId2, trackPoint2); contentProviderUtils.insertMarker(marker2); File dir2 = FileUtils.getPhotoDir(context, trackId2); @@ -527,7 +527,7 @@ public class CustomContentProviderUtilsTest { // Insert at first. TrackPoint trackPoint = contentProviderUtils.getLastValidTrackPoint(trackId); - Marker marker1 = TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint.getLocation()); + Marker marker1 = TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint); contentProviderUtils.insertMarker(marker1); // Check insert was done. @@ -661,7 +661,7 @@ public class CustomContentProviderUtilsTest { // Insert at first. TrackPoint trackPoint = contentProviderUtils.getLastValidTrackPoint(trackId); - Marker marker = TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint.getLocation()); + Marker marker = TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint); marker.setDescription(TEST_DESC); Marker.Id markerId = new Marker.Id(ContentUris.parseId(contentProviderUtils.insertMarker(marker))); @@ -696,7 +696,7 @@ public class CustomContentProviderUtilsTest { // Insert at first. TrackPoint trackPoint = contentProviderUtils.getLastValidTrackPoint(trackId); - Marker marker = TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint.getLocation()); + Marker marker = TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint); marker.setDescription(TEST_DESC); Marker.Id markerId = new Marker.Id(ContentUris.parseId(contentProviderUtils.insertMarker(marker))); @@ -730,9 +730,9 @@ public class CustomContentProviderUtilsTest { // Insert two markers with photos. TrackPoint trackPoint = contentProviderUtils.getLastValidTrackPoint(trackId); - Marker marker = TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint.getLocation()); + Marker marker = TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint); marker.setDescription(TEST_DESC); - Marker otherMarker = TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint.getLocation()); + Marker otherMarker = TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint); otherMarker.setDescription(TEST_DESC); Marker.Id markerId = new Marker.Id(ContentUris.parseId(contentProviderUtils.insertMarker(marker))); contentProviderUtils.insertMarker(otherMarker); diff --git a/src/main/java/de/dennisguse/opentracks/content/data/Marker.java b/src/main/java/de/dennisguse/opentracks/content/data/Marker.java index de7f1f273..7adb91ad6 100644 --- a/src/main/java/de/dennisguse/opentracks/content/data/Marker.java +++ b/src/main/java/de/dennisguse/opentracks/content/data/Marker.java @@ -23,7 +23,6 @@ import android.os.Parcelable; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; import java.time.Instant; import java.util.Objects; @@ -42,45 +41,49 @@ public final class Marker { private String category = ""; private String icon = ""; private final Track.Id trackId; + + private final Instant time; + private Double latitude; + private Double longitude; + private Float accuracy; + private Double altitude_m; + private Float bearing; + //TODO It is the distance from the track starting point; rename to something more meaningful private double length = 0.0; private long duration = 0; //TODO Duration - @Deprecated //TODO Replace by storing latitude/longitude directly. - private final Location location; @Deprecated //TODO Make an URI instead of String private String photoUrl = ""; - public Marker(@Nullable Track.Id trackId) { + public Marker(@Nullable Track.Id trackId, Instant time) { this.trackId = trackId; - location = null; + this.time = time; } - @VisibleForTesting - public Marker(@NonNull Track.Id trackId, @NonNull TrackPoint trackPoint) { - this(trackId, trackPoint.getLocation()); - } - - @Deprecated - //TODO Used by AbstractFileImporter to create an intermediate marker before saving a new one into the database. - public Marker(@NonNull Location location) { - this(null, location); - } - - public Marker(@NonNull Track.Id trackId, @NonNull Location location) { - this.location = location; + public Marker(@Nullable Track.Id trackId, @NonNull TrackPoint trackPoint) { this.trackId = trackId; + + this.time = trackPoint.getTime(); + + if (!trackPoint.hasLocation()) + throw new RuntimeException("Marker requires a trackpoint with a location."); + + this.latitude = trackPoint.getLatitude(); + this.longitude = trackPoint.getLongitude(); + if (trackPoint.hasAccuracy()) this.accuracy = trackPoint.getAccuracy(); + if (trackPoint.hasAltitude()) this.altitude_m = trackPoint.getAltitude(); + if (trackPoint.hasBearing()) this.bearing = trackPoint.getBearing(); } - public Marker(String name, String description, String category, String icon, @NonNull Track.Id trackId, double length, long duration, @NonNull Location location, String photoUrl) { + public Marker(String name, String description, String category, String icon, @NonNull Track.Id trackId, double length, long duration, @NonNull TrackPoint trackPoint, String photoUrl) { + this(trackId, trackPoint); this.name = name; this.description = description; this.category = category; this.icon = icon; - this.trackId = trackId; this.length = length; this.duration = duration; - this.location = location; this.photoUrl = photoUrl; } @@ -97,7 +100,7 @@ public final class Marker { } public Instant getTime() { - return Instant.ofEpochMilli(location.getTime()); + return time; } public String getName() { @@ -137,6 +140,83 @@ public final class Marker { return trackId; } + public boolean hasLocation() { + return latitude != null || longitude != null; + } + + @Nullable + public Location getLocation() { + Location location = new Location(""); + location.setTime(time.toEpochMilli()); + if (hasLocation()) { + location.setLatitude(latitude); + location.setLongitude(longitude); + } + if (hasBearing()) { + location.setBearing(bearing); + } + if (hasAccuracy()) { + location.setAccuracy(accuracy); + } + if (hasAltitude()) { + location.setAltitude(altitude_m); + } + + return location; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public boolean hasAccuracy() { + return accuracy != null; + } + + public Float getAccuracy() { + return accuracy; + } + + public void setAccuracy(Float accuracy) { + this.accuracy = accuracy; + } + + public boolean hasAltitude() { + return altitude_m != null; + } + + public Double getAltitude() { + return altitude_m; + } + + public void setAltitude(double altitude_m) { + this.altitude_m = altitude_m; + } + + public boolean hasBearing() { + return bearing != null; + } + + public Float getBearing() { + return bearing; + } + + public void setBearing(float bearing) { + this.bearing = bearing; + } + public double getLength() { return length; } @@ -153,11 +233,6 @@ public final class Marker { this.duration = duration; } - @NonNull - public Location getLocation() { - return location; - } - public String getPhotoUrl() { return photoUrl; } diff --git a/src/main/java/de/dennisguse/opentracks/content/provider/ContentProviderUtils.java b/src/main/java/de/dennisguse/opentracks/content/provider/ContentProviderUtils.java index 5703ec194..d3be560a2 100644 --- a/src/main/java/de/dennisguse/opentracks/content/provider/ContentProviderUtils.java +++ b/src/main/java/de/dennisguse/opentracks/content/provider/ContentProviderUtils.java @@ -309,27 +309,23 @@ public class ContentProviderUtils { int bearingIndex = cursor.getColumnIndexOrThrow(MarkerColumns.BEARING); int photoUrlIndex = cursor.getColumnIndexOrThrow(MarkerColumns.PHOTOURL); - Location location = new Location(""); + Track.Id trackId = new Track.Id(cursor.getLong(trackIdIndex)); + Marker marker = new Marker(trackId, Instant.ofEpochMilli(cursor.getLong(timeIndex))); + if (!cursor.isNull(longitudeIndex) && !cursor.isNull(latitudeIndex)) { - location.setLongitude(((double) cursor.getInt(longitudeIndex)) / 1E6); - location.setLatitude(((double) cursor.getInt(latitudeIndex)) / 1E6); - } - if (!cursor.isNull(timeIndex)) { - location.setTime(cursor.getLong(timeIndex)); + marker.setLongitude(((double) cursor.getInt(longitudeIndex)) / 1E6); + marker.setLatitude(((double) cursor.getInt(latitudeIndex)) / 1E6); } if (!cursor.isNull(altitudeIndex)) { - location.setAltitude(cursor.getFloat(altitudeIndex)); + marker.setAltitude(cursor.getFloat(altitudeIndex)); } if (!cursor.isNull(accuracyIndex)) { - location.setAccuracy(cursor.getFloat(accuracyIndex)); + marker.setAccuracy(cursor.getFloat(accuracyIndex)); } if (!cursor.isNull(bearingIndex)) { - location.setBearing(cursor.getFloat(bearingIndex)); + marker.setBearing(cursor.getFloat(bearingIndex)); } - Track.Id trackId = new Track.Id(cursor.getLong(trackIdIndex)); - Marker marker = new Marker(trackId, location); - if (!cursor.isNull(idIndex)) { marker.setId(new Marker.Id(cursor.getLong(idIndex))); } @@ -486,18 +482,17 @@ public class ContentProviderUtils { values.put(MarkerColumns.LENGTH, marker.getLength()); values.put(MarkerColumns.DURATION, marker.getDuration()); - Location location = marker.getLocation(); - values.put(MarkerColumns.LONGITUDE, (int) (location.getLongitude() * 1E6)); - values.put(MarkerColumns.LATITUDE, (int) (location.getLatitude() * 1E6)); - values.put(MarkerColumns.TIME, location.getTime()); - if (location.hasAltitude()) { - values.put(MarkerColumns.ALTITUDE, location.getAltitude()); + values.put(MarkerColumns.LONGITUDE, (int) (marker.getLongitude() * 1E6)); + values.put(MarkerColumns.LATITUDE, (int) (marker.getLatitude() * 1E6)); + values.put(MarkerColumns.TIME, marker.getTime().toEpochMilli()); + if (marker.hasAltitude()) { + values.put(MarkerColumns.ALTITUDE, marker.getAltitude()); } - if (location.hasAccuracy()) { - values.put(MarkerColumns.ACCURACY, location.getAccuracy()); + if (marker.hasAccuracy()) { + values.put(MarkerColumns.ACCURACY, marker.getAccuracy()); } - if (location.hasBearing()) { - values.put(MarkerColumns.BEARING, location.getBearing()); + if (marker.hasBearing()) { + values.put(MarkerColumns.BEARING, marker.getBearing()); } values.put(MarkerColumns.PHOTOURL, marker.getPhotoUrl()); diff --git a/src/main/java/de/dennisguse/opentracks/fragments/MarkerDetailFragment.java b/src/main/java/de/dennisguse/opentracks/fragments/MarkerDetailFragment.java index 7d592213f..071631a30 100644 --- a/src/main/java/de/dennisguse/opentracks/fragments/MarkerDetailFragment.java +++ b/src/main/java/de/dennisguse/opentracks/fragments/MarkerDetailFragment.java @@ -17,7 +17,6 @@ package de.dennisguse.opentracks.fragments; import android.content.Intent; -import android.location.Location; import android.os.Bundle; import android.os.Handler; import android.util.Log; @@ -253,16 +252,11 @@ public class MarkerDetailFragment extends Fragment { } private void setLocation(boolean addShadow) { - Location location = marker.getLocation(); - String value; - if (location == null) { - value = null; - } else { - value = "[" + getString(R.string.stats_latitude) + " " - + StringUtils.formatCoordinate(location.getLatitude()) + ", " - + getString(R.string.stats_longitude) + " " - + StringUtils.formatCoordinate(location.getLongitude()) + "]"; - } + String value = "[" + getString(R.string.stats_latitude) + " " + + StringUtils.formatCoordinate(marker.getLatitude()) + ", " + + getString(R.string.stats_longitude) + " " + + StringUtils.formatCoordinate(marker.getLongitude()) + "]"; + ListItemUtils.setTextView(getActivity(), viewBinding.markerDetailMarkerLocation, value, addShadow); } } diff --git a/src/main/java/de/dennisguse/opentracks/io/file/exporter/GpxTrackWriter.java b/src/main/java/de/dennisguse/opentracks/io/file/exporter/GpxTrackWriter.java index c01c2ad02..7128c4f16 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/exporter/GpxTrackWriter.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/exporter/GpxTrackWriter.java @@ -16,12 +16,9 @@ package de.dennisguse.opentracks.io.file.exporter; -import android.location.Location; - import java.io.OutputStream; import java.io.PrintWriter; import java.text.NumberFormat; -import java.time.Instant; import java.util.Locale; import de.dennisguse.opentracks.content.data.Marker; @@ -133,12 +130,11 @@ public class GpxTrackWriter implements TrackWriter { @Override public void writeMarker(Marker marker) { if (printWriter != null) { - Location location = marker.getLocation(); - printWriter.println(""); - if (location.hasAltitude()) { - printWriter.println("" + ELEVATION_FORMAT.format(location.getAltitude()) + ""); + printWriter.println(""); + if (marker.hasAltitude()) { + printWriter.println("" + ELEVATION_FORMAT.format(marker.getAltitude()) + ""); } - printWriter.println(""); + printWriter.println(""); printWriter.println("" + StringUtils.formatCData(marker.getName()) + ""); printWriter.println("" + StringUtils.formatCData(marker.getDescription()) + ""); printWriter.println("" + StringUtils.formatCData(marker.getCategory()) + ""); @@ -191,7 +187,7 @@ public class GpxTrackWriter implements TrackWriter { @Override public void writeTrackPoint(TrackPoint trackPoint) { if (printWriter != null) { - String coordinates = trackPoint.hasLocation() ? " " + formatLocation(trackPoint.getLocation()) : ""; + String coordinates = trackPoint.hasLocation() ? " " + formatLocation(trackPoint.getLatitude(), trackPoint.getLongitude()) : ""; printWriter.println(""); if (trackPoint.hasAltitude()) { @@ -230,12 +226,7 @@ public class GpxTrackWriter implements TrackWriter { } } - /** - * Formats a location with latitude and longitude coordinates. - * - * @param location the location - */ - private String formatLocation(Location location) { - return "lat=\"" + COORDINATE_FORMAT.format(location.getLatitude()) + "\" lon=\"" + COORDINATE_FORMAT.format(location.getLongitude()) + "\""; + private String formatLocation(double latitude, double longitude) { + return "lat=\"" + COORDINATE_FORMAT.format(latitude) + "\" lon=\"" + COORDINATE_FORMAT.format(longitude) + "\""; } } diff --git a/src/main/java/de/dennisguse/opentracks/io/file/importer/AbstractFileTrackImporter.java b/src/main/java/de/dennisguse/opentracks/io/file/importer/AbstractFileTrackImporter.java index f4bae0212..5159a3a46 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/importer/AbstractFileTrackImporter.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/importer/AbstractFileTrackImporter.java @@ -199,14 +199,14 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track } // Valid trackPoint - if (trackPoint.getLatitude() == marker.getLocation().getLatitude() && trackPoint.getLongitude() == marker.getLocation().getLongitude()) { + if (trackPoint.getLatitude() == marker.getLatitude() && trackPoint.getLongitude() == marker.getLongitude()) { String markerDescription = marker.getDescription(); String icon = context.getString(R.string.marker_icon_url); double length = trackStatisticsUpdater.getTrackStatistics().getTotalDistance(); long duration = trackStatisticsUpdater.getTrackStatistics().getTotalTime().toMillis(); // Insert marker - Marker newMarker = new Marker(marker.getName(), markerDescription, marker.getCategory(), icon, track.getId(), length, duration, trackPoint.getLocation(), marker.getPhotoUrl()); + Marker newMarker = new Marker(marker.getName(), markerDescription, marker.getCategory(), icon, track.getId(), length, duration, trackPoint, marker.getPhotoUrl()); contentProviderUtils.insertMarker(newMarker); } @@ -316,7 +316,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track Log.w(TAG, "Marker with invalid coordinates ignored: " + trackPoint.getLocation()); return; } - Marker marker = new Marker(trackPoint.getLocation()); + Marker marker = new Marker(null, trackPoint); if (name != null) { marker.setName(name); diff --git a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java index b459e8ff7..06f4ae447 100644 --- a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java +++ b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java @@ -269,7 +269,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand long duration = stats.getTotalTime().toMillis(); // Insert marker - Marker marker = new Marker(name, description, category, icon, recordingTrackId, length, duration, trackPoint.getLocation(), photoUrl); + Marker marker = new Marker(name, description, category, icon, recordingTrackId, length, duration, trackPoint, photoUrl); Uri uri = contentProviderUtils.insertMarker(marker); return new Marker.Id(ContentUris.parseId(uri)); } diff --git a/src/main/java/de/dennisguse/opentracks/util/IntentUtils.java b/src/main/java/de/dennisguse/opentracks/util/IntentUtils.java index 2472b5e10..6322c4879 100644 --- a/src/main/java/de/dennisguse/opentracks/util/IntentUtils.java +++ b/src/main/java/de/dennisguse/opentracks/util/IntentUtils.java @@ -155,7 +155,7 @@ public class IntentUtils { } public static void showCoordinateOnMap(Context context, Marker marker) { - showCoordinateOnMap(context, marker.getLocation().getLatitude(), marker.getLocation().getLongitude(), marker.getName()); + showCoordinateOnMap(context, marker.getLatitude(), marker.getLongitude(), marker.getName()); } /** @@ -166,7 +166,7 @@ public class IntentUtils { * @param longitude the longitude * @param label the label */ - public static void showCoordinateOnMap(Context context, double latitude, double longitude, String label) { + private static void showCoordinateOnMap(Context context, double latitude, double longitude, String label) { //SEE https://developer.android.com/guide/components/intents-common.html#Maps String uri = "geo:0,0?q=" + latitude + "," + longitude; if (label != null && label.length() > 0) { diff --git a/src/main/java/de/dennisguse/opentracks/viewmodels/MarkerEditViewModel.java b/src/main/java/de/dennisguse/opentracks/viewmodels/MarkerEditViewModel.java index 7394959d5..ddb1fa7d2 100644 --- a/src/main/java/de/dennisguse/opentracks/viewmodels/MarkerEditViewModel.java +++ b/src/main/java/de/dennisguse/opentracks/viewmodels/MarkerEditViewModel.java @@ -15,6 +15,7 @@ import androidx.lifecycle.MutableLiveData; import java.io.File; import java.io.FileDescriptor; import java.io.IOException; +import java.time.Instant; import java.util.NoSuchElementException; import de.dennisguse.opentracks.R; @@ -57,7 +58,7 @@ public class MarkerEditViewModel extends AndroidViewModel { isNewMarker = markerId == null; if (isNewMarker) { int nextMarkerNumber = trackId == null ? 0 : new ContentProviderUtils(getApplication()).getNextMarkerNumber(trackId); - marker = new Marker(trackId); + marker = new Marker(trackId, (Instant) null); marker.setName(getApplication().getString(R.string.marker_name_format, nextMarkerNumber)); } else { marker = new ContentProviderUtils(getApplication()).getMarker(markerId);