Compare commits

...

23 Commits

Author SHA1 Message Date
Dennis Guse 9e496f97c1 Release: v4.12.3 2024-04-28 11:02:07 +02:00
Dennis Guse 455c2fcf75 Bugfix: idle time should start also if the first trackpoint with a location is stored.
Identified in #1898.
2024-04-28 10:50:56 +02:00
Dennis Guse e590e4e07e Bugfix: overestimated distance.
A combination of idle trackpoint and stale GPS data, resulted in recording lat=0.0 and lng=0.0; and thus inflating distance as well as GPS-based speed.

Fixes #1898.

Introduced in dfdbc373ff
2024-04-28 10:50:56 +02:00
dependabot[bot] 36474e8541 Bump androidx.core:core from 1.12.0 to 1.13.0
Bumps androidx.core:core from 1.12.0 to 1.13.0.

---
updated-dependencies:
- dependency-name: androidx.core:core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-18 06:44:20 +02:00
Dennis Guse be7a43823a Release: v4.12.2. 2024-04-14 13:00:48 +02:00
Cat 64326590e6 Translated using Weblate (Danish)
Currently translated at 3.6% (5 of 137 strings)

Translation: OpenTracks/App store metadata files
Translate-URL: https://hosted.weblate.org/projects/opentracks/app-store-metadata-files/da/
2024-04-13 15:02:25 +02:00
Cat 82aa23f0bb Translated using Weblate (Danish)
Currently translated at 90.8% (475 of 523 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/da/
2024-04-13 15:02:24 +02:00
Dennis Guse 13eb5c30a2 Bugfix: if sensors are running, do not try to start again.
Fixes #1887.
2024-04-12 06:51:05 +02:00
dependabot[bot] 7bbdd55a93 Bump com.android.tools.build:gradle from 8.3.1 to 8.3.2
Bumps com.android.tools.build:gradle from 8.3.1 to 8.3.2.

---
updated-dependencies:
- dependency-name: com.android.tools.build:gradle
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-10 07:35:14 +02:00
Stephan Paternotte 1617a7377b Translated using Weblate (Dutch)
Currently translated at 100.0% (137 of 137 strings)

Translation: OpenTracks/App store metadata files
Translate-URL: https://hosted.weblate.org/projects/opentracks/app-store-metadata-files/nl/
2024-04-08 18:18:07 +02:00
Fjuro af25d158e1 Translated using Weblate (Czech)
Currently translated at 100.0% (137 of 137 strings)

Translation: OpenTracks/App store metadata files
Translate-URL: https://hosted.weblate.org/projects/opentracks/app-store-metadata-files/cs/
2024-04-08 18:18:07 +02:00
ken-der-guru 47525a260e Translated using Weblate (German)
Currently translated at 98.6% (516 of 523 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/de/
2024-04-08 18:18:07 +02:00
josé m 2984a8328a Translated using Weblate (Galician)
Currently translated at 100.0% (523 of 523 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/gl/
2024-04-08 18:18:07 +02:00
josé m c7a9a1a7b5 Translated using Weblate (Galician)
Currently translated at 16.1% (22 of 136 strings)

Translation: OpenTracks/App store metadata files
Translate-URL: https://hosted.weblate.org/projects/opentracks/app-store-metadata-files/gl/
2024-04-08 18:18:07 +02:00
ken-der-guru b56eaa740f Translated using Weblate (German)
Currently translated at 97.1% (508 of 523 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/de/
2024-04-08 18:18:06 +02:00
Ghost of Sparta 214f4adb70 Translated using Weblate (Hungarian)
Currently translated at 100.0% (523 of 523 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/hu/
2024-04-08 18:18:06 +02:00
gallegonovato bc1c3eabca Translated using Weblate (Spanish)
Currently translated at 100.0% (523 of 523 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/es/
2024-04-08 18:18:06 +02:00
Tea-NT cd1ba6d1ae Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (136 of 136 strings)

Translation: OpenTracks/App store metadata files
Translate-URL: https://hosted.weblate.org/projects/opentracks/app-store-metadata-files/zh_Hans/
2024-04-08 18:18:06 +02:00
Tea-NT 0c543e6083 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (523 of 523 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/zh_Hans/
2024-04-08 18:18:06 +02:00
Stephan Paternotte a28bf53245 Translated using Weblate (Dutch)
Currently translated at 100.0% (136 of 136 strings)

Translation: OpenTracks/App store metadata files
Translate-URL: https://hosted.weblate.org/projects/opentracks/app-store-metadata-files/nl/
2024-04-08 18:18:06 +02:00
Fjuro 6961f3ee50 Translated using Weblate (Czech)
Currently translated at 100.0% (136 of 136 strings)

Translation: OpenTracks/App store metadata files
Translate-URL: https://hosted.weblate.org/projects/opentracks/app-store-metadata-files/cs/
2024-04-08 18:18:06 +02:00
Dennis Guse 52624b5cfe PublicAPI: add test for setting icon via parameter.
Follow-up to #1818.
2024-04-08 18:17:54 +02:00
Dennis Guse dfdbc373ff GPS: event-based using Raw.
Part of #1424.
2024-04-08 17:48:29 +02:00
32 changed files with 306 additions and 188 deletions
+4 -4
View File
@@ -6,7 +6,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.3.1'
classpath 'com.android.tools.build:gradle:8.3.2'
}
}
@@ -64,8 +64,8 @@ android {
defaultConfig {
applicationId "de.dennisguse.opentracks"
versionCode 5730
versionName "v4.12.1"
versionCode 5753
versionName "v4.12.3"
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
@@ -133,7 +133,7 @@ dependencies {
implementation 'androidx.gridlayout:gridlayout:1.0.0'
implementation 'com.google.android.material:material:1.11.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.core:core:1.12.0'
implementation 'androidx.core:core:1.13.0'
implementation 'androidx.core:core-splashscreen:1.0.1'
implementation 'androidx.mediarouter:mediarouter:1.7.0'
@@ -0,0 +1,8 @@
v4.12.0: OpenTracks
Změny:
- Tmavý motiv pro obrazovky OLED (vyžaduje ruční restart)
- Změna uspořádání nastavení (GPS je senzor)
Vývojáři:
- Přidány skripty pro nahrání Fastlane na Obchod Play (překlady)
@@ -0,0 +1,5 @@
v4.12.1: OpenTracks
Oprava chyb:
- Android 14: nahlášení chybějících oprávnění (namísto nuceného pádu se stacktrace)
- POST_NOTIFICATION je volitelné
@@ -0,0 +1,15 @@
v3.0.0: OpenTracks
Første udgivelse af OpenTracks (dvs. hard fork fra MyTracks)
Ændringer:
- Omdøbt fra MyTracks til OpenTracks
- Tilføjet Bluetooth LE-pulssensor
- Fjernet alle funktioner, der kræver internetadgang
- Fjernet Google Maps-integration
- Fjernet brug af Google Play-tjenester
- ANT+ sensorer fjernet
- Fjernet klassiske Bluetooth-sensorer
- Fjernet Protobuf
- Fjernet kalorieberegning og aktivitetsberegning
- Fjernet MyTracks Service-API (dvs. ingen integration med andre apps)
@@ -1,11 +1,22 @@
OpenTracks er et program til sporing af sport, der fuldt ud respekterer dit privatliv.
En sporingsmakker, der respekterer dit privatliv.
Funktioner:
* Sport tracking: Spor dine sports- og udendørsaktiviteter
* Billeder og markører: Markér interessante steder under sporing
* Højdeforøgelse og -tab: via barometrisk sensor
* Højde vist i EGM2008 (over middelhavets overflade); eksporteret som WGS84
* Stemmemeddelelser
* Understøtter Bluetooth LE-sensorer: puls, hastighed og distance (cykling), kadence (cykling) og effektmåler (cykling)
* Eksport af data: Eksportér spor enten som KMZ (inkl. fotos), KML eller GPX
* Ingen internetadgang: Internet bruges ikke
Sports- og udendørsaktiviteter giver glæde, dygtighed og selvtillid.
Værdsæt dit helbred ved at holde styr på din træning.
Registrerer, mens du løber eller går, og giver dig en cykelcomputer med en større skærm til cykling.
Markér interessante steder undervejs med billeder.
Opbevar registrerede statistikker i detaljer til analyse.
Del kun de data, du ønsker, at andre skal have.
* Stemmemeddelelser.
* Understøtter Bluetooth LE-sensorer: puls, hastighed og distance (cykling), kadence (cykling) og effektmåler (cykling).
* Højdestigning og -fald: via barometrisk sensor.
* Højde vist i EGM2008 (over havets overflade); eksporteret som WGS84.
* Eksport af data i form af spor, enten som KMZ (inkl. fotos), KML eller GPX.
* Ingen internetadgang eller ekstra tilladelser.
* Mørkt og lyst tema, der respekterer systemindstillinger.
* Ingen reklamer.
Libre Software / Fri Software / Open Source
hvilket betyder, at du kan bruge, studere, ændre og dele kildekoden.
Licenseret Apache 2.0
@@ -1 +1 @@
En sportstracker, der respekterer dit privatliv fuldt ud.
En sportstracker, der respekterer dit privatliv.
@@ -0,0 +1,4 @@
v4.12.2.: OpenTracks
Bugfix:
- Allow to start sensors before recording
@@ -0,0 +1,8 @@
v4.12.3: OpenTracks
Bugfix:
- Using GPS and IDLE functionality stored coordinates 0.0/0.0 and thus overestimating all statistics (distance >10.000 km). (Introduced in v4.12.0)
- Idle: also trigger if only one location was received.
Regarding the overestimating distance bug: the stored data will not be fixed within OpenTracks.
Recommendation: export the as KML/KMZ and replace the invalid coordinates.
@@ -0,0 +1,8 @@
v4.12.0: OpenTracks
Cambios:
- decorado escuro amigable con OLED (hai que reiniciar)
- nova orde nos axustes (GPS é un sensor)
Desenvolvemento:
- Engadidos scripts Fastlane para subir á PlayStore (traducións)
@@ -0,0 +1,8 @@
v4.12.0: OpenTracks
Veranderingen:
- OLED-vriendelijk donker thema (handmatige herstart vereist)
- Re-order instellingen (GPS is een sensor)
Ontwikkelaar:
- Scripts toegevoegd voor Fastlane om PlayStore te uploaden (vertalingen)
@@ -0,0 +1,5 @@
v4.12.1: OpenTracks
Bugfix:
- Android 14: ontbrekende rechten melden (in plaats van geforceerde chrash met stacktrace)
- POST_NOTIFICATION is optioneel
@@ -0,0 +1,8 @@
v4.12.0: OpenTracks
更改:
- OLED 友好型暗色主题(需要手动重启)
- 重新排序设置(GPS 是一个传感器)
开发人员:
- 为 PlayStore 上传添加了 Fastlane 脚本(翻译)
@@ -65,6 +65,7 @@ import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingCadence;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingDistanceSpeed;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingPower;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorHeartRate;
import de.dennisguse.opentracks.sensors.sensorData.Raw;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
@@ -604,6 +605,6 @@ public class ExportImportTest {
mockAltitudeChange(trackPointCreator, altitudeGain);
trackPointCreator.setClock(time);
trackPointCreator.onChange(location);
trackPointCreator.getSensorManager().onChanged(new Raw<>(location));
}
}
@@ -1,18 +1,24 @@
package de.dennisguse.opentracks.publicapi;
import android.content.Context;
import android.content.Intent;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import androidx.test.rule.GrantPermissionRule;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.List;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.TestUtil;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.util.IntentUtils;
@@ -35,12 +41,23 @@ public class PublicApiTest {
@Test
public void StartStopTest() throws InterruptedException {
PreferencesUtils.setBoolean(R.string.publicapi_enabled_key, true);
context.startActivity(IntentUtils.newIntent(context, StartRecording.class));
Intent startIntent = IntentUtils.newIntent(context, StartRecording.class);
startIntent.putExtra("TRACK_NAME", "trackName");
startIntent.putExtra("TRACK_CATEGORY", "activityTypeLocalized");
startIntent.putExtra("TRACK_ICON", "airplane");
startIntent.putExtra("TRACK_DESCRIPTION", "description");
context.startActivity(startIntent);
Thread.sleep(5000);
context.startActivity(IntentUtils.newIntent(context, StopRecording.class));
List<Track> tracks = new ContentProviderUtils(context).getTracks();
Assert.assertEquals(1, tracks.size());
Track track = tracks.get(0);
Assert.assertEquals("trackName", track.getName());
Assert.assertEquals("activityTypeLocalized", track.getActivityTypeLocalized());
Assert.assertEquals("airplane", track.getActivityType().getId());
}
@Test
@@ -10,6 +10,7 @@ import android.os.Looper;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.MediumTest;
import androidx.test.rule.GrantPermissionRule;
import androidx.test.rule.ServiceTestRule;
import org.junit.AfterClass;
@@ -20,12 +21,14 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import java.time.Duration;
import java.time.Instant;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.TestUtil;
import de.dennisguse.opentracks.content.data.TestDataUtil;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.AltitudeGainLoss;
@@ -54,6 +57,9 @@ public class TrackRecordingServiceRecordingTest {
@Rule
public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(5, TimeUnit.SECONDS);
@Rule
public GrantPermissionRule mGrantPermissionRule = TestUtil.createGrantPermissionRule();
private final Context context = ApplicationProvider.getApplicationContext();
private ContentProviderUtils contentProviderUtils;
@@ -127,6 +133,47 @@ public class TrackRecordingServiceRecordingTest {
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
/**
* Test that an IDLE event, doesn't store invalid GPS-provided data.
*/
@MediumTest
@Test
public void recording_startIdle() throws InterruptedException {
// given
TrackPointCreator trackPointCreator = service.getTrackPointCreator();
String startTime = "2020-02-02T02:02:02Z";
trackPointCreator.setClock(startTime);
Track.Id trackId = service.startNewTrack();
String gps1 = "2020-02-02T02:02:03Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15);
String gps2 = "2020-02-02T02:02:04Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps2, 45.0, 35.0, 1, 15);
// when
String idleTime = "2020-02-02T02:02:17Z";
trackPointCreator.setClock("2020-02-02T02:02:17Z");
Thread.sleep(Duration.ofSeconds(15).toMillis());
// then
new TrackPointAssert().assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps1))
.setLatitude(45)
.setLongitude(35)
.setHorizontalAccuracy(Distance.of(1))
.setSpeed(Speed.of(15)),
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps2))
.setLatitude(45)
.setLongitude(35)
.setHorizontalAccuracy(Distance.of(1))
.setSpeed(Speed.of(15)),
new TrackPoint(TrackPoint.Type.IDLE, Instant.parse(idleTime))
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
@MediumTest
@Test
public void testRecording_startPauseResume() {
@@ -415,6 +462,10 @@ public class TrackRecordingServiceRecordingTest {
.setAltitudeGain(0f)
.setAltitudeLoss(0f),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
.setLatitude(45.00002)
.setLongitude(35)
.setHorizontalAccuracy(Distance.of(1))
.setSpeed(Speed.of(15))
.setAltitudeGain(0f)
.setAltitudeLoss(0f)
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
@@ -667,6 +718,9 @@ public class TrackRecordingServiceRecordingTest {
.setSpeed(Speed.of(5))
.setSensorDistance(Distance.of(0)),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
.setLatitude(45.001)
.setLongitude(35)
.setHorizontalAccuracy(Distance.of(1))
.setSensorDistance(Distance.of(11))
.setSpeed(Speed.of(5))
.setSensorDistance(Distance.of(0))
@@ -1,126 +0,0 @@
package de.dennisguse.opentracks.services.handlers;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.location.Location;
import android.os.Handler;
import android.os.Looper;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.time.Instant;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.settings.PreferencesUtils;
@RunWith(MockitoJUnitRunner.class)
public class GPSManagerTest {
private final Context context = ApplicationProvider.getApplicationContext();
@Mock
private TrackPointCreator trackPointCreator;
@InjectMocks
private GPSManager locationHandler;
@BeforeClass
public static void preSetUp() {
// Prepare looper for Android's message queue
if (Looper.myLooper() == null) Looper.prepare();
}
@Before
public void setUp() {
// Let's use default values.
PreferencesUtils.clear();
Mockito.when(trackPointCreator.createNow())
.thenReturn(Instant.now());
locationHandler.start(context, new Handler());
}
/**
* When a valid location changed in LocationHandler -> newTrackPoint service method is called.
*/
@Test
public void testOnLocationChanged_okay() {
// when
locationHandler.onLocationChanged(createLocation(45f, 35f, 3, 5, System.currentTimeMillis()));
// then
verify(trackPointCreator, times(1)).onChange(any(Location.class));
}
/**
* When location changed in LocationHandler with bad location -> newTrackPoint service method is not called.
*/
@Test
public void testOnLocationChanged_badLocation() {
// given
float latitude = 91f;
// when
// bad latitude
locationHandler.onLocationChanged(createLocation(latitude, 35f, 3, 5, System.currentTimeMillis()));
// then
verify(trackPointCreator, times(0)).onChange(any(Location.class));
}
/**
* When location changed in LocationHandler with poor accuracy -> newTrackPoint service method is not called.
*/
@Test
public void testOnLocationChanged_poorAccuracy() {
// given
Distance prefAccuracy = PreferencesUtils.getThresholdHorizontalAccuracy();
// when
locationHandler.onLocationChanged(createLocation(45f, 35f, (float) (prefAccuracy.toM() + 1), 5, System.currentTimeMillis()));
// then
// no newTrackPoint called
verify(trackPointCreator, times(0)).onChange(any(Location.class));
}
@Test
public void testOnLocationChanged_movingInaccurate() {
// when
locationHandler.onLocationChanged(createLocation(45.0, 35.0, 5, 15, System.currentTimeMillis()));
locationHandler.onLocationChanged(createLocation(45.1, 35.0, Long.MAX_VALUE, 15, System.currentTimeMillis()));
locationHandler.onLocationChanged(createLocation(45.2, 35.0, Long.MAX_VALUE, 15, System.currentTimeMillis()));
locationHandler.onLocationChanged(createLocation(45.3, 35.0, Long.MAX_VALUE, 15, System.currentTimeMillis()));
locationHandler.onLocationChanged(createLocation(99.0, 35.0, Long.MAX_VALUE, 15, System.currentTimeMillis()));
// then
verify(trackPointCreator, times(1)).onChange(any(Location.class));
}
/**
* Creates a location with parameters and returns the Location object.
*/
private static Location createLocation(double latitude, double longitude, float accuracy, long speed, long time) {
Location location = new Location("gps");
location.setLongitude(longitude);
location.setLatitude(latitude);
location.setAccuracy(accuracy);
location.setSpeed(speed);
location.setTime(time);
location.setBearing(3.0f);
return location;
}
}
@@ -130,6 +130,16 @@ public class Track {
this.trackStatistics = trackStatistics;
}
@Override
public String toString() {
return "Track{" +
"name='" + name + '\'' +
", description='" + description + '\'' +
", activityTypeLocalized='" + activityTypeLocalized + '\'' +
", activityType=" + activityType +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -30,7 +30,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
@Override
public void onConnect(Aggregator<?, ?> aggregator) {
sensorDataSet.add(aggregator);
observer.onChange(new SensorDataSet(sensorDataSet));
}
@Override
@@ -42,13 +41,11 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
@Override
public void onDisconnect(Aggregator<?, ?> aggregator) {
sensorDataSet.add(aggregator);
observer.onChange(new SensorDataSet(sensorDataSet));
}
@Override
public void onRemove(Aggregator<?, ?> aggregator) {
sensorDataSet.remove(aggregator);
observer.onChange(new SensorDataSet(sensorDataSet));
}
};
@@ -67,7 +64,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
throw new RuntimeException("SensorManager cannot be started twice; stop first.");
}
gpsManager = new GPSManager(observer); //TODO Pass listener
gpsManager = new GPSManager(observer, listener);
altitudeSumManager = new GainManager(listener);
bluetoothSensorManager = new BluetoothRemoteSensorManager(context, handler, listener);
@@ -104,7 +101,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
sensorDataSet.reset();
}
@Deprecated
@VisibleForTesting
public void onChanged(Raw<?> data) {
listener.onChange(data);
@@ -6,7 +6,7 @@ import java.time.Instant;
import de.dennisguse.opentracks.sensors.BluetoothRemoteSensorManager;
public abstract class Aggregator<Input extends Record, Output> {
public abstract class Aggregator<Input, Output> {
protected Raw<Input> previous;
@@ -44,7 +44,7 @@ public abstract class Aggregator<Input extends Record, Output> {
public Output getValue() {
if (!hasValue()) {
return null;
return null; //TODO Check if this is a good idea!
}
if (isRecent()) {
return value;
@@ -0,0 +1,31 @@
package de.dennisguse.opentracks.sensors.sensorData;
import android.location.Location;
import androidx.annotation.NonNull;
import java.util.Optional;
public class AggregatorGPS extends Aggregator<Location, Optional<Location>> {
public AggregatorGPS(String sensorAddress) {
super(sensorAddress);
}
@Override
protected void computeValue(Raw<Location> current) {
value = Optional.of(current.value());
}
@Override
public void reset() {
value = null;
}
@NonNull
@Override
protected Optional<Location> getNoneValue() {
return Optional.empty();
}
}
@@ -5,7 +5,7 @@ import androidx.annotation.NonNull;
import java.time.Instant;
public record Raw<T extends Record>(
public record Raw<T>(
@NonNull T value,
@NonNull Instant time
@@ -1,5 +1,6 @@
package de.dennisguse.opentracks.sensors.sensorData;
import android.location.Location;
import android.util.Log;
import android.util.Pair;
@@ -40,16 +41,20 @@ public final class SensorDataSet {
@VisibleForTesting
public AggregatorBarometer barometer;
public AggregatorGPS gps;
public SensorDataSet() {
}
public SensorDataSet(SensorDataSet toCopy) {
//TODO This is not a copy constructor anymore, but it should be - aggregators are no value objects
this.heartRate = toCopy.heartRate;
this.cyclingCadence = toCopy.cyclingCadence;
this.cyclingDistanceSpeed = toCopy.cyclingDistanceSpeed;
this.cyclingPower = toCopy.cyclingPower;
this.runningDistanceSpeedCadence = toCopy.runningDistanceSpeedCadence;
this.barometer = toCopy.barometer;
this.gps = toCopy.gps;
}
public Pair<HeartRate, String> getHeartRate() {
@@ -93,7 +98,7 @@ public final class SensorDataSet {
}
public void update(@NonNull Raw<?> data) {
Record value = data.value();
Object value = data.value();
if (value instanceof HeartRate) {
this.heartRate.add((Raw<HeartRate>) data);
@@ -122,6 +127,10 @@ public final class SensorDataSet {
this.barometer.add((Raw<AtmosphericPressure>) data);
return;
}
if (value instanceof Location) {
this.gps.add((Raw<Location>) data);
return;
}
throw new UnsupportedOperationException(data.getClass().getCanonicalName() + " " + data.value().getClass().getCanonicalName());
}
@@ -138,9 +147,15 @@ public final class SensorDataSet {
this.cyclingPower = null;
this.runningDistanceSpeedCadence = null;
this.barometer = null;
this.gps = null;
}
public void fillTrackPoint(TrackPoint trackPoint) {
if (gps != null && gps.hasValue()) {
gps.getValue()
.ifPresent(trackPoint::setLocation);
}
if (getHeartRate() != null) {
trackPoint.setHeartRate(getHeartRate().first);
}
@@ -180,6 +195,7 @@ public final class SensorDataSet {
if (cyclingPower != null) cyclingPower.reset();
if (runningDistanceSpeedCadence != null) runningDistanceSpeedCadence.reset();
if (barometer != null) barometer.reset();
if (gps != null) gps.reset();
}
private void set(@NonNull Aggregator<?, ?> type, @Nullable Aggregator<?, ?> sensorData) {
@@ -209,6 +225,10 @@ public final class SensorDataSet {
barometer = (AggregatorBarometer) sensorData;
return;
}
if (type instanceof AggregatorGPS) {
gps = (AggregatorGPS) sensorData;
return;
}
throw new UnsupportedOperationException(type.getClass().getCanonicalName());
}
@@ -197,6 +197,9 @@ public class TrackRecordingManager implements SharedPreferences.OnSharedPreferen
if (trackPoint.hasLocation() && lastStoredTrackPointWithLocation == null) {
insertTrackPoint(trackPoint, true);
handler.removeCallbacks(ON_IDLE);
handler.postDelayed(ON_IDLE, idleDuration.toMillis());
return true;
}
@@ -205,6 +205,7 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
private synchronized void startSensors() {
if (isSensorStarted()) {
Log.i(TAG, "sensors already started; skipping");
return;
}
Log.i(TAG, "startSensors");
wakeLock = SystemUtils.acquireWakeLock(this, wakeLock);
@@ -20,6 +20,9 @@ import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.sensors.SensorConnector;
import de.dennisguse.opentracks.sensors.SensorManager;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorGPS;
import de.dennisguse.opentracks.sensors.sensorData.Raw;
import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.util.LocationUtils;
import de.dennisguse.opentracks.util.PermissionRequester;
@@ -32,6 +35,8 @@ public class GPSManager implements SensorConnector, LocationListenerCompat, GpsS
private static final String LOCATION_PROVIDER = LocationManager.GPS_PROVIDER;
private TrackPointCreator trackPointCreator;
private SensorManager.SensorDataChangedObserver listener;
private Context context;
private Handler handler;
@@ -40,8 +45,9 @@ public class GPSManager implements SensorConnector, LocationListenerCompat, GpsS
private Duration gpsInterval;
private Distance thresholdHorizontalAccuracy;
public GPSManager(TrackPointCreator trackPointCreator) {
public GPSManager(TrackPointCreator trackPointCreator, SensorManager.SensorDataChangedObserver listener) {
this.trackPointCreator = trackPointCreator;
this.listener = listener;
}
public void start(@NonNull Context context, @NonNull Handler handler) {
@@ -52,6 +58,9 @@ public class GPSManager implements SensorConnector, LocationListenerCompat, GpsS
gpsStatusManager = new GpsStatusManager(context, this, handler);
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
listener.onConnect(new AggregatorGPS("internal"));
registerLocationListener();
gpsStatusManager.start();
}
@@ -72,6 +81,9 @@ public class GPSManager implements SensorConnector, LocationListenerCompat, GpsS
gpsStatusManager.stop();
gpsStatusManager = null;
listener.onDisconnect(new AggregatorGPS("internal"));
listener = null;
trackPointCreator = null;
}
@@ -126,7 +138,7 @@ public class GPSManager implements SensorConnector, LocationListenerCompat, GpsS
return;
}
trackPointCreator.onChange(location);
listener.onChange(new Raw<>(location));
}
@Override
@@ -2,7 +2,6 @@ package de.dennisguse.opentracks.services.handlers;
import android.content.Context;
import android.content.SharedPreferences;
import android.location.Location;
import android.os.Handler;
import android.util.Log;
import android.util.Pair;
@@ -69,10 +68,6 @@ public class TrackPointCreator implements SharedPreferences.OnSharedPreferenceCh
this.context = null;
}
public synchronized void onChange(@NonNull Location location) {
onNewTrackPoint(new TrackPoint(location, createNow()));
}
/**
* Got a new TrackPoint from Bluetooth only; contains no GPS location.
*/
+1 -1
View File
@@ -16,7 +16,7 @@ limitations under the License.
--><resources>
<string name="about_preference_title">Om OpenTracks</string>
<string name="about_description"><i> OpenTracks </i> er en sportstracker, der fuldt ud respekterer dit privatliv.</string>
<string name="about_url">Projekthjemmeside: <a href="%1$s">%1$s</a></string>
<string name="about_url">Projektets hjemmeside: <a href="%1$s">%1$s</a></string>
<string name="about_version_name">Versionsnavn: %1$s</string>
<string name="about_version_code">Versionskode: %1$d</string>
<string name="about_history">OpenTracks er en forgrening fra <a href="https://code.google.com/archive/p/mytracks/"> <i> Googles MyTracks </i> </a> (afviklet i 2016).</string>
+23 -3
View File
@@ -243,7 +243,7 @@ Meldet das GPS-Gerät ungenaue Daten (z.B. Standort, Geschwindigkeit, Höhe), ka
<string name="settings_recording_keep_screen_on_while_recording_title">Bildschirm eingeschaltet lassen</string>
<string name="settings_recording_keep_screen_on_while_recording_summary">Lasse während der Aufnahme den Bildschirm eingeschaltet.</string>
<string name="settings_recording_default_activity_title">Standardaktivität</string>
<string name="settings_recording_location_frequency_summary">Entfernungs-/Zeitintervall %1$s zwischen zwei Standortaufzeichnungen</string>
<string name="settings_recording_location_frequency_summary">%1$s zwischen Standort Überprüfungen</string>
<string name="settings_recording_max_recording_distance_summary">Ein neues Segment wird erstellt, wenn die Entfernung zwischen zwei Standorten mehr als %1$s beträgt</string>
<string name="settings_recording_max_recording_distance_title">Max. Entfernung</string>
<string name="settings_recording_min_recording_distance_title">Aufzeichnungsintervall</string>
@@ -490,7 +490,7 @@ Meldet das GPS-Gerät ungenaue Daten (z.B. Standort, Geschwindigkeit, Höhe), ka
<string name="menu_select_layout">Wähle Layout</string>
<string name="generic_choose_an_option">Wähle eine Option</string>
<string name="settings_gps_sensor">GPS</string>
<string name="settings_import_export_title">Import/Export</string>
<string name="settings_import_export_title">Import und Export</string>
<string name="settings_sensors_title">Sensoren</string>
<string name="settings_sensors_summary">Fahrradsensoren, Radumfang und Lauf-Sensoren</string>
<string name="settings_announcements_statistics_title">Sprachansagen</string>
@@ -532,7 +532,7 @@ Meldet das GPS-Gerät ungenaue Daten (z.B. Standort, Geschwindigkeit, Höhe), ka
<string name="export_dir_not_writable">" (nicht schreibbar)"</string>
<string name="stats_clock">Uhr</string>
<string name="image_discard">Verwerfen</string>
<string name="settings_announcements_distance_frequency">Entfernungsintervall</string>
<string name="settings_announcements_distance_frequency">Runden Länge</string>
<string name="settings_public_api_enabled_title">Öffentliche API</string>
<string name="track_discarding">Verwerfe Track</string>
<string name="average_heart_rate">Durchschnittlicher Puls</string>
@@ -618,4 +618,24 @@ Meldet das GPS-Gerät ungenaue Daten (z.B. Standort, Geschwindigkeit, Höhe), ka
<string name="settings_recording_min_required_accuracy_summary">Ort wird ignoriert wenn seine Genauigkeit über %1$s liegt</string>
<string name="settings_sensor_bluetooth_service_filter_title">Bluetooth Geräte filtern</string>
<string name="settings_sensor_bluetooth_service_filter_off">Alle verfügbaren Bluetooth Geräte anzeigen</string>
<string name="settings_theme_switch_restart">Themenänderungen können einen manuellen Neustart erfordern.</string>
<string name="settings_recording_idle_timeout_title">Stillstand Schwelle</string>
<string name="settings_night_mode_option_night_oled">Nacht (OLED freundlich)</string>
<string name="sensor_state_pressure">Barometer</string>
<string name="bluetooth_sensor_summary">%1$s (%2$s)</string>
<string name="settings_announcements_idle_category_title">Stillstand Benachrichtigung</string>
<string name="settings_announcements_idle_title">Stillstand</string>
<string name="settings_ui_dynamic_colors_title">Dynamische Farben</string>
<string name="value_internal_sensor">Interner Sensor</string>
<string name="permission_recording_failed">OpenTracks benötigt die Berechtigubg, auf Ihren Standort sowie nahe gelegene Geräte zuzugreifen.</string>
<string name="sensor_state_power_max">Maximale Leistung</string>
<string name="sensor_state_power_unit">W</string>
<string name="settings_recording_title">Aufnahme</string>
<string name="settings_ui_dynamic_colors_summary">Verwenden Sie benutzerdefinierte dynamische Farben (nur Android 12+; erfordert einen manuellen Neustart)</string>
<string name="value_int_seconds">%1$d s (empfohlen)</string>
<string name="sensor_state_cadence_unit">Drehzahl</string>
<string name="sensor_state_heart_rate_unit">bpm</string>
<string name="activity_type_kickscooter">Roller</string>
<string name="settings_recording_location_distance_summary">%1$s zwischen aufgezeichneten Orten</string>
<string name="voiceSpeedMKnotsPlural">{n, plural, =1 {1 Knoten} other {{n,number,#.0} Knoten} }</string>
</resources>
+3 -1
View File
@@ -520,7 +520,7 @@ limitations under the License.
<string name="settings_gps_sensor">GPS</string>
<string name="settings_announcements_statistics_title">Avisos de voz</string>
<string name="settings_units_category">Unidades</string>
<string name="settings_import_export_title">Importar/Exportar</string>
<string name="settings_import_export_title">Importar y exportar</string>
<string name="stats_custom_layout_default_layout">Diseño predeterminado</string>
<string name="custom_layout_select_layout">Seleccionar diseño</string>
<string name="custom_layout_list_edit_already_exists">El nombre de este diseño ya existe</string>
@@ -654,4 +654,6 @@ limitations under the License.
<string name="bluetooth_sensor_summary">%1$s (%2$s)</string>
<string name="settings_recording_min_sampling_interval_title">Intervalo de muestreo</string>
<string name="settings_recording_location_distance_summary">%1$s entre lugares registrados</string>
<string name="settings_theme_switch_restart">Los cambios del tema pueden requerir un reinicio manual.</string>
<string name="settings_night_mode_option_night_oled">Oscuro (compatible con OLED)</string>
</resources>
+20 -20
View File
@@ -30,10 +30,10 @@ limitations under the License.
\n * funciona sen precisar conexión á rede
\n * mostra as rutas nun mapa (ver abaixo)</string>
<string name="help_track_map_title">Como mostrar a ruta no mapa\?</string>
<string name="help_track_map_content"> Usa a icona do mapa pequeno.
\n a) (actualizacións en directo) Instala <a href="https://github.com/OpenTracksApp/OSMDashboard">OSMDashboard</a>. Proporciona mapas en liña ou sen conexión grazas a <a href="https://www.openstreetmap.org">OpenStreetMap</a>.
\n En realidade, OSMDashboard é unha aplicación independente que só pode acceder (temporalmente) aos datos das pistas que se amosarán.
\n b) A través dunha aplicación de mapa normal (por exemplo, <a href="http://osmand.net/">OsmAnd</a> e <a href="https://maps.me/">MAPS.ME</a>). Estas aplicacións precisan admitir o formato de ficheiro KMZ (só localizacións e marcas de tempo). De feito, unha aplicación ten que admitir <i>ACTION_VIEW</i> con MIME <i>application/vnd.google-earth.kmz</i>. </string>
<string name="help_track_map_content"> \u0020Usa a icona do mapa pequeno.
\n a) (actualizacións en directo) Instala <a href="https://github.com/OpenTracksApp/OSMDashboard">OSMDashboard</a>. Proporciona mapas en liña ou sen conexión grazas a <a href="https://www.openstreetmap.org">OpenStreetMap</a>.
\n En realidade, OSMDashboard é unha aplicación independente que só pode acceder (temporalmente) aos datos das pistas que se amosarán.
\n b) A través dunha aplicación de mapa normal (por exemplo, <a href="http://osmand.net/">OsmAnd</a> e <a href="https://maps.me/">MAPS.ME</a>). Estas aplicacións precisan admitir o formato de ficheiro KMZ (só localizacións e marcas de tempo). De feito, unha aplicación ten que admitir <i>ACTION_VIEW</i> con MIME <i>application/vnd.google-earth.kmz</i>. \u0020</string>
<string name="help_storage_pictures_title">De que xeito garda OpenTracks as fotos tomadas como marcadores\?</string>
<string name="help_storage_pictures_content">Gárdanse na almacenaxe interna da app (só accesible desde OpenTracks).</string>
<string name="help_track_export_title">De que xeito exporto/importo as rutas gravadas\?</string>
@@ -46,27 +46,27 @@ Se o GPS informa sobre datos pouco precisos (ex.: localización, velocidade, ele
<string name="help_data_storage_title">De que xeito garda OpenTracks os datos dos sensores\?</string>
<string name="help_data_storage_content"> \u0020Os datos dos sensores gárdanse asociados á localización. \u0020 Respecto do ritmo cardíaco, significa que só se garda <i>unha medida</i> asociada a unha localización. \u0020 Se te detés ou estás en interiores, non se gardarán datos do sensor (mais serán mostrados). \u0020</string>
<string name="help_gps_troubleshooting_title">OpenTracks non grava as localizacións\?</string>
<string name="help_gps_troubleshooting_content"> Podes intentar:
\n a) mira que o GPS esté activado,
\n b) mellora a recepción GPS (ex. sae ao exterior),
\n c) comprobaa coa app <a href="https://f-droid.org/en/packages/com.android.gpstest.osmdroid/">GPSTest</a>, e
\n d) desactiva o aforro de enerxía.
\n
\n Se isto non axuda, infórmanos do problema. </string>
<string name="help_gps_troubleshooting_content"> \u0020Podes intentar:
\n a) mira que o GPS esté activado,
\n b) mellora a recepción GPS (ex. sae ao exterior),
\n c) comprobaa coa app <a href="https://f-droid.org/en/packages/com.android.gpstest.osmdroid/">GPSTest</a>, e
\n d) desactiva o aforro de enerxía.
\n
\n Se isto non axuda, infórmanos do problema. \u0020</string>
<string name="help_support_title">Como podo axudar a OpenTracks\?</string>
<string name="help_support_content"> Podes:
\n a) falar de OpenTracks coas túas amizades,
\n b) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">propoñer novas funcións</a>,
\n c) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">informar de fallos</a>,
\n d) axudar no desenvolvemento,
\n e) mercar a app na <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore">Google Play Store</a>,
\n f) facer unha doazón, e
\n g) calquera cousa que estimes axuda a OpenTracks. </string>
<string name="help_support_content"> \u0020Podes:
\n a) falar de OpenTracks coas túas amizades,
\n b) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">propoñer novas funcións</a>,
\n c) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">informar de fallos</a>,
\n d) axudar no desenvolvemento,
\n e) mercar a app na <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore">Google Play Store</a>,
\n f) facer unha doazón, e
\n g) calquera cousa que estimes axuda a OpenTracks. \u0020</string>
<string name="open_track_as_trackfileformat">Abrir como %1$s</string>
<!-- Activity Type -->
<string name="activity_type_airplane">avión</string>
<string name="activity_type_atv">Quad</string>
<string name="activity_type_biking">ciclismo</string>
<string name="activity_type_biking">ir en bici</string>
<string name="activity_type_blimp">dirixible</string>
<string name="activity_type_boat">barco</string>
<string name="activity_type_climbing">escalada</string>
+1 -1
View File
@@ -558,7 +558,7 @@ limitations under the License.
<string name="report_bug">Hibajelentés</string>
<string name="select_show_on_map_behavior">A „megjelenítés a térképen” viselkedés választása</string>
<string name="image_discard">Eldobás</string>
<string name="settings_import_export_title">Importálás/exportálás</string>
<string name="settings_import_export_title">Importálás és exportálás</string>
<string name="generic_undo">Visszavonás</string>
<string name="settings_sensor_heart_rate_max">Zónák: maximális pulzusszám (bpm)</string>
<string name="settings_public_api_disabled_toast">Az OpenTracks nyilvános API-ja le van tiltva: a beállításokban engedélyezhető.</string>
+4 -2
View File
@@ -481,7 +481,7 @@ limitations under the License.
<string name="settings_ui_title">用户界面</string>
<string name="settings_ui_summary">外观,记录中布局,主题</string>
<string name="settings_gps_sensor">GPS</string>
<string name="settings_import_export_title">导入/导出</string>
<string name="settings_import_export_title">导入与导出</string>
<string name="settings_activity_defaults_category">活动默认</string>
<string name="settings_announcements_totaltime_frequency">时间间隔</string>
<string name="settings_announcements_distance_frequency">每圈长度</string>
@@ -549,7 +549,7 @@ limitations under the License.
<string name="generic_undo">撤销</string>
<string name="generic_dismiss">关闭</string>
<string name="settings_defaults_title">默认的单位和活动类型</string>
<string name="settings_sensors_title">蓝牙传感器</string>
<string name="settings_sensors_title">传感器</string>
<string name="settings_sensors_summary">自行车传感器,车轮周长,跑步传感器</string>
<string name="settings_announcements_statistics_title">语音播报</string>
<string name="settings_reset_summary">将设置重置为默认值</string>
@@ -632,4 +632,6 @@ limitations under the License.
<string name="bluetooth_sensor_summary">%1$s (%2$s)</string>
<string name="settings_recording_min_sampling_interval_title">采样时间间隔</string>
<string name="settings_recording_location_distance_summary">每隔%1$s记录地点之间</string>
<string name="settings_theme_switch_restart">主题变更可能需要手动重启。</string>
<string name="settings_night_mode_option_night_oled">黑夜模式(OLED优化)</string>
</resources>