Marker refactoring.

Location values are stored directly.
This commit is contained in:
Dennis Guse
2021-01-09 21:39:02 +01:00
parent 022d8146fe
commit d157e94220
10 changed files with 152 additions and 105 deletions
@@ -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<Marker> 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);
}
}
@@ -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);
@@ -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;
}
@@ -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());
@@ -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);
}
}
@@ -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("<wpt " + formatLocation(location) + ">");
if (location.hasAltitude()) {
printWriter.println("<ele>" + ELEVATION_FORMAT.format(location.getAltitude()) + "</ele>");
printWriter.println("<wpt " + formatLocation(marker.getLatitude(), marker.getLongitude()) + ">");
if (marker.hasAltitude()) {
printWriter.println("<ele>" + ELEVATION_FORMAT.format(marker.getAltitude()) + "</ele>");
}
printWriter.println("<time>" + StringUtils.formatDateTimeIso8601(Instant.ofEpochMilli(location.getTime())) + "</time>");
printWriter.println("<time>" + StringUtils.formatDateTimeIso8601(marker.getTime()) + "</time>");
printWriter.println("<name>" + StringUtils.formatCData(marker.getName()) + "</name>");
printWriter.println("<desc>" + StringUtils.formatCData(marker.getDescription()) + "</desc>");
printWriter.println("<type>" + StringUtils.formatCData(marker.getCategory()) + "</type>");
@@ -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("<trkpt " + coordinates + ">");
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) + "\"";
}
}
@@ -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);
@@ -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));
}
@@ -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) {
@@ -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);