forked from upstream-mirrors/OpenTracks
GPS is now optional: data source (internal, none) be selected in settings.
Migrated to GPSHandler. Fixes #1279.
This commit is contained in:
+8
-5
@@ -77,6 +77,7 @@ import de.dennisguse.opentracks.sensors.sensorData.AggregatorHeartRate;
|
|||||||
import de.dennisguse.opentracks.sensors.sensorData.AggregatorTemperature;
|
import de.dennisguse.opentracks.sensors.sensorData.AggregatorTemperature;
|
||||||
import de.dennisguse.opentracks.services.TrackRecordingService;
|
import de.dennisguse.opentracks.services.TrackRecordingService;
|
||||||
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
|
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
|
||||||
|
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Export a track to {@link TrackFileFormat} and verify that the import is identical.
|
* Export a track to {@link TrackFileFormat} and verify that the import is identical.
|
||||||
@@ -88,7 +89,7 @@ import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
|
|||||||
public class ExportImportTest {
|
public class ExportImportTest {
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(5, TimeUnit.SECONDS);
|
public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(50, TimeUnit.SECONDS); //TODO 5s
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public GrantPermissionRule mGrantPermissionRule = TestUtil.createGrantPermissionRule();
|
public GrantPermissionRule mGrantPermissionRule = TestUtil.createGrantPermissionRule();
|
||||||
@@ -97,13 +98,15 @@ public class ExportImportTest {
|
|||||||
@Rule
|
@Rule
|
||||||
public TimezoneRule timezoneRule = new TimezoneRule(TimeZone.getTimeZone("Europe/Berlin"));
|
public TimezoneRule timezoneRule = new TimezoneRule(TimeZone.getTimeZone("Europe/Berlin"));
|
||||||
|
|
||||||
|
private static final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void preSetUp() {
|
public static void preSetUp() {
|
||||||
// Prepare looper for Android's message queue
|
// Prepare looper for Android's message queue
|
||||||
if (Looper.myLooper() == null) Looper.prepare();
|
if (Looper.myLooper() == null) Looper.prepare();
|
||||||
}
|
|
||||||
|
|
||||||
private final Context context = ApplicationProvider.getApplicationContext();
|
PreferencesUtils.resetPreferences(context, true);
|
||||||
|
}
|
||||||
|
|
||||||
private final ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
|
private final ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
|
||||||
|
|
||||||
@@ -161,7 +164,7 @@ public class ExportImportTest {
|
|||||||
"Marker 1 desc",
|
"Marker 1 desc",
|
||||||
"Marker 1 typeLocalized",
|
"Marker 1 typeLocalized",
|
||||||
new Position(
|
new Position(
|
||||||
Instant.parse("2020-02-02T02:02:03Z"),
|
Instant.parse("2020-02-02T02:02:03Z"),
|
||||||
3.1234567, 14.0014567,
|
3.1234567, 14.0014567,
|
||||||
Distance.of(10),
|
Distance.of(10),
|
||||||
Altitude.WGS84.of(1020.25),
|
Altitude.WGS84.of(1020.25),
|
||||||
@@ -756,6 +759,6 @@ public class ExportImportTest {
|
|||||||
mockAltitudeChange(trackPointCreator, altitudeGain);
|
mockAltitudeChange(trackPointCreator, altitudeGain);
|
||||||
|
|
||||||
trackPointCreator.setClock(time);
|
trackPointCreator.setClock(time);
|
||||||
trackPointCreator.getSensorManager().getGpsManager().onDataReceived(location);
|
trackPointCreator.getSensorManager().getGpsHandler().onDataReceived(location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+5
-2
@@ -9,6 +9,7 @@ import android.location.Location;
|
|||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.core.location.LocationManagerCompat;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import androidx.test.filters.MediumTest;
|
import androidx.test.filters.MediumTest;
|
||||||
@@ -43,6 +44,7 @@ import de.dennisguse.opentracks.data.models.Track;
|
|||||||
import de.dennisguse.opentracks.data.models.TrackPoint;
|
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||||
import de.dennisguse.opentracks.io.file.importer.TrackPointAssert;
|
import de.dennisguse.opentracks.io.file.importer.TrackPointAssert;
|
||||||
import de.dennisguse.opentracks.sensors.SensorManager;
|
import de.dennisguse.opentracks.sensors.SensorManager;
|
||||||
|
import de.dennisguse.opentracks.sensors.driver.GpsInternal;
|
||||||
import de.dennisguse.opentracks.sensors.driver.RunningSpeedAndCadenceBluetooth;
|
import de.dennisguse.opentracks.sensors.driver.RunningSpeedAndCadenceBluetooth;
|
||||||
import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer;
|
import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer;
|
||||||
import de.dennisguse.opentracks.sensors.sensorData.AggregatorHeartRate;
|
import de.dennisguse.opentracks.sensors.sensorData.AggregatorHeartRate;
|
||||||
@@ -151,7 +153,8 @@ public class TrackRecordingServiceRecordingTest {
|
|||||||
Track.Id trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
|
||||||
//We do not want the real GPS to interfere.
|
//We do not want the real GPS to interfere.
|
||||||
trackPointCreator.getSensorManager().getGpsManager().driver.disconnect();
|
GpsInternal gpsInternal = (GpsInternal)trackPointCreator.getSensorManager().getGpsHandler().driver;
|
||||||
|
LocationManagerCompat.removeUpdates(gpsInternal.locationManager, gpsInternal.locationListenerCompat);
|
||||||
|
|
||||||
String gps1 = "2020-02-02T02:02:03Z";
|
String gps1 = "2020-02-02T02:02:03Z";
|
||||||
sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15);
|
sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15);
|
||||||
@@ -995,6 +998,6 @@ public class TrackRecordingServiceRecordingTest {
|
|||||||
location.setSpeed(speed);
|
location.setSpeed(speed);
|
||||||
|
|
||||||
trackPointCreator.setClock(time);
|
trackPointCreator.setClock(time);
|
||||||
trackPointCreator.getSensorManager().getGpsManager().onDataReceived(location);
|
trackPointCreator.getSensorManager().getGpsHandler().onDataReceived(location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+57
-93
@@ -1,9 +1,7 @@
|
|||||||
package de.dennisguse.opentracks.sensors;
|
package de.dennisguse.opentracks.sensors;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.os.Handler;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
@@ -12,95 +10,25 @@ import androidx.annotation.VisibleForTesting;
|
|||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.data.models.Distance;
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
import de.dennisguse.opentracks.data.models.Position;
|
import de.dennisguse.opentracks.data.models.Position;
|
||||||
import de.dennisguse.opentracks.sensors.driver.DriverObserver;
|
import de.dennisguse.opentracks.sensors.driver.Driver;
|
||||||
import de.dennisguse.opentracks.sensors.driver.GpsInternal;
|
import de.dennisguse.opentracks.sensors.driver.GpsInternal;
|
||||||
|
import de.dennisguse.opentracks.sensors.driver.SensorType;
|
||||||
import de.dennisguse.opentracks.sensors.sensorData.AggregatorGPS;
|
import de.dennisguse.opentracks.sensors.sensorData.AggregatorGPS;
|
||||||
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
|
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
|
||||||
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||||
|
|
||||||
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
|
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
|
||||||
public class GpsManager implements DriverObserver<Location>, GpsStatusManager.GpsStatusListener, SharedPreferences.OnSharedPreferenceChangeListener {
|
public class GpsHandler extends SensorHandler<Location, Position> {
|
||||||
|
|
||||||
private final String TAG = GpsManager.class.getSimpleName();
|
private final String TAG = GpsHandler.class.getSimpleName();
|
||||||
|
|
||||||
//TODO Refactor to just pass information via SensorManager.
|
//TODO Refactor to just pass information via SensorManager.
|
||||||
private TrackPointCreator trackPointCreator;
|
private TrackPointCreator trackPointCreator;
|
||||||
|
|
||||||
private SensorManager observer;
|
|
||||||
private Context context;
|
|
||||||
private Handler handler;
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
public GpsInternal driver;
|
|
||||||
private GpsStatusManager gpsStatusManager;
|
private GpsStatusManager gpsStatusManager;
|
||||||
private Distance thresholdHorizontalAccuracy;
|
private Distance thresholdHorizontalAccuracy;
|
||||||
|
|
||||||
private AggregatorGPS aggregatorGPS;
|
private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (sharedPreferences, key) -> {
|
||||||
|
|
||||||
public GpsManager(TrackPointCreator trackPointCreator, SensorManager observer) {
|
|
||||||
this.trackPointCreator = trackPointCreator;
|
|
||||||
this.observer = observer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start(@NonNull Context context, @NonNull Handler handler) {
|
|
||||||
this.context = context;
|
|
||||||
this.handler = handler;
|
|
||||||
|
|
||||||
onSharedPreferenceChanged(null, null);
|
|
||||||
|
|
||||||
gpsStatusManager = new GpsStatusManager(context, this, handler);
|
|
||||||
|
|
||||||
this.aggregatorGPS = new AggregatorGPS("internal");
|
|
||||||
|
|
||||||
this.driver = new GpsInternal(this);
|
|
||||||
this.driver.connect(context, handler, "internal");
|
|
||||||
gpsStatusManager.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings({"MissingPermission"})
|
|
||||||
public void stop() {
|
|
||||||
if (driver.isConnected()) {
|
|
||||||
driver.disconnect();
|
|
||||||
}
|
|
||||||
driver = null;
|
|
||||||
this.context = null;
|
|
||||||
handler = null;
|
|
||||||
|
|
||||||
gpsStatusManager.stop();
|
|
||||||
gpsStatusManager = null;
|
|
||||||
|
|
||||||
this.aggregatorGPS = null;
|
|
||||||
observer = null;
|
|
||||||
|
|
||||||
trackPointCreator = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO Exposed for refactoring. Is this necessary?
|
|
||||||
@Deprecated
|
|
||||||
AggregatorGPS getAggregatorGPS() {
|
|
||||||
return aggregatorGPS;
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO Exposed for refactoring. This is very ugly.
|
|
||||||
@Deprecated
|
|
||||||
void setAggregatorGPS() {
|
|
||||||
this.aggregatorGPS = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
|
||||||
boolean registerListener = false;
|
|
||||||
|
|
||||||
if (PreferencesUtils.isKey(R.string.min_sampling_interval_key, key)) {
|
|
||||||
registerListener = true;
|
|
||||||
|
|
||||||
if (gpsStatusManager != null) {
|
|
||||||
gpsStatusManager.onMinSamplingIntervalChanged(PreferencesUtils.getMinSamplingInterval());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (PreferencesUtils.isKey(R.string.recording_gps_accuracy_key, key)) {
|
|
||||||
thresholdHorizontalAccuracy = PreferencesUtils.getThresholdHorizontalAccuracy();
|
|
||||||
}
|
|
||||||
if (PreferencesUtils.isKey(R.string.recording_distance_interval_key, key)) {
|
if (PreferencesUtils.isKey(R.string.recording_distance_interval_key, key)) {
|
||||||
if (gpsStatusManager != null) {
|
if (gpsStatusManager != null) {
|
||||||
Distance gpsMinDistance = PreferencesUtils.getRecordingDistanceInterval();
|
Distance gpsMinDistance = PreferencesUtils.getRecordingDistanceInterval();
|
||||||
@@ -108,49 +36,85 @@ public class GpsManager implements DriverObserver<Location>, GpsStatusManager.Gp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (registerListener && driver != null && driver.isConnected()) {
|
if (PreferencesUtils.isKey(R.string.recording_gps_accuracy_key, key)) {
|
||||||
driver.disconnect();
|
thresholdHorizontalAccuracy = PreferencesUtils.getThresholdHorizontalAccuracy();
|
||||||
driver.connect(context, handler, "internal");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
if (PreferencesUtils.isKey(R.string.min_sampling_interval_key, key)) {
|
||||||
public void onGpsStatusChanged(GpsStatusValue currentStatus) {
|
if (gpsStatusManager != null) {
|
||||||
trackPointCreator.sendGpsStatus(currentStatus);
|
gpsStatusManager.onMinSamplingIntervalChanged(PreferencesUtils.getMinSamplingInterval());
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO
|
||||||
|
connect();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public GpsHandler(SensorManager sensorManager, TrackPointCreator trackPointCreator) {
|
||||||
|
super(sensorManager);
|
||||||
|
this.trackPointCreator = trackPointCreator;
|
||||||
|
gpsStatusManager = new GpsStatusManager(sensorManager.getContext(), trackPointCreator::sendGpsStatus, sensorManager.getHandler());
|
||||||
|
|
||||||
|
sharedPreferenceChangeListener.onSharedPreferenceChanged(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConnected(String sensorAddress, String sensorName) {
|
public void onConnected(String sensorAddress, String sensorName) {
|
||||||
|
super.onConnected(sensorAddress, sensorName);
|
||||||
gpsStatusManager.onGpsEnabled();
|
gpsStatusManager.onGpsEnabled();
|
||||||
}
|
gpsStatusManager.start();
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onConnectionLost() {
|
|
||||||
gpsStatusManager.onGpsDisabled();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisconnected() {
|
public void onDisconnected() {
|
||||||
|
super.onDisconnected();
|
||||||
|
gpsStatusManager.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSensorDeactivated() {
|
||||||
|
super.onSensorDeactivated();
|
||||||
gpsStatusManager.onGpsDisabled();
|
gpsStatusManager.onGpsDisabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDataReceived(Location location) {
|
public void onDataReceived(Location location) {
|
||||||
// Send each update to the status; please note that this TrackPoint is not stored.
|
// Send each update to the status; please note that this TrackPoint is not stored.
|
||||||
Position position = Position.of(location, observer.getNow());
|
Position position = Position.of(location, trackPointCreator.getNow());
|
||||||
gpsStatusManager.onNewTrackPoint(position);
|
gpsStatusManager.onNewTrackPoint(position);
|
||||||
|
|
||||||
|
//TODO We could move the following check into the AggregatorGPS
|
||||||
if (!position.hasValidLocation()) {
|
if (!position.hasValidLocation()) {
|
||||||
Log.w(TAG, "Ignore newTrackPoint. Location is invalid.");
|
Log.w(TAG, "Ignore newTrackPoint. Location is invalid.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!position.fulfillsAccuracy(thresholdHorizontalAccuracy)) {
|
if (!position.fulfillsAccuracy(thresholdHorizontalAccuracy)) {
|
||||||
Log.d(TAG, "Ignore newTrackPoint. Poor accuracy.");
|
Log.d(TAG, "Ignore newTrackPoint. Poor accuracy.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
aggregatorGPS.add(observer.getNow(), position);
|
super.onDataReceived(location);
|
||||||
observer.onChange();
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
protected Driver createDriverInternal() {
|
||||||
|
return new GpsInternal(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
protected AggregatorGPS createAggregator(String sensorAddress, String sensorName) {
|
||||||
|
return new AggregatorGPS(sensorAddress, sensorName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getSensorPreferenceKey() {
|
||||||
|
return R.string.settings_sensor_bluetooth_gps_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getSensorPreferenceDefaultValue() {
|
||||||
|
return SensorType.INTERNAL.getPreferenceValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,7 @@ class GpsStatusManager {
|
|||||||
private Duration signalLostThreshold;
|
private Duration signalLostThreshold;
|
||||||
|
|
||||||
private GpsStatusValue gpsStatus = GpsStatusValue.GPS_NONE;
|
private GpsStatusValue gpsStatus = GpsStatusValue.GPS_NONE;
|
||||||
private GpsStatusListener client;
|
private GpsStatusListener observer;
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -44,8 +44,8 @@ class GpsStatusManager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
public GpsStatusManager(Context context, GpsStatusListener client, Handler handler) {
|
public GpsStatusManager(Context context, GpsStatusListener observer, Handler handler) {
|
||||||
this.client = client;
|
this.observer = observer;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ class GpsStatusManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void start() {
|
public void start() {
|
||||||
client.onGpsStatusChanged(GpsStatusValue.GPS_ENABLED);
|
observer.onGpsStatusChanged(GpsStatusValue.GPS_ENABLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -62,9 +62,7 @@ class GpsStatusManager {
|
|||||||
*/
|
*/
|
||||||
public void stop() {
|
public void stop() {
|
||||||
stopTimer();
|
stopTimer();
|
||||||
client.onGpsStatusChanged(GpsStatusValue.GPS_NONE);
|
observer.onGpsStatusChanged(GpsStatusValue.GPS_NONE);
|
||||||
client = null;
|
|
||||||
handler = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -159,8 +157,8 @@ class GpsStatusManager {
|
|||||||
|
|
||||||
private void setGpsStatus(GpsStatusValue current) {
|
private void setGpsStatus(GpsStatusValue current) {
|
||||||
gpsStatus = current;
|
gpsStatus = current;
|
||||||
if (client != null) {
|
if (observer != null) {
|
||||||
client.onGpsStatusChanged(current);
|
observer.onGpsStatusChanged(current);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import java.time.Instant;
|
|||||||
|
|
||||||
import de.dennisguse.opentracks.sensors.driver.Driver;
|
import de.dennisguse.opentracks.sensors.driver.Driver;
|
||||||
import de.dennisguse.opentracks.sensors.driver.DriverObserver;
|
import de.dennisguse.opentracks.sensors.driver.DriverObserver;
|
||||||
|
import de.dennisguse.opentracks.sensors.driver.SensorType;
|
||||||
import de.dennisguse.opentracks.sensors.sensorData.Aggregator;
|
import de.dennisguse.opentracks.sensors.sensorData.Aggregator;
|
||||||
import de.dennisguse.opentracks.sensors.sensorData.SensorData;
|
import de.dennisguse.opentracks.sensors.sensorData.SensorData;
|
||||||
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||||
@@ -19,7 +20,8 @@ public abstract class SensorHandler<AggregatorInput, AggregatorOutput> implement
|
|||||||
|
|
||||||
private final SensorManager sensorManager;
|
private final SensorManager sensorManager;
|
||||||
|
|
||||||
private Driver driver;
|
@VisibleForTesting
|
||||||
|
public Driver driver;
|
||||||
|
|
||||||
protected Aggregator<AggregatorInput, AggregatorOutput> aggregator;
|
protected Aggregator<AggregatorInput, AggregatorOutput> aggregator;
|
||||||
|
|
||||||
@@ -30,7 +32,7 @@ public abstract class SensorHandler<AggregatorInput, AggregatorOutput> implement
|
|||||||
void connect() {
|
void connect() {
|
||||||
disconnect();
|
disconnect();
|
||||||
|
|
||||||
String address = PreferencesUtils.getString(getSensorPreferenceKey(), PreferencesUtils.getBluetoothSensorAddressNone());
|
String address = PreferencesUtils.getString(getSensorPreferenceKey(), getSensorPreferenceDefaultValue());
|
||||||
|
|
||||||
switch (PreferencesUtils.getSensorType(address)) {
|
switch (PreferencesUtils.getSensorType(address)) {
|
||||||
case NONE -> {
|
case NONE -> {
|
||||||
@@ -71,6 +73,10 @@ public abstract class SensorHandler<AggregatorInput, AggregatorOutput> implement
|
|||||||
|
|
||||||
protected abstract int getSensorPreferenceKey();
|
protected abstract int getSensorPreferenceKey();
|
||||||
|
|
||||||
|
protected String getSensorPreferenceDefaultValue() {
|
||||||
|
return SensorType.NONE.getPreferenceValue();
|
||||||
|
}
|
||||||
|
|
||||||
protected Context getContext() {
|
protected Context getContext() {
|
||||||
return sensorManager.getContext();
|
return sensorManager.getContext();
|
||||||
}
|
}
|
||||||
@@ -106,6 +112,9 @@ public abstract class SensorHandler<AggregatorInput, AggregatorOutput> implement
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDataReceived(AggregatorInput value) {
|
public void onDataReceived(AggregatorInput value) {
|
||||||
|
if (aggregator == null) {
|
||||||
|
throw new RuntimeException("Received data while being disconnected.");
|
||||||
|
}
|
||||||
SensorHandler.this.aggregator.add(sensorManager.getNow(), value);
|
SensorHandler.this.aggregator.add(sensorManager.getNow(), value);
|
||||||
sensorManager.onChange();
|
sensorManager.onChange();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import de.dennisguse.opentracks.data.models.Speed;
|
|||||||
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingCadence;
|
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingCadence;
|
||||||
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingDistanceSpeed;
|
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingDistanceSpeed;
|
||||||
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingPower;
|
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingPower;
|
||||||
import de.dennisguse.opentracks.sensors.sensorData.AggregatorGPS;
|
|
||||||
import de.dennisguse.opentracks.sensors.sensorData.AggregatorHeartRate;
|
import de.dennisguse.opentracks.sensors.sensorData.AggregatorHeartRate;
|
||||||
import de.dennisguse.opentracks.sensors.sensorData.AggregatorRunning;
|
import de.dennisguse.opentracks.sensors.sensorData.AggregatorRunning;
|
||||||
import de.dennisguse.opentracks.sensors.sensorData.AggregatorTemperature;
|
import de.dennisguse.opentracks.sensors.sensorData.AggregatorTemperature;
|
||||||
@@ -51,14 +50,14 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
|
|||||||
|
|
||||||
private AltitudeChangeHandler altitudeChangeHandler;
|
private AltitudeChangeHandler altitudeChangeHandler;
|
||||||
|
|
||||||
private GpsManager gpsManager;
|
private GpsHandler gpsHandler;
|
||||||
|
|
||||||
public SensorManager(TrackPointCreator observer) {
|
public SensorManager(TrackPointCreator observer) {
|
||||||
this.observer = observer;
|
this.observer = observer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start(Context context, Handler handler) {
|
public void start(Context context, Handler handler) {
|
||||||
if (gpsManager != null) {
|
if (isStarted()) {
|
||||||
throw new RuntimeException("SensorManager cannot be started twice; stop first.");
|
throw new RuntimeException("SensorManager cannot be started twice; stop first.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +65,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
|
|
||||||
gpsManager = new GpsManager(observer, this);
|
gpsHandler = new GpsHandler(this, observer);
|
||||||
altitudeChangeHandler = new AltitudeChangeHandler(this);
|
altitudeChangeHandler = new AltitudeChangeHandler(this);
|
||||||
heartRateHandler = new HeartRateHandler(this);
|
heartRateHandler = new HeartRateHandler(this);
|
||||||
temperatureHandler = new TemperatureHandler(this);
|
temperatureHandler = new TemperatureHandler(this);
|
||||||
@@ -76,8 +75,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
|
|||||||
runningSpeedCadenceDistanceHandler = new RunningSpeedCadenceDistanceHandler(this);
|
runningSpeedCadenceDistanceHandler = new RunningSpeedCadenceDistanceHandler(this);
|
||||||
|
|
||||||
onSharedPreferenceChanged(null, null);
|
onSharedPreferenceChanged(null, null);
|
||||||
|
|
||||||
gpsManager.start(context, handler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
@@ -104,15 +101,15 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
|
|||||||
altitudeChangeHandler.disconnect();
|
altitudeChangeHandler.disconnect();
|
||||||
altitudeChangeHandler = null;
|
altitudeChangeHandler = null;
|
||||||
|
|
||||||
gpsManager.stop();
|
gpsHandler.disconnect();
|
||||||
gpsManager = null;
|
gpsHandler = null;
|
||||||
|
|
||||||
context = null;
|
context = null;
|
||||||
handler = null;
|
handler = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
if (gpsManager == null || altitudeChangeHandler == null) {
|
if (gpsHandler == null || altitudeChangeHandler == null) {
|
||||||
Log.d(TAG, "No recording running and no reset necessary.");
|
Log.d(TAG, "No recording running and no reset necessary.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -126,11 +123,11 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
|
|||||||
cyclingPowerHandler.resetAggregated();
|
cyclingPowerHandler.resetAggregated();
|
||||||
runningSpeedCadenceDistanceHandler.resetAggregated();
|
runningSpeedCadenceDistanceHandler.resetAggregated();
|
||||||
altitudeChangeHandler.resetAggregated();
|
altitudeChangeHandler.resetAggregated();
|
||||||
if (gpsManager.getAggregatorGPS() != null) gpsManager.getAggregatorGPS().resetAggregated();
|
gpsHandler.resetAggregated();
|
||||||
}
|
}
|
||||||
|
|
||||||
public GpsManager getGpsManager() {
|
public GpsHandler getGpsHandler() {
|
||||||
return gpsManager;
|
return gpsHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@@ -141,36 +138,38 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, @Nullable String key) {
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, @Nullable String key) {
|
||||||
if (gpsManager != null) {
|
if (!isStarted()) return;
|
||||||
gpsManager.onSharedPreferenceChanged(sharedPreferences, key);
|
|
||||||
|
|
||||||
if (PreferencesUtils.isKey(altitudeChangeHandler.getSensorPreferenceKey(), key)) {
|
if (PreferencesUtils.isKey(gpsHandler.getSensorPreferenceKey(), key)) {
|
||||||
altitudeChangeHandler.connect();
|
gpsHandler.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PreferencesUtils.isKey(heartRateHandler.getSensorPreferenceKey(), key)) {
|
if (PreferencesUtils.isKey(altitudeChangeHandler.getSensorPreferenceKey(), key)) {
|
||||||
heartRateHandler.connect();
|
altitudeChangeHandler.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PreferencesUtils.isKey(temperatureHandler.getSensorPreferenceKey(), key)) {
|
if (PreferencesUtils.isKey(heartRateHandler.getSensorPreferenceKey(), key)) {
|
||||||
temperatureHandler.connect();
|
heartRateHandler.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PreferencesUtils.isKey(cyclingCadenceHandler.getSensorPreferenceKey(), key)) {
|
if (PreferencesUtils.isKey(temperatureHandler.getSensorPreferenceKey(), key)) {
|
||||||
cyclingCadenceHandler.connect();
|
temperatureHandler.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PreferencesUtils.isKey(cyclingDistanceSpeedHandler.getSensorPreferenceKey(), key)) {
|
if (PreferencesUtils.isKey(cyclingCadenceHandler.getSensorPreferenceKey(), key)) {
|
||||||
cyclingDistanceSpeedHandler.connect();
|
cyclingCadenceHandler.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PreferencesUtils.isKey(cyclingCadenceHandler.getSensorPreferenceKey(), key)) {
|
if (PreferencesUtils.isKey(cyclingDistanceSpeedHandler.getSensorPreferenceKey(), key)) {
|
||||||
cyclingPowerHandler.connect();
|
cyclingDistanceSpeedHandler.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PreferencesUtils.isKey(runningSpeedCadenceDistanceHandler.getSensorPreferenceKey(), key)) {
|
if (PreferencesUtils.isKey(cyclingCadenceHandler.getSensorPreferenceKey(), key)) {
|
||||||
runningSpeedCadenceDistanceHandler.connect();
|
cyclingPowerHandler.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (PreferencesUtils.isKey(runningSpeedCadenceDistanceHandler.getSensorPreferenceKey(), key)) {
|
||||||
|
runningSpeedCadenceDistanceHandler.connect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,10 +250,13 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SensorDataSet getSensorDataSet(Instant now) {
|
public SensorDataSet getSensorDataSet(Instant now) {
|
||||||
AggregatorGPS gps = gpsManager.getAggregatorGPS();
|
SensorData<Position> gpsSensorData = gpsHandler.getSensorData(now);
|
||||||
|
|
||||||
|
var a = temperatureHandler.getSensorData(now);
|
||||||
|
var b = altitudeChangeHandler.getSensorData(now);
|
||||||
|
|
||||||
return new SensorDataSet(
|
return new SensorDataSet(
|
||||||
gps != null && gps.hasReceivedData() ? gps.getAggregatedValueWithSensorName(now) : new SensorData<>(Position.of(now), ""),
|
gpsSensorData != null ? gpsSensorData : new SensorData<>(Position.of(now), ""), //We always need a Position(now)
|
||||||
getSpeed(now),
|
getSpeed(now),
|
||||||
getDistance(now),
|
getDistance(now),
|
||||||
getHeartRate(now),
|
getHeartRate(now),
|
||||||
@@ -291,11 +293,15 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
|
|||||||
if (runningSpeedCadenceDistanceHandler != null) {
|
if (runningSpeedCadenceDistanceHandler != null) {
|
||||||
runningSpeedCadenceDistanceHandler.setAggregator(null);
|
runningSpeedCadenceDistanceHandler.setAggregator(null);
|
||||||
}
|
}
|
||||||
if (this.gpsManager != null) {
|
if (this.gpsHandler != null) {
|
||||||
this.gpsManager.setAggregatorGPS();
|
this.gpsHandler.setAggregator(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isStarted() {
|
||||||
|
return wakeLock != null;
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public void setAggregator(AggregatorHeartRate data) {
|
public void setAggregator(AggregatorHeartRate data) {
|
||||||
heartRateHandler.setAggregator(data);
|
heartRateHandler.setAggregator(data);
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import de.dennisguse.opentracks.sensors.ServiceMeasurementUUID;
|
|||||||
/**
|
/**
|
||||||
* Manages connection to a Bluetooth LE sensor and subscribes for onChange-notifications.
|
* Manages connection to a Bluetooth LE sensor and subscribes for onChange-notifications.
|
||||||
*/
|
*/
|
||||||
|
//TODO Re-act to Bluetooth disabled/enabled
|
||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission")
|
||||||
public class BluetoothDriver<T> implements Driver {
|
public class BluetoothDriver<T> implements Driver {
|
||||||
|
|
||||||
|
|||||||
@@ -22,4 +22,10 @@ public interface DriverObserver<T> {
|
|||||||
*/
|
*/
|
||||||
//TODO check if really need this, because the driver was told to disconnect and then just signalizes that it finished this task.
|
//TODO check if really need this, because the driver was told to disconnect and then just signalizes that it finished this task.
|
||||||
void onDisconnected();
|
void onDisconnected();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Driver detected that the sensor got deactivated.
|
||||||
|
* For example, the user deactivated the internal GPS.
|
||||||
|
*/
|
||||||
|
default void onSensorDeactivated() {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import android.os.Handler;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.core.location.LocationListenerCompat;
|
import androidx.core.location.LocationListenerCompat;
|
||||||
import androidx.core.location.LocationManagerCompat;
|
import androidx.core.location.LocationManagerCompat;
|
||||||
import androidx.core.location.LocationRequestCompat;
|
import androidx.core.location.LocationRequestCompat;
|
||||||
@@ -18,9 +19,10 @@ public class GpsInternal implements Driver {
|
|||||||
|
|
||||||
private static final String TAG = GpsInternal.class.getSimpleName();
|
private static final String TAG = GpsInternal.class.getSimpleName();
|
||||||
|
|
||||||
private static final String LOCATION_PROVIDER = LocationManager.GPS_PROVIDER;
|
public static final String LOCATION_PROVIDER = LocationManager.GPS_PROVIDER;
|
||||||
|
|
||||||
private final LocationListenerCompat locationListenerCompat = new LocationListenerCompat() {
|
@VisibleForTesting
|
||||||
|
public final LocationListenerCompat locationListenerCompat = new LocationListenerCompat() {
|
||||||
@Override
|
@Override
|
||||||
public void onLocationChanged(@NonNull Location location) {
|
public void onLocationChanged(@NonNull Location location) {
|
||||||
driverObserver.onDataReceived(location);
|
driverObserver.onDataReceived(location);
|
||||||
@@ -33,13 +35,14 @@ public class GpsInternal implements Driver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onProviderDisabled(@NonNull String provider) {
|
public void onProviderDisabled(@NonNull String provider) {
|
||||||
driverObserver.onConnectionLost();
|
driverObserver.onSensorDeactivated();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final DriverObserver<Location> driverObserver;
|
private final DriverObserver<Location> driverObserver;
|
||||||
|
|
||||||
private LocationManager locationManager;
|
@VisibleForTesting
|
||||||
|
public LocationManager locationManager;
|
||||||
|
|
||||||
public GpsInternal(DriverObserver<Location> driverObserver) {
|
public GpsInternal(DriverObserver<Location> driverObserver) {
|
||||||
this.driverObserver = driverObserver;
|
this.driverObserver = driverObserver;
|
||||||
@@ -62,8 +65,8 @@ public class GpsInternal implements Driver {
|
|||||||
if (PermissionRequester.GPS.hasPermission(context)) {
|
if (PermissionRequester.GPS.hasPermission(context)) {
|
||||||
try {
|
try {
|
||||||
Log.i(TAG, "Register for location updates " + context);
|
Log.i(TAG, "Register for location updates " + context);
|
||||||
LocationManagerCompat.requestLocationUpdates(locationManager, LOCATION_PROVIDER, locationRequest, handler::post, locationListenerCompat);
|
|
||||||
driverObserver.onConnected(null, null);
|
driverObserver.onConnected(null, null);
|
||||||
|
LocationManagerCompat.requestLocationUpdates(locationManager, LOCATION_PROVIDER, locationRequest, handler::post, locationListenerCompat);
|
||||||
return;
|
return;
|
||||||
} catch (SecurityException e) {
|
} catch (SecurityException e) {
|
||||||
Log.e(TAG, "Could not register location listener; permissions not granted.", e);
|
Log.e(TAG, "Could not register location listener; permissions not granted.", e);
|
||||||
|
|||||||
@@ -16,10 +16,6 @@ public abstract class Aggregator<Input, Output> {
|
|||||||
private final String sensorAddress;
|
private final String sensorAddress;
|
||||||
private final String sensorName;
|
private final String sensorName;
|
||||||
|
|
||||||
Aggregator(String sensorAddress) {
|
|
||||||
this(sensorAddress, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
Aggregator(String sensorAddress, String sensorName) {
|
Aggregator(String sensorAddress, String sensorName) {
|
||||||
this.sensorAddress = sensorAddress;
|
this.sensorAddress = sensorAddress;
|
||||||
this.sensorName = sensorName;
|
this.sensorName = sensorName;
|
||||||
|
|||||||
@@ -1,21 +1,23 @@
|
|||||||
package de.dennisguse.opentracks.sensors.sensorData;
|
package de.dennisguse.opentracks.sensors.sensorData;
|
||||||
|
|
||||||
|
import android.location.Location;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.data.models.Position;
|
import de.dennisguse.opentracks.data.models.Position;
|
||||||
|
|
||||||
public class AggregatorGPS extends Aggregator<Position, Position> {
|
public class AggregatorGPS extends Aggregator<Location, Position> {
|
||||||
|
|
||||||
|
|
||||||
public AggregatorGPS(String sensorAddress) {
|
public AggregatorGPS(String sensorAddress, String sensorName) {
|
||||||
super(sensorAddress);
|
super(sensorAddress, sensorName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void computeValue(Raw<Position> current) {
|
protected void computeValue(Raw<Location> current) {
|
||||||
aggregatedValue = current.value();
|
aggregatedValue = Position.of(current.value(), current.time());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -253,10 +253,6 @@ public class PreferencesUtils {
|
|||||||
return isReportSpeed(track.activityTypeLocalized());
|
return isReportSpeed(track.activityTypeLocalized());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getBluetoothSensorAddressNone() {
|
|
||||||
return SensorType.NONE.getPreferenceValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SensorType getSensorType(String address) {
|
public static SensorType getSensorType(String address) {
|
||||||
return Arrays.stream(SensorType.values())
|
return Arrays.stream(SensorType.values())
|
||||||
.filter(it -> it.getPreferenceValue().equals(address))
|
.filter(it -> it.getPreferenceValue().equals(address))
|
||||||
|
|||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
package de.dennisguse.opentracks.settings.bluetooth;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.location.LocationManager;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
|
||||||
|
import androidx.core.location.LocationManagerCompat;
|
||||||
|
import androidx.preference.PreferenceDialogFragmentCompat;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.sensors.driver.GpsInternal;
|
||||||
|
|
||||||
|
public class BluetoothLeGpsPreference extends BluetoothLeSensorPreference {
|
||||||
|
|
||||||
|
public BluetoothLeGpsPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||||
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BluetoothLeGpsPreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BluetoothLeGpsPreference(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BluetoothLeGpsPreference(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PreferenceDialogFragmentCompat createInstance() {
|
||||||
|
boolean hasInternalSensor = LocationManagerCompat.hasProvider((LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE), GpsInternal.LOCATION_PROVIDER);
|
||||||
|
|
||||||
|
return BluetoothLeSensorPreferenceDialog
|
||||||
|
.newInstance(getKey(), List.of(), hasInternalSensor);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
<string name="settings_sensor_bluetooth_cycling_power_key" translatable="false">bluetoothCyclingPowerSensor</string>
|
<string name="settings_sensor_bluetooth_cycling_power_key" translatable="false">bluetoothCyclingPowerSensor</string>
|
||||||
<string name="settings_sensor_bluetooth_running_speed_and_cadence_key" translatable="false">bluetoothRunningSpeedAndCadenceSensor</string>
|
<string name="settings_sensor_bluetooth_running_speed_and_cadence_key" translatable="false">bluetoothRunningSpeedAndCadenceSensor</string>
|
||||||
<string name="settings_sensor_bluetooth_pressure_key" translatable="false">bluetoothPressureSensor</string>
|
<string name="settings_sensor_bluetooth_pressure_key" translatable="false">bluetoothPressureSensor</string>
|
||||||
|
<string name="settings_sensor_bluetooth_gps_key" translatable="false">bluetoothGPSSensor</string>
|
||||||
<string name="sensor_type_value_none" translatable="false">NONE</string>
|
<string name="sensor_type_value_none" translatable="false">NONE</string>
|
||||||
<string name="sensor_type_value_internal" translatable="false">INTERNAL</string>
|
<string name="sensor_type_value_internal" translatable="false">INTERNAL</string>
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,15 @@
|
|||||||
android:title="@string/settings_sensors_title">
|
android:title="@string/settings_sensors_title">
|
||||||
|
|
||||||
<PreferenceCategory android:title="@string/settings_gps_sensor">
|
<PreferenceCategory android:title="@string/settings_gps_sensor">
|
||||||
|
<de.dennisguse.opentracks.settings.bluetooth.BluetoothLeGpsPreference
|
||||||
|
android:defaultValue="@string/sensor_type_value_internal"
|
||||||
|
android:key="@string/settings_sensor_bluetooth_gps_key"
|
||||||
|
android:title="@string/settings_gps_sensor" />
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:defaultValue="@string/min_sampling_interval_default"
|
android:defaultValue="@string/min_sampling_interval_default"
|
||||||
android:entryValues="@array/min_sampling_interval_values"
|
android:entryValues="@array/min_sampling_interval_values"
|
||||||
android:key="@string/min_sampling_interval_key"
|
android:key="@string/min_sampling_interval_key"
|
||||||
android:title="@string/settings_recording_min_sampling_interval_title" />
|
android:title="@string/settings_recording_min_sampling_interval_title" />
|
||||||
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:defaultValue="@string/recording_gps_accuracy_default"
|
android:defaultValue="@string/recording_gps_accuracy_default"
|
||||||
android:entryValues="@array/recording_gps_accuracy_values"
|
android:entryValues="@array/recording_gps_accuracy_values"
|
||||||
@@ -71,9 +74,9 @@
|
|||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
android:defaultValue="@bool/settings_sensor_bluetooth_service_filter_enabled_default"
|
android:defaultValue="@bool/settings_sensor_bluetooth_service_filter_enabled_default"
|
||||||
android:key="@string/settings_sensor_bluetooth_service_filter_enabled_key"
|
android:key="@string/settings_sensor_bluetooth_service_filter_enabled_key"
|
||||||
android:title="@string/settings_sensor_bluetooth_service_filter_title"
|
android:summaryOff="@string/settings_sensor_bluetooth_service_filter_off"
|
||||||
android:summaryOn="@string/settings_sensor_bluetooth_service_filter_on"
|
android:summaryOn="@string/settings_sensor_bluetooth_service_filter_on"
|
||||||
android:summaryOff="@string/settings_sensor_bluetooth_service_filter_off" />
|
android:title="@string/settings_sensor_bluetooth_service_filter_title" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
Reference in New Issue
Block a user