Compare commits

..

4 Commits

Author SHA1 Message Date
Dennis Guse 979178a6f1 Bugfix: crash when exporting zero tracks.
Fixes #2285
2026-02-21 14:40:17 +01:00
Dennis Guse a92a1e7838 Bugfix: layout's could not be deleted.
Introduced in e9deebea6c

Fixes #2283
2026-02-19 07:54:50 +01:00
Dennis Guse 8cba53cfe4 Cleanup. 2026-02-17 06:27:11 +01:00
Dennis Guse fcedb9c444 Bugfix: crash when heartrate sensor did not send data continuously.
Introduced in 1a14fed287

Fixes #2281.
2026-02-17 06:26:43 +01:00
12 changed files with 38 additions and 27 deletions
@@ -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;
@@ -186,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);
@@ -263,7 +251,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
gpsSensorData, 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,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.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;
@@ -13,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);
@@ -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;
} }
@@ -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;
} }
@@ -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();
} }
} }
@@ -2,6 +2,8 @@ package de.dennisguse.opentracks.sensors.sensorData;
import android.location.Location; import android.location.Location;
import androidx.annotation.NonNull;
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> {
@@ -11,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());
} }
@@ -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;
} }
@@ -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();
} }
@@ -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) {