AltitudeSumManager: extracted Barometer driver.

Part of #1424.
This commit is contained in:
Dennis Guse
2023-05-27 09:22:49 +02:00
parent 4906d3f942
commit 6c852091ce
3 changed files with 99 additions and 65 deletions
@@ -1,33 +1,37 @@
package de.dennisguse.opentracks.sensors; package de.dennisguse.opentracks.sensors;
import static org.mockito.Mockito.when;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import de.dennisguse.opentracks.data.models.AtmosphericPressure; import de.dennisguse.opentracks.data.models.AtmosphericPressure;
import de.dennisguse.opentracks.sensors.driver.BarometerInternal;
/** /**
* NOTE: Test data is completely artificial. * NOTE: Test data is completely artificial.
*/ */
@RunWith(MockitoJUnitRunner.class)
public class AltitudeSumManagerTest { public class AltitudeSumManagerTest {
private final AltitudeSumManager subject = new AltitudeSumManager();
private static void addSensorValue(AltitudeSumManager altitudeSumManager, float[] values) { private static void addSensorValue(AltitudeSumManager altitudeSumManager, float[] values) {
for (float f : values) { for (float f : values) {
altitudeSumManager.onSensorValueChanged(AtmosphericPressure.ofHPA(f)); altitudeSumManager.onSensorValueChanged(AtmosphericPressure.ofHPA(f));
} }
} }
@Before @Mock
public void setUp() { BarometerInternal driver;
subject.reset();
}
@Test @Test
public void getAltitudeGainLoss_downhill() { public void getAltitudeGainLoss_downhill() {
// given // given
subject.setConnected(true); AltitudeSumManager subject = new AltitudeSumManager(driver);
when(driver.isConnected()).thenReturn(true);
// then // then
addSensorValue(subject, new float[]{1015f, 1015.01f, 1015.02f, 1015.03f, 1015.04f, 1015.05f, 1015.06f, 1015.07f, 1015.08f, 1015.09f, 1015.10f, 1015.11f, 1015.12f, 1015.13f, 1018f, 1018.1f, 1018.1f, 1018.1f, 1018.1f}); addSensorValue(subject, new float[]{1015f, 1015.01f, 1015.02f, 1015.03f, 1015.04f, 1015.05f, 1015.06f, 1015.07f, 1015.08f, 1015.09f, 1015.10f, 1015.11f, 1015.12f, 1015.13f, 1018f, 1018.1f, 1018.1f, 1018.1f, 1018.1f});
@@ -40,7 +44,9 @@ public class AltitudeSumManagerTest {
@Test @Test
public void sensorUnavailable() { public void sensorUnavailable() {
// given // given
subject.setConnected(false); AltitudeSumManager subject = new AltitudeSumManager(driver);
when(driver.isConnected()).thenReturn(true);
// then // then
subject.onSensorValueChanged(AtmosphericPressure.ofHPA(999f)); subject.onSensorValueChanged(AtmosphericPressure.ofHPA(999f));
@@ -1,10 +1,6 @@
package de.dennisguse.opentracks.sensors; package de.dennisguse.opentracks.sensors;
import android.content.Context; import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Handler; import android.os.Handler;
import android.util.Log; import android.util.Log;
@@ -12,19 +8,18 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import java.util.concurrent.TimeUnit;
import de.dennisguse.opentracks.data.models.AtmosphericPressure; import de.dennisguse.opentracks.data.models.AtmosphericPressure;
import de.dennisguse.opentracks.data.models.TrackPoint; 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). * Estimates the altitude gain and altitude loss using the device's pressure sensor (i.e., barometer).
*/ */
public class AltitudeSumManager implements SensorConnector, SensorEventListener { public class AltitudeSumManager implements SensorConnector {
private static final String TAG = AltitudeSumManager.class.getSimpleName(); private static final String TAG = AltitudeSumManager.class.getSimpleName();
private boolean isConnected = false; private final BarometerInternal driver;
private AtmosphericPressure lastAcceptedSensorValue; private AtmosphericPressure lastAcceptedSensorValue;
@@ -33,16 +28,17 @@ public class AltitudeSumManager implements SensorConnector, SensorEventListener
private Float altitudeGain_m; private Float altitudeGain_m;
private Float altitudeLoss_m; private Float altitudeLoss_m;
public void start(Context context, Handler handler) { public AltitudeSumManager() {
SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); driver = new BarometerInternal();
}
Sensor pressureSensor = sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE); @VisibleForTesting
if (pressureSensor == null) { public AltitudeSumManager(BarometerInternal mock) {
Log.w(TAG, "No pressure sensor available."); this.driver = mock;
isConnected = false; }
} else {
isConnected = sensorManager.registerListener(this, pressureSensor, (int) TimeUnit.SECONDS.toMicros(5), handler); public void start(Context context, Handler handler) {
} driver.connect(context, handler, this);
lastAcceptedSensorValue = null; lastAcceptedSensorValue = null;
reset(); reset();
@@ -51,18 +47,10 @@ public class AltitudeSumManager implements SensorConnector, SensorEventListener
public void stop(Context context) { public void stop(Context context) {
Log.d(TAG, "Stop"); Log.d(TAG, "Stop");
SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); driver.disconnect(context);
sensorManager.unregisterListener(this);
isConnected = false;
reset(); reset();
} }
@VisibleForTesting
public void setConnected(boolean isConnected) {
this.isConnected = isConnected;
}
public void fill(@NonNull TrackPoint trackPoint) { public void fill(@NonNull TrackPoint trackPoint) {
trackPoint.setAltitudeGain(altitudeGain_m); trackPoint.setAltitudeGain(altitudeGain_m);
trackPoint.setAltitudeLoss(altitudeLoss_m); trackPoint.setAltitudeLoss(altitudeLoss_m);
@@ -70,7 +58,7 @@ public class AltitudeSumManager implements SensorConnector, SensorEventListener
@Nullable @Nullable
public Float getAltitudeGain_m() { public Float getAltitudeGain_m() {
return isConnected ? altitudeGain_m : null; return driver.isConnected() ? altitudeGain_m : null;
} }
@VisibleForTesting @VisibleForTesting
@@ -78,21 +66,9 @@ public class AltitudeSumManager implements SensorConnector, SensorEventListener
this.altitudeGain_m = 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;
}
@VisibleForTesting
public void addAltitudeLoss_m(Float altitudeLoss_m) {
this.altitudeLoss_m = this.altitudeLoss_m == null ? 0f : this.altitudeLoss_m;
this.altitudeLoss_m += altitudeLoss_m;
}
@Nullable @Nullable
public Float getAltitudeLoss_m() { public Float getAltitudeLoss_m() {
return isConnected ? altitudeLoss_m : null; return driver.isConnected() ? altitudeLoss_m : null;
} }
@VisibleForTesting @VisibleForTesting
@@ -106,22 +82,7 @@ public class AltitudeSumManager implements SensorConnector, SensorEventListener
altitudeLoss_m = null; altitudeLoss_m = null;
} }
@Override public void onSensorValueChanged(AtmosphericPressure currentSensorValue) {
public void onAccuracyChanged(Sensor sensor, int accuracy) {
Log.w(TAG, "Sensor accuracy changes are (currently) ignored.");
}
@Override
public void onSensorChanged(SensorEvent event) {
if (!isConnected) {
Log.w(TAG, "Not connected to sensor, cannot process data.");
return;
}
onSensorValueChanged(AtmosphericPressure.ofHPA(event.values[0]));
}
@VisibleForTesting
void onSensorValueChanged(AtmosphericPressure currentSensorValue) {
if (lastAcceptedSensorValue == null) { if (lastAcceptedSensorValue == null) {
lastAcceptedSensorValue = currentSensorValue; lastAcceptedSensorValue = currentSensorValue;
lastSeenSensorValue = currentSensorValue; lastSeenSensorValue = currentSensorValue;
@@ -0,0 +1,67 @@
package de.dennisguse.opentracks.sensors.driver;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Handler;
import android.util.Log;
import java.util.concurrent.TimeUnit;
import de.dennisguse.opentracks.data.models.AtmosphericPressure;
import de.dennisguse.opentracks.sensors.AltitudeSumManager;
public class BarometerInternal {
private static final String TAG = BarometerInternal.class.getSimpleName();
private static final int SAMPLING_PERIOD = (int) TimeUnit.SECONDS.toMicros(5);
private AltitudeSumManager observer;
private final SensorEventListener listener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
if (!isConnected()) {
Log.w(TAG, "Not connected to sensor, cannot process data.");
return;
}
observer.onSensorValueChanged(AtmosphericPressure.ofHPA(event.values[0]));
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
Log.w(TAG, "Sensor accuracy changes are (currently) ignored.");
}
};
public void connect(Context context, Handler handler, AltitudeSumManager 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)) {
this.observer = observer;
return;
}
disconnect(context);
}
public void disconnect(Context context) {
SensorManager sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
sensorManager.unregisterListener(listener);
}
public boolean isConnected() {
return observer != null;
}
}