mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-10-02 09:33:06 +02:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9e496f97c1 | |||
| 455c2fcf75 | |||
| e590e4e07e | |||
| 36474e8541 | |||
| be7a43823a | |||
| 64326590e6 | |||
| 82aa23f0bb | |||
| 13eb5c30a2 | |||
| 7bbdd55a93 | |||
| 1617a7377b | |||
| af25d158e1 | |||
| 47525a260e | |||
| 2984a8328a | |||
| c7a9a1a7b5 | |||
| b56eaa740f | |||
| 214f4adb70 | |||
| bc1c3eabca | |||
| cd1ba6d1ae | |||
| 0c543e6083 | |||
| a28bf53245 | |||
| 6961f3ee50 | |||
| 52624b5cfe | |||
| dfdbc373ff |
+4
-4
@@ -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 脚本(翻译)
|
||||
+2
-1
@@ -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
|
||||
|
||||
+54
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user