diff --git a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java index def9c5762..53d8fcd2b 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/io/file/importer/ExportImportTest.java @@ -115,7 +115,7 @@ public class ExportImportTest { service.getTrackPointCreator().setClock(Clock.systemUTC()); } - public void setUp(boolean hasSensorDistance) throws TimeoutException { + public void setUp() throws TimeoutException { TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(new Intent(context, TrackRecordingService.class))) .getService(); @@ -123,13 +123,20 @@ public class ExportImportTest { trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:02Z"), ZoneId.of("CET"))); 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); - 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); + 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); trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:06Z"), ZoneId.of("CET"))); @@ -138,12 +145,17 @@ public class ExportImportTest { trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:20Z"), ZoneId.of("CET"))); service.resumeCurrentTrack(); + service.stopUpdateRecordingData(); 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); - sendLocation(trackPointCreator, Instant.parse("2020-02-02T02:02:23Z"), 3, 16.001, 10, 15, 10, 0, 66, 3, 50, sensorDistance); + mockBLESensorData(trackPointCreator, 15f, sensorDistance, 66f, 3f, 50f); + 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.setRemoteSensorManager(new BluetoothRemoteSensorManager(context)); @@ -176,7 +188,7 @@ public class ExportImportTest { @LargeTest @Test public void kmz_with_trackdetail_and_sensordata() throws TimeoutException, IOException { - setUp(true); + setUp(); // given Track track = contentProviderUtils.getTrack(trackId); @@ -213,22 +225,39 @@ public class ExportImportTest { assertEquals(Instant.parse("2020-02-02T02:02:02Z"), importedTrackStatistics.getStartTime()); 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(originalTrackStatistics.getMovingTime(), importedTrackStatistics.getMovingTime()); assertEquals(Duration.ofSeconds(4), importedTrackStatistics.getMovingTime()); // Distance + assertEquals(originalTrackStatistics.getTotalDistance(), importedTrackStatistics.getTotalDistance()); assertEquals(Distance.of(60), importedTrackStatistics.getTotalDistance()); // Speed + assertEquals(originalTrackStatistics.getMaxSpeed(), importedTrackStatistics.getMaxSpeed()); assertEquals(Speed.of(15), importedTrackStatistics.getMaxSpeed()); + + assertEquals(originalTrackStatistics.getAverageSpeed(), importedTrackStatistics.getAverageSpeed()); assertEquals(Speed.of(7.5), importedTrackStatistics.getAverageSpeed()); + + assertEquals(originalTrackStatistics.getAverageMovingSpeed(), importedTrackStatistics.getAverageMovingSpeed()); assertEquals(Speed.of(15), importedTrackStatistics.getAverageMovingSpeed()); // Altitude + assertEquals(originalTrackStatistics.getMinAltitude(), importedTrackStatistics.getMinAltitude(), 0.01); assertEquals(10, importedTrackStatistics.getMinAltitude(), 0.01); + + assertEquals(originalTrackStatistics.getMaxAltitude(), importedTrackStatistics.getMaxAltitude(), 0.01); assertEquals(10, importedTrackStatistics.getMaxAltitude(), 0.01); + + assertEquals(originalTrackStatistics.getTotalAltitudeGain(), importedTrackStatistics.getTotalAltitudeGain(), 0.01); assertEquals(1, importedTrackStatistics.getTotalAltitudeGain(), 0.01); + + assertEquals(originalTrackStatistics.getTotalAltitudeLoss(), importedTrackStatistics.getTotalAltitudeLoss(), 0.01); assertEquals(1, importedTrackStatistics.getTotalAltitudeLoss(), 0.01); // 4. markers @@ -238,7 +267,7 @@ public class ExportImportTest { @LargeTest @Test(expected = ImportAlreadyExistsException.class) public void kml_with_trackdetail_and_sensordata_duplicate_trackUUID() throws TimeoutException, IOException { - setUp(false); + setUp(); // given SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit(); @@ -264,7 +293,7 @@ public class ExportImportTest { @LargeTest @Test public void gpx() throws TimeoutException, IOException { - setUp(true); + setUp(); // given Track track = contentProviderUtils.getTrack(trackId); @@ -297,7 +326,7 @@ public class ExportImportTest { // Therefore, the track segmentation is changes. List 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(3).setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC); + trackPointsWithCoordinates.get(2).setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC); TrackPointAssert a = new TrackPointAssert() .setDelta(0.05) @@ -316,12 +345,12 @@ public class ExportImportTest { assertEquals(Duration.ofSeconds(4), importedTrackStatistics.getMovingTime()); // Distance - assertEquals(Distance.of(60), importedTrackStatistics.getTotalDistance()); + assertEquals(Distance.of(50), importedTrackStatistics.getTotalDistance()); //TODO Should be 60 due to SensorPoint // Speed assertEquals(Speed.of(15), importedTrackStatistics.getMaxSpeed()); - assertEquals(Speed.of(15), importedTrackStatistics.getAverageSpeed()); - assertEquals(Speed.of(15), importedTrackStatistics.getAverageMovingSpeed()); + assertEquals(Speed.of(12.5), importedTrackStatistics.getAverageSpeed()); + assertEquals(Speed.of(12.5), importedTrackStatistics.getAverageMovingSpeed()); // Altitude assertEquals(10, importedTrackStatistics.getMinAltitude(), 0.01); @@ -336,7 +365,7 @@ public class ExportImportTest { @LargeTest @Test(expected = ImportAlreadyExistsException.class) public void gpx_duplicate_trackUUID() throws TimeoutException, IOException { - setUp(false); + setUp(); // given 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) { - 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); - } - }); - + private void mockBLESensorData(TrackPointCreator trackPointCreator, Float speed, Distance distance, Float heartRate, Float cyclingCadence, Float power) { trackPointCreator.setRemoteSensorManager(new BluetoothRemoteSensorManager(context) { @Override public SensorDataSet fill(@NonNull TrackPoint trackPoint) { @@ -421,6 +435,24 @@ public class ExportImportTest { return sensorDataSet; } }); + } + + 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); + + AltitudeSumManager altitudeSumManager = trackPointCreator.getAltitudeSumManager(); + altitudeSumManager.setAltitudeGain_m(altitudeGain); + altitudeSumManager.setAltitudeLoss_m(altitudeGain); trackPointCreator.setClock(Clock.fixed(time, ZoneId.of("CET"))); trackPointCreator.getGpsHandler().onLocationChanged(location); diff --git a/src/main/java/de/dennisguse/opentracks/content/data/TrackPoint.java b/src/main/java/de/dennisguse/opentracks/content/data/TrackPoint.java index 63299f078..ebc2444cc 100644 --- a/src/main/java/de/dennisguse/opentracks/content/data/TrackPoint.java +++ b/src/main/java/de/dennisguse/opentracks/content/data/TrackPoint.java @@ -311,7 +311,7 @@ public class TrackPoint { } @Nullable - public Distance distanceToPrevious(TrackPoint previous) { + public Distance distanceToPrevious(@Nullable TrackPoint previous) { if (hasSensorDistance()) { return getSensorDistance(); } diff --git a/src/main/java/de/dennisguse/opentracks/io/file/exporter/GPXTrackExporter.java b/src/main/java/de/dennisguse/opentracks/io/file/exporter/GPXTrackExporter.java index 91bdb95d0..adfe89005 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/exporter/GPXTrackExporter.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/exporter/GPXTrackExporter.java @@ -151,6 +151,9 @@ public class GPXTrackExporter implements TrackExporter { wroteSegment = true; writeTrackPoint(trackPoint); break; + case SENSORPOINT: + //TODO We need somehow to compute the sensor data (mainly sensorDistance if present) and add it to the TRACKPOINT (if no segment followed in between)? + break; case TRACKPOINT: if (!wroteSegment) { // Might happen for older data (pre v3.15.0) @@ -159,6 +162,8 @@ public class GPXTrackExporter implements TrackExporter { } writeTrackPoint(trackPoint); break; + default: + throw new RuntimeException("Exporting this TrackPoint type is not implemented: " + trackPoint.getType()); } } diff --git a/src/main/java/de/dennisguse/opentracks/io/file/exporter/KMLTrackExporter.java b/src/main/java/de/dennisguse/opentracks/io/file/exporter/KMLTrackExporter.java index fa5b31647..59e342bb2 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/exporter/KMLTrackExporter.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/exporter/KMLTrackExporter.java @@ -181,6 +181,7 @@ public class KMLTrackExporter implements TrackExporter { writeCloseSegment(); wroteSegment = false; break; + case SENSORPOINT: case TRACKPOINT: if (!wroteSegment) { // Might happen for older data (pre v3.15.0) @@ -189,6 +190,8 @@ public class KMLTrackExporter implements TrackExporter { } writeTrackPoint(trackPoint); break; + default: + throw new RuntimeException("Exporting this TrackPoint type is not implemented: " + trackPoint.getType()); } } diff --git a/src/main/java/de/dennisguse/opentracks/io/file/importer/GpxTrackImporter.java b/src/main/java/de/dennisguse/opentracks/io/file/importer/GpxTrackImporter.java index fc0bf3616..71f1b395c 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/importer/GpxTrackImporter.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/importer/GpxTrackImporter.java @@ -243,7 +243,7 @@ public class GpxTrackImporter extends DefaultHandler implements XMLImporter.Trac private void onTrackSegmentEnd() { if (currentSegment.isEmpty()) { - Log.w(TAG, "No locations in current segment."); + Log.w(TAG, "No TrackPoints in current segment."); return; } @@ -256,7 +256,7 @@ public class GpxTrackImporter extends DefaultHandler implements XMLImporter.Trac private TrackPoint createTrackPoint() throws ParsingException { - Instant parsedTime = null; + Instant parsedTime; try { parsedTime = StringUtils.parseTime(time); } catch (Exception e) { diff --git a/src/main/java/de/dennisguse/opentracks/io/file/importer/KmlTrackImporter.java b/src/main/java/de/dennisguse/opentracks/io/file/importer/KmlTrackImporter.java index 2b0f4fba4..0a7cdf8a2 100644 --- a/src/main/java/de/dennisguse/opentracks/io/file/importer/KmlTrackImporter.java +++ b/src/main/java/de/dennisguse/opentracks/io/file/importer/KmlTrackImporter.java @@ -295,15 +295,21 @@ public class KmlTrackImporter extends DefaultHandler implements XMLImporter.Trac TrackPoint trackPoint; if (i == 0) { + //first if (location == null) { trackPoint = TrackPoint.createSegmentStartManualWithTime(time); } else { trackPoint = new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, location, time); } } else if (i == locationList.size() - 1 && location == null) { + //last trackPoint = TrackPoint.createSegmentEndWithTime(time); } 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) { diff --git a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingManager.java b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingManager.java index 46d18f5d8..45e42df5d 100644 --- a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingManager.java +++ b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingManager.java @@ -36,9 +36,11 @@ class TrackRecordingManager { private Track.Id trackId; private TrackStatisticsUpdater trackStatisticsUpdater; + //TDOO use lastStoredTrackPoint? private boolean currentSegmentHasTrackPoint; private TrackPoint lastTrackPoint; private TrackPoint lastStoredTrackPoint; + private TrackPoint lastStoredTrackPointWithLocation; TrackRecordingManager(Context context) { this.context = context; @@ -80,15 +82,20 @@ class TrackRecordingManager { trackStatisticsUpdater = new TrackStatisticsUpdater(track.getTrackStatistics()); insertTrackPoint(trackId, segmentStartTrackPoint); - currentSegmentHasTrackPoint = false; - lastTrackPoint = null; - lastStoredTrackPoint = null; } - void pause(TrackPointCreator trackPointCreator) { - insertTrackPoint(trackId, trackPointCreator.createSegmentEnd()); currentSegmentHasTrackPoint = false; lastTrackPoint = 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) { @@ -97,9 +104,11 @@ class TrackRecordingManager { trackId = null; trackStatisticsUpdater = null; + + currentSegmentHasTrackPoint = false; lastTrackPoint = null; lastStoredTrackPoint = null; - currentSegmentHasTrackPoint = false; + lastStoredTrackPointWithLocation = null; } Pair> get(TrackPointCreator trackPointCreator) { @@ -131,7 +140,7 @@ class TrackRecordingManager { 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."); return null; } @@ -160,18 +169,31 @@ class TrackRecordingManager { return true; } - Distance distanceToLastTrackLocation = trackPoint.distanceToPrevious(lastStoredTrackPoint); - if (distanceToLastTrackLocation != null) { - if (distanceToLastTrackLocation.greaterThan(maxRecordingDistance)) { + Distance distanceToLastStoredTrackPoint = trackPoint.distanceToPrevious(lastStoredTrackPoint); + if (distanceToLastStoredTrackPoint != null) { + if (distanceToLastStoredTrackPoint.greaterThan(maxRecordingDistance)) { trackPoint.setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC); insertTrackPoint(trackId, trackPoint); return true; } - if (distanceToLastTrackLocation.greaterOrEqualThan(recordingDistanceInterval) && trackPoint.isMoving()) { + if (distanceToLastStoredTrackPoint.greaterOrEqualThan(recordingDistanceInterval) && trackPoint.isMoving()) { insertTrackPoint(trackId, trackPoint); 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()) { @@ -212,6 +234,9 @@ class TrackRecordingManager { contentProviderUtils.updateTrackStatistics(trackId, trackStatisticsUpdater.getTrackStatistics()); lastStoredTrackPoint = trackPoint; + if (trackPoint.hasLocation()) { + lastStoredTrackPointWithLocation = lastStoredTrackPoint; + } } catch (SQLiteException e) { /* * Insert failed, most likely because of SqlLite error code 5 (SQLite_BUSY). diff --git a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java index 96cafce0d..754228cf1 100644 --- a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java +++ b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingService.java @@ -318,7 +318,7 @@ public class TrackRecordingService extends Service implements TrackPointCreator. * @param trackStopped true if track is stopped, false if track is paused */ private void endRecording(boolean trackStopped) { - handler.removeCallbacks(updateRecordingData); + stopUpdateRecordingData(); if (!trackStopped) { updateRecordingDataWhileRecording(); } else { @@ -458,6 +458,11 @@ public class TrackRecordingService extends Service implements TrackPointCreator. recordingDataObservable.postValue(new RecordingData(data.first, trackPoint, data.second.second)); } + @VisibleForTesting + public void stopUpdateRecordingData() { + handler.removeCallbacks(updateRecordingData); + } + public LiveData getRecordingStatusObservable() { return recordingStatusObservable; } diff --git a/src/main/java/de/dennisguse/opentracks/services/handlers/TrackPointCreator.java b/src/main/java/de/dennisguse/opentracks/services/handlers/TrackPointCreator.java index aabceb84d..192528e91 100644 --- a/src/main/java/de/dennisguse/opentracks/services/handlers/TrackPointCreator.java +++ b/src/main/java/de/dennisguse/opentracks/services/handlers/TrackPointCreator.java @@ -152,6 +152,11 @@ public class TrackPointCreator { return Instant.now(clock); } + @VisibleForTesting + public AltitudeSumManager getAltitudeSumManager() { + return altitudeSumManager; + } + @Deprecated @VisibleForTesting public void setAltitudeSumManager(AltitudeSumManager altitudeSumManager) { diff --git a/src/main/java/de/dennisguse/opentracks/services/sensors/AltitudeSumManager.java b/src/main/java/de/dennisguse/opentracks/services/sensors/AltitudeSumManager.java index 94ac27816..f67e852ab 100644 --- a/src/main/java/de/dennisguse/opentracks/services/sensors/AltitudeSumManager.java +++ b/src/main/java/de/dennisguse/opentracks/services/sensors/AltitudeSumManager.java @@ -65,29 +65,38 @@ public class AltitudeSumManager implements SensorEventListener { trackPoint.setAltitudeLoss(altitudeLoss_m); } - public @Nullable - Float getAltitudeGain_m() { + @Nullable + public Float getAltitudeGain_m() { return isConnected ? altitudeGain_m : null; } + @VisibleForTesting + public void setAltitudeGain_m(float altitudeGain_m) { + this.altitudeGain_m = altitudeGain_m; + } @VisibleForTesting public void addAltitudeGain_m(float altitudeGain_m) { this.altitudeGain_m = this.altitudeGain_m == null ? 0f : this.altitudeGain_m; - this.altitudeGain_m += altitudeGain_m ; + this.altitudeGain_m += altitudeGain_m; } @VisibleForTesting public void addAltitudeLoss_m(Float 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 - Float getAltitudeLoss_m() { + @Nullable + public Float getAltitudeLoss_m() { return isConnected ? altitudeLoss_m : null; } + @VisibleForTesting + public void setAltitudeLoss_m(float altitudeLoss_m) { + this.altitudeLoss_m = altitudeLoss_m; + } + public void reset() { Log.d(TAG, "Reset"); altitudeGain_m = null;