mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-10-02 17:43:06 +02:00
Introduced Position.
Internal value object replacing android.location.Location. Follow-up to #1898.
This commit is contained in:
+2
-6
@@ -9,7 +9,6 @@ import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.location.Location;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
@@ -65,7 +64,6 @@ import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingCadence;
|
||||
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingDistanceSpeed;
|
||||
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingPower;
|
||||
import de.dennisguse.opentracks.sensors.sensorData.AggregatorHeartRate;
|
||||
import de.dennisguse.opentracks.sensors.sensorData.Raw;
|
||||
import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet;
|
||||
import de.dennisguse.opentracks.services.TrackRecordingService;
|
||||
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
|
||||
@@ -596,15 +594,13 @@ public class ExportImportTest {
|
||||
location.setLatitude(latitude);
|
||||
location.setLongitude(longitude);
|
||||
location.setAccuracy(accuracy);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
location.setVerticalAccuracyMeters(verticalAccuracy);
|
||||
}
|
||||
location.setVerticalAccuracyMeters(verticalAccuracy);
|
||||
location.setSpeed(speed);
|
||||
location.setAltitude(altitude);
|
||||
|
||||
mockAltitudeChange(trackPointCreator, altitudeGain);
|
||||
|
||||
trackPointCreator.setClock(time);
|
||||
trackPointCreator.getSensorManager().onChanged(new Raw<>(location));
|
||||
trackPointCreator.getSensorManager().getGpsManager().onLocationChanged(location);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package de.dennisguse.opentracks.data.models;
|
||||
|
||||
import android.location.Location;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
//TODO Use everywhere instead of android.location.Location.
|
||||
public record Position(
|
||||
Instant time,
|
||||
Double latitude,
|
||||
Double longitude,
|
||||
Distance horizontalAccuracy,
|
||||
Altitude altitude,
|
||||
Distance verticalAccuracy,
|
||||
Float bearing,
|
||||
Speed speed
|
||||
) {
|
||||
public static Position empty() {
|
||||
return new Position(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
public static Position of(Location location) {
|
||||
return new Position(
|
||||
Instant.ofEpochMilli(location.getTime()),
|
||||
location.getLatitude(),
|
||||
location.getLongitude(),
|
||||
location.hasAccuracy() ? Distance.of(location.getAccuracy()) : null,
|
||||
location.hasAltitude() ? Altitude.WGS84.of(location.getAltitude()) : null,
|
||||
location.hasVerticalAccuracy() ? Distance.of(location.getVerticalAccuracyMeters()) : null,
|
||||
location.hasBearing() ? location.getBearing() : null,
|
||||
location.hasSpeed() ? Speed.of(location.getSpeed()) : null
|
||||
);
|
||||
}
|
||||
|
||||
public boolean hasLocation() {
|
||||
return latitude != null && longitude != null;
|
||||
}
|
||||
|
||||
public boolean hasHorizontalAccuracy() {
|
||||
return horizontalAccuracy != null;
|
||||
}
|
||||
|
||||
public boolean hasAltitude() {
|
||||
return altitude != null;
|
||||
}
|
||||
|
||||
public boolean hasBearing() {
|
||||
return bearing != null;
|
||||
}
|
||||
|
||||
public boolean hasSpeed() {
|
||||
return speed != null;
|
||||
}
|
||||
|
||||
public Location toLocation() {
|
||||
if (!hasLocation()) {
|
||||
throw new RuntimeException("Cannot convert to Location.");
|
||||
}
|
||||
|
||||
Location location = new Location("");
|
||||
location.setTime(time.toEpochMilli());
|
||||
location.setLatitude(latitude);
|
||||
location.setLongitude(longitude);
|
||||
if (hasBearing()) {
|
||||
location.setBearing(bearing);
|
||||
}
|
||||
if (hasHorizontalAccuracy()) {
|
||||
location.setAccuracy((float) horizontalAccuracy.toM());
|
||||
}
|
||||
if (hasAltitude()) {
|
||||
location.setAltitude(altitude.toM());
|
||||
}
|
||||
if (hasSpeed()) {
|
||||
location.setSpeed((float) speed.toMPS());
|
||||
}
|
||||
|
||||
return location;
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
package de.dennisguse.opentracks.data.models;
|
||||
|
||||
import android.location.Location;
|
||||
import android.os.Build;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
@@ -26,6 +25,7 @@ import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Sensor and/or location information for a specific point in time.
|
||||
@@ -42,6 +42,7 @@ public class TrackPoint {
|
||||
@NonNull
|
||||
private final Instant time;
|
||||
|
||||
//TODO We may use Position for these items
|
||||
private Double latitude;
|
||||
private Double longitude;
|
||||
private Distance horizontalAccuracy;
|
||||
@@ -185,42 +186,40 @@ public class TrackPoint {
|
||||
return this;
|
||||
}
|
||||
|
||||
//TODO Better return null, if no location is present aka latitude == null etc.
|
||||
@NonNull
|
||||
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 (hasHorizontalAccuracy()) {
|
||||
location.setAccuracy((float) horizontalAccuracy.toM());
|
||||
}
|
||||
if (hasAltitude()) {
|
||||
location.setAltitude(altitude.toM());
|
||||
}
|
||||
if (hasSpeed()) {
|
||||
location.setSpeed((float) speed.toMPS());
|
||||
}
|
||||
|
||||
return location;
|
||||
public Position getPosition() {
|
||||
return new Position(
|
||||
time,
|
||||
latitude,
|
||||
longitude,
|
||||
horizontalAccuracy,
|
||||
altitude,
|
||||
verticalAccuracy,
|
||||
bearing,
|
||||
speed
|
||||
);
|
||||
}
|
||||
|
||||
public TrackPoint setLocation(@NonNull Location location) {
|
||||
this.latitude = location.getLatitude();
|
||||
this.longitude = location.getLongitude();
|
||||
this.altitude = location.hasAltitude() ? Altitude.WGS84.of(location.getAltitude()) : null;
|
||||
this.speed = location.hasSpeed() ? Speed.of(location.getSpeed()) : null;
|
||||
this.horizontalAccuracy = location.hasAccuracy() ? Distance.of(location.getAccuracy()) : null;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
this.verticalAccuracy = location.hasVerticalAccuracy() ? Distance.of(location.getVerticalAccuracyMeters()) : null;
|
||||
}
|
||||
public TrackPoint setPosition(Position location) {
|
||||
this.latitude = location.latitude();
|
||||
this.longitude = location.longitude();
|
||||
this.altitude = location.altitude();
|
||||
this.speed = location.speed();
|
||||
this.horizontalAccuracy = location.horizontalAccuracy();
|
||||
this.verticalAccuracy = location.verticalAccuracy();
|
||||
|
||||
//TODO Should we copy the bearing?
|
||||
return this;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@NonNull
|
||||
public Location getLocation() {
|
||||
return getPosition().toLocation();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public TrackPoint setLocation(@NonNull Location location) {
|
||||
setPosition(Position.of(location));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -292,6 +291,7 @@ public class TrackPoint {
|
||||
this.speed = speed;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean hasBearing() {
|
||||
return bearing != null;
|
||||
}
|
||||
@@ -352,13 +352,20 @@ public class TrackPoint {
|
||||
return hasHorizontalAccuracy() && horizontalAccuracy.lessThan(thresholdHorizontalAccuracy);
|
||||
}
|
||||
|
||||
public float bearingTo(@NonNull TrackPoint dest) {
|
||||
public Optional<Float> bearingTo(@NonNull TrackPoint dest) {
|
||||
if (!dest.hasLocation() || !hasLocation()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return bearingTo(dest.getLocation());
|
||||
}
|
||||
|
||||
//TODO Bearing requires a location; what do we do if we don't have any?
|
||||
public float bearingTo(@NonNull Location dest) {
|
||||
return getLocation().bearingTo(dest);
|
||||
@Deprecated
|
||||
public Optional<Float> bearingTo(@NonNull Location dest) {
|
||||
if (!hasLocation()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return Optional.of(getLocation().bearingTo(dest));
|
||||
}
|
||||
|
||||
// Sensor data
|
||||
|
||||
@@ -33,6 +33,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||
@@ -274,7 +275,7 @@ public class KMLTrackExporter implements TrackExporter {
|
||||
float heading = getHeading(marker.getTrackId(), marker.getLocation());
|
||||
writePhotoOverlay(marker, heading, zoneOffset);
|
||||
} else {
|
||||
writePlacemark(marker.getName(), marker.getCategory(), marker.getDescription(), marker.getLocation(), zoneOffset);
|
||||
writePlacemark(marker.getName(), marker.getCategory(), marker.getDescription(), marker.getLocation(), marker.getTime(), zoneOffset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,7 +369,7 @@ public class KMLTrackExporter implements TrackExporter {
|
||||
|
||||
@VisibleForTesting
|
||||
void writeTrackPoint(ZoneOffset zoneOffset, TrackPoint trackPoint) {
|
||||
printWriter.println("<when>" + getTime(zoneOffset, trackPoint.getLocation()) + "</when>");
|
||||
printWriter.println("<when>" + getTime(zoneOffset, trackPoint.getTime()) + "</when>");
|
||||
|
||||
trackpointTypeList.add(trackPoint.getType());
|
||||
|
||||
@@ -411,12 +412,12 @@ public class KMLTrackExporter implements TrackExporter {
|
||||
printWriter.println("</SimpleArrayData>");
|
||||
}
|
||||
|
||||
private void writePlacemark(String name, String activityType, String description, Location location, ZoneOffset zoneOffset) {
|
||||
private void writePlacemark(String name, String activityType, String description, Location location, Instant time, ZoneOffset zoneOffset) {
|
||||
if (location != null) {
|
||||
printWriter.println("<Placemark>");
|
||||
printWriter.println("<name>" + StringUtils.formatCData(name) + "</name>");
|
||||
printWriter.println("<description>" + StringUtils.formatCData(description) + "</description>");
|
||||
printWriter.println("<TimeStamp><when>" + getTime(zoneOffset, location) + "</when></TimeStamp>");
|
||||
printWriter.println("<TimeStamp><when>" + getTime(zoneOffset, time) + "</when></TimeStamp>");
|
||||
printWriter.println("<styleUrl>#" + KMLTrackExporter.MARKER_STYLE + "</styleUrl>");
|
||||
writeTypeLocalized(activityType);
|
||||
printWriter.println("<Point>");
|
||||
@@ -437,7 +438,7 @@ public class KMLTrackExporter implements TrackExporter {
|
||||
printWriter.print("<heading>" + heading + "</heading>");
|
||||
printWriter.print("<tilt>90</tilt>");
|
||||
printWriter.println("</Camera>");
|
||||
printWriter.println("<TimeStamp><when>" + getTime(zoneOffset, marker.getLocation()) + "</when></TimeStamp>");
|
||||
printWriter.println("<TimeStamp><when>" + getTime(zoneOffset, marker.getTime()) + "</when></TimeStamp>");
|
||||
printWriter.println("<styleUrl>#" + MARKER_STYLE + "</styleUrl>");
|
||||
writeTypeLocalized(marker.getCategory());
|
||||
|
||||
@@ -460,14 +461,13 @@ public class KMLTrackExporter implements TrackExporter {
|
||||
|
||||
/**
|
||||
* Returns the formatted time of the location; either absolute or relative depending exportTrackDetail.
|
||||
*
|
||||
* @param location the location
|
||||
*/
|
||||
private String getTime(ZoneOffset zoneOffset, Location location) {
|
||||
return StringUtils.formatDateTimeIso8601(Instant.ofEpochMilli(location.getTime()), zoneOffset);
|
||||
private String getTime(ZoneOffset zoneOffset, Instant instant) {
|
||||
return StringUtils.formatDateTimeIso8601(instant, zoneOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: check if this is a useful feature (likely not).
|
||||
* Gets the heading to a location.
|
||||
*
|
||||
* @param trackId the track id containing the location
|
||||
@@ -480,7 +480,10 @@ public class KMLTrackExporter implements TrackExporter {
|
||||
}
|
||||
TrackPoint viewLocation = contentProviderUtils.getLastValidTrackPoint(trackId);
|
||||
if (viewLocation != null) {
|
||||
return viewLocation.bearingTo(location);
|
||||
Optional<Float> bearing = viewLocation.bearingTo(location);
|
||||
if (bearing.isPresent()) {
|
||||
return bearing.get();
|
||||
}
|
||||
}
|
||||
|
||||
return location.getBearing();
|
||||
|
||||
@@ -206,7 +206,8 @@ public class TrackImporter {
|
||||
}
|
||||
|
||||
if (!current.hasBearing()) {
|
||||
current.setBearing(previous.bearingTo(current));
|
||||
previous.bearingTo(current)
|
||||
.ifPresent(current::setBearing);
|
||||
}
|
||||
|
||||
if (current.getType().equals(TrackPoint.Type.TRACKPOINT) && distanceToPrevious.greaterThan(maxRecordingDistance)) {
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
package de.dennisguse.opentracks.sensors.sensorData;
|
||||
|
||||
import android.location.Location;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Optional;
|
||||
import de.dennisguse.opentracks.data.models.Position;
|
||||
|
||||
public class AggregatorGPS extends Aggregator<Location, Optional<Location>> {
|
||||
public class AggregatorGPS extends Aggregator<Position, Position> {
|
||||
|
||||
|
||||
public AggregatorGPS(String sensorAddress) {
|
||||
@@ -14,8 +12,8 @@ public class AggregatorGPS extends Aggregator<Location, Optional<Location>> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void computeValue(Raw<Location> current) {
|
||||
value = Optional.of(current.value());
|
||||
protected void computeValue(Raw<Position> current) {
|
||||
value = current.value();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -25,7 +23,7 @@ public class AggregatorGPS extends Aggregator<Location, Optional<Location>> {
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Optional<Location> getNoneValue() {
|
||||
return Optional.empty();
|
||||
protected Position getNoneValue() {
|
||||
return Position.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package de.dennisguse.opentracks.sensors.sensorData;
|
||||
|
||||
import android.location.Location;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
@@ -11,6 +10,7 @@ import androidx.annotation.VisibleForTesting;
|
||||
import de.dennisguse.opentracks.data.models.AtmosphericPressure;
|
||||
import de.dennisguse.opentracks.data.models.Cadence;
|
||||
import de.dennisguse.opentracks.data.models.HeartRate;
|
||||
import de.dennisguse.opentracks.data.models.Position;
|
||||
import de.dennisguse.opentracks.data.models.Speed;
|
||||
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||
import de.dennisguse.opentracks.sensors.BluetoothHandlerCyclingCadence;
|
||||
@@ -127,8 +127,8 @@ public final class SensorDataSet {
|
||||
this.barometer.add((Raw<AtmosphericPressure>) data);
|
||||
return;
|
||||
}
|
||||
if (value instanceof Location) {
|
||||
this.gps.add((Raw<Location>) data);
|
||||
if (value instanceof Position) {
|
||||
this.gps.add((Raw<Position>) data);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -152,8 +152,7 @@ public final class SensorDataSet {
|
||||
|
||||
public void fillTrackPoint(TrackPoint trackPoint) {
|
||||
if (gps != null && gps.hasValue()) {
|
||||
gps.getValue()
|
||||
.ifPresent(trackPoint::setLocation);
|
||||
trackPoint.setPosition(gps.getValue());
|
||||
}
|
||||
|
||||
if (getHeartRate() != null) {
|
||||
|
||||
@@ -18,6 +18,7 @@ import java.time.Duration;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.data.models.Distance;
|
||||
import de.dennisguse.opentracks.data.models.Position;
|
||||
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||
import de.dennisguse.opentracks.sensors.SensorConnector;
|
||||
import de.dennisguse.opentracks.sensors.SensorManager;
|
||||
@@ -138,7 +139,7 @@ public class GPSManager implements SensorConnector, LocationListenerCompat, GpsS
|
||||
return;
|
||||
}
|
||||
|
||||
listener.onChange(new Raw<>(location));
|
||||
listener.onChange(new Raw<>(Position.of(location)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user