forked from upstream-mirrors/OpenTracks
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 979178a6f1 | |||
| a92a1e7838 | |||
| 8cba53cfe4 | |||
| fcedb9c444 | |||
| 2ec82af8f1 | |||
| 447d1bb7a3 | |||
| 2f6765e45f | |||
| 90bf2e6ab0 | |||
| d12423522e | |||
| 24f052491b | |||
| 6b4e7d7d9b | |||
| 00fcbb070a |
+3
-3
@@ -6,7 +6,7 @@ buildscript {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:9.0.0'
|
classpath 'com.android.tools.build:gradle:9.0.1'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,8 +47,8 @@ android {
|
|||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId 'de.dennisguse.opentracks'
|
applicationId 'de.dennisguse.opentracks'
|
||||||
versionCode 6564
|
versionCode 6603
|
||||||
versionName "v4.25.2"
|
versionName "v4.26.0"
|
||||||
|
|
||||||
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
|
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
v4.26.0: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- GPS is optional: configurable in the settings
|
||||||
|
- BLE sensor address/name is only shown after successful connection
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Altitude is now shown again in EGM2008 (introduced in v4.25.0)
|
||||||
|
- Altitude and speed were shown as 0.0 briefly when data was stored
|
||||||
|
|
||||||
|
Developer:
|
||||||
|
- Refactored sensor subsystem
|
||||||
+3
-3
@@ -89,12 +89,12 @@ import de.dennisguse.opentracks.settings.PreferencesUtils;
|
|||||||
public class ExportImportTest {
|
public class ExportImportTest {
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(50, TimeUnit.SECONDS); //TODO 5s
|
public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(5, TimeUnit.SECONDS);
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public GrantPermissionRule mGrantPermissionRule = TestUtil.createGrantPermissionRule();
|
public GrantPermissionRule mGrantPermissionRule = TestUtil.createGrantPermissionRule();
|
||||||
|
|
||||||
//For csv_export_only() as we the timezone is hardcoded in the expectation.
|
//For csv_export_only() as the timezone is hardcoded in the expectation.
|
||||||
@Rule
|
@Rule
|
||||||
public TimezoneRule timezoneRule = new TimezoneRule(TimeZone.getTimeZone("Europe/Berlin"));
|
public TimezoneRule timezoneRule = new TimezoneRule(TimeZone.getTimeZone("Europe/Berlin"));
|
||||||
|
|
||||||
@@ -747,7 +747,7 @@ public class ExportImportTest {
|
|||||||
sensorManager.getAltitudeChangeHandler().setAggregator(aggregatorBarometer);
|
sensorManager.getAltitudeChangeHandler().setAggregator(aggregatorBarometer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendLocation(TrackPointCreator trackPointCreator, String time, double latitude, double longitude, float accuracy, float verticalAccuracy, float speed, double altitude, Float altitudeGain) {
|
public static void sendLocation(TrackPointCreator trackPointCreator, String time, double latitude, double longitude, float accuracy, float verticalAccuracy, float speed, double altitude, Float altitudeGain) {
|
||||||
Location location = new Location("mock");
|
Location location = new Location("mock");
|
||||||
location.setLatitude(latitude);
|
location.setLatitude(latitude);
|
||||||
location.setLongitude(longitude);
|
location.setLongitude(longitude);
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ public class TrackPointAssert {
|
|||||||
|
|
||||||
Assert.assertEquals("has altitude", expected.position().hasAltitude(), actual.position().hasAltitude());
|
Assert.assertEquals("has altitude", expected.position().hasAltitude(), actual.position().hasAltitude());
|
||||||
if (expected.position().hasAltitude()) {
|
if (expected.position().hasAltitude()) {
|
||||||
|
Assert.assertEquals("altitude", expected.position().altitude().getClass(), actual.position().altitude().getClass());
|
||||||
Assert.assertEquals("altitude", expected.position().altitude().toM(), actual.position().altitude().toM(), delta);
|
Assert.assertEquals("altitude", expected.position().altitude().toM(), actual.position().altitude().toM(), delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -135,7 +135,7 @@ public class TrackRecordingServiceStateMachineTest {
|
|||||||
// then
|
// then
|
||||||
assertEquals(TrackRecordingService.STATUS_DEFAULT, service.getRecordingStatusObservable().getValue());
|
assertEquals(TrackRecordingService.STATUS_DEFAULT, service.getRecordingStatusObservable().getValue());
|
||||||
assertEquals(RecordingData.NOT_RECORDING, service.getRecordingDataObservable().getValue());
|
assertEquals(RecordingData.NOT_RECORDING, service.getRecordingDataObservable().getValue());
|
||||||
// assertEquals(GpsStatusValue.GPS_NONE, service.getGpsStatusObservable().getValue()); TODO BUG: GPS can only be stopped if a service is recording.
|
assertEquals(GpsStatusValue.GPS_NONE, service.getGpsStatusObservable().getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
|
|||||||
+112
@@ -0,0 +1,112 @@
|
|||||||
|
package de.dennisguse.opentracks.services;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static de.dennisguse.opentracks.services.TrackRecordingService.RECORDING_DATA_UPDATE_INTERVAL;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Looper;
|
||||||
|
|
||||||
|
import androidx.core.location.LocationManagerCompat;
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
import androidx.test.rule.GrantPermissionRule;
|
||||||
|
import androidx.test.rule.ServiceTestRule;
|
||||||
|
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.TestUtil;
|
||||||
|
import de.dennisguse.opentracks.data.models.Altitude;
|
||||||
|
import de.dennisguse.opentracks.data.models.AltitudeGainLoss;
|
||||||
|
import de.dennisguse.opentracks.data.models.Position;
|
||||||
|
import de.dennisguse.opentracks.data.models.Speed;
|
||||||
|
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||||
|
import de.dennisguse.opentracks.io.file.importer.ExportImportTest;
|
||||||
|
import de.dennisguse.opentracks.io.file.importer.TrackPointAssert;
|
||||||
|
import de.dennisguse.opentracks.sensors.driver.GpsInternal;
|
||||||
|
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class TrackRecordingServiceUITest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(5, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public GrantPermissionRule mGrantPermissionRule = TestUtil.createGrantPermissionRule();
|
||||||
|
|
||||||
|
private static final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void preSetUp() {
|
||||||
|
// Prepare looper for Android's message queue
|
||||||
|
if (Looper.myLooper() == null) Looper.prepare();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getDataForUI_gps() throws TimeoutException, InterruptedException {
|
||||||
|
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(new Intent(context, TrackRecordingService.class)))
|
||||||
|
.getService();
|
||||||
|
RecordingData recordingData;
|
||||||
|
|
||||||
|
// given
|
||||||
|
TrackPointCreator trackPointCreator = service.getTrackPointCreator();
|
||||||
|
|
||||||
|
trackPointCreator.setClock("2020-02-02T02:02:02Z");
|
||||||
|
|
||||||
|
// when
|
||||||
|
service.startNewTrack();
|
||||||
|
//We do not want the real GPS to interfere.
|
||||||
|
GpsInternal gpsInternal = (GpsInternal)trackPointCreator.getSensorManager().getGpsHandler().driver;
|
||||||
|
LocationManagerCompat.removeUpdates(gpsInternal.locationManager, gpsInternal.locationListenerCompat);
|
||||||
|
Thread.sleep(RECORDING_DATA_UPDATE_INTERVAL.toMillis());
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(new TrackPoint(
|
||||||
|
null,
|
||||||
|
TrackPoint.Type.TRACKPOINT,
|
||||||
|
Position.of( Instant.parse("2020-02-02T02:02:02Z")),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
),
|
||||||
|
service.getRecordingDataObservable().getValue().latestTrackPoint());
|
||||||
|
|
||||||
|
|
||||||
|
// when
|
||||||
|
// In this step, the data is saved (and Aggregator.resetAggregated called), but data should still be shown in the UI.
|
||||||
|
trackPointCreator.setClock("2020-02-02T02:02:03Z");
|
||||||
|
ExportImportTest.sendLocation(trackPointCreator, "2020-02-02T02:02:03Z", 3.1234567, 14.0014567, 10, 13, 15, 1020.25, 1f);
|
||||||
|
|
||||||
|
// then
|
||||||
|
Thread.sleep(RECORDING_DATA_UPDATE_INTERVAL.toMillis());
|
||||||
|
recordingData = service.getRecordingDataObservable().getValue();
|
||||||
|
new TrackPointAssert().assertEquals(new TrackPoint(
|
||||||
|
null,
|
||||||
|
TrackPoint.Type.TRACKPOINT,
|
||||||
|
new Position(
|
||||||
|
Instant.parse("2020-02-02T02:02:03Z"),
|
||||||
|
3.1234567, 14.0014567, null,
|
||||||
|
Altitude.EGM2008.of(1013.05), null,
|
||||||
|
null,
|
||||||
|
Speed.of(15)),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new AltitudeGainLoss(1, 1)
|
||||||
|
),
|
||||||
|
recordingData.latestTrackPoint());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ import androidx.annotation.Nullable;
|
|||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
public record Position(
|
public record Position(
|
||||||
@Nullable Instant time,
|
@Nullable Instant time, //TODO It may be a good idea to move time out of Position
|
||||||
@Nullable Double latitude,
|
@Nullable Double latitude,
|
||||||
@Nullable Double longitude,
|
@Nullable Double longitude,
|
||||||
@Nullable Distance horizontalAccuracy,
|
@Nullable Distance horizontalAccuracy,
|
||||||
@@ -17,10 +17,6 @@ public record Position(
|
|||||||
@Nullable Float bearing,
|
@Nullable Float bearing,
|
||||||
@Nullable Speed speed
|
@Nullable Speed speed
|
||||||
) {
|
) {
|
||||||
@Deprecated
|
|
||||||
public static Position empty() {
|
|
||||||
return of(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Position of(@NonNull Instant time) {
|
public static Position of(@NonNull Instant time) {
|
||||||
return new Position(
|
return new Position(
|
||||||
|
|||||||
@@ -167,8 +167,11 @@ public class ExportActivity extends AbstractActivity {
|
|||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
directoryFiles = ExportUtils.getAllFiles(ExportActivity.this, documentFile.getUri());
|
directoryFiles = ExportUtils.getAllFiles(ExportActivity.this, documentFile.getUri());
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
createExportTasks(allInOneFile);
|
if (createExportTasks(allInOneFile)) {
|
||||||
nextExport(null);
|
nextExport(null);
|
||||||
|
} else {
|
||||||
|
onExportEnded();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}).start();
|
}).start();
|
||||||
} else {
|
} else {
|
||||||
@@ -217,8 +220,12 @@ public class ExportActivity extends AbstractActivity {
|
|||||||
exportTasks.clear();
|
exportTasks.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createExportTasks(boolean allInOneFile) {
|
private boolean createExportTasks(boolean allInOneFile) {
|
||||||
List<Track> tracks = contentProviderUtils.getTracks();
|
List<Track> tracks = contentProviderUtils.getTracks();
|
||||||
|
if (tracks.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
exportTasks = new ArrayList<>();
|
exportTasks = new ArrayList<>();
|
||||||
if (allInOneFile) {
|
if (allInOneFile) {
|
||||||
String filename = "OpenTracks-Backup";
|
String filename = "OpenTracks-Backup";
|
||||||
@@ -227,6 +234,7 @@ public class ExportActivity extends AbstractActivity {
|
|||||||
exportTasks.addAll(tracks.stream().map(it -> new ExportTask(null, trackFileFormat, List.of(it.id()))).toList());
|
exportTasks.addAll(tracks.stream().map(it -> new ExportTask(null, trackFileFormat, List.of(it.id()))).toList());
|
||||||
}
|
}
|
||||||
trackExportTotalCount = exportTasks.size();
|
trackExportTotalCount = exportTasks.size();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -391,7 +399,7 @@ public class ExportActivity extends AbstractActivity {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to resolve the conflict if user gave the info needed.
|
* Try to resolve the conflict if user gave the info needed.
|
||||||
* Otherwise shows the buttons and views needed to gives the user the possibility of take a decision.
|
* Otherwise, shows the buttons and views needed to gives the user the possibility of take a decision.
|
||||||
*
|
*
|
||||||
* @return true if it could resolve the conflict or false otherwise.
|
* @return true if it could resolve the conflict or false otherwise.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import java.time.Instant;
|
|||||||
|
|
||||||
import de.dennisguse.opentracks.data.models.Cadence;
|
import de.dennisguse.opentracks.data.models.Cadence;
|
||||||
import de.dennisguse.opentracks.data.models.Distance;
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
import de.dennisguse.opentracks.data.models.HeartRate;
|
|
||||||
import de.dennisguse.opentracks.data.models.Position;
|
import de.dennisguse.opentracks.data.models.Position;
|
||||||
import de.dennisguse.opentracks.data.models.Speed;
|
import de.dennisguse.opentracks.data.models.Speed;
|
||||||
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingCadence;
|
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingCadence;
|
||||||
@@ -126,6 +125,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
|
|||||||
gpsHandler.resetAggregated();
|
gpsHandler.resetAggregated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
public GpsHandler getGpsHandler() {
|
public GpsHandler getGpsHandler() {
|
||||||
return gpsHandler;
|
return gpsHandler;
|
||||||
}
|
}
|
||||||
@@ -185,17 +185,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
|
|||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SensorData<HeartRate> getHeartRate(Instant now) {
|
|
||||||
SensorData<HeartRate> value = heartRateHandler.getSensorData(now);
|
|
||||||
if (value != null) {
|
|
||||||
|
|
||||||
//TODO Move this check into HeartRateHandler
|
|
||||||
if (value.data().isValid()) return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private SensorData<Cadence> getCadence(Instant now) {
|
private SensorData<Cadence> getCadence(Instant now) {
|
||||||
{
|
{
|
||||||
SensorData<Cadence> value = cyclingCadenceHandler.getSensorData(now);
|
SensorData<Cadence> value = cyclingCadenceHandler.getSensorData(now);
|
||||||
@@ -250,16 +239,19 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SensorDataSet getSensorDataSet(Instant now) {
|
public SensorDataSet getSensorDataSet(Instant now) {
|
||||||
|
//We always need a Position with now
|
||||||
SensorData<Position> gpsSensorData = gpsHandler.getSensorData(now);
|
SensorData<Position> gpsSensorData = gpsHandler.getSensorData(now);
|
||||||
|
if (gpsSensorData != null && gpsSensorData.data() != null) {
|
||||||
var a = temperatureHandler.getSensorData(now);
|
gpsSensorData = new SensorData<>(gpsSensorData.data().with(now), gpsSensorData.sensorNameOrAddress());
|
||||||
var b = altitudeChangeHandler.getSensorData(now);
|
} else {
|
||||||
|
gpsSensorData = new SensorData<>(Position.of(now), "");
|
||||||
|
}
|
||||||
|
|
||||||
return new SensorDataSet(
|
return new SensorDataSet(
|
||||||
gpsSensorData != null ? gpsSensorData : new SensorData<>(Position.of(now), ""), //We always need a Position(now)
|
gpsSensorData,
|
||||||
getSpeed(now),
|
getSpeed(now),
|
||||||
getDistance(now),
|
getDistance(now),
|
||||||
getHeartRate(now),
|
heartRateHandler.getSensorData(now),
|
||||||
temperatureHandler.getSensorData(now),
|
temperatureHandler.getSensorData(now),
|
||||||
getCadence(now),
|
getCadence(now),
|
||||||
cyclingPowerHandler.getSensorData(now),
|
cyclingPowerHandler.getSensorData(now),
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public abstract class Aggregator<InputType, OutputType> {
|
|||||||
previous = next;
|
previous = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void computeValue(Raw<InputType> current);
|
protected abstract void computeValue(@NonNull Raw<InputType> current);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return did we process data from a sensor.
|
* @return did we process data from a sensor.
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package de.dennisguse.opentracks.sensors.sensorData;
|
package de.dennisguse.opentracks.sensors.sensorData;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.data.models.Altitude;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.data.models.AltitudeGainLoss;
|
import de.dennisguse.opentracks.data.models.AltitudeGainLoss;
|
||||||
import de.dennisguse.opentracks.data.models.AtmosphericPressure;
|
import de.dennisguse.opentracks.data.models.AtmosphericPressure;
|
||||||
import de.dennisguse.opentracks.sensors.PressureSensorUtils;
|
import de.dennisguse.opentracks.sensors.PressureSensorUtils;
|
||||||
@@ -14,7 +15,7 @@ public class AggregatorBarometer extends Aggregator<AtmosphericPressure, Altitud
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void computeValue(Raw<AtmosphericPressure> current) {
|
protected void computeValue(@NonNull Raw<AtmosphericPressure> current) {
|
||||||
if (previous == null) {
|
if (previous == null) {
|
||||||
lastAcceptedSensorValue = current.value();
|
lastAcceptedSensorValue = current.value();
|
||||||
output = new AltitudeGainLoss(0f, 0f);
|
output = new AltitudeGainLoss(0f, 0f);
|
||||||
@@ -40,6 +41,4 @@ public class AggregatorBarometer extends Aggregator<AtmosphericPressure, Altitud
|
|||||||
public void resetAggregated() {
|
public void resetAggregated() {
|
||||||
output = null;
|
output = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public record Data(Altitude gain, Altitude loss) {}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -2,6 +2,8 @@ package de.dennisguse.opentracks.sensors.sensorData;
|
|||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.data.models.Cadence;
|
import de.dennisguse.opentracks.data.models.Cadence;
|
||||||
@@ -17,7 +19,7 @@ public class AggregatorCyclingCadence extends Aggregator<CyclingCadenceBluetooth
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void computeValue(Raw<CyclingCadenceBluetooth.CrankData> current) {
|
protected void computeValue(@NonNull Raw<CyclingCadenceBluetooth.CrankData> current) {
|
||||||
if (previous == null) {
|
if (previous == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -2,6 +2,8 @@ package de.dennisguse.opentracks.sensors.sensorData;
|
|||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.data.models.Distance;
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
@@ -20,7 +22,7 @@ public class AggregatorCyclingDistanceSpeed extends Aggregator<CyclingDistanceSp
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void computeValue(Raw<CyclingDistanceSpeedBluetooth.WheelData> current) {
|
protected void computeValue(@NonNull Raw<CyclingDistanceSpeedBluetooth.WheelData> current) {
|
||||||
if (previous == null) {
|
if (previous == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -1,5 +1,7 @@
|
|||||||
package de.dennisguse.opentracks.sensors.sensorData;
|
package de.dennisguse.opentracks.sensors.sensorData;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.data.models.Power;
|
import de.dennisguse.opentracks.data.models.Power;
|
||||||
import de.dennisguse.opentracks.sensors.driver.CyclingPowerBluetooth;
|
import de.dennisguse.opentracks.sensors.driver.CyclingPowerBluetooth;
|
||||||
|
|
||||||
@@ -10,7 +12,7 @@ public class AggregatorCyclingPower extends Aggregator<CyclingPowerBluetooth.Dat
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void computeValue(Raw<CyclingPowerBluetooth.Data> current) {
|
public void computeValue(@NonNull Raw<CyclingPowerBluetooth.Data> current) {
|
||||||
this.output = current.value().power();
|
this.output = current.value().power();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import android.location.Location;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
|
|
||||||
import de.dennisguse.opentracks.data.models.Position;
|
import de.dennisguse.opentracks.data.models.Position;
|
||||||
|
|
||||||
public class AggregatorGPS extends Aggregator<Location, Position> {
|
public class AggregatorGPS extends Aggregator<Location, Position> {
|
||||||
@@ -15,7 +13,7 @@ public class AggregatorGPS extends Aggregator<Location, Position> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void computeValue(Raw<Location> current) {
|
protected void computeValue(@NonNull Raw<Location> current) {
|
||||||
output = Position.of(current.value(), current.time());
|
output = Position.of(current.value(), current.time());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,17 +22,7 @@ public class AggregatorGPS extends Aggregator<Location, Position> {
|
|||||||
/*
|
/*
|
||||||
* GPS data is not an aggregated value, but for now we want to ensure to only save the data once.
|
* GPS data is not an aggregated value, but for now we want to ensure to only save the data once.
|
||||||
* The data is too large to save it more often than needed (i.e., duplicated values).
|
* The data is too large to save it more often than needed (i.e., duplicated values).
|
||||||
* TODO: this behavior can be changed if TrackRecordingManager.insertTrackPoint() would strip GPS data if it was already saved. This would simplify TrackPointCreator.createCurrentTrackPoint()
|
|
||||||
*/
|
*/
|
||||||
output = null;
|
resetOutdated();
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public Position getAggregatedValue(Instant now) {
|
|
||||||
Position value = super.getAggregatedValue(now);
|
|
||||||
if (value == null) value = Position.empty();
|
|
||||||
|
|
||||||
return value.with(now);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package de.dennisguse.opentracks.sensors.sensorData;
|
package de.dennisguse.opentracks.sensors.sensorData;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.data.models.HeartRate;
|
import de.dennisguse.opentracks.data.models.HeartRate;
|
||||||
|
|
||||||
public class AggregatorHeartRate extends Aggregator<HeartRate, HeartRate> {
|
public class AggregatorHeartRate extends Aggregator<HeartRate, HeartRate> {
|
||||||
@@ -9,7 +11,7 @@ public class AggregatorHeartRate extends Aggregator<HeartRate, HeartRate> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void computeValue(Raw<HeartRate> current) {
|
protected void computeValue(@NonNull Raw<HeartRate> current) {
|
||||||
if (current.value().isValid()) {
|
if (current.value().isValid()) {
|
||||||
this.output = current.value();
|
this.output = current.value();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public final class AggregatorRunning extends Aggregator<RunningSpeedAndCadenceBl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void computeValue(Raw<RunningSpeedAndCadenceBluetooth.Data> current) {
|
public void computeValue(@NonNull Raw<RunningSpeedAndCadenceBluetooth.Data> current) {
|
||||||
if (previous == null) {
|
if (previous == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -1,5 +1,7 @@
|
|||||||
package de.dennisguse.opentracks.sensors.sensorData;
|
package de.dennisguse.opentracks.sensors.sensorData;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.data.models.Temperature;
|
import de.dennisguse.opentracks.data.models.Temperature;
|
||||||
@@ -10,7 +12,7 @@ public class AggregatorTemperature extends Aggregator<Temperature, Temperature>
|
|||||||
super(sensorAddress, sensorName);
|
super(sensorAddress, sensorName);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void computeValue(Raw<Temperature> current) {
|
protected void computeValue(@NonNull Raw<Temperature> current) {
|
||||||
this.output = current.value();
|
this.output = current.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet;
|
|||||||
*/
|
*/
|
||||||
public record RecordingData(
|
public record RecordingData(
|
||||||
Track track,
|
Track track,
|
||||||
|
/*
|
||||||
|
* The current view on the SensorData.
|
||||||
|
* May contain data from previous measurements that are not present in SensorDataSet.
|
||||||
|
*/
|
||||||
TrackPoint latestTrackPoint,
|
TrackPoint latestTrackPoint,
|
||||||
SensorDataSet sensorDataSet,
|
SensorDataSet sensorDataSet,
|
||||||
Statistics currentSegment) {
|
Statistics currentSegment) {
|
||||||
|
|||||||
@@ -131,10 +131,10 @@ public class TrackRecordingManager implements SharedPreferences.OnSharedPreferen
|
|||||||
|
|
||||||
RecordingData getDataForUI() {
|
RecordingData getDataForUI() {
|
||||||
Pair<TrackPoint, SensorDataSet> current = trackPointCreator.createCurrentTrackPoint(lastTrackPointUIWithSpeed, lastTrackPointUIWithAltitude, lastStoredTrackPointWithLocation);
|
Pair<TrackPoint, SensorDataSet> current = trackPointCreator.createCurrentTrackPoint(lastTrackPointUIWithSpeed, lastTrackPointUIWithAltitude, lastStoredTrackPointWithLocation);
|
||||||
|
TrackPoint trackPoint = current.first;
|
||||||
|
TrackStatisticsUpdater tmpTrackStatisticsUpdater = new TrackStatisticsUpdater(trackStatisticsUpdater, trackPoint);
|
||||||
|
|
||||||
TrackStatisticsUpdater tmpTrackStatisticsUpdater = new TrackStatisticsUpdater(trackStatisticsUpdater, current.first);
|
TrackPoint TrackPointWithEGM2008 = ALTITUDE_CORRECTION_MANAGER.correctAltitude(context, trackPoint);
|
||||||
|
|
||||||
ALTITUDE_CORRECTION_MANAGER.correctAltitude(context, current.first);
|
|
||||||
|
|
||||||
Track track = contentProviderUtils.getTrack(trackId); //Get copy TODO: Avoid re-loading data from DB
|
Track track = contentProviderUtils.getTrack(trackId); //Get copy TODO: Avoid re-loading data from DB
|
||||||
if (track == null) {
|
if (track == null) {
|
||||||
@@ -145,7 +145,7 @@ public class TrackRecordingManager implements SharedPreferences.OnSharedPreferen
|
|||||||
TrackBuilder trackBuilder = new TrackBuilder(track);
|
TrackBuilder trackBuilder = new TrackBuilder(track);
|
||||||
trackBuilder.setStatistics(tmpTrackStatisticsUpdater.getTrackStatistics());
|
trackBuilder.setStatistics(tmpTrackStatisticsUpdater.getTrackStatistics());
|
||||||
|
|
||||||
return new RecordingData(trackBuilder.getTrack(), current.first, current.second, tmpTrackStatisticsUpdater.getCurrentSegment());
|
return new RecordingData(trackBuilder.getTrack(), TrackPointWithEGM2008, current.second, tmpTrackStatisticsUpdater.getCurrentSegment());
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
|
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
|
||||||
|
|||||||
@@ -48,7 +48,8 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
|
|||||||
|
|
||||||
private static final String TAG = TrackRecordingService.class.getSimpleName();
|
private static final String TAG = TrackRecordingService.class.getSimpleName();
|
||||||
|
|
||||||
private static final Duration RECORDING_DATA_UPDATE_INTERVAL = Duration.ofSeconds(1);
|
@VisibleForTesting
|
||||||
|
public static final Duration RECORDING_DATA_UPDATE_INTERVAL = Duration.ofSeconds(1);
|
||||||
|
|
||||||
public static final RecordingStatus STATUS_DEFAULT = RecordingStatus.notRecording();
|
public static final RecordingStatus STATUS_DEFAULT = RecordingStatus.notRecording();
|
||||||
public static final GpsStatusValue STATUS_GPS_DEFAULT = GpsStatusValue.GPS_NONE;
|
public static final GpsStatusValue STATUS_GPS_DEFAULT = GpsStatusValue.GPS_NONE;
|
||||||
|
|||||||
@@ -102,10 +102,10 @@ public class TrackPointCreator implements SharedPreferences.OnSharedPreferenceCh
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (lastTrackPointUISpeed != null)
|
if (lastTrackPointUISpeed != null)
|
||||||
position.with(lastTrackPointUISpeed.position().speed());
|
position = position.with(lastTrackPointUISpeed.position().speed());
|
||||||
|
|
||||||
if (lastTrackPointUIAltitude != null)
|
if (lastTrackPointUIAltitude != null)
|
||||||
position.with(lastTrackPointUIAltitude.position().altitude());
|
position = position.with(lastTrackPointUIAltitude.position().altitude());
|
||||||
|
|
||||||
TrackPoint currentTrackPoint = new TrackPoint(
|
TrackPoint currentTrackPoint = new TrackPoint(
|
||||||
null,
|
null,
|
||||||
|
|||||||
+2
-1
@@ -5,6 +5,7 @@ import android.util.Log;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ public class RecordingLayoutIO {
|
|||||||
public static List<RecordingLayout> fromCsv(@NonNull String csv, @NonNull Resources resources) {
|
public static List<RecordingLayout> fromCsv(@NonNull String csv, @NonNull Resources resources) {
|
||||||
return CsvLayoutUtils.getCsvLines(csv).stream()
|
return CsvLayoutUtils.getCsvLines(csv).stream()
|
||||||
.map(line -> RecordingLayoutIO.fromCsvLine(line, resources))
|
.map(line -> RecordingLayoutIO.fromCsvLine(line, resources))
|
||||||
.toList();
|
.collect(Collectors.toCollection(ArrayList::new));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RecordingLayout fromCsvLine(@NonNull String csvLine, @NonNull Resources resources) {
|
public static RecordingLayout fromCsvLine(@NonNull String csvLine, @NonNull Resources resources) {
|
||||||
|
|||||||
Reference in New Issue
Block a user