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 d105b760b..d2ee20b54 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/content/data/TestDataUtil.java +++ b/src/androidTest/java/de/dennisguse/opentracks/content/data/TestDataUtil.java @@ -17,9 +17,13 @@ import de.dennisguse.opentracks.data.MarkerIterator; import de.dennisguse.opentracks.data.TrackPointIterator; import de.dennisguse.opentracks.data.models.ActivityType; import de.dennisguse.opentracks.data.models.Altitude; +import de.dennisguse.opentracks.data.models.AltitudeGainLoss; +import de.dennisguse.opentracks.data.models.Cadence; import de.dennisguse.opentracks.data.models.Distance; +import de.dennisguse.opentracks.data.models.HeartRate; import de.dennisguse.opentracks.data.models.Marker; import de.dennisguse.opentracks.data.models.Position; +import de.dennisguse.opentracks.data.models.Power; import de.dennisguse.opentracks.data.models.Speed; import de.dennisguse.opentracks.data.models.Statistics; import de.dennisguse.opentracks.data.models.Track; @@ -92,9 +96,9 @@ public class TestDataUtil { ); List markers = List.of( - new Marker(null, trackId, "Marker 1", "Marker description 1", "Marker typeLocalized 3", trackPoints.get(1).getPosition(), null), - new Marker(null, trackId, "Marker 2", "Marker description 2", "Marker typeLocalized 3", trackPoints.get(4).getPosition(), null), - new Marker(null, trackId, "Marker 3", "Marker description 3", "Marker typeLocalized 3", trackPoints.get(5).getPosition(), null) + new Marker(null, trackId, "Marker 1", "Marker description 1", "Marker typeLocalized 3", trackPoints.get(1).position(), null), + new Marker(null, trackId, "Marker 2", "Marker description 2", "Marker typeLocalized 3", trackPoints.get(4).position(), null), + new Marker(null, trackId, "Marker 3", "Marker description 3", "Marker typeLocalized 3", trackPoints.get(5).position(), null) ); return new TrackData(track, trackPoints, markers); @@ -112,8 +116,10 @@ public class TestDataUtil { return pair.first; } - public static TrackPoint createTrackPoint(int i) { - TrackPoint trackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT, + public static TrackPoint createTrackPoint(int i, TrackPoint.Type type, AltitudeGainLoss altitudeGainLoss) { + return new TrackPoint( + null, + type, new Position( Instant.ofEpochSecond(i), INITIAL_LATITUDE + (double) i / 10000.0, @@ -123,21 +129,24 @@ public class TestDataUtil { null, null, Speed.of(5f + (i / 10f)) - )); - - trackPoint.setHeartRate(100f + i % 80); - trackPoint.setCadence(300f + i); - trackPoint.setPower(400f + i); - trackPoint.setAltitudeGainLoss(ALTITUDE_GAIN, ALTITUDE_LOSS); - return trackPoint; + ), + null, + HeartRate.of(100f + i % 80), + Cadence.of(300f + i), + Power.of(400f + i), + altitudeGainLoss + ); } public static TrackPoint createTrackPoint(int i, TrackPoint.Type type) { - TrackPoint trackPoint = createTrackPoint(i); - trackPoint.setType(type); - return trackPoint; + return createTrackPoint(i, TrackPoint.Type.TRACKPOINT, new AltitudeGainLoss(ALTITUDE_GAIN, ALTITUDE_LOSS)); } + public static TrackPoint createTrackPoint(int i) { + return createTrackPoint(i, TrackPoint.Type.TRACKPOINT); + } + + /** * Inserts a track with locations into the database. * @@ -164,7 +173,7 @@ public class TestDataUtil { "Marker name", description, "Marker typeLocalized", - trackPoint.getPosition(), + trackPoint.position(), photoUri); } diff --git a/src/androidTest/java/de/dennisguse/opentracks/content/data/TestSensorDataUtil.java b/src/androidTest/java/de/dennisguse/opentracks/content/data/TestSensorDataUtil.java index a20380b01..5027d02b7 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/content/data/TestSensorDataUtil.java +++ b/src/androidTest/java/de/dennisguse/opentracks/content/data/TestSensorDataUtil.java @@ -6,8 +6,12 @@ import java.util.ArrayList; import java.util.List; import de.dennisguse.opentracks.data.models.Altitude; +import de.dennisguse.opentracks.data.models.AltitudeGainLoss; +import de.dennisguse.opentracks.data.models.Cadence; import de.dennisguse.opentracks.data.models.Distance; +import de.dennisguse.opentracks.data.models.HeartRate; import de.dennisguse.opentracks.data.models.Position; +import de.dennisguse.opentracks.data.models.Power; import de.dennisguse.opentracks.data.models.Speed; import de.dennisguse.opentracks.data.models.TrackPoint; @@ -20,7 +24,9 @@ public class TestSensorDataUtil { sensorDataList.add(new TestSensorDataUtil.SensorData(time, hr, cadence, power, type)); int i = trackPointList.size() + 1; - TrackPoint tp = new TrackPoint(type, + TrackPoint tp = new TrackPoint( + null, + type, new Position( time, TestDataUtil.INITIAL_LATITUDE + (double) i / 10000.0, @@ -30,18 +36,14 @@ public class TestSensorDataUtil { null, null, Speed.of(5f + (i / 10f)) - ) + ), + null, + HeartRate.ofOrNull(hr), + cadence != null ? Cadence.of(cadence) : null, + power != null ? Power.of(power) : null, + new AltitudeGainLoss(3, 3) ); - if (hr != null) { - tp.setHeartRate(hr); - } - if (cadence != null) { - tp.setCadence(cadence); - } - if (power != null) { - tp.setPower(power); - } - tp.setAltitudeGainLoss(3, 3); + trackPointList.add(tp); } diff --git a/src/androidTest/java/de/dennisguse/opentracks/data/CustomContentProviderUtilsTest.java b/src/androidTest/java/de/dennisguse/opentracks/data/CustomContentProviderUtilsTest.java index a16977049..28dddb87c 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/data/CustomContentProviderUtilsTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/data/CustomContentProviderUtilsTest.java @@ -54,19 +54,22 @@ import de.dennisguse.opentracks.data.models.ActivityType; import de.dennisguse.opentracks.data.models.Altitude; import de.dennisguse.opentracks.data.models.AltitudeExtremities; import de.dennisguse.opentracks.data.models.AltitudeGainLoss; +import de.dennisguse.opentracks.data.models.Cadence; import de.dennisguse.opentracks.data.models.Distance; +import de.dennisguse.opentracks.data.models.HeartRate; import de.dennisguse.opentracks.data.models.Marker; import de.dennisguse.opentracks.data.models.MarkerBuilder; import de.dennisguse.opentracks.data.models.Position; +import de.dennisguse.opentracks.data.models.Power; import de.dennisguse.opentracks.data.models.Speed; import de.dennisguse.opentracks.data.models.Statistics; import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.models.TrackBuilder; import de.dennisguse.opentracks.data.models.TrackPoint; +import de.dennisguse.opentracks.data.statistics.SensorStatistics; import de.dennisguse.opentracks.data.tables.MarkerColumns; import de.dennisguse.opentracks.data.tables.TrackPointsColumns; import de.dennisguse.opentracks.data.tables.TracksColumns; -import de.dennisguse.opentracks.data.statistics.SensorStatistics; import de.dennisguse.opentracks.util.FileUtils; /** @@ -124,7 +127,7 @@ public class CustomContentProviderUtilsTest { assertNotNull(trackPoint); locations.add(trackPoint); // Make sure the IDs are returned in the right order. - assertEquals(lastPointId.id() - numPoints + locations.size(), trackPoint.getId().id()); + assertEquals(lastPointId.id() - numPoints + locations.size(), trackPoint.id().id()); } assertEquals(numPoints, locations.size()); } @@ -167,7 +170,7 @@ public class CustomContentProviderUtilsTest { try (TrackPointIterator it = contentProviderUtils.getTrackPointIterator(id, null)) { while (it.hasNext()) { TrackPoint trackPoint = it.next(); - lastPointId = trackPoint.getId(); + lastPointId = trackPoint.id(); counter++; } } @@ -237,7 +240,7 @@ public class CustomContentProviderUtilsTest { "", "", "", - getLastValidTrackPoint(trackId).getPosition(), + getLastValidTrackPoint(trackId).position(), null )); @@ -300,7 +303,7 @@ public class CustomContentProviderUtilsTest { "", "", "", - getLastValidTrackPoint(trackId1).getPosition(), + getLastValidTrackPoint(trackId1).position(), null )); @@ -473,7 +476,7 @@ public class CustomContentProviderUtilsTest { "", TEST_DESC, "", - getLastValidTrackPoint(trackId).getPosition(), + getLastValidTrackPoint(trackId).position(), null )); @@ -553,7 +556,7 @@ public class CustomContentProviderUtilsTest { "", MOCK_DESC, "", - getLastValidTrackPoint(trackId).getPosition(), + getLastValidTrackPoint(trackId).position(), null )); Marker.Id marker2Id = contentProviderUtils.insertMarker(new Marker( @@ -562,7 +565,7 @@ public class CustomContentProviderUtilsTest { "", MOCK_DESC, "", - getLastValidTrackPoint(trackId).getPosition(), + getLastValidTrackPoint(trackId).position(), null )); @@ -589,7 +592,7 @@ public class CustomContentProviderUtilsTest { "", MOCK_DESC, "", - getLastValidTrackPoint(trackId).getPosition(), + getLastValidTrackPoint(trackId).position(), null )); } @@ -613,7 +616,7 @@ public class CustomContentProviderUtilsTest { "", TEST_DESC, "", - getLastValidTrackPoint(trackId).getPosition(), + getLastValidTrackPoint(trackId).position(), null )); @@ -636,7 +639,7 @@ public class CustomContentProviderUtilsTest { "", TEST_DESC, "", - getLastValidTrackPoint(trackId).getPosition(), + getLastValidTrackPoint(trackId).position(), null )); @@ -647,7 +650,7 @@ public class CustomContentProviderUtilsTest { "", TEST_DESC_NEW, "", - getLastValidTrackPoint(trackId).getPosition(), + getLastValidTrackPoint(trackId).position(), null )); @@ -803,20 +806,26 @@ public class CustomContentProviderUtilsTest { Track.Id trackId = new Track.Id(System.currentTimeMillis()); TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10); - TrackPoint trackPoint = TestDataUtil.createTrackPoint(5); - trackPoint.setHeartRate(1F); - trackPoint.setCadence(2F); - trackPoint.setPower(3F); + TrackPoint trackPoint = new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + TestDataUtil.createTrackPoint(5).position(), + null, + HeartRate.of(1), + Cadence.of(2), + Power.of(3), + null + ); // when contentProviderUtils.insertTrackPoint(trackPoint, trackId); // then List trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId); - assertTrue(trackPoints.get(10).hasHeartRate()); - assertEquals(trackPoint.getHeartRate(), trackPoints.get(10).getHeartRate()); - assertEquals(trackPoint.getCadence(), trackPoints.get(10).getCadence()); - assertEquals(trackPoint.getPower(), trackPoints.get(10).getPower()); + assertNotNull(trackPoints.get(10).heartRate()); + assertEquals(trackPoint.heartRate(), trackPoints.get(10).heartRate()); + assertEquals(trackPoint.cadence(), trackPoints.get(10).cadence()); + assertEquals(trackPoint.power(), trackPoints.get(10).power()); } @Test @@ -857,9 +866,9 @@ public class CustomContentProviderUtilsTest { for (int i = 0; i < trackpointIds.size(); i++) { assertTrue(trackPointIterator.hasNext()); TrackPoint trackPoint = trackPointIterator.next(); - assertEquals(startTrackPointId.id() + i, trackPoint.getId().id()); + assertEquals(startTrackPointId.id() + i, trackPoint.id().id()); - Position position = trackPoint.getPosition(); + Position position = trackPoint.position(); assertEquals(TestDataUtil.INITIAL_LATITUDE + i / 10000.0, position.latitude(), 0.01); assertEquals(TestDataUtil.INITIAL_LONGITUDE - i / 10000.0, position.longitude(), 0.01); assertEquals(i / 100.0, position.horizontalAccuracy().distance_m(), 0.01); @@ -879,11 +888,17 @@ public class CustomContentProviderUtilsTest { public void testGetSensorStats_noSensorData() { // given List trackPointList = new ArrayList<>(); - TrackPoint trackPoint = TestDataUtil.createTrackPoint(1); - trackPoint.setType(TrackPoint.Type.TRACKPOINT); - trackPoint.setPower(null); - trackPoint.setCadence(null); - trackPoint.setHeartRate(null); + TrackPoint trackPoint = new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + TestDataUtil.createTrackPoint(1).position(), + null, + null, + null, + null, + null + ); + trackPointList.add(trackPoint); Track.Id trackId = new Track.Id(System.currentTimeMillis()); Track track = TestDataUtil.createTrack(trackId); @@ -1217,7 +1232,7 @@ public class CustomContentProviderUtilsTest { return trackpoints.reversed() .stream() - .filter(it -> List.of(TrackPoint.Type.TRACKPOINT, TrackPoint.Type.SEGMENT_START_AUTOMATIC).contains(it.getType())) + .filter(it -> List.of(TrackPoint.Type.TRACKPOINT, TrackPoint.Type.SEGMENT_START_AUTOMATIC).contains(it.type())) .findFirst().orElseThrow(); } diff --git a/src/androidTest/java/de/dennisguse/opentracks/data/model/TrackPointTest.java b/src/androidTest/java/de/dennisguse/opentracks/data/model/TrackPointTest.java index e7ba22aec..5f654e497 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/data/model/TrackPointTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/data/model/TrackPointTest.java @@ -13,7 +13,7 @@ import de.dennisguse.opentracks.data.models.TrackPoint; public class TrackPointTest { @Test - public void distanceToPrevious() { + public void distanceToPrevious_gps() { TrackPoint tp1 = new TrackPoint(TrackPoint.Type.TRACKPOINT, new Position( Instant.ofEpochMilli(0), @@ -38,20 +38,119 @@ public class TrackPointTest { // without sensor distance assertEquals(11.13, tp2.distanceToPrevious(tp1).toM(), 0.01); + } + + @Test + public void distanceToPrevious_sensor_distance_first() { + TrackPoint tp1 = new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + new Position( + Instant.ofEpochMilli(0), + 0d, + 0.0001, + null, + null, + null, + null, + null), + Distance.of(5), + null, + null, + null, + null + ); + + TrackPoint tp2 = new TrackPoint(TrackPoint.Type.TRACKPOINT, + new Position( + Instant.ofEpochMilli(1), + 0d, + 0.0002, + null, + null, + null, + null, + null)); // tp1 has sensor distance - tp1.setSensorDistance(Distance.of(5)); - tp1.setSensorDistance(null); assertEquals(11.13, tp2.distanceToPrevious(tp1).toM(), 0.01); + } + + @Test + public void distanceToPrevious_sensor_distance_second() { + TrackPoint tp1 = new TrackPoint(TrackPoint.Type.TRACKPOINT, + new Position( + Instant.ofEpochMilli(0), + 0d, + 0.0001, + null, + null, + null, + null, + null)); + + TrackPoint tp2 = new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + new Position( + Instant.ofEpochMilli(1), + 0d, + 0.0002, + null, + null, + null, + null, + null), + Distance.of(5), + null, + null, + null, + null); // tp2 has sensor distance - tp1.setSensorDistance(null); - tp2.setSensorDistance(Distance.of(5)); assertEquals(5, tp2.distanceToPrevious(tp1).toM(), 0.01); + } + + @Test + public void distanceToPrevious_sensor_distance_both() { + TrackPoint tp1 = new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + new Position( + Instant.ofEpochMilli(0), + 0d, + 0.0001, + null, + null, + null, + null, + null), + Distance.of(10), + null, + null, + null, + null + ); + + TrackPoint tp2 = new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + new Position( + Instant.ofEpochMilli(1), + 0d, + 0.0002, + null, + null, + null, + null, + null), + Distance.of(5), + null, + null, + null, + null); // tp1 and tp2 have sensor distance - tp1.setSensorDistance(Distance.of(10)); - tp2.setSensorDistance(Distance.of(5)); assertEquals(5, tp2.distanceToPrevious(tp1).toM(), 0.01); } } \ No newline at end of file diff --git a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java index d12a62546..48f3144b0 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java @@ -26,7 +26,6 @@ import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mockito; import java.io.BufferedReader; import java.io.File; @@ -74,7 +73,7 @@ import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingDistanceSpee 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.sensors.sensorData.SensorDataAggregator; import de.dennisguse.opentracks.services.TrackRecordingService; import de.dennisguse.opentracks.services.handlers.TrackPointCreator; @@ -123,11 +122,13 @@ public class ExportImportTest { private TrackImporter trackImporter; @Before - public void fileSetup() throws IOException { + public void fileSetup() throws IOException, TimeoutException { tmpFile = File.createTempFile("test", "test", context.getFilesDir()); tmpFileUri = Uri.fromFile(tmpFile); trackImporter = new TrackImporter(context, contentProviderUtils, Distance.of(200), true); + + setUp(); } @After @@ -158,7 +159,15 @@ public class ExportImportTest { "Marker 1", "Marker 1 desc", "Marker 1 typeLocalized", - service.getLastStoredTrackPointWithLocation().getPosition(), + new Position( + Instant.parse("2020-02-02T02:02:03Z"), + 3.1234567, 14.0014567, + Distance.of(10), + Altitude.WGS84.of(1020.25), + Distance.of(13), + null, + Speed.of(15) + ), null )); @@ -166,7 +175,7 @@ public class ExportImportTest { trackPointCreator.setClock("2020-02-02T02:02:04Z"); mockSensorData(trackPointCreator, 15f, sensorDistance, 66f, 3f, 50f, 1f); - trackPointCreator.setClock("2020-02-02T02:02:14Z"); + trackPointCreator.setClock("2020-02-02T02:02:14Z"); //ignored mockSensorData(trackPointCreator, 15f, null, 67f, 3f, 50f, null); trackPointCreator.setClock("2020-02-02T02:02:15Z"); mockSensorData(trackPointCreator, null, null, 68f, 3f, 50f, null); @@ -181,12 +190,12 @@ public class ExportImportTest { "Marker 2", "Marker 2 desc", "Marker 2 typeLocalized", - service.getLastStoredTrackPointWithLocation().getPosition(), + service.getLastStoredTrackPointWithLocation().position(), null )); trackPointCreator.setClock("2020-02-02T02:02:18Z"); - trackPointCreator.getSensorManager().sensorDataSet = new SensorDataSet(trackPointCreator); + trackPointCreator.getSensorManager().sensorDataAggregator = new SensorDataAggregator(); service.endCurrentTrack(); trackPointCreator.setClock("2020-02-02T02:03:20Z"); @@ -201,7 +210,7 @@ public class ExportImportTest { sendLocation(trackPointCreator, "2020-02-02T02:03:50Z", 3.1234567, 16.001, 10, 27, 15, 999.123, 0f); - trackPointCreator.getSensorManager().sensorDataSet = new SensorDataSet(trackPointCreator); + trackPointCreator.getSensorManager().sensorDataAggregator = new SensorDataAggregator(); trackPointCreator.setClock("2020-02-02T02:04:00Z"); service.endCurrentTrack(); @@ -218,13 +227,126 @@ public class ExportImportTest { @LargeTest @Test public void track() throws TimeoutException { - setUp(); - Track track = contentProviderUtils.getTrack(trackId); Statistics trackStatistics = track.statistics(); assertEquals(ZoneOffset.of("+01:00"), track.zoneOffset()); + List actual = TestDataUtil.getTrackPoints(contentProviderUtils, trackId); + new TrackPointAssert().assertEquals(List.of( + new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse("2020-02-02T02:02:02Z")), + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + new Position( + Instant.parse("2020-02-02T02:02:03Z"), + 3.123456, 14.001456, Distance.of(10), + Altitude.WGS84.of(1020.25), null, + null, + Speed.of(15)), + null, + null, + null, + null, + new AltitudeGainLoss(1, 1) + ), + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + new Position( + Instant.parse("2020-02-02T02:02:04Z"), + null, null, null, + null, null, + null, + Speed.of(15)), + Distance.of(10), + HeartRate.of(66), + Cadence.of(3), + Power.of(50), + new AltitudeGainLoss(1, 1) + ), + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + Position.of(Instant.parse("2020-02-02T02:02:15Z")), + null, + HeartRate.of(68), + Cadence.of(3), + Power.of(50), + null + ), + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + new Position( + Instant.parse("2020-02-02T02:02:17Z"), + 3.123456, 14.001456, Distance.of(10), + Altitude.WGS84.of(1020.25), null, + null, + Speed.of(5)), + Distance.of(2), + HeartRate.of(69), + Cadence.of(3), + Power.of(50), + new AltitudeGainLoss(0, 0) + ), + new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse("2020-02-02T02:02:18Z")), + new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse("2020-02-02T02:03:20Z")), + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + new Position( + Instant.parse("2020-02-02T02:03:21Z"), + 3.123456, 14.002456, Distance.of(10), + Altitude.WGS84.of(999.1229858398438), null, + null, + Speed.of(15)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0) + ), + new TrackPoint( + null, + TrackPoint.Type.SEGMENT_START_AUTOMATIC, + new Position(Instant.parse("2020-02-02T02:03:22Z"), + 3.123456, 16d, Distance.of(10), + Altitude.WGS84.of(999.1229858398438), null, + null, + Speed.of(15)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0) + ), + new TrackPoint( + null, + TrackPoint.Type.IDLE, + Position.of(Instant.parse("2020-02-02T02:03:30Z")), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0) + ), + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + new Position( + Instant.parse("2020-02-02T02:03:50Z"), + 3.123456, 16.001, Distance.of(10), + Altitude.WGS84.of(999.1229858398438), null, + null, Speed.of(15)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0)), + new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse("2020-02-02T02:04:00Z")) + ), actual); + assertEquals(new Statistics( Instant.parse("2020-02-02T02:02:02Z"), Instant.parse("2020-02-02T02:04:00Z"), @@ -238,77 +360,12 @@ public class ExportImportTest { null ), trackStatistics); - - List actual = TestDataUtil.getTrackPoints(contentProviderUtils, trackId); - new TrackPointAssert().assertEquals(List.of( - new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse("2020-02-02T02:02:02Z")), - new TrackPoint(TrackPoint.Type.TRACKPOINT, - new Position( - Instant.parse("2020-02-02T02:02:03Z"), - 3.123456, 14.001456, Distance.of(10), - Altitude.WGS84.of(1020.25), null, - null, - Speed.of(15))) - .setAltitudeGainLoss(1, 1), - new TrackPoint(TrackPoint.Type.TRACKPOINT, - Instant.parse("2020-02-02T02:02:04Z")) - .setSensorDistance(Distance.of(10)) - .setSpeed(Speed.of(15)) - .setHeartRate(HeartRate.of(66)) - .setCadence(3) - .setPower(50).setAltitudeGainLoss(1, 1), - new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse("2020-02-02T02:02:15Z")) - .setHeartRate(HeartRate.of(68)) - .setCadence(3) - .setPower(50), - new TrackPoint(TrackPoint.Type.TRACKPOINT, - new Position( - Instant.parse("2020-02-02T02:02:17Z"), - 3.123456, 14.001456, Distance.of(10), - Altitude.WGS84.of(1020.25), null, - null, - Speed.of(5))) - .setSensorDistance(Distance.of(2)) - .setAltitudeGainLoss(0, 0) - .setHeartRate(HeartRate.of(69)) - .setCadence(3) - .setPower(50), - new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse("2020-02-02T02:02:18Z")), - new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse("2020-02-02T02:03:20Z")), - new TrackPoint(TrackPoint.Type.TRACKPOINT, - new Position( - Instant.parse("2020-02-02T02:03:21Z"), - 3.123456, 14.002456, Distance.of(10), - Altitude.WGS84.of(999.1229858398438), null, - null, - Speed.of(15))) - .setAltitudeGainLoss(0, 0), - new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, - new Position(Instant.parse("2020-02-02T02:03:22Z"), - 3.123456, 16d, Distance.of(10), - Altitude.WGS84.of(999.1229858398438), null, - null, - Speed.of(15))) - .setAltitudeGainLoss(0, 0), - new TrackPoint(TrackPoint.Type.IDLE, Instant.parse("2020-02-02T02:03:30Z")) - .setAltitudeGainLoss(0, 0), - new TrackPoint(TrackPoint.Type.TRACKPOINT, - new Position( - Instant.parse("2020-02-02T02:03:50Z"), - 3.123456, 16.001, Distance.of(10), - Altitude.WGS84.of(999.1229858398438), null, - null, Speed.of(15))) - .setAltitudeGainLoss(0, 0), - new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse("2020-02-02T02:04:00Z")) - ), actual); } //TODO Does not test marker images @LargeTest @Test public void kmz_with_trackdetail_and_sensordata() throws TimeoutException, IOException { - setUp(); - // given Track track = contentProviderUtils.getTrack(trackId); @@ -361,8 +418,6 @@ public class ExportImportTest { @LargeTest @Test(expected = ImportAlreadyExistsException.class) public void kml_with_trackdetail_and_sensordata_duplicate_trackUUID() throws TimeoutException, IOException { - setUp(); - // given SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit(); editor.putBoolean(context.getString(R.string.import_prevent_reimport_key), true); @@ -387,8 +442,6 @@ public class ExportImportTest { @LargeTest @Test public void gpx() throws TimeoutException, IOException { - setUp(); - // given Track track = contentProviderUtils.getTrack(trackId); @@ -421,51 +474,81 @@ public class ExportImportTest { .setDelta(0.05); // speed is not fully List actual = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId); a.assertEquals(List.of( - new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, + new TrackPoint( + null, + TrackPoint.Type.SEGMENT_START_AUTOMATIC, new Position( Instant.parse("2020-02-02T02:02:03Z"), 3.123456, 14.001456d, Distance.of(10), Altitude.WGS84.of(1020.2), null, null, - Speed.of(15))) - .setAltitudeGainLoss(1, 1), - new TrackPoint(TrackPoint.Type.TRACKPOINT, + Speed.of(15)), + null, + null, + null, + null, + new AltitudeGainLoss(1, 1) + ), + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, new Position( Instant.parse("2020-02-02T02:02:17Z"), 3.123456, 14.001456, Distance.of(10), Altitude.WGS84.of(1020.2), null, null, - Speed.of(5))) - .setAltitudeGainLoss(1, 1) - .setSensorDistance(Distance.of(12)) - .setHeartRate(69) - .setPower(50f) - .setCadence(3f), - new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, + Speed.of(5)), + Distance.of(12), + HeartRate.of(69), + Cadence.of(3), + Power.of(50), + new AltitudeGainLoss(1, 1) + ), + new TrackPoint( + null, + TrackPoint.Type.SEGMENT_START_AUTOMATIC, new Position( Instant.parse("2020-02-02T02:03:21Z"), 3.123456, 14.002456, Distance.of(10), Altitude.WGS84.of(999.0999755859375), null, null, - Speed.of(15))) - .setAltitudeGainLoss(0, 0), - new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, + Speed.of(15)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0) + ), + new TrackPoint( + null, + TrackPoint.Type.SEGMENT_START_AUTOMATIC, new Position( Instant.parse("2020-02-02T02:03:22Z"), 3.123456, 16d, Distance.of(10), Altitude.WGS84.of(999.0999755859375), null, null, - Speed.of(15))) - .setAltitudeGainLoss(0, 0), - new TrackPoint(TrackPoint.Type.TRACKPOINT, + Speed.of(15)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0) + ), + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, new Position( Instant.parse("2020-02-02T02:03:50Z"), 3.123456, 16.001, Distance.of(10), Altitude.WGS84.of(999.0999755859375), null, null, - Speed.of(10))) - .setAltitudeGainLoss(0, 0) - .setSpeed(Speed.of(15)) + Speed.of(15)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0) + ) ), actual); // 3. trackstatistics @@ -493,8 +576,6 @@ public class ExportImportTest { @LargeTest @Test(expected = ImportAlreadyExistsException.class) public void gpx_duplicate_trackUUID() throws TimeoutException, IOException { - setUp(); - // given SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit(); editor.putBoolean(context.getString(R.string.import_prevent_reimport_key), true); @@ -521,8 +602,6 @@ public class ExportImportTest { @LargeTest @Test public void csv_export_only() throws TimeoutException, IOException { - setUp(); - // given Track track = contentProviderUtils.getTrack(trackId); @@ -567,16 +646,16 @@ public class ExportImportTest { } private void mockSensorData(TrackPointCreator trackPointCreator, Float speed, Distance distance, float heartRate, float cadence, Float power, Float altitudeGain) { - SensorDataSet sensorDataSet = trackPointCreator.getSensorManager().sensorDataSet; + SensorDataAggregator sensorDataAggregator = trackPointCreator.getSensorManager().sensorDataAggregator; AggregatorCyclingPower cyclingPower = new AggregatorCyclingPower("", ""); cyclingPower.add(new Raw<>(trackPointCreator.createNow(), new BluetoothHandlerManagerCyclingPower.Data(Power.of(power), null))); - sensorDataSet.add(cyclingPower); + sensorDataAggregator.add(cyclingPower); AggregatorHeartRate avgHeartRate = new AggregatorHeartRate("", ""); avgHeartRate.add(new Raw<>(trackPointCreator.createNow(), HeartRate.of(heartRate))); - sensorDataSet.add(avgHeartRate); + sensorDataAggregator.add(avgHeartRate); AggregatorCyclingCadence cyclingCadence = new AggregatorCyclingCadence("", "") { @NonNull @@ -590,33 +669,52 @@ public class ExportImportTest { return true; } }; - sensorDataSet.add(cyclingCadence); + sensorDataAggregator.add(cyclingCadence); if (distance != null && speed != null) { - AggregatorCyclingDistanceSpeed distanceSpeed = Mockito.mock(AggregatorCyclingDistanceSpeed.class); - Mockito.when(distanceSpeed.hasReceivedData()).thenReturn(true); - Mockito.when(distanceSpeed.getAggregatedValue(Mockito.any())).thenReturn(new AggregatorCyclingDistanceSpeed.Data(null, distance, Speed.of(speed))); - sensorDataSet.add(distanceSpeed); + AggregatorCyclingDistanceSpeed aggregatorCyclingDistanceSpeed = new AggregatorCyclingDistanceSpeed("", "") { + @NonNull + @Override + public Data getAggregatedValue(Instant now) { + return new AggregatorCyclingDistanceSpeed.Data(null, distance, Speed.of(speed)); + } + + @Override + public boolean hasReceivedData() { + return true; + } + }; + sensorDataAggregator.add(aggregatorCyclingDistanceSpeed); } else { - sensorDataSet.add(new AggregatorCyclingDistanceSpeed("", "")); + sensorDataAggregator.add(new AggregatorCyclingDistanceSpeed("", "")); } mockAltitudeChange(trackPointCreator, altitudeGain); - trackPointCreator.onChange(sensorDataSet); + trackPointCreator.onChange(); } private void mockAltitudeChange(TrackPointCreator trackPointCreator, Float altitudeGain) { - SensorDataSet sensorDataSet = trackPointCreator.getSensorManager().sensorDataSet; + SensorDataAggregator sensorDataAggregator = trackPointCreator.getSensorManager().sensorDataAggregator; - if (altitudeGain != null) { - AggregatorBarometer barometer = Mockito.mock(AggregatorBarometer.class); - Mockito.when(barometer.hasReceivedData()).thenReturn(true); - Mockito.when(barometer.getAggregatedValue(Mockito.any())).thenReturn(new AltitudeGainLoss(altitudeGain, altitudeGain)); - sensorDataSet.add(barometer); - } else { - sensorDataSet.add(new AggregatorBarometer("test", null)); + if (altitudeGain == null) { + sensorDataAggregator.add(new AggregatorBarometer("test", null)); + return; } + + AggregatorBarometer aggregatorBarometer = new AggregatorBarometer("", "") { + @NonNull + @Override + public AltitudeGainLoss getAggregatedValue(Instant now) { + return new AltitudeGainLoss(altitudeGain, altitudeGain); + } + + @Override + public boolean hasReceivedData() { + return true; + } + }; + sensorDataAggregator.add(aggregatorBarometer); } private void sendLocation(TrackPointCreator trackPointCreator, String time, double latitude, double longitude, float accuracy, float verticalAccuracy, float speed, double altitude, Float altitudeGain) { diff --git a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/GPXTrackImporterTest.java b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/GPXTrackImporterTest.java index 81179fbc1..b4b37253e 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/GPXTrackImporterTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/GPXTrackImporterTest.java @@ -27,8 +27,12 @@ import de.dennisguse.opentracks.content.data.TestDataUtil; import de.dennisguse.opentracks.data.ContentProviderUtils; import de.dennisguse.opentracks.data.models.ActivityType; import de.dennisguse.opentracks.data.models.Altitude; +import de.dennisguse.opentracks.data.models.AltitudeGainLoss; +import de.dennisguse.opentracks.data.models.Cadence; import de.dennisguse.opentracks.data.models.Distance; +import de.dennisguse.opentracks.data.models.HeartRate; import de.dennisguse.opentracks.data.models.Position; +import de.dennisguse.opentracks.data.models.Power; import de.dennisguse.opentracks.data.models.Speed; import de.dennisguse.opentracks.data.models.Statistics; import de.dennisguse.opentracks.data.models.Track; @@ -193,51 +197,81 @@ public class GPXTrackImporterTest { TrackPointAssert a = new TrackPointAssert() .setDelta(0.05); // speed is not fully a.assertEquals(List.of( - new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, + new TrackPoint( + null, + TrackPoint.Type.SEGMENT_START_AUTOMATIC, new Position( Instant.parse("2020-02-02T02:02:03Z"), 3d, 14d, Distance.of(10), Altitude.WGS84.of(10), null, null, - Speed.of(15))) - .setAltitudeGainLoss(1, 1), - new TrackPoint(TrackPoint.Type.TRACKPOINT, + Speed.of(15)), + null, + null, + null, + null, + new AltitudeGainLoss(1, 1) + ), + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, new Position( Instant.parse("2020-02-02T02:02:17Z"), 3d, 14.001, Distance.of(10), Altitude.WGS84.of(10), null, null, - Speed.of(5))) - .setAltitudeGainLoss(1, 1) - .setSensorDistance(Distance.of(12)) - .setHeartRate(69) - .setPower(50f) - .setCadence(3f), - new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, + Speed.of(5)), + Distance.of(12), + HeartRate.of(69), + Cadence.of(3), + Power.of(50), + new AltitudeGainLoss(1, 1) + ), + new TrackPoint( + null, + TrackPoint.Type.SEGMENT_START_AUTOMATIC, new Position( Instant.parse("2020-02-02T02:03:21Z"), 3d, 14.002, Distance.of(10), Altitude.WGS84.of(10), null, null, - Speed.of(15))) - .setAltitudeGainLoss(0, 0), - new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, + Speed.of(15)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0) + ), + new TrackPoint( + null, + TrackPoint.Type.SEGMENT_START_AUTOMATIC, new Position( Instant.parse("2020-02-02T02:03:22Z"), 3d, 16d, Distance.of(10), Altitude.WGS84.of(10), null, null, - Speed.of(15))) - .setAltitudeGainLoss(0, 0), - new TrackPoint(TrackPoint.Type.TRACKPOINT, + Speed.of(15)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0) + ), + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, new Position( Instant.parse("2020-02-02T02:03:50Z"), 3d, 16.001, Distance.of(10), Altitude.WGS84.of(10), null, null, - Speed.of(10))) - .setAltitudeGainLoss(0, 0) - .setSpeed(Speed.of(15)) + Speed.of(15)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0) + ) ), actual); } @@ -247,7 +281,7 @@ public class GPXTrackImporterTest { // given XMLImporter importer = new XMLImporter(new GPXTrackImporter(context, trackImporter)); InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.gpx_timezone); - try(InputStream inputStreamExpected = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.gpx_timezone)) { + try (InputStream inputStreamExpected = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.gpx_timezone)) { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); // when diff --git a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/TrackPointAssert.java b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/TrackPointAssert.java index b1c8fe7d1..96239821e 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/TrackPointAssert.java +++ b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/TrackPointAssert.java @@ -16,57 +16,45 @@ public class TrackPointAssert { public void assertEquals(TrackPoint expected, TrackPoint actual) { Assert.assertEquals("time", expected.getTime(), actual.getTime()); - Assert.assertEquals("type", expected.getType(), actual.getType()); + Assert.assertEquals("type", expected.type(), actual.type()); - Assert.assertEquals("has location,", expected.hasLocation(), actual.hasLocation()); - if (expected.hasLocation()) { - Assert.assertEquals("latitude", expected.getPosition().latitude(), actual.getPosition().latitude(), 0.001); - Assert.assertEquals("longitude", expected.getPosition().longitude(), actual.getPosition().longitude(), 0.001); + Assert.assertEquals("has location,", expected.position().hasLocation(), actual.position().hasLocation()); + if (expected.position().hasLocation()) { + Assert.assertEquals("latitude", expected.position().latitude(), actual.position().latitude(), 0.001); + Assert.assertEquals("longitude", expected.position().longitude(), actual.position().longitude(), 0.001); } - Assert.assertEquals("has altitude", expected.hasAltitude(), actual.hasAltitude()); - if (expected.hasAltitude()) { - Assert.assertEquals("altitude", expected.getAltitude().toM(), actual.getAltitude().toM(), delta); + Assert.assertEquals("has altitude", expected.position().hasAltitude(), actual.position().hasAltitude()); + if (expected.position().hasAltitude()) { + Assert.assertEquals("altitude", expected.position().altitude().toM(), actual.position().altitude().toM(), delta); } - Assert.assertEquals("has altitudeGainLoss", expected.hasAltitudeGainLoss(), actual.hasAltitudeGainLoss()); - if (expected.hasAltitudeGainLoss()) { - Assert.assertEquals("altitudeGainLoss", expected.getAltitudeGainLoss(), actual.getAltitudeGainLoss()); + Assert.assertEquals("altitudeGainLoss", expected.altitudeGainLoss(), actual.altitudeGainLoss()); + + Assert.assertEquals("has speed", expected.position().hasSpeed(), actual.position().hasSpeed()); + if (expected.position().hasSpeed()) { + Assert.assertEquals("speed", expected.position().speed().toMPS(), actual.position().speed().toMPS(), delta); } - Assert.assertEquals("has speed", expected.hasSpeed(), actual.hasSpeed()); - if (expected.hasSpeed()) { - Assert.assertEquals("speed", expected.getSpeed().toMPS(), actual.getSpeed().toMPS(), delta); + Assert.assertEquals("has horizontalAccuracy", expected.position().hasHorizontalAccuracy(), actual.position().hasHorizontalAccuracy()); + if (expected.position().hasHorizontalAccuracy()) { + Assert.assertEquals("horizontalAccuracy", expected.position().horizontalAccuracy().toM(), actual.position().horizontalAccuracy().toM(), delta); + } + Assert.assertEquals("has verticalAccuracy", expected.position().hasVerticalAccuracy(), actual.position().hasVerticalAccuracy()); + if (expected.position().hasVerticalAccuracy()) { + Assert.assertEquals("verticalAccuracy", expected.position().verticalAccuracy().toM(), actual.position().verticalAccuracy().toM(), delta); } - Assert.assertEquals("has horizontalAccuracy", expected.hasHorizontalAccuracy(), actual.hasHorizontalAccuracy()); - if (expected.hasHorizontalAccuracy()) { - Assert.assertEquals("horizontalAccuracy", expected.getHorizontalAccuracy().toM(), actual.getHorizontalAccuracy().toM(), delta); - } - Assert.assertEquals("has verticalAccuracy", expected.hasVerticalAccuracy(), actual.hasVerticalAccuracy()); - if (expected.hasVerticalAccuracy()) { - Assert.assertEquals("verticalAccuracy", expected.getVerticalAccuracy().toM(), actual.getVerticalAccuracy().toM(), delta); + Assert.assertEquals("has sensorDistance", expected.sensorDistance() != null, actual.sensorDistance() != null); + if (expected.sensorDistance() != null) { + Assert.assertEquals("sensorDistance", expected.sensorDistance().toM(), actual.sensorDistance().toM(), delta); } - Assert.assertEquals("has sensorDistance", expected.hasSensorDistance(), actual.hasSensorDistance()); - if (expected.hasSensorDistance()) { - Assert.assertEquals("sensorDistance", expected.getSensorDistance().toM(), actual.getSensorDistance().toM(), delta); - } + Assert.assertEquals("heartRate", expected.heartRate(), actual.heartRate()); - Assert.assertEquals("has heartrate", expected.hasHeartRate(), actual.hasHeartRate()); - if (expected.hasHeartRate()) { - Assert.assertEquals("heartrate", expected.getHeartRate(), actual.getHeartRate()); - } + Assert.assertEquals("power", expected.power(), actual.power()); - Assert.assertEquals("has power", expected.hasPower(), actual.hasPower()); - if (expected.hasPower()) { - Assert.assertEquals("power", expected.getPower(), actual.getPower()); - } - - Assert.assertEquals("has cadence", expected.hasCadence(), actual.hasCadence()); - if (expected.hasCadence()) { - Assert.assertEquals("cadence", expected.getCadence(), actual.getCadence()); - } + Assert.assertEquals("cadence", expected.cadence(), actual.cadence()); } public void assertEquals(List expected, List actual) { diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java index 7abfcecf3..97cd6a0b4 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceRecordingTest.java @@ -35,6 +35,7 @@ import de.dennisguse.opentracks.TestUtil; import de.dennisguse.opentracks.content.data.TestDataUtil; import de.dennisguse.opentracks.data.ContentProviderUtils; import de.dennisguse.opentracks.data.models.AltitudeGainLoss; +import de.dennisguse.opentracks.data.models.Cadence; import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.HeartRate; import de.dennisguse.opentracks.data.models.Position; @@ -126,8 +127,15 @@ public class TrackRecordingServiceRecordingTest { new TrackPointAssert().assertEquals(List.of( new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)), - new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime)) - .setAltitudeGainLoss(0, 0) + new TrackPoint( + null, + TrackPoint.Type.SEGMENT_END_MANUAL, + Position.of(Instant.parse(stopTime)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0)) ), TestDataUtil.getTrackPoints(contentProviderUtils, trackId)); } @@ -201,8 +209,15 @@ public class TrackRecordingServiceRecordingTest { new TrackPointAssert().assertEquals(List.of( new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)), - new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(pauseTime)) - .setAltitudeGainLoss(0, 0) + new TrackPoint( + null, + TrackPoint.Type.SEGMENT_END_MANUAL, + Position.of(Instant.parse(pauseTime)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0)) ), TestDataUtil.getTrackPoints(contentProviderUtils, trackId)); //when @@ -216,8 +231,16 @@ public class TrackRecordingServiceRecordingTest { new TrackPointAssert().assertEquals(List.of( new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)), - new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(pauseTime)) - .setAltitudeGainLoss(0, 0), + new TrackPoint( + null, + TrackPoint.Type.SEGMENT_END_MANUAL, + Position.of(Instant.parse(pauseTime)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0) + ), new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(resumeTime)) ), TestDataUtil.getTrackPoints(contentProviderUtils, trackId)); } @@ -249,8 +272,15 @@ public class TrackRecordingServiceRecordingTest { List trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId); new TrackPointAssert().assertEquals(List.of( new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(starTime)), - new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(pauseTime)) - .setAltitudeGainLoss(0, 0) + new TrackPoint( + null, + TrackPoint.Type.SEGMENT_END_MANUAL, + Position.of(Instant.parse(pauseTime)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0)) ), trackPoints); } @@ -278,8 +308,16 @@ public class TrackRecordingServiceRecordingTest { // then new TrackPointAssert().assertEquals(List.of( new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)), - new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime)) - .setAltitudeGainLoss(0, 0), + new TrackPoint( + null, + TrackPoint.Type.SEGMENT_END_MANUAL, + Position.of(Instant.parse(stopTime)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0) + ), new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(resumeTime)) ), TestDataUtil.getTrackPoints(contentProviderUtils, trackId)); } @@ -296,7 +334,7 @@ public class TrackRecordingServiceRecordingTest { mockAltitudeChange(trackPointCreator, 0); SensorManager sensorManager = trackPointCreator.getSensorManager(); - sensorManager.sensorDataSet.add(new AggregatorHeartRate("", "")); + sensorManager.sensorDataAggregator.add(new AggregatorHeartRate("", "")); // when String sensor1 = "2020-02-02T02:02:03Z"; trackPointCreator.setClock(sensor1); @@ -314,12 +352,26 @@ public class TrackRecordingServiceRecordingTest { // then new TrackPointAssert().assertEquals(List.of( new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)), - new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(sensor3)) - .setAltitudeGainLoss(0, 0) - .setHeartRate(HeartRate.of(7)), - new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime)) - .setAltitudeGainLoss(0, 0) - .setHeartRate(HeartRate.of(7)) + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + Position.of(Instant.parse(sensor3)), + null, + HeartRate.of(7), + null, + null, + new AltitudeGainLoss(0, 0) + ), + new TrackPoint( + null, + TrackPoint.Type.SEGMENT_END_MANUAL, + Position.of(Instant.parse(stopTime)), + null, + HeartRate.of(7), + null, + null, + new AltitudeGainLoss(0, 0) + ) ), TestDataUtil.getTrackPoints(contentProviderUtils, trackId)); } @@ -369,32 +421,61 @@ public class TrackRecordingServiceRecordingTest { new TrackPointAssert().assertEquals(List.of( new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)), - new TrackPoint(TrackPoint.Type.TRACKPOINT, + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, new Position( Instant.parse(gps1), 45d, 35d, Distance.of(1), null, null, null, - Speed.of(15))) - .setAltitudeGainLoss(0, 0), - new TrackPoint(TrackPoint.Type.TRACKPOINT, + Speed.of(15)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0) + ), + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, new Position( Instant.parse(gps2), 45.001, 35d, Distance.of(1), null, null, null, - Speed.of(15))) - .setAltitudeGainLoss(0, 0), - new TrackPoint(TrackPoint.Type.TRACKPOINT, + Speed.of(15)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0) + ), + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, new Position( Instant.parse(gps3), 45.001, 35d, Distance.of(1), null, null, null, - Speed.of(15))) - .setAltitudeGainLoss(0, 0), - new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime)) - .setAltitudeGainLoss(0, 0) + Speed.of(15)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0) + ), + new TrackPoint( + null, + TrackPoint.Type.SEGMENT_END_MANUAL, + Position.of(Instant.parse(stopTime)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0) + ) ), TestDataUtil.getTrackPoints(contentProviderUtils, trackId)); } @@ -441,30 +522,51 @@ public class TrackRecordingServiceRecordingTest { new TrackPointAssert().assertEquals(List.of( new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)), - new TrackPoint(TrackPoint.Type.TRACKPOINT, + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, new Position( Instant.parse(gps1), 45d, 35d, Distance.of(1), null, null, null, - Speed.of(15))) - .setAltitudeGainLoss(0, 0), - new TrackPoint(TrackPoint.Type.TRACKPOINT, + Speed.of(15)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0) + ), + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, new Position( Instant.parse(gps3), 45.00002, 35d, Distance.of(1), null, null, null, - Speed.of(15))) - .setAltitudeGainLoss(0, 0), - new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, + Speed.of(15)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0) + ), + new TrackPoint( + null, + TrackPoint.Type.SEGMENT_END_MANUAL, new Position( Instant.parse(stopTime), 45.00002, 35d, Distance.of(1), null, null, null, - Speed.of(15))) - .setAltitudeGainLoss(0, 0) + Speed.of(15)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0) + ) ), TestDataUtil.getTrackPoints(contentProviderUtils, trackId)); } @@ -499,24 +601,44 @@ public class TrackRecordingServiceRecordingTest { // then new TrackPointAssert().assertEquals(List.of( new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)), - new TrackPoint(TrackPoint.Type.TRACKPOINT, + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, new Position( Instant.parse(gps1), 45d, 35d, Distance.of(1), null, null, null, - Speed.of(15))) - .setAltitudeGainLoss(0, 0), - new TrackPoint(TrackPoint.Type.TRACKPOINT, + Speed.of(15)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0) + ), + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, new Position( Instant.parse(gps3), 45d, 35d, Distance.of(1), null, null, null, - Speed.of(15))) - .setAltitudeGainLoss(0, 0), - new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime)) - .setAltitudeGainLoss(0, 0) + Speed.of(15)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0)), + new TrackPoint( + null, + TrackPoint.Type.SEGMENT_END_MANUAL, + Position.of(Instant.parse(stopTime)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0)) ), TestDataUtil.getTrackPoints(contentProviderUtils, trackId)); } @@ -559,8 +681,15 @@ public class TrackRecordingServiceRecordingTest { // then new TrackPointAssert().assertEquals(List.of( new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)), - new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime)) - .setAltitudeGainLoss(0, 0) + new TrackPoint( + null, + TrackPoint.Type.SEGMENT_END_MANUAL, + Position.of(Instant.parse(stopTime)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0)) ), TestDataUtil.getTrackPoints(contentProviderUtils, trackId)); } @@ -603,24 +732,45 @@ public class TrackRecordingServiceRecordingTest { // then new TrackPointAssert().assertEquals(List.of( new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)), - new TrackPoint(TrackPoint.Type.TRACKPOINT, + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, new Position( Instant.parse(gps1), 45d, 35d, Distance.of(1), null, null, null, - Speed.of(15))) - .setAltitudeGainLoss(0, 0), - new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, + Speed.of(15)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0) + ), + new TrackPoint( + null, + TrackPoint.Type.SEGMENT_START_AUTOMATIC, new Position( Instant.parse(gps2), 45.1, 35d, Distance.of(1), null, null, null, - Speed.of(15))) - .setAltitudeGainLoss(0, 0), - new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime)) - .setAltitudeGainLoss(0, 0) + Speed.of(15)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0) + ), + new TrackPoint( + null, + TrackPoint.Type.SEGMENT_END_MANUAL, + Position.of(Instant.parse(stopTime)), + null, + null, + null, + null, + new AltitudeGainLoss(0, 0)) ), TestDataUtil.getTrackPoints(contentProviderUtils, trackId)); } @@ -638,18 +788,18 @@ public class TrackRecordingServiceRecordingTest { Track.Id trackId = service.startNewTrack(); SensorManager sensorManager = trackPointCreator.getSensorManager(); - sensorManager.sensorDataSet.add(new AggregatorRunning("", "")); - sensorManager.sensorDataSet.barometer = null; + sensorManager.sensorDataAggregator.add(new AggregatorRunning("", "")); + sensorManager.sensorDataAggregator.barometer = null; // when String sensor1 = "2020-02-02T02:02:03Z"; trackPointCreator.setClock(sensor1); - sensorManager.onChanged(new Raw<>(sensor1, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), null, Distance.ZERO))); //Should be ignored + sensorManager.onChanged(new Raw<>(sensor1, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(1), Distance.ZERO))); //Should be ignored // when String sensor2 = "2020-02-02T02:02:04Z"; trackPointCreator.setClock(sensor2); - sensorManager.onChanged(new Raw<>(sensor2, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), null, Distance.of(2)))); + sensorManager.onChanged(new Raw<>(sensor2, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(2), Distance.of(2)))); // when String gps1 = "2020-02-02T02:02:05Z"; @@ -658,12 +808,12 @@ public class TrackRecordingServiceRecordingTest { // when String sensor3 = "2020-02-02T02:02:06Z"; trackPointCreator.setClock(sensor3); - sensorManager.onChanged(new Raw<>(sensor3, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), null, Distance.of(12)))); + sensorManager.onChanged(new Raw<>(sensor3, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(3), Distance.of(12)))); // when String sensor4 = "2020-02-02T02:02:07Z"; trackPointCreator.setClock(sensor4); - sensorManager.onChanged(new Raw<>(sensor4, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), null, Distance.of(14)))); //Should be ignored + sensorManager.onChanged(new Raw<>(sensor4, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(4), Distance.of(14)))); //Should be ignored // when String gps2 = "2020-02-02T02:02:08Z"; @@ -672,7 +822,7 @@ public class TrackRecordingServiceRecordingTest { // when String sensor5 = "2020-02-02T02:02:10Z"; trackPointCreator.setClock(sensor5); - sensorManager.onChanged(new Raw<>(sensor5, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), null, Distance.of(16)))); //Should be ignored + sensorManager.onChanged(new Raw<>(sensor5, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(5), Distance.of(16)))); //Should be ignored // when String gps3 = "2020-02-02T02:02:12Z"; @@ -691,49 +841,101 @@ public class TrackRecordingServiceRecordingTest { // then new TrackPointAssert().assertEquals(List.of( new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)), - new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(sensor2)) //First moving TrackPoint: store as the time might be interesting. - .setSpeed(Speed.of(5)) - .setSensorDistance(Distance.of(2)), - new TrackPoint(TrackPoint.Type.TRACKPOINT, + new TrackPoint( //First moving TrackPoint: stored as the time might be interesting. + null, + TrackPoint.Type.TRACKPOINT, + new Position( + Instant.parse(sensor2), + null, null, null, + null, null, + null, + Speed.of(5)), + Distance.of(2), + null, + Cadence.of(2), + null, + null + ), + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, new Position( Instant.parse(gps1), 45d, 35d, Distance.of(1), null, null, null, - Speed.of(5))) - .setSensorDistance(Distance.ZERO), - new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(sensor3)) - .setSpeed(Speed.of(5)) - .setSensorDistance(Distance.of(10)), - new TrackPoint(TrackPoint.Type.TRACKPOINT, + Speed.of(5)), + Distance.ZERO, + null, + Cadence.of(2), + null, + null + ), + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + new Position( + Instant.parse(sensor3), + null, null, null, + null, null, + null, + Speed.of(5)), + Distance.of(10), + null, + Cadence.of(3), + null, + null + ), + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, new Position( Instant.parse(gps3), 45.001, 35d, Distance.of(1), null, null, null, - Speed.of(5))) - .setSensorDistance(Distance.of(4.0)), - new TrackPoint(TrackPoint.Type.TRACKPOINT, + Speed.of(5)), + Distance.of(4.0), + null, + Cadence.of(5), + null, + null + ), + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, new Position( Instant.parse(gps4), 45.001, 35d, Distance.of(1), null, null, null, - Speed.of(5))) - .setSensorDistance(Distance.ZERO), - new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, + Speed.of(5)), + Distance.ZERO, + null, + Cadence.of(5), + null, + null + ), + new TrackPoint( + null, + TrackPoint.Type.SEGMENT_END_MANUAL, new Position( Instant.parse(stopTime), 45.001, 35d, Distance.of(1), null, null, null, - Speed.ZERO)) //Sensor data is now outdated, but we do not fall back to GPS. - .setSensorDistance(Distance.ZERO) + Speed.ZERO), //Sensor data is now outdated, but we do not fall back to GPS. + Distance.ZERO, + null, + Cadence.of(0), //TODO This could be null, right? + null, + null + ) ), TestDataUtil.getTrackPoints(contentProviderUtils, trackId)); } private void mockAltitudeChange(TrackPointCreator trackPointCreator, float altitudeGain) { - trackPointCreator.getSensorManager().sensorDataSet.barometer = new AggregatorBarometer("", "") { + trackPointCreator.getSensorManager().sensorDataAggregator.barometer = new AggregatorBarometer("", "") { @Override public boolean hasReceivedData() { return true; diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceStateMachineTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceStateMachineTest.java index 8bac0bcb9..b699a75f7 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceStateMachineTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceStateMachineTest.java @@ -45,6 +45,7 @@ import java.util.List; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import de.dennisguse.opentracks.TestUtil; import de.dennisguse.opentracks.data.ContentProviderUtils; import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.sensors.GpsStatusValue; @@ -60,7 +61,7 @@ public class TrackRecordingServiceStateMachineTest { public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(5, TimeUnit.SECONDS); @Rule - public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION); + public GrantPermissionRule mRuntimePermissionRule = TestUtil.createGrantPermissionRule(); private final Context context = ApplicationProvider.getApplicationContext(); private ContentProviderUtils contentProviderUtils; diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtilsTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtilsTest.java index 38ea9bdb0..d5d15252e 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtilsTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtilsTest.java @@ -15,7 +15,6 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mockito; import java.time.Duration; import java.time.Instant; @@ -34,10 +33,11 @@ import de.dennisguse.opentracks.data.models.Speed; import de.dennisguse.opentracks.data.models.Statistics; import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.models.TrackPoint; +import de.dennisguse.opentracks.data.statistics.SensorStatistics; +import de.dennisguse.opentracks.sensors.sensorData.SensorData; import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet; import de.dennisguse.opentracks.settings.PreferencesUtils; import de.dennisguse.opentracks.settings.UnitSystem; -import de.dennisguse.opentracks.data.statistics.SensorStatistics; import de.dennisguse.opentracks.ui.intervals.IntervalStatisticsUpdater; //Due to DateTimeFormatter using NBSP, these tests only work in SDK34+ @@ -84,8 +84,15 @@ public class VoiceAnnouncementUtilsTest { null )); - SensorDataSet dataSet = Mockito.mock(SensorDataSet.class); - Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused")); + SensorDataSet dataSet = new SensorDataSet( + null, + null, + null, + new SensorData<>(HeartRate.of(60), "unused"), + null, + null, + null + ); // when String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, true, null, null).toString(); @@ -117,8 +124,15 @@ public class VoiceAnnouncementUtilsTest { null )); - SensorDataSet dataSet = Mockito.mock(SensorDataSet.class); - Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused")); + SensorDataSet dataSet = new SensorDataSet( + null, + null, + null, + new SensorData<>(HeartRate.of(60), "unused"), + null, + null, + null + ); // when String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, true, null, null).toString(); @@ -150,8 +164,15 @@ public class VoiceAnnouncementUtilsTest { null )); - SensorDataSet dataSet = Mockito.mock(SensorDataSet.class); - Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused")); + SensorDataSet dataSet = new SensorDataSet( + null, + null, + null, + new SensorData<>(HeartRate.of(60), "unused"), + null, + null, + null + ); // when String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, true, null, null).toString(); @@ -183,8 +204,15 @@ public class VoiceAnnouncementUtilsTest { null )); - SensorDataSet dataSet = Mockito.mock(SensorDataSet.class); - Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused")); + SensorDataSet dataSet = new SensorDataSet( + null, + null, + null, + new SensorData<>(HeartRate.of(60), "unused"), + null, + null, + null + ); // when String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, true, null, null).toString(); @@ -198,8 +226,15 @@ public class VoiceAnnouncementUtilsTest { // given Pair data = buildTrackWithTrackPoints(); - SensorDataSet dataSet = Mockito.mock(SensorDataSet.class); - Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused")); + SensorDataSet dataSet = new SensorDataSet( + null, + null, + null, + new SensorData<>(HeartRate.of(60), "unused"), + null, + null, + null + ); // when String announcement = VoiceAnnouncementUtils.createStatistics(context, data.first, dataSet, UnitSystem.METRIC, true, data.second, null).toString(); @@ -231,8 +266,15 @@ public class VoiceAnnouncementUtilsTest { null )); - SensorDataSet dataSet = Mockito.mock(SensorDataSet.class); - Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused")); + SensorDataSet dataSet = new SensorDataSet( + null, + null, + null, + new SensorData<>(HeartRate.of(60), "unused"), + null, + null, + null + ); // when String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, false, null, null).toString(); @@ -246,8 +288,15 @@ public class VoiceAnnouncementUtilsTest { // given Pair data = buildTrackWithTrackPoints(); - SensorDataSet dataSet = Mockito.mock(SensorDataSet.class); - Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused")); + SensorDataSet dataSet = new SensorDataSet( + null, + null, + null, + new SensorData<>(HeartRate.of(60), "unused"), + null, + null, + null + ); // when String announcement = VoiceAnnouncementUtils.createStatistics(context, data.first, dataSet, UnitSystem.METRIC, false, data.second, null).toString(); @@ -279,8 +328,15 @@ public class VoiceAnnouncementUtilsTest { null )); - SensorDataSet dataSet = Mockito.mock(SensorDataSet.class); - Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused")); + SensorDataSet dataSet = new SensorDataSet( + null, + null, + null, + new SensorData<>(HeartRate.of(60), "unused"), + null, + null, + null + ); // when String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.IMPERIAL_FEET, true, null, null).toString(); @@ -312,8 +368,15 @@ public class VoiceAnnouncementUtilsTest { null )); - SensorDataSet dataSet = Mockito.mock(SensorDataSet.class); - Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused")); + SensorDataSet dataSet = new SensorDataSet( + null, + null, + null, + new SensorData<>(HeartRate.of(60), "unused"), + null, + null, + null + ); // when String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.IMPERIAL_FEET, true, null, null).toString(); @@ -345,8 +408,15 @@ public class VoiceAnnouncementUtilsTest { null )); - SensorDataSet dataSet = Mockito.mock(SensorDataSet.class); - Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused")); + SensorDataSet dataSet = new SensorDataSet( + null, + null, + null, + new SensorData<>(HeartRate.of(60), "unused"), + null, + null, + null + ); // when String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.IMPERIAL_METER, true, null, null).toString(); @@ -378,8 +448,15 @@ public class VoiceAnnouncementUtilsTest { null )); - SensorDataSet dataSet = Mockito.mock(SensorDataSet.class); - Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused")); + SensorDataSet dataSet = new SensorDataSet( + null, + null, + null, + new SensorData<>(HeartRate.of(60), "unused"), + null, + null, + null + ); // when String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, true, null, null).toString(); @@ -393,8 +470,15 @@ public class VoiceAnnouncementUtilsTest { // given Pair data = buildTrackWithTrackPoints(); - SensorDataSet dataSet = Mockito.mock(SensorDataSet.class); - Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused")); + SensorDataSet dataSet = new SensorDataSet( + null, + null, + null, + new SensorData<>(HeartRate.of(60), "unused"), + null, + null, + null + ); // when String announcement = VoiceAnnouncementUtils.createStatistics(context, data.first, dataSet, UnitSystem.IMPERIAL_FEET, true, data.second, null).toString(); @@ -426,8 +510,15 @@ public class VoiceAnnouncementUtilsTest { null )); - SensorDataSet dataSet = Mockito.mock(SensorDataSet.class); - Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused")); + SensorDataSet dataSet = new SensorDataSet( + null, + null, + null, + new SensorData<>(HeartRate.of(60), "unused"), + null, + null, + null + ); // when String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.IMPERIAL_FEET, false, null, null).toString(); @@ -441,8 +532,15 @@ public class VoiceAnnouncementUtilsTest { // given Pair data = buildTrackWithTrackPoints(); - SensorDataSet dataSet = Mockito.mock(SensorDataSet.class); - Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused")); + SensorDataSet dataSet = new SensorDataSet( + null, + null, + null, + new SensorData<>(HeartRate.of(60), "unused"), + null, + null, + null + ); // when String announcement = VoiceAnnouncementUtils.createStatistics(context, data.first, dataSet, UnitSystem.IMPERIAL_FEET, false, data.second, null).toString(); @@ -461,8 +559,15 @@ public class VoiceAnnouncementUtilsTest { SensorStatistics sensorStatistics = new SensorStatistics(HeartRate.of(180f), HeartRate.of(180f), null, null, null, null); - SensorDataSet dataSet = Mockito.mock(SensorDataSet.class); - Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused")); + SensorDataSet dataSet = new SensorDataSet( + null, + null, + null, + new SensorData<>(HeartRate.of(60), "unused"), + null, + null, + null + ); // when String announcement = VoiceAnnouncementUtils.createStatistics(context, data.first, dataSet, UnitSystem.METRIC, true, data.second, sensorStatistics).toString(); @@ -487,8 +592,15 @@ public class VoiceAnnouncementUtilsTest { SensorStatistics sensorStatistics = new SensorStatistics(HeartRate.of(180f), HeartRate.of(180f), null, null, null, null); - SensorDataSet dataSet = Mockito.mock(SensorDataSet.class); - Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused")); + SensorDataSet dataSet = new SensorDataSet( + null, + null, + null, + new SensorData<>(HeartRate.of(60), "unused"), + null, + null, + null + ); // when String announcement = VoiceAnnouncementUtils.createStatistics(context, data.first, dataSet, UnitSystem.METRIC, true, data.second, sensorStatistics).toString(); diff --git a/src/androidTest/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdaterTest.java b/src/androidTest/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdaterTest.java index 1224a96d9..678c5cbe3 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdaterTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/stats/TrackStatisticsUpdaterTest.java @@ -89,8 +89,7 @@ public class TrackStatisticsUpdaterTest { // given TrackPoint tp1 = new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochMilli(1000)); TrackPoint tp2 = createTrackPoint(0, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(2000)); - TrackPoint tp3 = createTrackPoint(0.00001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000)); - tp3.setSpeed(Speed.of(5f)); + TrackPoint tp3 = createTrackPoint(0.00001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000), Speed.of(5f), null); // when TrackStatisticsUpdater subject = new TrackStatisticsUpdater(List.of(tp1, tp2, tp3)); @@ -103,15 +102,17 @@ public class TrackStatisticsUpdaterTest { public void addTrackPoint_distance_from_GPS_moving_and_sensor_moving() { // given TrackPoint tp1 = new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochMilli(1000)); - TrackPoint tp2 = createTrackPoint(0, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(2000)); - tp2.setSpeed(Speed.of(5f)); - TrackPoint tp3 = createTrackPoint(0.001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000)); - tp3.setSpeed(Speed.of(5f)); - TrackPoint tp4 = createTrackPoint(0.001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(4000)); - tp4.setSpeed(Speed.of(5f)); - tp4.setSensorDistance(Distance.of(5f)); - TrackPoint tp5 = new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochMilli(5000)); - tp5.setSensorDistance(Distance.of(10f)); + TrackPoint tp2 = createTrackPoint(0, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(2000), Speed.of(5f), null); + TrackPoint tp3 = createTrackPoint(0.001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000), Speed.of(5f), null); + TrackPoint tp4 = createTrackPoint(0.001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(4000), Speed.of(5f), Distance.of(5)); + TrackPoint tp5 = new TrackPoint(null, + TrackPoint.Type.SEGMENT_END_MANUAL, + Position.of(Instant.ofEpochMilli(5000)), + Distance.of(10f), + null, + null, + null, + null); // when TrackStatisticsUpdater subject = new TrackStatisticsUpdater(List.of(tp1, tp2, tp3)); @@ -131,13 +132,10 @@ public class TrackStatisticsUpdaterTest { public void addTrackPoint_distance_from_GPS_moving_and_sensor_disconnecting() { // given TrackPoint tp1 = new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochMilli(1000)); - TrackPoint tp2 = createTrackPoint(0, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(2000)); - tp2.setSpeed(Speed.of(5f)); - TrackPoint tp3 = createTrackPoint(0.00001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000)); - tp3.setSensorDistance(Distance.of(5f)); - tp3.setSpeed(Speed.of(5f)); - TrackPoint tp4 = createTrackPoint(0.0005, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(4000)); - tp4.setSpeed(Speed.of(5f)); + TrackPoint tp2 = createTrackPoint(0, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(2000), Speed.of(5f), null); + + TrackPoint tp3 = createTrackPoint(0.00001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000), Speed.of(5f), Distance.of(5)); + TrackPoint tp4 = createTrackPoint(0.0005, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(4000), Speed.of(5f), null); TrackPoint tp5 = new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochMilli(5000)); // when @@ -158,10 +156,8 @@ public class TrackStatisticsUpdaterTest { public void addTrackPoint_maxSpeed_multiple_segments() { TrackStatisticsUpdater subject = new TrackStatisticsUpdater(List.of( new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochSecond(0)), - createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(1)) - .setSpeed(Speed.of(2f)), - createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(2)) - .setSpeed(Speed.of(2f)), + createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(1), Speed.of(2), null), + createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(2), Speed.of(2), null), new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochSecond(4)) )); assertEquals(Speed.of(2), subject.getTrackStatistics().maxSpeed()); @@ -169,10 +165,8 @@ public class TrackStatisticsUpdaterTest { // when List.of( new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochSecond(5)), - createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(6)) - .setSpeed(Speed.of(1f)), - createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(7)) - .setSpeed(Speed.of(1f)), + createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(6), Speed.of(1), null), + createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(7), Speed.of(1), null), new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochSecond(8)) ).forEach(subject::addTrackPoint); @@ -185,16 +179,30 @@ public class TrackStatisticsUpdaterTest { // when TrackStatisticsUpdater subject = new TrackStatisticsUpdater(List.of( new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochSecond(0)), - createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(1)) - .setSpeed(Speed.of(2f)), - createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(2)) - .setSpeed(Speed.of(2f)), + createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(1), Speed.of(2), null), + createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(2), Speed.of(2), null), new TrackPoint(TrackPoint.Type.IDLE, Instant.ofEpochSecond(30)), - new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochSecond(40)) - .setHeartRate(50), - new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochSecond(45)) - .setHeartRate(50), + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + Position.of(Instant.ofEpochSecond(40)), + null, + HeartRate.of(50), + null, + null, + null + ), + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + Position.of(Instant.ofEpochSecond(45)), + null, + HeartRate.of(50), + null, + null, + null + ), createTrackPoint(0, 1, Altitude.WGS84.of(0), Instant.ofEpochSecond(50)), createTrackPoint(0, 2, Altitude.WGS84.of(0), Instant.ofEpochSecond(55)), @@ -210,21 +218,40 @@ public class TrackStatisticsUpdaterTest { // when TrackStatisticsUpdater subject = new TrackStatisticsUpdater(List.of( new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochSecond(0)), - createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(1)) - .setSensorDistance(Distance.of(10)), - createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(2)) - .setSensorDistance(Distance.of(10)), - - new TrackPoint(TrackPoint.Type.IDLE, Instant.ofEpochSecond(30)) - .setSensorDistance(Distance.ofKilometer(1)), - new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochSecond(40)) - .setHeartRate(50), - new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochSecond(45)) - .setHeartRate(50), - createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(50)) - .setSensorDistance(Distance.of(10)), - createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(55)) - .setSensorDistance(Distance.of(10)), + createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(1), null, Distance.of(10)), + createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(2), null, Distance.of(10)), + new TrackPoint( + null, + TrackPoint.Type.IDLE, + Position.of(Instant.ofEpochSecond(30)), + Distance.ofKilometer(1), + null, + null, + null, + null + ), + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + Position.of(Instant.ofEpochSecond(40)), + null, + HeartRate.of(50), + null, + null, + null + ), + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + Position.of(Instant.ofEpochSecond(45)), + null, + HeartRate.of(50), + null, + null, + null + ), + createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(50), null, Distance.of(10)), + createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(55), null, Distance.of(10)), new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochSecond(60)) )); @@ -240,8 +267,8 @@ public class TrackStatisticsUpdaterTest { // when TrackStatisticsUpdater subject = new TrackStatisticsUpdater(new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochSecond(0))); subject.addTrackPoint( - createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(10)) - .setSensorDistance(Distance.of(10))); + createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(10), null, Distance.of(10)) + ); subject.addTrackPoint(new TrackPoint(TrackPoint.Type.IDLE, Instant.ofEpochSecond(30))); // then @@ -252,8 +279,17 @@ public class TrackStatisticsUpdaterTest { // when subject.addTrackPoint( - new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochSecond(40)) - .setSensorDistance(Distance.ZERO)); + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + Position.of(Instant.ofEpochSecond(40)), + Distance.ZERO, + null, + null, + null, + null + ) + ); // then assertTrue(subject.isIdle()); assertEquals(Duration.ofSeconds(30), subject.getTrackStatistics().movingDuration()); @@ -262,8 +298,17 @@ public class TrackStatisticsUpdaterTest { // when subject.addTrackPoint( - new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochSecond(45)) - .setSensorDistance(Distance.of(1))); + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + Position.of(Instant.ofEpochSecond(45)), + Distance.of(1), + null, + null, + null, + null + ) + ); // then assertTrue(subject.isIdle()); assertEquals(Duration.ofSeconds(30), subject.getTrackStatistics().movingDuration()); @@ -272,8 +317,17 @@ public class TrackStatisticsUpdaterTest { // when subject.addTrackPoint( - new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochSecond(50)) - .setSensorDistance(Distance.of(10))); + new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + Position.of(Instant.ofEpochSecond(50)), + Distance.of(10), + null, + null, + null, + null + ) + ); // then assertFalse(subject.isIdle()); assertEquals(Duration.ofSeconds(30), subject.getTrackStatistics().movingDuration()); @@ -294,15 +348,12 @@ public class TrackStatisticsUpdaterTest { public void copy_constructor() { // given TrackPoint tp1 = new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochMilli(1000)); - TrackPoint tp2 = createTrackPoint(0, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(2000)); - tp2.setSpeed(Speed.of(5f)); - TrackPoint tp3 = createTrackPoint(0.00001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000)); - tp3.setSpeed(Speed.of(5f)); - TrackPoint tp4 = createTrackPoint(0.0005, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(4000)); - tp4.setSpeed(Speed.of(5f)); + TrackPoint tp2 = createTrackPoint(0, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(2000), Speed.of(5f), null); + TrackPoint tp3 = createTrackPoint(0.00001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000), Speed.of(5f), null); + TrackPoint tp4 = createTrackPoint(0.0005, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(4000), Speed.of(5f), null); TrackPoint tp5 = new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochMilli(5000)); - TrackStatisticsUpdater initial = new TrackStatisticsUpdater(List.of(tp1, tp2,tp3, tp4)); + TrackStatisticsUpdater initial = new TrackStatisticsUpdater(List.of(tp1, tp2, tp3, tp4)); // when TrackStatisticsUpdater subject = new TrackStatisticsUpdater(initial, tp5); @@ -335,7 +386,13 @@ public class TrackStatisticsUpdaterTest { } public TrackPoint createTrackPoint(double latitude, double longitude, Altitude altitude, Instant time) { - return new TrackPoint(TrackPoint.Type.TRACKPOINT, + return createTrackPoint(latitude, longitude, altitude, time, null, null); + } + + public TrackPoint createTrackPoint(double latitude, double longitude, Altitude altitude, Instant time, Speed speed, Distance sensorDistance) { + return new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, new Position( time, latitude, @@ -344,7 +401,13 @@ public class TrackStatisticsUpdaterTest { altitude, null, null, - null - )); + speed + ), + sensorDistance, + null, + null, + null, + null + ); } } \ No newline at end of file diff --git a/src/androidTest/java/de/dennisguse/opentracks/ui/aggregatedStatistics/EspressoAggregatedFilterTest.java b/src/androidTest/java/de/dennisguse/opentracks/ui/aggregatedStatistics/EspressoAggregatedFilterTest.java index ed0d1f4f6..55962a21b 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/ui/aggregatedStatistics/EspressoAggregatedFilterTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/ui/aggregatedStatistics/EspressoAggregatedFilterTest.java @@ -30,6 +30,7 @@ import org.junit.runner.RunWith; import java.util.List; import de.dennisguse.opentracks.R; +import de.dennisguse.opentracks.TestUtil; import de.dennisguse.opentracks.TrackListActivity; import de.dennisguse.opentracks.content.data.TestDataUtil; import de.dennisguse.opentracks.data.ContentProviderUtils; @@ -47,7 +48,7 @@ public class EspressoAggregatedFilterTest { public ActivityScenarioRule mActivityTestRule = new ActivityScenarioRule<>(TrackListActivity.class); @Rule - public GrantPermissionRule mGrantPermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION); + public GrantPermissionRule mGrantPermissionRule = TestUtil.createGrantPermissionRule(); @Before public void setUp() { diff --git a/src/androidTest/java/de/dennisguse/opentracks/ui/intervals/IntervalStatisticsUpdaterTest.java b/src/androidTest/java/de/dennisguse/opentracks/ui/intervals/IntervalStatisticsUpdaterTest.java index 3149600b9..8bab9be0f 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/ui/intervals/IntervalStatisticsUpdaterTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/ui/intervals/IntervalStatisticsUpdaterTest.java @@ -104,8 +104,7 @@ public class IntervalStatisticsUpdaterTest { ArrayList trackPoints = new ArrayList<>(); for (int i = 0; i < numberOfPoints; i++) { - trackPoints.add(TestDataUtil.createTrackPoint(i) - .setAltitudeGainLoss(null)); + trackPoints.add(TestDataUtil.createTrackPoint(i, TrackPoint.Type.TRACKPOINT, null)); } TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater(trackPoints); diff --git a/src/main/java/de/dennisguse/opentracks/TrackRecordingActivity.java b/src/main/java/de/dennisguse/opentracks/TrackRecordingActivity.java index 8cc6d05ba..449aeb3b5 100644 --- a/src/main/java/de/dennisguse/opentracks/TrackRecordingActivity.java +++ b/src/main/java/de/dennisguse/opentracks/TrackRecordingActivity.java @@ -278,7 +278,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc Intent intent = IntentUtils .newIntent(this, MarkerEditActivity.class) .putExtra(MarkerEditActivity.EXTRA_TRACK_ID, trackId) - .putExtra(MarkerEditActivity.EXTRA_LOCATION, trackPoint.getPosition().toLocation()); + .putExtra(MarkerEditActivity.EXTRA_LOCATION, trackPoint.position().toLocation()); startActivity(intent); return true; } diff --git a/src/main/java/de/dennisguse/opentracks/chart/ChartFragment.java b/src/main/java/de/dennisguse/opentracks/chart/ChartFragment.java index 1d521a57c..563edfb6d 100644 --- a/src/main/java/de/dennisguse/opentracks/chart/ChartFragment.java +++ b/src/main/java/de/dennisguse/opentracks/chart/ChartFragment.java @@ -35,11 +35,11 @@ import de.dennisguse.opentracks.data.TrackDataHub; import de.dennisguse.opentracks.data.models.Statistics; import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.models.TrackPoint; +import de.dennisguse.opentracks.data.statistics.SegmentStatisticUpdater; +import de.dennisguse.opentracks.data.statistics.TrackStatisticsUpdater; import de.dennisguse.opentracks.databinding.ChartBinding; import de.dennisguse.opentracks.settings.PreferencesUtils; import de.dennisguse.opentracks.settings.UnitSystem; -import de.dennisguse.opentracks.data.statistics.SegmentStatisticUpdater; -import de.dennisguse.opentracks.data.statistics.TrackStatisticsUpdater; /** * A fragment to display track chart to the user. @@ -204,7 +204,7 @@ public class ChartFragment extends Fragment implements TrackDataHub.Listener { public void onSampledInTrackPoint(@NonNull TrackPoint trackPoint, @NonNull Statistics trackStatistics) { if (isResumed()) { - ChartPoint point = ChartPoint.create(trackStatistics, trackPoint, trackPoint.getSpeed(), chartByDistance, viewBinding.chartView.getUnitSystem()); + ChartPoint point = ChartPoint.create(trackStatistics, trackPoint, trackPoint.position().speed(), chartByDistance, viewBinding.chartView.getUnitSystem()); pendingPoints.add(point); } } diff --git a/src/main/java/de/dennisguse/opentracks/chart/ChartPoint.java b/src/main/java/de/dennisguse/opentracks/chart/ChartPoint.java index d7e20c0ae..68c8ee33a 100644 --- a/src/main/java/de/dennisguse/opentracks/chart/ChartPoint.java +++ b/src/main/java/de/dennisguse/opentracks/chart/ChartPoint.java @@ -27,8 +27,8 @@ public record ChartPoint( chartByDistance ? trackStatistics.totalDistance().toKM_Miles(unitSystem) : trackStatistics.totalDuration().toMillis(), - trackPoint.hasAltitude() - ? Distance.of(trackPoint.getAltitude().toM()).toM_FT(unitSystem) + trackPoint.position().hasAltitude() + ? Distance.of(trackPoint.position().altitude().toM()).toM_FT(unitSystem) : null, smoothedSpeed != null ? smoothedSpeed.to(unitSystem) @@ -36,14 +36,14 @@ public record ChartPoint( smoothedSpeed != null ? smoothedSpeed.toPace(unitSystem).toSeconds() / 60d : null, - trackPoint.hasHeartRate() - ? (double) trackPoint.getHeartRate().getBPM() + trackPoint.heartRate() != null + ? (double) trackPoint.heartRate().getBPM() : null, - trackPoint.hasCadence() - ? (double) trackPoint.getCadence().getRPM() + trackPoint.cadence() != null + ? (double) trackPoint.cadence().getRPM() : null, - trackPoint.hasPower() - ? (double) trackPoint.getPower().getW() + trackPoint.power() != null + ? (double) trackPoint.power().getW() : null ); } diff --git a/src/main/java/de/dennisguse/opentracks/data/ContentProviderUtils.java b/src/main/java/de/dennisguse/opentracks/data/ContentProviderUtils.java index fe88705ca..b134b5c9c 100644 --- a/src/main/java/de/dennisguse/opentracks/data/ContentProviderUtils.java +++ b/src/main/java/de/dennisguse/opentracks/data/ContentProviderUtils.java @@ -51,10 +51,10 @@ import de.dennisguse.opentracks.data.models.Speed; import de.dennisguse.opentracks.data.models.Statistics; import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.models.TrackPoint; +import de.dennisguse.opentracks.data.statistics.SensorStatistics; import de.dennisguse.opentracks.data.tables.MarkerColumns; import de.dennisguse.opentracks.data.tables.TrackPointsColumns; import de.dennisguse.opentracks.data.tables.TracksColumns; -import de.dennisguse.opentracks.data.statistics.SensorStatistics; import de.dennisguse.opentracks.ui.markers.MarkerUtils; import de.dennisguse.opentracks.util.FileUtils; @@ -544,7 +544,12 @@ public class ContentProviderUtils { int altitudeGainIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.ALTITUDE_GAIN); int altitudeLossIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.ALTITUDE_LOSS); - TrackPoint trackPoint = new TrackPoint( + AltitudeGainLoss altitudeGainLoss = null; + if (!cursor.isNull(altitudeGainIndex) && !cursor.isNull(altitudeLossIndex)) { + altitudeGainLoss = new AltitudeGainLoss(cursor.getFloat(altitudeGainIndex), cursor.getFloat(altitudeLossIndex)); + } + + return new TrackPoint( new TrackPoint.Id(cursor.getInt(idIndex)), TrackPoint.Type.getById(cursor.getInt(typeIndex)), new Position( @@ -556,26 +561,13 @@ public class ContentProviderUtils { !cursor.isNull(accuracyVerticalIndex) ? Distance.of(cursor.getFloat(accuracyVerticalIndex)) : null, !cursor.isNull(bearingIndex) ? cursor.getFloat(bearingIndex) : null, !cursor.isNull(speedIndex) ? Speed.of(cursor.getFloat(speedIndex)) : null - )); - - if (!cursor.isNull(sensorHeartRateIndex)) { - trackPoint.setHeartRate(cursor.getFloat(sensorHeartRateIndex)); - } - if (!cursor.isNull(sensorCadenceIndex)) { - trackPoint.setCadence(cursor.getFloat(sensorCadenceIndex)); - } - if (!cursor.isNull(sensorDistanceIndex)) { - trackPoint.setSensorDistance(Distance.of(cursor.getFloat(sensorDistanceIndex))); - } - if (!cursor.isNull(sensorPowerIndex)) { - trackPoint.setPower(cursor.getFloat(sensorPowerIndex)); - } - - if (!cursor.isNull(altitudeGainIndex) && !cursor.isNull(altitudeLossIndex)) { - trackPoint.setAltitudeGainLoss(cursor.getFloat(altitudeGainIndex), cursor.getFloat(altitudeLossIndex)); - } - - return trackPoint; + ), + !cursor.isNull(sensorDistanceIndex) ? Distance.of(cursor.getFloat(sensorDistanceIndex)) : null, + !cursor.isNull(sensorHeartRateIndex) ? HeartRate.of(cursor.getFloat(sensorHeartRateIndex)) : null, + !cursor.isNull(sensorCadenceIndex) ? Cadence.of(cursor.getFloat(sensorCadenceIndex)) : null, + !cursor.isNull(sensorPowerIndex) ? Power.of(cursor.getFloat(sensorPowerIndex)) : null, + altitudeGainLoss + ); } //TODO Only used for file import; might be better to replace it. @@ -637,42 +629,42 @@ public class ContentProviderUtils { private ContentValues createContentValues(TrackPoint trackPoint, Track.Id trackId) { ContentValues values = new ContentValues(); values.put(TrackPointsColumns.TRACKID, trackId.id()); - values.put(TrackPointsColumns.TYPE, trackPoint.getType().type_db); + values.put(TrackPointsColumns.TYPE, trackPoint.type().type_db); - if (trackPoint.hasLocation()) { - values.put(TrackPointsColumns.LATITUDE, (int) (trackPoint.getPosition().latitude() * 1E6)); - values.put(TrackPointsColumns.LONGITUDE, (int) (trackPoint.getPosition().longitude() * 1E6)); + if (trackPoint.position().hasLocation()) { + values.put(TrackPointsColumns.LATITUDE, (int) (trackPoint.position().latitude() * 1E6)); + values.put(TrackPointsColumns.LONGITUDE, (int) (trackPoint.position().longitude() * 1E6)); } values.put(TrackPointsColumns.TIME, trackPoint.getTime().toEpochMilli()); - if (trackPoint.hasAltitude()) { - values.put(TrackPointsColumns.ALTITUDE, trackPoint.getAltitude().toM()); + if (trackPoint.position().hasAltitude()) { + values.put(TrackPointsColumns.ALTITUDE, trackPoint.position().altitude().toM()); } - if (trackPoint.hasHorizontalAccuracy()) { - values.put(TrackPointsColumns.HORIZONTAL_ACCURACY, trackPoint.getHorizontalAccuracy().toM()); + if (trackPoint.position().hasHorizontalAccuracy()) { + values.put(TrackPointsColumns.HORIZONTAL_ACCURACY, trackPoint.position().horizontalAccuracy().toM()); } - if (trackPoint.hasSpeed()) { - values.put(TrackPointsColumns.SPEED, trackPoint.getSpeed().toMPS()); + if (trackPoint.position().hasSpeed()) { + values.put(TrackPointsColumns.SPEED, trackPoint.position().speed().toMPS()); } - if (trackPoint.hasBearing()) { - values.put(TrackPointsColumns.BEARING, trackPoint.getBearing()); + if (trackPoint.position().hasBearing()) { + values.put(TrackPointsColumns.BEARING, trackPoint.position().bearing()); } - if (trackPoint.hasHeartRate()) { - values.put(TrackPointsColumns.SENSOR_HEARTRATE, trackPoint.getHeartRate().getBPM()); + if (trackPoint.heartRate() != null) { + values.put(TrackPointsColumns.SENSOR_HEARTRATE, trackPoint.heartRate().getBPM()); } - if (trackPoint.hasCadence()) { - values.put(TrackPointsColumns.SENSOR_CADENCE, trackPoint.getCadence().getRPM()); + if (trackPoint.cadence() != null) { + values.put(TrackPointsColumns.SENSOR_CADENCE, trackPoint.cadence().getRPM()); } - if (trackPoint.hasSensorDistance()) { - values.put(TrackPointsColumns.SENSOR_DISTANCE, trackPoint.getSensorDistance().toM()); + if (trackPoint.sensorDistance() != null) { + values.put(TrackPointsColumns.SENSOR_DISTANCE, trackPoint.sensorDistance().toM()); } - if (trackPoint.hasPower()) { - values.put(TrackPointsColumns.SENSOR_POWER, trackPoint.getPower().getW()); + if (trackPoint.power() != null) { + values.put(TrackPointsColumns.SENSOR_POWER, trackPoint.power().getW()); } - if (trackPoint.hasAltitudeGainLoss()) { - values.put(TrackPointsColumns.ALTITUDE_GAIN, trackPoint.getAltitudeGainLoss().gain_m()); - values.put(TrackPointsColumns.ALTITUDE_LOSS, trackPoint.getAltitudeGainLoss().loss_m()); + if (trackPoint.altitudeGainLoss() != null) { + values.put(TrackPointsColumns.ALTITUDE_GAIN, trackPoint.altitudeGainLoss().gain_m()); + values.put(TrackPointsColumns.ALTITUDE_LOSS, trackPoint.altitudeGainLoss().loss_m()); } return values; } diff --git a/src/main/java/de/dennisguse/opentracks/data/TrackDataHub.java b/src/main/java/de/dennisguse/opentracks/data/TrackDataHub.java index 6a60964da..93e86ed49 100644 --- a/src/main/java/de/dennisguse/opentracks/data/TrackDataHub.java +++ b/src/main/java/de/dennisguse/opentracks/data/TrackDataHub.java @@ -33,12 +33,12 @@ import java.util.Set; import de.dennisguse.opentracks.data.models.Statistics; import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.models.TrackPoint; +import de.dennisguse.opentracks.data.statistics.TrackStatisticsUpdater; import de.dennisguse.opentracks.data.tables.TrackPointsColumns; import de.dennisguse.opentracks.data.tables.TracksColumns; import de.dennisguse.opentracks.services.RecordingStatus; import de.dennisguse.opentracks.services.TrackRecordingService; import de.dennisguse.opentracks.services.handlers.AltitudeCorrectionManager; -import de.dennisguse.opentracks.data.statistics.TrackStatisticsUpdater; /** * Track data hub. @@ -288,14 +288,14 @@ public class TrackDataHub { } trackPoint = trackPointIterator.next(); - TrackPoint.Id trackPointId = trackPoint.getId(); + TrackPoint.Id trackPointId = trackPoint.id(); // Stop if past the last wanted point if (maxPointId != null && trackPointId.id() > maxPointId.id()) { break; } - egm2008Correction.correctAltitude(context, trackPoint); + trackPoint = egm2008Correction.correctAltitude(context, trackPoint); if (localFirstSeenTrackPointId == null) { localFirstSeenTrackPointId = trackPointId; @@ -319,7 +319,7 @@ public class TrackDataHub { } if (trackPoint != null) { - localLastSeenTrackPointIdId = trackPoint.getId(); + localLastSeenTrackPointIdId = trackPoint.id(); } if (updateSamplingState) { diff --git a/src/main/java/de/dennisguse/opentracks/data/models/HeartRate.java b/src/main/java/de/dennisguse/opentracks/data/models/HeartRate.java index ea1f4d2b0..a2b748fab 100644 --- a/src/main/java/de/dennisguse/opentracks/data/models/HeartRate.java +++ b/src/main/java/de/dennisguse/opentracks/data/models/HeartRate.java @@ -1,5 +1,7 @@ package de.dennisguse.opentracks.data.models; +import androidx.annotation.Nullable; + public record HeartRate(float value) { public static HeartRate INVALID = HeartRate.of(0.0f); @@ -7,6 +9,12 @@ public record HeartRate(float value) { return new HeartRate(value); } + @Nullable + public static HeartRate ofOrNull(Float value) { + if (value == null) return null; + return new HeartRate(value); + } + public float getBPM() { return value; } diff --git a/src/main/java/de/dennisguse/opentracks/data/models/MarkerBuilder.java b/src/main/java/de/dennisguse/opentracks/data/models/MarkerBuilder.java index 05a8eb38e..38f54c09c 100644 --- a/src/main/java/de/dennisguse/opentracks/data/models/MarkerBuilder.java +++ b/src/main/java/de/dennisguse/opentracks/data/models/MarkerBuilder.java @@ -51,10 +51,10 @@ public final class MarkerBuilder { this.typeLocalized = ""; this.photoUrl = null; - if (!trackPoint.hasLocation()) + if (!trackPoint.position().hasLocation()) throw new RuntimeException("Marker requires a trackpoint with a location."); - this.position = trackPoint.getPosition(); + this.position = trackPoint.position(); } public MarkerBuilder(@Nullable Track.Id trackId, @NonNull TrackPoint trackPoint, String name, String description, String typeLocalized, Uri photoUrl) { diff --git a/src/main/java/de/dennisguse/opentracks/data/models/Position.java b/src/main/java/de/dennisguse/opentracks/data/models/Position.java index e5a520c11..4dd31c0d8 100644 --- a/src/main/java/de/dennisguse/opentracks/data/models/Position.java +++ b/src/main/java/de/dennisguse/opentracks/data/models/Position.java @@ -17,8 +17,9 @@ public record Position( @Nullable Float bearing, @Nullable Speed speed ) { + @Deprecated public static Position empty() { - return of((Instant) null); + return of(null); } public static Position of(@NonNull Instant time) { @@ -34,10 +35,6 @@ public record Position( ); } - public static Position of(@NonNull Location location) { - return of(location, Instant.ofEpochMilli(location.getTime())); - } - public static Position of(@NonNull Location location, @NonNull Instant time) { return new Position( time, @@ -132,9 +129,8 @@ public record Position( return new Position(time, latitude, longitude, horizontalAccuracy, altitude, verticalAccuracy, bearing, speed); } - //TODO Use double - public Position withCoordinates(Double latitude, Double longitude) { - return new Position(time, latitude, longitude, horizontalAccuracy, altitude, verticalAccuracy, bearing, speed); + public Position withCoordinates(Position position) { + return new Position(time, position.latitude, position.longitude, horizontalAccuracy, altitude, verticalAccuracy, bearing, speed); } //TODO Use float diff --git a/src/main/java/de/dennisguse/opentracks/data/models/TrackPoint.java b/src/main/java/de/dennisguse/opentracks/data/models/TrackPoint.java index 261c3dddc..6196d265d 100644 --- a/src/main/java/de/dennisguse/opentracks/data/models/TrackPoint.java +++ b/src/main/java/de/dennisguse/opentracks/data/models/TrackPoint.java @@ -22,23 +22,168 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.time.Instant; -import java.util.Optional; /** * Sensor and/or location information for a specific point in time. *

* Time is created using the {@link de.dennisguse.opentracks.services.handlers.MonotonicClock}, because system time jump backwards. - * GPS time is ignored as for non-GPS events, we could not create GPS-based timestamps. + * GPS time is ignored as for non-GPS events, we cannot create GPS-based timestamps. */ -//TODO Should be a record (with final properties) -public class TrackPoint { +public record TrackPoint( - @Nullable - private final TrackPoint.Id id; + @Nullable + TrackPoint.Id id, + + @NonNull + TrackPoint.Type type, + + //Requires: position.time must be non-null + @NonNull + Position position, + + Distance sensorDistance, + HeartRate heartRate, + Cadence cadence, + Power power, + AltitudeGainLoss altitudeGainLoss +) { + + public TrackPoint(Type type, Position position) { + this( + null, + type, + position, + null, + null, + null, + null, + null + ); + } + + @Deprecated //TOOD Private? + public TrackPoint(Type type, Instant now) { + this( + null, + type, + Position.of(now), + null, + null, + null, + null, + null + ); + } + + public static TrackPoint createSegmentStartManualWithTime(Instant time) { + return new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, time); + } + + public static TrackPoint with(TrackPoint trackPoint, Altitude.EGM2008 correctAltitude) { + return new TrackPoint( + trackPoint.id, + trackPoint.type, + new Position( + trackPoint.position.time(), + trackPoint.position.latitude(), + trackPoint.position.longitude(), + trackPoint.position.horizontalAccuracy(), + correctAltitude, + trackPoint.position.verticalAccuracy(), + trackPoint.position.bearing(), + trackPoint.position.speed() + ), + trackPoint.sensorDistance, + trackPoint.heartRate, + trackPoint.cadence, + trackPoint.power, + trackPoint.altitudeGainLoss + ); + } + + public TrackPoint with(Type newType) { + return new TrackPoint( + id, + newType, + position, + sensorDistance, + heartRate, + cadence, + power, + altitudeGainLoss + ); + } + + public TrackPoint with(Position newPosition) { + return new TrackPoint( + id, + type, + newPosition, + sensorDistance, + heartRate, + cadence, + power, + altitudeGainLoss + ); + } - //Requires: position.time must be non-null @NonNull - private Position position; + public Instant getTime() { + return position.time(); + } + + + public TrackPoint minusCumulativeSensorData(@NonNull TrackPoint lastTrackPoint) { + Distance newSensorDistance = sensorDistance; + if (sensorDistance != null && lastTrackPoint.sensorDistance != null) { + newSensorDistance = sensorDistance.minus(lastTrackPoint.sensorDistance); + } + AltitudeGainLoss newAltitudeGainLoss = altitudeGainLoss; + if (altitudeGainLoss != null && lastTrackPoint.altitudeGainLoss() != null) { + newAltitudeGainLoss = new AltitudeGainLoss( + altitudeGainLoss.gain_m() - lastTrackPoint.altitudeGainLoss.gain_m(), + altitudeGainLoss.loss_m() - lastTrackPoint.altitudeGainLoss.loss_m()); + } + return new TrackPoint( + id, + type, + position, + newSensorDistance, + heartRate, + cadence, + power, + newAltitudeGainLoss + ); + } + + @NonNull + public Distance distanceToPrevious(@NonNull TrackPoint previous) { + if (sensorDistance() != null) { + return sensorDistance(); + } + return distanceToPreviousFromLocation(previous); + } + + @NonNull + public Distance distanceToPreviousFromLocation(@NonNull TrackPoint previous) { + if (!position.hasLocation() || !previous.position().hasLocation()) { + throw new RuntimeException("Cannot compute distance."); + } + + return Distance.of(position().toLocation().distanceTo(previous.position().toLocation())); + } + + public boolean isIdleTriggered() { + return type == TrackPoint.Type.IDLE; + } + + public boolean isSegmentManualStart() { + return type == TrackPoint.Type.SEGMENT_START_MANUAL; + } + + public boolean isSegmentManualEnd() { + return type == TrackPoint.Type.SEGMENT_END_MANUAL; + } public enum Type { SEGMENT_START_MANUAL(-2), //Start of a segment due to user interaction (start, resume) @@ -75,298 +220,6 @@ public class TrackPoint { } } - @NonNull - private Type type; - - private Distance sensorDistance; - private HeartRate heartRate = null; - private Cadence cadence = null; - private Power power = null; - private AltitudeGainLoss altitudeGainLoss = null; - - public TrackPoint(@Nullable TrackPoint.Id id, @NonNull Type type, @NonNull Position position) { - this.id = id; - this.type = type; - this.position = position; - } - - public TrackPoint(@NonNull Type type, @NonNull Instant time) { - this(null, type, Position.of(time)); - } - - public TrackPoint(@NonNull Type type, @NonNull Position position) { - this(null, type, position); - } - - public static TrackPoint createSegmentStartManualWithTime(Instant time) { - return new TrackPoint(Type.SEGMENT_START_MANUAL, time); - } - - public static TrackPoint createSegmentEndWithTime(Instant time) { - return new TrackPoint(Type.SEGMENT_END_MANUAL, time); - } - - @NonNull - public Type getType() { - return type; - } - - @Deprecated //Should not be needed. - public TrackPoint setType(@NonNull Type type) { - this.type = type; - return this; - } - - public boolean isIdleTriggered() { - return type == Type.IDLE; - } - - public boolean isSegmentManualStart() { - return type == Type.SEGMENT_START_MANUAL; - } - - public boolean isSegmentManualEnd() { - return type == Type.SEGMENT_END_MANUAL; - } - - //TODO Check if naming is correct. - public boolean wasCreatedManually() { - return hasLocation() || hasSpeed(); - } - - /** - * May be null if the track was not loaded from the database. - */ - @Nullable - public TrackPoint.Id getId() { - return id; - } - - public boolean hasLocation() { - return position.hasLocation(); - } - - @NonNull - public Position getPosition() { - return position; - } - - public TrackPoint setPosition(Position position) { - this.position = position.with(this.position.time()); - return this; - } - - public boolean hasAltitudeGainLoss() { - return altitudeGainLoss != null; - } - - public AltitudeGainLoss getAltitudeGainLoss() { - return altitudeGainLoss; - } - - public TrackPoint setAltitudeGainLoss(AltitudeGainLoss altitudeGainLoss) { - this.altitudeGainLoss = altitudeGainLoss; - return this; - } - - public TrackPoint setAltitudeGainLoss(float altitudeGain_m, float altitudeLoss_m) { - setAltitudeGainLoss(new AltitudeGainLoss(altitudeGain_m, altitudeLoss_m)); - return this; - } - - @NonNull - public Instant getTime() { - return position.time(); - } - - public boolean hasAltitude() { - return position.hasAltitude(); - } - - public Altitude getAltitude() { - return position.altitude(); - } - - @Deprecated - public TrackPoint setAltitude(Altitude altitude) { - position = position.with(altitude); - return this; - } - - public boolean hasSpeed() { - return position.hasSpeed(); - } - - public Speed getSpeed() { - return position.speed(); - } - - @Deprecated - public TrackPoint setSpeed(Speed speed) { - this.position = position.with(speed); - return this; - } - - public boolean hasBearing() { - return position.hasBearing(); - } - - public float getBearing() { - return position.bearing(); - } - - public TrackPoint setBearing(Float bearing) { - this.position = this.position.withBearing(bearing); - return this; - } - - public boolean hasHorizontalAccuracy() { - return position.hasHorizontalAccuracy(); - } - - public Distance getHorizontalAccuracy() { - return position.horizontalAccuracy(); - } - - @Deprecated - public TrackPoint setHorizontalAccuracy(Distance horizontalAccuracy) { - this.position = this.position.withHorizontalAccuracy(horizontalAccuracy); - return this; - } - - public boolean hasVerticalAccuracy() { - return position.hasVerticalAccuracy(); - } - - public Distance getVerticalAccuracy() { - return position.verticalAccuracy(); - } - - public TrackPoint setVerticalAccuracy(Distance verticalAccuracy) { - this.position = this.position.withVerticalAccuracy(verticalAccuracy); - return this; - } - - @NonNull - public Distance distanceToPrevious(@NonNull TrackPoint previous) { - if (hasSensorDistance()) { - return getSensorDistance(); - } - return distanceToPreviousFromLocation(previous); - } - - @NonNull - public Distance distanceToPreviousFromLocation(@NonNull TrackPoint previous) { - if (!hasLocation() || hasLocation() != previous.hasLocation()) { - throw new RuntimeException("Cannot compute distance."); - } - - return Distance.of(getPosition().toLocation().distanceTo(previous.getPosition().toLocation())); - } - - public boolean fulfillsAccuracy(Distance thresholdHorizontalAccuracy) { - return position.fulfillsAccuracy(thresholdHorizontalAccuracy); - } - - public Optional bearingTo(@NonNull TrackPoint dest) { - if (!dest.hasLocation() || !hasLocation()) { - return Optional.empty(); - } - return Optional.of(getPosition().toLocation().bearingTo(dest.getPosition().toLocation())); - } - - // Sensor data - public boolean hasSensorDistance() { - return sensorDistance != null; - } - - public Distance getSensorDistance() { - return sensorDistance; - } - - public TrackPoint setSensorDistance(Distance distance_m) { - this.sensorDistance = distance_m; - return this; - } - - public TrackPoint minusCumulativeSensorData(@NonNull TrackPoint lastTrackPoint) { - if (hasSensorDistance() && lastTrackPoint.hasSensorDistance()) { - sensorDistance = sensorDistance.minus(lastTrackPoint.getSensorDistance()); - } - if (hasAltitudeGainLoss() && lastTrackPoint.hasAltitudeGainLoss()) { - altitudeGainLoss = new AltitudeGainLoss( - altitudeGainLoss.gain_m() - lastTrackPoint.altitudeGainLoss.gain_m(), - altitudeGainLoss.loss_m() - lastTrackPoint.altitudeGainLoss.loss_m()); - } - return this; - } - - public boolean hasHeartRate() { - return heartRate != null; - } - - public HeartRate getHeartRate() { - return heartRate; - } - - public TrackPoint setHeartRate(HeartRate heartRate) { - this.heartRate = heartRate; - return this; - } - - public TrackPoint setHeartRate(float heartRate) { - return setHeartRate(HeartRate.of(heartRate)); - } - - public boolean hasCadence() { - return cadence != null; - } - - public Cadence getCadence() { - return cadence; - } - - public TrackPoint setCadence(Cadence cadence) { - this.cadence = cadence; - return this; - } - - public TrackPoint setCadence(float cadence) { - return setCadence(Cadence.of(cadence)); - } - - public boolean hasPower() { - return power != null; - } - - public Power getPower() { - return power; - } - - public TrackPoint setPower(Power power) { - this.power = power; - return this; - } - - public TrackPoint setPower(float power) { - return setPower(Power.of(power)); - } - - @NonNull - @Override - public String toString() { - return "TrackPoint{" + - "id=" + id + - ", type=" + type + - ", position=" + position + - ", sensorDistance=" + sensorDistance + - ", heartRate=" + heartRate + - ", cadence=" + cadence + - ", power=" + power + - ", altitudeGainLoss=" + altitudeGainLoss + - '}'; - } - public record Id(long id) implements Parcelable { @Override diff --git a/src/main/java/de/dennisguse/opentracks/data/statistics/SegmentStatisticUpdater.java b/src/main/java/de/dennisguse/opentracks/data/statistics/SegmentStatisticUpdater.java index 168d52b04..500d5ce1a 100644 --- a/src/main/java/de/dennisguse/opentracks/data/statistics/SegmentStatisticUpdater.java +++ b/src/main/java/de/dennisguse/opentracks/data/statistics/SegmentStatisticUpdater.java @@ -154,7 +154,7 @@ public class SegmentStatisticUpdater { Duration movingDuration = Duration.between(lastTrackPoint.getTime(), trackPoint.getTime()); if (movingDuration.isNegative()) { - throw new RuntimeException("Moving time cannot be negative"); + throw new RuntimeException("Moving time cannot be negative: " + lastTrackPoint.getTime() + " is after " + trackPoint.getTime()); } this.movingDuration = this.movingDuration.plus(movingDuration); } diff --git a/src/main/java/de/dennisguse/opentracks/data/statistics/TrackStatisticsUpdater.java b/src/main/java/de/dennisguse/opentracks/data/statistics/TrackStatisticsUpdater.java index 3e157e587..46ad43431 100644 --- a/src/main/java/de/dennisguse/opentracks/data/statistics/TrackStatisticsUpdater.java +++ b/src/main/java/de/dennisguse/opentracks/data/statistics/TrackStatisticsUpdater.java @@ -111,32 +111,32 @@ public class TrackStatisticsUpdater { currentSegment.updateTotalTime(trackPoint.getTime()); // Process sensor data: barometer - if (trackPoint.hasAltitudeGainLoss()) { - currentSegment.addTotalAltitudeGainLoss(trackPoint.getAltitudeGainLoss()); + if (trackPoint.altitudeGainLoss() != null) { + currentSegment.addTotalAltitudeGainLoss(trackPoint.altitudeGainLoss()); } - //Update absolute (GPS-based) altitude - if (trackPoint.hasAltitude()) { - currentSegment.updateAltitudeExtremities(trackPoint.getAltitude()); + // Update absolute (GPS-based) altitude + if (trackPoint.position().hasAltitude()) { + currentSegment.updateAltitudeExtremities(trackPoint.position().altitude()); } // Update heart rate - if (trackPoint.hasHeartRate() && lastTrackPoint != null) { + if (trackPoint.heartRate() != null && lastTrackPoint != null) { Duration trackPointDuration = Duration.between(lastTrackPoint.getTime(), trackPoint.getTime()); Duration newTotalDuration = totalHeartRateDuration.plus(trackPointDuration); - averageHeartRateBPM = (totalHeartRateDuration.toMillis() * averageHeartRateBPM + trackPointDuration.toMillis() * trackPoint.getHeartRate().getBPM()) / newTotalDuration.toMillis(); + averageHeartRateBPM = (totalHeartRateDuration.toMillis() * averageHeartRateBPM + trackPointDuration.toMillis() * trackPoint.heartRate().getBPM()) / newTotalDuration.toMillis(); totalHeartRateDuration = newTotalDuration; currentSegment.setAverageHeartRate(HeartRate.of(averageHeartRateBPM)); } // Update power - if (trackPoint.hasPower() && lastTrackPoint != null) { + if (trackPoint.power() != null && lastTrackPoint != null) { Duration trackPointDuration = Duration.between(lastTrackPoint.getTime(), trackPoint.getTime()); Duration newTotalDuration = totalPowerDuration.plus(trackPointDuration); - averagePowerW = (totalPowerDuration.toMillis() * averagePowerW + trackPointDuration.toMillis() * trackPoint.getPower().getW()) / newTotalDuration.toMillis(); + averagePowerW = (totalPowerDuration.toMillis() * averagePowerW + trackPointDuration.toMillis() * trackPoint.power().getW()) / newTotalDuration.toMillis(); totalPowerDuration = newTotalDuration; currentSegment.setAveragePower(Power.of(averagePowerW)); @@ -145,11 +145,11 @@ public class TrackStatisticsUpdater { { // Update total distance Distance movingDistance = null; - if (trackPoint.hasSensorDistance()) { - movingDistance = trackPoint.getSensorDistance(); + if (trackPoint.sensorDistance() != null) { + movingDistance = trackPoint.sensorDistance(); } else if (lastTrackPoint != null - && lastTrackPoint.hasLocation() - && trackPoint.hasLocation()) { + && lastTrackPoint.position().hasLocation() + && trackPoint.position().hasLocation()) { // GPS-based distance/speed movingDistance = trackPoint.distanceToPrevious(lastTrackPoint); } @@ -173,7 +173,7 @@ public class TrackStatisticsUpdater { } } - if (trackPoint.hasSpeed()) { + if (trackPoint.position().hasSpeed()) { updateSpeed(trackPoint); } } @@ -205,7 +205,7 @@ public class TrackStatisticsUpdater { * Updates a speed reading while assuming the user is moving. */ private void updateSpeed(@NonNull TrackPoint trackPoint) { - Speed currentSpeed = trackPoint.getSpeed(); + Speed currentSpeed = trackPoint.position().speed(); if (currentSpeed.greaterThan(currentSegment.getMaxSpeed())) { currentSegment.setMaxSpeed(currentSpeed); } @@ -215,8 +215,8 @@ public class TrackStatisticsUpdater { @Override public String toString() { return "TrackStatisticsUpdater{" + - "segmentStatisticUpdater=" + statisticsWithoutCurrentSegment + - ", currentSegment=" + currentSegment + + "currentSegment=" + currentSegment + + ", segmentStatisticUpdater=" + statisticsWithoutCurrentSegment + ", lastTrackPoint=" + lastTrackPoint + '}'; } diff --git a/src/main/java/de/dennisguse/opentracks/io/file/exporter/CSVTrackExporter.java b/src/main/java/de/dennisguse/opentracks/io/file/exporter/CSVTrackExporter.java index 80bec7d1e..eb4fd0008 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/exporter/CSVTrackExporter.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/exporter/CSVTrackExporter.java @@ -90,20 +90,20 @@ public class CSVTrackExporter implements TrackExporter { public boolean writeTrack(@NonNull List tracks, @NonNull OutputStream outputStream) { List columns = List.of( new Column("time", null), - new Column("trackpoint_type", t -> quote(t.getType().name())), - new Column("latitude", t -> t.hasLocation() ? COORDINATE_FORMAT.format(t.getPosition().latitude()) : ""), - new Column("longitude", t -> t.hasLocation() ? COORDINATE_FORMAT.format(t.getPosition().longitude()) : ""), - new Column("altitude", t -> t.hasAltitude() ? ALTITUDE_FORMAT.format(t.getAltitude().toM()) : ""), - new Column("accuracy_horizontal", t -> t.hasHorizontalAccuracy() ? DISTANCE_FORMAT.format(t.getHorizontalAccuracy().toM()) : ""), - new Column("accuracy_vertical", t -> t.hasVerticalAccuracy() ? DISTANCE_FORMAT.format(t.getVerticalAccuracy().toM()) : ""), + new Column("trackpoint_type", t -> quote(t.type().name())), + new Column("latitude", t -> t.position().hasLocation() ? COORDINATE_FORMAT.format(t.position().latitude()) : ""), + new Column("longitude", t -> t.position().hasLocation() ? COORDINATE_FORMAT.format(t.position().longitude()) : ""), + new Column("altitude", t -> t.position().hasAltitude() ? ALTITUDE_FORMAT.format(t.position().altitude().toM()) : ""), + new Column("accuracy_horizontal", t -> t.position().hasHorizontalAccuracy() ? DISTANCE_FORMAT.format(t.position().horizontalAccuracy().toM()) : ""), + new Column("accuracy_vertical", t -> t.position().hasVerticalAccuracy() ? DISTANCE_FORMAT.format(t.position().verticalAccuracy().toM()) : ""), - new Column("speed", t -> t.hasSpeed() ? SPEED_FORMAT.format(t.getSpeed().toKMH()) : ""), - new Column("altitude_gain", t -> t.hasAltitudeGainLoss() ? ALTITUDE_FORMAT.format(t.getAltitudeGainLoss().gain_m()) : ""), - new Column("altitude_loss", t -> t.hasAltitudeGainLoss() ? ALTITUDE_FORMAT.format(t.getAltitudeGainLoss().loss_m()) : ""), - new Column("sensor_distance", t -> t.hasSensorDistance() ? DISTANCE_FORMAT.format(t.getSensorDistance().toM()) : ""), - new Column("heartrate", t -> t.hasHeartRate() ? HEARTRATE_FORMAT.format(t.getHeartRate().getBPM()) : ""), - new Column("cadence", t -> t.hasCadence() ? CADENCE_FORMAT.format(t.getCadence().getRPM()) : ""), - new Column("power", t -> t.hasPower() ? POWER_FORMAT.format(t.getPower().getW()) : "")); + new Column("speed", t -> t.position().hasSpeed() ? SPEED_FORMAT.format(t.position().speed().toKMH()) : ""), + new Column("altitude_gain", t -> t.altitudeGainLoss() != null ? ALTITUDE_FORMAT.format(t.altitudeGainLoss().gain_m()) : ""), + new Column("altitude_loss", t -> t.altitudeGainLoss() != null ? ALTITUDE_FORMAT.format(t.altitudeGainLoss().loss_m()) : ""), + new Column("sensor_distance", t -> t.sensorDistance() != null ? DISTANCE_FORMAT.format(t.sensorDistance().toM()) : ""), + new Column("heartrate", t -> t.heartRate() != null ? HEARTRATE_FORMAT.format(t.heartRate().getBPM()) : ""), + new Column("cadence", t -> t.cadence() != null ? CADENCE_FORMAT.format(t.cadence().getRPM()) : ""), + new Column("power", t -> t.power() != null ? POWER_FORMAT.format(t.power().getW()) : "")); try { prepare(outputStream); diff --git a/src/main/java/de/dennisguse/opentracks/io/file/exporter/GPXTrackExporter.java b/src/main/java/de/dennisguse/opentracks/io/file/exporter/GPXTrackExporter.java index 31046f28e..402a7185b 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/exporter/GPXTrackExporter.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/exporter/GPXTrackExporter.java @@ -140,7 +140,7 @@ public class GPXTrackExporter implements TrackExporter { wroteTrack = true; } - switch (trackPoint.getType()) { + switch (trackPoint.type()) { case SEGMENT_START_MANUAL -> Log.i(TAG, "Exporting " + TrackPoint.Type.SEGMENT_START_MANUAL.name() + " is not supported."); case SEGMENT_END_MANUAL -> { @@ -152,7 +152,7 @@ public class GPXTrackExporter implements TrackExporter { if (wroteSegment) writeCloseSegment(); writeOpenSegment(); wroteSegment = true; - if (trackPoint.hasLocation()) { + if (trackPoint.position().hasLocation()) { trackDistance = trackDistance.plus(writeTrackPoint(track.zoneOffset(), trackPoint, sensorPoints, trackDistance)); sensorPoints.clear(); } else { @@ -165,7 +165,7 @@ public class GPXTrackExporter implements TrackExporter { writeOpenSegment(); wroteSegment = true; } - if (trackPoint.hasLocation()) { + if (trackPoint.position().hasLocation()) { trackDistance = trackDistance.plus(writeTrackPoint(track.zoneOffset(), trackPoint, sensorPoints, trackDistance)); sensorPoints.clear(); } else { @@ -176,7 +176,7 @@ public class GPXTrackExporter implements TrackExporter { // Not supported as IDLE-TrackPoints have no location. } default -> - throw new RuntimeException("Exporting this TrackPoint type is not implemented: " + trackPoint.getType()); + throw new RuntimeException("Exporting this TrackPoint type is not implemented: " + trackPoint.type()); } } @@ -306,10 +306,10 @@ public class GPXTrackExporter implements TrackExporter { private Distance writeTrackPoint(ZoneOffset zoneOffset, TrackPoint trackPoint, List sensorPoints, Distance trackDistance) { Distance cumulativeDistance; - printWriter.println(""); + printWriter.println(""); - if (trackPoint.hasAltitude()) { - printWriter.println("" + ALTITUDE_FORMAT.format(trackPoint.getAltitude().toM()) + ""); + if (trackPoint.position().hasAltitude()) { + printWriter.println("" + ALTITUDE_FORMAT.format(trackPoint.position().altitude().toM()) + ""); } printWriter.println(""); @@ -317,41 +317,41 @@ public class GPXTrackExporter implements TrackExporter { { String trackPointExtensionV2Content = ""; - if (trackPoint.hasHeartRate()) { - trackPointExtensionV2Content += "" + HEARTRATE_FORMAT.format(trackPoint.getHeartRate().getBPM()) + "\n"; + if (trackPoint.heartRate() != null) { + trackPointExtensionV2Content += "" + HEARTRATE_FORMAT.format(trackPoint.heartRate().getBPM()) + "\n"; } - if (trackPoint.hasCadence()) { - trackPointExtensionV2Content += "" + CADENCE_FORMAT.format(trackPoint.getCadence().getRPM()) + "\n"; + if (trackPoint.cadence() != null) { + trackPointExtensionV2Content += "" + CADENCE_FORMAT.format(trackPoint.cadence().getRPM()) + "\n"; } - if (trackPoint.hasSpeed()) { - trackPointExtensionV2Content += "" + SPEED_FORMAT.format(trackPoint.getSpeed().toMPS()) + "\n"; + if (trackPoint.position().hasSpeed()) { + trackPointExtensionV2Content += "" + SPEED_FORMAT.format(trackPoint.position().speed().toMPS()) + "\n"; } String extensionContent = ""; - if (trackPoint.hasPower()) { - extensionContent += "" + POWER_FORMAT.format(trackPoint.getPower().getW()) + "\n"; + if (trackPoint.power() != null) { + extensionContent += "" + POWER_FORMAT.format(trackPoint.power().getW()) + "\n"; } - Double cumulativeGain = cumulateSensorData(trackPoint, sensorPoints, (tp) -> tp.hasAltitudeGainLoss() ? (double) tp.getAltitudeGainLoss().gain_m() : null); + Double cumulativeGain = cumulateSensorData(trackPoint, sensorPoints, (tp) -> tp.altitudeGainLoss() != null ? (double) tp.altitudeGainLoss().gain_m() : null); if (cumulativeGain != null) { extensionContent += ("" + ALTITUDE_FORMAT.format(cumulativeGain) + "\n"); } - Double cumulativeLoss = cumulateSensorData(trackPoint, sensorPoints, (tp) -> tp.hasAltitudeGainLoss() ? (double) tp.getAltitudeGainLoss().loss_m() : null); + Double cumulativeLoss = cumulateSensorData(trackPoint, sensorPoints, (tp) -> tp.altitudeGainLoss() != null ? (double) tp.altitudeGainLoss().loss_m() : null); if (cumulativeLoss != null) { extensionContent += ("" + ALTITUDE_FORMAT.format(cumulativeLoss) + "\n"); } - if (trackPoint.hasHorizontalAccuracy()) { - extensionContent += ("" + DISTANCE_FORMAT.format(trackPoint.getHorizontalAccuracy().toM()) + ""); + if (trackPoint.position().hasHorizontalAccuracy()) { + extensionContent += ("" + DISTANCE_FORMAT.format(trackPoint.position().horizontalAccuracy().toM()) + ""); } - if (trackPoint.hasVerticalAccuracy()) { - extensionContent += ("" + DISTANCE_FORMAT.format(trackPoint.getVerticalAccuracy().toM()) + ""); + if (trackPoint.position().hasVerticalAccuracy()) { + extensionContent += ("" + DISTANCE_FORMAT.format(trackPoint.position().verticalAccuracy().toM()) + ""); } - cumulativeDistance = Distance.ofOrNull(cumulateSensorData(trackPoint, sensorPoints, (tp) -> tp.hasSensorDistance() ? tp.getSensorDistance().toM() : null)); + cumulativeDistance = Distance.ofOrNull(cumulateSensorData(trackPoint, sensorPoints, (tp) -> tp.sensorDistance() != null ? tp.sensorDistance().toM() : null)); if (cumulativeDistance != null) { extensionContent += ("" + DISTANCE_FORMAT.format(cumulativeDistance.toM()) + "\n"); extensionContent += ("" + DISTANCE_FORMAT.format(trackDistance.plus(cumulativeDistance).toM()) + "\n"); diff --git a/src/main/java/de/dennisguse/opentracks/io/file/exporter/KMLTrackExporter.java b/src/main/java/de/dennisguse/opentracks/io/file/exporter/KMLTrackExporter.java index 056e47300..dee163490 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/exporter/KMLTrackExporter.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/exporter/KMLTrackExporter.java @@ -95,7 +95,7 @@ public class KMLTrackExporter implements TrackExporter { private final List powerList = new ArrayList<>(); private final List cadenceList = new ArrayList<>(); private final List heartRateList = new ArrayList<>(); - private final List altitudeGainList = new ArrayList<>(); + private final List altitudeGainList = new ArrayList<>(); //TODO Join with altitudeLossList private final List altitudeLossList = new ArrayList<>(); private final List accuracyHorizontal = new ArrayList<>(); private final List accuracyVertical = new ArrayList<>(); @@ -167,7 +167,7 @@ public class KMLTrackExporter implements TrackExporter { wroteTrack = true; } - switch (trackPoint.getType()) { + switch (trackPoint.type()) { case SEGMENT_START_MANUAL, SEGMENT_START_AUTOMATIC -> { if (wroteSegment) writeCloseSegment(); writeOpenSegment(); @@ -190,7 +190,7 @@ public class KMLTrackExporter implements TrackExporter { writeTrackPoint(track.zoneOffset(), trackPoint); } default -> - throw new RuntimeException("Exporting this TrackPoint type is not implemented: " + trackPoint.getType()); + throw new RuntimeException("Exporting this TrackPoint type is not implemented: " + trackPoint.type()); } } @@ -370,28 +370,28 @@ public class KMLTrackExporter implements TrackExporter { void writeTrackPoint(ZoneOffset zoneOffset, TrackPoint trackPoint) { printWriter.println("" + getTime(zoneOffset, trackPoint.getTime()) + ""); - trackpointTypeList.add(trackPoint.getType()); + trackpointTypeList.add(trackPoint.type()); - if (trackPoint.hasLocation()) { - printWriter.println("" + getCoordinates(trackPoint.getPosition(), " ") + ""); + if (trackPoint.position().hasLocation()) { + printWriter.println("" + getCoordinates(trackPoint.position(), " ") + ""); } else { printWriter.println(""); } - speedList.add(trackPoint.hasSpeed() ? (float) trackPoint.getSpeed().toMPS() : null); + speedList.add(trackPoint.position().hasSpeed() ? (float) trackPoint.position().speed().toMPS() : null); - distanceList.add(trackPoint.hasSensorDistance() ? (float) trackPoint.getSensorDistance().toM() : null); - heartRateList.add(trackPoint.hasHeartRate() ? trackPoint.getHeartRate().getBPM() : null); - cadenceList.add(trackPoint.hasCadence() ? trackPoint.getCadence().getRPM() : null); - powerList.add(trackPoint.hasPower() ? trackPoint.getPower().getW() : null); - if (trackPoint.hasAltitudeGainLoss()) { - altitudeGainList.add(trackPoint.getAltitudeGainLoss().loss_m()); - altitudeLossList.add(trackPoint.getAltitudeGainLoss().loss_m()); + distanceList.add(trackPoint.sensorDistance() != null ? (float) trackPoint.sensorDistance().toM() : null); + heartRateList.add(trackPoint.heartRate() != null ? trackPoint.heartRate().getBPM() : null); + cadenceList.add(trackPoint.cadence() != null ? trackPoint.cadence().getRPM() : null); + powerList.add(trackPoint.power() != null ? trackPoint.power().getW() : null); + if (trackPoint.altitudeGainLoss() != null) { + altitudeGainList.add(trackPoint.altitudeGainLoss().loss_m()); + altitudeLossList.add(trackPoint.altitudeGainLoss().loss_m()); } else { altitudeGainList.add(null); altitudeLossList.add(null); } - accuracyHorizontal.add(trackPoint.hasHorizontalAccuracy() ? (float) trackPoint.getHorizontalAccuracy().toM() : null); - accuracyVertical.add(trackPoint.hasVerticalAccuracy() ? (float) trackPoint.getVerticalAccuracy().toM() : null); + accuracyHorizontal.add(trackPoint.position().hasHorizontalAccuracy() ? (float) trackPoint.position().horizontalAccuracy().toM() : null); + accuracyVertical.add(trackPoint.position().hasVerticalAccuracy() ? (float) trackPoint.position().verticalAccuracy().toM() : null); } private void writeSimpleArraySensorData(List list, String name) { diff --git a/src/main/java/de/dennisguse/opentracks/io/file/importer/GPXTrackImporter.java b/src/main/java/de/dennisguse/opentracks/io/file/importer/GPXTrackImporter.java index 6c66673b6..d517e94c7 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/importer/GPXTrackImporter.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/importer/GPXTrackImporter.java @@ -32,9 +32,13 @@ import java.util.List; import java.util.Locale; import de.dennisguse.opentracks.data.models.Altitude; +import de.dennisguse.opentracks.data.models.AltitudeGainLoss; +import de.dennisguse.opentracks.data.models.Cadence; import de.dennisguse.opentracks.data.models.Distance; +import de.dennisguse.opentracks.data.models.HeartRate; import de.dennisguse.opentracks.data.models.Marker; import de.dennisguse.opentracks.data.models.Position; +import de.dennisguse.opentracks.data.models.Power; import de.dennisguse.opentracks.data.models.Speed; import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.models.TrackPoint; @@ -265,8 +269,8 @@ public class GPXTrackImporter extends DefaultHandler implements XMLImporter.Trac return; } - TrackPoint first = currentSegment.getFirst(); - first.setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC); + TrackPoint first = currentSegment.removeFirst(); + currentSegment.addFirst(first.with(TrackPoint.Type.SEGMENT_START_AUTOMATIC)); trackImporter.addTrackPoints(currentSegment); currentSegment.clear(); @@ -332,59 +336,70 @@ public class GPXTrackImporter extends DefaultHandler implements XMLImporter.Trac } } - TrackPoint trackPoint = new TrackPoint( - TrackPoint.Type.TRACKPOINT, - new Position( - parsedTime.toInstant(), - latitudeParsed, - longitudeParsed, - accuracyHorizontalParsed, - altitudeParsed, - accuracyVerticalParsed, - null, - speedParsed - )); - - if (heartrate != null) { - try { - trackPoint.setHeartRate(Float.parseFloat(heartrate)); - } catch (NumberFormatException e) { - throw new ParsingException(createErrorMessage(String.format(Locale.US, "Unable to parse heart rate: %s", heartrate)), e); - } - } - - if (cadence != null) { - try { - trackPoint.setCadence(Float.parseFloat(cadence)); - } catch (Exception e) { - throw new ParsingException(createErrorMessage(String.format(Locale.US, "Unable to parse cadence: %s", cadence)), e); - } - } - - if (power != null) { - try { - trackPoint.setPower(Float.parseFloat(power)); - } catch (NumberFormatException e) { - throw new ParsingException(createErrorMessage(String.format(Locale.US, "Unable to parse power: %s", power)), e); - } - } - - if (gain != null && loss != null) { - try { - trackPoint.setAltitudeGainLoss(Float.parseFloat(gain), Float.parseFloat(loss)); - } catch (NumberFormatException e) { - throw new ParsingException(createErrorMessage(String.format(Locale.US, "Unable to parse altitude gain: %s or los: %s", gain, loss)), e); - } - } + Distance parsedSensorDistance = null; if (sensorDistance != null) { try { - trackPoint.setSensorDistance(Distance.of(Float.parseFloat(sensorDistance))); + parsedSensorDistance = Distance.of(Float.parseFloat(sensorDistance)); } catch (NumberFormatException e) { throw new ParsingException(createErrorMessage(String.format(Locale.US, "Unable to parse distance: %s", sensorDistance)), e); } } - return trackPoint; + HeartRate parsedHeartRate = null; + if (heartrate != null) { + try { + parsedHeartRate = HeartRate.of(Float.parseFloat(heartrate)); + } catch (NumberFormatException e) { + throw new ParsingException(createErrorMessage(String.format(Locale.US, "Unable to parse heart rate: %s", heartrate)), e); + } + } + + Cadence parsedCadence = null; + if (cadence != null) { + try { + parsedCadence = Cadence.of(Float.parseFloat(cadence)); + } catch (Exception e) { + throw new ParsingException(createErrorMessage(String.format(Locale.US, "Unable to parse cadence: %s", cadence)), e); + } + } + + Power parsedPower = null; + if (power != null) { + try { + parsedPower = Power.of(Float.parseFloat(power)); + } catch (NumberFormatException e) { + throw new ParsingException(createErrorMessage(String.format(Locale.US, "Unable to parse power: %s", power)), e); + } + } + + AltitudeGainLoss altitudeGainLoss = null; + if (gain != null && loss != null) { + try { + altitudeGainLoss = new AltitudeGainLoss(Float.parseFloat(gain), Float.parseFloat(loss)); + } catch (NumberFormatException e) { + throw new ParsingException(createErrorMessage(String.format(Locale.US, "Unable to parse altitude gain: %s or los: %s", gain, loss)), e); + } + } + + return new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + new Position( + parsedTime.toInstant(), + latitudeParsed, + longitudeParsed, + accuracyHorizontalParsed, + altitudeParsed, + accuracyVerticalParsed, + null, + speedParsed + ), + parsedSensorDistance, + parsedHeartRate, + parsedCadence, + parsedPower, + altitudeGainLoss + ); } private void onTrackPointStart(Attributes attributes) { @@ -425,8 +440,8 @@ public class GPXTrackImporter extends DefaultHandler implements XMLImporter.Trac TrackPoint trackPoint = createTrackPoint(); - if (!trackPoint.hasLocation()) { - Log.w(TAG, "Marker with invalid coordinates ignored: " + trackPoint.getPosition()); + if (!trackPoint.position().hasLocation()) { + Log.w(TAG, "Marker with invalid coordinates ignored: " + trackPoint.position()); return; } markers.add(new Marker( @@ -435,7 +450,7 @@ public class GPXTrackImporter extends DefaultHandler implements XMLImporter.Trac name != null ? name : "", description != null ? description : "", markerType != null ? markerType : "", - trackPoint.getPosition(), + trackPoint.position(), photoUrl )); } diff --git a/src/main/java/de/dennisguse/opentracks/io/file/importer/KMLTrackImporter.java b/src/main/java/de/dennisguse/opentracks/io/file/importer/KMLTrackImporter.java index 59a3666b7..ba9d740c4 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/importer/KMLTrackImporter.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/importer/KMLTrackImporter.java @@ -33,9 +33,13 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; +import de.dennisguse.opentracks.data.models.AltitudeGainLoss; +import de.dennisguse.opentracks.data.models.Cadence; import de.dennisguse.opentracks.data.models.Distance; +import de.dennisguse.opentracks.data.models.HeartRate; import de.dennisguse.opentracks.data.models.Marker; import de.dennisguse.opentracks.data.models.Position; +import de.dennisguse.opentracks.data.models.Power; import de.dennisguse.opentracks.data.models.Speed; import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.models.TrackPoint; @@ -95,10 +99,11 @@ public class KMLTrackImporter extends DefaultHandler implements XMLImporter.Trac private ZoneOffset zoneOffset; private final ArrayList whenList = new ArrayList<>(); - private final ArrayList positionList = new ArrayList<>(); + private final ArrayList positionList = new ArrayList<>(); //TODO This is only latitude, longitude, and altitude private String dataType; + //TODO For ArrayList use specific data models; and why Float? Double would be easier. private final ArrayList trackpointTypeList = new ArrayList<>(); private final ArrayList sensorSpeedList = new ArrayList<>(); private final ArrayList sensorDistanceList = new ArrayList<>(); @@ -151,8 +156,7 @@ public class KMLTrackImporter extends DefaultHandler implements XMLImporter.Trac } onTrackSegmentStart(); } - case TAG_EXTENDED_DATA, TAG_SIMPLE_ARRAY_DATA, TAG_KML22_SIMPLE_ARRAY_DATA -> - dataType = attributes.getValue(ATTRIBUTE_NAME); + case TAG_EXTENDED_DATA, TAG_SIMPLE_ARRAY_DATA, TAG_KML22_SIMPLE_ARRAY_DATA -> dataType = attributes.getValue(ATTRIBUTE_NAME); } } @@ -317,62 +321,77 @@ public class KMLTrackImporter extends DefaultHandler implements XMLImporter.Trac for (int i = 0; i < positionList.size(); i++) { Instant time = whenList.get(i); Position position = positionList.get(i); - - TrackPoint trackPoint; if (position == null) { - trackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT, Position.of(time)); + position = Position.of(time); } else { - trackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT, position.with(time)); + position = position.with(time); } + TrackPoint.Type type = null; + Speed speed = null; + Distance sensorDistance = null; + HeartRate heartRate = null; + Cadence cadence = null; + Power power = null; + AltitudeGainLoss altitudeGainLoss = null; + Distance horizontalAccuracy = null; + Distance verticalAccuracy = null; + if (i < trackpointTypeList.size() && trackpointTypeList.get(i) != null) { - TrackPoint.Type type = TrackPoint.Type.valueOf(trackpointTypeList.get(i)); - trackPoint.setType(type); + type = TrackPoint.Type.valueOf(trackpointTypeList.get(i)); } - if (i < sensorSpeedList.size() && sensorSpeedList.get(i) != null) { - trackPoint.setSpeed(Speed.of(sensorSpeedList.get(i))); + speed = Speed.of(sensorSpeedList.get(i)); } if (i < sensorDistanceList.size() && sensorDistanceList.get(i) != null) { - trackPoint.setSensorDistance(Distance.of(sensorDistanceList.get(i))); + sensorDistance = Distance.of(sensorDistanceList.get(i)); } - if (i < sensorHeartRateList.size() && sensorHeartRateList.get(i) != null) { - trackPoint.setHeartRate(sensorHeartRateList.get(i)); + if (i < sensorHeartRateList.size()) { + heartRate = HeartRate.ofOrNull(sensorHeartRateList.get(i)); } if (i < sensorCadenceList.size() && sensorCadenceList.get(i) != null) { - trackPoint.setCadence(sensorCadenceList.get(i)); + cadence = Cadence.of(sensorCadenceList.get(i)); } if (i < sensorPowerList.size() && sensorPowerList.get(i) != null) { - trackPoint.setPower(sensorPowerList.get(i)); + power = Power.of(sensorPowerList.get(i)); } - if (i < altitudeGainList.size() && i < altitudeLossList.size()) { - if (altitudeGainList.get(i) != null && altitudeLossList.get(i) != null) { - trackPoint.setAltitudeGainLoss(altitudeGainList.get(i), altitudeLossList.get(i)); - } + if ((i < altitudeGainList.size() && altitudeGainList.get(i) != null) + && (i < altitudeLossList.size() && altitudeLossList.get(i) != null)) { + altitudeGainLoss = new AltitudeGainLoss(altitudeGainList.get(i), altitudeLossList.get(i)); } if (i < accuracyHorizontal.size() && accuracyHorizontal.get(i) != null) { - trackPoint.setHorizontalAccuracy(Distance.of(accuracyHorizontal.get(i))); + horizontalAccuracy = Distance.of(accuracyHorizontal.get(i)); } if (i < accuracyVertical.size() && accuracyVertical.get(i) != null) { - trackPoint.setVerticalAccuracy(Distance.of(accuracyVertical.get(i))); + verticalAccuracy = Distance.of(accuracyVertical.get(i)); } // Update TrackPoint type for START / STOP. - TrackPoint.Type type = trackPoint.getType(); if (i == 0) { //first - if (!trackPoint.wasCreatedManually()) { - type = TrackPoint.Type.SEGMENT_START_MANUAL; - } else { + if (wasCreatedAutomatically(position)) { type = TrackPoint.Type.SEGMENT_START_AUTOMATIC; + } else { + type = TrackPoint.Type.SEGMENT_START_MANUAL; } - } else if (i == positionList.size() - 1 && !trackPoint.wasCreatedManually()) { + } else if (i == positionList.size() - 1 && !wasCreatedAutomatically(position)) { //last type = TrackPoint.Type.SEGMENT_END_MANUAL; } - trackPoint.setType(type); - trackImporter.addTrackPoint(trackPoint); + trackImporter.addTrackPoint(new TrackPoint( + null, + type != null ? type : TrackPoint.Type.TRACKPOINT, + position + .with(speed) + .withHorizontalAccuracy(horizontalAccuracy) + .withVerticalAccuracy(verticalAccuracy), + sensorDistance, + heartRate, + cadence, + power, + altitudeGainLoss + )); } } @@ -392,6 +411,7 @@ public class KMLTrackImporter extends DefaultHandler implements XMLImporter.Trac } private Position createPosition(String latitude, String longitude, String altitude) { + //TODO Do not use Location. if (longitude != null && latitude != null) { Location location = new Location("import"); try { @@ -439,12 +459,9 @@ public class KMLTrackImporter extends DefaultHandler implements XMLImporter.Trac case KMLTrackExporter.EXTENDED_DATA_TYPE_CADENCE -> sensorCadenceList.add(value); case KMLTrackExporter.EXTENDED_DATA_TYPE_ALTITUDE_GAIN -> altitudeGainList.add(value); case KMLTrackExporter.EXTENDED_DATA_TYPE_ALTITUDE_LOSS -> altitudeLossList.add(value); - case KMLTrackExporter.EXTENDED_DATA_TYPE_ACCURACY_HORIZONTAL -> - accuracyHorizontal.add(value); - case KMLTrackExporter.EXTENDED_DATA_TYPE_ACCURACY_VERTICAL -> - accuracyVertical.add(value); - default -> - Log.w(TAG, "Data from extended data " + dataType + " is not (yet) supported."); + case KMLTrackExporter.EXTENDED_DATA_TYPE_ACCURACY_HORIZONTAL -> accuracyHorizontal.add(value); + case KMLTrackExporter.EXTENDED_DATA_TYPE_ACCURACY_VERTICAL -> accuracyVertical.add(value); + default -> Log.w(TAG, "Data from extended data " + dataType + " is not (yet) supported."); } } @@ -457,6 +474,10 @@ public class KMLTrackImporter extends DefaultHandler implements XMLImporter.Trac trackImporter.finish(); } + public boolean wasCreatedAutomatically(Position position) { + return position.hasLocation() || position.hasSpeed(); + } + @Override public DefaultHandler getHandler() { return this; diff --git a/src/main/java/de/dennisguse/opentracks/io/file/importer/TrackImporter.java b/src/main/java/de/dennisguse/opentracks/io/file/importer/TrackImporter.java index 69db9164a..e46f5f21c 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/importer/TrackImporter.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/importer/TrackImporter.java @@ -176,21 +176,19 @@ public class TrackImporter { TrackPoint previous = trackPoints.get(i - 1); TrackPoint current = trackPoints.get(i); - if (current.hasSensorDistance() || (previous.hasLocation() && current.hasLocation())) { + if (current.sensorDistance() != null || (previous.position().hasLocation() && current.position().hasLocation())) { + TrackPoint newCurrent = current; + Distance distanceToPrevious = current.distanceToPrevious(previous); - if (!current.hasSpeed()) { + if (!current.position().hasSpeed()) { Duration timeDifference = Duration.between(previous.getTime(), current.getTime()); - current.setSpeed(Speed.of(distanceToPrevious, timeDifference)); + newCurrent = newCurrent.with(newCurrent.position().with(Speed.of(distanceToPrevious, timeDifference))); } - if (!current.hasBearing()) { - previous.bearingTo(current) - .ifPresent(current::setBearing); - } - - if (current.getType().equals(TrackPoint.Type.TRACKPOINT) && distanceToPrevious.greaterThan(maxRecordingDistance)) { - current.setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC); + if (current.type().equals(TrackPoint.Type.TRACKPOINT) && distanceToPrevious.greaterThan(maxRecordingDistance)) { + newCurrent = newCurrent.with(TrackPoint.Type.SEGMENT_START_AUTOMATIC); } + trackPoints.set(i, newCurrent); } } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java b/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java index 692a15b3e..7016375ef 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/GpsManager.java @@ -124,20 +124,20 @@ public class GpsManager implements SensorConnector, LocationListenerCompat, GpsS @Override public void onLocationChanged(@NonNull Location location) { // Send each update to the status; please note that this TrackPoint is not stored. - TrackPoint trackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT, Position.of(location, trackPointCreator.createNow())); - gpsStatusManager.onNewTrackPoint(trackPoint); + Position position = Position.of(location, trackPointCreator.createNow()); + gpsStatusManager.onNewTrackPoint(new TrackPoint(TrackPoint.Type.TRACKPOINT, position)); - if (!trackPoint.getPosition().hasValidLocation()) { - Log.w(TAG, "Ignore newTrackPoint. location is invalid."); + if (!position.hasValidLocation()) { + Log.w(TAG, "Ignore newTrackPoint. Location is invalid."); return; } - if (!trackPoint.getPosition().fulfillsAccuracy(thresholdHorizontalAccuracy)) { + if (!position.fulfillsAccuracy(thresholdHorizontalAccuracy)) { Log.d(TAG, "Ignore newTrackPoint. Poor accuracy."); return; } - observer.onChange(new Raw<>(observer.getNow(), Position.of(location))); + observer.onChange(new Raw<>(observer.getNow(), position)); } @Override diff --git a/src/main/java/de/dennisguse/opentracks/sensors/GpsStatusManager.java b/src/main/java/de/dennisguse/opentracks/sensors/GpsStatusManager.java index 8effc373b..c5b887d3f 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/GpsStatusManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/GpsStatusManager.java @@ -18,6 +18,7 @@ import de.dennisguse.opentracks.settings.PreferencesUtils; /** * This class handle GPS status according to received locations and some thresholds. */ +//TODO Use Position instead of TrackPoint. class GpsStatusManager { private static final String TAG = GpsStatusManager.class.getSimpleName(); @@ -100,7 +101,7 @@ class GpsStatusManager { //TODO use MonotonicClock instead of Instant.now() @VisibleForTesting void determineGpsStatusOnTrackpoint(@NonNull TrackPoint lastTrackPoint) { - if (lastTrackPoint.fulfillsAccuracy(horizontalAccuracyThreshold)) { + if (lastTrackPoint.position().fulfillsAccuracy(horizontalAccuracyThreshold)) { if (gpsStatus != GpsStatusValue.GPS_SIGNAL_FIX) { setGpsStatus(GpsStatusValue.GPS_SIGNAL_FIX); scheduleTimer(); //TODO diff --git a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java index b28bedfdd..d645748ea 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/SensorManager.java @@ -11,9 +11,9 @@ import androidx.annotation.VisibleForTesting; import java.time.Instant; -import de.dennisguse.opentracks.data.models.TrackPoint; import de.dennisguse.opentracks.sensors.sensorData.Aggregator; import de.dennisguse.opentracks.sensors.sensorData.Raw; +import de.dennisguse.opentracks.sensors.sensorData.SensorDataAggregator; import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet; import de.dennisguse.opentracks.services.handlers.TrackPointCreator; import de.dennisguse.opentracks.util.SystemUtils; @@ -24,7 +24,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange //TODO Should be final and not be visible for testing @VisibleForTesting - public SensorDataSet sensorDataSet; + public SensorDataAggregator sensorDataAggregator; private PowerManager.WakeLock wakeLock; @@ -34,23 +34,23 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange @Override public void onConnect(Aggregator aggregator) { - sensorDataSet.add(aggregator); + sensorDataAggregator.add(aggregator); } @Override public void onChange(Raw data) { - sensorDataSet.update(data); - observer.onChange(new SensorDataSet(sensorDataSet)); + sensorDataAggregator.update(data); + observer.onChange(); } @Override public void onDisconnect(Aggregator aggregator) { - sensorDataSet.add(aggregator); + sensorDataAggregator.add(aggregator); } @Override public void onRemove(Aggregator aggregator) { - sensorDataSet.remove(aggregator); + sensorDataAggregator.remove(aggregator); } @Override @@ -67,7 +67,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange public SensorManager(TrackPointCreator observer) { this.observer = observer; - this.sensorDataSet = new SensorDataSet(observer); + this.sensorDataAggregator = new SensorDataAggregator(); } public void start(Context context, Handler handler) { @@ -100,12 +100,11 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange gpsManager.stop(context); gpsManager = null; - sensorDataSet.clear(); + sensorDataAggregator.clear(); } - public SensorDataSet fill(TrackPoint trackPoint) { - sensorDataSet.fillTrackPoint(trackPoint); - return new SensorDataSet(sensorDataSet); + public SensorDataSet getSensorDataSet(Instant now) { + return sensorDataAggregator.getSensorData(now); } public void reset() { @@ -113,7 +112,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange Log.d(TAG, "No recording running and no reset necessary."); return; } - sensorDataSet.reset(); + sensorDataAggregator.reset(); } @VisibleForTesting diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java index 7f59b79c4..749d5a27c 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/Aggregator.java @@ -1,7 +1,5 @@ package de.dennisguse.opentracks.sensors.sensorData; -import android.util.Pair; - import androidx.annotation.NonNull; import java.time.Instant; @@ -61,8 +59,8 @@ public abstract class Aggregator { } @NonNull - public Pair getAggregatedValueWithSensorName(Instant now) { - return new Pair<>(getAggregatedValue(now), getSensorNameOrAddress()); + public SensorData getAggregatedValueWithSensorName(Instant now) { + return new SensorData<>(getAggregatedValue(now), getSensorNameOrAddress()); } /** diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorGPS.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorGPS.java index 1b3b05428..62838e11d 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorGPS.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/AggregatorGPS.java @@ -2,6 +2,8 @@ package de.dennisguse.opentracks.sensors.sensorData; import androidx.annotation.NonNull; +import java.time.Instant; + import de.dennisguse.opentracks.data.models.Position; public class AggregatorGPS extends Aggregator { @@ -36,4 +38,11 @@ public class AggregatorGPS extends Aggregator { protected Position getNoneValue() { return Position.empty(); } + + @NonNull + @Override + public Position getAggregatedValue(Instant now) { + return super.getAggregatedValue(now) + .with(now); + } } diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorData.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorData.java new file mode 100644 index 000000000..104bf718a --- /dev/null +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorData.java @@ -0,0 +1,9 @@ +package de.dennisguse.opentracks.sensors.sensorData; + +public record SensorData( + + T data, + + String sensorNameOrAddress +) { +} diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataAggregator.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataAggregator.java new file mode 100644 index 000000000..6787a3e3a --- /dev/null +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataAggregator.java @@ -0,0 +1,212 @@ +package de.dennisguse.opentracks.sensors.sensorData; + +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + +import java.time.Instant; + +import de.dennisguse.opentracks.data.models.AtmosphericPressure; +import de.dennisguse.opentracks.data.models.Cadence; +import de.dennisguse.opentracks.data.models.Distance; +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.sensors.BluetoothHandlerCyclingCadence; +import de.dennisguse.opentracks.sensors.BluetoothHandlerCyclingDistanceSpeed; +import de.dennisguse.opentracks.sensors.BluetoothHandlerManagerCyclingPower; +import de.dennisguse.opentracks.sensors.BluetoothHandlerRunningSpeedAndCadence; +import de.dennisguse.opentracks.settings.PreferencesUtils; + +public class SensorDataAggregator { + + private static final String TAG = SensorDataAggregator.class.getSimpleName(); + + @VisibleForTesting + public AggregatorHeartRate heartRate; + + @VisibleForTesting + public AggregatorCyclingCadence cyclingCadence; + + @VisibleForTesting + public AggregatorCyclingDistanceSpeed cyclingDistanceSpeed; + + @VisibleForTesting + public AggregatorCyclingPower cyclingPower; + + @VisibleForTesting + public AggregatorRunning runningDistanceSpeedCadence; + + @VisibleForTesting + public AggregatorBarometer barometer; + + public AggregatorGPS gps; + + @VisibleForTesting + public SensorData getHeartRate(Instant now) { + if (heartRate != null) { + SensorData value = heartRate.getAggregatedValueWithSensorName(now); + if (value.data().isValid()) return value; + } + + return null; + } + + private SensorData getCadence(Instant now) { + if (cyclingCadence != null) { + return cyclingCadence.getAggregatedValueWithSensorName(now); + } + + if (runningDistanceSpeedCadence != null && runningDistanceSpeedCadence.hasReceivedData() && runningDistanceSpeedCadence.getAggregatedValue(now).cadence() != null) { + return new SensorData<>(runningDistanceSpeedCadence.aggregatedValue.cadence(), runningDistanceSpeedCadence.getSensorNameOrAddress()); + } + + return null; + } + + private SensorData getDistance(Instant now) { + if (cyclingDistanceSpeed != null && cyclingDistanceSpeed.hasReceivedData()) { + return new SensorData<>(cyclingDistanceSpeed.getAggregatedValue(now).distanceOverall(), cyclingDistanceSpeed.getSensorNameOrAddress()); + } + + if (runningDistanceSpeedCadence != null && runningDistanceSpeedCadence.hasReceivedData()) { + return new SensorData<>(runningDistanceSpeedCadence.getAggregatedValue(now).distance(), runningDistanceSpeedCadence.getSensorNameOrAddress()); + + } + + return null; + } + + //TOOD simplify? + private SensorData getSpeed(Instant now) { + + if (cyclingDistanceSpeed != null && cyclingDistanceSpeed.hasReceivedData() && cyclingDistanceSpeed.getAggregatedValue(now).speed() != null) { + return new SensorData<>(cyclingDistanceSpeed.getAggregatedValue(now).speed(), cyclingDistanceSpeed.getSensorNameOrAddress()); + } + + if (runningDistanceSpeedCadence != null && runningDistanceSpeedCadence.hasReceivedData() && runningDistanceSpeedCadence.getAggregatedValue(now).speed() != null) { + return new SensorData<>(runningDistanceSpeedCadence.aggregatedValue.speed(), runningDistanceSpeedCadence.getSensorNameOrAddress()); + } + + return null; + } + + public void add(@NonNull Aggregator data) { + set(data, data); + } + + public void update(@NonNull Raw data) { + Object value = data.value(); + + if (value instanceof HeartRate) { + this.heartRate.add((Raw) data); + return; + } + + if (value instanceof BluetoothHandlerCyclingCadence.CrankData) { + this.cyclingCadence.add((Raw) data); + return; + } + if (value instanceof BluetoothHandlerCyclingDistanceSpeed.WheelData) { + this.cyclingDistanceSpeed.setWheelCircumference(PreferencesUtils.getWheelCircumference()); //TODO Fetch once and then listen for changes. + this.cyclingDistanceSpeed.add((Raw) data); + return; + } + if (value instanceof BluetoothHandlerRunningSpeedAndCadence.Data) { + this.runningDistanceSpeedCadence.add((Raw) data); + + return; + } + if (value instanceof BluetoothHandlerManagerCyclingPower.Data) { + this.cyclingPower.add((Raw) data); + return; + } + if (value instanceof AtmosphericPressure) { + this.barometer.add((Raw) data); + return; + } + if (value instanceof Position) { + this.gps.add((Raw) data); + return; + } + + throw new UnsupportedOperationException(data.getClass().getCanonicalName() + " " + data.value().getClass().getCanonicalName()); + } + + public void remove(@NonNull Aggregator type) { + set(type, null); + } + + public void clear() { + Log.i(TAG, "Removing all aggregators"); + this.heartRate = null; + this.cyclingCadence = null; + this.cyclingDistanceSpeed = null; + this.cyclingPower = null; + this.runningDistanceSpeedCadence = null; + this.barometer = null; + this.gps = null; + } + + public SensorDataSet getSensorData(Instant now) { + return new SensorDataSet( + gps != null && gps.hasReceivedData() ? gps.getAggregatedValueWithSensorName(now) : new SensorData<>(Position.of(now), ""), + getSpeed(now), + getDistance(now), + getHeartRate(now), + getCadence(now), + cyclingPower != null && cyclingPower.hasReceivedData() ? cyclingPower.getAggregatedValueWithSensorName(now) : null, + barometer != null && barometer.hasReceivedData() ? barometer.getAggregatedValueWithSensorName(now) : null + ); + } + + public void reset() { + Log.i(TAG, "Resetting data"); + + if (heartRate != null) heartRate.resetAggregated(); + if (cyclingCadence != null) cyclingCadence.resetAggregated(); + if (cyclingDistanceSpeed != null) cyclingDistanceSpeed.resetAggregated(); + if (cyclingPower != null) cyclingPower.resetAggregated(); + if (runningDistanceSpeedCadence != null) runningDistanceSpeedCadence.resetAggregated(); + if (barometer != null) barometer.resetAggregated(); + if (gps != null) gps.resetAggregated(); + } + + //TODO Refactor generic "fun" here: go explicit. + private void set(@NonNull Aggregator type, @Nullable Aggregator sensorData) { + Log.i(TAG, "Setting aggregator " + type.getClass().getCanonicalName() + " to " + sensorData); + + if (type instanceof AggregatorHeartRate) { + heartRate = (AggregatorHeartRate) sensorData; + return; + } + if (type instanceof AggregatorCyclingCadence) { + cyclingCadence = (AggregatorCyclingCadence) sensorData; + return; + } + if (type instanceof AggregatorCyclingDistanceSpeed) { + cyclingDistanceSpeed = (AggregatorCyclingDistanceSpeed) sensorData; + return; + } + if (type instanceof AggregatorCyclingPower) { + cyclingPower = (AggregatorCyclingPower) sensorData; + return; + } + if (type instanceof AggregatorRunning) { + runningDistanceSpeedCadence = (AggregatorRunning) sensorData; + return; + } + if (type instanceof AggregatorBarometer) { + barometer = (AggregatorBarometer) sensorData; + return; + } + if (type instanceof AggregatorGPS) { + gps = (AggregatorGPS) sensorData; + return; + } + + throw new UnsupportedOperationException(type.getClass().getCanonicalName()); + } +} diff --git a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataSet.java b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataSet.java index 4ed3bed7c..fbb05121b 100644 --- a/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataSet.java +++ b/src/main/java/de/dennisguse/opentracks/sensors/sensorData/SensorDataSet.java @@ -1,240 +1,30 @@ package de.dennisguse.opentracks.sensors.sensorData; -import android.util.Log; -import android.util.Pair; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; -import de.dennisguse.opentracks.data.models.AtmosphericPressure; +import de.dennisguse.opentracks.data.models.AltitudeGainLoss; import de.dennisguse.opentracks.data.models.Cadence; +import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.HeartRate; import de.dennisguse.opentracks.data.models.Position; +import de.dennisguse.opentracks.data.models.Power; import de.dennisguse.opentracks.data.models.Speed; -import de.dennisguse.opentracks.data.models.TrackPoint; -import de.dennisguse.opentracks.sensors.BluetoothHandlerCyclingCadence; -import de.dennisguse.opentracks.sensors.BluetoothHandlerCyclingDistanceSpeed; -import de.dennisguse.opentracks.sensors.BluetoothHandlerManagerCyclingPower; -import de.dennisguse.opentracks.sensors.BluetoothHandlerRunningSpeedAndCadence; -import de.dennisguse.opentracks.services.handlers.TrackPointCreator; -import de.dennisguse.opentracks.settings.PreferencesUtils; -public class SensorDataSet { - - private static final String TAG = SensorDataSet.class.getSimpleName(); - - @VisibleForTesting - public AggregatorHeartRate heartRate; - - @VisibleForTesting - public AggregatorCyclingCadence cyclingCadence; - - @VisibleForTesting - public AggregatorCyclingDistanceSpeed cyclingDistanceSpeed; - - @VisibleForTesting - public AggregatorCyclingPower cyclingPower; - - @VisibleForTesting - public AggregatorRunning runningDistanceSpeedCadence; - - @VisibleForTesting - public AggregatorBarometer barometer; - - public AggregatorGPS gps; - - private final TrackPointCreator trackPointCreator; - - public SensorDataSet(TrackPointCreator trackPointCreator) { - this.trackPointCreator = trackPointCreator; - } - - @Deprecated //TODO This is not a copy constructor anymore, but it should be - aggregators are no value objects; best guess: can be removed - public SensorDataSet(SensorDataSet toCopy) { - this.trackPointCreator = toCopy.trackPointCreator; - this.heartRate = toCopy.heartRate; - this.cyclingCadence = toCopy.cyclingCadence; - this.cyclingDistanceSpeed = toCopy.cyclingDistanceSpeed; - this.cyclingPower = toCopy.cyclingPower; - this.runningDistanceSpeedCadence = toCopy.runningDistanceSpeedCadence; - this.barometer = toCopy.barometer; - this.gps = toCopy.gps; - } - - public Pair getHeartRate() { - if (heartRate != null) { - Pair value = heartRate.getAggregatedValueWithSensorName(trackPointCreator.createNow()); - if (value.first.isValid()) return value; - } - - return null; - } - - public Pair getCadence() { - if (cyclingCadence != null) { - return cyclingCadence.getAggregatedValueWithSensorName(trackPointCreator.createNow()); - } - - if (runningDistanceSpeedCadence != null && runningDistanceSpeedCadence.hasReceivedData() && runningDistanceSpeedCadence.aggregatedValue.cadence() != null) { - return new Pair<>(runningDistanceSpeedCadence.aggregatedValue.cadence(), runningDistanceSpeedCadence.getSensorNameOrAddress()); - } - - return null; - } - - public Pair getSpeed() { - if (cyclingDistanceSpeed != null && cyclingDistanceSpeed.hasReceivedData() && cyclingDistanceSpeed.getAggregatedValue(trackPointCreator.createNow()).speed() != null) { - return new Pair<>(cyclingDistanceSpeed.getAggregatedValue(trackPointCreator.createNow()).speed(), cyclingDistanceSpeed.getSensorNameOrAddress()); - } - - if (runningDistanceSpeedCadence != null && runningDistanceSpeedCadence.hasReceivedData() && runningDistanceSpeedCadence.getAggregatedValue(trackPointCreator.createNow()).speed() != null) { - return new Pair<>(runningDistanceSpeedCadence.aggregatedValue.speed(), runningDistanceSpeedCadence.getSensorNameOrAddress()); - } - - return null; - } - - public AggregatorCyclingPower getCyclingPower() { - return cyclingPower; - } - - public void add(@NonNull Aggregator data) { - set(data, data); - } - - public void update(@NonNull Raw data) { - Object value = data.value(); - - if (value instanceof HeartRate) { - this.heartRate.add((Raw) data); - return; - } - - if (value instanceof BluetoothHandlerCyclingCadence.CrankData) { - this.cyclingCadence.add((Raw) data); - return; - } - if (value instanceof BluetoothHandlerCyclingDistanceSpeed.WheelData ) { - this.cyclingDistanceSpeed.setWheelCircumference(PreferencesUtils.getWheelCircumference()); //TODO Fetch once and then listen for changes. - this.cyclingDistanceSpeed.add((Raw) data); - return; - } - if (value instanceof BluetoothHandlerRunningSpeedAndCadence.Data) { - this.runningDistanceSpeedCadence.add((Raw) data); - - return; - } - if (value instanceof BluetoothHandlerManagerCyclingPower.Data) { - this.cyclingPower.add((Raw) data); - return; - } - if (value instanceof AtmosphericPressure) { - this.barometer.add((Raw) data); - return; - } - if (value instanceof Position) { - this.gps.add((Raw) data); - return; - } - - throw new UnsupportedOperationException(data.getClass().getCanonicalName() + " " + data.value().getClass().getCanonicalName()); - } - - public void remove(@NonNull Aggregator type) { - set(type, null); - } - - public void clear() { - Log.i(TAG, "Removing all aggregators"); - this.heartRate = null; - this.cyclingCadence = null; - this.cyclingDistanceSpeed = null; - this.cyclingPower = null; - this.runningDistanceSpeedCadence = null; - this.barometer = null; - this.gps = null; - } - - public void fillTrackPoint(TrackPoint trackPoint) { - if (gps != null && gps.hasReceivedData()) { - trackPoint.setPosition(gps.getAggregatedValue(trackPointCreator.createNow())); - } - - Pair heartRate = getHeartRate(); - if (heartRate != null) { - trackPoint.setHeartRate(heartRate.first); - } - - if (getCadence() != null) { - trackPoint.setCadence(getCadence().first); - } - - if (getSpeed() != null) { - trackPoint.setSpeed(getSpeed().first); - } - - if (cyclingDistanceSpeed != null && cyclingDistanceSpeed.hasReceivedData()) { - trackPoint.setSensorDistance(cyclingDistanceSpeed.getAggregatedValue(trackPointCreator.createNow()).distanceOverall()); - } - - if (cyclingPower != null && cyclingPower.hasReceivedData()) { - trackPoint.setPower(cyclingPower.getAggregatedValue(trackPointCreator.createNow())); - } - - if (runningDistanceSpeedCadence != null && runningDistanceSpeedCadence.hasReceivedData()) { - trackPoint.setSensorDistance(runningDistanceSpeedCadence.getAggregatedValue(trackPointCreator.createNow()).distance()); - } - - if (barometer != null && barometer.hasReceivedData()) { - trackPoint.setAltitudeGainLoss(barometer.getAggregatedValue(trackPointCreator.createNow()).gain_m(), barometer.getAggregatedValue(trackPointCreator.createNow()).loss_m()); - } - } - - public void reset() { - Log.i(TAG, "Resetting data"); - - if (heartRate != null) heartRate.resetAggregated(); - if (cyclingCadence != null) cyclingCadence.resetAggregated(); - if (cyclingDistanceSpeed != null) cyclingDistanceSpeed.resetAggregated(); - if (cyclingPower != null) cyclingPower.resetAggregated(); - if (runningDistanceSpeedCadence != null) runningDistanceSpeedCadence.resetAggregated(); - if (barometer != null) barometer.resetAggregated(); - if (gps != null) gps.resetAggregated(); - } - - private void set(@NonNull Aggregator type, @Nullable Aggregator sensorData) { - Log.i(TAG, "Setting aggregator " + type.getClass().getCanonicalName() + " to " + sensorData); - - if (type instanceof AggregatorHeartRate) { - heartRate = (AggregatorHeartRate) sensorData; - return; - } - if (type instanceof AggregatorCyclingCadence) { - cyclingCadence = (AggregatorCyclingCadence) sensorData; - return; - } - if (type instanceof AggregatorCyclingDistanceSpeed) { - cyclingDistanceSpeed = (AggregatorCyclingDistanceSpeed) sensorData; - return; - } - if (type instanceof AggregatorCyclingPower) { - cyclingPower = (AggregatorCyclingPower) sensorData; - return; - } - if (type instanceof AggregatorRunning) { - runningDistanceSpeedCadence = (AggregatorRunning) sensorData; - return; - } - if (type instanceof AggregatorBarometer) { - barometer = (AggregatorBarometer) sensorData; - return; - } - if (type instanceof AggregatorGPS) { - gps = (AggregatorGPS) sensorData; - return; - } - - throw new UnsupportedOperationException(type.getClass().getCanonicalName()); - } +public record SensorDataSet( + @NonNull + SensorData position, + @Nullable + SensorData speed, + @Nullable + SensorData distance, + @Nullable + SensorData heartRate, + @Nullable + SensorData cadence, + @Nullable + SensorData power, + @Nullable + SensorData altitudeGainLoss +) { } diff --git a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingManager.java b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingManager.java index 53937d772..b5c1a6092 100644 --- a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingManager.java +++ b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingManager.java @@ -22,11 +22,11 @@ import de.dennisguse.opentracks.data.models.Statistics; import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.models.TrackBuilder; import de.dennisguse.opentracks.data.models.TrackPoint; +import de.dennisguse.opentracks.data.statistics.TrackStatisticsUpdater; import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet; import de.dennisguse.opentracks.services.handlers.AltitudeCorrectionManager; import de.dennisguse.opentracks.services.handlers.TrackPointCreator; import de.dennisguse.opentracks.settings.PreferencesUtils; -import de.dennisguse.opentracks.data.statistics.TrackStatisticsUpdater; import de.dennisguse.opentracks.util.TrackNameUtils; public class TrackRecordingManager implements SharedPreferences.OnSharedPreferenceChangeListener { @@ -160,14 +160,14 @@ public class TrackRecordingManager implements SharedPreferences.OnSharedPreferen * @return TrackPoint was stored? */ synchronized boolean onNewTrackPoint(@NonNull TrackPoint trackPoint) { - if (trackPoint.hasSpeed()) { + if (trackPoint.position().hasSpeed()) { lastTrackPointUIWithSpeed = trackPoint; } - if (trackPoint.hasAltitude()) { + if (trackPoint.position().hasAltitude()) { lastTrackPointUIWithAltitude = trackPoint; } - if (trackPoint.getType() == TrackPoint.Type.IDLE) { + if (trackPoint.type() == TrackPoint.Type.IDLE) { insertTrackPoint(trackPoint, true); handler.removeCallbacks(ON_IDLE); return true; @@ -180,14 +180,14 @@ public class TrackRecordingManager implements SharedPreferences.OnSharedPreferen return true; } - if (trackPoint.hasLocation() && lastStoredTrackPointWithLocation == null) { + if (trackPoint.position().hasLocation() && lastStoredTrackPointWithLocation == null) { insertTrackPoint(trackPoint, true); scheduleNewIdleTimeout(); return true; } - if (!trackPoint.hasLocation() && !trackPoint.hasSensorDistance()) { + if (!trackPoint.position().hasLocation() && trackPoint.sensorDistance() == null) { Duration minStorageInterval = Duration.ofSeconds(10); // TODO Should be configurable. boolean shouldStore = lastStoredTrackPoint.getTime().plus(minStorageInterval) .isBefore(trackPoint.getTime()); @@ -201,14 +201,14 @@ public class TrackRecordingManager implements SharedPreferences.OnSharedPreferen } Distance distanceToLastStoredTrackPoint; - if (trackPoint.hasLocation() && !lastStoredTrackPoint.hasLocation()) { + if (trackPoint.position().hasLocation() && !lastStoredTrackPoint.position().hasLocation()) { distanceToLastStoredTrackPoint = trackPoint.distanceToPreviousFromLocation(lastStoredTrackPointWithLocation); } else { distanceToLastStoredTrackPoint = trackPoint.distanceToPrevious(lastStoredTrackPoint); } if (distanceToLastStoredTrackPoint.greaterThan(maxRecordingDistance)) { - trackPoint.setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC); + trackPoint = trackPoint.with(TrackPoint.Type.SEGMENT_START_AUTOMATIC); insertTrackPoint(trackPoint, true); scheduleNewIdleTimeout(); @@ -248,8 +248,8 @@ public class TrackRecordingManager implements SharedPreferences.OnSharedPreferen Log.w(TAG, "Ignore insertTrackPoint. trackPoint time same as last valid trackId point time."); } else { insertTrackPointHelper(lastTrackPoint); - // Remove the sensorDistance from trackPoint that is already going be stored with lastTrackPoint. - trackPoint.minusCumulativeSensorData(lastTrackPoint); + // Remove the sensorDistance from trackPoint that is already going be stored with lastTrackPoint. + trackPoint = trackPoint.minusCumulativeSensorData(lastTrackPoint); } } lastTrackPoint = null; @@ -264,7 +264,7 @@ public class TrackRecordingManager implements SharedPreferences.OnSharedPreferen contentProviderUtils.updateTrackStatistics(trackId, trackStatisticsUpdater.getTrackStatistics()); lastStoredTrackPoint = trackPoint; - if (trackPoint.hasLocation()) { + if (trackPoint.position().hasLocation()) { lastStoredTrackPointWithLocation = lastStoredTrackPoint; } } catch (SQLiteException e) { diff --git a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java index bd40a0018..02663a824 100644 --- a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java +++ b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java @@ -255,7 +255,7 @@ public class TrackRecordingService extends Service implements TrackPointCreator. "", "", "", - trackPoint.getPosition(), + trackPoint.position(), null ); return new ContentProviderUtils(this).insertMarker(marker); diff --git a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceNotificationManager.java b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceNotificationManager.java index 0ed87d29f..196fc1cb1 100644 --- a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceNotificationManager.java +++ b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceNotificationManager.java @@ -109,17 +109,17 @@ class TrackRecordingServiceNotificationManager implements SharedPreferences.OnSh .build(context); //TODO The decision if a trackpoint is not accurate enough should happen in the TrackRecordingManager (via RecordingData). - if (recordingData.latestTrackPoint().hasHorizontalAccuracy()) { - formattedAccuracy = formatter.formatDistance(recordingData.latestTrackPoint().getHorizontalAccuracy()); + if (recordingData.latestTrackPoint().position().hasHorizontalAccuracy()) { + formattedAccuracy = formatter.formatDistance(recordingData.latestTrackPoint().position().horizontalAccuracy()); - boolean currentLocationWasAccurate = recordingData.latestTrackPoint().getHorizontalAccuracy().lessThan(thresholdHorizontalAccuracy); + boolean currentLocationWasAccurate = recordingData.latestTrackPoint().position().horizontalAccuracy().lessThan(thresholdHorizontalAccuracy); boolean shouldAlert = !currentLocationWasAccurate && previousLocationWasAccurate; notificationBuilder.setOnlyAlertOnce(!shouldAlert); previousLocationWasAccurate = currentLocationWasAccurate; } notificationBuilder.setContentTitle(context.getString(R.string.track_distance_notification, formatter.formatDistance(recordingData.trackStatistics().totalDistance()))); - String formattedSpeed = SpeedFormatter.Builder().setUnit(unitSystem).setReportSpeedOrPace(true).build(context).formatSpeed(recordingData.latestTrackPoint().getSpeed()); + String formattedSpeed = SpeedFormatter.Builder().setUnit(unitSystem).setReportSpeedOrPace(true).build(context).formatSpeed(recordingData.latestTrackPoint().position().speed()); notificationBuilder.setContentText(context.getString(R.string.track_speed_notification, formattedSpeed)); notificationBuilder.setSubText(context.getString(R.string.track_recording_notification_accuracy, formattedAccuracy)); updateNotification(); diff --git a/src/main/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtils.java b/src/main/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtils.java index c14514f86..bbce637e9 100644 --- a/src/main/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtils.java +++ b/src/main/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtils.java @@ -18,7 +18,6 @@ import android.text.Spannable; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.style.TtsSpan; -import android.util.Pair; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -35,9 +34,10 @@ import de.dennisguse.opentracks.data.models.HeartRate; import de.dennisguse.opentracks.data.models.Speed; import de.dennisguse.opentracks.data.models.Statistics; import de.dennisguse.opentracks.data.models.Track; +import de.dennisguse.opentracks.data.statistics.SensorStatistics; +import de.dennisguse.opentracks.sensors.sensorData.SensorData; import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet; import de.dennisguse.opentracks.settings.UnitSystem; -import de.dennisguse.opentracks.data.statistics.SensorStatistics; import de.dennisguse.opentracks.util.StringUtils; class VoiceAnnouncementUtils { @@ -160,9 +160,9 @@ class VoiceAnnouncementUtils { } } - Pair heartrate = sensorDataSet.getHeartRate(); - if (shouldVoiceAnnounceHeartRateCurrent() && heartrate != null && heartrate.first != null && heartrate.first.isValid()) { //TODO Check has an announcable value? - int averageHeartRate = Math.round(heartrate.first.getBPM()); + SensorData heartrate = sensorDataSet.heartRate(); + if (shouldVoiceAnnounceHeartRateCurrent() && heartrate != null && heartrate.data().isValid()) { //TODO Check has an announceable value? + int averageHeartRate = Math.round(heartrate.data().getBPM()); builder.append(" ") .append(context.getString(R.string.current_heart_rate)); diff --git a/src/main/java/de/dennisguse/opentracks/services/handlers/AltitudeCorrectionManager.java b/src/main/java/de/dennisguse/opentracks/services/handlers/AltitudeCorrectionManager.java index f8613b21c..811ce510e 100644 --- a/src/main/java/de/dennisguse/opentracks/services/handlers/AltitudeCorrectionManager.java +++ b/src/main/java/de/dennisguse/opentracks/services/handlers/AltitudeCorrectionManager.java @@ -19,22 +19,22 @@ public class AltitudeCorrectionManager { private static final String TAG = AltitudeCorrectionManager.class.getSimpleName(); - public void correctAltitude(Context context, TrackPoint trackPoint) { - if (!trackPoint.hasLocation() || !trackPoint.hasAltitude()) { - return; + public TrackPoint correctAltitude(Context context, TrackPoint trackPoint) { + if (!trackPoint.position().hasLocation() || !trackPoint.position().hasAltitude()) { + return trackPoint; } - // TODO The following is doing IO and should not be done in main thread. + final TrackPoint[] newTrackPoint = {null}; //TODO this is kind of ugly // AltitudeConverterCompat uses internally a RoomDatabase that cannot be access from main thread and thus fails on version <= 34. Thread t = new Thread(() -> { - try { - Location loc = trackPoint.getPosition().toLocation(); - AltitudeConverterCompat.addMslAltitudeToLocation(context, loc); - trackPoint.setAltitude(Altitude.EGM2008.of(LocationCompat.getMslAltitudeMeters(loc))); - } catch (IOException e) { - Log.w(TAG, "Android's AltitudeConverterCompat failed with " + e.getMessage()); - } - }); + try { + Location loc = trackPoint.position().toLocation(); + AltitudeConverterCompat.addMslAltitudeToLocation(context, loc); + newTrackPoint[0] = TrackPoint.with(trackPoint, Altitude.EGM2008.of(LocationCompat.getMslAltitudeMeters(loc))); + } catch (IOException e) { + Log.w(TAG, "Android's AltitudeConverterCompat failed with " + e.getMessage()); + } + }); t.start(); try { @@ -42,5 +42,7 @@ public class AltitudeCorrectionManager { } catch (InterruptedException e) { Log.w(TAG, "Android's AltitudeConverterCompat failed with " + e.getMessage()); } + + return newTrackPoint[0]; } } \ No newline at end of file diff --git a/src/main/java/de/dennisguse/opentracks/services/handlers/TrackPointCreator.java b/src/main/java/de/dennisguse/opentracks/services/handlers/TrackPointCreator.java index cce45bf80..827e263e0 100644 --- a/src/main/java/de/dennisguse/opentracks/services/handlers/TrackPointCreator.java +++ b/src/main/java/de/dennisguse/opentracks/services/handlers/TrackPointCreator.java @@ -3,7 +3,6 @@ package de.dennisguse.opentracks.services.handlers; import android.content.Context; import android.content.SharedPreferences; import android.os.Handler; -import android.util.Log; import android.util.Pair; import androidx.annotation.NonNull; @@ -15,6 +14,7 @@ import java.time.Instant; import java.time.ZoneId; 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.GpsStatusValue; import de.dennisguse.opentracks.sensors.SensorManager; @@ -55,15 +55,6 @@ public class TrackPointCreator implements SharedPreferences.OnSharedPreferenceCh sensorManager.reset(); } - private SensorDataSet addSensorData(TrackPoint trackPoint) { - if (!isStarted()) { - Log.w(TAG, "Not started, should not be called."); - return null; - } - - return sensorManager.fill(trackPoint); - } - public void stop() { sensorManager.stop(context); this.context = null; @@ -72,13 +63,8 @@ public class TrackPointCreator implements SharedPreferences.OnSharedPreferenceCh /** * Got a new TrackPoint from Bluetooth only; contains no GPS location. */ - public synchronized void onChange(@NonNull SensorDataSet unused) { - onNewTrackPoint(new TrackPoint(TrackPoint.Type.TRACKPOINT, createNow())); - } - - @VisibleForTesting - public void onNewTrackPoint(@NonNull TrackPoint trackPoint) { - addSensorData(trackPoint); + public synchronized void onChange() { + TrackPoint trackPoint = createTrackPoint(TrackPoint.Type.TRACKPOINT); boolean stored = service.newTrackPoint(trackPoint, PreferencesUtils.getThresholdHorizontalAccuracy()); //TODO Cache preference for performance if (stored) { @@ -91,40 +77,73 @@ public class TrackPointCreator implements SharedPreferences.OnSharedPreferenceCh } public synchronized TrackPoint createSegmentEnd() { - TrackPoint segmentEnd = TrackPoint.createSegmentEndWithTime(createNow()); - addSensorData(segmentEnd); + TrackPoint segmentEnd = createTrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL); reset(); return segmentEnd; } public synchronized TrackPoint createIdle() { - TrackPoint idle = new TrackPoint(TrackPoint.Type.IDLE, createNow()); - addSensorData(idle); + TrackPoint idle = createTrackPoint(TrackPoint.Type.IDLE); reset(); return idle; } public Pair createCurrentTrackPoint(@Nullable TrackPoint lastTrackPointUISpeed, @Nullable TrackPoint lastTrackPointUIAltitude, @Nullable TrackPoint lastStoredTrackPointWithLocation) { - TrackPoint currentTrackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT, createNow()); + Instant now = createNow(); + SensorDataSet sensorDataSet = sensorManager.getSensorDataSet(now); - SensorDataSet sensorDataSet = addSensorData(currentTrackPoint); + Position position = sensorDataSet.position().data(); - if (!currentTrackPoint.hasLocation() && lastStoredTrackPointWithLocation != null && lastStoredTrackPointWithLocation.hasLocation()) { + if (!position.hasLocation() + && lastStoredTrackPointWithLocation != null + && lastStoredTrackPointWithLocation.position().hasLocation()) { //We are taking the coordinates from the last stored TrackPoint, so the distance is monotonously increasing. - currentTrackPoint.setPosition(lastStoredTrackPointWithLocation.getPosition()); + position = position.withCoordinates(lastStoredTrackPointWithLocation.position()); } - if (lastTrackPointUISpeed != null) { - currentTrackPoint.setSpeed(lastTrackPointUISpeed.getSpeed()); - } + if (lastTrackPointUISpeed != null) + position.with(lastTrackPointUISpeed.position().speed()); - if (lastTrackPointUIAltitude != null) { - currentTrackPoint.setAltitude(lastTrackPointUIAltitude.getAltitude()); - } + if (lastTrackPointUIAltitude != null) + position.with(lastTrackPointUIAltitude.position().altitude()); + + TrackPoint currentTrackPoint = new TrackPoint( + null, + TrackPoint.Type.TRACKPOINT, + position, + sensorDataSet.distance() != null ? sensorDataSet.distance().data() : null, + sensorDataSet.heartRate() != null ? sensorDataSet.heartRate().data() : null, + sensorDataSet.cadence() != null ? sensorDataSet.cadence().data() : null, + sensorDataSet.power() != null ? sensorDataSet.power().data() : null, + sensorDataSet.altitudeGainLoss() != null ? sensorDataSet.altitudeGainLoss().data() : null + ); return new Pair<>(currentTrackPoint, sensorDataSet); } + private TrackPoint createTrackPoint(TrackPoint.Type type) { + Instant now = createNow(); + + SensorDataSet sensorDataSet = sensorManager.getSensorDataSet(now); + + Position position = sensorDataSet.position().data(); + if (sensorDataSet.speed() != null) { + position = position.with(sensorDataSet.speed().data()); + } + + return + new TrackPoint( + null, + type, + position, + sensorDataSet.distance() != null ? sensorDataSet.distance().data() : null, + sensorDataSet.heartRate() != null ? sensorDataSet.heartRate().data() : null, + sensorDataSet.cadence() != null ? sensorDataSet.cadence().data() : null, + sensorDataSet.power() != null ? sensorDataSet.power().data() : null, + sensorDataSet.altitudeGainLoss() != null ? sensorDataSet.altitudeGainLoss().data() : null + ); + } + public Instant createNow() { return Instant.now(clock); } diff --git a/src/main/java/de/dennisguse/opentracks/ui/intervals/IntervalStatisticsUpdater.java b/src/main/java/de/dennisguse/opentracks/ui/intervals/IntervalStatisticsUpdater.java index 6e4ea3619..1167833e7 100644 --- a/src/main/java/de/dennisguse/opentracks/ui/intervals/IntervalStatisticsUpdater.java +++ b/src/main/java/de/dennisguse/opentracks/ui/intervals/IntervalStatisticsUpdater.java @@ -76,7 +76,7 @@ public class IntervalStatisticsUpdater { } } - return trackPoint != null ? trackPoint.getId() : null; + return trackPoint != null ? trackPoint.id() : null; } public List getIntervalList() { @@ -152,9 +152,9 @@ public class IntervalStatisticsUpdater { if (lastTrackPoint == null) { return; } - if (gain_m != null && lastTrackPoint.hasAltitudeGainLoss()) { - gain_m = gain_m - lastTrackPoint.getAltitudeGainLoss().gain_m(); - loss_m = loss_m - lastTrackPoint.getAltitudeGainLoss().loss_m(); + if (gain_m != null && lastTrackPoint.altitudeGainLoss() != null) { + gain_m = gain_m - lastTrackPoint.altitudeGainLoss().gain_m(); + loss_m = loss_m - lastTrackPoint.altitudeGainLoss().loss_m(); } } diff --git a/src/main/java/de/dennisguse/opentracks/ui/markers/MarkerEditViewModel.java b/src/main/java/de/dennisguse/opentracks/ui/markers/MarkerEditViewModel.java index 0753c04fe..016d60f06 100644 --- a/src/main/java/de/dennisguse/opentracks/ui/markers/MarkerEditViewModel.java +++ b/src/main/java/de/dennisguse/opentracks/ui/markers/MarkerEditViewModel.java @@ -150,7 +150,7 @@ public class MarkerEditViewModel extends AndroidViewModel { name, "", "", - trackPoint.getPosition(), + trackPoint.position(), null); if (markerData == null) { diff --git a/src/main/java/de/dennisguse/opentracks/viewmodels/GenericStatisticsViewHolder.java b/src/main/java/de/dennisguse/opentracks/viewmodels/GenericStatisticsViewHolder.java index f0efe2d66..f3d96ffde 100644 --- a/src/main/java/de/dennisguse/opentracks/viewmodels/GenericStatisticsViewHolder.java +++ b/src/main/java/de/dennisguse/opentracks/viewmodels/GenericStatisticsViewHolder.java @@ -84,11 +84,11 @@ public abstract class GenericStatisticsViewHolder extends StatisticViewHolder valueAndUnit = StringUtils.getAltitudeParts(getContext(), altitude, unitSystem); getBinding().statsValue.setText(valueAndUnit.first); @@ -294,8 +294,8 @@ public abstract class GenericStatisticsViewHolder extends StatisticViewHolder valueAndUnit; - Pair heartRate; - if (sensorDataSet != null && (heartRate = sensorDataSet.getHeartRate()) != null) { - valueAndUnit = StringUtils.getHeartRateParts(getContext(), heartRate.first); - sensorName = heartRate.second; + if (sensorDataSet != null && sensorDataSet.heartRate() != null) { + valueAndUnit = StringUtils.getHeartRateParts(getContext(), sensorDataSet.heartRate().data()); + sensorName = sensorDataSet.heartRate().sensorNameOrAddress(); } else { valueAndUnit = StringUtils.getHeartRateParts(getContext(), null); } @@ -48,8 +44,8 @@ public abstract class SensorStatisticsViewHolder extends StatisticViewHolder valueAndUnit; - if (sensorDataSet != null && sensorDataSet.getCadence() != null) { - valueAndUnit = StringUtils.getCadenceParts(getContext(), sensorDataSet.getCadence().first); - sensorName = sensorDataSet.getCadence().second; + if (sensorDataSet != null && sensorDataSet.cadence() != null) { + valueAndUnit = StringUtils.getCadenceParts(getContext(), sensorDataSet.cadence().data()); + sensorName = sensorDataSet.cadence().sensorNameOrAddress(); } else { valueAndUnit = StringUtils.getCadenceParts(getContext(), null); } @@ -95,9 +91,9 @@ public abstract class SensorStatisticsViewHolder extends StatisticViewHolder valueAndUnit; - if (sensorDataSet != null && sensorDataSet.getCyclingPower() != null) { - valueAndUnit = StringUtils.getPowerParts(getContext(), sensorDataSet.getCyclingPower().getAggregatedValue(Instant.now())); //TODO Use MonotonicClock - sensorName = sensorDataSet.getCyclingPower().getSensorNameOrAddress(); + if (sensorDataSet != null && sensorDataSet.power() != null) { + valueAndUnit = StringUtils.getPowerParts(getContext(), sensorDataSet.power().data()); + sensorName = sensorDataSet.power().sensorNameOrAddress(); } else { valueAndUnit = StringUtils.getCadenceParts(getContext(), null); }