forked from upstream-mirrors/OpenTracks
Merge pull request #1033 from OpenTracksApp/indoor#500
Storing data from sensors without GPS
This commit is contained in:
@@ -78,7 +78,7 @@ _OpenTracks_ is a sport tracking application that completely respects your priva
|
|||||||
* __Photos and Markers:__ mark interesting locations while tracking
|
* __Photos and Markers:__ mark interesting locations while tracking
|
||||||
* __Export:__
|
* __Export:__
|
||||||
* export tracks either as KMZ (incl. photos), KML, or GPX
|
* export tracks either as KMZ (incl. photos), KML, or GPX
|
||||||
* export automatically after each recording (e.g., to sync)
|
* export automatically after each recording (e.g., to sync via [Nextcloud](https://nextcloud.com/))
|
||||||
* avoid duplication: each exported file contain a random unique identifier (i.e., `opentracks:trackid`)
|
* avoid duplication: each exported file contain a random unique identifier (i.e., `opentracks:trackid`)
|
||||||
* __Altitude:__
|
* __Altitude:__
|
||||||
* gain/loss via barometric sensor (if present)
|
* gain/loss via barometric sensor (if present)
|
||||||
@@ -89,6 +89,8 @@ _OpenTracks_ is a sport tracking application that completely respects your priva
|
|||||||
* cycling: cadence
|
* cycling: cadence
|
||||||
* cycling: power meter
|
* cycling: power meter
|
||||||
* running: speed and cadence
|
* running: speed and cadence
|
||||||
|
* support for BLE sensor training only (i.e., without GPS) for indoor training
|
||||||
|
|
||||||
An overview of tested sensors: [README_TESTED_SENSORS.md](README_TESTED_SENSORS.md)
|
An overview of tested sensors: [README_TESTED_SENSORS.md](README_TESTED_SENSORS.md)
|
||||||
|
|
||||||
### Gadgetbridge integration
|
### Gadgetbridge integration
|
||||||
|
|||||||
+9
-7
@@ -15,6 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
package de.dennisguse.opentracks.content.provider;
|
package de.dennisguse.opentracks.content.provider;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.ContentUris;
|
import android.content.ContentUris;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
@@ -57,13 +64,6 @@ import de.dennisguse.opentracks.stats.TrackStatistics;
|
|||||||
import de.dennisguse.opentracks.util.FileUtils;
|
import de.dennisguse.opentracks.util.FileUtils;
|
||||||
import de.dennisguse.opentracks.util.UUIDUtils;
|
import de.dennisguse.opentracks.util.UUIDUtils;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A unit test for {@link ContentProviderUtils}.
|
* A unit test for {@link ContentProviderUtils}.
|
||||||
*
|
*
|
||||||
@@ -220,6 +220,8 @@ public class CustomContentProviderUtilsTest {
|
|||||||
assertEquals(0, tracksPointsCursor.getCount());
|
assertEquals(0, tracksPointsCursor.getCount());
|
||||||
markerCursor = contentResolver.query(MarkerColumns.CONTENT_URI, null, null, null, MarkerColumns._ID);
|
markerCursor = contentResolver.query(MarkerColumns.CONTENT_URI, null, null, null, MarkerColumns._ID);
|
||||||
assertEquals(0, markerCursor.getCount());
|
assertEquals(0, markerCursor.getCount());
|
||||||
|
|
||||||
|
//TODO Close all cursors
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+86
-50
@@ -55,6 +55,7 @@ import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
|||||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||||
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
|
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
|
||||||
import de.dennisguse.opentracks.services.TrackRecordingService;
|
import de.dennisguse.opentracks.services.TrackRecordingService;
|
||||||
|
import de.dennisguse.opentracks.services.TrackRecordingServiceTest;
|
||||||
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
|
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
|
||||||
import de.dennisguse.opentracks.services.sensors.AltitudeSumManager;
|
import de.dennisguse.opentracks.services.sensors.AltitudeSumManager;
|
||||||
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
|
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
|
||||||
@@ -98,24 +99,29 @@ public class ExportImportTest {
|
|||||||
private TrackImporter trackImporter;
|
private TrackImporter trackImporter;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void fileSetup() throws IOException {
|
public void fileSetup() throws IOException, TimeoutException {
|
||||||
|
TrackRecordingServiceTest.resetService(mServiceRule, context);
|
||||||
|
|
||||||
tmpFile = File.createTempFile("test", "test", context.getFilesDir());
|
tmpFile = File.createTempFile("test", "test", context.getFilesDir());
|
||||||
tmpFileUri = Uri.fromFile(tmpFile);
|
tmpFileUri = Uri.fromFile(tmpFile);
|
||||||
|
|
||||||
trackImporter = new TrackImporter(context, contentProviderUtils, Distance.of(10), Distance.of(200), true);
|
trackImporter = new TrackImporter(context, contentProviderUtils, Distance.of(10), Distance.of(200), true);
|
||||||
|
|
||||||
|
TrackRecordingServiceTest.resetService(mServiceRule, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void FileTearDown() throws TimeoutException {
|
public void tearDown() throws TimeoutException {
|
||||||
tmpFile.deleteOnExit();
|
tmpFile.deleteOnExit();
|
||||||
tmpFileUri = null;
|
tmpFileUri = null;
|
||||||
|
|
||||||
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(new Intent(context, TrackRecordingService.class)))
|
// Ensure that the database is empty after every test
|
||||||
.getService();
|
contentProviderUtils.deleteAllTracks(context);
|
||||||
service.getTrackPointCreator().setClock(Clock.systemUTC());
|
|
||||||
|
TrackRecordingServiceTest.resetService(mServiceRule, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUp(boolean hasSensorDistance) throws TimeoutException {
|
public void setUp() throws TimeoutException {
|
||||||
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(new Intent(context, TrackRecordingService.class)))
|
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(new Intent(context, TrackRecordingService.class)))
|
||||||
.getService();
|
.getService();
|
||||||
|
|
||||||
@@ -123,13 +129,21 @@ public class ExportImportTest {
|
|||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:02Z"), ZoneId.of("CET")));
|
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:02Z"), ZoneId.of("CET")));
|
||||||
trackId = service.startNewTrack();
|
trackId = service.startNewTrack();
|
||||||
|
service.stopUpdateRecordingData();
|
||||||
|
|
||||||
Distance sensorDistance = hasSensorDistance ? Distance.of(10) : null; // recording distance interval
|
Distance sensorDistance = Distance.of(10); // recording distance interval
|
||||||
|
|
||||||
sendLocation(trackPointCreator, Instant.parse("2020-02-02T02:02:03Z"), 3, 14, 10, 15, 10, 1, 66, 3, 50, sensorDistance);
|
mockBLESensorData(trackPointCreator, 15f, sensorDistance, 66f, 3f, 50f);
|
||||||
|
sendLocation(trackPointCreator, Instant.parse("2020-02-02T02:02:03Z"), 3, 14, 10, 15, 10, 1);
|
||||||
service.insertMarker("Marker 1", "Marker 1 category", "Marker 1 desc", null);
|
service.insertMarker("Marker 1", "Marker 1 category", "Marker 1 desc", null);
|
||||||
sendLocation(trackPointCreator, Instant.parse("2020-02-02T02:02:04Z"), 3, 14.001, 10, 15, 10, 0, 66, 3, 50, sensorDistance);
|
|
||||||
sendLocation(trackPointCreator, Instant.parse("2020-02-02T02:02:05Z"), 3, 14.002, 10, 15, 10, 0, 66, 3, 50, sensorDistance);
|
// A sensor-only TrackPoint
|
||||||
|
mockBLESensorData(trackPointCreator, 15f, sensorDistance, 66f, 3f, 50f);
|
||||||
|
mockAltitudeChange(trackPointCreator, 1);
|
||||||
|
sendSensor(trackPointCreator, Instant.parse("2020-02-02T02:02:04Z"));
|
||||||
|
|
||||||
|
mockBLESensorData(trackPointCreator, 15f, sensorDistance, 66f, 3f, 50f);
|
||||||
|
sendLocation(trackPointCreator, Instant.parse("2020-02-02T02:02:05Z"), 3, 14.002, 10, 15, 10, 0);
|
||||||
service.insertMarker("Marker 2", "Marker 2 category", "Marker 2 desc", null);
|
service.insertMarker("Marker 2", "Marker 2 category", "Marker 2 desc", null);
|
||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:06Z"), ZoneId.of("CET")));
|
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:06Z"), ZoneId.of("CET")));
|
||||||
@@ -138,12 +152,17 @@ public class ExportImportTest {
|
|||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:20Z"), ZoneId.of("CET")));
|
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:20Z"), ZoneId.of("CET")));
|
||||||
service.resumeCurrentTrack();
|
service.resumeCurrentTrack();
|
||||||
|
service.stopUpdateRecordingData();
|
||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:21Z"), ZoneId.of("CET")));
|
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:21Z"), ZoneId.of("CET")));
|
||||||
sendLocation(trackPointCreator, Instant.parse("2020-02-02T02:02:21Z"), 3, 14.003, 10, 15, 10, 0, 66, 3, 50, sensorDistance);
|
mockBLESensorData(trackPointCreator, 15f, sensorDistance, 66f, 3f, 50f);
|
||||||
|
sendLocation(trackPointCreator, Instant.parse("2020-02-02T02:02:21Z"), 3, 14.003, 10, 15, 10, 0);
|
||||||
|
|
||||||
sendLocation(trackPointCreator, Instant.parse("2020-02-02T02:02:22Z"), 3, 16, 10, 15, 10, 0, 66, 3, 50, sensorDistance);
|
mockBLESensorData(trackPointCreator, 15f, sensorDistance, 66f, 3f, 50f);
|
||||||
sendLocation(trackPointCreator, Instant.parse("2020-02-02T02:02:23Z"), 3, 16.001, 10, 15, 10, 0, 66, 3, 50, sensorDistance);
|
sendLocation(trackPointCreator, Instant.parse("2020-02-02T02:02:22Z"), 3, 16, 10, 15, 10, 0);
|
||||||
|
|
||||||
|
mockBLESensorData(trackPointCreator, 15f, sensorDistance, 66f, 3f, 50f);
|
||||||
|
sendLocation(trackPointCreator, Instant.parse("2020-02-02T02:02:23Z"), 3, 16.001, 10, 15, 10, 0);
|
||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:24Z"), ZoneId.of("CET")));
|
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:24Z"), ZoneId.of("CET")));
|
||||||
trackPointCreator.setRemoteSensorManager(new BluetoothRemoteSensorManager(context));
|
trackPointCreator.setRemoteSensorManager(new BluetoothRemoteSensorManager(context));
|
||||||
@@ -162,21 +181,11 @@ public class ExportImportTest {
|
|||||||
assertEquals(2, markers.size());
|
assertEquals(2, markers.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDown() {
|
|
||||||
if (trackId != null) {
|
|
||||||
contentProviderUtils.deleteTrack(context, trackId);
|
|
||||||
}
|
|
||||||
if (importTrackId != null) {
|
|
||||||
contentProviderUtils.deleteTrack(context, importTrackId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO Does not test images
|
//TODO Does not test images
|
||||||
@LargeTest
|
@LargeTest
|
||||||
@Test
|
@Test
|
||||||
public void kmz_with_trackdetail_and_sensordata() throws TimeoutException, IOException {
|
public void kmz_with_trackdetail_and_sensordata() throws TimeoutException, IOException {
|
||||||
setUp(true);
|
setUp();
|
||||||
|
|
||||||
// given
|
// given
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
@@ -213,23 +222,40 @@ public class ExportImportTest {
|
|||||||
assertEquals(Instant.parse("2020-02-02T02:02:02Z"), importedTrackStatistics.getStartTime());
|
assertEquals(Instant.parse("2020-02-02T02:02:02Z"), importedTrackStatistics.getStartTime());
|
||||||
assertEquals(Instant.parse("2020-02-02T02:02:24Z"), importedTrackStatistics.getStopTime());
|
assertEquals(Instant.parse("2020-02-02T02:02:24Z"), importedTrackStatistics.getStopTime());
|
||||||
|
|
||||||
assertEquals(track.getTrackStatistics().getTotalTime(), importedTrackStatistics.getTotalTime());
|
TrackStatistics originalTrackStatistics = track.getTrackStatistics();
|
||||||
|
|
||||||
|
assertEquals(originalTrackStatistics.getTotalTime(), importedTrackStatistics.getTotalTime());
|
||||||
assertEquals(Duration.ofSeconds(8), importedTrackStatistics.getTotalTime());
|
assertEquals(Duration.ofSeconds(8), importedTrackStatistics.getTotalTime());
|
||||||
|
|
||||||
|
assertEquals(originalTrackStatistics.getMovingTime(), importedTrackStatistics.getMovingTime());
|
||||||
assertEquals(Duration.ofSeconds(4), importedTrackStatistics.getMovingTime());
|
assertEquals(Duration.ofSeconds(4), importedTrackStatistics.getMovingTime());
|
||||||
|
|
||||||
// Distance
|
// Distance
|
||||||
|
assertEquals(originalTrackStatistics.getTotalDistance(), importedTrackStatistics.getTotalDistance());
|
||||||
assertEquals(Distance.of(60), importedTrackStatistics.getTotalDistance());
|
assertEquals(Distance.of(60), importedTrackStatistics.getTotalDistance());
|
||||||
|
|
||||||
// Speed
|
// Speed
|
||||||
|
assertEquals(originalTrackStatistics.getMaxSpeed(), importedTrackStatistics.getMaxSpeed());
|
||||||
assertEquals(Speed.of(15), importedTrackStatistics.getMaxSpeed());
|
assertEquals(Speed.of(15), importedTrackStatistics.getMaxSpeed());
|
||||||
|
|
||||||
|
assertEquals(originalTrackStatistics.getAverageSpeed(), importedTrackStatistics.getAverageSpeed());
|
||||||
assertEquals(Speed.of(7.5), importedTrackStatistics.getAverageSpeed());
|
assertEquals(Speed.of(7.5), importedTrackStatistics.getAverageSpeed());
|
||||||
|
|
||||||
|
assertEquals(originalTrackStatistics.getAverageMovingSpeed(), importedTrackStatistics.getAverageMovingSpeed());
|
||||||
assertEquals(Speed.of(15), importedTrackStatistics.getAverageMovingSpeed());
|
assertEquals(Speed.of(15), importedTrackStatistics.getAverageMovingSpeed());
|
||||||
|
|
||||||
// Altitude
|
// Altitude
|
||||||
|
assertEquals(originalTrackStatistics.getMinAltitude(), importedTrackStatistics.getMinAltitude(), 0.01);
|
||||||
assertEquals(10, importedTrackStatistics.getMinAltitude(), 0.01);
|
assertEquals(10, importedTrackStatistics.getMinAltitude(), 0.01);
|
||||||
|
|
||||||
|
assertEquals(originalTrackStatistics.getMaxAltitude(), importedTrackStatistics.getMaxAltitude(), 0.01);
|
||||||
assertEquals(10, importedTrackStatistics.getMaxAltitude(), 0.01);
|
assertEquals(10, importedTrackStatistics.getMaxAltitude(), 0.01);
|
||||||
assertEquals(1, importedTrackStatistics.getTotalAltitudeGain(), 0.01);
|
|
||||||
assertEquals(1, importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
|
assertEquals(originalTrackStatistics.getTotalAltitudeGain(), importedTrackStatistics.getTotalAltitudeGain(), 0.01);
|
||||||
|
assertEquals(2, importedTrackStatistics.getTotalAltitudeGain(), 0.01);
|
||||||
|
|
||||||
|
assertEquals(originalTrackStatistics.getTotalAltitudeLoss(), importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
|
||||||
|
assertEquals(2, importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
|
||||||
|
|
||||||
// 4. markers
|
// 4. markers
|
||||||
assertMarkers();
|
assertMarkers();
|
||||||
@@ -238,7 +264,7 @@ public class ExportImportTest {
|
|||||||
@LargeTest
|
@LargeTest
|
||||||
@Test(expected = ImportAlreadyExistsException.class)
|
@Test(expected = ImportAlreadyExistsException.class)
|
||||||
public void kml_with_trackdetail_and_sensordata_duplicate_trackUUID() throws TimeoutException, IOException {
|
public void kml_with_trackdetail_and_sensordata_duplicate_trackUUID() throws TimeoutException, IOException {
|
||||||
setUp(false);
|
setUp();
|
||||||
|
|
||||||
// given
|
// given
|
||||||
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
|
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
|
||||||
@@ -264,7 +290,7 @@ public class ExportImportTest {
|
|||||||
@LargeTest
|
@LargeTest
|
||||||
@Test
|
@Test
|
||||||
public void gpx() throws TimeoutException, IOException {
|
public void gpx() throws TimeoutException, IOException {
|
||||||
setUp(true);
|
setUp();
|
||||||
|
|
||||||
// given
|
// given
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
@@ -297,7 +323,10 @@ public class ExportImportTest {
|
|||||||
// Therefore, the track segmentation is changes.
|
// Therefore, the track segmentation is changes.
|
||||||
List<TrackPoint> trackPointsWithCoordinates = trackPoints.stream().filter(it -> TrackPoint.Type.SEGMENT_START_AUTOMATIC.equals(it.getType()) || TrackPoint.Type.TRACKPOINT.equals(it.getType())).collect(Collectors.toList());
|
List<TrackPoint> trackPointsWithCoordinates = trackPoints.stream().filter(it -> TrackPoint.Type.SEGMENT_START_AUTOMATIC.equals(it.getType()) || TrackPoint.Type.TRACKPOINT.equals(it.getType())).collect(Collectors.toList());
|
||||||
trackPointsWithCoordinates.get(0).setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC);
|
trackPointsWithCoordinates.get(0).setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC);
|
||||||
trackPointsWithCoordinates.get(3).setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC);
|
trackPointsWithCoordinates.get(1).setSensorDistance(Distance.of(20));
|
||||||
|
trackPointsWithCoordinates.get(1).setAltitudeGain(1f);
|
||||||
|
trackPointsWithCoordinates.get(1).setAltitudeLoss(1f);
|
||||||
|
trackPointsWithCoordinates.get(2).setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC);
|
||||||
|
|
||||||
TrackPointAssert a = new TrackPointAssert()
|
TrackPointAssert a = new TrackPointAssert()
|
||||||
.setDelta(0.05)
|
.setDelta(0.05)
|
||||||
@@ -326,8 +355,8 @@ public class ExportImportTest {
|
|||||||
// Altitude
|
// Altitude
|
||||||
assertEquals(10, importedTrackStatistics.getMinAltitude(), 0.01);
|
assertEquals(10, importedTrackStatistics.getMinAltitude(), 0.01);
|
||||||
assertEquals(10, importedTrackStatistics.getMaxAltitude(), 0.01);
|
assertEquals(10, importedTrackStatistics.getMaxAltitude(), 0.01);
|
||||||
assertEquals(1, importedTrackStatistics.getTotalAltitudeGain(), 0.01);
|
assertEquals(2, importedTrackStatistics.getTotalAltitudeGain(), 0.01);
|
||||||
assertEquals(1, importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
|
assertEquals(2, importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
|
||||||
|
|
||||||
// 4. markers
|
// 4. markers
|
||||||
assertMarkers();
|
assertMarkers();
|
||||||
@@ -336,7 +365,7 @@ public class ExportImportTest {
|
|||||||
@LargeTest
|
@LargeTest
|
||||||
@Test(expected = ImportAlreadyExistsException.class)
|
@Test(expected = ImportAlreadyExistsException.class)
|
||||||
public void gpx_duplicate_trackUUID() throws TimeoutException, IOException {
|
public void gpx_duplicate_trackUUID() throws TimeoutException, IOException {
|
||||||
setUp(false);
|
setUp();
|
||||||
|
|
||||||
// given
|
// given
|
||||||
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
|
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
|
||||||
@@ -380,22 +409,7 @@ public class ExportImportTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendLocation(TrackPointCreator trackPointCreator, Instant time, double latitude, double longitude, float accuracy, float speed, float altitude, float altitudeGain, float heartRate, float cyclingCadence, float power, Distance distance) {
|
private void mockBLESensorData(TrackPointCreator trackPointCreator, Float speed, Distance distance, Float heartRate, Float cyclingCadence, Float power) {
|
||||||
Location location = new Location("mock");
|
|
||||||
location.setLatitude(latitude);
|
|
||||||
location.setLongitude(longitude);
|
|
||||||
location.setAccuracy(accuracy);
|
|
||||||
location.setSpeed(speed);
|
|
||||||
location.setAltitude(altitude);
|
|
||||||
|
|
||||||
trackPointCreator.setAltitudeSumManager(new AltitudeSumManager() {
|
|
||||||
@Override
|
|
||||||
public void fill(@NonNull TrackPoint trackPoint) {
|
|
||||||
trackPoint.setAltitudeGain(altitudeGain);
|
|
||||||
trackPoint.setAltitudeLoss(altitudeGain);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
trackPointCreator.setRemoteSensorManager(new BluetoothRemoteSensorManager(context) {
|
trackPointCreator.setRemoteSensorManager(new BluetoothRemoteSensorManager(context) {
|
||||||
@Override
|
@Override
|
||||||
public SensorDataSet fill(@NonNull TrackPoint trackPoint) {
|
public SensorDataSet fill(@NonNull TrackPoint trackPoint) {
|
||||||
@@ -421,8 +435,30 @@ public class ExportImportTest {
|
|||||||
return sensorDataSet;
|
return sensorDataSet;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mockAltitudeChange(TrackPointCreator trackPointCreator, float altitudeGain) {
|
||||||
|
AltitudeSumManager altitudeSumManager = trackPointCreator.getAltitudeSumManager();
|
||||||
|
altitudeSumManager.setAltitudeGain_m(altitudeGain);
|
||||||
|
altitudeSumManager.setAltitudeLoss_m(altitudeGain);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendSensor(TrackPointCreator trackPointCreator, Instant time) {
|
||||||
|
trackPointCreator.setClock(Clock.fixed(time, ZoneId.of("CET")));
|
||||||
|
trackPointCreator.onNewTrackPointWithoutGPS();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendLocation(TrackPointCreator trackPointCreator, Instant time, double latitude, double longitude, float accuracy, float speed, float altitude, float altitudeGain) {
|
||||||
|
Location location = new Location("mock");
|
||||||
|
location.setLatitude(latitude);
|
||||||
|
location.setLongitude(longitude);
|
||||||
|
location.setAccuracy(accuracy);
|
||||||
|
location.setSpeed(speed);
|
||||||
|
location.setAltitude(altitude);
|
||||||
|
|
||||||
|
mockAltitudeChange(trackPointCreator, altitudeGain);
|
||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(time, ZoneId.of("CET")));
|
trackPointCreator.setClock(Clock.fixed(time, ZoneId.of("CET")));
|
||||||
trackPointCreator.getLocationHandler().onLocationChanged(location);
|
trackPointCreator.getGpsHandler().onLocationChanged(location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+28
-20
@@ -22,7 +22,6 @@ import static org.junit.Assert.assertNotNull;
|
|||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import android.content.ContentProvider;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
@@ -60,7 +59,6 @@ import de.dennisguse.opentracks.content.data.TestDataUtil;
|
|||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.content.provider.CustomContentProvider;
|
|
||||||
import de.dennisguse.opentracks.io.file.importer.TrackPointAssert;
|
import de.dennisguse.opentracks.io.file.importer.TrackPointAssert;
|
||||||
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
|
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
|
||||||
import de.dennisguse.opentracks.services.sensors.AltitudeSumManager;
|
import de.dennisguse.opentracks.services.sensors.AltitudeSumManager;
|
||||||
@@ -110,30 +108,15 @@ public class TrackRecordingServiceTest {
|
|||||||
};
|
};
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() throws TimeoutException {
|
||||||
// Set up the mock content resolver
|
|
||||||
ContentProvider customContentProvider = new CustomContentProvider() {
|
|
||||||
};
|
|
||||||
customContentProvider.attachInfo(context, null);
|
|
||||||
|
|
||||||
contentProviderUtils = new ContentProviderUtils(context);
|
contentProviderUtils = new ContentProviderUtils(context);
|
||||||
|
|
||||||
// Let's use default values.
|
tearDown();
|
||||||
PreferencesUtils.clear();
|
|
||||||
|
|
||||||
// Ensure that the database is empty before every test
|
|
||||||
contentProviderUtils.deleteAllTracks(context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws TimeoutException {
|
public void tearDown() throws TimeoutException {
|
||||||
// Reset service (if some previous test failed)
|
TrackRecordingServiceTest.resetService(mServiceRule, context);
|
||||||
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context)))
|
|
||||||
.getService();
|
|
||||||
if (service.isRecording() || service.isPaused()) {
|
|
||||||
service.endCurrentTrack();
|
|
||||||
}
|
|
||||||
service.getTrackPointCreator().setClock(Clock.systemUTC());
|
|
||||||
|
|
||||||
// Ensure that the database is empty after every test
|
// Ensure that the database is empty after every test
|
||||||
contentProviderUtils.deleteAllTracks(context);
|
contentProviderUtils.deleteAllTracks(context);
|
||||||
@@ -211,6 +194,7 @@ public class TrackRecordingServiceTest {
|
|||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:02Z"), ZoneId.of("CET")));
|
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:02Z"), ZoneId.of("CET")));
|
||||||
Track.Id trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
service.stopUpdateRecordingData();
|
||||||
trackPointCreator.stopGPS();
|
trackPointCreator.stopGPS();
|
||||||
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
||||||
|
|
||||||
@@ -241,12 +225,14 @@ public class TrackRecordingServiceTest {
|
|||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:02Z"), ZoneId.of("CET")));
|
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:02Z"), ZoneId.of("CET")));
|
||||||
Track.Id trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
service.stopUpdateRecordingData();
|
||||||
trackPointCreator.stopGPS();
|
trackPointCreator.stopGPS();
|
||||||
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:03Z"), ZoneId.of("CET")));
|
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:03Z"), ZoneId.of("CET")));
|
||||||
service.pauseCurrentTrack();
|
service.pauseCurrentTrack();
|
||||||
|
service.stopUpdateRecordingData();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(2, contentProviderUtils.getTrackPointCursor(trackId, null).getCount());
|
assertEquals(2, contentProviderUtils.getTrackPointCursor(trackId, null).getCount());
|
||||||
@@ -254,6 +240,7 @@ public class TrackRecordingServiceTest {
|
|||||||
//when
|
//when
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:04Z"), ZoneId.of("CET")));
|
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:04Z"), ZoneId.of("CET")));
|
||||||
service.resumeTrack(trackId);
|
service.resumeTrack(trackId);
|
||||||
|
service.stopUpdateRecordingData();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertTrue(service.isRecording());
|
assertTrue(service.isRecording());
|
||||||
@@ -280,6 +267,7 @@ public class TrackRecordingServiceTest {
|
|||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:02Z"), ZoneId.of("CET")));
|
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:02Z"), ZoneId.of("CET")));
|
||||||
Track.Id trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
service.stopUpdateRecordingData();
|
||||||
trackPointCreator.stopGPS();
|
trackPointCreator.stopGPS();
|
||||||
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
||||||
|
|
||||||
@@ -322,6 +310,7 @@ public class TrackRecordingServiceTest {
|
|||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:02Z"), ZoneId.of("CET")));
|
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:02Z"), ZoneId.of("CET")));
|
||||||
Track.Id trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
service.stopUpdateRecordingData();
|
||||||
trackPointCreator.stopGPS();
|
trackPointCreator.stopGPS();
|
||||||
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
||||||
|
|
||||||
@@ -352,10 +341,13 @@ public class TrackRecordingServiceTest {
|
|||||||
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context)))
|
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context)))
|
||||||
.getService();
|
.getService();
|
||||||
Track.Id trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
service.stopUpdateRecordingData();
|
||||||
|
|
||||||
assertTrue(service.isRecording());
|
assertTrue(service.isRecording());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
Track.Id newTrackId = service.startNewTrack();
|
Track.Id newTrackId = service.startNewTrack();
|
||||||
|
service.stopUpdateRecordingData();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertNotNull(trackId);
|
assertNotNull(trackId);
|
||||||
@@ -405,6 +397,7 @@ public class TrackRecordingServiceTest {
|
|||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:02Z"), ZoneId.of("CET")));
|
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:02Z"), ZoneId.of("CET")));
|
||||||
Track.Id trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
service.stopUpdateRecordingData();
|
||||||
|
|
||||||
assertTrue(service.isRecording());
|
assertTrue(service.isRecording());
|
||||||
trackPointCreator.onNewTrackPoint(
|
trackPointCreator.onNewTrackPoint(
|
||||||
@@ -461,4 +454,19 @@ public class TrackRecordingServiceTest {
|
|||||||
|
|
||||||
trackRecordingService.getTrackPointCreator().onNewTrackPoint(trackPoint, Distance.of(50));
|
trackRecordingService.getTrackPointCreator().onNewTrackPoint(trackPoint, Distance.of(50));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO Workaround as service is not stopped on API23; thus sharedpreferences are not reset between tests.
|
||||||
|
//TODO Anyhow, the service should re-create all it's resources if a recording starts and makes sure that there is no leftovers from previous recordings.
|
||||||
|
@Deprecated
|
||||||
|
public static void resetService(ServiceTestRule mServiceRule, Context context) throws TimeoutException {
|
||||||
|
// Let's use default values.
|
||||||
|
PreferencesUtils.clear();
|
||||||
|
|
||||||
|
// Reset service (if some previous test failed)
|
||||||
|
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(new Intent(context, TrackRecordingService.class)))
|
||||||
|
.getService();
|
||||||
|
service.endCurrentTrack();
|
||||||
|
service.getTrackPointCreator().setClock(Clock.systemUTC());
|
||||||
|
service.sharedPreferenceChangeListener.onSharedPreferenceChanged(null, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-12
@@ -2,7 +2,6 @@ package de.dennisguse.opentracks.services;
|
|||||||
|
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
|
||||||
import android.content.ContentProvider;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
|
||||||
@@ -31,14 +30,12 @@ import de.dennisguse.opentracks.content.data.TestDataUtil;
|
|||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.content.provider.CustomContentProvider;
|
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorDataHeartRate;
|
import de.dennisguse.opentracks.content.sensor.SensorDataHeartRate;
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorDataRunning;
|
import de.dennisguse.opentracks.content.sensor.SensorDataRunning;
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
||||||
import de.dennisguse.opentracks.io.file.importer.TrackPointAssert;
|
import de.dennisguse.opentracks.io.file.importer.TrackPointAssert;
|
||||||
import de.dennisguse.opentracks.services.sensors.AltitudeSumManager;
|
import de.dennisguse.opentracks.services.sensors.AltitudeSumManager;
|
||||||
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
|
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
|
||||||
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests insert location.
|
* Tests insert location.
|
||||||
@@ -79,24 +76,17 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws TimeoutException {
|
public void setUp() throws TimeoutException {
|
||||||
// Set up the mock content resolver
|
|
||||||
ContentProvider customContentProvider = new CustomContentProvider() {
|
|
||||||
};
|
|
||||||
customContentProvider.attachInfo(context, null);
|
|
||||||
|
|
||||||
contentProviderUtils = new ContentProviderUtils(context);
|
contentProviderUtils = new ContentProviderUtils(context);
|
||||||
tearDown();
|
tearDown();
|
||||||
|
|
||||||
// Let's use default values.
|
|
||||||
PreferencesUtils.clear();
|
|
||||||
|
|
||||||
service = ((TrackRecordingService.Binder) mServiceRule.bindService(TrackRecordingServiceTest.createStartIntent(context)))
|
service = ((TrackRecordingService.Binder) mServiceRule.bindService(TrackRecordingServiceTest.createStartIntent(context)))
|
||||||
.getService();
|
.getService();
|
||||||
service.getTrackPointCreator().stopGPS();
|
service.getTrackPointCreator().stopGPS();
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() {
|
public void tearDown() throws TimeoutException {
|
||||||
|
TrackRecordingServiceTest.resetService(mServiceRule, context);
|
||||||
// Ensure that the database is empty after every test
|
// Ensure that the database is empty after every test
|
||||||
contentProviderUtils.deleteAllTracks(context);
|
contentProviderUtils.deleteAllTracks(context);
|
||||||
}
|
}
|
||||||
@@ -106,6 +96,7 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
public void testOnLocationChangedAsync_movingAccurate() {
|
public void testOnLocationChangedAsync_movingAccurate() {
|
||||||
// given
|
// given
|
||||||
Track.Id trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
service.stopUpdateRecordingData();
|
||||||
service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager);
|
service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -179,6 +170,7 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
public void testOnLocationChangedAsync_slowMovingAccurate() {
|
public void testOnLocationChangedAsync_slowMovingAccurate() {
|
||||||
// given
|
// given
|
||||||
Track.Id trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
service.stopUpdateRecordingData();
|
||||||
service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager);
|
service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -224,6 +216,7 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
public void testOnLocationChangedAsync_idle() {
|
public void testOnLocationChangedAsync_idle() {
|
||||||
// given
|
// given
|
||||||
Track.Id trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
service.stopUpdateRecordingData();
|
||||||
service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager);
|
service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -269,6 +262,7 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
public void testOnLocationChangedAsync_idle_withMovement() {
|
public void testOnLocationChangedAsync_idle_withMovement() {
|
||||||
// given
|
// given
|
||||||
Track.Id trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
service.stopUpdateRecordingData();
|
||||||
service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager);
|
service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager);
|
||||||
service.getTrackPointCreator().stopGPS();
|
service.getTrackPointCreator().stopGPS();
|
||||||
|
|
||||||
@@ -329,6 +323,7 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
public void testOnLocationChangedAsync_idle_withSensorData() {
|
public void testOnLocationChangedAsync_idle_withSensorData() {
|
||||||
// given
|
// given
|
||||||
Track.Id trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
service.stopUpdateRecordingData();
|
||||||
service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager);
|
service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager);
|
||||||
service.getTrackPointCreator().setRemoteSensorManager(new BluetoothRemoteSensorManager(context) {
|
service.getTrackPointCreator().setRemoteSensorManager(new BluetoothRemoteSensorManager(context) {
|
||||||
|
|
||||||
@@ -403,6 +398,7 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
|
|
||||||
// given
|
// given
|
||||||
Track.Id trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
service.stopUpdateRecordingData();
|
||||||
service.getTrackPointCreator().setRemoteSensorManager(remoteSensorManager);
|
service.getTrackPointCreator().setRemoteSensorManager(remoteSensorManager);
|
||||||
service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager);
|
service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager);
|
||||||
altitudeSumManager.stop(service);
|
altitudeSumManager.stop(service);
|
||||||
@@ -474,6 +470,7 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
public void testOnLocationChangedAsync_segment() {
|
public void testOnLocationChangedAsync_segment() {
|
||||||
// given
|
// given
|
||||||
Track.Id trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
service.stopUpdateRecordingData();
|
||||||
service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager);
|
service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
|
|||||||
+11
-25
@@ -1,6 +1,10 @@
|
|||||||
package de.dennisguse.opentracks.services;
|
package de.dennisguse.opentracks.services;
|
||||||
|
|
||||||
import android.content.ContentProvider;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
@@ -30,20 +34,15 @@ import de.dennisguse.opentracks.content.data.Speed;
|
|||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.content.provider.CustomContentProvider;
|
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
|
||||||
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||||
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for the track recording service, which require a {@link Looper}.
|
* Tests for the track recording service, which require a {@link Looper}.
|
||||||
*
|
*
|
||||||
* @author Bartlomiej Niechwiej
|
* @author Bartlomiej Niechwiej
|
||||||
*/
|
*/
|
||||||
|
//TODO Check that those tests are really testing something!
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class TrackRecordingServiceTestLooper {
|
public class TrackRecordingServiceTestLooper {
|
||||||
|
|
||||||
@@ -66,29 +65,15 @@ public class TrackRecordingServiceTestLooper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() throws TimeoutException {
|
||||||
// Set up the mock content resolver
|
|
||||||
ContentProvider customContentProvider = new CustomContentProvider() {
|
|
||||||
};
|
|
||||||
customContentProvider.attachInfo(context, null);
|
|
||||||
|
|
||||||
contentProviderUtils = new ContentProviderUtils(context);
|
contentProviderUtils = new ContentProviderUtils(context);
|
||||||
|
|
||||||
// Let's use default values.
|
tearDown();
|
||||||
PreferencesUtils.clear();
|
|
||||||
|
|
||||||
// Ensure that the database is empty before every test
|
|
||||||
contentProviderUtils.deleteAllTracks(context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws TimeoutException {
|
public void tearDown() throws TimeoutException {
|
||||||
// Reset service (if some previous test failed)
|
TrackRecordingServiceTest.resetService(mServiceRule, context);
|
||||||
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(TrackRecordingServiceTest.createStartIntent(context)))
|
|
||||||
.getService();
|
|
||||||
if (service.isRecording() || service.isPaused()) {
|
|
||||||
service.endCurrentTrack();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure that the database is empty after every test
|
// Ensure that the database is empty after every test
|
||||||
contentProviderUtils.deleteAllTracks(context);
|
contentProviderUtils.deleteAllTracks(context);
|
||||||
@@ -195,6 +180,7 @@ public class TrackRecordingServiceTestLooper {
|
|||||||
|
|
||||||
// Start a track.
|
// Start a track.
|
||||||
Track.Id trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
service.stopUpdateRecordingData();
|
||||||
assertNotNull(trackId);
|
assertNotNull(trackId);
|
||||||
assertTrue(service.isRecording());
|
assertTrue(service.isRecording());
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
|
|||||||
+9
-27
@@ -3,10 +3,7 @@ package de.dennisguse.opentracks.services;
|
|||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
|
||||||
import android.content.ContentProvider;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
@@ -18,7 +15,6 @@ import androidx.test.rule.ServiceTestRule;
|
|||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Assume;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
@@ -38,9 +34,7 @@ import de.dennisguse.opentracks.content.data.TestDataUtil;
|
|||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.content.provider.CustomContentProvider;
|
|
||||||
import de.dennisguse.opentracks.services.sensors.AltitudeSumManager;
|
import de.dennisguse.opentracks.services.sensors.AltitudeSumManager;
|
||||||
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -81,27 +75,15 @@ public class TrackRecordingServiceTestStatistics {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws TimeoutException {
|
public void setUp() throws TimeoutException {
|
||||||
// Set up the mock content resolver
|
|
||||||
ContentProvider customContentProvider = new CustomContentProvider() {
|
|
||||||
};
|
|
||||||
customContentProvider.attachInfo(context, null);
|
|
||||||
|
|
||||||
contentProviderUtils = new ContentProviderUtils(context);
|
contentProviderUtils = new ContentProviderUtils(context);
|
||||||
|
|
||||||
tearDown();
|
tearDown();
|
||||||
|
|
||||||
// Let's use default values.
|
|
||||||
PreferencesUtils.clear();
|
|
||||||
|
|
||||||
service = ((TrackRecordingService.Binder) mServiceRule.bindService(TrackRecordingServiceTest.createStartIntent(context)))
|
|
||||||
.getService();
|
|
||||||
service.getTrackPointCreator().stopGPS();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws TimeoutException {
|
public void tearDown() throws TimeoutException {
|
||||||
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(new Intent(context, TrackRecordingService.class)))
|
TrackRecordingServiceTest.resetService(mServiceRule, context);
|
||||||
.getService();
|
contentProviderUtils.deleteAllTracks(context);
|
||||||
service.getTrackPointCreator().setClock(Clock.systemUTC());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -109,15 +91,15 @@ public class TrackRecordingServiceTestStatistics {
|
|||||||
*/
|
*/
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@Test
|
@Test
|
||||||
public void movingtime_with_pauses() {
|
public void movingtime_with_pauses() throws TimeoutException {
|
||||||
Assume.assumeTrue(
|
|
||||||
"Test fails on API23; reproducible on CI and some machines.",
|
|
||||||
Build.VERSION.SDK_INT > 23
|
|
||||||
);
|
|
||||||
|
|
||||||
// given
|
// given
|
||||||
|
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(TrackRecordingServiceTest.createStartIntent(context)))
|
||||||
|
.getService();
|
||||||
|
service.getTrackPointCreator().stopGPS();
|
||||||
|
|
||||||
service.getTrackPointCreator().setClock(Clock.fixed(Instant.ofEpochMilli(0), ZoneId.systemDefault()));
|
service.getTrackPointCreator().setClock(Clock.fixed(Instant.ofEpochMilli(0), ZoneId.systemDefault()));
|
||||||
Track.Id trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
service.stopUpdateRecordingData();
|
||||||
service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager);
|
service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager);
|
||||||
|
|
||||||
Function<Integer, Void> assertMovingTime = expected -> {
|
Function<Integer, Void> assertMovingTime = expected -> {
|
||||||
|
|||||||
+2
-2
@@ -26,7 +26,7 @@ import de.dennisguse.opentracks.content.data.TrackPoint;
|
|||||||
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class LocationHandlerTest {
|
public class GPSHandlerTest {
|
||||||
|
|
||||||
private final Context context = ApplicationProvider.getApplicationContext();
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ public class LocationHandlerTest {
|
|||||||
private TrackPointCreator trackPointCreator;
|
private TrackPointCreator trackPointCreator;
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private LocationHandler locationHandler;
|
private GPSHandler locationHandler;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void preSetUp() {
|
public static void preSetUp() {
|
||||||
+1
-5
@@ -3,7 +3,6 @@ package de.dennisguse.opentracks.services.handlers;
|
|||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -26,10 +25,7 @@ public class TrackPointCreatorTest {
|
|||||||
private TrackPointCreator.Callback server;
|
private TrackPointCreator.Callback server;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private LocationHandler locationHandler;
|
private GPSHandler locationHandler;
|
||||||
|
|
||||||
@Mock
|
|
||||||
private SharedPreferences sharedPreferences;
|
|
||||||
|
|
||||||
private TrackPointCreator subject;
|
private TrackPointCreator subject;
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,8 @@ public class TrackPoint {
|
|||||||
SEGMENT_START_MANUAL(-2), //Start of a segment due to user interaction (start, resume)
|
SEGMENT_START_MANUAL(-2), //Start of a segment due to user interaction (start, resume)
|
||||||
|
|
||||||
SEGMENT_START_AUTOMATIC(-1), //Start of a segment due to too much distance from previous TrackPoint
|
SEGMENT_START_AUTOMATIC(-1), //Start of a segment due to too much distance from previous TrackPoint
|
||||||
TRACKPOINT(0), //Just GPS data.
|
TRACKPOINT(0), //Just GPS data and may contain BLE sensor data
|
||||||
|
SENSORPOINT(2), //Just BLE sensor data
|
||||||
|
|
||||||
SEGMENT_END_MANUAL(1); //End of a segment
|
SEGMENT_END_MANUAL(1); //End of a segment
|
||||||
|
|
||||||
@@ -310,7 +311,7 @@ public class TrackPoint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public Distance distanceToPrevious(TrackPoint previous) {
|
public Distance distanceToPrevious(@Nullable TrackPoint previous) {
|
||||||
if (hasSensorDistance()) {
|
if (hasSensorDistance()) {
|
||||||
return getSensorDistance();
|
return getSensorDistance();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ public interface TrackPointsColumns extends BaseColumns {
|
|||||||
+ SENSOR_POWER + " FLOAT, "
|
+ SENSOR_POWER + " FLOAT, "
|
||||||
+ ALTITUDE_GAIN + " FLOAT, "
|
+ ALTITUDE_GAIN + " FLOAT, "
|
||||||
+ ALTITUDE_LOSS + " FLOAT, "
|
+ ALTITUDE_LOSS + " FLOAT, "
|
||||||
+ TYPE + " TEXT CHECK(type IN (-2, -1, 0, 1)), "
|
+ TYPE + " TEXT CHECK(type IN (-2, -1, 0, 1, 2)), "
|
||||||
+ SENSOR_DISTANCE + " FLOAT, "
|
+ SENSOR_DISTANCE + " FLOAT, "
|
||||||
+ "FOREIGN KEY (" + TRACKID + ") REFERENCES " + TracksColumns.TABLE_NAME + "(" + TracksColumns._ID + ") ON UPDATE CASCADE ON DELETE CASCADE"
|
+ "FOREIGN KEY (" + TRACKID + ") REFERENCES " + TracksColumns.TABLE_NAME + "(" + TracksColumns._ID + ") ON UPDATE CASCADE ON DELETE CASCADE"
|
||||||
+ ")";
|
+ ")";
|
||||||
|
|||||||
+38
-1
@@ -26,7 +26,7 @@ public class CustomSQLiteOpenHelper extends SQLiteOpenHelper {
|
|||||||
|
|
||||||
private static final String TAG = CustomSQLiteOpenHelper.class.getSimpleName();
|
private static final String TAG = CustomSQLiteOpenHelper.class.getSimpleName();
|
||||||
|
|
||||||
private static final int DATABASE_VERSION = 31;
|
private static final int DATABASE_VERSION = 32;
|
||||||
|
|
||||||
public CustomSQLiteOpenHelper(Context context) {
|
public CustomSQLiteOpenHelper(Context context) {
|
||||||
this(context, ((Startup) context.getApplicationContext()).getDatabaseName());
|
this(context, ((Startup) context.getApplicationContext()).getDatabaseName());
|
||||||
@@ -83,6 +83,9 @@ public class CustomSQLiteOpenHelper extends SQLiteOpenHelper {
|
|||||||
case 31:
|
case 31:
|
||||||
upgradeFrom30to31(db);
|
upgradeFrom30to31(db);
|
||||||
break;
|
break;
|
||||||
|
case 32:
|
||||||
|
upgradeFrom31to32(db);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new RuntimeException("Not implemented: upgrade to " + toVersion);
|
throw new RuntimeException("Not implemented: upgrade to " + toVersion);
|
||||||
@@ -119,6 +122,9 @@ public class CustomSQLiteOpenHelper extends SQLiteOpenHelper {
|
|||||||
case 30:
|
case 30:
|
||||||
downgradeFrom31to30(db);
|
downgradeFrom31to30(db);
|
||||||
break;
|
break;
|
||||||
|
case 31:
|
||||||
|
downgradeFrom32to31(db);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new RuntimeException("Not implemented: downgrade to " + toVersion);
|
throw new RuntimeException("Not implemented: downgrade to " + toVersion);
|
||||||
}
|
}
|
||||||
@@ -425,4 +431,35 @@ public class CustomSQLiteOpenHelper extends SQLiteOpenHelper {
|
|||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add TrackPoint type SENSORPOINT (2).
|
||||||
|
*/
|
||||||
|
private void upgradeFrom31to32(SQLiteDatabase db) {
|
||||||
|
db.beginTransaction();
|
||||||
|
|
||||||
|
db.execSQL("ALTER TABLE trackpoints RENAME TO trackpoints_old");
|
||||||
|
db.execSQL("CREATE TABLE trackpoints (_id INTEGER PRIMARY KEY AUTOINCREMENT, trackid INTEGER NOT NULL, longitude INTEGER, latitude INTEGER, time INTEGER, elevation FLOAT, accuracy FLOAT, speed FLOAT, bearing FLOAT, sensor_heartrate FLOAT, sensor_cadence FLOAT, sensor_power FLOAT, elevation_gain FLOAT, elevation_loss FLOAT, type TEXT CHECK(type IN (-2, -1, 0, 1, 2)), sensor_distance FLOAT, FOREIGN KEY (trackid) REFERENCES tracks(_id) ON UPDATE CASCADE ON DELETE CASCADE)");
|
||||||
|
db.execSQL("INSERT INTO trackpoints SELECT _id, trackid, longitude, latitude, time, elevation, accuracy, speed, bearing, sensor_heartrate, sensor_cadence, sensor_power, elevation_gain, elevation_gain, type, sensor_distance FROM trackpoints_old");
|
||||||
|
db.execSQL("DROP TABLE trackpoints_old");
|
||||||
|
|
||||||
|
db.execSQL("CREATE INDEX trackpoints_trackid_index ON trackpoints(trackid)");
|
||||||
|
|
||||||
|
db.setTransactionSuccessful();
|
||||||
|
db.endTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void downgradeFrom32to31(SQLiteDatabase db) {
|
||||||
|
db.beginTransaction();
|
||||||
|
|
||||||
|
db.execSQL("ALTER TABLE trackpoints RENAME TO trackpoints_old");
|
||||||
|
db.execSQL("CREATE TABLE trackpoints (_id INTEGER PRIMARY KEY AUTOINCREMENT, trackid INTEGER NOT NULL, longitude INTEGER, latitude INTEGER, time INTEGER, elevation FLOAT, accuracy FLOAT, speed FLOAT, bearing FLOAT, sensor_heartrate FLOAT, sensor_cadence FLOAT, sensor_power FLOAT, elevation_gain FLOAT, elevation_loss FLOAT, type TEXT CHECK(type IN (-2, -1, 0, 1)), sensor_distance FLOAT, FOREIGN KEY (trackid) REFERENCES tracks(_id) ON UPDATE CASCADE ON DELETE CASCADE)");
|
||||||
|
db.execSQL("INSERT INTO trackpoints SELECT _id, trackid, longitude, latitude, time, elevation, accuracy, speed, bearing, sensor_heartrate, sensor_cadence, sensor_power, elevation_gain, elevation_gain, type, sensor_distance FROM trackpoints_old");
|
||||||
|
db.execSQL("DROP TABLE trackpoints_old");
|
||||||
|
|
||||||
|
db.execSQL("CREATE INDEX trackpoints_trackid_index ON trackpoints(trackid)");
|
||||||
|
|
||||||
|
db.setTransactionSuccessful();
|
||||||
|
db.endTransaction();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -182,7 +182,9 @@ public class IntervalsFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void updateIntervals(boolean metricUnits, IntervalStatisticsModel.IntervalOption selectedInterval) {
|
private synchronized void updateIntervals(boolean metricUnits, IntervalStatisticsModel.IntervalOption selectedInterval) {
|
||||||
boolean update = metricUnits != this.metricUnits || !selectedInterval.sameMultiplier(this.selectedInterval);
|
boolean update = metricUnits != this.metricUnits
|
||||||
|
|| selectedInterval == null
|
||||||
|
|| !selectedInterval.sameMultiplier(this.selectedInterval);
|
||||||
this.metricUnits = metricUnits;
|
this.metricUnits = metricUnits;
|
||||||
this.selectedInterval = selectedInterval;
|
this.selectedInterval = selectedInterval;
|
||||||
|
|
||||||
|
|||||||
@@ -24,13 +24,19 @@ import androidx.annotation.NonNull;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Marker;
|
import de.dennisguse.opentracks.content.data.Marker;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
||||||
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
import de.dennisguse.opentracks.util.StringUtils;
|
import de.dennisguse.opentracks.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -122,6 +128,8 @@ public class GPXTrackExporter implements TrackExporter {
|
|||||||
boolean wroteTrack = false;
|
boolean wroteTrack = false;
|
||||||
boolean wroteSegment = false;
|
boolean wroteSegment = false;
|
||||||
|
|
||||||
|
LinkedList<TrackPoint> sensorPoints = new LinkedList<>();
|
||||||
|
|
||||||
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), null)) {
|
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), null)) {
|
||||||
while (trackPointIterator.hasNext()) {
|
while (trackPointIterator.hasNext()) {
|
||||||
if (Thread.interrupted()) throw new InterruptedException();
|
if (Thread.interrupted()) throw new InterruptedException();
|
||||||
@@ -149,7 +157,12 @@ public class GPXTrackExporter implements TrackExporter {
|
|||||||
if (wroteSegment) writeCloseSegment();
|
if (wroteSegment) writeCloseSegment();
|
||||||
writeOpenSegment();
|
writeOpenSegment();
|
||||||
wroteSegment = true;
|
wroteSegment = true;
|
||||||
writeTrackPoint(trackPoint);
|
|
||||||
|
writeTrackPoint(trackPoint, sensorPoints);
|
||||||
|
sensorPoints.clear();
|
||||||
|
break;
|
||||||
|
case SENSORPOINT:
|
||||||
|
sensorPoints.add(trackPoint);
|
||||||
break;
|
break;
|
||||||
case TRACKPOINT:
|
case TRACKPOINT:
|
||||||
if (!wroteSegment) {
|
if (!wroteSegment) {
|
||||||
@@ -157,11 +170,21 @@ public class GPXTrackExporter implements TrackExporter {
|
|||||||
writeOpenSegment();
|
writeOpenSegment();
|
||||||
wroteSegment = true;
|
wroteSegment = true;
|
||||||
}
|
}
|
||||||
writeTrackPoint(trackPoint);
|
|
||||||
|
writeTrackPoint(trackPoint, sensorPoints);
|
||||||
|
sensorPoints.clear();
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("Exporting this TrackPoint type is not implemented: " + trackPoint.getType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!sensorPoints.isEmpty()) {
|
||||||
|
//TODO We might miss to export data; this happens if there are SENSORPOINTs after the final TRACKPOINT of a track.
|
||||||
|
//For segments the data is added to the next segment.
|
||||||
|
Log.d(TAG, "SENSORPOINTs after final TRACKPOINT; this data is not exported.");
|
||||||
|
}
|
||||||
|
|
||||||
if (wroteSegment) {
|
if (wroteSegment) {
|
||||||
// Should not be necessary as tracks should end with SEGMENT_END_MANUAL.
|
// Should not be necessary as tracks should end with SEGMENT_END_MANUAL.
|
||||||
// Anyhow, make sure that the last segment is closed.
|
// Anyhow, make sure that the last segment is closed.
|
||||||
@@ -200,6 +223,7 @@ public class GPXTrackExporter implements TrackExporter {
|
|||||||
printWriter.println("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
|
printWriter.println("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
|
||||||
printWriter.println("xmlns:opentracks=\"http://opentracksapp.com/xmlschemas/v1\"");
|
printWriter.println("xmlns:opentracks=\"http://opentracksapp.com/xmlschemas/v1\"");
|
||||||
printWriter.println("xmlns:gpxtpx=\"http://www.garmin.com/xmlschemas/TrackPointExtension/v2\"");
|
printWriter.println("xmlns:gpxtpx=\"http://www.garmin.com/xmlschemas/TrackPointExtension/v2\"");
|
||||||
|
printWriter.println("xmlns:gpxtrkx=\"http://www.garmin.com/xmlschemas/TrackStatsExtension/v1\"");
|
||||||
printWriter.println("xmlns:pwr=\"http://www.garmin.com/xmlschemas/PowerExtension/v1\"");
|
printWriter.println("xmlns:pwr=\"http://www.garmin.com/xmlschemas/PowerExtension/v1\"");
|
||||||
printWriter.println("xsi:schemaLocation=" +
|
printWriter.println("xsi:schemaLocation=" +
|
||||||
"\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"
|
"\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"
|
||||||
@@ -256,6 +280,18 @@ public class GPXTrackExporter implements TrackExporter {
|
|||||||
printWriter.println("<extensions>");
|
printWriter.println("<extensions>");
|
||||||
printWriter.println("<topografix:color>c0c0c0</topografix:color>");
|
printWriter.println("<topografix:color>c0c0c0</topografix:color>");
|
||||||
printWriter.println("<opentracks:trackid>" + track.getUuid() + "</opentracks:trackid>");
|
printWriter.println("<opentracks:trackid>" + track.getUuid() + "</opentracks:trackid>");
|
||||||
|
|
||||||
|
TrackStatistics trackStatistics = track.getTrackStatistics();
|
||||||
|
printWriter.println("<gpxtrkx:TrackStatsExtension>");
|
||||||
|
printWriter.println("<gpxtrkx:Distance>" + trackStatistics.getTotalDistance().toM() + "</gpxtrkx:Distance>");
|
||||||
|
printWriter.println("<gpxtrkx:TimerTime>" + trackStatistics.getTotalTime().getSeconds() + "</gpxtrkx:TimerTime>");
|
||||||
|
printWriter.println("<gpxtrkx:MovingTime>" + trackStatistics.getMovingTime().getSeconds() + "</gpxtrkx:MovingTime>");
|
||||||
|
printWriter.println("<gpxtrkx:StoppedTime>" + trackStatistics.getStoppedTime().getSeconds() + "</gpxtrkx:StoppedTime>");
|
||||||
|
printWriter.println("<gpxtrkx:MaxSpeed>" + trackStatistics.getMaxSpeed().toMPS() + "</gpxtrkx:MaxSpeed>");
|
||||||
|
printWriter.println("<gpxtrkx:Ascent>" + trackStatistics.getTotalAltitudeGain() + "</gpxtrkx:Ascent>");
|
||||||
|
printWriter.println("<gpxtrkx:Descent>" + trackStatistics.getTotalAltitudeLoss() + "</gpxtrkx:Descent>");
|
||||||
|
printWriter.println("</gpxtrkx:TrackStatsExtension>");
|
||||||
|
|
||||||
printWriter.println("</extensions>");
|
printWriter.println("</extensions>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -274,7 +310,7 @@ public class GPXTrackExporter implements TrackExporter {
|
|||||||
printWriter.println("</trkseg>");
|
printWriter.println("</trkseg>");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTrackPoint(TrackPoint trackPoint) {
|
public void writeTrackPoint(TrackPoint trackPoint, List<TrackPoint> sensorPoints) {
|
||||||
if (printWriter != null) {
|
if (printWriter != null) {
|
||||||
|
|
||||||
printWriter.println("<trkpt " + formatLocation(trackPoint.getLatitude(), trackPoint.getLongitude()) + ">");
|
printWriter.println("<trkpt " + formatLocation(trackPoint.getLatitude(), trackPoint.getLongitude()) + ">");
|
||||||
@@ -285,44 +321,59 @@ public class GPXTrackExporter implements TrackExporter {
|
|||||||
|
|
||||||
printWriter.println("<time>" + StringUtils.formatDateTimeIso8601(trackPoint.getTime()) + "</time>");
|
printWriter.println("<time>" + StringUtils.formatDateTimeIso8601(trackPoint.getTime()) + "</time>");
|
||||||
|
|
||||||
if (trackPoint.hasSpeed() || trackPoint.hasHeartRate() || trackPoint.hasCadence() || trackPoint.hasAltitudeGain() || trackPoint.hasAltitudeLoss()) {
|
{
|
||||||
printWriter.println("<extensions><gpxtpx:TrackPointExtension>");
|
String trackPointExtensionContent = "";
|
||||||
|
|
||||||
if (trackPoint.hasSpeed()) {
|
if (trackPoint.hasSpeed()) {
|
||||||
printWriter.println("<gpxtpx:speed>" + SPEED_FORMAT.format(trackPoint.getSpeed().toMPS()) + "</gpxtpx:speed>");
|
trackPointExtensionContent += "<gpxtpx:speed>" + SPEED_FORMAT.format(trackPoint.getSpeed().toMPS()) + "</gpxtpx:speed>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trackPoint.hasHeartRate()) {
|
if (trackPoint.hasHeartRate()) {
|
||||||
printWriter.println("<gpxtpx:hr>" + HEARTRATE_FORMAT.format(trackPoint.getHeartRate_bpm()) + "</gpxtpx:hr>");
|
trackPointExtensionContent += "<gpxtpx:hr>" + HEARTRATE_FORMAT.format(trackPoint.getHeartRate_bpm()) + "</gpxtpx:hr>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trackPoint.hasCadence()) {
|
if (trackPoint.hasCadence()) {
|
||||||
printWriter.println("<gpxtpx:cad>" + CADENCE_FORMAT.format(trackPoint.getCadence_rpm()) + "</gpxtpx:cad>");
|
trackPointExtensionContent += "<gpxtpx:cad>" + CADENCE_FORMAT.format(trackPoint.getCadence_rpm()) + "</gpxtpx:cad>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trackPoint.hasPower()) {
|
if (trackPoint.hasPower()) {
|
||||||
printWriter.println("<pwr:PowerInWatts>" + POWER_FORMAT.format(trackPoint.getPower()) + "</pwr:PowerInWatts>");
|
trackPointExtensionContent += "<pwr:PowerInWatts>" + POWER_FORMAT.format(trackPoint.getPower()) + "</pwr:PowerInWatts>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trackPoint.hasAltitudeGain()) {
|
Double cumulativeGain = cumulateSensorData(trackPoint, sensorPoints, (tp) -> tp.hasAltitudeGain() ? (double) tp.getAltitudeGain() : null);
|
||||||
printWriter.println("<opentracks:gain>" + ALTITUDE_FORMAT.format(trackPoint.getAltitudeGain()) + "</opentracks:gain>");
|
if (cumulativeGain != null) {
|
||||||
|
trackPointExtensionContent += ("<opentracks:gain>" + ALTITUDE_FORMAT.format(cumulativeGain) + "</opentracks:gain>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trackPoint.hasAltitudeLoss()) {
|
Double cumulativeLoss = cumulateSensorData(trackPoint, sensorPoints, (tp) -> tp.hasAltitudeLoss() ? (double) tp.getAltitudeLoss() : null);
|
||||||
printWriter.println("<opentracks:loss>" + ALTITUDE_FORMAT.format(trackPoint.getAltitudeLoss()) + "</opentracks:loss>");
|
if (cumulativeLoss != null) {
|
||||||
|
trackPointExtensionContent += ("<opentracks:loss>" + ALTITUDE_FORMAT.format(cumulativeLoss) + "</opentracks:loss>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trackPoint.hasSensorDistance()) {
|
Double cumulativeDistance = cumulateSensorData(trackPoint, sensorPoints, (tp) -> tp.hasSensorDistance() ? tp.getSensorDistance().toM() : null);
|
||||||
printWriter.println("<opentracks:distance>" + DISTANCE_FORMAT.format(trackPoint.getSensorDistance().toM()) + "</opentracks:distance>");
|
if (cumulativeDistance != null) {
|
||||||
|
trackPointExtensionContent += ("<opentracks:distance>" + ALTITUDE_FORMAT.format(cumulativeDistance) + "</opentracks:distance>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
printWriter.println("</gpxtpx:TrackPointExtension></extensions>");
|
if (!trackPointExtensionContent.isEmpty()) {
|
||||||
|
printWriter.println("<extensions><gpxtpx:TrackPointExtension>");
|
||||||
|
printWriter.print(trackPointExtensionContent);
|
||||||
|
printWriter.println("</gpxtpx:TrackPointExtension></extensions>");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printWriter.println("</trkpt>");
|
printWriter.println("</trkpt>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Double cumulateSensorData(TrackPoint trackPoint, List<TrackPoint> sensorPoints, Function<TrackPoint, Double> map) {
|
||||||
|
return Stream.concat(sensorPoints.stream(), Stream.of(trackPoint))
|
||||||
|
.map(map)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.reduce((gain, next) -> gain + next)
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
private String formatLocation(double latitude, double longitude) {
|
private String formatLocation(double latitude, double longitude) {
|
||||||
return "lat=\"" + COORDINATE_FORMAT.format(latitude) + "\" lon=\"" + COORDINATE_FORMAT.format(longitude) + "\"";
|
return "lat=\"" + COORDINATE_FORMAT.format(latitude) + "\" lon=\"" + COORDINATE_FORMAT.format(longitude) + "\"";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,6 +181,7 @@ public class KMLTrackExporter implements TrackExporter {
|
|||||||
writeCloseSegment();
|
writeCloseSegment();
|
||||||
wroteSegment = false;
|
wroteSegment = false;
|
||||||
break;
|
break;
|
||||||
|
case SENSORPOINT:
|
||||||
case TRACKPOINT:
|
case TRACKPOINT:
|
||||||
if (!wroteSegment) {
|
if (!wroteSegment) {
|
||||||
// Might happen for older data (pre v3.15.0)
|
// Might happen for older data (pre v3.15.0)
|
||||||
@@ -189,6 +190,8 @@ public class KMLTrackExporter implements TrackExporter {
|
|||||||
}
|
}
|
||||||
writeTrackPoint(trackPoint);
|
writeTrackPoint(trackPoint);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("Exporting this TrackPoint type is not implemented: " + trackPoint.getType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ public class GpxTrackImporter extends DefaultHandler implements XMLImporter.Trac
|
|||||||
|
|
||||||
private void onTrackSegmentEnd() {
|
private void onTrackSegmentEnd() {
|
||||||
if (currentSegment.isEmpty()) {
|
if (currentSegment.isEmpty()) {
|
||||||
Log.w(TAG, "No locations in current segment.");
|
Log.w(TAG, "No TrackPoints in current segment.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,7 +256,7 @@ public class GpxTrackImporter extends DefaultHandler implements XMLImporter.Trac
|
|||||||
|
|
||||||
|
|
||||||
private TrackPoint createTrackPoint() throws ParsingException {
|
private TrackPoint createTrackPoint() throws ParsingException {
|
||||||
Instant parsedTime = null;
|
Instant parsedTime;
|
||||||
try {
|
try {
|
||||||
parsedTime = StringUtils.parseTime(time);
|
parsedTime = StringUtils.parseTime(time);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|||||||
@@ -295,15 +295,21 @@ public class KmlTrackImporter extends DefaultHandler implements XMLImporter.Trac
|
|||||||
|
|
||||||
TrackPoint trackPoint;
|
TrackPoint trackPoint;
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
|
//first
|
||||||
if (location == null) {
|
if (location == null) {
|
||||||
trackPoint = TrackPoint.createSegmentStartManualWithTime(time);
|
trackPoint = TrackPoint.createSegmentStartManualWithTime(time);
|
||||||
} else {
|
} else {
|
||||||
trackPoint = new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, location, time);
|
trackPoint = new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, location, time);
|
||||||
}
|
}
|
||||||
} else if (i == locationList.size() - 1 && location == null) {
|
} else if (i == locationList.size() - 1 && location == null) {
|
||||||
|
//last
|
||||||
trackPoint = TrackPoint.createSegmentEndWithTime(time);
|
trackPoint = TrackPoint.createSegmentEndWithTime(time);
|
||||||
} else {
|
} else {
|
||||||
trackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT, location, time);
|
if (location == null) {
|
||||||
|
trackPoint = new TrackPoint(TrackPoint.Type.SENSORPOINT, time);
|
||||||
|
} else {
|
||||||
|
trackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT, location, time);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i < sensorSpeedList.size() && sensorSpeedList.get(i) != null) {
|
if (i < sensorSpeedList.size() && sensorSpeedList.get(i) != null) {
|
||||||
|
|||||||
@@ -36,9 +36,11 @@ class TrackRecordingManager {
|
|||||||
private Track.Id trackId;
|
private Track.Id trackId;
|
||||||
private TrackStatisticsUpdater trackStatisticsUpdater;
|
private TrackStatisticsUpdater trackStatisticsUpdater;
|
||||||
|
|
||||||
|
//TDOO use lastStoredTrackPoint?
|
||||||
private boolean currentSegmentHasTrackPoint;
|
private boolean currentSegmentHasTrackPoint;
|
||||||
private TrackPoint lastTrackPoint;
|
private TrackPoint lastTrackPoint;
|
||||||
private TrackPoint lastStoredTrackPoint;
|
private TrackPoint lastStoredTrackPoint;
|
||||||
|
private TrackPoint lastStoredTrackPointWithLocation;
|
||||||
|
|
||||||
TrackRecordingManager(Context context) {
|
TrackRecordingManager(Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
@@ -80,15 +82,20 @@ class TrackRecordingManager {
|
|||||||
|
|
||||||
trackStatisticsUpdater = new TrackStatisticsUpdater(track.getTrackStatistics());
|
trackStatisticsUpdater = new TrackStatisticsUpdater(track.getTrackStatistics());
|
||||||
insertTrackPoint(trackId, segmentStartTrackPoint);
|
insertTrackPoint(trackId, segmentStartTrackPoint);
|
||||||
currentSegmentHasTrackPoint = false;
|
|
||||||
lastTrackPoint = null;
|
|
||||||
lastStoredTrackPoint = null; }
|
|
||||||
|
|
||||||
void pause(TrackPointCreator trackPointCreator) {
|
|
||||||
insertTrackPoint(trackId, trackPointCreator.createSegmentEnd());
|
|
||||||
currentSegmentHasTrackPoint = false;
|
currentSegmentHasTrackPoint = false;
|
||||||
lastTrackPoint = null;
|
lastTrackPoint = null;
|
||||||
lastStoredTrackPoint = null;
|
lastStoredTrackPoint = null;
|
||||||
|
lastStoredTrackPointWithLocation = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pause(TrackPointCreator trackPointCreator) {
|
||||||
|
insertTrackPoint(trackId, trackPointCreator.createSegmentEnd());
|
||||||
|
|
||||||
|
currentSegmentHasTrackPoint = false;
|
||||||
|
lastTrackPoint = null;
|
||||||
|
lastStoredTrackPoint = null;
|
||||||
|
lastStoredTrackPointWithLocation = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
void end(TrackPointCreator trackPointCreator) {
|
void end(TrackPointCreator trackPointCreator) {
|
||||||
@@ -97,9 +104,11 @@ class TrackRecordingManager {
|
|||||||
|
|
||||||
trackId = null;
|
trackId = null;
|
||||||
trackStatisticsUpdater = null;
|
trackStatisticsUpdater = null;
|
||||||
|
|
||||||
|
currentSegmentHasTrackPoint = false;
|
||||||
lastTrackPoint = null;
|
lastTrackPoint = null;
|
||||||
lastStoredTrackPoint = null;
|
lastStoredTrackPoint = null;
|
||||||
currentSegmentHasTrackPoint = false;
|
lastStoredTrackPointWithLocation = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pair<Track, Pair<TrackPoint, SensorDataSet>> get(TrackPointCreator trackPointCreator) {
|
Pair<Track, Pair<TrackPoint, SensorDataSet>> get(TrackPointCreator trackPointCreator) {
|
||||||
@@ -131,7 +140,7 @@ class TrackRecordingManager {
|
|||||||
name = context.getString(R.string.marker_name_format, nextMarkerNumber + 1);
|
name = context.getString(R.string.marker_name_format, nextMarkerNumber + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastStoredTrackPoint == null) {
|
if (lastStoredTrackPointWithLocation == null) {
|
||||||
Log.i(TAG, "Could not create a marker as trackPoint is unknown.");
|
Log.i(TAG, "Could not create a marker as trackPoint is unknown.");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -142,11 +151,14 @@ class TrackRecordingManager {
|
|||||||
photoUrl = photoUrl != null ? photoUrl : "";
|
photoUrl = photoUrl != null ? photoUrl : "";
|
||||||
|
|
||||||
// Insert marker
|
// Insert marker
|
||||||
Marker marker = new Marker(name, description, category, icon, trackId, getTrackStatistics(), lastStoredTrackPoint, photoUrl);
|
Marker marker = new Marker(name, description, category, icon, trackId, getTrackStatistics(), lastStoredTrackPointWithLocation, photoUrl);
|
||||||
Uri uri = contentProviderUtils.insertMarker(marker);
|
Uri uri = contentProviderUtils.insertMarker(marker);
|
||||||
return new Marker.Id(ContentUris.parseId(uri));
|
return new Marker.Id(ContentUris.parseId(uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return TrackPoint was stored?
|
||||||
|
*/
|
||||||
boolean onNewTrackPoint(TrackPoint trackPoint) {
|
boolean onNewTrackPoint(TrackPoint trackPoint) {
|
||||||
//Storing trackPoint
|
//Storing trackPoint
|
||||||
|
|
||||||
@@ -157,18 +169,31 @@ class TrackRecordingManager {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Distance distanceToLastTrackLocation = trackPoint.distanceToPrevious(lastStoredTrackPoint);
|
Distance distanceToLastStoredTrackPoint = trackPoint.distanceToPrevious(lastStoredTrackPoint);
|
||||||
if (distanceToLastTrackLocation != null) {
|
if (distanceToLastStoredTrackPoint != null) {
|
||||||
if (distanceToLastTrackLocation.greaterThan(maxRecordingDistance)) {
|
if (distanceToLastStoredTrackPoint.greaterThan(maxRecordingDistance)) {
|
||||||
trackPoint.setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC);
|
trackPoint.setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC);
|
||||||
insertTrackPoint(trackId, trackPoint);
|
insertTrackPoint(trackId, trackPoint);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (distanceToLastTrackLocation.greaterOrEqualThan(recordingDistanceInterval) && trackPoint.isMoving()) {
|
if (distanceToLastStoredTrackPoint.greaterOrEqualThan(recordingDistanceInterval) && trackPoint.isMoving()) {
|
||||||
insertTrackPoint(trackId, trackPoint);
|
insertTrackPoint(trackId, trackPoint);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (trackPoint.hasLocation()) {
|
||||||
|
if (lastStoredTrackPointWithLocation == null) {
|
||||||
|
insertTrackPoint(trackId, trackPoint);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Distance distanceToLastStoredTrackPointWithLocation = trackPoint.distanceToPrevious(lastStoredTrackPointWithLocation);
|
||||||
|
if (distanceToLastStoredTrackPointWithLocation != null && distanceToLastStoredTrackPointWithLocation.greaterOrEqualThan(recordingDistanceInterval)) {
|
||||||
|
insertTrackPoint(trackId, trackPoint);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastStoredTrackPoint != null && trackPoint.isMoving() != lastStoredTrackPoint.isMoving()) {
|
if (lastStoredTrackPoint != null && trackPoint.isMoving() != lastStoredTrackPoint.isMoving()) {
|
||||||
@@ -209,6 +234,9 @@ class TrackRecordingManager {
|
|||||||
|
|
||||||
contentProviderUtils.updateTrackStatistics(trackId, trackStatisticsUpdater.getTrackStatistics());
|
contentProviderUtils.updateTrackStatistics(trackId, trackStatisticsUpdater.getTrackStatistics());
|
||||||
lastStoredTrackPoint = trackPoint;
|
lastStoredTrackPoint = trackPoint;
|
||||||
|
if (trackPoint.hasLocation()) {
|
||||||
|
lastStoredTrackPointWithLocation = lastStoredTrackPoint;
|
||||||
|
}
|
||||||
} catch (SQLiteException e) {
|
} catch (SQLiteException e) {
|
||||||
/*
|
/*
|
||||||
* Insert failed, most likely because of SqlLite error code 5 (SQLite_BUSY).
|
* Insert failed, most likely because of SqlLite error code 5 (SQLite_BUSY).
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ package de.dennisguse.opentracks.services;
|
|||||||
|
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||||
@@ -50,11 +49,11 @@ import de.dennisguse.opentracks.services.handlers.EGM2008CorrectionManager;
|
|||||||
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
|
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
|
||||||
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
|
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
|
||||||
import de.dennisguse.opentracks.services.tasks.VoiceAnnouncementManager;
|
import de.dennisguse.opentracks.services.tasks.VoiceAnnouncementManager;
|
||||||
|
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||||
import de.dennisguse.opentracks.settings.SettingsActivity;
|
import de.dennisguse.opentracks.settings.SettingsActivity;
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
import de.dennisguse.opentracks.util.ExportUtils;
|
import de.dennisguse.opentracks.util.ExportUtils;
|
||||||
import de.dennisguse.opentracks.util.IntentUtils;
|
import de.dennisguse.opentracks.util.IntentUtils;
|
||||||
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
|
||||||
import de.dennisguse.opentracks.util.SystemUtils;
|
import de.dennisguse.opentracks.util.SystemUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -73,6 +72,8 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
|
|||||||
public static final RecordingData NOT_RECORDING = new RecordingData(null, null, null);
|
public static final RecordingData NOT_RECORDING = new RecordingData(null, null, null);
|
||||||
public static final GpsStatusValue STATUS_GPS_DEFAULT = GpsStatusValue.GPS_NONE;
|
public static final GpsStatusValue STATUS_GPS_DEFAULT = GpsStatusValue.GPS_NONE;
|
||||||
|
|
||||||
|
private final Binder binder = new Binder();
|
||||||
|
|
||||||
// The following variables are setFrequency in onCreate:
|
// The following variables are setFrequency in onCreate:
|
||||||
private VoiceAnnouncementManager voiceAnnouncementManager;
|
private VoiceAnnouncementManager voiceAnnouncementManager;
|
||||||
private TrackRecordingServiceNotificationManager notificationManager;
|
private TrackRecordingServiceNotificationManager notificationManager;
|
||||||
@@ -86,6 +87,8 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
updateRecordingDataWhileRecording();
|
updateRecordingDataWhileRecording();
|
||||||
|
trackPointCreator.onNewTrackPointWithoutGPS(); //TODO Should not be called every second, right? + with do some duplicate computation with updateRecordingDataWhileRecording().
|
||||||
|
|
||||||
Handler localHandler = TrackRecordingService.this.handler;
|
Handler localHandler = TrackRecordingService.this.handler;
|
||||||
if (localHandler == null) {
|
if (localHandler == null) {
|
||||||
// when this happens, no recording is running and we should not send any notifications.
|
// when this happens, no recording is running and we should not send any notifications.
|
||||||
@@ -96,7 +99,10 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
|
@Deprecated
|
||||||
|
//TODO Workaround as service is not stopped on API23; thus sharedpreferences are not reset between tests.
|
||||||
|
@VisibleForTesting
|
||||||
|
final OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
if (PreferencesUtils.isKey(R.string.stats_units_key, key)) {
|
if (PreferencesUtils.isKey(R.string.stats_units_key, key)) {
|
||||||
@@ -115,11 +121,9 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// The following variables are setFrequency when recording:
|
// The following variables are set when recording:
|
||||||
private WakeLock wakeLock;
|
private WakeLock wakeLock;
|
||||||
|
|
||||||
private final Binder binder = new Binder();
|
|
||||||
|
|
||||||
private TrackPointCreator trackPointCreator; //TODO Move to TrackRecordingManager?
|
private TrackPointCreator trackPointCreator; //TODO Move to TrackRecordingManager?
|
||||||
|
|
||||||
private RecordingStatus recordingStatus;
|
private RecordingStatus recordingStatus;
|
||||||
@@ -148,27 +152,20 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
|
|||||||
PreferencesUtils.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
PreferencesUtils.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
|
||||||
return START_STICKY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Binder onBind(Intent intent) {
|
|
||||||
return binder;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
|
handler.removeCallbacksAndMessages(null); //Some tests do not finish the recording completely
|
||||||
handler = null;
|
handler = null;
|
||||||
|
|
||||||
|
PreferencesUtils.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
||||||
|
|
||||||
trackPointCreator.stop();
|
trackPointCreator.stop();
|
||||||
trackPointCreator = null;
|
trackPointCreator = null;
|
||||||
|
trackRecordingManager = null;
|
||||||
|
|
||||||
// Reverse order from onCreate
|
// Reverse order from onCreate
|
||||||
showNotification(false); //TODO Why?
|
showNotification(false); //TODO Why?
|
||||||
|
notificationManager = null;
|
||||||
PreferencesUtils.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
voiceAnnouncementManager.shutdown();
|
voiceAnnouncementManager.shutdown();
|
||||||
@@ -179,6 +176,7 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
|
|||||||
// This should be the next to last operation
|
// This should be the next to last operation
|
||||||
wakeLock = SystemUtils.releaseWakeLock(wakeLock);
|
wakeLock = SystemUtils.releaseWakeLock(wakeLock);
|
||||||
|
|
||||||
|
updateRecordingStatus(STATUS_DEFAULT);
|
||||||
recordingStatusObservable = null;
|
recordingStatusObservable = null;
|
||||||
gpsStatusObservable = null;
|
gpsStatusObservable = null;
|
||||||
recordingDataObservable = null;
|
recordingDataObservable = null;
|
||||||
@@ -186,6 +184,16 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
|
|||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
|
return START_STICKY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Binder onBind(Intent intent) {
|
||||||
|
return binder;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isRecording() {
|
public boolean isRecording() {
|
||||||
return recordingStatus.isRecording();
|
return recordingStatus.isRecording();
|
||||||
}
|
}
|
||||||
@@ -317,7 +325,7 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
|
|||||||
* @param trackStopped true if track is stopped, false if track is paused
|
* @param trackStopped true if track is stopped, false if track is paused
|
||||||
*/
|
*/
|
||||||
private void endRecording(boolean trackStopped) {
|
private void endRecording(boolean trackStopped) {
|
||||||
handler.removeCallbacks(updateRecordingData);
|
stopUpdateRecordingData();
|
||||||
if (!trackStopped) {
|
if (!trackStopped) {
|
||||||
updateRecordingDataWhileRecording();
|
updateRecordingDataWhileRecording();
|
||||||
} else {
|
} else {
|
||||||
@@ -360,8 +368,9 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean stored = trackRecordingManager.onNewTrackPoint(trackPoint);
|
||||||
notificationManager.updateTrackPoint(this, trackRecordingManager.getTrackStatistics(), trackPoint, thresholdHorizontalAccuracy);
|
notificationManager.updateTrackPoint(this, trackRecordingManager.getTrackStatistics(), trackPoint, thresholdHorizontalAccuracy);
|
||||||
return trackRecordingManager.onNewTrackPoint(trackPoint);
|
return stored;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -419,6 +428,12 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
|
|||||||
return trackPointCreator;
|
return trackPointCreator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
@VisibleForTesting
|
||||||
|
public TrackRecordingManager getTrackRecordingManager() {
|
||||||
|
return trackRecordingManager;
|
||||||
|
}
|
||||||
|
|
||||||
public LiveData<GpsStatusValue> getGpsStatusObservable() {
|
public LiveData<GpsStatusValue> getGpsStatusObservable() {
|
||||||
return gpsStatusObservable;
|
return gpsStatusObservable;
|
||||||
}
|
}
|
||||||
@@ -456,6 +471,11 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
|
|||||||
recordingDataObservable.postValue(new RecordingData(data.first, trackPoint, data.second.second));
|
recordingDataObservable.postValue(new RecordingData(data.first, trackPoint, data.second.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public void stopUpdateRecordingData() {
|
||||||
|
handler.removeCallbacks(updateRecordingData);
|
||||||
|
}
|
||||||
|
|
||||||
public LiveData<RecordingStatus> getRecordingStatusObservable() {
|
public LiveData<RecordingStatus> getRecordingStatusObservable() {
|
||||||
return recordingStatusObservable;
|
return recordingStatusObservable;
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-4
@@ -15,13 +15,13 @@ import java.time.Duration;
|
|||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
import de.dennisguse.opentracks.content.data.Distance;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
import de.dennisguse.opentracks.util.LocationUtils;
|
|
||||||
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||||
|
import de.dennisguse.opentracks.util.LocationUtils;
|
||||||
|
|
||||||
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
|
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
|
||||||
public class LocationHandler implements LocationListener, GpsStatus.GpsStatusListener {
|
public class GPSHandler implements LocationListener, GpsStatus.GpsStatusListener {
|
||||||
|
|
||||||
private final String TAG = LocationHandler.class.getSimpleName();
|
private final String TAG = GPSHandler.class.getSimpleName();
|
||||||
|
|
||||||
private LocationManager locationManager;
|
private LocationManager locationManager;
|
||||||
private final TrackPointCreator trackPointCreator;
|
private final TrackPointCreator trackPointCreator;
|
||||||
@@ -30,7 +30,7 @@ public class LocationHandler implements LocationListener, GpsStatus.GpsStatusLis
|
|||||||
private Distance thresholdHorizontalAccuracy;
|
private Distance thresholdHorizontalAccuracy;
|
||||||
private TrackPoint lastTrackPoint;
|
private TrackPoint lastTrackPoint;
|
||||||
|
|
||||||
public LocationHandler(TrackPointCreator trackPointCreator) {
|
public GPSHandler(TrackPointCreator trackPointCreator) {
|
||||||
this.trackPointCreator = trackPointCreator;
|
this.trackPointCreator = trackPointCreator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,6 +158,10 @@ public class LocationHandler implements LocationListener, GpsStatus.GpsStatusLis
|
|||||||
return lastTrackPoint;
|
return lastTrackPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Distance getThresholdHorizontalAccuracy() {
|
||||||
|
return thresholdHorizontalAccuracy;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called from {@link GpsStatus} to inform that GPS status has changed from prevStatus to currentStatus.
|
* Called from {@link GpsStatus} to inform that GPS status has changed from prevStatus to currentStatus.
|
||||||
*
|
*
|
||||||
@@ -31,25 +31,25 @@ public class TrackPointCreator {
|
|||||||
@NonNull
|
@NonNull
|
||||||
private Clock clock = Clock.systemUTC();
|
private Clock clock = Clock.systemUTC();
|
||||||
|
|
||||||
private final LocationHandler locationHandler;
|
private final GPSHandler gpsHandler;
|
||||||
private BluetoothRemoteSensorManager remoteSensorManager;
|
private BluetoothRemoteSensorManager remoteSensorManager;
|
||||||
private AltitudeSumManager altitudeSumManager;
|
private AltitudeSumManager altitudeSumManager;
|
||||||
|
|
||||||
public TrackPointCreator(Callback service) {
|
public TrackPointCreator(Callback service) {
|
||||||
this.service = service;
|
this.service = service;
|
||||||
this.locationHandler = new LocationHandler(this);
|
this.gpsHandler = new GPSHandler(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
TrackPointCreator(LocationHandler locationHandler, Callback service) {
|
TrackPointCreator(GPSHandler gpsHandler, Callback service) {
|
||||||
this.service = service;
|
this.service = service;
|
||||||
this.locationHandler = locationHandler;
|
this.gpsHandler = gpsHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start(@NonNull Context context) {
|
public void start(@NonNull Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
|
||||||
locationHandler.onStart(context);
|
gpsHandler.onStart(context);
|
||||||
|
|
||||||
remoteSensorManager = new BluetoothRemoteSensorManager(context);
|
remoteSensorManager = new BluetoothRemoteSensorManager(context);
|
||||||
remoteSensorManager.start();
|
remoteSensorManager.start();
|
||||||
@@ -58,11 +58,15 @@ public class TrackPointCreator {
|
|||||||
altitudeSumManager.start(context);
|
altitudeSumManager.start(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isStarted() {
|
||||||
|
return context != null;
|
||||||
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
//There should be a cooler way to do this; we want to send fake locations without getting affected by real GPS data.
|
//There should be a cooler way to do this; we want to send fake locations without getting affected by real GPS data.
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public void stopGPS() {
|
public void stopGPS() {
|
||||||
locationHandler.onStop();
|
gpsHandler.onStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetSensorData() {
|
public void resetSensorData() {
|
||||||
@@ -75,6 +79,10 @@ public class TrackPointCreator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private SensorDataSet fill(TrackPoint trackPoint) {
|
private SensorDataSet fill(TrackPoint trackPoint) {
|
||||||
|
if (!isStarted()) {
|
||||||
|
Log.w(TAG, "Not started, should not be called.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
SensorDataSet sensorDataSet = remoteSensorManager.fill(trackPoint);
|
SensorDataSet sensorDataSet = remoteSensorManager.fill(trackPoint);
|
||||||
altitudeSumManager.fill(trackPoint);
|
altitudeSumManager.fill(trackPoint);
|
||||||
|
|
||||||
@@ -82,7 +90,7 @@ public class TrackPointCreator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
locationHandler.onStop();
|
gpsHandler.onStop();
|
||||||
|
|
||||||
if (remoteSensorManager != null) {
|
if (remoteSensorManager != null) {
|
||||||
remoteSensorManager.stop();
|
remoteSensorManager.stop();
|
||||||
@@ -98,10 +106,10 @@ public class TrackPointCreator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onSharedPreferenceChanged(String key) {
|
public void onSharedPreferenceChanged(String key) {
|
||||||
locationHandler.onSharedPreferenceChanged(key);
|
gpsHandler.onSharedPreferenceChanged(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onNewTrackPoint(TrackPoint trackPoint, Distance thresholdHorizontalAccuracy) {
|
public synchronized void onNewTrackPoint(@NonNull TrackPoint trackPoint, @NonNull Distance thresholdHorizontalAccuracy) {
|
||||||
fill(trackPoint);
|
fill(trackPoint);
|
||||||
|
|
||||||
boolean stored = service.newTrackPoint(trackPoint, thresholdHorizontalAccuracy);
|
boolean stored = service.newTrackPoint(trackPoint, thresholdHorizontalAccuracy);
|
||||||
@@ -110,6 +118,10 @@ public class TrackPointCreator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onNewTrackPointWithoutGPS() {
|
||||||
|
onNewTrackPoint(new TrackPoint(TrackPoint.Type.SENSORPOINT, createNow()), gpsHandler.getThresholdHorizontalAccuracy());
|
||||||
|
}
|
||||||
|
|
||||||
public TrackPoint createSegmentStartManual() {
|
public TrackPoint createSegmentStartManual() {
|
||||||
return TrackPoint.createSegmentStartManualWithTime(createNow());
|
return TrackPoint.createSegmentStartManualWithTime(createNow());
|
||||||
}
|
}
|
||||||
@@ -123,7 +135,7 @@ public class TrackPointCreator {
|
|||||||
|
|
||||||
public Pair<TrackPoint, SensorDataSet> createCurrentTrackPoint(@Nullable TrackPoint lastValidTrackPoint) {
|
public Pair<TrackPoint, SensorDataSet> createCurrentTrackPoint(@Nullable TrackPoint lastValidTrackPoint) {
|
||||||
TrackPoint currentTrackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT, createNow());
|
TrackPoint currentTrackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT, createNow());
|
||||||
TrackPoint lastTrackPoint = locationHandler.getLastTrackPoint();
|
TrackPoint lastTrackPoint = gpsHandler.getLastTrackPoint();
|
||||||
|
|
||||||
if (lastTrackPoint != null && lastTrackPoint.hasLocation()) {
|
if (lastTrackPoint != null && lastTrackPoint.hasLocation()) {
|
||||||
currentTrackPoint.setSpeed(lastTrackPoint.getSpeed());
|
currentTrackPoint.setSpeed(lastTrackPoint.getSpeed());
|
||||||
@@ -148,6 +160,11 @@ public class TrackPointCreator {
|
|||||||
return Instant.now(clock);
|
return Instant.now(clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public AltitudeSumManager getAltitudeSumManager() {
|
||||||
|
return altitudeSumManager;
|
||||||
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public void setAltitudeSumManager(AltitudeSumManager altitudeSumManager) {
|
public void setAltitudeSumManager(AltitudeSumManager altitudeSumManager) {
|
||||||
@@ -166,8 +183,8 @@ public class TrackPointCreator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public LocationHandler getLocationHandler() {
|
public GPSHandler getGpsHandler() {
|
||||||
return locationHandler;
|
return gpsHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendGpsStatus(GpsStatusValue gpsStatusValue) {
|
void sendGpsStatus(GpsStatusValue gpsStatusValue) {
|
||||||
|
|||||||
@@ -65,29 +65,38 @@ public class AltitudeSumManager implements SensorEventListener {
|
|||||||
trackPoint.setAltitudeLoss(altitudeLoss_m);
|
trackPoint.setAltitudeLoss(altitudeLoss_m);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable
|
@Nullable
|
||||||
Float getAltitudeGain_m() {
|
public Float getAltitudeGain_m() {
|
||||||
return isConnected ? altitudeGain_m : null;
|
return isConnected ? altitudeGain_m : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public void setAltitudeGain_m(float altitudeGain_m) {
|
||||||
|
this.altitudeGain_m = altitudeGain_m;
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public void addAltitudeGain_m(float altitudeGain_m) {
|
public void addAltitudeGain_m(float altitudeGain_m) {
|
||||||
this.altitudeGain_m = this.altitudeGain_m == null ? 0f : this.altitudeGain_m;
|
this.altitudeGain_m = this.altitudeGain_m == null ? 0f : this.altitudeGain_m;
|
||||||
this.altitudeGain_m += altitudeGain_m ;
|
this.altitudeGain_m += altitudeGain_m;
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public void addAltitudeLoss_m(Float altitudeLoss_m) {
|
public void addAltitudeLoss_m(Float altitudeLoss_m) {
|
||||||
this.altitudeLoss_m = this.altitudeLoss_m == null ? 0f : this.altitudeLoss_m;
|
this.altitudeLoss_m = this.altitudeLoss_m == null ? 0f : this.altitudeLoss_m;
|
||||||
this.altitudeLoss_m += altitudeLoss_m ;
|
this.altitudeLoss_m += altitudeLoss_m;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable
|
@Nullable
|
||||||
Float getAltitudeLoss_m() {
|
public Float getAltitudeLoss_m() {
|
||||||
return isConnected ? altitudeLoss_m : null;
|
return isConnected ? altitudeLoss_m : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public void setAltitudeLoss_m(float altitudeLoss_m) {
|
||||||
|
this.altitudeLoss_m = altitudeLoss_m;
|
||||||
|
}
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
Log.d(TAG, "Reset");
|
Log.d(TAG, "Reset");
|
||||||
altitudeGain_m = null;
|
altitudeGain_m = null;
|
||||||
|
|||||||
@@ -203,6 +203,10 @@ public class TrackStatistics {
|
|||||||
movingTime = movingTime.plus(time);
|
movingTime = movingTime.plus(time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Duration getStoppedTime() {
|
||||||
|
return totalTime.minus(movingTime);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the average speed.
|
* Gets the average speed.
|
||||||
* This calculation only takes into account the displacement until the last point that was accounted for in statistics.
|
* This calculation only takes into account the displacement until the last point that was accounted for in statistics.
|
||||||
|
|||||||
Reference in New Issue
Block a user