forked from upstream-mirrors/OpenTracks
@@ -0,0 +1,3 @@
|
||||
package de.dennisguse.opentracks.data.models;
|
||||
|
||||
public record AltitudeGainLoss(float gain_m, float loss_m) {}
|
||||
@@ -1,108 +0,0 @@
|
||||
package de.dennisguse.opentracks.sensors;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import de.dennisguse.opentracks.data.models.AtmosphericPressure;
|
||||
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||
import de.dennisguse.opentracks.sensors.driver.BarometerInternal;
|
||||
|
||||
/**
|
||||
* Estimates the altitude gain and altitude loss using the device's pressure sensor (i.e., barometer).
|
||||
*/
|
||||
public class AltitudeSumManager implements SensorConnector {
|
||||
|
||||
private static final String TAG = AltitudeSumManager.class.getSimpleName();
|
||||
|
||||
private final BarometerInternal driver;
|
||||
|
||||
private AtmosphericPressure lastAcceptedSensorValue;
|
||||
|
||||
private AtmosphericPressure lastSeenSensorValue;
|
||||
|
||||
private Float altitudeGain_m;
|
||||
private Float altitudeLoss_m;
|
||||
|
||||
public AltitudeSumManager() {
|
||||
driver = new BarometerInternal();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public AltitudeSumManager(BarometerInternal mock) {
|
||||
this.driver = mock;
|
||||
}
|
||||
|
||||
public void start(Context context, Handler handler) {
|
||||
driver.connect(context, handler, this);
|
||||
|
||||
lastAcceptedSensorValue = null;
|
||||
reset();
|
||||
}
|
||||
|
||||
public void stop(Context context) {
|
||||
Log.d(TAG, "Stop");
|
||||
|
||||
driver.disconnect(context);
|
||||
reset();
|
||||
}
|
||||
|
||||
public void fill(@NonNull TrackPoint trackPoint) {
|
||||
trackPoint.setAltitudeGain(altitudeGain_m);
|
||||
trackPoint.setAltitudeLoss(altitudeLoss_m);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Float getAltitudeGain_m() {
|
||||
return driver.isConnected() ? altitudeGain_m : null;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void setAltitudeGain_m(float altitudeGain_m) {
|
||||
this.altitudeGain_m = altitudeGain_m;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Float getAltitudeLoss_m() {
|
||||
return driver.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;
|
||||
altitudeLoss_m = null;
|
||||
}
|
||||
|
||||
public void onSensorValueChanged(AtmosphericPressure currentSensorValue) {
|
||||
if (lastAcceptedSensorValue == null) {
|
||||
lastAcceptedSensorValue = currentSensorValue;
|
||||
lastSeenSensorValue = currentSensorValue;
|
||||
return;
|
||||
}
|
||||
|
||||
altitudeGain_m = altitudeGain_m != null ? altitudeGain_m : 0;
|
||||
altitudeLoss_m = altitudeLoss_m != null ? altitudeLoss_m : 0;
|
||||
|
||||
PressureSensorUtils.AltitudeChange altitudeChange = PressureSensorUtils.computeChangesWithSmoothing_m(lastAcceptedSensorValue, lastSeenSensorValue, currentSensorValue);
|
||||
if (altitudeChange != null) {
|
||||
altitudeGain_m += altitudeChange.getAltitudeGain_m();
|
||||
|
||||
altitudeLoss_m += altitudeChange.getAltitudeLoss_m();
|
||||
|
||||
lastAcceptedSensorValue = altitudeChange.currentSensorValue();
|
||||
}
|
||||
|
||||
lastSeenSensorValue = currentSensorValue;
|
||||
|
||||
Log.v(TAG, "altitude gain: " + altitudeGain_m + ", altitude loss: " + altitudeLoss_m);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package de.dennisguse.opentracks.sensors;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
|
||||
import de.dennisguse.opentracks.data.models.AtmosphericPressure;
|
||||
import de.dennisguse.opentracks.sensors.driver.BarometerInternal;
|
||||
import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer;
|
||||
import de.dennisguse.opentracks.sensors.sensorData.Raw;
|
||||
|
||||
/**
|
||||
* Estimates the altitude gain and altitude loss using the device's pressure sensor (i.e., barometer).
|
||||
*/
|
||||
public class GainManager implements SensorConnector {
|
||||
|
||||
private static final String TAG = GainManager.class.getSimpleName();
|
||||
|
||||
private final BarometerInternal driver;
|
||||
|
||||
private final SensorManager.SensorDataChangedObserver listener;
|
||||
|
||||
public GainManager(SensorManager.SensorDataChangedObserver listener) {
|
||||
this.listener = listener;
|
||||
driver = new BarometerInternal();
|
||||
}
|
||||
|
||||
public void start(Context context, Handler handler) {
|
||||
driver.connect(context, handler, this);
|
||||
|
||||
if (driver.isConnected()) {
|
||||
listener.onConnect(new AggregatorBarometer("internal"));
|
||||
}
|
||||
}
|
||||
|
||||
public void stop(Context context) {
|
||||
Log.d(TAG, "Stop");
|
||||
|
||||
driver.disconnect(context);
|
||||
listener.onDisconnect(new AggregatorBarometer("internal"));
|
||||
}
|
||||
|
||||
public void onSensorValueChanged(AtmosphericPressure currentSensorValue) {
|
||||
listener.onChange(new Raw<>(currentSensorValue));
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
|
||||
|
||||
private BluetoothRemoteSensorManager bluetoothSensorManager;
|
||||
|
||||
private AltitudeSumManager altitudeSumManager;
|
||||
private GainManager altitudeSumManager;
|
||||
|
||||
private GPSManager gpsManager;
|
||||
|
||||
@@ -58,7 +58,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
|
||||
|
||||
public void start(Context context, Handler handler) {
|
||||
gpsManager = new GPSManager(observer); //TODO Pass listener
|
||||
altitudeSumManager = new AltitudeSumManager();
|
||||
altitudeSumManager = new GainManager(listener);
|
||||
bluetoothSensorManager = new BluetoothRemoteSensorManager(context, handler, listener);
|
||||
|
||||
onSharedPreferenceChanged(null, null);
|
||||
@@ -82,7 +82,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
|
||||
}
|
||||
|
||||
public SensorDataSet fill(TrackPoint trackPoint) {
|
||||
altitudeSumManager.fill(trackPoint);
|
||||
sensorDataSet.fillTrackPoint(trackPoint);
|
||||
return new SensorDataSet(sensorDataSet);
|
||||
}
|
||||
@@ -93,7 +92,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
|
||||
return;
|
||||
}
|
||||
sensorDataSet.reset();
|
||||
altitudeSumManager.reset();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@@ -108,13 +106,13 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
|
||||
|
||||
@Deprecated
|
||||
@VisibleForTesting
|
||||
public AltitudeSumManager getAltitudeSumManager() {
|
||||
public GainManager getAltitudeSumManager() {
|
||||
return altitudeSumManager;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@VisibleForTesting
|
||||
public void setAltitudeSumManager(AltitudeSumManager altitudeSumManager) {
|
||||
public void setAltitudeSumManager(GainManager altitudeSumManager) {
|
||||
this.altitudeSumManager = altitudeSumManager;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import android.util.Log;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import de.dennisguse.opentracks.data.models.AtmosphericPressure;
|
||||
import de.dennisguse.opentracks.sensors.AltitudeSumManager;
|
||||
import de.dennisguse.opentracks.sensors.GainManager;
|
||||
|
||||
public class BarometerInternal {
|
||||
|
||||
@@ -19,7 +19,7 @@ public class BarometerInternal {
|
||||
|
||||
private static final int SAMPLING_PERIOD = (int) TimeUnit.SECONDS.toMicros(5);
|
||||
|
||||
private AltitudeSumManager observer;
|
||||
private GainManager observer;
|
||||
|
||||
private final SensorEventListener listener = new SensorEventListener() {
|
||||
@Override
|
||||
@@ -38,14 +38,13 @@ public class BarometerInternal {
|
||||
}
|
||||
};
|
||||
|
||||
public void connect(Context context, Handler handler, AltitudeSumManager observer) {
|
||||
public void connect(Context context, Handler handler, GainManager observer) {
|
||||
this.observer = observer;
|
||||
SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
|
||||
Sensor pressureSensor = sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE);
|
||||
if (pressureSensor == null) {
|
||||
Log.w(TAG, "No pressure sensor available.");
|
||||
this.observer = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (sensorManager.registerListener(listener, pressureSensor, SAMPLING_PERIOD, handler)) {
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package de.dennisguse.opentracks.sensors.sensorData;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import de.dennisguse.opentracks.data.models.Altitude;
|
||||
import de.dennisguse.opentracks.data.models.AltitudeGainLoss;
|
||||
import de.dennisguse.opentracks.data.models.AtmosphericPressure;
|
||||
import de.dennisguse.opentracks.sensors.PressureSensorUtils;
|
||||
|
||||
public class AggregatorBarometer extends Aggregator<AtmosphericPressure, AltitudeGainLoss> {
|
||||
|
||||
private AtmosphericPressure lastAcceptedSensorValue;
|
||||
|
||||
public AggregatorBarometer(String sensorAddress) {
|
||||
super(sensorAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void computeValue(Raw<AtmosphericPressure> current) {
|
||||
if (previous == null) {
|
||||
lastAcceptedSensorValue = current.value();
|
||||
value = getNoneValue();
|
||||
return;
|
||||
}
|
||||
|
||||
PressureSensorUtils.AltitudeChange altitudeChange = PressureSensorUtils.computeChangesWithSmoothing_m(lastAcceptedSensorValue, previous.value(), current.value());
|
||||
if (altitudeChange != null) {
|
||||
value = new AltitudeGainLoss(value.gain_m() + altitudeChange.getAltitudeGain_m(), value.loss_m() + altitudeChange.getAltitudeLoss_m());
|
||||
|
||||
lastAcceptedSensorValue = altitudeChange.currentSensorValue();
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected AltitudeGainLoss getNoneValue() {
|
||||
return new AltitudeGainLoss(0f, 0f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
value = getNoneValue();
|
||||
}
|
||||
|
||||
public record Data(Altitude gain, Altitude loss) {}
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
package de.dennisguse.opentracks.sensors.sensorData;
|
||||
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import de.dennisguse.opentracks.data.models.AtmosphericPressure;
|
||||
import de.dennisguse.opentracks.data.models.Cadence;
|
||||
import de.dennisguse.opentracks.data.models.HeartRate;
|
||||
import de.dennisguse.opentracks.data.models.Power;
|
||||
@@ -36,6 +38,9 @@ public final class SensorDataSet {
|
||||
@VisibleForTesting
|
||||
public AggregatorRunning runningDistanceSpeedCadence;
|
||||
|
||||
@VisibleForTesting
|
||||
public AggregatorBarometer barometer;
|
||||
|
||||
public SensorDataSet() {
|
||||
}
|
||||
|
||||
@@ -45,6 +50,7 @@ public final class SensorDataSet {
|
||||
this.cyclingDistanceSpeed = toCopy.cyclingDistanceSpeed;
|
||||
this.cyclingPower = toCopy.cyclingPower;
|
||||
this.runningDistanceSpeedCadence = toCopy.runningDistanceSpeedCadence;
|
||||
this.barometer = toCopy.barometer;
|
||||
}
|
||||
|
||||
public Pair<HeartRate, String> getHeartRate() {
|
||||
@@ -113,8 +119,12 @@ public final class SensorDataSet {
|
||||
this.cyclingPower.add((Raw<Power>) data);
|
||||
return;
|
||||
}
|
||||
if (value instanceof AtmosphericPressure) {
|
||||
this.barometer.add((Raw<AtmosphericPressure>) data);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException(data.getClass().getCanonicalName());
|
||||
throw new UnsupportedOperationException(data.getClass().getCanonicalName() + " " + data.value().getClass().getCanonicalName());
|
||||
}
|
||||
|
||||
public void remove(@NonNull Aggregator<?, ?> type) {
|
||||
@@ -122,11 +132,13 @@ public final class SensorDataSet {
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
Log.i(TAG, "Removing all aggregators");
|
||||
this.heartRate = null;
|
||||
this.cyclingCadence = null;
|
||||
this.cyclingDistanceSpeed = null;
|
||||
this.cyclingPower = null;
|
||||
this.runningDistanceSpeedCadence = null;
|
||||
this.barometer = null;
|
||||
}
|
||||
|
||||
public void fillTrackPoint(TrackPoint trackPoint) {
|
||||
@@ -153,17 +165,27 @@ public final class SensorDataSet {
|
||||
if (runningDistanceSpeedCadence != null && runningDistanceSpeedCadence.hasValue()) {
|
||||
trackPoint.setSensorDistance(runningDistanceSpeedCadence.getValue().distance());
|
||||
}
|
||||
|
||||
if (barometer != null && barometer.hasValue()) {
|
||||
trackPoint.setAltitudeGain(barometer.getValue().gain_m());
|
||||
trackPoint.setAltitudeLoss(barometer.getValue().loss_m());
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
Log.i(TAG, "Resetting data");
|
||||
|
||||
if (heartRate != null) heartRate.reset();
|
||||
if (cyclingCadence != null) cyclingCadence.reset();
|
||||
if (cyclingDistanceSpeed != null) cyclingDistanceSpeed.reset();
|
||||
if (cyclingPower != null) cyclingPower.reset();
|
||||
if (runningDistanceSpeedCadence != null) runningDistanceSpeedCadence.reset();
|
||||
if (barometer != null) barometer.reset();
|
||||
}
|
||||
|
||||
private void set(@NonNull Aggregator<?, ?> type, @Nullable Aggregator<?, ?> sensorData) {
|
||||
Log.i(TAG, "Setting aggregator " + type.getClass().getCanonicalName());
|
||||
|
||||
if (type instanceof AggregatorHeartRate) {
|
||||
heartRate = (AggregatorHeartRate) sensorData;
|
||||
return;
|
||||
@@ -184,6 +206,10 @@ public final class SensorDataSet {
|
||||
runningDistanceSpeedCadence = (AggregatorRunning) sensorData;
|
||||
return;
|
||||
}
|
||||
if (type instanceof AggregatorBarometer) {
|
||||
barometer = (AggregatorBarometer) sensorData;
|
||||
return;
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException(type.getClass().getCanonicalName());
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ public class TrackPointCreator implements SharedPreferences.OnSharedPreferenceCh
|
||||
|
||||
@NonNull
|
||||
private Clock clock = new MonotonicClock();
|
||||
private SensorManager sensorManager;
|
||||
private final SensorManager sensorManager;
|
||||
|
||||
public TrackPointCreator(Callback service) {
|
||||
this.service = service;
|
||||
@@ -64,7 +64,7 @@ public class TrackPointCreator implements SharedPreferences.OnSharedPreferenceCh
|
||||
return sensorManager.fill(trackPoint);
|
||||
}
|
||||
|
||||
public synchronized void stop() {
|
||||
public void stop() {
|
||||
sensorManager.stop(context);
|
||||
this.context = null;
|
||||
}
|
||||
@@ -139,11 +139,6 @@ public class TrackPointCreator implements SharedPreferences.OnSharedPreferenceCh
|
||||
return sensorManager;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void setSensorManager(SensorManager sensorManager) {
|
||||
this.sensorManager = sensorManager;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void setClock(@NonNull String time) {
|
||||
this.clock = Clock.fixed(Instant.parse(time), ZoneId.of("CET"));
|
||||
|
||||
Reference in New Issue
Block a user