mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-10-24 19:24:48 +02:00
Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0b30ecabb1 | |||
| 107cc14a2d | |||
| 6d3d8bb83c | |||
| 9c8e0335ef | |||
| 8c648c69e8 | |||
| 4422464f8d | |||
| d094531779 | |||
| a01341d235 | |||
| 83065dad39 | |||
| 68ba3e0c2a | |||
| 3f21edc44c | |||
| aefd1a6a35 | |||
| 74fa73e4a4 | |||
| 0a006d64f9 | |||
| 997ab6060e | |||
| 6d926ca7a8 | |||
| 3c1f1a9ba5 | |||
| ed5da55fba | |||
| d1e9649505 | |||
| 2431d60171 | |||
| e08f5e7273 | |||
| 7d2a6fff59 | |||
| a5158a55d9 | |||
| 15fbd90ca4 | |||
| eebc33f60c | |||
| ba2a755fb7 | |||
| 344c50a20c | |||
| 9a9a610321 | |||
| 8af427ea48 | |||
| 7b7d7c8061 | |||
| 7d6919d3f9 | |||
| 7eceb979c3 | |||
| bd48944ad5 | |||
| 503cba1315 | |||
| a313cb6244 | |||
| 7f0c6309c0 | |||
| 02c578327d | |||
| 7fec0dcff4 | |||
| 34eb7a833a | |||
| 5db3aa7ac1 | |||
| 47fd7c51a9 | |||
| 2f6f0b4e17 | |||
| 41b794f66b | |||
| e2c592367a | |||
| 7a24c56474 | |||
| 3f6bd6926a | |||
| 508af45449 | |||
| 0f89cd7875 | |||
| 29b522b8a2 | |||
| 14e63a1a54 | |||
| e559583d23 |
@@ -19,6 +19,12 @@ However, often only one value is provided.
|
|||||||
### Speed
|
### Speed
|
||||||
|
|
||||||
* Garmin Speed Sensor 2
|
* Garmin Speed Sensor 2
|
||||||
|
* Has updatable firmware that requires an account for garmin.com
|
||||||
|
* This sensor reports speed data as cadence.
|
||||||
|
A workaround is in place.
|
||||||
|
* This sensor sometimes counts backwards (unknown software version).
|
||||||
|
A workaround is in place.
|
||||||
|
|
||||||
* Wahoo Speed (Model: WFRPMSPD)
|
* Wahoo Speed (Model: WFRPMSPD)
|
||||||
|
|
||||||
### Cadence
|
### Cadence
|
||||||
|
|||||||
+4
-4
@@ -6,7 +6,7 @@ buildscript {
|
|||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:4.1.2'
|
classpath 'com.android.tools.build:gradle:4.1.3'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,8 +51,8 @@ android {
|
|||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "de.dennisguse.opentracks"
|
applicationId "de.dennisguse.opentracks"
|
||||||
versionCode 3890
|
versionCode 3941
|
||||||
versionName "v3.15.3"
|
versionName "v3.16.0"
|
||||||
|
|
||||||
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
|
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0-alpha04'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0-alpha05'
|
||||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
||||||
|
|
||||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||||
|
|||||||
@@ -2,17 +2,7 @@
|
|||||||
interface TrackExporter {
|
interface TrackExporter {
|
||||||
}
|
}
|
||||||
class KmzTrackExporter implements TrackExporter
|
class KmzTrackExporter implements TrackExporter
|
||||||
KmzTrackExporter o-- FileTrackExporter
|
class KmlTrackExporter implements TrackExporter
|
||||||
class FileTrackExporter implements TrackExporter {
|
|
||||||
/' One track only '/
|
|
||||||
}
|
|
||||||
FileTrackExporter o-- TrackWriter
|
|
||||||
|
|
||||||
interface TrackWriter {
|
|
||||||
}
|
|
||||||
class GpxTrackWriter implements TrackWriter
|
|
||||||
class KmlTrackWriter implements TrackWriter
|
|
||||||
|
|
||||||
|
|
||||||
interface TrackImporter {
|
interface TrackImporter {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,32 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||||
targetNamespace="http://opentracksapp.com/xmlschemas/v1">
|
targetNamespace="http://opentracksapp.com/xmlschemas/v1">
|
||||||
|
|
||||||
<xs:element name="trackuuid"
|
<xsd:element name="trackuuid"
|
||||||
type="xs:string" />
|
type="xsd:string">
|
||||||
|
<xsd:annotation>
|
||||||
|
<xsd:documentation xml:lang="en">
|
||||||
|
A unique track identifier stored as UUID.
|
||||||
|
</xsd:documentation>
|
||||||
|
</xsd:annotation>
|
||||||
|
</xsd:element>
|
||||||
|
|
||||||
</xs:schema>
|
<xsd:element name="loss"
|
||||||
|
type="xsd:float">
|
||||||
|
<xsd:annotation>
|
||||||
|
<xsd:documentation xml:lang="en">
|
||||||
|
The lost elevation in meters from the previous to the current TrackPoint.
|
||||||
|
Only used in GPX.
|
||||||
|
</xsd:documentation>
|
||||||
|
</xsd:annotation>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="gain"
|
||||||
|
type="xsd:string">
|
||||||
|
<xsd:annotation>
|
||||||
|
<xsd:documentation xml:lang="en">
|
||||||
|
The gained elevation in meters from the previous to the current TrackPoint.
|
||||||
|
Only used in GPX.
|
||||||
|
</xsd:documentation>
|
||||||
|
</xsd:annotation>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
v3.15.4: OpenTracks
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Voice annoucements interval should be in minutes (introduced in v3.15.0)
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
v3.16.0: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Cycling: get distance from BLE speed sensor
|
||||||
|
- Reworked UI presented while recording
|
||||||
|
- UI performance optimizations
|
||||||
|
- Exported filenames: <First 32bits UUID>_<track's name>.<extension>
|
||||||
|
- Import multiple files via Intent (e.g., from Gadgetbridge)
|
||||||
|
- GPX: export power data
|
||||||
|
- Updated translations
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Voice announcement use minutes correctly
|
||||||
@@ -11,6 +11,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
|
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
||||||
import de.dennisguse.opentracks.util.FileUtils;
|
import de.dennisguse.opentracks.util.FileUtils;
|
||||||
|
|
||||||
public class TestDataUtil {
|
public class TestDataUtil {
|
||||||
@@ -150,4 +151,13 @@ public class TestDataUtil {
|
|||||||
|
|
||||||
return new Marker("Marker name", "Marker description", "Marker category", "", trackId, 0.0, 0, trackPoint, photoUrl);
|
return new Marker("Marker name", "Marker description", "Marker category", "", trackId, 0.0, 0, trackPoint, photoUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<TrackPoint> getTrackPoints(ContentProviderUtils contentProviderUtils, Track.Id trackId) {
|
||||||
|
TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null);
|
||||||
|
ArrayList<TrackPoint> trackPoints = new ArrayList<>();
|
||||||
|
while (trackPointIterator.hasNext()) {
|
||||||
|
trackPoints.add(trackPointIterator.next());
|
||||||
|
}
|
||||||
|
return trackPoints;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -7,8 +7,8 @@ import java.util.List;
|
|||||||
|
|
||||||
public class TestSensorDataUtil {
|
public class TestSensorDataUtil {
|
||||||
|
|
||||||
private List<TrackPoint> trackPointList = new ArrayList<>();
|
private final List<TrackPoint> trackPointList = new ArrayList<>();
|
||||||
private List<SensorData> sensorDataList = new ArrayList<>();
|
private final List<SensorData> sensorDataList = new ArrayList<>();
|
||||||
|
|
||||||
public void add(Instant time, Float hr, Float cadence, Float power, TrackPoint.Type type) {
|
public void add(Instant time, Float hr, Float cadence, Float power, TrackPoint.Type type) {
|
||||||
sensorDataList.add(new TestSensorDataUtil.SensorData(time, hr, cadence, power, type));
|
sensorDataList.add(new TestSensorDataUtil.SensorData(time, hr, cadence, power, type));
|
||||||
@@ -33,7 +33,7 @@ public class TestSensorDataUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SensorDataStats computeStats() {
|
public SensorDataStats computeStats() {
|
||||||
if (sensorDataList == null || sensorDataList.size() <= 1) {
|
if (sensorDataList.size() <= 1) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,9 +49,9 @@ public class TestSensorDataUtil {
|
|||||||
if (dataPrev.type != TrackPoint.Type.SEGMENT_START_MANUAL) {
|
if (dataPrev.type != TrackPoint.Type.SEGMENT_START_MANUAL) {
|
||||||
timeElapsed = dataCurrent.type != TrackPoint.Type.SEGMENT_START_MANUAL ? dataCurrent.time.getEpochSecond() - dataPrev.time.getEpochSecond() : 0;
|
timeElapsed = dataCurrent.type != TrackPoint.Type.SEGMENT_START_MANUAL ? dataCurrent.time.getEpochSecond() - dataPrev.time.getEpochSecond() : 0;
|
||||||
stats.avgHr += (dataPrev.hr * timeElapsed);
|
stats.avgHr += (dataPrev.hr * timeElapsed);
|
||||||
stats.maxHr = dataPrev.hr > stats.maxHr ? dataPrev.hr : stats.maxHr;
|
stats.maxHr = Math.max(dataPrev.hr, stats.maxHr);
|
||||||
stats.avgCadence += (dataPrev.cadence * timeElapsed);
|
stats.avgCadence += (dataPrev.cadence * timeElapsed);
|
||||||
stats.maxCadence = dataPrev.cadence > stats.maxCadence ? dataPrev.cadence : stats.maxCadence;
|
stats.maxCadence = Math.max(dataPrev.cadence, stats.maxCadence);
|
||||||
stats.avgPower += (dataPrev.power * timeElapsed);
|
stats.avgPower += (dataPrev.power * timeElapsed);
|
||||||
|
|
||||||
movingTime += timeElapsed;
|
movingTime += timeElapsed;
|
||||||
@@ -67,11 +67,11 @@ public class TestSensorDataUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class SensorData {
|
private static class SensorData {
|
||||||
Instant time;
|
final Instant time;
|
||||||
float hr;
|
final float hr;
|
||||||
float cadence;
|
final float cadence;
|
||||||
float power;
|
final float power;
|
||||||
TrackPoint.Type type;
|
final TrackPoint.Type type;
|
||||||
|
|
||||||
public SensorData(Instant time, Float hr, Float cadence, Float power, TrackPoint.Type type) {
|
public SensorData(Instant time, Float hr, Float cadence, Float power, TrackPoint.Type type) {
|
||||||
this.time = time;
|
this.time = time;
|
||||||
|
|||||||
+17
-24
@@ -94,29 +94,22 @@ public class CustomContentProviderUtilsTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLocationIterator_noPoints() {
|
public void testLocationIterator_noPoints() {
|
||||||
testIterator(new Track.Id(1), 0, 1);
|
testIterator(new Track.Id(1), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLocationIterator_noBatchAscending() {
|
public void testLocationIterator_noAscending() {
|
||||||
testIterator(new Track.Id(1), 50, 100);
|
testIterator(new Track.Id(1), 50);
|
||||||
testIterator(new Track.Id(2), 50, 50);
|
testIterator(new Track.Id(2), 50);
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testLocationIterator_batchAscending() {
|
|
||||||
testIterator(new Track.Id(1), 50, 11);
|
|
||||||
testIterator(new Track.Id(2), 50, 25);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLocationIterator_largeTrack() {
|
public void testLocationIterator_largeTrack() {
|
||||||
testIterator(new Track.Id(1), 20000, 2000);
|
testIterator(new Track.Id(1), 20000);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testIterator(Track.Id trackId, int numPoints, int batchSize) {
|
private void testIterator(Track.Id trackId, int numPoints) {
|
||||||
long lastPointId = initializeTrack(trackId, numPoints);
|
TrackPoint.Id lastPointId = initializeTrack(trackId, numPoints);
|
||||||
contentProviderUtils.setDefaultCursorBatchSize(batchSize);
|
|
||||||
List<TrackPoint> locations = new ArrayList<>(numPoints);
|
List<TrackPoint> locations = new ArrayList<>(numPoints);
|
||||||
try (TrackPointIterator it = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
|
try (TrackPointIterator it = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
@@ -124,13 +117,13 @@ public class CustomContentProviderUtilsTest {
|
|||||||
assertNotNull(trackPoint);
|
assertNotNull(trackPoint);
|
||||||
locations.add(trackPoint);
|
locations.add(trackPoint);
|
||||||
// Make sure the IDs are returned in the right order.
|
// Make sure the IDs are returned in the right order.
|
||||||
assertEquals(lastPointId - numPoints + locations.size(), trackPoint.getId().getId());
|
assertEquals(lastPointId.getId() - numPoints + locations.size(), trackPoint.getId().getId());
|
||||||
}
|
}
|
||||||
assertEquals(numPoints, locations.size());
|
assertEquals(numPoints, locations.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private long initializeTrack(Track.Id id, int numPoints) {
|
private TrackPoint.Id initializeTrack(Track.Id id, int numPoints) {
|
||||||
Track track = new Track();
|
Track track = new Track();
|
||||||
track.setId(id);
|
track.setId(id);
|
||||||
track.setName("Test: " + id.getId());
|
track.setName("Test: " + id.getId());
|
||||||
@@ -150,17 +143,17 @@ public class CustomContentProviderUtilsTest {
|
|||||||
contentProviderUtils.bulkInsertTrackPoint(trackPoints, id);
|
contentProviderUtils.bulkInsertTrackPoint(trackPoints, id);
|
||||||
|
|
||||||
// Load all inserted trackPoints.
|
// Load all inserted trackPoints.
|
||||||
long lastPointId = -1;
|
TrackPoint.Id lastPointId = null;
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
try (TrackPointIterator it = contentProviderUtils.getTrackPointLocationIterator(id, null)) {
|
try (TrackPointIterator it = contentProviderUtils.getTrackPointLocationIterator(id, null)) {
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
TrackPoint trackPoint = it.next();
|
TrackPoint trackPoint = it.next();
|
||||||
lastPointId = trackPoint.getId().getId();
|
lastPointId = trackPoint.getId();
|
||||||
counter++;
|
counter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue(numPoints == 0 || lastPointId > 0);
|
assertTrue(numPoints == 0 || lastPointId.getId() > 0);
|
||||||
assertEquals(numPoints, counter);
|
assertEquals(numPoints, counter);
|
||||||
|
|
||||||
return lastPointId;
|
return lastPointId;
|
||||||
@@ -770,9 +763,9 @@ public class CustomContentProviderUtilsTest {
|
|||||||
|
|
||||||
// when / then
|
// when / then
|
||||||
contentProviderUtils.bulkInsertTrackPoint(track.second, trackId);
|
contentProviderUtils.bulkInsertTrackPoint(track.second, trackId);
|
||||||
assertEquals(20, contentProviderUtils.getTrackPointCursor(trackId, null, 1000).getCount());
|
assertEquals(20, contentProviderUtils.getTrackPointCursor(trackId, null).getCount());
|
||||||
contentProviderUtils.bulkInsertTrackPoint(track.second.subList(0, 8), trackId);
|
contentProviderUtils.bulkInsertTrackPoint(track.second.subList(0, 8), trackId);
|
||||||
assertEquals(28, contentProviderUtils.getTrackPointCursor(trackId, null, 1000).getCount());
|
assertEquals(28, contentProviderUtils.getTrackPointCursor(trackId, null).getCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -829,7 +822,7 @@ public class CustomContentProviderUtilsTest {
|
|||||||
Track track = TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
Track track = TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||||
|
|
||||||
contentProviderUtils.insertTrackPoint(TestDataUtil.createTrackPoint(22), trackId);
|
contentProviderUtils.insertTrackPoint(TestDataUtil.createTrackPoint(22), trackId);
|
||||||
assertEquals(11, contentProviderUtils.getTrackPoints(trackId).size());
|
assertEquals(11, contentProviderUtils.getTrackPointCursor(trackId, null).getCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -847,7 +840,7 @@ public class CustomContentProviderUtilsTest {
|
|||||||
contentProviderUtils.insertTrackPoint(trackPoint, trackId);
|
contentProviderUtils.insertTrackPoint(trackPoint, trackId);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
||||||
assertTrue(trackPoints.get(10).hasHeartRate());
|
assertTrue(trackPoints.get(10).hasHeartRate());
|
||||||
assertEquals(trackPoint.getHeartRate_bpm(), trackPoints.get(10).getHeartRate_bpm(), 0.01);
|
assertEquals(trackPoint.getHeartRate_bpm(), trackPoints.get(10).getHeartRate_bpm(), 0.01);
|
||||||
assertEquals(trackPoint.getCyclingCadence_rpm(), trackPoints.get(10).getCyclingCadence_rpm(), 0.01);
|
assertEquals(trackPoint.getCyclingCadence_rpm(), trackPoints.get(10).getCyclingCadence_rpm(), 0.01);
|
||||||
@@ -879,7 +872,7 @@ public class CustomContentProviderUtilsTest {
|
|||||||
.map(TrackPoint.Id::new).collect(Collectors.toList());
|
.map(TrackPoint.Id::new).collect(Collectors.toList());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
Cursor cursor = contentProviderUtils.getTrackPointCursor(trackId, trackpointIds.get(8), 5);
|
Cursor cursor = contentProviderUtils.getTrackPointCursor(trackId, trackpointIds.get(8));
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(2, cursor.getCount());
|
assertEquals(2, cursor.getCount());
|
||||||
|
|||||||
+10
-8
@@ -96,34 +96,36 @@ public class SensorDataCyclingTest {
|
|||||||
@Test
|
@Test
|
||||||
public void compute_speed() {
|
public void compute_speed() {
|
||||||
// given
|
// given
|
||||||
SensorDataCycling.Speed previous = new SensorDataCycling.Speed("sensorAddress", "sensorName", 1, 6184);
|
SensorDataCycling.DistanceSpeed previous = new SensorDataCycling.DistanceSpeed("sensorAddress", "sensorName", 1, 6184);
|
||||||
SensorDataCycling.Speed current = new SensorDataCycling.Speed("sensorAddress", "sensorName", 2, 8016);
|
SensorDataCycling.DistanceSpeed current = new SensorDataCycling.DistanceSpeed("sensorAddress", "sensorName", 2, 8016);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
current.compute(previous, 2150);
|
current.compute(previous, 2150);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(1.20, current.getValue(), 0.01);
|
assertEquals(1.20, current.getValue().distance_m, 2150);
|
||||||
|
assertEquals(1.20, current.getValue().speed_mps, 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void compute_speed_rollOverCount() {
|
public void compute_speed_rollOverCount() {
|
||||||
// given
|
// given
|
||||||
SensorDataCycling.Speed previous = new SensorDataCycling.Speed("sensorAddress", "sensorName", UintUtils.UINT16_MAX - 1, 1024);
|
SensorDataCycling.DistanceSpeed previous = new SensorDataCycling.DistanceSpeed("sensorAddress", "sensorName", UintUtils.UINT16_MAX - 1, 1024);
|
||||||
SensorDataCycling.Speed current = new SensorDataCycling.Speed("sensorAddress", "sensorName", 0, 2048);
|
SensorDataCycling.DistanceSpeed current = new SensorDataCycling.DistanceSpeed("sensorAddress", "sensorName", 0, 2048);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
current.compute(previous, 2000);
|
current.compute(previous, 2000);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(2, current.getValue(), 0.01);
|
assertEquals(1.20, current.getValue().distance_m, 2000);
|
||||||
|
assertEquals(2, current.getValue().speed_mps, 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void equals_speed_with_no_data() {
|
public void equals_speed_with_no_data() {
|
||||||
// given
|
// given
|
||||||
SensorDataCycling.Speed previous = new SensorDataCycling.Speed("sensorAddress");
|
SensorDataCycling.DistanceSpeed previous = new SensorDataCycling.DistanceSpeed("sensorAddress");
|
||||||
SensorDataCycling.Speed current = new SensorDataCycling.Speed("sensorAddress", "sensorName", 0, 2048);
|
SensorDataCycling.DistanceSpeed current = new SensorDataCycling.DistanceSpeed("sensorAddress", "sensorName", 0, 2048);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
previous.toString();
|
previous.toString();
|
||||||
|
|||||||
+40
-70
@@ -2,7 +2,7 @@ package de.dennisguse.opentracks.io.file.importer;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.location.Location;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
@@ -23,6 +23,7 @@ import org.junit.runners.JUnit4;
|
|||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -31,6 +32,7 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.content.data.Marker;
|
import de.dennisguse.opentracks.content.data.Marker;
|
||||||
|
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
@@ -69,6 +71,7 @@ public class ExportImportTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final Context context = ApplicationProvider.getApplicationContext();
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
private final SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||||
|
|
||||||
private final ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
|
private final ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
|
||||||
|
|
||||||
@@ -89,17 +92,17 @@ public class ExportImportTest {
|
|||||||
|
|
||||||
trackId = service.startNewTrack();
|
trackId = service.startNewTrack();
|
||||||
|
|
||||||
service.newTrackPoint(createTrackPoint(System.currentTimeMillis(), 3, 14, 10, 15, 10, 0, 66, 3, 50), 0);
|
service.newTrackPoint(createTrackPoint(System.currentTimeMillis(), 3, 14, 10, 15, 10, 0, 66, 3, 50, 5), 0);
|
||||||
service.insertMarker("Marker 1", "Marker 1 category", "Marker 1 desc", null);
|
service.insertMarker("Marker 1", "Marker 1 category", "Marker 1 desc", null);
|
||||||
service.newTrackPoint(createTrackPoint(System.currentTimeMillis(), 3, 14.001, 10, 15, 10, 0, 66, 3, 50), 0);
|
service.newTrackPoint(createTrackPoint(System.currentTimeMillis(), 3, 14.001, 10, 15, 10, 0, 66, 3, 50, 5), 0);
|
||||||
service.newTrackPoint(createTrackPoint(System.currentTimeMillis(), 3, 14.002, 10, 15, 10, 0, 66, 3, 50), 0);
|
service.newTrackPoint(createTrackPoint(System.currentTimeMillis(), 3, 14.002, 10, 15, 10, 0, 66, 3, 50, 5), 0);
|
||||||
service.insertMarker("Marker 2", "Marker 2 category", "Marker 2 desc", null);
|
service.insertMarker("Marker 2", "Marker 2 category", "Marker 2 desc", null);
|
||||||
service.pauseCurrentTrack();
|
service.pauseCurrentTrack();
|
||||||
|
|
||||||
service.resumeCurrentTrack();
|
service.resumeCurrentTrack();
|
||||||
service.newTrackPoint(createTrackPoint(System.currentTimeMillis(), 3, 14.003, 10, 15, 10, 0, 66, 3, 50), 0);
|
service.newTrackPoint(createTrackPoint(System.currentTimeMillis(), 3, 14.003, 10, 15, 10, 0, 66, 3, 50, 5), 0);
|
||||||
service.newTrackPoint(createTrackPoint(System.currentTimeMillis(), 3, 16, 10, 15, 10, 0, 66, 3, 50), 0);
|
service.newTrackPoint(createTrackPoint(System.currentTimeMillis(), 3, 16, 10, 15, 10, 0, 66, 3, 50, 5), 0);
|
||||||
service.newTrackPoint(createTrackPoint(System.currentTimeMillis(), 3, 16.001, 10, 15, 10, 0, 66, 3, 50), 0);
|
service.newTrackPoint(createTrackPoint(System.currentTimeMillis(), 3, 16.001, 10, 15, 10, 0, 66, 3, 50, 5), 0);
|
||||||
service.endCurrentTrack();
|
service.endCurrentTrack();
|
||||||
|
|
||||||
track = contentProviderUtils.getTrack(trackId);
|
track = contentProviderUtils.getTrack(trackId);
|
||||||
@@ -109,7 +112,7 @@ public class ExportImportTest {
|
|||||||
contentProviderUtils.updateTrack(track);
|
contentProviderUtils.updateTrack(track);
|
||||||
|
|
||||||
track = contentProviderUtils.getTrack(trackId);
|
track = contentProviderUtils.getTrack(trackId);
|
||||||
trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
||||||
markers = contentProviderUtils.getMarkers(trackId);
|
markers = contentProviderUtils.getMarkers(trackId);
|
||||||
assertEquals(10, trackPoints.size());
|
assertEquals(10, trackPoints.size());
|
||||||
assertEquals(2, markers.size());
|
assertEquals(2, markers.size());
|
||||||
@@ -148,7 +151,7 @@ public class ExportImportTest {
|
|||||||
// 2. import
|
// 2. import
|
||||||
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
||||||
AbstractFileTrackImporter trackImporter = new KmlFileTrackImporter(context);
|
AbstractFileTrackImporter trackImporter = new KmlFileTrackImporter(context);
|
||||||
importTrackId = trackImporter.importFile(inputStream);
|
importTrackId = trackImporter.importFile(inputStream).get(0);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
// 1. track
|
// 1. track
|
||||||
@@ -161,10 +164,10 @@ public class ExportImportTest {
|
|||||||
assertEquals(track.getUuid(), importedTrack.getUuid());
|
assertEquals(track.getUuid(), importedTrack.getUuid());
|
||||||
|
|
||||||
// 2. trackpoints
|
// 2. trackpoints
|
||||||
assertTrackpoints(trackPoints, false, false, false, false, false);
|
assertTrackpoints(trackPoints, false, false, false, false, false, false);
|
||||||
|
|
||||||
// 3. trackstatistics
|
// 3. trackstatistics
|
||||||
assertTrackStatistics(false, false);
|
assertTrackStatistics(false, false, false);
|
||||||
|
|
||||||
// 4. markers
|
// 4. markers
|
||||||
assertMarkers();
|
assertMarkers();
|
||||||
@@ -187,7 +190,7 @@ public class ExportImportTest {
|
|||||||
// 2. import
|
// 2. import
|
||||||
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
||||||
AbstractFileTrackImporter trackImporter = new KmlFileTrackImporter(context);
|
AbstractFileTrackImporter trackImporter = new KmlFileTrackImporter(context);
|
||||||
importTrackId = trackImporter.importFile(inputStream);
|
importTrackId = trackImporter.importFile(inputStream).get(0);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
// 1. track
|
// 1. track
|
||||||
@@ -199,10 +202,10 @@ public class ExportImportTest {
|
|||||||
assertEquals(track.getIcon(), importedTrack.getIcon());
|
assertEquals(track.getIcon(), importedTrack.getIcon());
|
||||||
|
|
||||||
// 2. trackpoints
|
// 2. trackpoints
|
||||||
assertTrackpoints(trackPoints, true, true, true, true, true);
|
assertTrackpoints(trackPoints, true, true, true, true, true, true);
|
||||||
|
|
||||||
// 2. trackstatistics
|
// 2. trackstatistics
|
||||||
assertTrackStatistics(false, true);
|
assertTrackStatistics(false, true, true);
|
||||||
|
|
||||||
// 4. markers
|
// 4. markers
|
||||||
assertMarkers();
|
assertMarkers();
|
||||||
@@ -212,7 +215,7 @@ public class ExportImportTest {
|
|||||||
@Test(expected = ImportAlreadyExistsException.class)
|
@Test(expected = ImportAlreadyExistsException.class)
|
||||||
public void kml_with_trackdetail_and_sensordata_duplicate_trackUUID() {
|
public void kml_with_trackdetail_and_sensordata_duplicate_trackUUID() {
|
||||||
// given
|
// given
|
||||||
PreferencesUtils.setBoolean(context, R.string.import_prevent_reimport_key, true);
|
PreferencesUtils.setBoolean(sharedPreferences, context, R.string.import_prevent_reimport_key, true);
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
|
|
||||||
TrackExporter trackExporter = TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA.createTrackExporter(context);
|
TrackExporter trackExporter = TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA.createTrackExporter(context);
|
||||||
@@ -225,45 +228,13 @@ public class ExportImportTest {
|
|||||||
// 2. import
|
// 2. import
|
||||||
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
||||||
AbstractFileTrackImporter trackImporter = new KmlFileTrackImporter(context);
|
AbstractFileTrackImporter trackImporter = new KmlFileTrackImporter(context);
|
||||||
importTrackId = trackImporter.importFile(inputStream);
|
importTrackId = trackImporter.importFile(inputStream).get(0);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
|
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
|
||||||
assertNull(importedTrack);
|
assertNull(importedTrack);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@LargeTest
|
|
||||||
@Test
|
|
||||||
public void kmz_only_track() {
|
|
||||||
// TODO
|
|
||||||
Log.e(TAG, "Test not implemented.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@LargeTest
|
|
||||||
@Test
|
|
||||||
public void kmz_with_trackdetail() {
|
|
||||||
// TODO
|
|
||||||
Log.e(TAG, "Test not implemented.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@LargeTest
|
|
||||||
@Test
|
|
||||||
public void kmz_with_trackdetail_and_sensordata() {
|
|
||||||
// TODO
|
|
||||||
Log.e(TAG, "Test not implemented.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@LargeTest
|
|
||||||
@Test
|
|
||||||
public void kmz_with_trackdetail_and_sensordata_and_pictures() {
|
|
||||||
// TODO
|
|
||||||
Log.e(TAG, "Test not implemented.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@LargeTest
|
@LargeTest
|
||||||
@Test
|
@Test
|
||||||
public void gpx() {
|
public void gpx() {
|
||||||
@@ -281,7 +252,7 @@ public class ExportImportTest {
|
|||||||
// 2. import
|
// 2. import
|
||||||
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
||||||
AbstractFileTrackImporter trackImporter = new GpxFileTrackImporter(context, contentProviderUtils);
|
AbstractFileTrackImporter trackImporter = new GpxFileTrackImporter(context, contentProviderUtils);
|
||||||
importTrackId = trackImporter.importFile(inputStream);
|
importTrackId = trackImporter.importFile(inputStream).get(0);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
// 1. track
|
// 1. track
|
||||||
@@ -301,10 +272,10 @@ public class ExportImportTest {
|
|||||||
trackPointsWithCoordinates.get(0).setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC);
|
trackPointsWithCoordinates.get(0).setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC);
|
||||||
trackPointsWithCoordinates.get(3).setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC);
|
trackPointsWithCoordinates.get(3).setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC);
|
||||||
|
|
||||||
assertTrackpoints(trackPointsWithCoordinates, false, true, true, true, true);
|
assertTrackpoints(trackPointsWithCoordinates, true, true, true, true, true, false);
|
||||||
|
|
||||||
// 3. trackstatistics
|
// 3. trackstatistics
|
||||||
assertTrackStatistics(true, true);
|
assertTrackStatistics(true, true, false);
|
||||||
|
|
||||||
// 4. markers
|
// 4. markers
|
||||||
assertMarkers();
|
assertMarkers();
|
||||||
@@ -314,7 +285,7 @@ public class ExportImportTest {
|
|||||||
@Test(expected = ImportAlreadyExistsException.class)
|
@Test(expected = ImportAlreadyExistsException.class)
|
||||||
public void gpx_duplicate_trackUUID() {
|
public void gpx_duplicate_trackUUID() {
|
||||||
// given
|
// given
|
||||||
PreferencesUtils.setBoolean(context, R.string.import_prevent_reimport_key, true);
|
PreferencesUtils.setBoolean(sharedPreferences, context, R.string.import_prevent_reimport_key, true);
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
|
|
||||||
TrackExporter trackExporter = TrackFileFormat.GPX.createTrackExporter(context);
|
TrackExporter trackExporter = TrackFileFormat.GPX.createTrackExporter(context);
|
||||||
@@ -327,7 +298,7 @@ public class ExportImportTest {
|
|||||||
// 2. import
|
// 2. import
|
||||||
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
|
||||||
AbstractFileTrackImporter trackImporter = new GpxFileTrackImporter(context, contentProviderUtils);
|
AbstractFileTrackImporter trackImporter = new GpxFileTrackImporter(context, contentProviderUtils);
|
||||||
importTrackId = trackImporter.importFile(inputStream);
|
importTrackId = trackImporter.importFile(inputStream).get(0);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
// 1. track
|
// 1. track
|
||||||
@@ -354,9 +325,8 @@ public class ExportImportTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertTrackpoints(List<TrackPoint> trackPoints, boolean verifyPower, boolean verifyHeartrate, boolean verifyCadence, boolean verifyElevationGain, boolean verifyElevationLoss) {
|
private void assertTrackpoints(List<TrackPoint> trackPoints, boolean verifyPower, boolean verifyHeartrate, boolean verifyCadence, boolean verifyElevationGain, boolean verifyElevationLoss, boolean verifyDistance) {
|
||||||
List<TrackPoint> importedTrackPoints = contentProviderUtils.getTrackPoints(importTrackId);
|
List<TrackPoint> importedTrackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
|
||||||
|
|
||||||
assertEquals(trackPoints.size(), importedTrackPoints.size());
|
assertEquals(trackPoints.size(), importedTrackPoints.size());
|
||||||
|
|
||||||
for (int i = 0; i < trackPoints.size(); i++) {
|
for (int i = 0; i < trackPoints.size(); i++) {
|
||||||
@@ -391,13 +361,13 @@ public class ExportImportTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (verifyHeartrate) {
|
if (verifyHeartrate) {
|
||||||
assertEquals(trackPoint.getHeartRate_bpm(), importedTrackPoint.getHeartRate_bpm(), 0.01);
|
assertEquals("" + trackPoint, trackPoint.getHeartRate_bpm(), importedTrackPoint.getHeartRate_bpm(), 0.01);
|
||||||
}
|
}
|
||||||
if (verifyCadence) {
|
if (verifyCadence) {
|
||||||
assertEquals(trackPoint.getCyclingCadence_rpm(), importedTrackPoint.getCyclingCadence_rpm(), 0.01);
|
assertEquals("" + trackPoint, trackPoint.getCyclingCadence_rpm(), importedTrackPoint.getCyclingCadence_rpm(), 0.01);
|
||||||
}
|
}
|
||||||
if (verifyPower) {
|
if (verifyPower) {
|
||||||
assertEquals(trackPoint.getPower(), importedTrackPoint.getPower(), 0.01);
|
assertEquals("" + trackPoint, trackPoint.getPower(), importedTrackPoint.getPower(), 0.01);
|
||||||
}
|
}
|
||||||
if (verifyElevationGain) {
|
if (verifyElevationGain) {
|
||||||
assertEquals(trackPoint.getElevationGain(), importedTrackPoint.getElevationGain(), 0.01);
|
assertEquals(trackPoint.getElevationGain(), importedTrackPoint.getElevationGain(), 0.01);
|
||||||
@@ -405,10 +375,13 @@ public class ExportImportTest {
|
|||||||
if (verifyElevationLoss) {
|
if (verifyElevationLoss) {
|
||||||
assertEquals(trackPoint.getElevationLoss(), importedTrackPoint.getElevationLoss(), 0.01);
|
assertEquals(trackPoint.getElevationLoss(), importedTrackPoint.getElevationLoss(), 0.01);
|
||||||
}
|
}
|
||||||
|
if (verifyDistance) {
|
||||||
|
assertEquals(trackPoint.getSensorDistance(), importedTrackPoint.getSensorDistance(), 0.01);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertTrackStatistics(boolean isGpx, boolean verifyElevationGainAndLoss) {
|
private void assertTrackStatistics(boolean isGpx, boolean verifyElevationGainAndLoss, boolean verifyDistance) {
|
||||||
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
|
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
|
||||||
|
|
||||||
assertNotNull(importedTrack.getTrackStatistics());
|
assertNotNull(importedTrack.getTrackStatistics());
|
||||||
@@ -426,7 +399,9 @@ public class ExportImportTest {
|
|||||||
assertEquals(trackStatistics.getMovingTime(), importedTrackStatistics.getMovingTime());
|
assertEquals(trackStatistics.getMovingTime(), importedTrackStatistics.getMovingTime());
|
||||||
|
|
||||||
// Distance
|
// Distance
|
||||||
|
if (verifyDistance) {
|
||||||
assertEquals(trackStatistics.getTotalDistance(), importedTrackStatistics.getTotalDistance(), 0.01);
|
assertEquals(trackStatistics.getTotalDistance(), importedTrackStatistics.getTotalDistance(), 0.01);
|
||||||
|
}
|
||||||
|
|
||||||
// Speed
|
// Speed
|
||||||
assertEquals(trackStatistics.getMaxSpeed(), importedTrackStatistics.getMaxSpeed(), 0.01);
|
assertEquals(trackStatistics.getMaxSpeed(), importedTrackStatistics.getMaxSpeed(), 0.01);
|
||||||
@@ -446,20 +421,15 @@ public class ExportImportTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TrackPoint createTrackPoint(long time, double latitude, double longitude, float accuracy, long speed, long altitude, float elevationGain, float heartRate, float cyclingCadence, float power) {
|
private static TrackPoint createTrackPoint(long time, double latitude, double longitude, float accuracy, float speed, float altitude, float elevationGain, float heartRate, float cyclingCadence, float power, float distance) {
|
||||||
Location location = new Location("");
|
TrackPoint tp = new TrackPoint(latitude, longitude, (double) altitude, Instant.ofEpochMilli(time));
|
||||||
location.setTime(time);
|
tp.setAccuracy(accuracy);
|
||||||
location.setLongitude(longitude);
|
tp.setSpeed(speed);
|
||||||
location.setLatitude(latitude);
|
|
||||||
location.setAccuracy(accuracy);
|
|
||||||
location.setAltitude(altitude);
|
|
||||||
location.setSpeed(speed);
|
|
||||||
|
|
||||||
TrackPoint tp = new TrackPoint(location);
|
|
||||||
tp.setHeartRate_bpm(heartRate);
|
tp.setHeartRate_bpm(heartRate);
|
||||||
tp.setCyclingCadence_rpm(cyclingCadence);
|
tp.setCyclingCadence_rpm(cyclingCadence);
|
||||||
tp.setPower(power);
|
tp.setPower(power);
|
||||||
tp.setElevationGain(elevationGain);
|
tp.setElevationGain(elevationGain);
|
||||||
|
tp.setSensorDistance(distance);
|
||||||
return tp;
|
return tp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+6
-5
@@ -14,6 +14,7 @@ import org.junit.runners.JUnit4;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
@@ -54,7 +55,7 @@ public class LegacyImportTest {
|
|||||||
|
|
||||||
// when
|
// when
|
||||||
// 1. import
|
// 1. import
|
||||||
importTrackId = trackImporter.importFile(inputStream);
|
importTrackId = trackImporter.importFile(inputStream).get(0);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
// 1. track
|
// 1. track
|
||||||
@@ -69,7 +70,7 @@ public class LegacyImportTest {
|
|||||||
assertEquals(0, contentProviderUtils.getMarkerCount(importTrackId));
|
assertEquals(0, contentProviderUtils.getMarkerCount(importTrackId));
|
||||||
|
|
||||||
// 3. trackpoints
|
// 3. trackpoints
|
||||||
List<TrackPoint> importedTrackPoints = contentProviderUtils.getTrackPoints(importTrackId);
|
List<TrackPoint> importedTrackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
|
||||||
assertEquals(6, importedTrackPoints.size());
|
assertEquals(6, importedTrackPoints.size());
|
||||||
|
|
||||||
// first 3 trackpoints
|
// first 3 trackpoints
|
||||||
@@ -95,7 +96,7 @@ public class LegacyImportTest {
|
|||||||
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.debug.test.R.raw.legacy_kml_empty);
|
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.debug.test.R.raw.legacy_kml_empty);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
importTrackId = trackImporter.importFile(inputStream);
|
importTrackId = trackImporter.importFile(inputStream).get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -110,7 +111,7 @@ public class LegacyImportTest {
|
|||||||
|
|
||||||
// when
|
// when
|
||||||
// 1. import
|
// 1. import
|
||||||
importTrackId = trackImporter.importFile(inputStream);
|
importTrackId = trackImporter.importFile(inputStream).get(0);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
// 1. track
|
// 1. track
|
||||||
@@ -122,7 +123,7 @@ public class LegacyImportTest {
|
|||||||
assertEquals("UNKNOWN", importedTrack.getIcon());
|
assertEquals("UNKNOWN", importedTrack.getIcon());
|
||||||
|
|
||||||
// 3. trackpoints
|
// 3. trackpoints
|
||||||
List<TrackPoint> importedTrackPoints = contentProviderUtils.getTrackPoints(importTrackId);
|
List<TrackPoint> importedTrackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
|
||||||
assertEquals(6, importedTrackPoints.size());
|
assertEquals(6, importedTrackPoints.size());
|
||||||
|
|
||||||
// first segment
|
// first segment
|
||||||
|
|||||||
+13
-7
@@ -12,6 +12,7 @@ import org.mockito.Mock;
|
|||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
@@ -25,7 +26,10 @@ public class TrackRecordingServiceNotificationManagerTest {
|
|||||||
private final Context context = ApplicationProvider.getApplicationContext();
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private TrackPoint locationMock;
|
private TrackPoint trackPointMock;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private TrackStatistics trackStatisticsMock;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private NotificationCompat.Builder notificationCompatBuilder;
|
private NotificationCompat.Builder notificationCompatBuilder;
|
||||||
@@ -35,18 +39,20 @@ public class TrackRecordingServiceNotificationManagerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void updateLocation_triggersAlertOnlyOnFirstInaccurateLocation() {
|
public void updateLocation_triggersAlertOnlyOnFirstInaccurateLocation() {
|
||||||
when(locationMock.hasAccuracy()).thenReturn(true);
|
when(trackPointMock.hasAccuracy()).thenReturn(true);
|
||||||
when(locationMock.getAccuracy()).thenReturn(999f);
|
when(trackPointMock.getAccuracy()).thenReturn(999f);
|
||||||
|
when(trackStatisticsMock.getTotalDistance()).thenReturn(0d);
|
||||||
when(notificationCompatBuilder.setContentText(anyString())).thenReturn(notificationCompatBuilder);
|
when(notificationCompatBuilder.setContentText(anyString())).thenReturn(notificationCompatBuilder);
|
||||||
when(notificationCompatBuilder.setOnlyAlertOnce(anyBoolean())).thenReturn(notificationCompatBuilder);
|
when(notificationCompatBuilder.setOnlyAlertOnce(anyBoolean())).thenReturn(notificationCompatBuilder);
|
||||||
|
|
||||||
TrackRecordingServiceNotificationManager subject = new TrackRecordingServiceNotificationManager(notificationManager, notificationCompatBuilder);
|
TrackRecordingServiceNotificationManager subject = new TrackRecordingServiceNotificationManager(notificationManager, notificationCompatBuilder);
|
||||||
|
subject.setMetricUnits(true);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
subject.updateTrackPoint(context, locationMock, 100);
|
subject.updateTrackPoint(context, trackStatisticsMock, trackPointMock, 100);
|
||||||
subject.updateTrackPoint(context, locationMock, 100);
|
subject.updateTrackPoint(context, trackStatisticsMock, trackPointMock, 100);
|
||||||
subject.updateTrackPoint(context, locationMock, 1000);
|
subject.updateTrackPoint(context, trackStatisticsMock, trackPointMock, 1000);
|
||||||
subject.updateTrackPoint(context, locationMock, 100);
|
subject.updateTrackPoint(context, trackStatisticsMock, trackPointMock, 100);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(notificationCompatBuilder, times(6)).setOnlyAlertOnce(true);
|
verify(notificationCompatBuilder, times(6)).setOnlyAlertOnce(true);
|
||||||
|
|||||||
+16
-16
@@ -45,6 +45,7 @@ import java.util.concurrent.TimeoutException;
|
|||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.content.data.Marker;
|
import de.dennisguse.opentracks.content.data.Marker;
|
||||||
|
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
@@ -84,6 +85,7 @@ public class TrackRecordingServiceTest {
|
|||||||
|
|
||||||
|
|
||||||
private final Context context = ApplicationProvider.getApplicationContext();
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
private final SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||||
private ContentProviderUtils contentProviderUtils;
|
private ContentProviderUtils contentProviderUtils;
|
||||||
|
|
||||||
private final Track.Id trackId = new Track.Id(Math.abs(new Random().nextLong()));
|
private final Track.Id trackId = new Track.Id(Math.abs(new Random().nextLong()));
|
||||||
@@ -102,7 +104,6 @@ public class TrackRecordingServiceTest {
|
|||||||
contentProviderUtils = new ContentProviderUtils(context);
|
contentProviderUtils = new ContentProviderUtils(context);
|
||||||
|
|
||||||
// Let's use default values.
|
// Let's use default values.
|
||||||
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
|
||||||
sharedPreferences.edit().clear().commit();
|
sharedPreferences.edit().clear().commit();
|
||||||
|
|
||||||
// Ensure that the database is empty before every test
|
// Ensure that the database is empty before every test
|
||||||
@@ -190,7 +191,7 @@ public class TrackRecordingServiceTest {
|
|||||||
Track.Id trackId = service.startNewTrack();
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
||||||
|
|
||||||
assertEquals(1, trackPoints.size());
|
assertEquals(1, trackPoints.size());
|
||||||
assertEquals(TrackPoint.Type.SEGMENT_START_MANUAL, trackPoints.get(0).getType());
|
assertEquals(TrackPoint.Type.SEGMENT_START_MANUAL, trackPoints.get(0).getType());
|
||||||
@@ -207,7 +208,7 @@ public class TrackRecordingServiceTest {
|
|||||||
service.endCurrentTrack();
|
service.endCurrentTrack();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
||||||
|
|
||||||
assertEquals(2, trackPoints.size());
|
assertEquals(2, trackPoints.size());
|
||||||
assertEquals(TrackPoint.Type.SEGMENT_START_MANUAL, trackPoints.get(0).getType());
|
assertEquals(TrackPoint.Type.SEGMENT_START_MANUAL, trackPoints.get(0).getType());
|
||||||
@@ -225,7 +226,7 @@ public class TrackRecordingServiceTest {
|
|||||||
service.pauseCurrentTrack();
|
service.pauseCurrentTrack();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(2, contentProviderUtils.getTrackPoints(trackId).size());
|
assertEquals(2, contentProviderUtils.getTrackPointCursor(trackId, null).getCount());
|
||||||
|
|
||||||
//when
|
//when
|
||||||
service.resumeTrack(trackId);
|
service.resumeTrack(trackId);
|
||||||
@@ -234,7 +235,7 @@ public class TrackRecordingServiceTest {
|
|||||||
assertTrue(service.isRecording());
|
assertTrue(service.isRecording());
|
||||||
assertEquals(trackId, service.getRecordingTrackId());
|
assertEquals(trackId, service.getRecordingTrackId());
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
||||||
assertEquals(3, trackPoints.size());
|
assertEquals(3, trackPoints.size());
|
||||||
assertEquals(TrackPoint.Type.SEGMENT_START_MANUAL, trackPoints.get(0).getType());
|
assertEquals(TrackPoint.Type.SEGMENT_START_MANUAL, trackPoints.get(0).getType());
|
||||||
assertEquals(TrackPoint.Type.SEGMENT_END_MANUAL, trackPoints.get(1).getType());
|
assertEquals(TrackPoint.Type.SEGMENT_END_MANUAL, trackPoints.get(1).getType());
|
||||||
@@ -250,7 +251,7 @@ public class TrackRecordingServiceTest {
|
|||||||
assertTrue(service.isRecording());
|
assertTrue(service.isRecording());
|
||||||
service.endCurrentTrack();
|
service.endCurrentTrack();
|
||||||
|
|
||||||
assertEquals(2, contentProviderUtils.getTrackPoints(trackId).size());
|
assertEquals(2, contentProviderUtils.getTrackPointCursor(trackId, null).getCount());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
service.resumeTrack(trackId);
|
service.resumeTrack(trackId);
|
||||||
@@ -260,7 +261,7 @@ public class TrackRecordingServiceTest {
|
|||||||
assertTrue(service.isRecording());
|
assertTrue(service.isRecording());
|
||||||
assertEquals(trackId, service.getRecordingTrackId());
|
assertEquals(trackId, service.getRecordingTrackId());
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
||||||
assertEquals(4, trackPoints.size());
|
assertEquals(4, trackPoints.size());
|
||||||
assertEquals(TrackPoint.Type.SEGMENT_START_MANUAL, trackPoints.get(0).getType());
|
assertEquals(TrackPoint.Type.SEGMENT_START_MANUAL, trackPoints.get(0).getType());
|
||||||
assertEquals(TrackPoint.Type.SEGMENT_END_MANUAL, trackPoints.get(1).getType());
|
assertEquals(TrackPoint.Type.SEGMENT_END_MANUAL, trackPoints.get(1).getType());
|
||||||
@@ -277,7 +278,7 @@ public class TrackRecordingServiceTest {
|
|||||||
assertTrue(service.isRecording());
|
assertTrue(service.isRecording());
|
||||||
service.pauseCurrentTrack();
|
service.pauseCurrentTrack();
|
||||||
|
|
||||||
assertEquals(2, contentProviderUtils.getTrackPoints(trackId).size());
|
assertEquals(2, contentProviderUtils.getTrackPointCursor(trackId, null).getCount());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
service.endCurrentTrack();
|
service.endCurrentTrack();
|
||||||
@@ -286,7 +287,7 @@ public class TrackRecordingServiceTest {
|
|||||||
assertFalse(service.isRecording());
|
assertFalse(service.isRecording());
|
||||||
assertNull(service.getRecordingTrackId());
|
assertNull(service.getRecordingTrackId());
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
||||||
assertEquals(2, trackPoints.size());
|
assertEquals(2, trackPoints.size());
|
||||||
assertEquals(TrackPoint.Type.SEGMENT_START_MANUAL, trackPoints.get(0).getType());
|
assertEquals(TrackPoint.Type.SEGMENT_START_MANUAL, trackPoints.get(0).getType());
|
||||||
assertEquals(TrackPoint.Type.SEGMENT_END_MANUAL, trackPoints.get(1).getType());
|
assertEquals(TrackPoint.Type.SEGMENT_END_MANUAL, trackPoints.get(1).getType());
|
||||||
@@ -302,7 +303,7 @@ public class TrackRecordingServiceTest {
|
|||||||
// when
|
// when
|
||||||
// Just set recording track to a bogus value.
|
// Just set recording track to a bogus value.
|
||||||
// Make sure that the service will not start recording and will clear the bogus track.
|
// Make sure that the service will not start recording and will clear the bogus track.
|
||||||
PreferencesUtils.setLong(context, R.string.recording_track_id_key, 123L);
|
PreferencesUtils.setLong(sharedPreferences, context, R.string.recording_track_id_key, 123L);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertFalse(service.isRecording());
|
assertFalse(service.isRecording());
|
||||||
@@ -325,7 +326,7 @@ public class TrackRecordingServiceTest {
|
|||||||
// then
|
// then
|
||||||
assertNull(newTrackId);
|
assertNull(newTrackId);
|
||||||
|
|
||||||
assertEquals(trackId, PreferencesUtils.getRecordingTrackId(context));
|
assertEquals(trackId, PreferencesUtils.getRecordingTrackId(sharedPreferences, context));
|
||||||
assertEquals(trackId, service.getRecordingTrackId());
|
assertEquals(trackId, service.getRecordingTrackId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,7 +342,7 @@ public class TrackRecordingServiceTest {
|
|||||||
service.endCurrentTrack();
|
service.endCurrentTrack();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertFalse(PreferencesUtils.isRecording(context));
|
assertFalse(PreferencesUtils.isRecording(sharedPreferences, context));
|
||||||
assertNull(service.getRecordingTrackId());
|
assertNull(service.getRecordingTrackId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,8 +389,8 @@ public class TrackRecordingServiceTest {
|
|||||||
assertNotNull(track.getId());
|
assertNotNull(track.getId());
|
||||||
contentProviderUtils.insertTrack(track);
|
contentProviderUtils.insertTrack(track);
|
||||||
assertEquals(track.getId(), contentProviderUtils.getTrack(track.getId()).getId());
|
assertEquals(track.getId(), contentProviderUtils.getTrack(track.getId()).getId());
|
||||||
PreferencesUtils.setLong(context, R.string.recording_track_id_key, isRecording ? track.getId().getId() : PreferencesUtils.RECORDING_TRACK_ID_DEFAULT);
|
PreferencesUtils.setLong(sharedPreferences, context, R.string.recording_track_id_key, isRecording ? track.getId().getId() : PreferencesUtils.RECORDING_TRACK_ID_DEFAULT);
|
||||||
PreferencesUtils.setBoolean(context, R.string.recording_track_paused_key, !isRecording);
|
PreferencesUtils.setBoolean(sharedPreferences, context, R.string.recording_track_paused_key, !isRecording);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Do not use to create a track that is currently recording.
|
// NOTE: Do not use to create a track that is currently recording.
|
||||||
@@ -422,7 +423,6 @@ public class TrackRecordingServiceTest {
|
|||||||
location.setTime(time);
|
location.setTime(time);
|
||||||
location.setBearing(3.0f);
|
location.setBearing(3.0f);
|
||||||
TrackPoint trackPoint = new TrackPoint(location);
|
TrackPoint trackPoint = new TrackPoint(location);
|
||||||
int prefAccuracy = PreferencesUtils.getRecordingGPSAccuracy(ApplicationProvider.getApplicationContext());
|
trackRecordingService.newTrackPoint(trackPoint, 50);
|
||||||
trackRecordingService.newTrackPoint(trackPoint, prefAccuracy);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-6
@@ -23,6 +23,7 @@ import java.util.List;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
@@ -104,7 +105,7 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
// then
|
// then
|
||||||
assertFalse(service.isRecording());
|
assertFalse(service.isRecording());
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
||||||
assertEquals(8, trackPoints.size());
|
assertEquals(8, trackPoints.size());
|
||||||
assertTrackPoints(List.of(
|
assertTrackPoints(List.of(
|
||||||
new Pair<>(TrackPoint.Type.SEGMENT_START_MANUAL, null),
|
new Pair<>(TrackPoint.Type.SEGMENT_START_MANUAL, null),
|
||||||
@@ -138,7 +139,7 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
// then
|
// then
|
||||||
assertFalse(service.isRecording());
|
assertFalse(service.isRecording());
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
||||||
assertEquals(4, trackPoints.size());
|
assertEquals(4, trackPoints.size());
|
||||||
assertTrackPoints(List.of(
|
assertTrackPoints(List.of(
|
||||||
new Pair<>(TrackPoint.Type.SEGMENT_START_MANUAL, null),
|
new Pair<>(TrackPoint.Type.SEGMENT_START_MANUAL, null),
|
||||||
@@ -185,7 +186,7 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
// then
|
// then
|
||||||
assertFalse(service.isRecording());
|
assertFalse(service.isRecording());
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
||||||
assertTrackPoints(List.of(
|
assertTrackPoints(List.of(
|
||||||
new Pair<>(TrackPoint.Type.SEGMENT_START_MANUAL, null),
|
new Pair<>(TrackPoint.Type.SEGMENT_START_MANUAL, null),
|
||||||
new Pair<>(TrackPoint.Type.TRACKPOINT, 1),
|
new Pair<>(TrackPoint.Type.TRACKPOINT, 1),
|
||||||
@@ -214,7 +215,7 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
// then
|
// then
|
||||||
assertFalse(service.isRecording());
|
assertFalse(service.isRecording());
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
||||||
assertEquals(6, trackPoints.size());
|
assertEquals(6, trackPoints.size());
|
||||||
assertTrackPoints(List.of(
|
assertTrackPoints(List.of(
|
||||||
new Pair<>(TrackPoint.Type.SEGMENT_START_MANUAL, null),
|
new Pair<>(TrackPoint.Type.SEGMENT_START_MANUAL, null),
|
||||||
@@ -260,7 +261,7 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
// then
|
// then
|
||||||
assertFalse(service.isRecording());
|
assertFalse(service.isRecording());
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
||||||
assertEquals(8, trackPoints.size());
|
assertEquals(8, trackPoints.size());
|
||||||
assertTrackPoints(List.of(
|
assertTrackPoints(List.of(
|
||||||
new Pair<>(TrackPoint.Type.SEGMENT_START_MANUAL, null),
|
new Pair<>(TrackPoint.Type.SEGMENT_START_MANUAL, null),
|
||||||
@@ -292,7 +293,7 @@ public class TrackRecordingServiceTestLocation {
|
|||||||
// then
|
// then
|
||||||
assertFalse(service.isRecording());
|
assertFalse(service.isRecording());
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(trackId);
|
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
||||||
assertEquals(7, trackPoints.size());
|
assertEquals(7, trackPoints.size());
|
||||||
assertTrackPoints(List.of(
|
assertTrackPoints(List.of(
|
||||||
new Pair<>(TrackPoint.Type.SEGMENT_START_MANUAL, null),
|
new Pair<>(TrackPoint.Type.SEGMENT_START_MANUAL, null),
|
||||||
|
|||||||
+16
-16
@@ -53,6 +53,7 @@ public class TrackRecordingServiceTestLooper {
|
|||||||
public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(5, TimeUnit.SECONDS);
|
public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(5, TimeUnit.SECONDS);
|
||||||
|
|
||||||
private final Context context = ApplicationProvider.getApplicationContext();
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
private final SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||||
|
|
||||||
private ContentProviderUtils contentProviderUtils;
|
private ContentProviderUtils contentProviderUtils;
|
||||||
|
|
||||||
@@ -77,7 +78,6 @@ public class TrackRecordingServiceTestLooper {
|
|||||||
contentProviderUtils = new ContentProviderUtils(context);
|
contentProviderUtils = new ContentProviderUtils(context);
|
||||||
|
|
||||||
// Let's use default values.
|
// Let's use default values.
|
||||||
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
|
||||||
sharedPreferences.edit().clear().apply();
|
sharedPreferences.edit().clear().apply();
|
||||||
|
|
||||||
// Ensure that the database is empty before every test
|
// Ensure that the database is empty before every test
|
||||||
@@ -99,28 +99,28 @@ public class TrackRecordingServiceTestLooper {
|
|||||||
@MediumTest
|
@MediumTest
|
||||||
@Test
|
@Test
|
||||||
public void testWithProperties_minRequiredAccuracy() throws TimeoutException {
|
public void testWithProperties_minRequiredAccuracy() throws TimeoutException {
|
||||||
PreferencesUtils.setInt(context, R.string.recording_gps_accuracy_key, 500);
|
PreferencesUtils.setInt(sharedPreferences, context, R.string.recording_gps_accuracy_key, 500);
|
||||||
fullRecordingSession();
|
fullRecordingSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@Test
|
@Test
|
||||||
public void testWithProperties_voiceFrequencyDefault() throws TimeoutException {
|
public void testWithProperties_voiceFrequencyDefault() throws TimeoutException {
|
||||||
PreferencesUtils.setInt(context, R.string.voice_frequency_key, Integer.parseInt(context.getResources().getString(R.string.voice_frequency_default)));
|
PreferencesUtils.setInt(sharedPreferences, context, R.string.voice_frequency_key, Integer.parseInt(context.getResources().getString(R.string.voice_frequency_default)));
|
||||||
fullRecordingSession();
|
fullRecordingSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@Test
|
@Test
|
||||||
public void testWithProperties_voiceFrequencyByDistance() throws TimeoutException {
|
public void testWithProperties_voiceFrequencyByDistance() throws TimeoutException {
|
||||||
PreferencesUtils.setInt(context, R.string.voice_frequency_key, -1);
|
PreferencesUtils.setInt(sharedPreferences, context, R.string.voice_frequency_key, -1);
|
||||||
fullRecordingSession();
|
fullRecordingSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@Test
|
@Test
|
||||||
public void testWithProperties_voiceFrequencyByTime() throws TimeoutException {
|
public void testWithProperties_voiceFrequencyByTime() throws TimeoutException {
|
||||||
PreferencesUtils.setInt(context, R.string.voice_frequency_key, 1);
|
PreferencesUtils.setInt(sharedPreferences, context, R.string.voice_frequency_key, 1);
|
||||||
fullRecordingSession();
|
fullRecordingSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,14 +128,14 @@ public class TrackRecordingServiceTestLooper {
|
|||||||
@MediumTest
|
@MediumTest
|
||||||
@Test
|
@Test
|
||||||
public void testWithProperties_maxRecordingDistanceDefault() throws TimeoutException {
|
public void testWithProperties_maxRecordingDistanceDefault() throws TimeoutException {
|
||||||
PreferencesUtils.setInt(context, R.string.max_recording_distance_key, Integer.parseInt(context.getResources().getString(R.string.max_recording_distance_default)));
|
PreferencesUtils.setInt(sharedPreferences, context, R.string.max_recording_distance_key, Integer.parseInt(context.getResources().getString(R.string.max_recording_distance_default)));
|
||||||
fullRecordingSession();
|
fullRecordingSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@Test
|
@Test
|
||||||
public void testWithProperties_maxRecordingDistance() throws TimeoutException {
|
public void testWithProperties_maxRecordingDistance() throws TimeoutException {
|
||||||
PreferencesUtils.setInt(context, R.string.max_recording_distance_key, 50);
|
PreferencesUtils.setInt(sharedPreferences, context, R.string.max_recording_distance_key, 50);
|
||||||
fullRecordingSession();
|
fullRecordingSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,42 +143,42 @@ public class TrackRecordingServiceTestLooper {
|
|||||||
@Test
|
@Test
|
||||||
public void testWithProperties_minRecordingDistanceDefault() throws TimeoutException {
|
public void testWithProperties_minRecordingDistanceDefault() throws TimeoutException {
|
||||||
int minRecordingIntervalDefault = Integer.parseInt(context.getResources().getString(R.string.min_recording_interval_default));
|
int minRecordingIntervalDefault = Integer.parseInt(context.getResources().getString(R.string.min_recording_interval_default));
|
||||||
PreferencesUtils.setInt(context, R.string.recording_distance_interval_key, minRecordingIntervalDefault);
|
PreferencesUtils.setInt(sharedPreferences, context, R.string.recording_distance_interval_key, minRecordingIntervalDefault);
|
||||||
fullRecordingSession();
|
fullRecordingSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@Test
|
@Test
|
||||||
public void testWithProperties_minRecordingDistance() throws TimeoutException {
|
public void testWithProperties_minRecordingDistance() throws TimeoutException {
|
||||||
PreferencesUtils.setInt(context, R.string.recording_distance_interval_key, 2);
|
PreferencesUtils.setInt(sharedPreferences, context, R.string.recording_distance_interval_key, 2);
|
||||||
fullRecordingSession();
|
fullRecordingSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@Test
|
@Test
|
||||||
public void testWithProperties_metricUnitsDefault() throws TimeoutException {
|
public void testWithProperties_metricUnitsDefault() throws TimeoutException {
|
||||||
PreferencesUtils.setString(context, R.string.stats_units_key, context.getString(R.string.stats_units_default));
|
PreferencesUtils.setString(sharedPreferences, context, R.string.stats_units_key, context.getString(R.string.stats_units_default));
|
||||||
fullRecordingSession();
|
fullRecordingSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@Test
|
@Test
|
||||||
public void testWithProperties_metricUnitsDisabled() throws TimeoutException {
|
public void testWithProperties_metricUnitsDisabled() throws TimeoutException {
|
||||||
PreferencesUtils.setString(context, R.string.stats_units_key, context.getString(R.string.stats_units_imperial));
|
PreferencesUtils.setString(sharedPreferences, context, R.string.stats_units_key, context.getString(R.string.stats_units_imperial));
|
||||||
fullRecordingSession();
|
fullRecordingSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@Test
|
@Test
|
||||||
public void testWithProperties_minRecordingIntervalDefault() throws TimeoutException {
|
public void testWithProperties_minRecordingIntervalDefault() throws TimeoutException {
|
||||||
PreferencesUtils.setInt(context, R.string.min_recording_interval_key, Integer.parseInt(context.getResources().getString(R.string.min_recording_interval_default)));
|
PreferencesUtils.setInt(sharedPreferences, context, R.string.min_recording_interval_key, Integer.parseInt(context.getResources().getString(R.string.min_recording_interval_default)));
|
||||||
fullRecordingSession();
|
fullRecordingSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
@MediumTest
|
@MediumTest
|
||||||
@Test
|
@Test
|
||||||
public void testWithProperties_minRecordingInterval() throws TimeoutException {
|
public void testWithProperties_minRecordingInterval() throws TimeoutException {
|
||||||
PreferencesUtils.setInt(context, R.string.min_recording_interval_key, 2);
|
PreferencesUtils.setInt(sharedPreferences, context, R.string.min_recording_interval_key, 2);
|
||||||
fullRecordingSession();
|
fullRecordingSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ public class TrackRecordingServiceTestLooper {
|
|||||||
@Test
|
@Test
|
||||||
public void testWithProperties_minRequiredAccuracyDefault() throws TimeoutException {
|
public void testWithProperties_minRequiredAccuracyDefault() throws TimeoutException {
|
||||||
int recordingGPSAccuracyDefault = Integer.parseInt(context.getResources().getString(R.string.recording_gps_accuracy_default));
|
int recordingGPSAccuracyDefault = Integer.parseInt(context.getResources().getString(R.string.recording_gps_accuracy_default));
|
||||||
PreferencesUtils.setInt(context, R.string.recording_gps_accuracy_key, recordingGPSAccuracyDefault);
|
PreferencesUtils.setInt(sharedPreferences, context, R.string.recording_gps_accuracy_key, recordingGPSAccuracyDefault);
|
||||||
fullRecordingSession();
|
fullRecordingSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,7 +209,7 @@ public class TrackRecordingServiceTestLooper {
|
|||||||
Track track = contentProviderUtils.getTrack(trackId);
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
assertNotNull(track);
|
assertNotNull(track);
|
||||||
assertEquals(trackId, track.getId());
|
assertEquals(trackId, track.getId());
|
||||||
assertEquals(trackId, PreferencesUtils.getRecordingTrackId(context));
|
assertEquals(trackId, PreferencesUtils.getRecordingTrackId(sharedPreferences, context));
|
||||||
assertEquals(trackId, service.getRecordingTrackId());
|
assertEquals(trackId, service.getRecordingTrackId());
|
||||||
|
|
||||||
// Insert a few points, markers and statistics.
|
// Insert a few points, markers and statistics.
|
||||||
@@ -223,7 +223,7 @@ public class TrackRecordingServiceTestLooper {
|
|||||||
location.setTime(startTime + i * 10000);
|
location.setTime(startTime + i * 10000);
|
||||||
location.setBearing(3.0f);
|
location.setBearing(3.0f);
|
||||||
TrackPoint trackPoint = new TrackPoint(location);
|
TrackPoint trackPoint = new TrackPoint(location);
|
||||||
int prefAccuracy = PreferencesUtils.getRecordingGPSAccuracy(context);
|
int prefAccuracy = PreferencesUtils.getRecordingGPSAccuracy(sharedPreferences, context);
|
||||||
service.newTrackPoint(trackPoint, prefAccuracy);
|
service.newTrackPoint(trackPoint, prefAccuracy);
|
||||||
|
|
||||||
if (i % 7 == 0) {
|
if (i % 7 == 0) {
|
||||||
|
|||||||
+6
-2
@@ -1,6 +1,7 @@
|
|||||||
package de.dennisguse.opentracks.services.handlers;
|
package de.dennisguse.opentracks.services.handlers;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -25,6 +26,9 @@ public class HandlerServerTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private LocationHandler locationHandler;
|
private LocationHandler locationHandler;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private SharedPreferences sharedPreferences;
|
||||||
|
|
||||||
private HandlerServer subject;
|
private HandlerServer subject;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -41,10 +45,10 @@ public class HandlerServerTest {
|
|||||||
@Test
|
@Test
|
||||||
public void onSharedPreferenceChanged() {
|
public void onSharedPreferenceChanged() {
|
||||||
// when
|
// when
|
||||||
subject.onSharedPreferenceChanged(null, null, null);
|
subject.onSharedPreferenceChanged(context, sharedPreferences, null);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(locationHandler).onSharedPreferenceChanged(null, null, null);
|
verify(locationHandler).onSharedPreferenceChanged(context, sharedPreferences, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
+4
-4
@@ -27,6 +27,7 @@ import static org.mockito.Mockito.verify;
|
|||||||
public class LocationHandlerTest {
|
public class LocationHandlerTest {
|
||||||
|
|
||||||
private final Context context = ApplicationProvider.getApplicationContext();
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
private final SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private HandlerServer handlerServer;
|
private HandlerServer handlerServer;
|
||||||
@@ -43,11 +44,10 @@ public class LocationHandlerTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
// Let's use default values.
|
// Let's use default values.
|
||||||
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
|
||||||
sharedPreferences.edit().clear().commit();
|
sharedPreferences.edit().clear().commit();
|
||||||
|
|
||||||
locationHandler.onSharedPreferenceChanged(context, PreferencesUtils.getSharedPreferences(context), context.getString(R.string.recording_gps_accuracy_key));
|
locationHandler.onSharedPreferenceChanged(context, sharedPreferences, context.getString(R.string.recording_gps_accuracy_key));
|
||||||
locationHandler.onSharedPreferenceChanged(context, PreferencesUtils.getSharedPreferences(context), context.getString(R.string.min_recording_interval_key));
|
locationHandler.onSharedPreferenceChanged(context, sharedPreferences, context.getString(R.string.min_recording_interval_key));
|
||||||
locationHandler.onStart(context);
|
locationHandler.onStart(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ public class LocationHandlerTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testOnLocationChanged_poorAccuracy() {
|
public void testOnLocationChanged_poorAccuracy() {
|
||||||
// given
|
// given
|
||||||
int prefAccuracy = PreferencesUtils.getRecordingGPSAccuracy(context);
|
int prefAccuracy = PreferencesUtils.getRecordingGPSAccuracy(sharedPreferences, context);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
locationHandler.onLocationChanged(createLocation(45f, 35f, prefAccuracy + 1, 5, System.currentTimeMillis()));
|
locationHandler.onLocationChanged(createLocation(45f, 35f, prefAccuracy + 1, 5, System.currentTimeMillis()));
|
||||||
|
|||||||
+131
-4
@@ -1,27 +1,36 @@
|
|||||||
package de.dennisguse.opentracks.stats;
|
package de.dennisguse.opentracks.stats;
|
||||||
|
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class TrackStatisticsUpdaterTest {
|
public class TrackStatisticsUpdaterTest {
|
||||||
|
|
||||||
|
private static final int GPS_DISTANCE = 50;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void addTrackPoint() {
|
public void addTrackPoint_TestingTrack() {
|
||||||
// given
|
// given
|
||||||
TestDataUtil.TrackData data = TestDataUtil.createTestingTrack(new Track.Id(1));
|
TestDataUtil.TrackData data = TestDataUtil.createTestingTrack(new Track.Id(1));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
TrackStatisticsUpdater updater = new TrackStatisticsUpdater();
|
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
|
||||||
data.trackPoints.forEach(it -> updater.addTrackPoint(it, 50));
|
data.trackPoints.forEach(it -> subject.addTrackPoint(it, GPS_DISTANCE));
|
||||||
|
|
||||||
// then
|
// then
|
||||||
TrackStatistics statistics = updater.getTrackStatistics();
|
TrackStatistics statistics = subject.getTrackStatistics();
|
||||||
assertEquals(85.35, statistics.getTotalDistance(), 0.01);
|
assertEquals(85.35, statistics.getTotalDistance(), 0.01);
|
||||||
assertEquals(Duration.ofMillis(13999), statistics.getTotalTime());
|
assertEquals(Duration.ofMillis(13999), statistics.getTotalTime());
|
||||||
assertEquals(Duration.ofSeconds(6), statistics.getMovingTime());
|
assertEquals(Duration.ofSeconds(6), statistics.getMovingTime());
|
||||||
@@ -35,4 +44,122 @@ public class TrackStatisticsUpdaterTest {
|
|||||||
assertEquals(14.226, statistics.getAverageMovingSpeed(), 0.01);
|
assertEquals(14.226, statistics.getAverageMovingSpeed(), 0.01);
|
||||||
assertEquals(6.566, statistics.getAverageSpeed(), 0.01);
|
assertEquals(6.566, statistics.getAverageSpeed(), 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addTrackPoint_distance_from_GPS_not_moving() {
|
||||||
|
// given
|
||||||
|
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
|
||||||
|
|
||||||
|
TrackPoint tp1 = new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochMilli(1000));
|
||||||
|
TrackPoint tp2 = new TrackPoint(0, 0, 5.0, Instant.ofEpochMilli(2000));
|
||||||
|
TrackPoint tp3 = new TrackPoint(0.00001, 0, 5.0, Instant.ofEpochMilli(3000));
|
||||||
|
|
||||||
|
// when
|
||||||
|
subject.addTrackPoint(tp1, GPS_DISTANCE);
|
||||||
|
subject.addTrackPoint(tp2, GPS_DISTANCE);
|
||||||
|
subject.addTrackPoint(tp3, GPS_DISTANCE);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(0, subject.getTrackStatistics().getTotalDistance(), 0.01);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addTrackPoint_distance_from_GPS_moving() {
|
||||||
|
// given
|
||||||
|
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
|
||||||
|
|
||||||
|
TrackPoint tp1 = new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochMilli(1000));
|
||||||
|
TrackPoint tp2 = new TrackPoint(0, 0, 5.0, Instant.ofEpochMilli(2000));
|
||||||
|
TrackPoint tp3 = new TrackPoint(0.00001, 0, 5.0, Instant.ofEpochMilli(3000));
|
||||||
|
tp3.setSpeed(5f);
|
||||||
|
|
||||||
|
// when
|
||||||
|
subject.addTrackPoint(tp1, GPS_DISTANCE);
|
||||||
|
subject.addTrackPoint(tp2, GPS_DISTANCE);
|
||||||
|
subject.addTrackPoint(tp3, GPS_DISTANCE);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(1.10, subject.getTrackStatistics().getTotalDistance(), 0.01);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addTrackPoint_distance_from_GPS_moving_and_sensor_moving() {
|
||||||
|
// given
|
||||||
|
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
|
||||||
|
|
||||||
|
TrackPoint tp1 = new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochMilli(1000));
|
||||||
|
TrackPoint tp2 = new TrackPoint(0, 0, 5.0, Instant.ofEpochMilli(2000));
|
||||||
|
tp2.setSpeed(5f);
|
||||||
|
TrackPoint tp3 = new TrackPoint(0.001, 0, 5.0, Instant.ofEpochMilli(3000));
|
||||||
|
tp2.setSpeed(5f);
|
||||||
|
TrackPoint tp4 = new TrackPoint(0.001, 0, 5.0, Instant.ofEpochMilli(4000));
|
||||||
|
tp2.setSpeed(5f);
|
||||||
|
tp4.setSensorDistance(5f);
|
||||||
|
TrackPoint tp5 = new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochMilli(5000));
|
||||||
|
tp5.setSensorDistance(10f);
|
||||||
|
|
||||||
|
// when
|
||||||
|
subject.addTrackPoint(tp1, GPS_DISTANCE);
|
||||||
|
subject.addTrackPoint(tp2, GPS_DISTANCE);
|
||||||
|
subject.addTrackPoint(tp3, GPS_DISTANCE);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(110.57, subject.getTrackStatistics().getTotalDistance(), 0.01);
|
||||||
|
|
||||||
|
// when
|
||||||
|
subject.addTrackPoint(tp4, GPS_DISTANCE);
|
||||||
|
subject.addTrackPoint(tp5, GPS_DISTANCE);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(125.57, subject.getTrackStatistics().getTotalDistance(), 0.01);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addTrackPoint_distance_from_GPS_not_moving_and_sensor_moving() {
|
||||||
|
// given
|
||||||
|
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
|
||||||
|
|
||||||
|
TrackPoint tp1 = new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochMilli(1000));
|
||||||
|
TrackPoint tp2 = new TrackPoint(0, 0, 5.0, Instant.ofEpochMilli(2000));
|
||||||
|
TrackPoint tp3 = new TrackPoint(0.00001, 0, 5.0, Instant.ofEpochMilli(3000));
|
||||||
|
TrackPoint tp4 = new TrackPoint(0.00001, 0, 5.0, Instant.ofEpochMilli(4000));
|
||||||
|
tp4.setSensorDistance(5f);
|
||||||
|
TrackPoint tp5 = new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochMilli(5000));
|
||||||
|
tp5.setSensorDistance(10f);
|
||||||
|
|
||||||
|
// when
|
||||||
|
subject.addTrackPoint(tp1, GPS_DISTANCE);
|
||||||
|
subject.addTrackPoint(tp2, GPS_DISTANCE);
|
||||||
|
subject.addTrackPoint(tp3, GPS_DISTANCE);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(0, subject.getTrackStatistics().getTotalDistance(), 0.01);
|
||||||
|
|
||||||
|
// when
|
||||||
|
subject.addTrackPoint(tp4, GPS_DISTANCE);
|
||||||
|
subject.addTrackPoint(tp5, GPS_DISTANCE);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(15, subject.getTrackStatistics().getTotalDistance(), 0.01);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("TODO: create a concept ont to compute speed from GPS and sensor")
|
||||||
|
@Test
|
||||||
|
public void addTrackPoint_speed_from_GPS_not_moving() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("TODO: create a concept ont to compute speed from GPS and sensor")
|
||||||
|
@Test
|
||||||
|
public void addTrackPoint_speed_from_GPS_moving() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("TODO: create a concept ont to compute speed from GPS and sensor")
|
||||||
|
@Test
|
||||||
|
public void addTrackPoint_speed_from_GPS_not_moving_and_sensor_speed() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("TODO: create a concept ont to compute speed from GPS and sensor")
|
||||||
|
@Test
|
||||||
|
public void addTrackPoint_speed_from_GPS_moving_and_sensor_speed() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,6 @@ import org.junit.runner.RunWith;
|
|||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
|
||||||
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
@@ -27,30 +26,26 @@ public class AnnouncementUtilsTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAnnouncement_metric() {
|
public void getAnnouncement_metric() {
|
||||||
PreferencesUtils.setString(context, R.string.stats_units_key, context.getString(R.string.stats_units_metric));
|
|
||||||
|
|
||||||
TrackStatistics stats = new TrackStatistics();
|
TrackStatistics stats = new TrackStatistics();
|
||||||
stats.setTotalDistance(20000);
|
stats.setTotalDistance(20000);
|
||||||
stats.setTotalTime(Duration.ofMillis(600000));
|
stats.setTotalTime(Duration.ofHours(2).plusMinutes(5).plusSeconds(10));
|
||||||
stats.setMovingTime(Duration.ofMillis(300000));
|
stats.setMovingTime(Duration.ofHours(1).plusMinutes(5).plusSeconds(10));
|
||||||
stats.setMaxSpeed(100);
|
stats.setMaxSpeed(100);
|
||||||
stats.setTotalElevationGain(6000f);
|
stats.setTotalElevationGain(6000f);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
String announcement = AnnouncementUtils.getAnnouncement(context, stats, "airplane", null);
|
String announcement = AnnouncementUtils.getAnnouncement(context, stats, true, true, null);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals("OpenTracks total distance 20.00 kilometers in 5 minutes 0 seconds at 240.0 kilometers per hour", announcement);
|
assertEquals("OpenTracks total distance 20.00 kilometers in 1 hour 5 minutes 10 seconds at 18.4 kilometers per hour", announcement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getAnnouncement_withInterval_metric() {
|
public void getAnnouncement_withInterval_metric() {
|
||||||
PreferencesUtils.setString(context, R.string.stats_units_key, context.getString(R.string.stats_units_metric));
|
|
||||||
|
|
||||||
TrackStatistics stats = new TrackStatistics();
|
TrackStatistics stats = new TrackStatistics();
|
||||||
stats.setTotalDistance(20000);
|
stats.setTotalDistance(20000);
|
||||||
stats.setTotalTime(Duration.ofMillis(600000));
|
stats.setTotalTime(Duration.ofHours(2).plusMinutes(5).plusSeconds(10));
|
||||||
stats.setMovingTime(Duration.ofMillis(300000));
|
stats.setMovingTime(Duration.ofHours(1).plusMinutes(5).plusSeconds(10));
|
||||||
stats.setMaxSpeed(100);
|
stats.setMaxSpeed(100);
|
||||||
stats.setTotalElevationGain(6000f);
|
stats.setTotalElevationGain(6000f);
|
||||||
|
|
||||||
@@ -58,12 +53,10 @@ public class AnnouncementUtilsTest {
|
|||||||
IntervalStatistics intervalStatistics = new IntervalStatistics(trackPoints, 1000);
|
IntervalStatistics intervalStatistics = new IntervalStatistics(trackPoints, 1000);
|
||||||
IntervalStatistics.Interval lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
|
IntervalStatistics.Interval lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
|
||||||
|
|
||||||
String expected = "OpenTracks total distance 20.00 kilometers in 5 minutes 0 seconds at 240.0 kilometers per hour Lap speed of 51.2 kilometers per hour";
|
|
||||||
|
|
||||||
// when
|
// when
|
||||||
String announcement = AnnouncementUtils.getAnnouncement(context, stats, "airplane", lastInterval);
|
String announcement = AnnouncementUtils.getAnnouncement(context, stats, true, true, lastInterval);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(expected, announcement);
|
assertEquals("OpenTracks total distance 20.00 kilometers in 1 hour 5 minutes 10 seconds at 18.4 kilometers per hour Lap speed of 51.2 kilometers per hour", announcement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,7 +47,7 @@ public class BluetoothUtilsTest {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(200, sensor.getCadence().getCrankRevolutionsCount());
|
assertEquals(200, sensor.getCadence().getCrankRevolutionsCount());
|
||||||
assertNull(sensor.getSpeed());
|
assertNull(sensor.getDistanceSpeed());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -60,7 +60,7 @@ public class BluetoothUtilsTest {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
assertNull(sensor.getCadence());
|
assertNull(sensor.getCadence());
|
||||||
assertEquals(225, sensor.getSpeed().getWheelRevolutionsCount());
|
assertEquals(225, sensor.getDistanceSpeed().getWheelRevolutionsCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -73,7 +73,7 @@ public class BluetoothUtilsTest {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(200, sensor.getCadence().getCrankRevolutionsCount());
|
assertEquals(200, sensor.getCadence().getCrankRevolutionsCount());
|
||||||
assertEquals(225, sensor.getSpeed().getWheelRevolutionsCount());
|
assertEquals(225, sensor.getDistanceSpeed().getWheelRevolutionsCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package de.dennisguse.opentracks.util;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class ExportUtilsTest extends TestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsExportFileExists_exists() {
|
||||||
|
// given
|
||||||
|
UUID uuid = UUID.randomUUID();
|
||||||
|
String format = "kmz";
|
||||||
|
List<String> fileNames = new ArrayList<>();
|
||||||
|
fileNames.add(uuid.toString().substring(0, 8) + "_name.gpx");
|
||||||
|
fileNames.add(uuid.toString().substring(0, 8) + "_other name name.kmz");
|
||||||
|
|
||||||
|
// when
|
||||||
|
boolean exists = ExportUtils.isExportFileExists(uuid, format, fileNames);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertTrue(exists);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsExportFileExists_not_exists1() {
|
||||||
|
// given
|
||||||
|
UUID uuid = UUID.randomUUID();
|
||||||
|
String format = "gpx";
|
||||||
|
List<String> fileNames = new ArrayList<>();
|
||||||
|
fileNames.add(UUID.randomUUID().toString().substring(0, 8) + "_name.gpx");
|
||||||
|
fileNames.add(UUID.randomUUID().toString().substring(0, 8) + "_other name name.gpx");
|
||||||
|
|
||||||
|
// when
|
||||||
|
boolean exists = ExportUtils.isExportFileExists(uuid, format, fileNames);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertFalse(exists);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsExportFileExists_not_exists2() {
|
||||||
|
// given
|
||||||
|
UUID uuid = UUID.randomUUID();
|
||||||
|
String format = "kmz";
|
||||||
|
List<String> fileNames = new ArrayList<>();
|
||||||
|
fileNames.add(uuid.toString().substring(0, 8) + "_name.gpx");
|
||||||
|
fileNames.add(UUID.randomUUID().toString().substring(0, 8) + "_other name name.gpx");
|
||||||
|
|
||||||
|
// when
|
||||||
|
boolean exists = ExportUtils.isExportFileExists(uuid, format, fileNames);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertFalse(exists);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,12 +22,14 @@ public class PreferencesUtilsTest {
|
|||||||
@Test
|
@Test
|
||||||
public void ExportTrackFileFormat_ok() {
|
public void ExportTrackFileFormat_ok() {
|
||||||
// given
|
// given
|
||||||
SharedPreferences.Editor editor = PreferencesUtils.getSharedPreferences(context).edit();
|
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
|
||||||
editor.putString(context.getString(R.string.export_trackfileformat_key), TrackFileFormat.KMZ_WITH_TRACKDETAIL.name());
|
editor.putString(context.getString(R.string.export_trackfileformat_key), TrackFileFormat.KMZ_WITH_TRACKDETAIL.name());
|
||||||
editor.commit();
|
editor.commit();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(context);
|
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(sharedPreferences, context);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL, trackFileFormat);
|
assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL, trackFileFormat);
|
||||||
@@ -36,12 +38,13 @@ public class PreferencesUtilsTest {
|
|||||||
@Test
|
@Test
|
||||||
public void ExportTrackFileFormat_invalid() {
|
public void ExportTrackFileFormat_invalid() {
|
||||||
// given
|
// given
|
||||||
SharedPreferences.Editor editor = PreferencesUtils.getSharedPreferences(context).edit();
|
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
editor.putString(context.getString(R.string.export_trackfileformat_key), "invalid");
|
editor.putString(context.getString(R.string.export_trackfileformat_key), "invalid");
|
||||||
editor.commit();
|
editor.commit();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(context);
|
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(sharedPreferences, context);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, trackFileFormat);
|
assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, trackFileFormat);
|
||||||
@@ -50,12 +53,13 @@ public class PreferencesUtilsTest {
|
|||||||
@Test
|
@Test
|
||||||
public void ExportTrackFileFormat_noValue() {
|
public void ExportTrackFileFormat_noValue() {
|
||||||
// given
|
// given
|
||||||
SharedPreferences.Editor editor = PreferencesUtils.getSharedPreferences(context).edit();
|
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
editor.clear();
|
editor.clear();
|
||||||
editor.commit();
|
editor.commit();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(context);
|
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(sharedPreferences, context);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, trackFileFormat);
|
assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, trackFileFormat);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package de.dennisguse.opentracks.util;
|
package de.dennisguse.opentracks.util;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
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;
|
||||||
@@ -46,12 +47,14 @@ public class TrackNameUtilsTest {
|
|||||||
|
|
||||||
private static final Context CONTEXT = ApplicationProvider.getApplicationContext();
|
private static final Context CONTEXT = ApplicationProvider.getApplicationContext();
|
||||||
|
|
||||||
|
private static final SharedPreferences SHARED_PREFERENCES = PreferencesUtils.getSharedPreferences(CONTEXT);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests when the track_name_key is settings_recording_track_name_date_local_value.
|
* Tests when the track_name_key is settings_recording_track_name_date_local_value.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testTrackName_date_local() {
|
public void testTrackName_date_local() {
|
||||||
PreferencesUtils.setString(CONTEXT, R.string.track_name_key, CONTEXT.getString(R.string.settings_recording_track_name_date_local_value));
|
PreferencesUtils.setString(SHARED_PREFERENCES, CONTEXT, R.string.track_name_key, CONTEXT.getString(R.string.settings_recording_track_name_date_local_value));
|
||||||
assertEquals(StringUtils.formatDateTime(CONTEXT, START_TIME), TrackNameUtils.getTrackName(CONTEXT, TRACK_ID, START_TIME));
|
assertEquals(StringUtils.formatDateTime(CONTEXT, START_TIME), TrackNameUtils.getTrackName(CONTEXT, TRACK_ID, START_TIME));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,7 +63,7 @@ public class TrackNameUtilsTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testTrackName_date_iso_8601() {
|
public void testTrackName_date_iso_8601() {
|
||||||
PreferencesUtils.setString(CONTEXT, R.string.track_name_key, CONTEXT.getString(R.string.settings_recording_track_name_date_iso_8601_value));
|
PreferencesUtils.setString(SHARED_PREFERENCES, CONTEXT, R.string.track_name_key, CONTEXT.getString(R.string.settings_recording_track_name_date_iso_8601_value));
|
||||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(TrackNameUtils.ISO_8601_FORMAT, Locale.US);
|
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(TrackNameUtils.ISO_8601_FORMAT, Locale.US);
|
||||||
assertEquals(simpleDateFormat.format(START_TIME.toEpochMilli()), TrackNameUtils.getTrackName(CONTEXT, TRACK_ID, START_TIME));
|
assertEquals(simpleDateFormat.format(START_TIME.toEpochMilli()), TrackNameUtils.getTrackName(CONTEXT, TRACK_ID, START_TIME));
|
||||||
}
|
}
|
||||||
@@ -70,7 +73,7 @@ public class TrackNameUtilsTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testTrackName_number() {
|
public void testTrackName_number() {
|
||||||
PreferencesUtils.setString(CONTEXT, R.string.track_name_key, CONTEXT.getString(R.string.settings_recording_track_name_number_value));
|
PreferencesUtils.setString(SHARED_PREFERENCES, CONTEXT, R.string.track_name_key, CONTEXT.getString(R.string.settings_recording_track_name_number_value));
|
||||||
assertEquals("Track " + TRACK_ID.getId(), TrackNameUtils.getTrackName(CONTEXT, TRACK_ID, START_TIME));
|
assertEquals("Track " + TRACK_ID.getId(), TrackNameUtils.getTrackName(CONTEXT, TRACK_ID, START_TIME));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,11 +73,13 @@ limitations under the License.
|
|||||||
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.SEND" />
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<data android:mimeType="application/gpx+xml" />
|
<data android:mimeType="application/gpx+xml" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.SEND" />
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<data android:mimeType="application/gpx" />
|
<data android:mimeType="application/gpx" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
@@ -135,6 +137,7 @@ limitations under the License.
|
|||||||
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.SEND" />
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<data android:mimeType="application/vnd.google-earth.kmz" />
|
<data android:mimeType="application/vnd.google-earth.kmz" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
@@ -192,6 +195,8 @@ limitations under the License.
|
|||||||
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.SEND" />
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<data android:mimeType="application/vnd.google-earth.kml+xml" />
|
<data android:mimeType="application/vnd.google-earth.kml+xml" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ public abstract class AbstractListActivity extends AbstractActivity implements C
|
|||||||
public void onConfirmDeleteDone(Track.Id... trackIds) {
|
public void onConfirmDeleteDone(Track.Id... trackIds) {
|
||||||
boolean stopRecording = false;
|
boolean stopRecording = false;
|
||||||
|
|
||||||
Track.Id recordingTrackId = PreferencesUtils.getRecordingTrackId(this);
|
Track.Id recordingTrackId = PreferencesUtils.getRecordingTrackId(PreferencesUtils.getSharedPreferences(this), this);
|
||||||
for (Track.Id trackId : trackIds) {
|
for (Track.Id trackId : trackIds) {
|
||||||
if (trackId.equals(recordingTrackId)) {
|
if (trackId.equals(recordingTrackId)) {
|
||||||
stopRecording = true;
|
stopRecording = true;
|
||||||
|
|||||||
@@ -66,12 +66,12 @@ public class MarkerListActivity extends AbstractActivity implements DeleteMarker
|
|||||||
|
|
||||||
private final OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
|
private final OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
if (PreferencesUtils.isKey(MarkerListActivity.this, R.string.recording_track_id_key, key)) {
|
if (PreferencesUtils.isKey(MarkerListActivity.this, R.string.recording_track_id_key, key)) {
|
||||||
recordingTrackId = PreferencesUtils.getRecordingTrackId(MarkerListActivity.this);
|
recordingTrackId = PreferencesUtils.getRecordingTrackId(sharedPreferences, MarkerListActivity.this);
|
||||||
}
|
}
|
||||||
if (PreferencesUtils.isKey(MarkerListActivity.this, R.string.recording_track_paused_key, key)) {
|
if (PreferencesUtils.isKey(MarkerListActivity.this, R.string.recording_track_paused_key, key)) {
|
||||||
recordingTrackPaused = PreferencesUtils.isRecordingTrackPaused(MarkerListActivity.this);
|
recordingTrackPaused = PreferencesUtils.isRecordingTrackPaused(sharedPreferences, MarkerListActivity.this);
|
||||||
}
|
}
|
||||||
if (key != null) {
|
if (key != null) {
|
||||||
runOnUiThread(MarkerListActivity.this::invalidateOptionsMenu);
|
runOnUiThread(MarkerListActivity.this::invalidateOptionsMenu);
|
||||||
@@ -138,7 +138,7 @@ public class MarkerListActivity extends AbstractActivity implements DeleteMarker
|
|||||||
protected void onStart() {
|
protected void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
||||||
sharedPreferenceChangeListener.onSharedPreferenceChanged(null, null);
|
sharedPreferenceChangeListener.onSharedPreferenceChanged(sharedPreferences, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package de.dennisguse.opentracks;
|
package de.dennisguse.opentracks;
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.os.StrictMode;
|
import android.os.StrictMode;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
@@ -27,31 +28,24 @@ public class Startup extends Application {
|
|||||||
Log.i(TAG, BuildConfig.APPLICATION_ID + "; BuildType: " + BuildConfig.BUILD_TYPE + "; VersionName: " + BuildConfig.VERSION_NAME + "/" + BuildConfig.VERSION_NAME_FULL + " VersionCode: " + BuildConfig.VERSION_CODE);
|
Log.i(TAG, BuildConfig.APPLICATION_ID + "; BuildType: " + BuildConfig.BUILD_TYPE + "; VersionName: " + BuildConfig.VERSION_NAME + "/" + BuildConfig.VERSION_NAME_FULL + " VersionCode: " + BuildConfig.VERSION_CODE);
|
||||||
|
|
||||||
//Set default values of preferences on first start.
|
//Set default values of preferences on first start.
|
||||||
PreferencesUtils.resetPreferences(this, false);
|
SharedPreferences sharedPreferences = PreferencesUtils.resetPreferences(this, false);
|
||||||
if (PreferencesUtils.getString(this, R.string.stats_units_key, "").equals("")) {
|
if (PreferencesUtils.getString(sharedPreferences, this, R.string.stats_units_key, "").equals("")) {
|
||||||
String statsUnits = getString(Locale.US.equals(Locale.getDefault()) ? R.string.stats_units_imperial : R.string.stats_units_metric);
|
String statsUnits = getString(Locale.US.equals(Locale.getDefault()) ? R.string.stats_units_imperial : R.string.stats_units_metric);
|
||||||
PreferencesUtils.setString(this, R.string.stats_units_key, statsUnits);
|
PreferencesUtils.setString(sharedPreferences, this, R.string.stats_units_key, statsUnits);
|
||||||
}
|
}
|
||||||
|
|
||||||
ActivityUtils.applyNightMode(this);
|
ActivityUtils.applyNightMode(sharedPreferences, this);
|
||||||
|
|
||||||
//TODO Workaround to reset recordingTrackId on app startup as the TrackRecordingService (likely) crashed.
|
//TODO Workaround to reset recordingTrackId on app startup as the TrackRecordingService (likely) crashed.
|
||||||
if (PreferencesUtils.isRecording(this)) {
|
if (PreferencesUtils.isRecording(sharedPreferences, this)) {
|
||||||
Log.e(TAG, "Reset recordingTrackId; likely the TrackRecordingService crashed.");
|
Log.e(TAG, "Reset recordingTrackId; likely the TrackRecordingService crashed.");
|
||||||
PreferencesUtils.setLong(this, R.string.recording_track_id_key, PreferencesUtils.RECORDING_TRACK_ID_DEFAULT);
|
PreferencesUtils.setLong(sharedPreferences, this, R.string.recording_track_id_key, PreferencesUtils.RECORDING_TRACK_ID_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
//In debug builds: show thread and VM warnings.
|
//In debug builds: show thread and VM warnings.
|
||||||
if (BuildConfig.DEBUG) {
|
if (BuildConfig.DEBUG) {
|
||||||
Log.d(TAG, "Enabling strict mode");
|
Log.d(TAG, "Enabling strict mode");
|
||||||
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
|
StrictMode.enableDefaults();
|
||||||
.detectAll()
|
|
||||||
.penaltyLog()
|
|
||||||
.build());
|
|
||||||
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
|
|
||||||
.detectAll()
|
|
||||||
.penaltyLog()
|
|
||||||
.build());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package de.dennisguse.opentracks;
|
package de.dennisguse.opentracks;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
|
import android.app.ActivityOptions;
|
||||||
import android.app.SearchManager;
|
import android.app.SearchManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -29,6 +30,7 @@ import android.location.LocationManager;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
@@ -107,18 +109,18 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
|
|||||||
|
|
||||||
private final OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
|
private final OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
if (PreferencesUtils.isKey(TrackListActivity.this, R.string.stats_units_key, key)) {
|
if (PreferencesUtils.isKey(TrackListActivity.this, R.string.stats_units_key, key)) {
|
||||||
metricUnits = PreferencesUtils.isMetricUnits(TrackListActivity.this);
|
metricUnits = PreferencesUtils.isMetricUnits(sharedPreferences, TrackListActivity.this);
|
||||||
}
|
}
|
||||||
if (PreferencesUtils.isKey(TrackListActivity.this, R.string.recording_track_id_key, key)) {
|
if (PreferencesUtils.isKey(TrackListActivity.this, R.string.recording_track_id_key, key)) {
|
||||||
recordingTrackId = PreferencesUtils.getRecordingTrackId(TrackListActivity.this);
|
recordingTrackId = PreferencesUtils.getRecordingTrackId(sharedPreferences, TrackListActivity.this);
|
||||||
if (key != null && PreferencesUtils.isRecording(recordingTrackId)) {
|
if (key != null && PreferencesUtils.isRecording(recordingTrackId)) {
|
||||||
trackRecordingServiceConnection.startAndBind(TrackListActivity.this);
|
trackRecordingServiceConnection.startAndBind(TrackListActivity.this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (PreferencesUtils.isKey(TrackListActivity.this, R.string.recording_track_paused_key, key)) {
|
if (PreferencesUtils.isKey(TrackListActivity.this, R.string.recording_track_paused_key, key)) {
|
||||||
recordingTrackPaused = PreferencesUtils.isRecordingTrackPaused(TrackListActivity.this);
|
recordingTrackPaused = PreferencesUtils.isRecordingTrackPaused(sharedPreferences, TrackListActivity.this);
|
||||||
}
|
}
|
||||||
if (key != null) {
|
if (key != null) {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
@@ -195,17 +197,20 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
|
|||||||
|
|
||||||
viewBinding.trackList.setEmptyView(viewBinding.trackListEmptyView);
|
viewBinding.trackList.setEmptyView(viewBinding.trackListEmptyView);
|
||||||
viewBinding.trackList.setOnItemClickListener((parent, view, position, trackId) -> {
|
viewBinding.trackList.setOnItemClickListener((parent, view, position, trackId) -> {
|
||||||
Intent newIntent;
|
|
||||||
if (trackId == recordingTrackId.getId()) {
|
if (trackId == recordingTrackId.getId()) {
|
||||||
// Is recording -> open record activity.
|
// Is recording -> open record activity.
|
||||||
newIntent = IntentUtils.newIntent(TrackListActivity.this, TrackRecordingActivity.class)
|
Intent newIntent = IntentUtils.newIntent(TrackListActivity.this, TrackRecordingActivity.class)
|
||||||
.putExtra(TrackRecordedActivity.EXTRA_TRACK_ID, new Track.Id(trackId));
|
.putExtra(TrackRecordedActivity.EXTRA_TRACK_ID, new Track.Id(trackId));
|
||||||
|
startActivity(newIntent);
|
||||||
} else {
|
} else {
|
||||||
// Not recording -> open detail activity.
|
// Not recording -> open detail activity.
|
||||||
newIntent = IntentUtils.newIntent(TrackListActivity.this, TrackRecordedActivity.class)
|
Intent newIntent = IntentUtils.newIntent(TrackListActivity.this, TrackRecordedActivity.class)
|
||||||
.putExtra(TrackRecordedActivity.EXTRA_TRACK_ID, new Track.Id(trackId));
|
.putExtra(TrackRecordedActivity.EXTRA_TRACK_ID, new Track.Id(trackId));
|
||||||
|
ActivityOptions activityOptions = ActivityOptions.makeSceneTransitionAnimation(
|
||||||
|
this,
|
||||||
|
new Pair<>(view.findViewById(R.id.list_item_icon), TrackRecordedActivity.VIEW_TRACK_ICON));
|
||||||
|
startActivity(newIntent, activityOptions.toBundle());
|
||||||
}
|
}
|
||||||
startActivity(newIntent);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
resourceCursorAdapter = new ResourceCursorAdapter(this, R.layout.list_item, null, 0) {
|
resourceCursorAdapter = new ResourceCursorAdapter(this, R.layout.list_item, null, 0) {
|
||||||
@@ -257,7 +262,7 @@ public class TrackListActivity extends AbstractListActivity implements ConfirmDe
|
|||||||
super.onStart();
|
super.onStart();
|
||||||
|
|
||||||
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
||||||
sharedPreferenceChangeListener.onSharedPreferenceChanged(null, null);
|
sharedPreferenceChangeListener.onSharedPreferenceChanged(sharedPreferences, null);
|
||||||
trackRecordingServiceConnection.startConnection(this);
|
trackRecordingServiceConnection.startConnection(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import android.view.MenuItem;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.core.view.ViewCompat;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||||
@@ -55,6 +56,8 @@ public class TrackRecordedActivity extends AbstractListActivity implements Confi
|
|||||||
|
|
||||||
private static final String TAG = TrackRecordedActivity.class.getSimpleName();
|
private static final String TAG = TrackRecordedActivity.class.getSimpleName();
|
||||||
|
|
||||||
|
public static final String VIEW_TRACK_ICON = "track_icon";
|
||||||
|
|
||||||
public static final String EXTRA_TRACK_ID = "track_id";
|
public static final String EXTRA_TRACK_ID = "track_id";
|
||||||
public static final String EXTRA_MARKER_ID = "marker_id";
|
public static final String EXTRA_MARKER_ID = "marker_id";
|
||||||
|
|
||||||
@@ -84,6 +87,8 @@ public class TrackRecordedActivity extends AbstractListActivity implements Confi
|
|||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
viewBinding.trackDetailActivityViewPager.setCurrentItem(savedInstanceState.getInt(CURRENT_TAB_TAG_KEY));
|
viewBinding.trackDetailActivityViewPager.setCurrentItem(savedInstanceState.getInt(CURRENT_TAB_TAG_KEY));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
postponeEnterTransition();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -138,7 +143,7 @@ public class TrackRecordedActivity extends AbstractListActivity implements Confi
|
|||||||
@Override
|
@Override
|
||||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||||
menu.findItem(R.id.track_detail_markers).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
menu.findItem(R.id.track_detail_markers).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
||||||
menu.findItem(R.id.track_detail_resume_track).setVisible(!PreferencesUtils.isRecording(this));
|
menu.findItem(R.id.track_detail_resume_track).setVisible(!PreferencesUtils.isRecording(PreferencesUtils.getSharedPreferences(this), this));
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
setTitle(track != null ? track.getName() : "");
|
setTitle(track != null ? track.getName() : "");
|
||||||
return super.onPrepareOptionsMenu(menu);
|
return super.onPrepareOptionsMenu(menu);
|
||||||
@@ -275,4 +280,9 @@ public class TrackRecordedActivity extends AbstractListActivity implements Confi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void startPostponedEnterTransitionWith(View viewIcon, View viewName) {
|
||||||
|
ViewCompat.setTransitionName(viewIcon, TrackRecordedActivity.VIEW_TRACK_ICON);
|
||||||
|
startPostponedEnterTransition();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -97,9 +97,9 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
|||||||
|
|
||||||
private final OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
|
private final OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
if (PreferencesUtils.isKey(TrackRecordingActivity.this, R.string.recording_track_paused_key, key)) {
|
if (PreferencesUtils.isKey(TrackRecordingActivity.this, R.string.recording_track_paused_key, key)) {
|
||||||
recordingTrackPaused = PreferencesUtils.isRecordingTrackPaused(TrackRecordingActivity.this);
|
recordingTrackPaused = PreferencesUtils.isRecordingTrackPaused(sharedPreferences, TrackRecordingActivity.this);
|
||||||
setLockscreenPolicy();
|
setLockscreenPolicy();
|
||||||
setScreenOnPolicy();
|
setScreenOnPolicy();
|
||||||
}
|
}
|
||||||
@@ -170,7 +170,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setLockscreenPolicy() {
|
private void setLockscreenPolicy() {
|
||||||
boolean showOnLockScreen = PreferencesUtils.shouldShowStatsOnLockscreen(TrackRecordingActivity.this);
|
boolean showOnLockScreen = PreferencesUtils.shouldShowStatsOnLockscreen(sharedPreferences, TrackRecordingActivity.this);
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
||||||
setShowWhenLocked(showOnLockScreen);
|
setShowWhenLocked(showOnLockScreen);
|
||||||
@@ -182,7 +182,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setScreenOnPolicy() {
|
private void setScreenOnPolicy() {
|
||||||
boolean keepScreenOn = PreferencesUtils.shouldKeepScreenOn(TrackRecordingActivity.this);
|
boolean keepScreenOn = PreferencesUtils.shouldKeepScreenOn(sharedPreferences, TrackRecordingActivity.this);
|
||||||
|
|
||||||
if (keepScreenOn) {
|
if (keepScreenOn) {
|
||||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||||
@@ -192,7 +192,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setFullscreenPolicy() {
|
private void setFullscreenPolicy() {
|
||||||
boolean keepScreenOn = PreferencesUtils.shouldUseFullscreen(TrackRecordingActivity.this);
|
boolean keepScreenOn = PreferencesUtils.shouldUseFullscreen(sharedPreferences, TrackRecordingActivity.this);
|
||||||
|
|
||||||
if (keepScreenOn) {
|
if (keepScreenOn) {
|
||||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||||
@@ -206,7 +206,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
|
|||||||
super.onStart();
|
super.onStart();
|
||||||
|
|
||||||
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
||||||
sharedPreferenceChangeListener.onSharedPreferenceChanged(null, null);
|
sharedPreferenceChangeListener.onSharedPreferenceChanged(sharedPreferences, null);
|
||||||
|
|
||||||
trackRecordingServiceConnection.startConnection(this);
|
trackRecordingServiceConnection.startConnection(this);
|
||||||
trackDataHub.start();
|
trackDataHub.start();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package de.dennisguse.opentracks.adapters;
|
package de.dennisguse.opentracks.adapters;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -134,11 +135,13 @@ public class AggregatedStatisticsAdapter extends BaseAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO Check preference handling.
|
||||||
private void setCommonValues(AggregatedStatistics.AggregatedStatistic aggregatedStatistic) {
|
private void setCommonValues(AggregatedStatistics.AggregatedStatistic aggregatedStatistic) {
|
||||||
String category = aggregatedStatistic.getCategory();
|
String category = aggregatedStatistic.getCategory();
|
||||||
|
|
||||||
reportSpeed = PreferencesUtils.isReportSpeed(context, category);
|
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||||
metricsUnits = PreferencesUtils.isMetricUnits(context);
|
reportSpeed = PreferencesUtils.isReportSpeed(sharedPreferences, context, category);
|
||||||
|
metricsUnits = PreferencesUtils.isMetricUnits(sharedPreferences, context);
|
||||||
|
|
||||||
sportIcon.setImageResource(getIcon(aggregatedStatistic));
|
sportIcon.setImageResource(getIcon(aggregatedStatistic));
|
||||||
typeLabel.setText(category);
|
typeLabel.setText(category);
|
||||||
|
|||||||
@@ -25,11 +25,12 @@ public class IntervalStatisticsAdapter extends ArrayAdapter<IntervalStatistics.I
|
|||||||
|
|
||||||
public IntervalStatisticsAdapter(Context context, List<IntervalStatistics.Interval> intervalList, String category, StackMode stackMode) {
|
public IntervalStatisticsAdapter(Context context, List<IntervalStatistics.Interval> intervalList, String category, StackMode stackMode) {
|
||||||
super(context, R.layout.interval_stats_list_item, intervalList);
|
super(context, R.layout.interval_stats_list_item, intervalList);
|
||||||
metricUnits = PreferencesUtils.isMetricUnits(context);
|
metricUnits = PreferencesUtils.isMetricUnits(PreferencesUtils.getSharedPreferences(context), context);
|
||||||
this.category = category;
|
this.category = category;
|
||||||
this.stackMode = stackMode;
|
this.stackMode = stackMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO Check preference handling! Should not be accessed in getView()
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public View getView(int position, @Nullable View intervalView, @NonNull ViewGroup parent) {
|
public View getView(int position, @Nullable View intervalView, @NonNull ViewGroup parent) {
|
||||||
@@ -60,7 +61,7 @@ public class IntervalStatisticsAdapter extends ArrayAdapter<IntervalStatistics.I
|
|||||||
}
|
}
|
||||||
viewHolder.distance.setText(StringUtils.formatDistance(getContext(), sumDistance_m, metricUnits));
|
viewHolder.distance.setText(StringUtils.formatDistance(getContext(), sumDistance_m, metricUnits));
|
||||||
|
|
||||||
if (PreferencesUtils.isReportSpeed(getContext(), category)) {
|
if (PreferencesUtils.isReportSpeed(PreferencesUtils.getSharedPreferences(getContext()), getContext(), category)) {
|
||||||
viewHolder.rate.setText(StringUtils.formatSpeed(getContext(), interval.getSpeed_ms(), metricUnits, true));
|
viewHolder.rate.setText(StringUtils.formatSpeed(getContext(), interval.getSpeed_ms(), metricUnits, true));
|
||||||
} else {
|
} else {
|
||||||
viewHolder.rate.setText(StringUtils.formatSpeed(getContext(), interval.getSpeed_ms(), metricUnits, false));
|
viewHolder.rate.setText(StringUtils.formatSpeed(getContext(), interval.getSpeed_ms(), metricUnits, false));
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public class MarkerResourceCursorAdapter extends ResourceCursorAdapter implement
|
|||||||
private final Activity activity;
|
private final Activity activity;
|
||||||
|
|
||||||
//TODO Should be Marker.Id
|
//TODO Should be Marker.Id
|
||||||
private final ExecutorListViewService executorService = new ExecutorListViewService<Long>(LIST_PREFERRED_ITEM_HEIGHT_DEFAULT);
|
private final ExecutorListViewService<Long> executorService = new ExecutorListViewService<Long>(LIST_PREFERRED_ITEM_HEIGHT_DEFAULT);
|
||||||
|
|
||||||
private boolean scroll = false;
|
private boolean scroll = false;
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
|||||||
private final ContentProviderUtils contentProviderUtils;
|
private final ContentProviderUtils contentProviderUtils;
|
||||||
private final int targetNumPoints;
|
private final int targetNumPoints;
|
||||||
|
|
||||||
|
private SharedPreferences sharedPreferences;
|
||||||
|
|
||||||
private boolean started;
|
private boolean started;
|
||||||
private HandlerThread handlerThread;
|
private HandlerThread handlerThread;
|
||||||
private Handler handler;
|
private Handler handler;
|
||||||
@@ -140,8 +142,10 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
|||||||
contentResolver.registerContentObserver(TrackPointsColumns.CONTENT_URI_BY_ID, false, trackPointsTableObserver);
|
contentResolver.registerContentObserver(TrackPointsColumns.CONTENT_URI_BY_ID, false, trackPointsTableObserver);
|
||||||
|
|
||||||
|
|
||||||
PreferencesUtils.register(context, this);
|
sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||||
onSharedPreferenceChanged(null, null);
|
sharedPreferences.registerOnSharedPreferenceChangeListener(this);
|
||||||
|
onSharedPreferenceChanged(sharedPreferences, null);
|
||||||
|
|
||||||
handler.post(() -> {
|
handler.post(() -> {
|
||||||
if (started) {
|
if (started) {
|
||||||
loadDataForAll();
|
loadDataForAll();
|
||||||
@@ -155,7 +159,8 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PreferencesUtils.unregister(context, this);
|
sharedPreferences.unregisterOnSharedPreferenceChangeListener(this);
|
||||||
|
sharedPreferences = null;
|
||||||
|
|
||||||
started = false;
|
started = false;
|
||||||
|
|
||||||
@@ -224,10 +229,10 @@ public class TrackDataHub implements SharedPreferences.OnSharedPreferenceChangeL
|
|||||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, final String key) {
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, final String key) {
|
||||||
handler.post(() -> {
|
handler.post(() -> {
|
||||||
if (PreferencesUtils.isKey(context, R.string.recording_track_id_key, key)) {
|
if (PreferencesUtils.isKey(context, R.string.recording_track_id_key, key)) {
|
||||||
recordingTrackId = PreferencesUtils.getRecordingTrackId(context);
|
recordingTrackId = PreferencesUtils.getRecordingTrackId(sharedPreferences, context);
|
||||||
}
|
}
|
||||||
if (PreferencesUtils.isKey(context, R.string.recording_track_paused_key, key)) {
|
if (PreferencesUtils.isKey(context, R.string.recording_track_paused_key, key)) {
|
||||||
recordingTrackPaused = PreferencesUtils.isRecordingTrackPaused(context);
|
recordingTrackPaused = PreferencesUtils.isRecordingTrackPaused(sharedPreferences, context);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,6 +109,19 @@ public class Track {
|
|||||||
this.trackStatistics = trackStatistics;
|
this.trackStatistics = trackStatistics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Track track = (Track) o;
|
||||||
|
return id.equals(track.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(id);
|
||||||
|
}
|
||||||
|
|
||||||
public static class Id implements Parcelable {
|
public static class Id implements Parcelable {
|
||||||
|
|
||||||
private final long id;
|
private final long id;
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ public class TrackPoint {
|
|||||||
private Double altitude_m;
|
private Double altitude_m;
|
||||||
private Float speed_mps;
|
private Float speed_mps;
|
||||||
private Float bearing;
|
private Float bearing;
|
||||||
|
private Float sensorDistance_m;
|
||||||
|
|
||||||
public enum Type {
|
public enum Type {
|
||||||
SEGMENT_START_MANUAL(-2), //Start of a segment due to user interaction (start, resume)
|
SEGMENT_START_MANUAL(-2), //Start of a segment due to user interaction (start, resume)
|
||||||
@@ -224,7 +225,7 @@ public class TrackPoint {
|
|||||||
return elevationGain != null;
|
return elevationGain != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Float getElevationGain() {
|
public float getElevationGain() {
|
||||||
return elevationGain;
|
return elevationGain;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,8 +311,12 @@ public class TrackPoint {
|
|||||||
this.accuracy = horizontalAccuracy;
|
this.accuracy = horizontalAccuracy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float distanceTo(@NonNull TrackPoint dest) {
|
public float distanceToPrevious(@NonNull TrackPoint previous) {
|
||||||
return getLocation().distanceTo(dest.getLocation());
|
if (hasSensorDistance()) {
|
||||||
|
return getSensorDistance();
|
||||||
|
}
|
||||||
|
|
||||||
|
return getLocation().distanceTo(previous.getLocation());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean fulfillsAccuracy(int poorAccuracy) {
|
public boolean fulfillsAccuracy(int poorAccuracy) {
|
||||||
@@ -327,6 +332,18 @@ public class TrackPoint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sensor data
|
// Sensor data
|
||||||
|
public boolean hasSensorDistance() {
|
||||||
|
return sensorDistance_m != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Float getSensorDistance() {
|
||||||
|
return sensorDistance_m;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSensorDistance(Float distance_m) {
|
||||||
|
this.sensorDistance_m = distance_m;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasSensorData() {
|
public boolean hasSensorData() {
|
||||||
return hasHeartRate() || hasCyclingCadence() || hasPower();
|
return hasHeartRate() || hasCyclingCadence() || hasPower();
|
||||||
}
|
}
|
||||||
@@ -347,7 +364,7 @@ public class TrackPoint {
|
|||||||
return cyclingCadence_rpm != null;
|
return cyclingCadence_rpm != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Float getCyclingCadence_rpm() {
|
public float getCyclingCadence_rpm() {
|
||||||
return cyclingCadence_rpm;
|
return cyclingCadence_rpm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,7 +376,7 @@ public class TrackPoint {
|
|||||||
return power != null;
|
return power != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Float getPower() {
|
public float getPower() {
|
||||||
return power;
|
return power;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ public interface TrackPointsColumns extends BaseColumns {
|
|||||||
String BEARING = "bearing";
|
String BEARING = "bearing";
|
||||||
String SENSOR_HEARTRATE = "sensor_heartrate";
|
String SENSOR_HEARTRATE = "sensor_heartrate";
|
||||||
String SENSOR_CADENCE = "sensor_cadence";
|
String SENSOR_CADENCE = "sensor_cadence";
|
||||||
|
String SENSOR_DISTANCE = "sensor_distance"; //DISTANCE from previous TrackPoint
|
||||||
String SENSOR_POWER = "sensor_power";
|
String SENSOR_POWER = "sensor_power";
|
||||||
String ELEVATION_GAIN = "elevation_gain";
|
String ELEVATION_GAIN = "elevation_gain";
|
||||||
String ELEVATION_LOSS = "elevation_loss";
|
String ELEVATION_LOSS = "elevation_loss";
|
||||||
@@ -77,6 +78,7 @@ public interface TrackPointsColumns extends BaseColumns {
|
|||||||
+ ELEVATION_GAIN + " FLOAT, "
|
+ ELEVATION_GAIN + " FLOAT, "
|
||||||
+ ELEVATION_LOSS + " FLOAT, "
|
+ ELEVATION_LOSS + " FLOAT, "
|
||||||
+ TYPE + " TEXT CHECK(type IN (-2, -1, 0, 1)), "
|
+ TYPE + " TEXT CHECK(type IN (-2, -1, 0, 1)), "
|
||||||
|
+ SENSOR_DISTANCE + " FLOAT, "
|
||||||
+ "FOREIGN KEY (" + TRACKID + ") REFERENCES " + TracksColumns.TABLE_NAME + "(" + TracksColumns._ID + ") ON UPDATE CASCADE ON DELETE CASCADE"
|
+ "FOREIGN KEY (" + TRACKID + ") REFERENCES " + TracksColumns.TABLE_NAME + "(" + TracksColumns._ID + ") ON UPDATE CASCADE ON DELETE CASCADE"
|
||||||
+ ")";
|
+ ")";
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ class CachedTrackPointsIndexes {
|
|||||||
final int bearingIndex;
|
final int bearingIndex;
|
||||||
final int sensorHeartRateIndex;
|
final int sensorHeartRateIndex;
|
||||||
final int sensorCadenceIndex;
|
final int sensorCadenceIndex;
|
||||||
|
final int sensorDistanceIndex;
|
||||||
final int sensorPowerIndex;
|
final int sensorPowerIndex;
|
||||||
final int elevationGainIndex;
|
final int elevationGainIndex;
|
||||||
final int elevationLossIndex;
|
final int elevationLossIndex;
|
||||||
@@ -35,6 +36,7 @@ class CachedTrackPointsIndexes {
|
|||||||
bearingIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.BEARING);
|
bearingIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.BEARING);
|
||||||
sensorHeartRateIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.SENSOR_HEARTRATE);
|
sensorHeartRateIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.SENSOR_HEARTRATE);
|
||||||
sensorCadenceIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.SENSOR_CADENCE);
|
sensorCadenceIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.SENSOR_CADENCE);
|
||||||
|
sensorDistanceIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.SENSOR_DISTANCE);
|
||||||
sensorPowerIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.SENSOR_POWER);
|
sensorPowerIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.SENSOR_POWER);
|
||||||
elevationGainIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.ELEVATION_GAIN);
|
elevationGainIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.ELEVATION_GAIN);
|
||||||
elevationLossIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.ELEVATION_LOSS);
|
elevationLossIndex = cursor.getColumnIndexOrThrow(TrackPointsColumns.ELEVATION_LOSS);
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ public class ContentProviderUtils {
|
|||||||
private static final String ID_SEPARATOR = ",";
|
private static final String ID_SEPARATOR = ",";
|
||||||
|
|
||||||
private final ContentResolver contentResolver;
|
private final ContentResolver contentResolver;
|
||||||
private int defaultCursorBatchSize = 2000;
|
|
||||||
|
|
||||||
public ContentProviderUtils(Context context) {
|
public ContentProviderUtils(Context context) {
|
||||||
contentResolver = context.getContentResolver();
|
contentResolver = context.getContentResolver();
|
||||||
@@ -176,7 +175,7 @@ public class ContentProviderUtils {
|
|||||||
|
|
||||||
// Delete track last since it triggers a database vacuum call
|
// Delete track last since it triggers a database vacuum call
|
||||||
String whereClause = String.format(TracksColumns._ID + " IN (%s)", TextUtils.join(",", Collections.nCopies(trackIds.size(), "?")));
|
String whereClause = String.format(TracksColumns._ID + " IN (%s)", TextUtils.join(",", Collections.nCopies(trackIds.size(), "?")));
|
||||||
contentResolver.delete(TracksColumns.CONTENT_URI, whereClause, trackIds.stream().map(id->Long.toString(id.getId())).toArray(String[]::new));
|
contentResolver.delete(TracksColumns.CONTENT_URI, whereClause, trackIds.stream().map(id -> Long.toString(id.getId())).toArray(String[]::new));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteTrack(Context context, @NonNull Track.Id trackId) {
|
public void deleteTrack(Context context, @NonNull Track.Id trackId) {
|
||||||
@@ -556,6 +555,9 @@ public class ContentProviderUtils {
|
|||||||
if (!cursor.isNull(indexes.sensorCadenceIndex)) {
|
if (!cursor.isNull(indexes.sensorCadenceIndex)) {
|
||||||
trackPoint.setCyclingCadence_rpm(cursor.getFloat(indexes.sensorCadenceIndex));
|
trackPoint.setCyclingCadence_rpm(cursor.getFloat(indexes.sensorCadenceIndex));
|
||||||
}
|
}
|
||||||
|
if (!cursor.isNull(indexes.sensorDistanceIndex)) {
|
||||||
|
trackPoint.setSensorDistance(cursor.getFloat(indexes.sensorDistanceIndex));
|
||||||
|
}
|
||||||
if (!cursor.isNull(indexes.sensorPowerIndex)) {
|
if (!cursor.isNull(indexes.sensorPowerIndex)) {
|
||||||
trackPoint.setPower(cursor.getFloat(indexes.sensorPowerIndex));
|
trackPoint.setPower(cursor.getFloat(indexes.sensorPowerIndex));
|
||||||
}
|
}
|
||||||
@@ -629,9 +631,9 @@ public class ContentProviderUtils {
|
|||||||
*
|
*
|
||||||
* @param trackId the track id
|
* @param trackId the track id
|
||||||
* @param startTrackPointId the starting trackPoint id. `null` to ignore
|
* @param startTrackPointId the starting trackPoint id. `null` to ignore
|
||||||
* @param maxLocations maximum number of locations to return. `null` for no limit
|
|
||||||
*/
|
*/
|
||||||
public Cursor getTrackPointCursor(Track.Id trackId, TrackPoint.Id startTrackPointId, Integer maxLocations) {
|
@NonNull
|
||||||
|
public Cursor getTrackPointCursor(@NonNull Track.Id trackId, TrackPoint.Id startTrackPointId) {
|
||||||
String selection;
|
String selection;
|
||||||
String[] selectionArgs;
|
String[] selectionArgs;
|
||||||
if (startTrackPointId != null) {
|
if (startTrackPointId != null) {
|
||||||
@@ -642,11 +644,7 @@ public class ContentProviderUtils {
|
|||||||
selectionArgs = new String[]{Long.toString(trackId.getId())};
|
selectionArgs = new String[]{Long.toString(trackId.getId())};
|
||||||
}
|
}
|
||||||
|
|
||||||
String sortOrder = TrackPointsColumns.DEFAULT_SORT_ORDER;
|
return getTrackPointCursor(null, selection, selectionArgs, TrackPointsColumns.DEFAULT_SORT_ORDER);
|
||||||
if (maxLocations != null) {
|
|
||||||
sortOrder += " LIMIT " + maxLocations;
|
|
||||||
}
|
|
||||||
return getTrackPointCursor(null, selection, selectionArgs, sortOrder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -708,6 +706,9 @@ public class ContentProviderUtils {
|
|||||||
if (trackPoint.hasCyclingCadence()) {
|
if (trackPoint.hasCyclingCadence()) {
|
||||||
values.put(TrackPointsColumns.SENSOR_CADENCE, trackPoint.getCyclingCadence_rpm());
|
values.put(TrackPointsColumns.SENSOR_CADENCE, trackPoint.getCyclingCadence_rpm());
|
||||||
}
|
}
|
||||||
|
if (trackPoint.hasSensorDistance()) {
|
||||||
|
values.put(TrackPointsColumns.SENSOR_DISTANCE, trackPoint.getSensorDistance());
|
||||||
|
}
|
||||||
if (trackPoint.hasPower()) {
|
if (trackPoint.hasPower()) {
|
||||||
values.put(TrackPointsColumns.SENSOR_POWER, trackPoint.getPower());
|
values.put(TrackPointsColumns.SENSOR_POWER, trackPoint.getPower());
|
||||||
}
|
}
|
||||||
@@ -757,39 +758,6 @@ public class ContentProviderUtils {
|
|||||||
return contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, projection, selection, selectionArgs, sortOrder);
|
return contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, projection, selection, selectionArgs, sortOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
public List<TrackPoint> getTrackPoints(Track.Id trackId) {
|
|
||||||
List<TrackPoint> trackPoints = null;
|
|
||||||
|
|
||||||
try (Cursor trackPointCursor = getTrackPointCursor(trackId, null, null)) {
|
|
||||||
if (trackPointCursor != null) {
|
|
||||||
trackPointCursor.moveToFirst();
|
|
||||||
trackPoints = new ArrayList<>(trackPointCursor.getCount());
|
|
||||||
for (int i = 0; i < trackPointCursor.getCount(); i++) {
|
|
||||||
trackPoints.add(createTrackPoint(trackPointCursor));
|
|
||||||
trackPointCursor.moveToNext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return trackPoints;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getDefaultCursorBatchSize() {
|
|
||||||
return defaultCursorBatchSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the default cursor batch size. For testing purpose.
|
|
||||||
*
|
|
||||||
* @param defaultCursorBatchSize the default cursor batch size
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
|
||||||
void setDefaultCursorBatchSize(int defaultCursorBatchSize) {
|
|
||||||
this.defaultCursorBatchSize = defaultCursorBatchSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static String formatIdListForUri(Track.Id... trackIds) {
|
public static String formatIdListForUri(Track.Id... trackIds) {
|
||||||
long[] ids = new long[trackIds.length];
|
long[] ids = new long[trackIds.length];
|
||||||
for (int i = 0; i < trackIds.length; i++) {
|
for (int i = 0; i < trackIds.length; i++) {
|
||||||
|
|||||||
@@ -259,8 +259,7 @@ public class CustomContentProvider extends ContentProvider {
|
|||||||
break;
|
break;
|
||||||
case TRACKS_SENSOR_STATS:
|
case TRACKS_SENSOR_STATS:
|
||||||
long trackId = ContentUris.parseId(url);
|
long trackId = ContentUris.parseId(url);
|
||||||
Cursor cursor = db.rawQuery(SENSOR_STATS_QUERY, new String[]{String.valueOf(trackId), String.valueOf(trackId)});
|
return db.rawQuery(SENSOR_STATS_QUERY, new String[]{String.valueOf(trackId), String.valueOf(trackId)});
|
||||||
return cursor;
|
|
||||||
case MARKERS:
|
case MARKERS:
|
||||||
queryBuilder.setTables(MarkerColumns.TABLE_NAME);
|
queryBuilder.setTables(MarkerColumns.TABLE_NAME);
|
||||||
sortOrder = sort != null ? sort : MarkerColumns.DEFAULT_SORT_ORDER;
|
sortOrder = sort != null ? sort : MarkerColumns.DEFAULT_SORT_ORDER;
|
||||||
|
|||||||
+35
-2
@@ -25,7 +25,7 @@ public class CustomSQLiteOpenHelper extends SQLiteOpenHelper {
|
|||||||
|
|
||||||
private static final String TAG = CustomSQLiteOpenHelper.class.getSimpleName();
|
private static final String TAG = CustomSQLiteOpenHelper.class.getSimpleName();
|
||||||
|
|
||||||
private static final int DATABASE_VERSION = 30;
|
private static final int DATABASE_VERSION = 31;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public static final String DATABASE_NAME = "database.db";
|
public static final String DATABASE_NAME = "database.db";
|
||||||
@@ -82,6 +82,9 @@ public class CustomSQLiteOpenHelper extends SQLiteOpenHelper {
|
|||||||
case 30:
|
case 30:
|
||||||
upgradeFrom29to30(db);
|
upgradeFrom29to30(db);
|
||||||
break;
|
break;
|
||||||
|
case 31:
|
||||||
|
upgradeFrom30to31(db);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new RuntimeException("Not implemented: upgrade to " + toVersion);
|
throw new RuntimeException("Not implemented: upgrade to " + toVersion);
|
||||||
@@ -115,7 +118,9 @@ public class CustomSQLiteOpenHelper extends SQLiteOpenHelper {
|
|||||||
case 29:
|
case 29:
|
||||||
downgradeFrom30to29(db);
|
downgradeFrom30to29(db);
|
||||||
break;
|
break;
|
||||||
|
case 30:
|
||||||
|
downgradeFrom31to30(db);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new RuntimeException("Not implemented: downgrade to " + toVersion);
|
throw new RuntimeException("Not implemented: downgrade to " + toVersion);
|
||||||
}
|
}
|
||||||
@@ -394,4 +399,32 @@ public class CustomSQLiteOpenHelper extends SQLiteOpenHelper {
|
|||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add distance column to TrackPoint.
|
||||||
|
*/
|
||||||
|
private void upgradeFrom30to31(SQLiteDatabase db) {
|
||||||
|
db.beginTransaction();
|
||||||
|
|
||||||
|
// TrackPoints
|
||||||
|
db.execSQL("ALTER TABLE trackpoints ADD COLUMN sensor_distance FLOAT");
|
||||||
|
|
||||||
|
db.setTransactionSuccessful();
|
||||||
|
db.endTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void downgradeFrom31to30(SQLiteDatabase db) {
|
||||||
|
db.beginTransaction();
|
||||||
|
|
||||||
|
// TrackPoints; identical to upgradeFrom27to28()
|
||||||
|
db.execSQL("ALTER TABLE trackpoints RENAME TO trackpoints_old");
|
||||||
|
db.execSQL("CREATE TABLE trackpoints (_id INTEGER PRIMARY KEY AUTOINCREMENT, trackid INTEGER NOT NULL, longitude INTEGER, latitude INTEGER, time INTEGER, elevation FLOAT, accuracy FLOAT, speed FLOAT, bearing FLOAT, sensor_heartrate FLOAT, sensor_cadence FLOAT, sensor_power FLOAT, elevation_gain FLOAT, elevation_loss FLOAT, type TEXT CHECK(type IN (-2, -1, 0, 1)), FOREIGN KEY (trackid) REFERENCES tracks(_id) ON UPDATE CASCADE ON DELETE CASCADE)");
|
||||||
|
db.execSQL("INSERT INTO trackpoints SELECT _id, trackid, longitude, latitude, time, elevation, accuracy, speed, bearing, sensor_heartrate, sensor_cadence, sensor_power, elevation_gain, elevation_gain, type FROM trackpoints_old");
|
||||||
|
db.execSQL("DROP TABLE trackpoints_old");
|
||||||
|
|
||||||
|
db.execSQL("CREATE INDEX trackpoints_trackid_index ON trackpoints(trackid)");
|
||||||
|
|
||||||
|
db.setTransactionSuccessful();
|
||||||
|
db.endTransaction();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package de.dennisguse.opentracks.content.provider;
|
package de.dennisguse.opentracks.content.provider;
|
||||||
|
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.util.Log;
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
@@ -10,9 +12,8 @@ import de.dennisguse.opentracks.content.data.Track;
|
|||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A lightweight wrapper around the original {@link Cursor} with a method to clean up.
|
* A lightweight wrapper around the original {@link Cursor}.
|
||||||
*/
|
*/
|
||||||
//TODO Remove batching; that should be handled by the database/contentprovider (i.e., already in place as we use a cursor)!
|
|
||||||
public class TrackPointIterator implements Iterator<TrackPoint>, AutoCloseable {
|
public class TrackPointIterator implements Iterator<TrackPoint>, AutoCloseable {
|
||||||
|
|
||||||
private static final String TAG = TrackPointIterator.class.getSimpleName();
|
private static final String TAG = TrackPointIterator.class.getSimpleName();
|
||||||
@@ -20,7 +21,6 @@ public class TrackPointIterator implements Iterator<TrackPoint>, AutoCloseable {
|
|||||||
private final ContentProviderUtils contentProviderUtils;
|
private final ContentProviderUtils contentProviderUtils;
|
||||||
private final Track.Id trackId;
|
private final Track.Id trackId;
|
||||||
private final CachedTrackPointsIndexes indexes;
|
private final CachedTrackPointsIndexes indexes;
|
||||||
private TrackPoint.Id lastTrackPointId = null;
|
|
||||||
private Cursor cursor;
|
private Cursor cursor;
|
||||||
|
|
||||||
public TrackPointIterator(ContentProviderUtils contentProviderUtils, Track.Id trackId, TrackPoint.Id startTrackPointId) {
|
public TrackPointIterator(ContentProviderUtils contentProviderUtils, Track.Id trackId, TrackPoint.Id startTrackPointId) {
|
||||||
@@ -28,28 +28,11 @@ public class TrackPointIterator implements Iterator<TrackPoint>, AutoCloseable {
|
|||||||
this.trackId = trackId;
|
this.trackId = trackId;
|
||||||
|
|
||||||
cursor = getCursor(startTrackPointId);
|
cursor = getCursor(startTrackPointId);
|
||||||
indexes = cursor != null ? new CachedTrackPointsIndexes(cursor)
|
indexes = new CachedTrackPointsIndexes(cursor);
|
||||||
: null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the track point cursor.
|
|
||||||
*
|
|
||||||
* @param trackPointId the starting track point id
|
|
||||||
*/
|
|
||||||
private Cursor getCursor(TrackPoint.Id trackPointId) {
|
private Cursor getCursor(TrackPoint.Id trackPointId) {
|
||||||
return contentProviderUtils.getTrackPointCursor(trackId, trackPointId, contentProviderUtils.getDefaultCursorBatchSize());
|
return contentProviderUtils.getTrackPointCursor(trackId, trackPointId);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Advances the cursor to the next batch. Returns true if successful.
|
|
||||||
*/
|
|
||||||
private boolean advanceCursorToNextBatch() {
|
|
||||||
TrackPoint.Id trackPointId = lastTrackPointId == null ? null : new TrackPoint.Id(lastTrackPointId.getId() + 1);
|
|
||||||
Log.d(TAG, "Advancing track point id: " + trackPointId);
|
|
||||||
cursor.close();
|
|
||||||
cursor = getCursor(trackPointId);
|
|
||||||
return cursor != null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -57,32 +40,23 @@ public class TrackPointIterator implements Iterator<TrackPoint>, AutoCloseable {
|
|||||||
if (cursor == null) {
|
if (cursor == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (cursor.isAfterLast()) {
|
return !cursor.isLast() && !cursor.isAfterLast();
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (cursor.isLast()) {
|
|
||||||
if (cursor.getCount() != contentProviderUtils.getDefaultCursorBatchSize()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return advanceCursorToNextBatch() && !cursor.isAfterLast();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@NonNull
|
||||||
public TrackPoint next() {
|
public TrackPoint next() {
|
||||||
if (cursor == null) {
|
if (cursor == null || !cursor.moveToNext()) {
|
||||||
throw new NoSuchElementException();
|
throw new NoSuchElementException();
|
||||||
}
|
}
|
||||||
if (!cursor.moveToNext()) {
|
|
||||||
if (!advanceCursorToNextBatch() || !cursor.moveToNext()) {
|
|
||||||
throw new NoSuchElementException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lastTrackPointId = new TrackPoint.Id(cursor.getLong(indexes.idIndex));
|
|
||||||
return ContentProviderUtils.fillTrackPoint(cursor, indexes);
|
return ContentProviderUtils.fillTrackPoint(cursor, indexes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public int getCount() {
|
||||||
|
return cursor.getCount();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
if (cursor != null) {
|
if (cursor != null) {
|
||||||
|
|||||||
@@ -54,6 +54,12 @@ public abstract class SensorData<T> {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset long term aggregated values (more than derived from previous SensorData). e.g. overall distance.
|
||||||
|
*/
|
||||||
|
public void reset() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is the data recent considering the current time.
|
* Is the data recent considering the current time.
|
||||||
*/
|
*/
|
||||||
@@ -61,4 +67,10 @@ public abstract class SensorData<T> {
|
|||||||
return Instant.now()
|
return Instant.now()
|
||||||
.isBefore(time.plus(BluetoothRemoteSensorManager.MAX_SENSOR_DATE_SET_AGE_MS));
|
.isBefore(time.plus(BluetoothRemoteSensorManager.MAX_SENSOR_DATE_SET_AGE_MS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "sensorAddress='" + sensorAddress;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ public final class SensorDataCycling {
|
|||||||
/**
|
/**
|
||||||
* Workaround for Wahoo CADENCE: provides speed instead of cadence
|
* Workaround for Wahoo CADENCE: provides speed instead of cadence
|
||||||
*/
|
*/
|
||||||
public Cadence(@NonNull SensorDataCycling.Speed speed) {
|
public Cadence(@NonNull DistanceSpeed speed) {
|
||||||
this(speed.getSensorAddress(), speed.getSensorName(), speed.wheelRevolutionsCount, speed.wheelRevolutionsTime);
|
this(speed.getSensorAddress(), speed.getSensorName(), speed.wheelRevolutionsCount, speed.wheelRevolutionsTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ public final class SensorDataCycling {
|
|||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "cadence=" + value + " time=" + crankRevolutionsTime + " count=" + crankRevolutionsCount;
|
return super.toString() + " cadence=" + value + " time=" + crankRevolutionsTime + " count=" + crankRevolutionsCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -90,18 +90,18 @@ public final class SensorDataCycling {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Speed extends SensorData<Float> {
|
public static class DistanceSpeed extends SensorData<DistanceSpeed.Data> {
|
||||||
|
|
||||||
private final Integer wheelRevolutionsCount; // UINT16
|
private final Integer wheelRevolutionsCount; // UINT16
|
||||||
private final Integer wheelRevolutionsTime; // UINT16; 1/1024s
|
private final Integer wheelRevolutionsTime; // UINT16; 1/1024s
|
||||||
|
|
||||||
public Speed(String sensorAddress) {
|
public DistanceSpeed(String sensorAddress) {
|
||||||
super(sensorAddress);
|
super(sensorAddress);
|
||||||
this.wheelRevolutionsCount = null;
|
this.wheelRevolutionsCount = null;
|
||||||
this.wheelRevolutionsTime = null;
|
this.wheelRevolutionsTime = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Speed(String sensorAddress, String sensorName, int wheelRevolutionsCount, int wheelRevolutionsTime) {
|
public DistanceSpeed(String sensorAddress, String sensorName, int wheelRevolutionsCount, int wheelRevolutionsTime) {
|
||||||
super(sensorAddress, sensorName);
|
super(sensorAddress, sensorName);
|
||||||
this.wheelRevolutionsCount = wheelRevolutionsCount;
|
this.wheelRevolutionsCount = wheelRevolutionsCount;
|
||||||
this.wheelRevolutionsTime = wheelRevolutionsTime;
|
this.wheelRevolutionsTime = wheelRevolutionsTime;
|
||||||
@@ -119,7 +119,7 @@ public final class SensorDataCycling {
|
|||||||
return wheelRevolutionsTime;
|
return wheelRevolutionsTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void compute(Speed previous, int wheel_circumference_mm) {
|
public void compute(DistanceSpeed previous, int wheel_circumference_mm) {
|
||||||
if (hasData() && previous != null && previous.hasData()) {
|
if (hasData() && previous != null && previous.hasData()) {
|
||||||
float timeDiff_ms = UintUtils.diff(wheelRevolutionsTime, previous.wheelRevolutionsTime, UintUtils.UINT16_MAX) / 1024f * UnitConversions.S_TO_MS;
|
float timeDiff_ms = UintUtils.diff(wheelRevolutionsTime, previous.wheelRevolutionsTime, UintUtils.UINT16_MAX) / 1024f * UnitConversions.S_TO_MS;
|
||||||
if (timeDiff_ms <= 0) {
|
if (timeDiff_ms <= 0) {
|
||||||
@@ -127,43 +127,79 @@ public final class SensorDataCycling {
|
|||||||
value = null;
|
value = null;
|
||||||
} else {
|
} else {
|
||||||
long wheelDiff = UintUtils.diff(wheelRevolutionsCount, previous.wheelRevolutionsCount, UintUtils.UINT16_MAX);
|
long wheelDiff = UintUtils.diff(wheelRevolutionsCount, previous.wheelRevolutionsCount, UintUtils.UINT16_MAX);
|
||||||
|
wheelDiff = Math.abs(wheelDiff); //HACK for Garmin Speed 2 as it some of those seem to count backwards
|
||||||
|
|
||||||
double timeDiff_s = timeDiff_ms * UnitConversions.MS_TO_S;
|
double timeDiff_s = timeDiff_ms * UnitConversions.MS_TO_S;
|
||||||
value = (float) (wheelDiff * wheel_circumference_mm * UnitConversions.MM_TO_M / timeDiff_s);
|
float distance_m = (float) (wheelDiff * wheel_circumference_mm * UnitConversions.MM_TO_M);
|
||||||
|
float distance_overall_m = distance_m;
|
||||||
|
if (previous.hasValue()) {
|
||||||
|
distance_overall_m += previous.getValue().distance_overall_m;
|
||||||
}
|
}
|
||||||
|
float speed_mps = (float) (distance_m / timeDiff_s);
|
||||||
|
value = new Data(distance_m, distance_overall_m, speed_mps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
if (value != null) {
|
||||||
|
value = new Data(value.distance_m, 0, value.speed_mps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "speed=" + value + " time=" + wheelRevolutionsTime + " count=" + wheelRevolutionsCount;
|
return super.toString() + " data=" + value + " time=" + wheelRevolutionsTime + " count=" + wheelRevolutionsCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(@Nullable Object obj) {
|
public boolean equals(@Nullable Object obj) {
|
||||||
if (!(obj instanceof Speed)) return false;
|
if (!(obj instanceof DistanceSpeed)) return false;
|
||||||
|
|
||||||
Speed comp = (Speed) obj;
|
DistanceSpeed comp = (DistanceSpeed) obj;
|
||||||
if (hasData() && comp.hasData() == hasData()) {
|
if (hasData() && comp.hasData() == hasData()) {
|
||||||
return getWheelRevolutionsCount() == comp.getWheelRevolutionsCount() && getWheelRevolutionsTime() == comp.getWheelRevolutionsTime();
|
return getWheelRevolutionsCount() == comp.getWheelRevolutionsCount() && getWheelRevolutionsTime() == comp.getWheelRevolutionsTime();
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Data {
|
||||||
|
public final float distance_m;
|
||||||
|
public final float distance_overall_m;
|
||||||
|
public final float speed_mps;
|
||||||
|
|
||||||
|
private Data(float distance_m, float distance_overall_m, float speed_mps) {
|
||||||
|
this.distance_m = distance_m;
|
||||||
|
this.distance_overall_m = distance_overall_m;
|
||||||
|
this.speed_mps = speed_mps;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class CadenceAndSpeed extends SensorData<Pair<Cadence, Speed>> {
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Data{" +
|
||||||
|
"distance_m=" + distance_m +
|
||||||
|
", distance_overall_m=" + distance_overall_m +
|
||||||
|
", speed_mps=" + speed_mps +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public CadenceAndSpeed(String sensorAddress, String sensorName, @NonNull Cadence cadence, @NonNull Speed speed) {
|
public static class CadenceAndSpeed extends SensorData<Pair<Cadence, DistanceSpeed>> {
|
||||||
|
|
||||||
|
public CadenceAndSpeed(String sensorAddress, String sensorName, @Nullable Cadence cadence, @Nullable DistanceSpeed distanceSpeed) {
|
||||||
super(sensorAddress, sensorName);
|
super(sensorAddress, sensorName);
|
||||||
this.value = new Pair<>(cadence, speed);
|
this.value = new Pair<>(cadence, distanceSpeed);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Cadence getCadence() {
|
public Cadence getCadence() {
|
||||||
return this.value != null ? this.value.first : null;
|
return this.value != null ? this.value.first : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Speed getSpeed() {
|
public DistanceSpeed getDistanceSpeed() {
|
||||||
return this.value != null ? this.value.second : null;
|
return this.value != null ? this.value.second : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,6 @@ public class SensorDataCyclingPower extends SensorData<Float> {
|
|||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "power=" + value;
|
return super.toString() + " power=" + value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,6 @@ public class SensorDataHeartRate extends SensorData<Float> {
|
|||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "heart=" + value;
|
return super.toString() + " heart=" + value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ public final class SensorDataSet {
|
|||||||
|
|
||||||
private SensorDataCycling.Cadence cyclingCadence;
|
private SensorDataCycling.Cadence cyclingCadence;
|
||||||
|
|
||||||
private SensorDataCycling.Speed cyclingSpeed;
|
private SensorDataCycling.DistanceSpeed cyclingDistanceSpeed;
|
||||||
|
|
||||||
private SensorDataCyclingPower cyclingPower;
|
private SensorDataCyclingPower cyclingPower;
|
||||||
|
|
||||||
@@ -25,8 +25,8 @@ public final class SensorDataSet {
|
|||||||
return cyclingCadence;
|
return cyclingCadence;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SensorDataCycling.Speed getCyclingSpeed() {
|
public SensorDataCycling.DistanceSpeed getCyclingDistanceSpeed() {
|
||||||
return cyclingSpeed;
|
return cyclingDistanceSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SensorDataCyclingPower getCyclingPower() {
|
public SensorDataCyclingPower getCyclingPower() {
|
||||||
@@ -44,7 +44,7 @@ public final class SensorDataSet {
|
|||||||
public void clear() {
|
public void clear() {
|
||||||
this.heartRate = null;
|
this.heartRate = null;
|
||||||
this.cyclingCadence = null;
|
this.cyclingCadence = null;
|
||||||
this.cyclingSpeed = null;
|
this.cyclingDistanceSpeed = null;
|
||||||
this.cyclingPower = null;
|
this.cyclingPower = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,8 +57,9 @@ public final class SensorDataSet {
|
|||||||
trackPoint.setCyclingCadence_rpm(cyclingCadence.getValue());
|
trackPoint.setCyclingCadence_rpm(cyclingCadence.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cyclingSpeed != null && cyclingSpeed.hasValue()) {
|
if (cyclingDistanceSpeed != null && cyclingDistanceSpeed.hasValue()) {
|
||||||
trackPoint.setSpeed(cyclingSpeed.getValue());
|
trackPoint.setSensorDistance(cyclingDistanceSpeed.getValue().distance_overall_m);
|
||||||
|
trackPoint.setSpeed(cyclingDistanceSpeed.getValue().speed_mps);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cyclingPower != null && cyclingPower.hasValue()) {
|
if (cyclingPower != null && cyclingPower.hasValue()) {
|
||||||
@@ -66,12 +67,19 @@ public final class SensorDataSet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
if (heartRate != null) heartRate.reset();
|
||||||
|
if (cyclingCadence != null) cyclingCadence.reset();
|
||||||
|
if (cyclingDistanceSpeed != null) cyclingDistanceSpeed.reset();
|
||||||
|
if (cyclingPower != null) cyclingPower.reset();
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return (getHeartRate() != null ? "" + getHeartRate() : "")
|
return (getHeartRate() != null ? "" + getHeartRate() : "")
|
||||||
+ (getCyclingCadence() != null ? " " + getCyclingCadence() : "")
|
+ (getCyclingCadence() != null ? " " + getCyclingCadence() : "")
|
||||||
+ (getCyclingSpeed() != null ? " " + getCyclingSpeed() : "")
|
+ (getCyclingDistanceSpeed() != null ? " " + getCyclingDistanceSpeed() : "")
|
||||||
+ (getCyclingPower() != null ? " " + getCyclingPower() : "");
|
+ (getCyclingPower() != null ? " " + getCyclingPower() : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,8 +93,8 @@ public final class SensorDataSet {
|
|||||||
this.cyclingCadence = (SensorDataCycling.Cadence) data;
|
this.cyclingCadence = (SensorDataCycling.Cadence) data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type instanceof SensorDataCycling.Speed) {
|
if (type instanceof SensorDataCycling.DistanceSpeed) {
|
||||||
this.cyclingSpeed = (SensorDataCycling.Speed) data;
|
this.cyclingDistanceSpeed = (SensorDataCycling.DistanceSpeed) data;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,31 +65,28 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
|||||||
return chartFragment;
|
return chartFragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final List<ChartPoint> pendingPoints = new ArrayList<>();
|
private SharedPreferences sharedPreferences;
|
||||||
|
private int recordingDistanceInterval;
|
||||||
|
|
||||||
private TrackDataHub trackDataHub;
|
private TrackDataHub trackDataHub;
|
||||||
|
|
||||||
// Stats gathered from the received data
|
// Stats gathered from the received data
|
||||||
private TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater();
|
private TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater();
|
||||||
|
private final List<ChartPoint> pendingPoints = new ArrayList<>();
|
||||||
private ChartBinding viewBinding;
|
|
||||||
|
|
||||||
//TODO REMOVE: Used to restore the TrackStatistics via TrackStatisticsUpdater; for the diagrams we should consider not this setting and just use all data that is in the database
|
|
||||||
@Deprecated
|
|
||||||
private int recordingDistanceInterval;
|
|
||||||
private String category = "";
|
private String category = "";
|
||||||
|
|
||||||
// Modes of operation
|
// Modes of operation
|
||||||
private boolean chartByDistance;
|
private boolean chartByDistance;
|
||||||
|
|
||||||
|
private ChartBinding viewBinding;
|
||||||
// UI elements
|
// UI elements
|
||||||
private ChartView chartView;
|
private ChartView chartView;
|
||||||
|
|
||||||
private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
|
private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
if (PreferencesUtils.isKey(getContext(), R.string.stats_units_key, key)) {
|
if (PreferencesUtils.isKey(getContext(), R.string.stats_units_key, key)) {
|
||||||
boolean metricUnits = PreferencesUtils.isMetricUnits(getContext());
|
boolean metricUnits = PreferencesUtils.isMetricUnits(sharedPreferences, getContext());
|
||||||
if (metricUnits != chartView.getMetricUnits()) {
|
if (metricUnits != chartView.getMetricUnits()) {
|
||||||
chartView.setMetricUnits(metricUnits);
|
chartView.setMetricUnits(metricUnits);
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
@@ -100,7 +97,7 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (PreferencesUtils.isKey(getContext(), R.string.stats_rate_key, key)) {
|
if (PreferencesUtils.isKey(getContext(), R.string.stats_rate_key, key)) {
|
||||||
boolean reportSpeed = PreferencesUtils.isReportSpeed(getContext(), category);
|
boolean reportSpeed = PreferencesUtils.isReportSpeed(sharedPreferences, getContext(), category);
|
||||||
if (reportSpeed != chartView.getReportSpeed()) {
|
if (reportSpeed != chartView.getReportSpeed()) {
|
||||||
chartView.setReportSpeed(reportSpeed);
|
chartView.setReportSpeed(reportSpeed);
|
||||||
chartView.applyReportSpeed();
|
chartView.applyReportSpeed();
|
||||||
@@ -114,7 +111,7 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (PreferencesUtils.isKey(getContext(), R.string.recording_distance_interval_key, key)) {
|
if (PreferencesUtils.isKey(getContext(), R.string.recording_distance_interval_key, key)) {
|
||||||
recordingDistanceInterval = PreferencesUtils.getRecordingDistanceInterval(getContext());
|
recordingDistanceInterval = PreferencesUtils.getRecordingDistanceInterval(sharedPreferences, getContext());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -165,8 +162,9 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
|||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
resumeTrackDataHub();
|
resumeTrackDataHub();
|
||||||
PreferencesUtils.register(getContext(), sharedPreferenceChangeListener);
|
sharedPreferences = PreferencesUtils.getSharedPreferences(getContext());
|
||||||
sharedPreferenceChangeListener.onSharedPreferenceChanged(null, null);
|
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
||||||
|
sharedPreferenceChangeListener.onSharedPreferenceChanged(sharedPreferences, null);
|
||||||
|
|
||||||
checkChartSettings();
|
checkChartSettings();
|
||||||
getActivity().runOnUiThread(updateChart);
|
getActivity().runOnUiThread(updateChart);
|
||||||
@@ -176,7 +174,7 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
|||||||
public void onPause() {
|
public void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
pauseTrackDataHub();
|
pauseTrackDataHub();
|
||||||
PreferencesUtils.unregister(getContext(), sharedPreferenceChangeListener);
|
sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -192,6 +190,12 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
|||||||
viewBinding = null;
|
viewBinding = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
sharedPreferences = null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTrackUpdated(Track track) {
|
public void onTrackUpdated(Track track) {
|
||||||
if (isResumed()) {
|
if (isResumed()) {
|
||||||
@@ -201,7 +205,7 @@ public class ChartFragment extends Fragment implements TrackDataListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
category = track.getCategory();
|
category = track.getCategory();
|
||||||
boolean reportSpeed = PreferencesUtils.isReportSpeed(getContext(), category);
|
boolean reportSpeed = PreferencesUtils.isReportSpeed(PreferencesUtils.getSharedPreferences(getContext()), getContext(), category);
|
||||||
if (reportSpeed != chartView.getReportSpeed()) {
|
if (reportSpeed != chartView.getReportSpeed()) {
|
||||||
chartView.setReportSpeed(reportSpeed);
|
chartView.setReportSpeed(reportSpeed);
|
||||||
chartView.applyReportSpeed();
|
chartView.applyReportSpeed();
|
||||||
|
|||||||
@@ -44,14 +44,16 @@ public class IntervalsFragment extends Fragment implements TrackDataListener {
|
|||||||
private IntervalStatisticsAdapter adapter;
|
private IntervalStatisticsAdapter adapter;
|
||||||
private ArrayAdapter<IntervalStatisticsModel.IntervalOption> spinnerAdapter;
|
private ArrayAdapter<IntervalStatisticsModel.IntervalOption> spinnerAdapter;
|
||||||
|
|
||||||
|
private SharedPreferences sharedPreferences;
|
||||||
|
|
||||||
private TrackDataHub trackDataHub;
|
private TrackDataHub trackDataHub;
|
||||||
private String category;
|
private String category;
|
||||||
|
|
||||||
private IntervalListViewBinding viewBinding;
|
private IntervalListViewBinding viewBinding;
|
||||||
|
|
||||||
protected final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (preferences, key) -> {
|
protected final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (sharedPreferences, key) -> {
|
||||||
if (PreferencesUtils.isKey(getContext(), R.string.stats_units_key, key) || PreferencesUtils.isKey(getContext(), R.string.stats_rate_key, key)) {
|
if (PreferencesUtils.isKey(getContext(), R.string.stats_units_key, key) || PreferencesUtils.isKey(getContext(), R.string.stats_rate_key, key)) {
|
||||||
metricUnits = PreferencesUtils.isMetricUnits(getContext());
|
metricUnits = PreferencesUtils.isMetricUnits(sharedPreferences, getContext());
|
||||||
if (adapter != null) {
|
if (adapter != null) {
|
||||||
adapter.notifyDataSetChanged();
|
adapter.notifyDataSetChanged();
|
||||||
spinnerAdapter.notifyDataSetChanged();
|
spinnerAdapter.notifyDataSetChanged();
|
||||||
@@ -73,8 +75,9 @@ public class IntervalsFragment extends Fragment implements TrackDataListener {
|
|||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
|
||||||
PreferencesUtils.register(getContext(), sharedPreferenceChangeListener);
|
sharedPreferences = PreferencesUtils.getSharedPreferences(getContext());
|
||||||
metricUnits = PreferencesUtils.isMetricUnits(getContext());
|
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
||||||
|
sharedPreferenceChangeListener.onSharedPreferenceChanged(sharedPreferences, null);
|
||||||
|
|
||||||
viewBinding.intervalList.setEmptyView(viewBinding.intervalListEmptyView);
|
viewBinding.intervalList.setEmptyView(viewBinding.intervalListEmptyView);
|
||||||
|
|
||||||
@@ -125,6 +128,8 @@ public class IntervalsFragment extends Fragment implements TrackDataListener {
|
|||||||
public void onPause() {
|
public void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
pauseTrackDataHub();
|
pauseTrackDataHub();
|
||||||
|
|
||||||
|
sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -137,7 +142,7 @@ public class IntervalsFragment extends Fragment implements TrackDataListener {
|
|||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
|
||||||
PreferencesUtils.unregister(getContext(), sharedPreferenceChangeListener);
|
sharedPreferences = null;
|
||||||
|
|
||||||
adapter = null;
|
adapter = null;
|
||||||
viewModel = null;
|
viewModel = null;
|
||||||
@@ -183,7 +188,7 @@ public class IntervalsFragment extends Fragment implements TrackDataListener {
|
|||||||
category = track != null ? track.getCategory() : "";
|
category = track != null ? track.getCategory() : "";
|
||||||
|
|
||||||
// Set rate label.
|
// Set rate label.
|
||||||
boolean reportSpeed = PreferencesUtils.isReportSpeed(getContext(), category);
|
boolean reportSpeed = PreferencesUtils.isReportSpeed(sharedPreferences, getContext(), category); //TODO Handle sharedPreferenceChangeListener
|
||||||
viewBinding.intervalRate.setText(reportSpeed ? R.string.stats_speed : R.string.stats_pace);
|
viewBinding.intervalRate.setText(reportSpeed ? R.string.stats_speed : R.string.stats_pace);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.TrackRecordedActivity;
|
||||||
import de.dennisguse.opentracks.adapters.SensorsAdapter;
|
import de.dennisguse.opentracks.adapters.SensorsAdapter;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
@@ -64,7 +65,6 @@ public class StatisticsRecordedFragment extends Fragment {
|
|||||||
return fragment;
|
return fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private TrackStatistics trackStatistics;
|
private TrackStatistics trackStatistics;
|
||||||
private SensorStatistics sensorStatistics;
|
private SensorStatistics sensorStatistics;
|
||||||
private SensorsAdapter sensorsAdapter;
|
private SensorsAdapter sensorsAdapter;
|
||||||
@@ -152,26 +152,35 @@ public class StatisticsRecordedFragment extends Fragment {
|
|||||||
getActivity().runOnUiThread(() -> {
|
getActivity().runOnUiThread(() -> {
|
||||||
if (isResumed()) {
|
if (isResumed()) {
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
trackStatistics = track != null ? track.getTrackStatistics() : null;
|
trackStatistics = track.getTrackStatistics();
|
||||||
sensorStatistics = contentProviderUtils.getSensorStats(trackId);
|
sensorStatistics = contentProviderUtils.getSensorStats(trackId);
|
||||||
|
|
||||||
String newCategory = track != null ? track.getCategory() : "";
|
String newCategory = track.getCategory();
|
||||||
if (!category.equals(newCategory)) {
|
if (!category.equals(newCategory)) {
|
||||||
category = newCategory;
|
category = newCategory;
|
||||||
sharedPreferenceChangeListener.onSharedPreferenceChanged(sharedPreferences, getString(R.string.stats_rate_key));
|
sharedPreferenceChangeListener.onSharedPreferenceChanged(sharedPreferences, getString(R.string.stats_rate_key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadTrackDescription(track);
|
||||||
updateUI();
|
updateUI();
|
||||||
updateSensorUI();
|
updateSensorUI();
|
||||||
|
|
||||||
|
((TrackRecordedActivity) getActivity()).startPostponedEnterTransitionWith(viewBinding.statsActivityTypeIcon, viewBinding.statsNameValue);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadTrackDescription(@NonNull Track track) {
|
||||||
|
viewBinding.statsNameValue.setText(track.getName());
|
||||||
|
viewBinding.statsDescriptionValue.setText(track.getDescription());
|
||||||
|
viewBinding.statsStartDatetimeValue.setText(StringUtils.formatDateTime(getContext(), trackStatistics.getStartTime()));
|
||||||
|
}
|
||||||
|
|
||||||
private void updateUI() {
|
private void updateUI() {
|
||||||
// Set total distance
|
// Set total distance
|
||||||
{
|
{
|
||||||
double totalDistance = trackStatistics == null ? Double.NaN : trackStatistics.getTotalDistance();
|
double totalDistance = trackStatistics.getTotalDistance();
|
||||||
Pair<String, String> parts = StringUtils.getDistanceParts(getContext(), totalDistance, preferenceMetricUnits);
|
Pair<String, String> parts = StringUtils.getDistanceParts(getContext(), totalDistance, preferenceMetricUnits);
|
||||||
|
|
||||||
viewBinding.statsDistanceValue.setText(parts.first);
|
viewBinding.statsDistanceValue.setText(parts.first);
|
||||||
@@ -185,14 +194,14 @@ public class StatisticsRecordedFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set time and start datetime
|
// Set time and start datetime
|
||||||
if (trackStatistics != null) {
|
{
|
||||||
viewBinding.statsMovingTimeValue.setText(StringUtils.formatElapsedTime(trackStatistics.getMovingTime()));
|
viewBinding.statsMovingTimeValue.setText(StringUtils.formatElapsedTime(trackStatistics.getMovingTime()));
|
||||||
viewBinding.statsTotalTimeValue.setText(StringUtils.formatElapsedTime(trackStatistics.getTotalTime()));
|
viewBinding.statsTotalTimeValue.setText(StringUtils.formatElapsedTime(trackStatistics.getTotalTime()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set average speed/pace
|
// Set average speed/pace
|
||||||
{
|
{
|
||||||
double speed = trackStatistics != null ? trackStatistics.getAverageSpeed() : Double.NaN;
|
double speed = trackStatistics.getAverageSpeed();
|
||||||
viewBinding.statsAverageSpeedLabel.setText(preferenceReportSpeed ? R.string.stats_average_speed : R.string.stats_average_pace);
|
viewBinding.statsAverageSpeedLabel.setText(preferenceReportSpeed ? R.string.stats_average_speed : R.string.stats_average_pace);
|
||||||
|
|
||||||
Pair<String, String> parts = StringUtils.getSpeedParts(getContext(), speed, preferenceMetricUnits, preferenceReportSpeed);
|
Pair<String, String> parts = StringUtils.getSpeedParts(getContext(), speed, preferenceMetricUnits, preferenceReportSpeed);
|
||||||
@@ -202,7 +211,7 @@ public class StatisticsRecordedFragment extends Fragment {
|
|||||||
|
|
||||||
// Set max speed/pace
|
// Set max speed/pace
|
||||||
{
|
{
|
||||||
double speed = trackStatistics == null ? Double.NaN : trackStatistics.getMaxSpeed();
|
double speed = trackStatistics.getMaxSpeed();
|
||||||
|
|
||||||
viewBinding.statsMaxSpeedLabel.setText(preferenceReportSpeed ? R.string.stats_max_speed : R.string.stats_fastest_pace);
|
viewBinding.statsMaxSpeedLabel.setText(preferenceReportSpeed ? R.string.stats_max_speed : R.string.stats_fastest_pace);
|
||||||
|
|
||||||
@@ -213,7 +222,7 @@ public class StatisticsRecordedFragment extends Fragment {
|
|||||||
|
|
||||||
// Set moving speed/pace
|
// Set moving speed/pace
|
||||||
{
|
{
|
||||||
double speed = trackStatistics != null ? trackStatistics.getAverageMovingSpeed() : Double.NaN;
|
double speed = trackStatistics.getAverageMovingSpeed();
|
||||||
|
|
||||||
viewBinding.statsMovingSpeedLabel.setText(preferenceReportSpeed ? R.string.stats_average_moving_speed : R.string.stats_average_moving_pace);
|
viewBinding.statsMovingSpeedLabel.setText(preferenceReportSpeed ? R.string.stats_average_moving_speed : R.string.stats_average_moving_pace);
|
||||||
|
|
||||||
@@ -225,11 +234,11 @@ public class StatisticsRecordedFragment extends Fragment {
|
|||||||
// Set elevation gain and loss
|
// Set elevation gain and loss
|
||||||
{
|
{
|
||||||
// Make elevation visible?
|
// Make elevation visible?
|
||||||
boolean showElevation = PreferencesUtils.isShowStatsElevation(getContext());
|
boolean showElevation = PreferencesUtils.isShowStatsElevation(sharedPreferences, getContext());
|
||||||
viewBinding.statsElevationGroup.setVisibility(showElevation ? View.VISIBLE : View.GONE);
|
viewBinding.statsElevationGroup.setVisibility(showElevation ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
Float elevationGain_m = trackStatistics != null ? trackStatistics.getTotalElevationGain() : null;
|
Float elevationGain_m = trackStatistics.getTotalElevationGain();
|
||||||
Float elevationLoss_m = trackStatistics != null ? trackStatistics.getTotalElevationLoss() : null;
|
Float elevationLoss_m = trackStatistics.getTotalElevationLoss();
|
||||||
|
|
||||||
Pair<String, String> parts;
|
Pair<String, String> parts;
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
|
|||||||
private TrackRecordingServiceConnection trackRecordingServiceConnection = new TrackRecordingServiceConnection();
|
private TrackRecordingServiceConnection trackRecordingServiceConnection = new TrackRecordingServiceConnection();
|
||||||
private TrackPoint lastTrackPoint;
|
private TrackPoint lastTrackPoint;
|
||||||
|
|
||||||
|
//TODO Should not be nullable
|
||||||
private TrackStatistics lastTrackStatistics;
|
private TrackStatistics lastTrackStatistics;
|
||||||
|
|
||||||
private String category = "";
|
private String category = "";
|
||||||
@@ -366,29 +367,26 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setSpeedSensorData(SensorDataSet sensorDataSet) {
|
private void setSpeedSensorData(SensorDataSet sensorDataSet) {
|
||||||
if (sensorDataSet != null && sensorDataSet.getCyclingSpeed() != null) {
|
if (sensorDataSet != null && sensorDataSet.getCyclingDistanceSpeed() != null) {
|
||||||
SensorDataCycling.Speed data = sensorDataSet.getCyclingSpeed();
|
SensorDataCycling.DistanceSpeed data = sensorDataSet.getCyclingDistanceSpeed();
|
||||||
|
|
||||||
if (data.hasValue() && data.isRecent()) {
|
if (data.hasValue() && data.isRecent()) {
|
||||||
setSpeed(data.getValue());
|
setTotalDistance(data.getValue().distance_overall_m);
|
||||||
|
setSpeed(data.getValue().speed_mps);
|
||||||
|
}
|
||||||
|
if (data.hasValue() && data.isRecent()) {
|
||||||
|
setSpeed(data.getValue().speed_mps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateStats() {
|
private void updateStats() {
|
||||||
String trackIconValue = TrackIconUtils.getIconValue(getContext(), category);
|
|
||||||
|
|
||||||
// Set total distance
|
setTotalDistance(0);
|
||||||
{
|
|
||||||
double totalDistance = lastTrackStatistics == null ? Double.NaN : lastTrackStatistics.getTotalDistance();
|
|
||||||
Pair<String, String> parts = StringUtils.getDistanceParts(getContext(), totalDistance, preferenceMetricUnits);
|
|
||||||
|
|
||||||
viewBinding.statsDistanceValue.setText(parts.first);
|
|
||||||
viewBinding.statsDistanceUnit.setText(parts.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set activity type
|
// Set activity type
|
||||||
{
|
{
|
||||||
|
String trackIconValue = TrackIconUtils.getIconValue(getContext(), category);
|
||||||
viewBinding.statsActivityTypeIcon.setEnabled(isSelectedTrackRecording());
|
viewBinding.statsActivityTypeIcon.setEnabled(isSelectedTrackRecording());
|
||||||
viewBinding.statsActivityTypeIcon.setImageResource(TrackIconUtils.getIconDrawable(trackIconValue));
|
viewBinding.statsActivityTypeIcon.setImageResource(TrackIconUtils.getIconDrawable(trackIconValue));
|
||||||
}
|
}
|
||||||
@@ -479,6 +477,14 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setTotalDistance(double sensorDistanceSinceLastTrackpoint) {
|
||||||
|
double totalDistance = lastTrackStatistics != null ? (lastTrackStatistics.getTotalDistance() + sensorDistanceSinceLastTrackpoint) : Double.NaN;
|
||||||
|
Pair<String, String> parts = StringUtils.getDistanceParts(getContext(), totalDistance, preferenceMetricUnits);
|
||||||
|
|
||||||
|
viewBinding.statsDistanceValue.setText(parts.first);
|
||||||
|
viewBinding.statsDistanceUnit.setText(parts.second);
|
||||||
|
}
|
||||||
|
|
||||||
private void setSpeed(double speed) {
|
private void setSpeed(double speed) {
|
||||||
viewBinding.statsSpeedLabel.setText(preferenceReportSpeed ? R.string.stats_speed : R.string.stats_pace);
|
viewBinding.statsSpeedLabel.setText(preferenceReportSpeed ? R.string.stats_speed : R.string.stats_pace);
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
private ContentProviderUtils contentProviderUtils;
|
private ContentProviderUtils contentProviderUtils;
|
||||||
|
|
||||||
// List of tracks to be exported.
|
// List of tracks to be exported.
|
||||||
private final ArrayList<Track.Id> trackIds = new ArrayList<>();
|
private final ArrayList<Track> tracks = new ArrayList<>();
|
||||||
|
|
||||||
private final LinkedBlockingQueue<PendingConflict> conflictsQueue = new LinkedBlockingQueue<>();
|
private final LinkedBlockingQueue<PendingConflict> conflictsQueue = new LinkedBlockingQueue<>();
|
||||||
private final Handler conflictsHandler = new Handler();
|
private final Handler conflictsHandler = new Handler();
|
||||||
@@ -187,7 +187,7 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
conflictsQueue.clear();
|
conflictsQueue.clear();
|
||||||
trackIds.clear();
|
tracks.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -215,11 +215,11 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
for (int i = from; i < trackExportTotalCount; i++) {
|
for (int i = from; i < trackExportTotalCount; i++) {
|
||||||
cursor.moveToPosition(i);
|
cursor.moveToPosition(i);
|
||||||
Track track = ContentProviderUtils.createTrack(cursor);
|
Track track = ContentProviderUtils.createTrack(cursor);
|
||||||
trackIds.add(track.getId());
|
tracks.add(track);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!trackIds.isEmpty()) {
|
if (!tracks.isEmpty()) {
|
||||||
export(trackIds.get(0));
|
export(tracks.get(0));
|
||||||
} else {
|
} else {
|
||||||
onExportEnded();
|
onExportEnded();
|
||||||
}
|
}
|
||||||
@@ -227,26 +227,26 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enqueue track identified by trackId to be exported if not exported already or there is a conflict resolution.
|
* Enqueue track identified by UUID to be exported if not exported already or there is a conflict resolution.
|
||||||
*
|
*
|
||||||
* @param trackId the track's id.
|
* @param track Track object.
|
||||||
* @param conflictResolution conflict resolution to be applied if needed.
|
* @param conflictResolution conflict resolution to be applied if needed.
|
||||||
*/
|
*/
|
||||||
private void export(Track.Id trackId, int conflictResolution) {
|
private void export(Track track, int conflictResolution) {
|
||||||
boolean fileExists = ExportUtils.isExportFileExists(trackId, trackFileFormat.getExtension(), directoryFiles);
|
boolean fileExists = ExportUtils.isExportFileExists(track.getUuid(), trackFileFormat.getExtension(), directoryFiles);
|
||||||
|
|
||||||
if (fileExists && conflictResolution == CONFLICT_NONE) {
|
if (fileExists && conflictResolution == CONFLICT_NONE) {
|
||||||
conflict(trackId);
|
conflict(track);
|
||||||
} else if (fileExists && conflictResolution == CONFLICT_SKIP) {
|
} else if (fileExists && conflictResolution == CONFLICT_SKIP) {
|
||||||
trackExportSkippedCount++;
|
trackExportSkippedCount++;
|
||||||
onExportCompleted(trackId);
|
onExportCompleted(track);
|
||||||
} else {
|
} else {
|
||||||
ExportService.enqueue(this, resultReceiver, trackId, trackFileFormat, directoryUri);
|
ExportService.enqueue(this, resultReceiver, track.getId(), trackFileFormat, directoryUri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void export(Track.Id trackId) {
|
private void export(Track track) {
|
||||||
export(trackId, autoConflict);
|
export(track, autoConflict);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setConflictVisibility(int visibility) {
|
private void setConflictVisibility(int visibility) {
|
||||||
@@ -278,14 +278,15 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
viewBinding.exportProgressSummaryErrorsGroup.setVisibility(trackExportErrorCount > 0 ? View.VISIBLE : View.GONE);
|
viewBinding.exportProgressSummaryErrorsGroup.setVisibility(trackExportErrorCount > 0 ? View.VISIBLE : View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onExportCompleted(Track.Id trackId) {
|
private void onExportCompleted(Track track) {
|
||||||
trackIds.remove(trackId);
|
tracks.remove(track);
|
||||||
|
|
||||||
setProgress();
|
setProgress();
|
||||||
if (trackIds.isEmpty()) {
|
if (tracks.isEmpty()) {
|
||||||
onExportEnded();
|
onExportEnded();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
export(trackIds.get(0));
|
export(tracks.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onExportEnded() {
|
private void onExportEnded() {
|
||||||
@@ -317,15 +318,15 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
}
|
}
|
||||||
|
|
||||||
Track.Id trackId = resultData.getParcelable(ExportServiceResultReceiver.RESULT_EXTRA_TRACK_ID);
|
Track.Id trackId = resultData.getParcelable(ExportServiceResultReceiver.RESULT_EXTRA_TRACK_ID);
|
||||||
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
|
|
||||||
switch (resultCode) {
|
switch (resultCode) {
|
||||||
case ExportServiceResultReceiver.RESULT_CODE_ERROR:
|
case ExportServiceResultReceiver.RESULT_CODE_ERROR:
|
||||||
trackExportErrorCount++;
|
trackExportErrorCount++;
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
|
||||||
trackErrors.add(track.getName());
|
trackErrors.add(track.getName());
|
||||||
break;
|
break;
|
||||||
case ExportServiceResultReceiver.RESULT_CODE_SUCCESS:
|
case ExportServiceResultReceiver.RESULT_CODE_SUCCESS:
|
||||||
if (ExportUtils.isExportFileExists(trackId, trackFileFormat.getExtension(), directoryFiles)) {
|
if (ExportUtils.isExportFileExists(track.getUuid(), trackFileFormat.getExtension(), directoryFiles)) {
|
||||||
trackExportOverwrittenCount++;
|
trackExportOverwrittenCount++;
|
||||||
} else {
|
} else {
|
||||||
trackExportSuccessCount++;
|
trackExportSuccessCount++;
|
||||||
@@ -335,11 +336,11 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
throw new RuntimeException(TAG + ": export service result code invalid: " + resultCode);
|
throw new RuntimeException(TAG + ": export service result code invalid: " + resultCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
onExportCompleted(trackId);
|
onExportCompleted(track);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void conflict(Track.Id trackId) {
|
private void conflict(Track track) {
|
||||||
PendingConflict newConflict = new PendingConflict(trackId);
|
PendingConflict newConflict = new PendingConflict(track);
|
||||||
conflictsQueue.add(newConflict);
|
conflictsQueue.add(newConflict);
|
||||||
|
|
||||||
if (conflictsQueue.size() == 1) {
|
if (conflictsQueue.size() == 1) {
|
||||||
@@ -351,10 +352,10 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
* Handle conflicts (exporting file already exists).
|
* Handle conflicts (exporting file already exists).
|
||||||
*/
|
*/
|
||||||
private class PendingConflict {
|
private class PendingConflict {
|
||||||
private final Track.Id trackId;
|
private final Track track;
|
||||||
|
|
||||||
public PendingConflict(Track.Id trackId) {
|
public PendingConflict(Track track) {
|
||||||
this.trackId = trackId;
|
this.track = track;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -365,14 +366,13 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
*/
|
*/
|
||||||
public boolean resolve() {
|
public boolean resolve() {
|
||||||
if (autoConflict == CONFLICT_NONE) {
|
if (autoConflict == CONFLICT_NONE) {
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
|
||||||
viewBinding.exportProgressAlertIcon.setImageDrawable(ContextCompat.getDrawable(ExportActivity.this, R.drawable.ic_report_problem_24));
|
viewBinding.exportProgressAlertIcon.setImageDrawable(ContextCompat.getDrawable(ExportActivity.this, R.drawable.ic_report_problem_24));
|
||||||
viewBinding.exportProgressAlertMsg.setText(getString(R.string.export_track_already_exists_msg, track.getName()));
|
viewBinding.exportProgressAlertMsg.setText(getString(R.string.export_track_already_exists_msg, track.getName()));
|
||||||
setConflictVisibility(View.VISIBLE);
|
setConflictVisibility(View.VISIBLE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export(trackId);
|
export(track);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,7 +380,7 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
* Overwrite the export file and set the autoConflict if user set the "do it for all" switch button.
|
* Overwrite the export file and set the autoConflict if user set the "do it for all" switch button.
|
||||||
*/
|
*/
|
||||||
public void overwrite() {
|
public void overwrite() {
|
||||||
export(trackId, CONFLICT_OVERWRITE);
|
export(track, CONFLICT_OVERWRITE);
|
||||||
|
|
||||||
if (viewBinding.exportProgressApplyToAll.isChecked()) {
|
if (viewBinding.exportProgressApplyToAll.isChecked()) {
|
||||||
autoConflict = CONFLICT_OVERWRITE;
|
autoConflict = CONFLICT_OVERWRITE;
|
||||||
@@ -391,7 +391,7 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
|
|||||||
* Skip the export file and set the autoConflict if user set the "do it for all" switch button.
|
* Skip the export file and set the autoConflict if user set the "do it for all" switch button.
|
||||||
*/
|
*/
|
||||||
public void skip() {
|
public void skip() {
|
||||||
export(trackId, CONFLICT_SKIP);
|
export(track, CONFLICT_SKIP);
|
||||||
|
|
||||||
if (viewBinding.exportProgressApplyToAll.isChecked()) {
|
if (viewBinding.exportProgressApplyToAll.isChecked()) {
|
||||||
autoConflict = CONFLICT_SKIP;
|
autoConflict = CONFLICT_SKIP;
|
||||||
|
|||||||
@@ -49,8 +49,10 @@ public class GPXTrackExporter implements TrackExporter {
|
|||||||
private static final NumberFormat ELEVATION_FORMAT = NumberFormat.getInstance(Locale.US);
|
private static final NumberFormat ELEVATION_FORMAT = NumberFormat.getInstance(Locale.US);
|
||||||
private static final NumberFormat COORDINATE_FORMAT = NumberFormat.getInstance(Locale.US);
|
private static final NumberFormat COORDINATE_FORMAT = NumberFormat.getInstance(Locale.US);
|
||||||
private static final NumberFormat SPEED_FORMAT = NumberFormat.getInstance(Locale.US);
|
private static final NumberFormat SPEED_FORMAT = NumberFormat.getInstance(Locale.US);
|
||||||
|
private static final NumberFormat DISTANCE_FORMAT = NumberFormat.getInstance(Locale.US);
|
||||||
private static final NumberFormat HEARTRATE_FORMAT = NumberFormat.getInstance(Locale.US);
|
private static final NumberFormat HEARTRATE_FORMAT = NumberFormat.getInstance(Locale.US);
|
||||||
private static final NumberFormat CADENCE_FORMAT = NumberFormat.getInstance(Locale.US);
|
private static final NumberFormat CADENCE_FORMAT = NumberFormat.getInstance(Locale.US);
|
||||||
|
private static final NumberFormat POWER_FORMAT = NumberFormat.getInstance(Locale.US);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
/*
|
/*
|
||||||
@@ -72,6 +74,9 @@ public class GPXTrackExporter implements TrackExporter {
|
|||||||
|
|
||||||
CADENCE_FORMAT.setMaximumFractionDigits(0);
|
CADENCE_FORMAT.setMaximumFractionDigits(0);
|
||||||
CADENCE_FORMAT.setGroupingUsed(false);
|
CADENCE_FORMAT.setGroupingUsed(false);
|
||||||
|
|
||||||
|
POWER_FORMAT.setMaximumFractionDigits(0);
|
||||||
|
POWER_FORMAT.setGroupingUsed(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ContentProviderUtils contentProviderUtils;
|
private final ContentProviderUtils contentProviderUtils;
|
||||||
@@ -91,15 +96,16 @@ public class GPXTrackExporter implements TrackExporter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean writeTrack(Track[] tracks, @NonNull OutputStream outputStream) {
|
public boolean writeTrack(Track[] tracks, @NonNull OutputStream outputStream) {
|
||||||
Track mainTrack = tracks[0];
|
|
||||||
try {
|
try {
|
||||||
prepare(outputStream);
|
prepare(outputStream);
|
||||||
writeHeader(mainTrack);
|
writeHeader();
|
||||||
|
|
||||||
writeMarkers(mainTrack);
|
|
||||||
|
|
||||||
for (Track track : tracks) {
|
for (Track track : tracks) {
|
||||||
writeLocations(track);
|
writeMarkers(track);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Track track : tracks) {
|
||||||
|
writeTrackPoints(track);
|
||||||
}
|
}
|
||||||
|
|
||||||
writeFooter();
|
writeFooter();
|
||||||
@@ -112,7 +118,7 @@ public class GPXTrackExporter implements TrackExporter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeLocations(Track track) throws InterruptedException {
|
private void writeTrackPoints(Track track) throws InterruptedException {
|
||||||
boolean wroteTrack = false;
|
boolean wroteTrack = false;
|
||||||
boolean wroteSegment = false;
|
boolean wroteSegment = false;
|
||||||
|
|
||||||
@@ -183,7 +189,7 @@ public class GPXTrackExporter implements TrackExporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void writeHeader(Track track) {
|
public void writeHeader() {
|
||||||
if (printWriter != null) {
|
if (printWriter != null) {
|
||||||
printWriter.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
printWriter.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||||
printWriter.println("<gpx");
|
printWriter.println("<gpx");
|
||||||
@@ -195,17 +201,13 @@ public class GPXTrackExporter implements TrackExporter {
|
|||||||
printWriter.println("xmlns:atom=\"http://www.w3.org/2005/Atom\"");
|
printWriter.println("xmlns:atom=\"http://www.w3.org/2005/Atom\"");
|
||||||
printWriter.println("xmlns:opentracks=\"http://opentracksapp.com/xmlschemas/v1\"");
|
printWriter.println("xmlns:opentracks=\"http://opentracksapp.com/xmlschemas/v1\"");
|
||||||
printWriter.println("xmlns:gpxtpx=\"http://www.garmin.com/xmlschemes/TrackPointExtension/v2\"");
|
printWriter.println("xmlns:gpxtpx=\"http://www.garmin.com/xmlschemes/TrackPointExtension/v2\"");
|
||||||
|
printWriter.println("xmlns:pwr=\"http://www.garmin.com/xmlschemas/PowerExtension/v1\"");
|
||||||
printWriter.println("xsi:schemaLocation=" +
|
printWriter.println("xsi:schemaLocation=" +
|
||||||
"\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"
|
"\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"
|
||||||
+ " http://www.topografix.com/GPX/Private/TopoGrafix/0/1 http://www.topografix.com/GPX/Private/TopoGrafix/0/1/topografix.xsd"
|
+ " http://www.topografix.com/GPX/Private/TopoGrafix/0/1 http://www.topografix.com/GPX/Private/TopoGrafix/0/1/topografix.xsd"
|
||||||
+ " http://www.garmin.com/xmlschemas/TrackPointExtension/v2 https://www8.garmin.com/xmlschemas/TrackPointExtensionv2.xsd"
|
+ " http://www.garmin.com/xmlschemas/TrackPointExtension/v2 https://www8.garmin.com/xmlschemas/TrackPointExtensionv2.xsd"
|
||||||
|
+ " http://www.garmin.com/xmlschemas/PowerExtension/v1 https://www8.garmin.com/xmlschemas/PowerExtensionv1.xsd"
|
||||||
+ " http://opentracksapp.com/xmlschemas/v1 http://opentracksapp.com/xmlschemas/OpenTracks_v1.xsd\">");
|
+ " http://opentracksapp.com/xmlschemas/v1 http://opentracksapp.com/xmlschemas/OpenTracks_v1.xsd\">");
|
||||||
|
|
||||||
printWriter.println("<metadata>");
|
|
||||||
|
|
||||||
printWriter.println("<name>" + StringUtils.formatCData(track.getName()) + "</name>");
|
|
||||||
printWriter.println("<desc>" + StringUtils.formatCData(track.getDescription()) + "</desc>");
|
|
||||||
printWriter.println("</metadata>");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,6 +301,10 @@ public class GPXTrackExporter implements TrackExporter {
|
|||||||
printWriter.println("<gpxtpx:cad>" + CADENCE_FORMAT.format(trackPoint.getCyclingCadence_rpm()) + "</gpxtpx:cad>");
|
printWriter.println("<gpxtpx:cad>" + CADENCE_FORMAT.format(trackPoint.getCyclingCadence_rpm()) + "</gpxtpx:cad>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (trackPoint.hasPower()) {
|
||||||
|
printWriter.println("<pwr:PowerInWatts>" + POWER_FORMAT.format(trackPoint.getPower()) + "</pwr:PowerInWatts>");
|
||||||
|
}
|
||||||
|
|
||||||
if (trackPoint.hasElevationGain()) {
|
if (trackPoint.hasElevationGain()) {
|
||||||
printWriter.println("<opentracks:gain>" + ELEVATION_FORMAT.format(trackPoint.getElevationGain()) + "</opentracks:gain>");
|
printWriter.println("<opentracks:gain>" + ELEVATION_FORMAT.format(trackPoint.getElevationGain()) + "</opentracks:gain>");
|
||||||
}
|
}
|
||||||
@@ -307,6 +313,10 @@ public class GPXTrackExporter implements TrackExporter {
|
|||||||
printWriter.println("<opentracks:loss>" + ELEVATION_FORMAT.format(trackPoint.getElevationLoss()) + "</opentracks:loss>");
|
printWriter.println("<opentracks:loss>" + ELEVATION_FORMAT.format(trackPoint.getElevationLoss()) + "</opentracks:loss>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (trackPoint.hasSensorDistance()) {
|
||||||
|
printWriter.println("<opentracks:distance>" + DISTANCE_FORMAT.format(trackPoint.getElevationLoss()) + "</opentracks:distance>");
|
||||||
|
}
|
||||||
|
|
||||||
printWriter.println("</gpxtpx:TrackPointExtension></extensions>");
|
printWriter.println("</gpxtpx:TrackPointExtension></extensions>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ public class KMLTrackExporter implements TrackExporter {
|
|||||||
private static final String SCHEMA_ID = "schema";
|
private static final String SCHEMA_ID = "schema";
|
||||||
|
|
||||||
public static final String EXTENDED_DATA_TYPE_SPEED = "speed";
|
public static final String EXTENDED_DATA_TYPE_SPEED = "speed";
|
||||||
|
public static final String EXTENDED_DATA_TYPE_DISTANCE = "distance";
|
||||||
public static final String EXTENDED_DATA_TYPE_CADENCE = "cadence";
|
public static final String EXTENDED_DATA_TYPE_CADENCE = "cadence";
|
||||||
public static final String EXTENDED_DATA_TYPE_HEART_RATE = "heart_rate";
|
public static final String EXTENDED_DATA_TYPE_HEART_RATE = "heart_rate";
|
||||||
public static final String EXTENDED_DATA_TYPE_POWER = "power";
|
public static final String EXTENDED_DATA_TYPE_POWER = "power";
|
||||||
@@ -74,6 +75,7 @@ public class KMLTrackExporter implements TrackExporter {
|
|||||||
|
|
||||||
private PrintWriter printWriter;
|
private PrintWriter printWriter;
|
||||||
private final List<Float> speedList = new ArrayList<>();
|
private final List<Float> speedList = new ArrayList<>();
|
||||||
|
private final List<Float> distanceList = new ArrayList<>();
|
||||||
private final List<Float> powerList = new ArrayList<>();
|
private final List<Float> powerList = new ArrayList<>();
|
||||||
private final List<Float> cadenceList = new ArrayList<>();
|
private final List<Float> cadenceList = new ArrayList<>();
|
||||||
private final List<Float> heartRateList = new ArrayList<>();
|
private final List<Float> heartRateList = new ArrayList<>();
|
||||||
@@ -338,6 +340,7 @@ public class KMLTrackExporter implements TrackExporter {
|
|||||||
if (printWriter != null) {
|
if (printWriter != null) {
|
||||||
printWriter.println("<gx:Track>");
|
printWriter.println("<gx:Track>");
|
||||||
speedList.clear();
|
speedList.clear();
|
||||||
|
distanceList.clear();
|
||||||
powerList.clear();
|
powerList.clear();
|
||||||
cadenceList.clear();
|
cadenceList.clear();
|
||||||
heartRateList.clear();
|
heartRateList.clear();
|
||||||
@@ -355,6 +358,9 @@ public class KMLTrackExporter implements TrackExporter {
|
|||||||
writeSimpleArrayData(speedList, EXTENDED_DATA_TYPE_SPEED);
|
writeSimpleArrayData(speedList, EXTENDED_DATA_TYPE_SPEED);
|
||||||
}
|
}
|
||||||
if (exportSensorData) {
|
if (exportSensorData) {
|
||||||
|
if (distanceList.stream().anyMatch(Objects::nonNull)) {
|
||||||
|
writeSimpleArrayData(distanceList, EXTENDED_DATA_TYPE_DISTANCE);
|
||||||
|
}
|
||||||
if (powerList.stream().anyMatch(Objects::nonNull)) {
|
if (powerList.stream().anyMatch(Objects::nonNull)) {
|
||||||
writeSimpleArrayData(powerList, EXTENDED_DATA_TYPE_POWER);
|
writeSimpleArrayData(powerList, EXTENDED_DATA_TYPE_POWER);
|
||||||
}
|
}
|
||||||
@@ -392,6 +398,7 @@ public class KMLTrackExporter implements TrackExporter {
|
|||||||
speedList.add(trackPoint.hasSpeed() ? trackPoint.getSpeed() : null);
|
speedList.add(trackPoint.hasSpeed() ? trackPoint.getSpeed() : null);
|
||||||
|
|
||||||
if (exportSensorData) {
|
if (exportSensorData) {
|
||||||
|
distanceList.add(trackPoint.hasSensorDistance() ? trackPoint.getSensorDistance() : null);
|
||||||
heartRateList.add(trackPoint.hasHeartRate() ? trackPoint.getHeartRate_bpm() : null);
|
heartRateList.add(trackPoint.hasHeartRate() ? trackPoint.getHeartRate_bpm() : null);
|
||||||
cadenceList.add(trackPoint.hasCyclingCadence() ? trackPoint.getCyclingCadence_rpm() : null);
|
cadenceList.add(trackPoint.hasCyclingCadence() ? trackPoint.getCyclingCadence_rpm() : null);
|
||||||
powerList.add(trackPoint.hasPower() ? trackPoint.getPower() : null);
|
powerList.add(trackPoint.hasPower() ? trackPoint.getPower() : null);
|
||||||
|
|||||||
+28
-10
@@ -17,6 +17,7 @@
|
|||||||
package de.dennisguse.opentracks.io.file.importer;
|
package de.dennisguse.opentracks.io.file.importer;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.database.sqlite.SQLiteConstraintException;
|
import android.database.sqlite.SQLiteConstraintException;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -90,6 +91,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
protected String uuid;
|
protected String uuid;
|
||||||
protected String gain;
|
protected String gain;
|
||||||
protected String loss;
|
protected String loss;
|
||||||
|
protected String distance;
|
||||||
|
|
||||||
// The current track data
|
// The current track data
|
||||||
private TrackData trackData;
|
private TrackData trackData;
|
||||||
@@ -97,10 +99,13 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
// The SAX locator to get the current line information
|
// The SAX locator to get the current line information
|
||||||
private Locator locator;
|
private Locator locator;
|
||||||
|
|
||||||
|
private final SharedPreferences sharedPreferences;
|
||||||
|
|
||||||
AbstractFileTrackImporter(Context context, ContentProviderUtils contentProviderUtils) {
|
AbstractFileTrackImporter(Context context, ContentProviderUtils contentProviderUtils) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.contentProviderUtils = contentProviderUtils;
|
this.contentProviderUtils = contentProviderUtils;
|
||||||
this.recordingDistanceInterval = PreferencesUtils.getRecordingDistanceInterval(context);
|
sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||||
|
this.recordingDistanceInterval = PreferencesUtils.getRecordingDistanceInterval(sharedPreferences, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -120,10 +125,11 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Track.Id importFile(InputStream inputStream) {
|
@NonNull
|
||||||
|
public List<Track.Id> importFile(InputStream inputStream) {
|
||||||
try {
|
try {
|
||||||
SAXParserFactory.newInstance().newSAXParser().parse(inputStream, this);
|
SAXParserFactory.newInstance().newSAXParser().parse(inputStream, this);
|
||||||
return trackIds.get(0);
|
return trackIds;
|
||||||
} catch (IOException | SAXException | ParserConfigurationException | ParsingException e) {
|
} catch (IOException | SAXException | ParserConfigurationException | ParsingException e) {
|
||||||
Log.e(TAG, "Unable to import file", e);
|
Log.e(TAG, "Unable to import file", e);
|
||||||
if (trackIds.size() > 0) {
|
if (trackIds.size() > 0) {
|
||||||
@@ -136,9 +142,6 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* On file end.
|
|
||||||
*/
|
|
||||||
protected void onFileEnd() {
|
protected void onFileEnd() {
|
||||||
// Add markers to the last imported track
|
// Add markers to the last imported track
|
||||||
int size = trackIds.size();
|
int size = trackIds.size();
|
||||||
@@ -261,7 +264,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
|
|
||||||
Track track = contentProviderUtils.getTrack(trackData.track.getUuid());
|
Track track = contentProviderUtils.getTrack(trackData.track.getUuid());
|
||||||
if (track != null) {
|
if (track != null) {
|
||||||
if (PreferencesUtils.getPreventReimportTracks(context)) {
|
if (PreferencesUtils.getPreventReimportTracks(sharedPreferences, context)) {
|
||||||
throw new ImportAlreadyExistsException(context.getString(R.string.import_prevent_reimport));
|
throw new ImportAlreadyExistsException(context.getString(R.string.import_prevent_reimport));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,7 +374,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
* GPS points tend to have some inherent imprecision, speed and bearing will likely be off, so the statistics for things like max speed will also be off.
|
* GPS points tend to have some inherent imprecision, speed and bearing will likely be off, so the statistics for things like max speed will also be off.
|
||||||
*/
|
*/
|
||||||
if (trackPoint.hasLocation() && trackData.lastLocationInCurrentSegment.hasLocation()) {
|
if (trackPoint.hasLocation() && trackData.lastLocationInCurrentSegment.hasLocation()) {
|
||||||
float speed = trackData.lastLocationInCurrentSegment.distanceTo(trackPoint) / timeDifference.toMillis();
|
float speed = trackData.lastLocationInCurrentSegment.distanceToPrevious(trackPoint) / timeDifference.toMillis();
|
||||||
trackPoint.setSpeed(speed);
|
trackPoint.setSpeed(speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -379,8 +382,8 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
if (trackPoint.hasLocation() && trackData.lastLocationInCurrentSegment.hasLocation()) {
|
if (trackPoint.hasLocation() && trackData.lastLocationInCurrentSegment.hasLocation()) {
|
||||||
trackPoint.setBearing(trackData.lastLocationInCurrentSegment.bearingTo(trackPoint));
|
trackPoint.setBearing(trackData.lastLocationInCurrentSegment.bearingTo(trackPoint));
|
||||||
|
|
||||||
long maxRecordingDistance = PreferencesUtils.getMaxRecordingDistance(context);
|
long maxRecordingDistance = PreferencesUtils.getMaxRecordingDistance(sharedPreferences, context); //TODO Should only be read once!
|
||||||
double distanceToLastTrackLocation = trackPoint.distanceTo(trackData.lastLocationInCurrentSegment);
|
double distanceToLastTrackLocation = trackPoint.distanceToPrevious(trackData.lastLocationInCurrentSegment);
|
||||||
if (distanceToLastTrackLocation > maxRecordingDistance) {
|
if (distanceToLastTrackLocation > maxRecordingDistance) {
|
||||||
trackPoint.setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC);
|
trackPoint.setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC);
|
||||||
}
|
}
|
||||||
@@ -478,6 +481,14 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (power != null) {
|
||||||
|
try {
|
||||||
|
trackPoint.setPower(Float.parseFloat(power));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ParsingException(createErrorMessage(String.format(Locale.US, "Unable to parse power: %s", power)), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (gain != null) {
|
if (gain != null) {
|
||||||
try {
|
try {
|
||||||
trackPoint.setElevationGain(Float.parseFloat(gain));
|
trackPoint.setElevationGain(Float.parseFloat(gain));
|
||||||
@@ -492,6 +503,13 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
|
|||||||
throw new ParsingException(createErrorMessage(String.format(Locale.US, "Unable to parse elevation loss: %s", loss)), e);
|
throw new ParsingException(createErrorMessage(String.format(Locale.US, "Unable to parse elevation loss: %s", loss)), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (distance != null) {
|
||||||
|
try {
|
||||||
|
trackPoint.setSensorDistance(Float.parseFloat(distance));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ParsingException(createErrorMessage(String.format(Locale.US, "Unable to parse distance: %s", distance)), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return trackPoint;
|
return trackPoint;
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-6
@@ -2,6 +2,7 @@ package de.dennisguse.opentracks.io.file.importer;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.provider.DocumentsContract;
|
import android.provider.DocumentsContract;
|
||||||
@@ -18,10 +19,14 @@ public abstract class DirectoryChooserActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
private static final int DIRECTORY_PICKER_REQUEST_CODE = 6;
|
private static final int DIRECTORY_PICKER_REQUEST_CODE = 6;
|
||||||
|
|
||||||
|
protected SharedPreferences sharedPreferences;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
sharedPreferences = PreferencesUtils.getSharedPreferences(this);
|
||||||
|
|
||||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||||
DocumentFile directoryUri = configureDirectoryChooserIntent(intent);
|
DocumentFile directoryUri = configureDirectoryChooserIntent(intent);
|
||||||
if (directoryUri == null) {
|
if (directoryUri == null) {
|
||||||
@@ -38,6 +43,12 @@ public abstract class DirectoryChooserActivity extends AppCompatActivity {
|
|||||||
onActivityResultCustom(requestCode, resultCode, resultData);
|
onActivityResultCustom(requestCode, resultCode, resultData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
sharedPreferences = null;
|
||||||
|
}
|
||||||
|
|
||||||
protected void onActivityResultCustom(int requestCode, int resultCode, @Nullable Intent resultData) {
|
protected void onActivityResultCustom(int requestCode, int resultCode, @Nullable Intent resultData) {
|
||||||
if (requestCode == DIRECTORY_PICKER_REQUEST_CODE) {
|
if (requestCode == DIRECTORY_PICKER_REQUEST_CODE) {
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
@@ -80,14 +91,14 @@ public abstract class DirectoryChooserActivity extends AppCompatActivity {
|
|||||||
super.configureDirectoryChooserIntent(intent);
|
super.configureDirectoryChooserIntent(intent);
|
||||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
|
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
|
||||||
|
|
||||||
return PreferencesUtils.getDefaultExportDirectoryUri(this);
|
return PreferencesUtils.getDefaultExportDirectoryUri(sharedPreferences, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Intent createNextActivityIntent(Uri directoryUri) {
|
protected Intent createNextActivityIntent(Uri directoryUri) {
|
||||||
Intent intent = IntentUtils.newIntent(this, ExportActivity.class);
|
Intent intent = IntentUtils.newIntent(this, ExportActivity.class);
|
||||||
intent.putExtra(ExportActivity.EXTRA_DIRECTORY_URI_KEY, directoryUri);
|
intent.putExtra(ExportActivity.EXTRA_DIRECTORY_URI_KEY, directoryUri);
|
||||||
intent.putExtra(ExportActivity.EXTRA_TRACKFILEFORMAT_KEY, PreferencesUtils.getExportTrackFileFormat(this));
|
intent.putExtra(ExportActivity.EXTRA_TRACKFILEFORMAT_KEY, PreferencesUtils.getExportTrackFileFormat(sharedPreferences, this));
|
||||||
return intent;
|
return intent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -101,11 +112,11 @@ public abstract class DirectoryChooserActivity extends AppCompatActivity {
|
|||||||
case RESULT_OK:
|
case RESULT_OK:
|
||||||
Uri directoryUri = resultData.getData();
|
Uri directoryUri = resultData.getData();
|
||||||
|
|
||||||
PreferencesUtils.setDefaultExportDirectoryUri(this, directoryUri);
|
PreferencesUtils.setDefaultExportDirectoryUri(sharedPreferences, this, directoryUri);
|
||||||
IntentUtils.persistDirectoryAccessPermission(getApplicationContext(), resultData, directoryUri);
|
IntentUtils.persistDirectoryAccessPermission(getApplicationContext(), resultData, directoryUri);
|
||||||
break;
|
break;
|
||||||
case RESULT_CANCELED:
|
case RESULT_CANCELED:
|
||||||
PreferencesUtils.setDefaultExportDirectoryUri(this, null);
|
PreferencesUtils.setDefaultExportDirectoryUri(sharedPreferences, this, null);
|
||||||
//TODO Remove stored permission contentResolver.releasePersistableUriPermission
|
//TODO Remove stored permission contentResolver.releasePersistableUriPermission
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -118,8 +129,8 @@ public abstract class DirectoryChooserActivity extends AppCompatActivity {
|
|||||||
protected DocumentFile configureDirectoryChooserIntent(Intent intent) {
|
protected DocumentFile configureDirectoryChooserIntent(Intent intent) {
|
||||||
super.configureDirectoryChooserIntent(intent);
|
super.configureDirectoryChooserIntent(intent);
|
||||||
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||||
if (PreferencesUtils.isDefaultExportDirectoryUri(this)) {
|
if (PreferencesUtils.isDefaultExportDirectoryUri(sharedPreferences, this)) {
|
||||||
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, PreferencesUtils.getDefaultExportDirectoryUri(this).getUri());
|
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, PreferencesUtils.getDefaultExportDirectoryUri(sharedPreferences, this).getUri());
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,9 @@ import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Imports a GPX file.
|
* Imports a GPX file.
|
||||||
* Uses https://www8.garmin.com/xmlschemas/TrackPointExtensionv2.xsd
|
* Uses:
|
||||||
|
* * https://www8.garmin.com/xmlschemas/TrackPointExtensionv2.xsd
|
||||||
|
* * https://www8.garmin.com/xmlschemas/PowerExtensionv1.xsd
|
||||||
* <p>
|
* <p>
|
||||||
* {@link de.dennisguse.opentracks.io.file.exporter.GPXTrackExporter} does not export information if a segment was started automatic or manually.
|
* {@link de.dennisguse.opentracks.io.file.exporter.GPXTrackExporter} does not export information if a segment was started automatic or manually.
|
||||||
* Therefore, all segments starts are marked as SEGMENT_START_AUTOMATIC.
|
* Therefore, all segments starts are marked as SEGMENT_START_AUTOMATIC.
|
||||||
@@ -57,9 +59,11 @@ public class GpxFileTrackImporter extends AbstractFileTrackImporter {
|
|||||||
private static final String TAG_EXTENSION_SPEED = "gpxtpx:speed";
|
private static final String TAG_EXTENSION_SPEED = "gpxtpx:speed";
|
||||||
private static final String TAG_EXTENSION_HEARTRATE = "gpxtpx:hr";
|
private static final String TAG_EXTENSION_HEARTRATE = "gpxtpx:hr";
|
||||||
private static final String TAG_EXTENSION_CADENCE = "gpxtpx:cad";
|
private static final String TAG_EXTENSION_CADENCE = "gpxtpx:cad";
|
||||||
|
private static final String TAG_EXTENSION_POWER = "pwr:PowerInWatts";
|
||||||
|
|
||||||
private static final String TAG_EXTENSION_GAIN = "opentracks:gain";
|
private static final String TAG_EXTENSION_GAIN = "opentracks:gain";
|
||||||
private static final String TAG_EXTENSION_LOSS = "opentracks:loss";
|
private static final String TAG_EXTENSION_LOSS = "opentracks:loss";
|
||||||
|
private static final String TAG_EXTENSION_DISTANCE = "opentracks:distance";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
@@ -156,6 +160,11 @@ public class GpxFileTrackImporter extends AbstractFileTrackImporter {
|
|||||||
cadence = content.trim();
|
cadence = content.trim();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case TAG_EXTENSION_POWER:
|
||||||
|
if (content != null) {
|
||||||
|
power = content.trim();
|
||||||
|
}
|
||||||
|
break;
|
||||||
case TAG_ID:
|
case TAG_ID:
|
||||||
if (content != null) {
|
if (content != null) {
|
||||||
uuid = content.trim();
|
uuid = content.trim();
|
||||||
@@ -171,6 +180,11 @@ public class GpxFileTrackImporter extends AbstractFileTrackImporter {
|
|||||||
loss = content.trim();
|
loss = content.trim();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case TAG_EXTENSION_DISTANCE:
|
||||||
|
if (content != null) {
|
||||||
|
distance = content.trim();
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset element content
|
// Reset element content
|
||||||
@@ -196,11 +210,12 @@ public class GpxFileTrackImporter extends AbstractFileTrackImporter {
|
|||||||
altitude = null;
|
altitude = null;
|
||||||
time = null;
|
time = null;
|
||||||
speed = null;
|
speed = null;
|
||||||
|
power = null;
|
||||||
gain = null;
|
gain = null;
|
||||||
loss = null;
|
loss = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onTrackPointEnd() throws SAXException {
|
private void onTrackPointEnd() {
|
||||||
boolean isFirstTrackPointInSegment = isFirstTrackPointInSegment();
|
boolean isFirstTrackPointInSegment = isFirstTrackPointInSegment();
|
||||||
TrackPoint trackPoint = getTrackPoint();
|
TrackPoint trackPoint = getTrackPoint();
|
||||||
if (isFirstTrackPointInSegment) {
|
if (isFirstTrackPointInSegment) {
|
||||||
@@ -221,7 +236,7 @@ public class GpxFileTrackImporter extends AbstractFileTrackImporter {
|
|||||||
markerType = null;
|
markerType = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onMarkerEnd() throws SAXException {
|
private void onMarkerEnd() {
|
||||||
addMarker();
|
addMarker();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package de.dennisguse.opentracks.io.file.importer;
|
package de.dennisguse.opentracks.io.file.importer;
|
||||||
|
|
||||||
|
import android.content.ClipData;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -30,6 +31,10 @@ import androidx.documentfile.provider.DocumentFile;
|
|||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.TrackRecordedActivity;
|
import de.dennisguse.opentracks.TrackRecordedActivity;
|
||||||
import de.dennisguse.opentracks.databinding.ImportActivityBinding;
|
import de.dennisguse.opentracks.databinding.ImportActivityBinding;
|
||||||
@@ -47,17 +52,15 @@ public class ImportActivity extends FragmentActivity {
|
|||||||
|
|
||||||
public static final String EXTRA_DIRECTORY_URI_KEY = "directory_uri";
|
public static final String EXTRA_DIRECTORY_URI_KEY = "directory_uri";
|
||||||
|
|
||||||
private static final String BUNDLE_TOOLBAR_TITLE = "toolbar_title";
|
private static final String BUNDLE_DOCUMENT_URIS = "document_uris";
|
||||||
private static final String BUNDLE_DOCUMENT_URI = "document_uri";
|
|
||||||
private static final String BUNDLE_IS_DIRECTORY = "is_directory";
|
private static final String BUNDLE_IS_DIRECTORY = "is_directory";
|
||||||
|
|
||||||
private ImportActivityBinding viewBinding;
|
private ImportActivityBinding viewBinding;
|
||||||
|
|
||||||
boolean doubleBackToCancel = false;
|
boolean doubleBackToCancel = false;
|
||||||
|
|
||||||
private Uri documentUri;
|
private ArrayList<Uri> documentUris = new ArrayList<>();
|
||||||
private boolean isDirectory;
|
private boolean isDirectory;
|
||||||
private String toolbarTitle;
|
|
||||||
|
|
||||||
private ImportViewModel viewModel;
|
private ImportViewModel viewModel;
|
||||||
private ImportViewModel.Summary summary;
|
private ImportViewModel.Summary summary;
|
||||||
@@ -70,35 +73,46 @@ public class ImportActivity extends FragmentActivity {
|
|||||||
|
|
||||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||||
|
|
||||||
final DocumentFile documentFile;
|
final Intent intent = getIntent();
|
||||||
|
final ClipData intentClipData = intent.getClipData();
|
||||||
|
|
||||||
if (savedInstanceState == null) {
|
if (savedInstanceState == null) {
|
||||||
if (getIntent().getData() != null) {
|
if (intent.getData() != null) {
|
||||||
documentUri = getIntent().getData();
|
documentUris.add(intent.getData());
|
||||||
isDirectory = false;
|
isDirectory = false;
|
||||||
} else if (getIntent().getClipData() != null && getIntent().getClipData().getItemCount() > 0) {
|
} else {
|
||||||
documentUri = getIntent().getClipData().getItemAt(0).getUri();
|
if (intentClipData != null && intentClipData.getItemCount() > 0) {
|
||||||
|
for (int i = 0; i < intentClipData.getItemCount(); i++) {
|
||||||
|
documentUris.add(intentClipData.getItemAt(i).getUri());
|
||||||
|
}
|
||||||
isDirectory = false;
|
isDirectory = false;
|
||||||
} else {
|
} else {
|
||||||
// Started from DirectoryChooserActivity
|
// Started from DirectoryChooserActivity
|
||||||
documentUri = getIntent().getParcelableExtra(EXTRA_DIRECTORY_URI_KEY);
|
documentUris.add(intent.getParcelableExtra(EXTRA_DIRECTORY_URI_KEY));
|
||||||
isDirectory = true;
|
isDirectory = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
documentFile = isDirectory ? DocumentFile.fromTreeUri(this, documentUri) : DocumentFile.fromSingleUri(this, documentUri);
|
|
||||||
toolbarTitle = getString(R.string.import_progress_message, documentFile.getName());
|
|
||||||
} else {
|
|
||||||
documentUri = savedInstanceState.getParcelable(BUNDLE_DOCUMENT_URI);
|
|
||||||
toolbarTitle = savedInstanceState.getString(BUNDLE_TOOLBAR_TITLE);
|
|
||||||
isDirectory = savedInstanceState.getBoolean(BUNDLE_IS_DIRECTORY);
|
|
||||||
|
|
||||||
documentFile = isDirectory ? DocumentFile.fromTreeUri(this, documentUri) : DocumentFile.fromSingleUri(this, documentUri);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toolbar.setTitle(toolbarTitle);
|
} else {
|
||||||
|
documentUris = savedInstanceState.getParcelable(BUNDLE_DOCUMENT_URIS);
|
||||||
|
isDirectory = savedInstanceState.getBoolean(BUNDLE_IS_DIRECTORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<DocumentFile> documentFiles;
|
||||||
|
if (isDirectory) {
|
||||||
|
documentFiles = new ArrayList<>();
|
||||||
|
documentFiles.add(DocumentFile.fromTreeUri(this, documentUris.get(0)));
|
||||||
|
} else {
|
||||||
|
documentFiles = documentUris.stream().map(it -> DocumentFile.fromSingleUri(this, it)).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
//Works for a directory, but we might have received multiple files via SEND_MULTIPLE.
|
||||||
|
toolbar.setTitle(getString(R.string.import_progress_message, documentFiles.get(0).getName()));
|
||||||
|
|
||||||
initViews();
|
initViews();
|
||||||
|
|
||||||
viewModel = new ViewModelProvider(this).get(ImportViewModel.class);
|
viewModel = new ViewModelProvider(this).get(ImportViewModel.class);
|
||||||
viewModel.getImportData(documentFile).observe(this, data -> {
|
viewModel.getImportData(documentFiles).observe(this, data -> {
|
||||||
summary = data;
|
summary = data;
|
||||||
setProgress();
|
setProgress();
|
||||||
});
|
});
|
||||||
@@ -107,9 +121,8 @@ public class ImportActivity extends FragmentActivity {
|
|||||||
@Override
|
@Override
|
||||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
outState.putParcelable(BUNDLE_DOCUMENT_URI, documentUri);
|
outState.putParcelableArrayList(BUNDLE_DOCUMENT_URIS, documentUris);
|
||||||
outState.putBoolean(BUNDLE_IS_DIRECTORY, isDirectory);
|
outState.putBoolean(BUNDLE_IS_DIRECTORY, isDirectory);
|
||||||
outState.putString(BUNDLE_TOOLBAR_TITLE, toolbarTitle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import androidx.documentfile.provider.DocumentFile;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
@@ -62,11 +63,12 @@ public class ImportService extends JobIntentService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try (InputStream inputStream = getContentResolver().openInputStream(file.getUri())) {
|
try (InputStream inputStream = getContentResolver().openInputStream(file.getUri())) {
|
||||||
Track.Id trackId = trackImporter.importFile(inputStream);
|
ArrayList<Track.Id> trackIds = new ArrayList<>(trackImporter.importFile(inputStream));
|
||||||
if (trackId != null) {
|
|
||||||
sendResult(ImportServiceResultReceiver.RESULT_CODE_IMPORTED, trackId, file, getString(R.string.import_file_imported, file.getName()));
|
if (!trackIds.isEmpty()) {
|
||||||
|
sendResult(ImportServiceResultReceiver.RESULT_CODE_IMPORTED, trackIds, file, getString(R.string.import_file_imported, file.getName()));
|
||||||
} else {
|
} else {
|
||||||
sendResult(ImportServiceResultReceiver.RESULT_CODE_ERROR, trackId, file, getString(R.string.import_unable_to_import_file, file.getName()));
|
sendResult(ImportServiceResultReceiver.RESULT_CODE_ERROR, trackIds, file, getString(R.string.import_unable_to_import_file, file.getName()));
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.d(TAG, "Unable to import file", e);
|
Log.d(TAG, "Unable to import file", e);
|
||||||
@@ -80,9 +82,9 @@ public class ImportService extends JobIntentService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendResult(int resultCode, Track.Id trackId, DocumentFile file, String message) {
|
private void sendResult(int resultCode, ArrayList<Track.Id> trackId, DocumentFile file, String message) {
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.putParcelable(ImportServiceResultReceiver.RESULT_EXTRA_TRACK_ID, trackId);
|
bundle.putParcelableArrayList(ImportServiceResultReceiver.RESULT_EXTRA_LIST_TRACK_ID, trackId);
|
||||||
bundle.putString(ImportServiceResultReceiver.RESULT_EXTRA_FILENAME, file.getName());
|
bundle.putString(ImportServiceResultReceiver.RESULT_EXTRA_FILENAME, file.getName());
|
||||||
bundle.putString(ImportServiceResultReceiver.RESULT_EXTRA_MESSAGE, message);
|
bundle.putString(ImportServiceResultReceiver.RESULT_EXTRA_MESSAGE, message);
|
||||||
resultReceiver.send(resultCode, bundle);
|
resultReceiver.send(resultCode, bundle);
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@ public class ImportServiceResultReceiver extends ResultReceiver {
|
|||||||
public static final int RESULT_CODE_IMPORTED = 1;
|
public static final int RESULT_CODE_IMPORTED = 1;
|
||||||
public static final int RESULT_CODE_ALREADY_EXISTS = 2;
|
public static final int RESULT_CODE_ALREADY_EXISTS = 2;
|
||||||
|
|
||||||
public static final String RESULT_EXTRA_TRACK_ID = "result_track_id";
|
public static final String RESULT_EXTRA_LIST_TRACK_ID = "result_track_id";
|
||||||
public static final String RESULT_EXTRA_FILENAME = "result_extra_filename";
|
public static final String RESULT_EXTRA_FILENAME = "result_extra_filename";
|
||||||
public static final String RESULT_EXTRA_MESSAGE = "result_extra_message";
|
public static final String RESULT_EXTRA_MESSAGE = "result_extra_message";
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ import androidx.lifecycle.LiveData;
|
|||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
@@ -33,20 +35,20 @@ public class ImportViewModel extends AndroidViewModel implements ImportServiceRe
|
|||||||
summary = new Summary();
|
summary = new Summary();
|
||||||
}
|
}
|
||||||
|
|
||||||
public LiveData<Summary> getImportData(DocumentFile documentFile) {
|
LiveData<Summary> getImportData(List<DocumentFile> documentFiles) {
|
||||||
if (importData == null) {
|
if (importData == null) {
|
||||||
importData = new MutableLiveData<>();
|
importData = new MutableLiveData<>();
|
||||||
loadData(documentFile);
|
loadData(documentFiles);
|
||||||
}
|
}
|
||||||
return importData;
|
return importData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cancel() {
|
void cancel() {
|
||||||
cancel = true;
|
cancel = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadData(DocumentFile documentFile) {
|
private void loadData(List<DocumentFile> documentFiles) {
|
||||||
List<DocumentFile> fileList = FileUtils.getFiles(documentFile);
|
List<DocumentFile> fileList = documentFiles.stream().map(FileUtils::getFiles).flatMap(Collection::stream).collect(Collectors.toList());
|
||||||
summary.totalCount = fileList.size();
|
summary.totalCount = fileList.size();
|
||||||
filesToImport.addAll(fileList);
|
filesToImport.addAll(fileList);
|
||||||
importNextFile();
|
importNextFile();
|
||||||
@@ -66,7 +68,7 @@ public class ImportViewModel extends AndroidViewModel implements ImportServiceRe
|
|||||||
throw new RuntimeException(TAG + ": onReceiveResult resultData NULL");
|
throw new RuntimeException(TAG + ": onReceiveResult resultData NULL");
|
||||||
}
|
}
|
||||||
|
|
||||||
Track.Id trackId = resultData.getParcelable(ImportServiceResultReceiver.RESULT_EXTRA_TRACK_ID);
|
ArrayList<Track.Id> trackIds = resultData.getParcelableArrayList(ImportServiceResultReceiver.RESULT_EXTRA_LIST_TRACK_ID);
|
||||||
String fileName = resultData.getString(ImportServiceResultReceiver.RESULT_EXTRA_FILENAME);
|
String fileName = resultData.getString(ImportServiceResultReceiver.RESULT_EXTRA_FILENAME);
|
||||||
String message = resultData.getString(ImportServiceResultReceiver.RESULT_EXTRA_MESSAGE);
|
String message = resultData.getString(ImportServiceResultReceiver.RESULT_EXTRA_MESSAGE);
|
||||||
|
|
||||||
@@ -76,7 +78,7 @@ public class ImportViewModel extends AndroidViewModel implements ImportServiceRe
|
|||||||
summary.fileErrors.add(getApplication().getString(R.string.import_error_info, fileName, message));
|
summary.fileErrors.add(getApplication().getString(R.string.import_error_info, fileName, message));
|
||||||
break;
|
break;
|
||||||
case ImportServiceResultReceiver.RESULT_CODE_IMPORTED:
|
case ImportServiceResultReceiver.RESULT_CODE_IMPORTED:
|
||||||
summary.importedTrackIds.add(trackId);
|
summary.importedTrackIds.addAll(trackIds);
|
||||||
summary.successCount++;
|
summary.successCount++;
|
||||||
break;
|
break;
|
||||||
case ImportServiceResultReceiver.RESULT_CODE_ALREADY_EXISTS:
|
case ImportServiceResultReceiver.RESULT_CODE_ALREADY_EXISTS:
|
||||||
@@ -90,7 +92,7 @@ public class ImportViewModel extends AndroidViewModel implements ImportServiceRe
|
|||||||
importNextFile();
|
importNextFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Summary {
|
static class Summary {
|
||||||
private int totalCount;
|
private int totalCount;
|
||||||
private int successCount;
|
private int successCount;
|
||||||
private int existsCount;
|
private int existsCount;
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import de.dennisguse.opentracks.io.file.exporter.KMLTrackExporter;
|
|||||||
*
|
*
|
||||||
* @author Jimmy Shih
|
* @author Jimmy Shih
|
||||||
*/
|
*/
|
||||||
|
//TODO Do not use AbstractFileTrackImporter as TrackPoint sensor generation is done differently here.
|
||||||
public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
||||||
|
|
||||||
private static final String TAG = KmlFileTrackImporter.class.getSimpleName();
|
private static final String TAG = KmlFileTrackImporter.class.getSimpleName();
|
||||||
@@ -65,6 +66,7 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
|||||||
private String extendedDataType;
|
private String extendedDataType;
|
||||||
private final ArrayList<TrackPoint> trackPoints = new ArrayList<>();
|
private final ArrayList<TrackPoint> trackPoints = new ArrayList<>();
|
||||||
private final ArrayList<Float> speedList = new ArrayList<>();
|
private final ArrayList<Float> speedList = new ArrayList<>();
|
||||||
|
private final ArrayList<Float> distanceList = new ArrayList<>();
|
||||||
private final ArrayList<Float> cadenceList = new ArrayList<>();
|
private final ArrayList<Float> cadenceList = new ArrayList<>();
|
||||||
private final ArrayList<Float> heartRateList = new ArrayList<>();
|
private final ArrayList<Float> heartRateList = new ArrayList<>();
|
||||||
private final ArrayList<Float> powerList = new ArrayList<>();
|
private final ArrayList<Float> powerList = new ArrayList<>();
|
||||||
@@ -215,6 +217,7 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
|||||||
super.onTrackSegmentStart();
|
super.onTrackSegmentStart();
|
||||||
trackPoints.clear();
|
trackPoints.clear();
|
||||||
speedList.clear();
|
speedList.clear();
|
||||||
|
distanceList.clear();
|
||||||
heartRateList.clear();
|
heartRateList.clear();
|
||||||
cadenceList.clear();
|
cadenceList.clear();
|
||||||
powerList.clear();
|
powerList.clear();
|
||||||
@@ -231,6 +234,9 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
|||||||
if (i < speedList.size()) {
|
if (i < speedList.size()) {
|
||||||
trackPoint.setSpeed(speedList.get(i));
|
trackPoint.setSpeed(speedList.get(i));
|
||||||
}
|
}
|
||||||
|
if (i < distanceList.size()) {
|
||||||
|
trackPoint.setSensorDistance(distanceList.get(i));
|
||||||
|
}
|
||||||
if (i < heartRateList.size()) {
|
if (i < heartRateList.size()) {
|
||||||
trackPoint.setHeartRate_bpm(heartRateList.get(i));
|
trackPoint.setHeartRate_bpm(heartRateList.get(i));
|
||||||
}
|
}
|
||||||
@@ -309,6 +315,9 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
|
|||||||
case KMLTrackExporter.EXTENDED_DATA_TYPE_SPEED:
|
case KMLTrackExporter.EXTENDED_DATA_TYPE_SPEED:
|
||||||
speedList.add(value);
|
speedList.add(value);
|
||||||
break;
|
break;
|
||||||
|
case KMLTrackExporter.EXTENDED_DATA_TYPE_DISTANCE:
|
||||||
|
distanceList.add(value);
|
||||||
|
break;
|
||||||
case KMLTrackExporter.EXTENDED_DATA_TYPE_POWER:
|
case KMLTrackExporter.EXTENDED_DATA_TYPE_POWER:
|
||||||
powerList.add(value);
|
powerList.add(value);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ import android.content.Context;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -66,17 +68,23 @@ public class KmzTrackImporter implements TrackImporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Track.Id importFile(InputStream inputStream) {
|
public @NonNull
|
||||||
Track.Id trackId = findAndParseKmlFile(inputStream);
|
List<Track.Id> importFile(InputStream inputStream) {
|
||||||
|
List<Track.Id> trackIds = findAndParseKmlFile(inputStream);
|
||||||
|
|
||||||
if (!copyKmzImages(trackId)) {
|
ArrayList<Track.Id> trackIdsWithImages = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Track.Id trackId : trackIds) {
|
||||||
|
if (copyKmzImages(trackId)) {
|
||||||
|
trackIdsWithImages.add(trackId);
|
||||||
|
deleteOrphanImages(context, trackId);
|
||||||
|
} else {
|
||||||
cleanImport(context, trackId);
|
cleanImport(context, trackId);
|
||||||
return null;
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteOrphanImages(context, trackId);
|
return trackIdsWithImages;
|
||||||
|
|
||||||
return trackId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -150,14 +158,13 @@ public class KmzTrackImporter implements TrackImporter {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds KmzTrackExporter.KMZ_KML_FILE file inside kmz file (inputStream) and it parses it.
|
* Finds KmzTrackExporter.KMZ_KML_FILE file inside kmz file (inputStream) and it parses it.
|
||||||
* TODO: May load multiple tracks, but only returns the last Track.Id.
|
|
||||||
*
|
*
|
||||||
* @param inputStream kmz input stream.
|
* @param inputStream kmz input stream.
|
||||||
*/
|
*/
|
||||||
private Track.Id findAndParseKmlFile(InputStream inputStream) {
|
private List<Track.Id> findAndParseKmlFile(InputStream inputStream) {
|
||||||
try (ZipInputStream zipInputStream = new ZipInputStream(inputStream)) {
|
try (ZipInputStream zipInputStream = new ZipInputStream(inputStream)) {
|
||||||
ZipEntry zipEntry;
|
ZipEntry zipEntry;
|
||||||
Track.Id trackId = null;
|
ArrayList<Track.Id> trackIds = new ArrayList<>();
|
||||||
|
|
||||||
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
|
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
|
||||||
if (Thread.interrupted()) {
|
if (Thread.interrupted()) {
|
||||||
@@ -167,20 +174,21 @@ public class KmzTrackImporter implements TrackImporter {
|
|||||||
|
|
||||||
String fileName = zipEntry.getName();
|
String fileName = zipEntry.getName();
|
||||||
if (KmzTrackExporter.KMZ_KML_FILE.equals(fileName)) {
|
if (KmzTrackExporter.KMZ_KML_FILE.equals(fileName)) {
|
||||||
trackId = parseKml(zipInputStream);
|
List<Track.Id> trackId = parseKml(zipInputStream);
|
||||||
if (trackId == null) {
|
if (trackId.isEmpty()) {
|
||||||
Log.d(TAG, "Unable to parse kml in kmz");
|
Log.d(TAG, "Unable to parse kml in kmz");
|
||||||
throw new ImportParserException(context.getString(R.string.import_unable_to_import_file, fileName));
|
throw new ImportParserException(context.getString(R.string.import_unable_to_import_file, fileName));
|
||||||
}
|
}
|
||||||
|
trackIds.addAll(trackId);
|
||||||
}
|
}
|
||||||
|
|
||||||
zipInputStream.closeEntry();
|
zipInputStream.closeEntry();
|
||||||
}
|
}
|
||||||
if (trackId == null) {
|
if (trackIds.isEmpty()) {
|
||||||
Log.d(TAG, "Unable to find doc.kml in kmz");
|
Log.d(TAG, "Unable to find doc.kml in kmz");
|
||||||
throw new ImportParserException(context.getString(R.string.import_no_kml_file_found));
|
throw new ImportParserException(context.getString(R.string.import_no_kml_file_found));
|
||||||
}
|
}
|
||||||
return trackId;
|
return trackIds;
|
||||||
} catch (ImportParserException | ImportAlreadyExistsException e) {
|
} catch (ImportParserException | ImportAlreadyExistsException e) {
|
||||||
Log.e(TAG, "Unable to import file", e);
|
Log.e(TAG, "Unable to import file", e);
|
||||||
throw e;
|
throw e;
|
||||||
@@ -234,13 +242,7 @@ public class KmzTrackImporter implements TrackImporter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private List<Track.Id> parseKml(ZipInputStream zipInputStream) {
|
||||||
* Parses kml
|
|
||||||
*
|
|
||||||
* @param zipInputStream the zip input stream
|
|
||||||
* @return the imported track id or -1L
|
|
||||||
*/
|
|
||||||
private Track.Id parseKml(ZipInputStream zipInputStream) {
|
|
||||||
KmlFileTrackImporter kmlFileTrackImporter = new KmlFileTrackImporter(context);
|
KmlFileTrackImporter kmlFileTrackImporter = new KmlFileTrackImporter(context);
|
||||||
|
|
||||||
try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(getKml(zipInputStream))) {
|
try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(getKml(zipInputStream))) {
|
||||||
|
|||||||
@@ -15,7 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package de.dennisguse.opentracks.io.file.importer;
|
package de.dennisguse.opentracks.io.file.importer;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
|
|
||||||
@@ -30,8 +33,7 @@ public interface TrackImporter {
|
|||||||
* Import a file.
|
* Import a file.
|
||||||
*
|
*
|
||||||
* @param inputStream the file's input stream
|
* @param inputStream the file's input stream
|
||||||
* @return the imported track id or null.
|
|
||||||
*/
|
*/
|
||||||
//TODO Figure out how can make the import an atomic operation (incl. database transaction rollback).
|
@NonNull
|
||||||
Track.Id importFile(InputStream inputStream);
|
List<Track.Id> importFile(InputStream inputStream) throws ImportParserException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,39 +82,40 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
private PeriodicTaskExecutor voiceExecutor;
|
private PeriodicTaskExecutor voiceExecutor;
|
||||||
private TrackRecordingServiceNotificationManager notificationManager;
|
private TrackRecordingServiceNotificationManager notificationManager;
|
||||||
|
|
||||||
|
private SharedPreferences sharedPreferences;
|
||||||
private Track.Id recordingTrackId;
|
private Track.Id recordingTrackId;
|
||||||
private boolean recordingTrackPaused;
|
private boolean recordingTrackPaused;
|
||||||
private int recordingDistanceInterval;
|
private int recordingDistanceInterval;
|
||||||
private int maxRecordingDistance;
|
private int maxRecordingDistance;
|
||||||
|
|
||||||
private final OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
|
private final OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
Context context = TrackRecordingService.this;
|
Context context = TrackRecordingService.this;
|
||||||
if (PreferencesUtils.isKey(TrackRecordingService.this, R.string.recording_track_id_key, key)) {
|
if (PreferencesUtils.isKey(TrackRecordingService.this, R.string.recording_track_id_key, key)) {
|
||||||
// Only through the TrackRecordingService can one stop a recording and set the recordingTrackId to -1L.
|
// Only through the TrackRecordingService can one stop a recording and set the recordingTrackId to -1L.
|
||||||
if (PreferencesUtils.isRecording(TrackRecordingService.this)) {
|
if (PreferencesUtils.isRecording(sharedPreferences, TrackRecordingService.this)) {
|
||||||
recordingTrackId = PreferencesUtils.getRecordingTrackId(TrackRecordingService.this);
|
recordingTrackId = PreferencesUtils.getRecordingTrackId(sharedPreferences, TrackRecordingService.this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (PreferencesUtils.isKey(context, R.string.recording_track_paused_key, key)) {
|
if (PreferencesUtils.isKey(context, R.string.recording_track_paused_key, key)) {
|
||||||
recordingTrackPaused = PreferencesUtils.isRecordingTrackPaused(context);
|
recordingTrackPaused = PreferencesUtils.isRecordingTrackPaused(sharedPreferences, context);
|
||||||
}
|
}
|
||||||
if (PreferencesUtils.isKey(context, R.string.stats_units_key, key)) {
|
if (PreferencesUtils.isKey(context, R.string.stats_units_key, key)) {
|
||||||
boolean metricUnits = PreferencesUtils.isMetricUnits(context);
|
boolean metricUnits = PreferencesUtils.isMetricUnits(sharedPreferences, context);
|
||||||
voiceExecutor.setMetricUnits(metricUnits);
|
voiceExecutor.setMetricUnits(metricUnits);
|
||||||
|
notificationManager.setMetricUnits(metricUnits);
|
||||||
}
|
}
|
||||||
if (PreferencesUtils.isKey(context, R.string.voice_frequency_key, key)) {
|
if (PreferencesUtils.isKey(context, R.string.voice_frequency_key, key)) {
|
||||||
voiceExecutor.setTaskFrequency(PreferencesUtils.getVoiceFrequency(context));
|
voiceExecutor.setTaskFrequency(PreferencesUtils.getVoiceFrequency(sharedPreferences, context));
|
||||||
}
|
}
|
||||||
if (PreferencesUtils.isKey(context, R.string.recording_distance_interval_key, key)) {
|
if (PreferencesUtils.isKey(context, R.string.recording_distance_interval_key, key)) {
|
||||||
recordingDistanceInterval = PreferencesUtils.getRecordingDistanceInterval(context);
|
recordingDistanceInterval = PreferencesUtils.getRecordingDistanceInterval(sharedPreferences, context);
|
||||||
}
|
}
|
||||||
if (PreferencesUtils.isKey(context, R.string.max_recording_distance_key, key)) {
|
if (PreferencesUtils.isKey(context, R.string.max_recording_distance_key, key)) {
|
||||||
maxRecordingDistance = PreferencesUtils.getMaxRecordingDistance(context);
|
maxRecordingDistance = PreferencesUtils.getMaxRecordingDistance(sharedPreferences, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
handlerServer.onSharedPreferenceChanged(context, preferences, key);
|
handlerServer.onSharedPreferenceChanged(context, sharedPreferences, key);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -147,8 +148,9 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
// onSharedPreferenceChanged might not set recordingTrackId.
|
// onSharedPreferenceChanged might not set recordingTrackId.
|
||||||
recordingTrackId = null;
|
recordingTrackId = null;
|
||||||
|
|
||||||
PreferencesUtils.register(this, sharedPreferenceChangeListener);
|
sharedPreferences = PreferencesUtils.getSharedPreferences(this);
|
||||||
sharedPreferenceChangeListener.onSharedPreferenceChanged(null, null);
|
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
||||||
|
sharedPreferenceChangeListener.onSharedPreferenceChanged(sharedPreferences, null);
|
||||||
|
|
||||||
restartTrackAfterServiceRestart();
|
restartTrackAfterServiceRestart();
|
||||||
}
|
}
|
||||||
@@ -189,8 +191,8 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
// Reverse order from onCreate
|
// Reverse order from onCreate
|
||||||
showNotification(false); //TODO Why?
|
showNotification(false); //TODO Why?
|
||||||
|
|
||||||
PreferencesUtils.unregister(this, sharedPreferenceChangeListener);
|
sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
||||||
|
sharedPreferences = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
voiceExecutor.shutdown();
|
voiceExecutor.shutdown();
|
||||||
@@ -305,7 +307,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
//TODO Pass TrackPoint
|
//TODO Pass TrackPoint
|
||||||
track.setName(TrackNameUtils.getTrackName(this, trackId, segmentStartTrackPoint.getTime()));
|
track.setName(TrackNameUtils.getTrackName(this, trackId, segmentStartTrackPoint.getTime()));
|
||||||
|
|
||||||
String category = PreferencesUtils.getDefaultActivity(this);
|
String category = PreferencesUtils.getDefaultActivity(sharedPreferences, this);
|
||||||
track.setCategory(category);
|
track.setCategory(category);
|
||||||
track.setIcon(TrackIconUtils.getIconValue(this, category));
|
track.setIcon(TrackIconUtils.getIconValue(this, category));
|
||||||
track.setTrackStatistics(trackStatisticsUpdater.getTrackStatistics());
|
track.setTrackStatistics(trackStatisticsUpdater.getTrackStatistics());
|
||||||
@@ -536,9 +538,9 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
private void updateRecordingState(Track.Id trackId, boolean paused) {
|
private void updateRecordingState(Track.Id trackId, boolean paused) {
|
||||||
recordingTrackId = trackId;
|
recordingTrackId = trackId;
|
||||||
long currentTrackId = trackId != null ? trackId.getId() : PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
long currentTrackId = trackId != null ? trackId.getId() : PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
|
||||||
PreferencesUtils.setLong(this, R.string.recording_track_id_key, currentTrackId);
|
PreferencesUtils.setLong(sharedPreferences, this, R.string.recording_track_id_key, currentTrackId);
|
||||||
recordingTrackPaused = paused;
|
recordingTrackPaused = paused;
|
||||||
PreferencesUtils.setBoolean(this, R.string.recording_track_paused_key, recordingTrackPaused);
|
PreferencesUtils.setBoolean(sharedPreferences, this, R.string.recording_track_paused_key, recordingTrackPaused);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -556,7 +558,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
|
|
||||||
fillWithSensorDataSet(trackPoint);
|
fillWithSensorDataSet(trackPoint);
|
||||||
|
|
||||||
notificationManager.updateTrackPoint(this, trackPoint, recordingGpsAccuracy);
|
notificationManager.updateTrackPoint(this, track.getTrackStatistics(), trackPoint, recordingGpsAccuracy);
|
||||||
|
|
||||||
//TODO Figure out how to avoid loading the lastValidTrackPoint from the database
|
//TODO Figure out how to avoid loading the lastValidTrackPoint from the database
|
||||||
TrackPoint lastValidTrackPoint = getLastValidTrackPointInCurrentSegment(track.getId());
|
TrackPoint lastValidTrackPoint = getLastValidTrackPointInCurrentSegment(track.getId());
|
||||||
@@ -570,7 +572,7 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
double distanceToLastTrackLocation = trackPoint.distanceTo(lastValidTrackPoint);
|
double distanceToLastTrackLocation = trackPoint.distanceToPrevious(lastValidTrackPoint);
|
||||||
if (distanceToLastTrackLocation > maxRecordingDistance) {
|
if (distanceToLastTrackLocation > maxRecordingDistance) {
|
||||||
insertTrackPointIfNewer(track, lastTrackPoint);
|
insertTrackPointIfNewer(track, lastTrackPoint);
|
||||||
|
|
||||||
@@ -663,6 +665,10 @@ public class TrackRecordingService extends Service implements HandlerServer.Hand
|
|||||||
trackPoint.setElevationLoss(elevationSumManager.getElevationLoss_m());
|
trackPoint.setElevationLoss(elevationSumManager.getElevationLoss_m());
|
||||||
elevationSumManager.reset();
|
elevationSumManager.reset();
|
||||||
}
|
}
|
||||||
|
if (remoteSensorManager != null) {
|
||||||
|
fillWithSensorDataSet(trackPoint);
|
||||||
|
remoteSensorManager.reset();
|
||||||
|
}
|
||||||
contentProviderUtils.insertTrackPoint(trackPoint, track.getId());
|
contentProviderUtils.insertTrackPoint(trackPoint, track.getId());
|
||||||
trackStatisticsUpdater.addTrackPoint(trackPoint, recordingDistanceInterval);
|
trackStatisticsUpdater.addTrackPoint(trackPoint, recordingDistanceInterval);
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -20,6 +20,7 @@ import android.content.ComponentName;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.IBinder.DeathRecipient;
|
import android.os.IBinder.DeathRecipient;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
@@ -209,9 +210,10 @@ public class TrackRecordingServiceConnection implements ServiceConnection, Death
|
|||||||
try {
|
try {
|
||||||
if (showEditor) {
|
if (showEditor) {
|
||||||
// Need to remember the recordingTrackId before calling endCurrentTrack() as endCurrentTrack() sets the value to -1L.
|
// Need to remember the recordingTrackId before calling endCurrentTrack() as endCurrentTrack() sets the value to -1L.
|
||||||
Track.Id recordingTrackId = PreferencesUtils.getRecordingTrackId(context);
|
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||||
|
Track.Id recordingTrackId = PreferencesUtils.getRecordingTrackId(sharedPreferences, context);
|
||||||
trackRecordingService.endCurrentTrack();
|
trackRecordingService.endCurrentTrack();
|
||||||
if (PreferencesUtils.isRecording(context)) {
|
if (PreferencesUtils.isRecording(sharedPreferences, context)) {
|
||||||
Intent intent = IntentUtils.newIntent(context, TrackEditActivity.class)
|
Intent intent = IntentUtils.newIntent(context, TrackEditActivity.class)
|
||||||
.putExtra(TrackEditActivity.EXTRA_TRACK_ID, recordingTrackId)
|
.putExtra(TrackEditActivity.EXTRA_TRACK_ID, recordingTrackId)
|
||||||
.putExtra(TrackEditActivity.EXTRA_NEW_TRACK, true);
|
.putExtra(TrackEditActivity.EXTRA_NEW_TRACK, true);
|
||||||
|
|||||||
+13
-5
@@ -12,7 +12,7 @@ import androidx.core.app.NotificationCompat;
|
|||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
import de.dennisguse.opentracks.util.StringUtils;
|
import de.dennisguse.opentracks.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,6 +30,8 @@ class TrackRecordingServiceNotificationManager {
|
|||||||
|
|
||||||
private boolean previousLocationWasAccurate = true;
|
private boolean previousLocationWasAccurate = true;
|
||||||
|
|
||||||
|
private Boolean metricUnits = null;
|
||||||
|
|
||||||
TrackRecordingServiceNotificationManager(Context context) {
|
TrackRecordingServiceNotificationManager(Context context) {
|
||||||
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
@@ -59,14 +61,14 @@ class TrackRecordingServiceNotificationManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void updateContent(String content) {
|
void updateContent(String content) {
|
||||||
notificationBuilder.setContentText(content);
|
notificationBuilder.setSubText(content);
|
||||||
updateNotification();
|
updateNotification();
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateTrackPoint(Context context, TrackPoint trackPoint, int recordingGpsAccuracy) {
|
void updateTrackPoint(Context context, TrackStatistics trackStatistics, TrackPoint trackPoint, int recordingGpsAccuracy) {
|
||||||
String formattedAccuracy = context.getString(R.string.value_none);
|
String formattedAccuracy = context.getString(R.string.value_none);
|
||||||
if (trackPoint.hasAccuracy()) {
|
if (trackPoint.hasAccuracy()) {
|
||||||
formattedAccuracy = StringUtils.formatDistance(context, trackPoint.getAccuracy(), PreferencesUtils.isMetricUnits(context));
|
formattedAccuracy = StringUtils.formatDistance(context, trackPoint.getAccuracy(), metricUnits);
|
||||||
|
|
||||||
boolean currentLocationWasAccurate = trackPoint.getAccuracy() < recordingGpsAccuracy;
|
boolean currentLocationWasAccurate = trackPoint.getAccuracy() < recordingGpsAccuracy;
|
||||||
boolean shouldAlert = !currentLocationWasAccurate && previousLocationWasAccurate;
|
boolean shouldAlert = !currentLocationWasAccurate && previousLocationWasAccurate;
|
||||||
@@ -74,7 +76,9 @@ class TrackRecordingServiceNotificationManager {
|
|||||||
previousLocationWasAccurate = currentLocationWasAccurate;
|
previousLocationWasAccurate = currentLocationWasAccurate;
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationBuilder.setContentText(context.getString(R.string.track_recording_notification_accuracy, formattedAccuracy));
|
notificationBuilder.setContentTitle(context.getString(R.string.track_distance_notification, StringUtils.formatDistance(context, trackStatistics.getTotalDistance(), metricUnits)));
|
||||||
|
notificationBuilder.setContentText(context.getString(R.string.track_speed_notification, StringUtils.formatSpeed(context, trackPoint.getSpeed(), metricUnits, true)));
|
||||||
|
notificationBuilder.setSubText(context.getString(R.string.track_recording_notification_accuracy, formattedAccuracy));
|
||||||
updateNotification();
|
updateNotification();
|
||||||
|
|
||||||
notificationBuilder.setOnlyAlertOnce(true);
|
notificationBuilder.setOnlyAlertOnce(true);
|
||||||
@@ -93,6 +97,10 @@ class TrackRecordingServiceNotificationManager {
|
|||||||
return notificationBuilder.build();
|
return notificationBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setMetricUnits(boolean metricUnits) {
|
||||||
|
this.metricUnits = metricUnits;
|
||||||
|
}
|
||||||
|
|
||||||
private void updateNotification() {
|
private void updateNotification() {
|
||||||
notificationManager.notify(NOTIFICATION_ID, getNotification());
|
notificationManager.notify(NOTIFICATION_ID, getNotification());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package de.dennisguse.opentracks.services.handlers;
|
package de.dennisguse.opentracks.services.handlers;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.location.LocationManager;
|
import android.location.LocationManager;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
|
||||||
@@ -15,6 +16,7 @@ import de.dennisguse.opentracks.util.PreferencesUtils;
|
|||||||
/**
|
/**
|
||||||
* This class handle GPS status according to received locations and some thresholds.
|
* This class handle GPS status according to received locations and some thresholds.
|
||||||
*/
|
*/
|
||||||
|
//TODO should handle sharedpreference changes
|
||||||
class GpsStatus {
|
class GpsStatus {
|
||||||
|
|
||||||
private static final String TAG = GpsStatus.class.getSimpleName();
|
private static final String TAG = GpsStatus.class.getSimpleName();
|
||||||
@@ -60,16 +62,16 @@ class GpsStatus {
|
|||||||
private final Handler gpsStatusHandler;
|
private final Handler gpsStatusHandler;
|
||||||
private GpsStatusRunner gpsStatusRunner = null;
|
private GpsStatusRunner gpsStatusRunner = null;
|
||||||
|
|
||||||
/**
|
public GpsStatus(Context context, GpsStatusListener client) {
|
||||||
* @param context The context object.
|
|
||||||
* @param client The client.
|
|
||||||
* @param minRecordingInterval Value of min recording interval preference.
|
|
||||||
*/
|
|
||||||
public GpsStatus(Context context, GpsStatusListener client, Duration minRecordingInterval) {
|
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
signalBadThreshold = PreferencesUtils.getRecordingDistanceInterval(context);
|
|
||||||
|
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||||
|
signalBadThreshold = PreferencesUtils.getRecordingDistanceInterval(sharedPreferences, context);
|
||||||
|
|
||||||
|
Duration minRecordingInterval = Duration.ofSeconds(PreferencesUtils.getMinRecordingInterval(sharedPreferences, context));
|
||||||
signalLostThreshold = !minRecordingInterval.isNegative() ? SIGNAL_LOST_THRESHOLD.plus(minRecordingInterval) : SIGNAL_LOST_THRESHOLD;
|
signalLostThreshold = !minRecordingInterval.isNegative() ? SIGNAL_LOST_THRESHOLD.plus(minRecordingInterval) : SIGNAL_LOST_THRESHOLD;
|
||||||
|
|
||||||
gpsStatusHandler = new Handler();
|
gpsStatusHandler = new Handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,14 @@ package de.dennisguse.opentracks.services.handlers;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
|
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||||
|
|
||||||
public class HandlerServer {
|
public class HandlerServer {
|
||||||
|
|
||||||
@@ -32,8 +34,9 @@ public class HandlerServer {
|
|||||||
public void start(Context context) {
|
public void start(Context context) {
|
||||||
serviceExecutor = Executors.newSingleThreadExecutor();
|
serviceExecutor = Executors.newSingleThreadExecutor();
|
||||||
|
|
||||||
|
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||||
locationHandler.onStart(context);
|
locationHandler.onStart(context);
|
||||||
locationHandler.onSharedPreferenceChanged(context, null, null);
|
locationHandler.onSharedPreferenceChanged(context, sharedPreferences, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stop(Context context) {
|
public void stop(Context context) {
|
||||||
@@ -45,7 +48,7 @@ public class HandlerServer {
|
|||||||
serviceExecutor = null;
|
serviceExecutor = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onSharedPreferenceChanged(Context context, SharedPreferences preferences, String key) {
|
public void onSharedPreferenceChanged(@NonNull Context context, @NonNull SharedPreferences preferences, String key) {
|
||||||
locationHandler.onSharedPreferenceChanged(context, preferences, key);
|
locationHandler.onSharedPreferenceChanged(context, preferences, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,8 +73,10 @@ public class HandlerServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public interface Handler {
|
public interface Handler {
|
||||||
void onStart(Context context);
|
void onStart(@NonNull Context context);
|
||||||
void onStop(Context context);
|
|
||||||
void onSharedPreferenceChanged(Context context, SharedPreferences preferences, String key);
|
void onStop(@NonNull Context context);
|
||||||
|
|
||||||
|
void onSharedPreferenceChanged(@NonNull Context context, @NonNull SharedPreferences preferences, String key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,14 +34,14 @@ class LocationHandler implements HandlerServer.Handler, LocationListener, GpsSta
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart(Context context) {
|
public void onStart(@NonNull Context context) {
|
||||||
gpsStatus = new GpsStatus(context, this, Duration.ofSeconds(PreferencesUtils.getMinRecordingInterval(context)));
|
gpsStatus = new GpsStatus(context, this);
|
||||||
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
||||||
registerLocationListener();
|
registerLocationListener();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStop(Context context) {
|
public void onStop(@NonNull Context context) {
|
||||||
unregisterLocationListener();
|
unregisterLocationListener();
|
||||||
locationManager = null;
|
locationManager = null;
|
||||||
if (gpsStatus != null) {
|
if (gpsStatus != null) {
|
||||||
@@ -51,9 +51,9 @@ class LocationHandler implements HandlerServer.Handler, LocationListener, GpsSta
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSharedPreferenceChanged(Context context, SharedPreferences preferences, String key) {
|
public void onSharedPreferenceChanged(@NonNull Context context, @NonNull SharedPreferences sharedPreferences, String key) {
|
||||||
if (PreferencesUtils.isKey(context, R.string.min_recording_interval_key, key)) {
|
if (PreferencesUtils.isKey(context, R.string.min_recording_interval_key, key)) {
|
||||||
int minRecordingInterval = PreferencesUtils.getMinRecordingInterval(context);
|
int minRecordingInterval = PreferencesUtils.getMinRecordingInterval(sharedPreferences, context);
|
||||||
if (minRecordingInterval == PreferencesUtils.getMinRecordingIntervalAdaptBatteryLife(context)) {
|
if (minRecordingInterval == PreferencesUtils.getMinRecordingIntervalAdaptBatteryLife(context)) {
|
||||||
// Choose battery life over moving time accuracy.
|
// Choose battery life over moving time accuracy.
|
||||||
locationListenerPolicy = new AdaptiveLocationListenerPolicy(Duration.ofSeconds(30), Duration.ofSeconds(5), 5);
|
locationListenerPolicy = new AdaptiveLocationListenerPolicy(Duration.ofSeconds(30), Duration.ofSeconds(5), 5);
|
||||||
@@ -69,16 +69,16 @@ class LocationHandler implements HandlerServer.Handler, LocationListener, GpsSta
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (PreferencesUtils.isKey(context, R.string.recording_gps_accuracy_key, key)) {
|
if (PreferencesUtils.isKey(context, R.string.recording_gps_accuracy_key, key)) {
|
||||||
recordingGpsAccuracy = PreferencesUtils.getRecordingGPSAccuracy(context);
|
recordingGpsAccuracy = PreferencesUtils.getRecordingGPSAccuracy(sharedPreferences, context);
|
||||||
}
|
}
|
||||||
if (PreferencesUtils.isKey(context, R.string.min_recording_interval_key, key)) {
|
if (PreferencesUtils.isKey(context, R.string.min_recording_interval_key, key)) {
|
||||||
if (gpsStatus != null) {
|
if (gpsStatus != null) {
|
||||||
gpsStatus.onMinRecordingIntervalChanged(PreferencesUtils.getMinRecordingInterval(context));
|
gpsStatus.onMinRecordingIntervalChanged(PreferencesUtils.getMinRecordingInterval(sharedPreferences, context));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (PreferencesUtils.isKey(context, R.string.recording_distance_interval_key, key)) {
|
if (PreferencesUtils.isKey(context, R.string.recording_distance_interval_key, key)) {
|
||||||
if (gpsStatus != null) {
|
if (gpsStatus != null) {
|
||||||
gpsStatus.onRecordingDistanceChanged(PreferencesUtils.getRecordingDistanceInterval(context));
|
gpsStatus.onRecordingDistanceChanged(PreferencesUtils.getRecordingDistanceInterval(sharedPreferences, context));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-19
@@ -101,11 +101,11 @@ public abstract class BluetoothConnectionManager {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCharacteristicChanged(BluetoothGatt gatt, @NonNull BluetoothGattCharacteristic characteristic) {
|
public void onCharacteristicChanged(BluetoothGatt gatt, @NonNull BluetoothGattCharacteristic characteristic) {
|
||||||
String sensorName = gatt.getDevice().getName();
|
Log.d(TAG, "Received data from " + gatt.getDevice().getAddress());
|
||||||
Log.d(TAG, "Received data from " + sensorName);
|
|
||||||
|
|
||||||
SensorData sensorData = parsePayload(sensorName, gatt.getDevice().getAddress(), characteristic);
|
SensorData<?> sensorData = parsePayload(gatt.getDevice().getName(), gatt.getDevice().getAddress(), characteristic);
|
||||||
if (sensorData != null) {
|
if (sensorData != null) {
|
||||||
|
Log.d(TAG, "Decoded data from " + gatt.getDevice().getAddress() + ": " + sensorData);
|
||||||
observer.onChanged(sensorData);
|
observer.onChanged(sensorData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,7 +125,7 @@ public abstract class BluetoothConnectionManager {
|
|||||||
Log.d(TAG, "Connecting to: " + device);
|
Log.d(TAG, "Connecting to: " + device);
|
||||||
|
|
||||||
bluetoothGatt = device.connectGatt(context, true, connectCallback);
|
bluetoothGatt = device.connectGatt(context, true, connectCallback);
|
||||||
SensorData sensorData = createEmptySensorData(bluetoothGatt.getDevice().getAddress());
|
SensorData<?> sensorData = createEmptySensorData(bluetoothGatt.getDevice().getAddress());
|
||||||
observer.onChanged(sensorData);
|
observer.onChanged(sensorData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,12 +148,12 @@ public abstract class BluetoothConnectionManager {
|
|||||||
return address.equals(bluetoothGatt.getDevice().getAddress());
|
return address.equals(bluetoothGatt.getDevice().getAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract SensorData createEmptySensorData(String address);
|
protected abstract SensorData<?> createEmptySensorData(String address);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return null if data could not be parsed.
|
* @return null if data could not be parsed.
|
||||||
*/
|
*/
|
||||||
protected abstract SensorData parsePayload(String sensorName, String address, BluetoothGattCharacteristic characteristic);
|
protected abstract SensorData<?> parsePayload(String sensorName, String address, BluetoothGattCharacteristic characteristic);
|
||||||
|
|
||||||
public static class HeartRate extends BluetoothConnectionManager {
|
public static class HeartRate extends BluetoothConnectionManager {
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ public abstract class BluetoothConnectionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SensorData createEmptySensorData(String address) {
|
protected SensorDataHeartRate createEmptySensorData(String address) {
|
||||||
return new SensorDataHeartRate(address);
|
return new SensorDataHeartRate(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,7 +181,7 @@ public abstract class BluetoothConnectionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SensorData createEmptySensorData(String address) {
|
protected SensorDataCycling.Cadence createEmptySensorData(String address) {
|
||||||
return new SensorDataCycling.Cadence(address);
|
return new SensorDataCycling.Cadence(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,30 +197,36 @@ public abstract class BluetoothConnectionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Workaround for Wahoo CADENCE: this sensor reports speed (instead of cadence)
|
//Workaround for Wahoo CADENCE: this sensor reports speed (instead of cadence)
|
||||||
if (cadenceAndSpeed.getSpeed() != null) {
|
if (cadenceAndSpeed.getDistanceSpeed() != null) {
|
||||||
return new SensorDataCycling.Cadence(cadenceAndSpeed.getSpeed());
|
return new SensorDataCycling.Cadence(cadenceAndSpeed.getDistanceSpeed());
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class CyclingSpeed extends BluetoothConnectionManager {
|
public static class CyclingDistanceSpeed extends BluetoothConnectionManager {
|
||||||
|
|
||||||
CyclingSpeed(SensorDataObserver observer) {
|
CyclingDistanceSpeed(SensorDataObserver observer) {
|
||||||
super(BluetoothUtils.CYCLING_SPEED_CADENCE_SERVICE_UUID, BluetoothUtils.CYCLING_SPEED_CADENCE_MEASUREMENT_CHAR_UUID, observer);
|
super(BluetoothUtils.CYCLING_SPEED_CADENCE_SERVICE_UUID, BluetoothUtils.CYCLING_SPEED_CADENCE_MEASUREMENT_CHAR_UUID, observer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SensorData createEmptySensorData(String address) {
|
protected SensorDataCycling.DistanceSpeed createEmptySensorData(String address) {
|
||||||
return new SensorDataCycling.Speed(address);
|
return new SensorDataCycling.DistanceSpeed(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SensorDataCycling.Speed parsePayload(String sensorName, String address, BluetoothGattCharacteristic characteristic) {
|
protected SensorDataCycling.DistanceSpeed parsePayload(String sensorName, String address, BluetoothGattCharacteristic characteristic) {
|
||||||
SensorDataCycling.CadenceAndSpeed cadenceAndSpeed = BluetoothUtils.parseCyclingCrankAndWheel(address, sensorName, characteristic);
|
SensorDataCycling.CadenceAndSpeed cadenceAndSpeed = BluetoothUtils.parseCyclingCrankAndWheel(address, sensorName, characteristic);
|
||||||
if (cadenceAndSpeed != null) {
|
if (cadenceAndSpeed != null) {
|
||||||
return cadenceAndSpeed.getSpeed();
|
// Workaround for Garmin Speed Sensor 2: provides cadence instead of speed
|
||||||
|
SensorDataCycling.DistanceSpeed result = cadenceAndSpeed.getDistanceSpeed();
|
||||||
|
if (result == null && cadenceAndSpeed.getCadence() != null) {
|
||||||
|
result = new SensorDataCycling.DistanceSpeed(cadenceAndSpeed.getSensorAddress(), cadenceAndSpeed.getSensorName(), (int) cadenceAndSpeed.getCadence().getCrankRevolutionsCount(), cadenceAndSpeed.getCadence().getCrankRevolutionsTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -233,7 +239,7 @@ public abstract class BluetoothConnectionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SensorData createEmptySensorData(String address) {
|
protected SensorDataCyclingPower createEmptySensorData(String address) {
|
||||||
return new SensorDataCyclingPower(address);
|
return new SensorDataCyclingPower(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,8 +253,8 @@ public abstract class BluetoothConnectionManager {
|
|||||||
|
|
||||||
interface SensorDataObserver {
|
interface SensorDataObserver {
|
||||||
|
|
||||||
void onChanged(SensorData sensorData);
|
void onChanged(SensorData<?> sensorData);
|
||||||
|
|
||||||
void onDisconnecting(SensorData sensorData);
|
void onDisconnecting(SensorData<?> sensorData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-15
@@ -53,43 +53,50 @@ public class BluetoothRemoteSensorManager implements BluetoothConnectionManager.
|
|||||||
|
|
||||||
private final BluetoothAdapter bluetoothAdapter;
|
private final BluetoothAdapter bluetoothAdapter;
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final SharedPreferences sharedPreferences;
|
|
||||||
|
|
||||||
private boolean started = false;
|
private boolean started = false;
|
||||||
|
|
||||||
|
private final SharedPreferences sharedPreferences;
|
||||||
|
private int preferenceWheelCircumference;
|
||||||
|
|
||||||
private final BluetoothConnectionManager.HeartRate heartRate = new BluetoothConnectionManager.HeartRate(this);
|
private final BluetoothConnectionManager.HeartRate heartRate = new BluetoothConnectionManager.HeartRate(this);
|
||||||
private final BluetoothConnectionManager.CyclingCadence cyclingCadence = new BluetoothConnectionManager.CyclingCadence(this);
|
private final BluetoothConnectionManager.CyclingCadence cyclingCadence = new BluetoothConnectionManager.CyclingCadence(this);
|
||||||
private final BluetoothConnectionManager.CyclingSpeed cyclingSpeed = new BluetoothConnectionManager.CyclingSpeed(this);
|
private final BluetoothConnectionManager.CyclingDistanceSpeed cyclingSpeed = new BluetoothConnectionManager.CyclingDistanceSpeed(this);
|
||||||
private final BluetoothConnectionManager.CyclingPower cyclingPower = new BluetoothConnectionManager.CyclingPower(this);
|
private final BluetoothConnectionManager.CyclingPower cyclingPower = new BluetoothConnectionManager.CyclingPower(this);
|
||||||
|
|
||||||
private final SensorDataSet sensorDataSet = new SensorDataSet();
|
private final SensorDataSet sensorDataSet = new SensorDataSet();
|
||||||
|
|
||||||
private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
|
private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
if (!started) return;
|
if (!started) return;
|
||||||
|
|
||||||
if (PreferencesUtils.isKey(context, R.string.settings_sensor_bluetooth_heart_rate_key, key)) {
|
if (PreferencesUtils.isKey(context, R.string.settings_sensor_bluetooth_heart_rate_key, key)) {
|
||||||
String address = PreferencesUtils.getBluetoothHeartRateSensorAddress(context);
|
String address = PreferencesUtils.getBluetoothHeartRateSensorAddress(sharedPreferences, context);
|
||||||
connect(heartRate, address);
|
connect(heartRate, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PreferencesUtils.isKey(context, R.string.settings_sensor_bluetooth_cycling_cadence_key, key)) {
|
if (PreferencesUtils.isKey(context, R.string.settings_sensor_bluetooth_cycling_cadence_key, key)) {
|
||||||
String address = PreferencesUtils.getBluetoothCyclingCadenceSensorAddress(context);
|
String address = PreferencesUtils.getBluetoothCyclingCadenceSensorAddress(sharedPreferences, context);
|
||||||
connect(cyclingCadence, address);
|
connect(cyclingCadence, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PreferencesUtils.isKey(context, R.string.settings_sensor_bluetooth_cycling_cadence_key, key)) {
|
if (PreferencesUtils.isKey(context, R.string.settings_sensor_bluetooth_cycling_cadence_key, key)) {
|
||||||
String address = PreferencesUtils.getBluetoothCyclingSpeedSensorAddress(context);
|
String address = PreferencesUtils.getBluetoothCyclingSpeedSensorAddress(sharedPreferences, context);
|
||||||
|
|
||||||
connect(cyclingSpeed, address);
|
connect(cyclingSpeed, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PreferencesUtils.isKey(context, R.string.settings_sensor_bluetooth_cycling_power_key, key)) {
|
if (PreferencesUtils.isKey(context, R.string.settings_sensor_bluetooth_cycling_power_key, key)) {
|
||||||
String address = PreferencesUtils.getBluetoothCyclingPowerSensorAddress(context);
|
String address = PreferencesUtils.getBluetoothCyclingPowerSensorAddress(sharedPreferences, context);
|
||||||
|
|
||||||
connect(cyclingPower, address);
|
connect(cyclingPower, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (PreferencesUtils.isKey(context, R.string.settings_sensor_bluetooth_cycling_power_key, key)) {
|
||||||
|
preferenceWheelCircumference = PreferencesUtils.getWheelCircumference(sharedPreferences, context);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -104,7 +111,7 @@ public class BluetoothRemoteSensorManager implements BluetoothConnectionManager.
|
|||||||
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
||||||
|
|
||||||
//Trigger connection startup
|
//Trigger connection startup
|
||||||
sharedPreferenceChangeListener.onSharedPreferenceChanged(null, null);
|
sharedPreferenceChangeListener.onSharedPreferenceChanged(sharedPreferences, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void stop() {
|
public synchronized void stop() {
|
||||||
@@ -155,11 +162,15 @@ public class BluetoothRemoteSensorManager implements BluetoothConnectionManager.
|
|||||||
return sensorDataSet;
|
return sensorDataSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
sensorDataSet.reset();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void onChanged(SensorData sensorData) {
|
public synchronized void onChanged(SensorData<?> sensorData) {
|
||||||
if (sensorData instanceof SensorDataCycling.Cadence) {
|
if (sensorData instanceof SensorDataCycling.Cadence) {
|
||||||
SensorDataCycling.Cadence previous = sensorDataSet.getCyclingCadence();
|
SensorDataCycling.Cadence previous = sensorDataSet.getCyclingCadence();
|
||||||
Log.d(TAG, "previous " + previous + "; current" + sensorData);
|
Log.d(TAG, "Previous: " + previous + "; current: " + sensorData);
|
||||||
|
|
||||||
if (sensorData.equals(previous)) {
|
if (sensorData.equals(previous)) {
|
||||||
Log.d(TAG, "onChanged: cadence data repeated.");
|
Log.d(TAG, "onChanged: cadence data repeated.");
|
||||||
@@ -167,21 +178,21 @@ public class BluetoothRemoteSensorManager implements BluetoothConnectionManager.
|
|||||||
}
|
}
|
||||||
((SensorDataCycling.Cadence) sensorData).compute(previous);
|
((SensorDataCycling.Cadence) sensorData).compute(previous);
|
||||||
}
|
}
|
||||||
if (sensorData instanceof SensorDataCycling.Speed) {
|
if (sensorData instanceof SensorDataCycling.DistanceSpeed) {
|
||||||
SensorDataCycling.Speed previous = sensorDataSet.getCyclingSpeed();
|
SensorDataCycling.DistanceSpeed previous = sensorDataSet.getCyclingDistanceSpeed();
|
||||||
Log.d(TAG, "previous " + previous + "; current" + sensorData);
|
Log.d(TAG, "Previous: " + previous + "; Current" + sensorData);
|
||||||
if (sensorData.equals(previous)) {
|
if (sensorData.equals(previous)) {
|
||||||
Log.d(TAG, "onChanged: speed data repeated.");
|
Log.d(TAG, "onChanged: speed data repeated.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
((SensorDataCycling.Speed) sensorData).compute(previous, PreferencesUtils.getWheelCircumference(context));
|
((SensorDataCycling.DistanceSpeed) sensorData).compute(previous, PreferencesUtils.getWheelCircumference(sharedPreferences, context));
|
||||||
}
|
}
|
||||||
|
|
||||||
sensorDataSet.set(sensorData);
|
sensorDataSet.set(sensorData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisconnecting(SensorData sensorData) {
|
public void onDisconnecting(SensorData<?> sensorData) {
|
||||||
sensorDataSet.remove(sensorData);
|
sensorDataSet.remove(sensorData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-5
@@ -17,17 +17,19 @@
|
|||||||
package de.dennisguse.opentracks.services.tasks;
|
package de.dennisguse.opentracks.services.tasks;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.speech.tts.TextToSpeech;
|
import android.speech.tts.TextToSpeech;
|
||||||
import android.speech.tts.UtteranceProgressListener;
|
import android.speech.tts.UtteranceProgressListener;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.ArrayList;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
|
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
||||||
import de.dennisguse.opentracks.services.TrackRecordingService;
|
import de.dennisguse.opentracks.services.TrackRecordingService;
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
import de.dennisguse.opentracks.util.AnnouncementUtils;
|
import de.dennisguse.opentracks.util.AnnouncementUtils;
|
||||||
@@ -102,6 +104,8 @@ public class AnnouncementPeriodicTask implements PeriodicTask {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private SharedPreferences sharedPreferences;
|
||||||
|
|
||||||
private TextToSpeech tts;
|
private TextToSpeech tts;
|
||||||
// Response from TTS after its initialization
|
// Response from TTS after its initialization
|
||||||
private int ttsInitStatus = TextToSpeech.ERROR;
|
private int ttsInitStatus = TextToSpeech.ERROR;
|
||||||
@@ -112,12 +116,15 @@ public class AnnouncementPeriodicTask implements PeriodicTask {
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
||||||
contentProviderUtils = new ContentProviderUtils(context);
|
contentProviderUtils = new ContentProviderUtils(context);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start() {
|
public void start() {
|
||||||
Log.d(TAG, "Start");
|
Log.d(TAG, "Start");
|
||||||
|
|
||||||
|
sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||||
|
|
||||||
if (tts == null) {
|
if (tts == null) {
|
||||||
tts = new TextToSpeech(context, status -> {
|
tts = new TextToSpeech(context, status -> {
|
||||||
Log.i(TAG, "TextToSpeech initialized with status " + status);
|
Log.i(TAG, "TextToSpeech initialized with status " + status);
|
||||||
@@ -164,14 +171,23 @@ public class AnnouncementPeriodicTask implements PeriodicTask {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Track track = contentProviderUtils.getTrack(PreferencesUtils.getRecordingTrackId(context));
|
Track track = contentProviderUtils.getTrack(PreferencesUtils.getRecordingTrackId(sharedPreferences, context));
|
||||||
String category = track != null ? track.getCategory() : "";
|
String category = track != null ? track.getCategory() : "";
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = contentProviderUtils.getTrackPoints(track.getId());
|
//TODO Querying all TrackPoints all the time is inefficient; use TrackDataHub or something else.
|
||||||
IntervalStatistics intervalStatistics = new IntervalStatistics(trackPoints, (float) (PreferencesUtils.isMetricUnits(context) ? 1d * UnitConversions.KM_TO_M : 1d * UnitConversions.MI_TO_M));
|
TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), null);
|
||||||
|
ArrayList<TrackPoint> trackPoints = new ArrayList<>();
|
||||||
|
while (trackPointIterator.hasNext()) {
|
||||||
|
trackPoints.add(trackPointIterator.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isMetricUnits = PreferencesUtils.isMetricUnits(sharedPreferences, context);
|
||||||
|
boolean isReportSpeed = PreferencesUtils.isReportSpeed(sharedPreferences, context, category);
|
||||||
|
|
||||||
|
IntervalStatistics intervalStatistics = new IntervalStatistics(trackPoints, (float) (isMetricUnits ? 1d * UnitConversions.KM_TO_M : 1d * UnitConversions.MI_TO_M));
|
||||||
IntervalStatistics.Interval lastInterval = intervalStatistics.getLastInterval();
|
IntervalStatistics.Interval lastInterval = intervalStatistics.getLastInterval();
|
||||||
|
|
||||||
String announcement = AnnouncementUtils.getAnnouncement(context, trackStatistics, category, lastInterval);
|
String announcement = AnnouncementUtils.getAnnouncement(context, trackStatistics, isMetricUnits, isReportSpeed, lastInterval);
|
||||||
speakAnnouncement(announcement);
|
speakAnnouncement(announcement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,6 +197,8 @@ public class AnnouncementPeriodicTask implements PeriodicTask {
|
|||||||
tts.shutdown();
|
tts.shutdown();
|
||||||
tts = null;
|
tts = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sharedPreferences = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onTtsReady() {
|
private void onTtsReady() {
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ public class PeriodicTaskExecutor {
|
|||||||
if (timerTaskExecutor == null) {
|
if (timerTaskExecutor == null) {
|
||||||
timerTaskExecutor = new TimerTaskExecutor(periodicTask, trackRecordingService);
|
timerTaskExecutor = new TimerTaskExecutor(periodicTask, trackRecordingService);
|
||||||
}
|
}
|
||||||
timerTaskExecutor.scheduleTask(Duration.ofSeconds(taskFrequency));
|
timerTaskExecutor.scheduleTask(Duration.ofMinutes(taskFrequency));
|
||||||
} else {
|
} else {
|
||||||
// For distance periodic task
|
// For distance periodic task
|
||||||
calculateNextTaskDistance();
|
calculateNextTaskDistance();
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package de.dennisguse.opentracks.settings;
|
package de.dennisguse.opentracks.settings;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -48,7 +49,7 @@ public class ActivityTypePreference extends DialogPreference {
|
|||||||
setDialogIcon(null);
|
setDialogIcon(null);
|
||||||
setPersistent(true);
|
setPersistent(true);
|
||||||
|
|
||||||
SummaryProvider<DialogPreference> summaryProvider = preference -> PreferencesUtils.getDefaultActivity(ActivityTypePreference.this.getContext());
|
SummaryProvider<DialogPreference> summaryProvider = preference -> PreferencesUtils.getDefaultActivity(PreferencesUtils.getSharedPreferences(context), ActivityTypePreference.this.getContext());
|
||||||
setSummaryProvider(summaryProvider);
|
setSummaryProvider(summaryProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,6 +61,8 @@ public class ActivityTypePreference extends DialogPreference {
|
|||||||
|
|
||||||
public static class ActivityPreferenceDialog extends PreferenceDialogFragmentCompat {
|
public static class ActivityPreferenceDialog extends PreferenceDialogFragmentCompat {
|
||||||
|
|
||||||
|
private SharedPreferences sharedPreferences;
|
||||||
|
|
||||||
private AutoCompleteTextView textView;
|
private AutoCompleteTextView textView;
|
||||||
private ImageView iconView;
|
private ImageView iconView;
|
||||||
|
|
||||||
@@ -77,9 +80,11 @@ public class ActivityTypePreference extends DialogPreference {
|
|||||||
super.onBindDialogView(view);
|
super.onBindDialogView(view);
|
||||||
|
|
||||||
final Context context = getActivity();
|
final Context context = getActivity();
|
||||||
|
sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||||
|
|
||||||
|
|
||||||
textView = view.findViewById(R.id.activity_type_preference_text_view);
|
textView = view.findViewById(R.id.activity_type_preference_text_view);
|
||||||
String category = PreferencesUtils.getDefaultActivity(context);
|
String category = PreferencesUtils.getDefaultActivity(sharedPreferences, context);
|
||||||
textView.setText(category);
|
textView.setText(category);
|
||||||
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(context, R.array.activity_types, android.R.layout.simple_dropdown_item_1line);
|
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(context, R.array.activity_types, android.R.layout.simple_dropdown_item_1line);
|
||||||
textView.setAdapter(adapter);
|
textView.setAdapter(adapter);
|
||||||
@@ -100,8 +105,14 @@ public class ActivityTypePreference extends DialogPreference {
|
|||||||
updateIcon(TrackIconUtils.getIconValue(context, category));
|
updateIcon(TrackIconUtils.getIconValue(context, category));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
sharedPreferences = null;
|
||||||
|
}
|
||||||
|
|
||||||
private void showIconSelectDialog() {
|
private void showIconSelectDialog() {
|
||||||
String category = PreferencesUtils.getDefaultActivity(getActivity());
|
String category = PreferencesUtils.getDefaultActivity(sharedPreferences, getActivity());
|
||||||
ChooseActivityTypeDialogFragment.showDialog(getActivity().getSupportFragmentManager(), category);
|
ChooseActivityTypeDialogFragment.showDialog(getActivity().getSupportFragmentManager(), category);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +121,7 @@ public class ActivityTypePreference extends DialogPreference {
|
|||||||
if (positiveResult) {
|
if (positiveResult) {
|
||||||
String newDefaultActivity = textView.getText().toString();
|
String newDefaultActivity = textView.getText().toString();
|
||||||
if (getPreference().callChangeListener(newDefaultActivity)) {
|
if (getPreference().callChangeListener(newDefaultActivity)) {
|
||||||
PreferencesUtils.setDefaultActivity(getActivity(), newDefaultActivity);
|
PreferencesUtils.setDefaultActivity(sharedPreferences, getActivity(), newDefaultActivity);
|
||||||
HackUtils.invalidatePreference(getPreference());
|
HackUtils.invalidatePreference(getPreference());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,7 +91,9 @@ public class SettingsActivity extends AbstractActivity implements ChooseActivity
|
|||||||
|
|
||||||
public static class PrefsFragment extends PreferenceFragmentCompat {
|
public static class PrefsFragment extends PreferenceFragmentCompat {
|
||||||
|
|
||||||
private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (preferences, key) -> {
|
private SharedPreferences sharedPreferences;
|
||||||
|
|
||||||
|
private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (sharedPreferences, key) -> {
|
||||||
if (PreferencesUtils.isKey(getActivity(), R.string.recording_track_id_key, key)) {
|
if (PreferencesUtils.isKey(getActivity(), R.string.recording_track_id_key, key)) {
|
||||||
getActivity().runOnUiThread(this::updateReset);
|
getActivity().runOnUiThread(this::updateReset);
|
||||||
}
|
}
|
||||||
@@ -99,7 +101,7 @@ public class SettingsActivity extends AbstractActivity implements ChooseActivity
|
|||||||
getActivity().runOnUiThread(this::updateUnits);
|
getActivity().runOnUiThread(this::updateUnits);
|
||||||
}
|
}
|
||||||
if (PreferencesUtils.isKey(getActivity(), R.string.night_mode_key, key)) {
|
if (PreferencesUtils.isKey(getActivity(), R.string.night_mode_key, key)) {
|
||||||
getActivity().runOnUiThread(() -> ActivityUtils.applyNightMode(getContext()));
|
getActivity().runOnUiThread(() -> ActivityUtils.applyNightMode(sharedPreferences, getContext()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -108,6 +110,8 @@ public class SettingsActivity extends AbstractActivity implements ChooseActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||||
|
sharedPreferences = PreferencesUtils.getSharedPreferences(getContext());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setPreferencesFromResource(R.xml.settings, rootKey);
|
setPreferencesFromResource(R.xml.settings, rootKey);
|
||||||
} catch (ClassCastException e) {
|
} catch (ClassCastException e) {
|
||||||
@@ -123,7 +127,7 @@ public class SettingsActivity extends AbstractActivity implements ChooseActivity
|
|||||||
|
|
||||||
Preference instantExportDirectoryPreference = findPreference(getString(R.string.settings_default_export_directory_key));
|
Preference instantExportDirectoryPreference = findPreference(getString(R.string.settings_default_export_directory_key));
|
||||||
instantExportDirectoryPreference.setSummaryProvider(preference -> {
|
instantExportDirectoryPreference.setSummaryProvider(preference -> {
|
||||||
DocumentFile directory = PreferencesUtils.getDefaultExportDirectoryUri(getContext());
|
DocumentFile directory = PreferencesUtils.getDefaultExportDirectoryUri(sharedPreferences, getContext());
|
||||||
//Use same value for not set as Androidx ListPreference and EditTextPreference
|
//Use same value for not set as Androidx ListPreference and EditTextPreference
|
||||||
return directory != null ? directory.getName() : getString(R.string.not_set);
|
return directory != null ? directory.getName() : getString(R.string.not_set);
|
||||||
});
|
});
|
||||||
@@ -132,7 +136,10 @@ public class SettingsActivity extends AbstractActivity implements ChooseActivity
|
|||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
PreferencesUtils.getSharedPreferences(getActivity()).registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
|
||||||
|
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
||||||
|
sharedPreferenceChangeListener.onSharedPreferenceChanged(sharedPreferences, null);
|
||||||
|
|
||||||
updateUnits();
|
updateUnits();
|
||||||
updateReset();
|
updateReset();
|
||||||
updateBluetooth();
|
updateBluetooth();
|
||||||
@@ -142,13 +149,13 @@ public class SettingsActivity extends AbstractActivity implements ChooseActivity
|
|||||||
|
|
||||||
private void updatePostWorkoutExport() {
|
private void updatePostWorkoutExport() {
|
||||||
Preference instantExportEnabledPreference = findPreference(getString(R.string.post_workout_export_enabled_key));
|
Preference instantExportEnabledPreference = findPreference(getString(R.string.post_workout_export_enabled_key));
|
||||||
instantExportEnabledPreference.setEnabled(PreferencesUtils.isDefaultExportDirectoryUri(getContext()));
|
instantExportEnabledPreference.setEnabled(PreferencesUtils.isDefaultExportDirectoryUri(sharedPreferences, getContext()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
PreferencesUtils.getSharedPreferences(getActivity()).unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -176,6 +183,12 @@ public class SettingsActivity extends AbstractActivity implements ChooseActivity
|
|||||||
super.onDisplayPreferenceDialog(preference);
|
super.onDisplayPreferenceDialog(preference);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
sharedPreferences = null;
|
||||||
|
}
|
||||||
|
|
||||||
public void setDefaultActivity(String iconValue) {
|
public void setDefaultActivity(String iconValue) {
|
||||||
if (activityPreferenceDialog != null) {
|
if (activityPreferenceDialog != null) {
|
||||||
activityPreferenceDialog.updateUI(iconValue);
|
activityPreferenceDialog.updateUI(iconValue);
|
||||||
@@ -183,7 +196,7 @@ public class SettingsActivity extends AbstractActivity implements ChooseActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateReset() {
|
private void updateReset() {
|
||||||
final boolean isRecording = PreferencesUtils.isRecording(getActivity());
|
final boolean isRecording = PreferencesUtils.isRecording(sharedPreferences, getActivity());
|
||||||
Preference resetPreference = findPreference(getString(R.string.settings_reset_key));
|
Preference resetPreference = findPreference(getString(R.string.settings_reset_key));
|
||||||
resetPreference.setSummary(isRecording ? getString(R.string.settings_not_while_recording) : "");
|
resetPreference.setSummary(isRecording ? getString(R.string.settings_not_while_recording) : "");
|
||||||
resetPreference.setEnabled(!isRecording);
|
resetPreference.setEnabled(!isRecording);
|
||||||
@@ -196,7 +209,7 @@ public class SettingsActivity extends AbstractActivity implements ChooseActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateUnits() {
|
private void updateUnits() {
|
||||||
boolean metricUnits = PreferencesUtils.isMetricUnits(getActivity());
|
boolean metricUnits = PreferencesUtils.isMetricUnits(sharedPreferences, getActivity());
|
||||||
|
|
||||||
ListPreference voiceFrequency = findPreference(getString(R.string.voice_frequency_key));
|
ListPreference voiceFrequency = findPreference(getString(R.string.voice_frequency_key));
|
||||||
voiceFrequency.setEntries(StringUtils.getFrequencyOptions(getActivity(), metricUnits));
|
voiceFrequency.setEntries(StringUtils.getFrequencyOptions(getActivity(), metricUnits));
|
||||||
|
|||||||
@@ -104,9 +104,14 @@ public class TrackStatisticsUpdater {
|
|||||||
* Adds a trackPoint.
|
* Adds a trackPoint.
|
||||||
*
|
*
|
||||||
* @param trackPoint the trackPoint
|
* @param trackPoint the trackPoint
|
||||||
* @param minRecordingDistance the min recording distance
|
* @param minGPSDistance the min recording distance
|
||||||
*/
|
*/
|
||||||
public void addTrackPoint(TrackPoint trackPoint, int minRecordingDistance) {
|
public void addTrackPoint(TrackPoint trackPoint, int minGPSDistance) {
|
||||||
|
internalAddTrackPoint(trackPoint, minGPSDistance);
|
||||||
|
Log.d(TAG, this.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void internalAddTrackPoint(TrackPoint trackPoint, int minGPSDistance) {
|
||||||
if (!trackInitialized) {
|
if (!trackInitialized) {
|
||||||
trackStatistics.setStartTime(trackPoint.getTime());
|
trackStatistics.setStartTime(trackPoint.getTime());
|
||||||
trackInitialized = true;
|
trackInitialized = true;
|
||||||
@@ -120,19 +125,26 @@ public class TrackStatisticsUpdater {
|
|||||||
currentSegment.setStopTime(trackPoint.getTime());
|
currentSegment.setStopTime(trackPoint.getTime());
|
||||||
currentSegment.setTotalTime(Duration.between(currentSegment.getStartTime(), trackPoint.getTime()));
|
currentSegment.setTotalTime(Duration.between(currentSegment.getStartTime(), trackPoint.getTime()));
|
||||||
|
|
||||||
if (trackPoint.isSegmentStart() || trackPoint.isSegmentEnd()) {
|
if (trackPoint.isSegmentStart()) {
|
||||||
if (trackPoint.isSegmentEnd()) {
|
reset(trackPoint);
|
||||||
if (lastTrackPoint != null && lastMovingTrackPoint != null && lastTrackPoint != lastMovingTrackPoint) {
|
return;
|
||||||
currentSegment.addTotalDistance(lastMovingTrackPoint.distanceTo(lastTrackPoint));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
trackStatistics.merge(currentSegment);
|
|
||||||
currentSegment.reset(trackPoint.getTime());
|
|
||||||
|
|
||||||
lastTrackPoint = null;
|
// Process sensor data
|
||||||
lastMovingTrackPoint = null;
|
if (trackPoint.hasElevationGain()) {
|
||||||
elevationBuffer_m.reset();
|
currentSegment.addTotalElevationGain(trackPoint.getElevationGain());
|
||||||
speedBuffer_ms.reset();
|
}
|
||||||
|
|
||||||
|
if (trackPoint.hasElevationLoss()) {
|
||||||
|
currentSegment.addTotalElevationLoss(trackPoint.getElevationLoss());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trackPoint.hasSensorDistance()) {
|
||||||
|
currentSegment.addTotalDistance(trackPoint.getSensorDistance());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trackPoint.isSegmentEnd()) {
|
||||||
|
reset(trackPoint);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,39 +153,30 @@ public class TrackStatisticsUpdater {
|
|||||||
updateAbsoluteElevation(trackPoint.getAltitude());
|
updateAbsoluteElevation(trackPoint.getAltitude());
|
||||||
}
|
}
|
||||||
|
|
||||||
//Get elevation gain
|
|
||||||
if (trackPoint.hasElevationGain()) {
|
|
||||||
currentSegment.addTotalElevationGain(trackPoint.getElevationGain());
|
|
||||||
Log.d(TAG, "elevation gain: " + trackPoint.getElevationGain());
|
|
||||||
}
|
|
||||||
|
|
||||||
//Get elevation loss
|
|
||||||
if (trackPoint.hasElevationLoss()) {
|
|
||||||
currentSegment.addTotalElevationLoss(trackPoint.getElevationLoss());
|
|
||||||
Log.d(TAG, "elevation loss: " + trackPoint.getElevationLoss());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastTrackPoint == null || lastMovingTrackPoint == null) {
|
if (lastTrackPoint == null || lastMovingTrackPoint == null) {
|
||||||
lastTrackPoint = trackPoint;
|
lastTrackPoint = trackPoint;
|
||||||
lastMovingTrackPoint = trackPoint;
|
lastMovingTrackPoint = trackPoint;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
double movingDistance = lastMovingTrackPoint.distanceTo(trackPoint);
|
if (!trackPoint.hasSensorDistance()) {
|
||||||
if (movingDistance < minRecordingDistance && !trackPoint.isMoving()) {
|
// GPS-based distance/speed
|
||||||
|
float movingDistance = lastMovingTrackPoint.distanceToPrevious(trackPoint);
|
||||||
|
if (movingDistance < minGPSDistance && !trackPoint.isMoving()) {
|
||||||
speedBuffer_ms.reset();
|
speedBuffer_ms.reset();
|
||||||
lastTrackPoint = trackPoint;
|
lastTrackPoint = trackPoint;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Update total distance
|
||||||
|
currentSegment.addTotalDistance(movingDistance);
|
||||||
|
}
|
||||||
|
|
||||||
Duration movingTime = Duration.between(lastTrackPoint.getTime(), trackPoint.getTime());
|
Duration movingTime = Duration.between(lastTrackPoint.getTime(), trackPoint.getTime());
|
||||||
if (movingTime.isNegative()) {
|
if (movingTime.isNegative()) {
|
||||||
lastTrackPoint = trackPoint;
|
lastTrackPoint = trackPoint;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update total distance
|
|
||||||
currentSegment.addTotalDistance(movingDistance);
|
|
||||||
|
|
||||||
// Update moving time
|
// Update moving time
|
||||||
currentSegment.addMovingTime(movingTime);
|
currentSegment.addMovingTime(movingTime);
|
||||||
|
|
||||||
@@ -186,6 +189,16 @@ public class TrackStatisticsUpdater {
|
|||||||
lastMovingTrackPoint = trackPoint;
|
lastMovingTrackPoint = trackPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void reset(TrackPoint trackPoint) {
|
||||||
|
trackStatistics.merge(currentSegment);
|
||||||
|
currentSegment.reset(trackPoint.getTime());
|
||||||
|
|
||||||
|
lastTrackPoint = null;
|
||||||
|
lastMovingTrackPoint = null;
|
||||||
|
elevationBuffer_m.reset();
|
||||||
|
speedBuffer_ms.reset();
|
||||||
|
}
|
||||||
|
|
||||||
public void addTrackPoint(TrackPointIterator iterator, int minRecordingDistance) {
|
public void addTrackPoint(TrackPointIterator iterator, int minRecordingDistance) {
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
TrackPoint location = iterator.next();
|
TrackPoint location = iterator.next();
|
||||||
@@ -224,20 +237,14 @@ public class TrackStatisticsUpdater {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates an elevation reading.
|
* Updates an elevation reading.
|
||||||
*
|
|
||||||
* @param elevation the elevation
|
|
||||||
* @return the difference
|
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
private void updateAbsoluteElevation(double elevation) {
|
||||||
private double updateAbsoluteElevation(double elevation) {
|
|
||||||
// Update elevation using the smoothed average
|
// Update elevation using the smoothed average
|
||||||
double oldAverage = elevationBuffer_m.getAverage();
|
double oldAverage = elevationBuffer_m.getAverage();
|
||||||
elevationBuffer_m.setNext(elevation);
|
elevationBuffer_m.setNext(elevation);
|
||||||
double newAverage = elevationBuffer_m.getAverage();
|
double newAverage = elevationBuffer_m.getAverage();
|
||||||
|
|
||||||
currentSegment.updateElevationExtremities(newAverage);
|
currentSegment.updateElevationExtremities(newAverage);
|
||||||
|
|
||||||
return newAverage - oldAverage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isValidSpeed(@NonNull TrackPoint trackPoint, @NonNull TrackPoint lastTrackPoint) {
|
private boolean isValidSpeed(@NonNull TrackPoint trackPoint, @NonNull TrackPoint lastTrackPoint) {
|
||||||
@@ -267,4 +274,11 @@ public class TrackStatisticsUpdater {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "TrackStatisticsUpdater{" +
|
||||||
|
"trackStatistics=" + trackStatistics +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package de.dennisguse.opentracks.util;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.SearchManager;
|
import android.app.SearchManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.VibrationEffect;
|
import android.os.VibrationEffect;
|
||||||
import android.os.Vibrator;
|
import android.os.Vibrator;
|
||||||
@@ -150,7 +151,7 @@ public class ActivityUtils {
|
|||||||
toast.show();
|
toast.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void applyNightMode(Context context) {
|
public static void applyNightMode(SharedPreferences sharedPreferences, Context context) {
|
||||||
AppCompatDelegate.setDefaultNightMode(PreferencesUtils.getDefaultNightMode(context));
|
AppCompatDelegate.setDefaultNightMode(PreferencesUtils.getDefaultNightMode(sharedPreferences, context));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,7 @@ public class AnnouncementUtils {
|
|||||||
private AnnouncementUtils() {
|
private AnnouncementUtils() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getAnnouncement(Context context, TrackStatistics trackStatistics, String category, @Nullable IntervalStatistics.Interval currentInterval) {
|
public static String getAnnouncement(Context context, TrackStatistics trackStatistics, boolean isMetricUnits, boolean isReportSpeed, @Nullable IntervalStatistics.Interval currentInterval) {
|
||||||
boolean metricUnits = PreferencesUtils.isMetricUnits(context);
|
|
||||||
boolean reportSpeed = PreferencesUtils.isReportSpeed(context, category);
|
|
||||||
double distance = trackStatistics.getTotalDistance() * UnitConversions.M_TO_KM;
|
double distance = trackStatistics.getTotalDistance() * UnitConversions.M_TO_KM;
|
||||||
double distancePerTime = trackStatistics.getAverageMovingSpeed() * UnitConversions.MPS_TO_KMH;
|
double distancePerTime = trackStatistics.getAverageMovingSpeed() * UnitConversions.MPS_TO_KMH;
|
||||||
double currentDistancePerTime = currentInterval != null ? currentInterval.getSpeed_ms() * UnitConversions.MPS_TO_KMH : 0;
|
double currentDistancePerTime = currentInterval != null ? currentInterval.getSpeed_ms() * UnitConversions.MPS_TO_KMH : 0;
|
||||||
@@ -26,7 +24,7 @@ public class AnnouncementUtils {
|
|||||||
return context.getString(R.string.voice_total_distance_zero);
|
return context.getString(R.string.voice_total_distance_zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!metricUnits) {
|
if (!isMetricUnits) {
|
||||||
distance *= UnitConversions.KM_TO_MI;
|
distance *= UnitConversions.KM_TO_MI;
|
||||||
distancePerTime *= UnitConversions.KM_TO_MI;
|
distancePerTime *= UnitConversions.KM_TO_MI;
|
||||||
currentDistancePerTime *= UnitConversions.KM_TO_MI;
|
currentDistancePerTime *= UnitConversions.KM_TO_MI;
|
||||||
@@ -35,15 +33,15 @@ public class AnnouncementUtils {
|
|||||||
String rate;
|
String rate;
|
||||||
String currentRate;
|
String currentRate;
|
||||||
String currentRateMsg;
|
String currentRateMsg;
|
||||||
if (reportSpeed) {
|
if (isReportSpeed) {
|
||||||
int speedId = metricUnits ? R.plurals.voiceSpeedKilometersPerHour : R.plurals.voiceSpeedMilesPerHour;
|
int speedId = isMetricUnits ? R.plurals.voiceSpeedKilometersPerHour : R.plurals.voiceSpeedMilesPerHour;
|
||||||
rate = context.getResources().getQuantityString(speedId, getQuantityCount(distancePerTime), distancePerTime);
|
rate = context.getResources().getQuantityString(speedId, getQuantityCount(distancePerTime), distancePerTime);
|
||||||
|
|
||||||
currentRate = context.getResources().getQuantityString(speedId, getQuantityCount(currentDistancePerTime), currentDistancePerTime);
|
currentRate = context.getResources().getQuantityString(speedId, getQuantityCount(currentDistancePerTime), currentDistancePerTime);
|
||||||
currentRateMsg = context.getString(R.string.voice_speed_lap, currentRate);
|
currentRateMsg = context.getString(R.string.voice_speed_lap, currentRate);
|
||||||
} else {
|
} else {
|
||||||
double timePerDistance = distancePerTime == 0 ? 0.0 : 1 / distancePerTime;
|
double timePerDistance = distancePerTime == 0 ? 0.0 : 1 / distancePerTime;
|
||||||
int paceId = metricUnits ? R.string.voice_pace_per_kilometer : R.string.voice_pace_per_mile;
|
int paceId = isMetricUnits ? R.string.voice_pace_per_kilometer : R.string.voice_pace_per_mile;
|
||||||
Duration time = Duration.ofMillis((long) (timePerDistance * UnitConversions.HR_TO_MIN * UnitConversions.MIN_TO_S * UnitConversions.S_TO_MS));
|
Duration time = Duration.ofMillis((long) (timePerDistance * UnitConversions.HR_TO_MIN * UnitConversions.MIN_TO_S * UnitConversions.S_TO_MS));
|
||||||
rate = context.getString(paceId, getAnnounceTime(context, time));
|
rate = context.getString(paceId, getAnnounceTime(context, time));
|
||||||
|
|
||||||
@@ -53,7 +51,7 @@ public class AnnouncementUtils {
|
|||||||
currentRateMsg = context.getString(R.string.voice_pace_lap, currentRate);
|
currentRateMsg = context.getString(R.string.voice_pace_lap, currentRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
int totalDistanceId = metricUnits ? R.plurals.voiceTotalDistanceKilometers : R.plurals.voiceTotalDistanceMiles;
|
int totalDistanceId = isMetricUnits ? R.plurals.voiceTotalDistanceKilometers : R.plurals.voiceTotalDistanceMiles;
|
||||||
String totalDistance = context.getResources().getQuantityString(totalDistanceId, getQuantityCount(distance), distance);
|
String totalDistance = context.getResources().getQuantityString(totalDistanceId, getQuantityCount(distance), distance);
|
||||||
|
|
||||||
currentRateMsg = currentInterval == null ? "" : " " + currentRateMsg;
|
currentRateMsg = currentInterval == null ? "" : " " + currentRateMsg;
|
||||||
@@ -65,8 +63,8 @@ public class AnnouncementUtils {
|
|||||||
private static String getAnnounceTime(Context context, Duration duration) {
|
private static String getAnnounceTime(Context context, Duration duration) {
|
||||||
String result = "";
|
String result = "";
|
||||||
|
|
||||||
int hours = (int) (duration.getSeconds() / (60 * 60));
|
int hours = (int) (duration.toHours());
|
||||||
int minutes = (int) (duration.getSeconds() / 60);
|
int minutes = (int) (duration.toMinutes() % 60);
|
||||||
int seconds = (int) (duration.getSeconds() % 60);
|
int seconds = (int) (duration.getSeconds() % 60);
|
||||||
|
|
||||||
if (hours != 0) {
|
if (hours != 0) {
|
||||||
|
|||||||
@@ -126,12 +126,12 @@ public class BluetoothUtils {
|
|||||||
cadence = new SensorDataCycling.Cadence(address, sensorName, crankCount, crankTime);
|
cadence = new SensorDataCycling.Cadence(address, sensorName, crankCount, crankTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
SensorDataCycling.Speed speed = null;
|
SensorDataCycling.DistanceSpeed speed = null;
|
||||||
if (hasWheel && valueLength - index >= 4) {
|
if (hasWheel && valueLength - index >= 4) {
|
||||||
int wheelCount = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, index);
|
int wheelCount = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, index);
|
||||||
index += 2;
|
index += 2;
|
||||||
int wheelTime = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, index); // 1/1024s
|
int wheelTime = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, index); // 1/1024s
|
||||||
speed = new SensorDataCycling.Speed(address, sensorName, wheelCount, wheelTime);
|
speed = new SensorDataCycling.DistanceSpeed(address, sensorName, wheelCount, wheelTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new SensorDataCycling.CadenceAndSpeed(address, sensorName, cadence, speed);
|
return new SensorDataCycling.CadenceAndSpeed(address, sensorName, cadence, speed);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package de.dennisguse.opentracks.util;
|
|||||||
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.provider.DocumentsContract;
|
import android.provider.DocumentsContract;
|
||||||
@@ -14,6 +15,8 @@ import java.io.IOException;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||||
@@ -26,9 +29,10 @@ public class ExportUtils {
|
|||||||
private static final String TAG = ExportUtils.class.getSimpleName();
|
private static final String TAG = ExportUtils.class.getSimpleName();
|
||||||
|
|
||||||
public static void postWorkoutExport(Context context, Track track, ExportServiceResultReceiver resultReceiver) {
|
public static void postWorkoutExport(Context context, Track track, ExportServiceResultReceiver resultReceiver) {
|
||||||
if (PreferencesUtils.shouldInstantExportAfterWorkout(context)) {
|
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||||
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(context);
|
if (PreferencesUtils.shouldInstantExportAfterWorkout(sharedPreferences, context)) {
|
||||||
DocumentFile directory = PreferencesUtils.getDefaultExportDirectoryUri(context);
|
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(sharedPreferences, context);
|
||||||
|
DocumentFile directory = PreferencesUtils.getDefaultExportDirectoryUri(sharedPreferences, context);
|
||||||
|
|
||||||
ExportService.enqueue(context, resultReceiver, track.getId(), trackFileFormat, directory.getUri());
|
ExportService.enqueue(context, resultReceiver, track.getId(), trackFileFormat, directory.getUri());
|
||||||
}
|
}
|
||||||
@@ -37,7 +41,7 @@ public class ExportUtils {
|
|||||||
public static boolean exportTrack(Context context, TrackFileFormat trackFileFormat, DocumentFile directory, Track track) {
|
public static boolean exportTrack(Context context, TrackFileFormat trackFileFormat, DocumentFile directory, Track track) {
|
||||||
TrackExporter trackExporter = trackFileFormat.createTrackExporter(context);
|
TrackExporter trackExporter = trackFileFormat.createTrackExporter(context);
|
||||||
|
|
||||||
Uri exportDocumentFileUri = getExportDocumentFileUri(context, track.getId(), trackFileFormat, directory);
|
Uri exportDocumentFileUri = getExportDocumentFileUri(context, track, trackFileFormat, directory);
|
||||||
if (exportDocumentFileUri == null) {
|
if (exportDocumentFileUri == null) {
|
||||||
Log.e(TAG, "Couldn't create document file for export");
|
Log.e(TAG, "Couldn't create document file for export");
|
||||||
return false;
|
return false;
|
||||||
@@ -62,8 +66,10 @@ public class ExportUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isExportFileExists(Track.Id trackId, String trackFileFormatExtension, List<String> filesName) {
|
public static boolean isExportFileExists(UUID uuuid, String trackFileFormatExtension, List<String> filesName) {
|
||||||
return filesName.contains(getExportFileNameByTrackId(trackId, trackFileFormatExtension));
|
String word = uuuid.toString().substring(0, 8) + ".*\\." + trackFileFormatExtension;
|
||||||
|
Pattern pattern = Pattern.compile(word);
|
||||||
|
return filesName.stream().anyMatch(w -> pattern.matcher(w).matches());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<String> getAllFiles(Context context, Uri directoryUri) {
|
public static List<String> getAllFiles(Context context, Uri directoryUri) {
|
||||||
@@ -82,8 +88,8 @@ public class ExportUtils {
|
|||||||
return fileNames;
|
return fileNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Uri getExportDocumentFileUri(Context context, Track.Id trackId, TrackFileFormat trackFileFormat, DocumentFile directory) {
|
private static Uri getExportDocumentFileUri(Context context, Track track, TrackFileFormat trackFileFormat, DocumentFile directory) {
|
||||||
String exportFileName = getExportFileNameByTrackId(trackId, trackFileFormat.getExtension());
|
String exportFileName = getExportFileNameForTrack(track, trackFileFormat.getExtension());
|
||||||
Uri exportDocumentFileUri = findFile(context, directory.getUri(), exportFileName);
|
Uri exportDocumentFileUri = findFile(context, directory.getUri(), exportFileName);
|
||||||
if (exportDocumentFileUri == null) {
|
if (exportDocumentFileUri == null) {
|
||||||
final DocumentFile file = directory.createFile(trackFileFormat.getMimeType(), exportFileName);
|
final DocumentFile file = directory.createFile(trackFileFormat.getMimeType(), exportFileName);
|
||||||
@@ -94,8 +100,8 @@ public class ExportUtils {
|
|||||||
return exportDocumentFileUri;
|
return exportDocumentFileUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getExportFileNameByTrackId(Track.Id trackId, String trackFileFormatExtension) {
|
private static String getExportFileNameForTrack(Track track, String trackFileFormatExtension) {
|
||||||
return trackId.getId() + "." + trackFileFormatExtension;
|
return track.getUuid().toString().substring(0, 8) + "_" + track.getName() + "." + trackFileFormatExtension;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Uri findFile(Context context, Uri directoryUri, String exportFileName) {
|
private static Uri findFile(Context context, Uri directoryUri, String exportFileName) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package de.dennisguse.opentracks.util;
|
|||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
@@ -73,11 +74,13 @@ public class IntentDashboardUtils {
|
|||||||
|
|
||||||
intent.putParcelableArrayListExtra(ACTION_DASHBOARD_PAYLOAD, uris);
|
intent.putParcelableArrayListExtra(ACTION_DASHBOARD_PAYLOAD, uris);
|
||||||
|
|
||||||
intent.putExtra(EXTRAS_SHOULD_KEEP_SCREEN_ON, PreferencesUtils.shouldKeepScreenOn(context));
|
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||||
intent.putExtra(EXTRAS_SHOW_WHEN_LOCKED, PreferencesUtils.shouldShowStatsOnLockscreen(context));
|
|
||||||
|
intent.putExtra(EXTRAS_SHOULD_KEEP_SCREEN_ON, PreferencesUtils.shouldKeepScreenOn(sharedPreferences, context));
|
||||||
|
intent.putExtra(EXTRAS_SHOW_WHEN_LOCKED, PreferencesUtils.shouldShowStatsOnLockscreen(sharedPreferences, context));
|
||||||
intent.putExtra(EXTRAS_OPENTRACKS_IS_RECORDING_THIS_TRACK, isRecording);
|
intent.putExtra(EXTRAS_OPENTRACKS_IS_RECORDING_THIS_TRACK, isRecording);
|
||||||
if (isRecording) {
|
if (isRecording) {
|
||||||
intent.putExtra(EXTRAS_SHOW_FULLSCREEN, PreferencesUtils.shouldUseFullscreen(context));
|
intent.putExtra(EXTRAS_SHOW_FULLSCREEN, PreferencesUtils.shouldUseFullscreen(sharedPreferences, context));
|
||||||
}
|
}
|
||||||
|
|
||||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ public class IntentUtils {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pair<Uri, String> uriAndMime = ShareContentProvider.createURI(trackId, track.getName(), PreferencesUtils.getExportTrackFileFormat(context));
|
Pair<Uri, String> uriAndMime = ShareContentProvider.createURI(trackId, track.getName(), PreferencesUtils.getExportTrackFileFormat(PreferencesUtils.getSharedPreferences(context), context));
|
||||||
uris.add(uriAndMime.first);
|
uris.add(uriAndMime.first);
|
||||||
mime = uriAndMime.second;
|
mime = uriAndMime.second;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,37 +42,32 @@ public class PreferencesUtils {
|
|||||||
private PreferencesUtils() {
|
private PreferencesUtils() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated //Should only be used to get a sharedPreference for more than one interaction!
|
||||||
public static SharedPreferences getSharedPreferences(Context context) {
|
public static SharedPreferences getSharedPreferences(Context context) {
|
||||||
return PreferenceManager.getDefaultSharedPreferences(context);
|
return PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SharedPreferences register(Context context, SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener) {
|
|
||||||
SharedPreferences sharedPreferences = getSharedPreferences(context);
|
|
||||||
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
|
||||||
return sharedPreferences;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void unregister(Context context, SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener) {
|
|
||||||
getSharedPreferences(context).unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
//NOTE: is at the moment still used to determine if a track is currently recorded; better ask the service directly.
|
//NOTE: is at the moment still used to determine if a track is currently recorded; better ask the service directly.
|
||||||
//NOTE: This was also used to recover from a service restart, but this data should not be exposed to the whole application.
|
//NOTE: This was also used to recover from a service restart, but this data should not be exposed to the whole application.
|
||||||
public static final long RECORDING_TRACK_ID_DEFAULT = -1L;
|
public static final long RECORDING_TRACK_ID_DEFAULT = -1L;
|
||||||
|
|
||||||
@Deprecated //Use the TrackRecordingService
|
@Deprecated //Use the TrackRecordingService
|
||||||
public static Track.Id getRecordingTrackId(Context context) {
|
public static Track.Id getRecordingTrackId(Context context, SharedPreferences sharedPreferences) {
|
||||||
SharedPreferences sharedPreferences = getSharedPreferences(context);
|
|
||||||
return new Track.Id(sharedPreferences.getLong(getKey(context, R.string.recording_track_id_key), RECORDING_TRACK_ID_DEFAULT));
|
return new Track.Id(sharedPreferences.getLong(getKey(context, R.string.recording_track_id_key), RECORDING_TRACK_ID_DEFAULT));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getDefaultActivity(Context context) {
|
@Deprecated //Use the TrackRecordingService
|
||||||
return getString(context, R.string.default_activity_key, context.getString(R.string.default_activity_default));
|
public static Track.Id getRecordingTrackId(SharedPreferences sharedPreferences, Context context) {
|
||||||
|
return getRecordingTrackId(context, sharedPreferences);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setDefaultActivity(Context context, String newDefaultActivity) {
|
public static String getDefaultActivity(SharedPreferences sharedPreferences, Context context) {
|
||||||
setString(context, R.string.default_activity_key, newDefaultActivity);
|
return getString(sharedPreferences, context, R.string.default_activity_key, context.getString(R.string.default_activity_default));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setDefaultActivity(SharedPreferences sharedPreferences, Context context, String newDefaultActivity) {
|
||||||
|
setString(sharedPreferences, context, R.string.default_activity_key, newDefaultActivity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -96,48 +91,19 @@ public class PreferencesUtils {
|
|||||||
return key == null || key.equals(getKey(context, keyId));
|
return key == null || key.equals(getKey(context, keyId));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static boolean getBoolean(SharedPreferences sharedPreferences, Context context, int keyId, boolean defaultValue) {
|
||||||
* Gets a boolean preference value.
|
|
||||||
*
|
|
||||||
* @param context the context
|
|
||||||
* @param keyId the key id
|
|
||||||
* @param defaultValue the default value
|
|
||||||
*/
|
|
||||||
private static boolean getBoolean(Context context, int keyId, boolean defaultValue) {
|
|
||||||
SharedPreferences sharedPreferences = getSharedPreferences(context);
|
|
||||||
return sharedPreferences.getBoolean(getKey(context, keyId), defaultValue);
|
return sharedPreferences.getBoolean(getKey(context, keyId), defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean getBoolean(Context context, SharedPreferences sharedPreferences, int keyId, boolean defaultValue) {
|
|
||||||
return sharedPreferences.getBoolean(getKey(context, keyId), defaultValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a boolean preference value.
|
|
||||||
*
|
|
||||||
* @param context the context
|
|
||||||
* @param keyId the key id
|
|
||||||
* @param value the value
|
|
||||||
*/
|
|
||||||
//TODO Don't use; this function is only to be used TrackRecordingService and will be removed.
|
//TODO Don't use; this function is only to be used TrackRecordingService and will be removed.
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public static void setBoolean(Context context, int keyId, boolean value) {
|
public static void setBoolean(SharedPreferences sharedPreferences, Context context, int keyId, boolean value) {
|
||||||
SharedPreferences sharedPreferences = getSharedPreferences(context);
|
|
||||||
Editor editor = sharedPreferences.edit();
|
Editor editor = sharedPreferences.edit();
|
||||||
editor.putBoolean(getKey(context, keyId), value);
|
editor.putBoolean(getKey(context, keyId), value);
|
||||||
editor.apply();
|
editor.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static int getInt(SharedPreferences sharedPreferences, Context context, int keyId, int defaultValue) {
|
||||||
* Gets an integer preference value.
|
|
||||||
*
|
|
||||||
* @param context the context
|
|
||||||
* @param keyId the key id
|
|
||||||
* @param defaultValue the default value
|
|
||||||
*/
|
|
||||||
private static int getInt(Context context, int keyId, int defaultValue) {
|
|
||||||
SharedPreferences sharedPreferences = getSharedPreferences(context);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return sharedPreferences.getInt(getKey(context, keyId), defaultValue);
|
return sharedPreferences.getInt(getKey(context, keyId), defaultValue);
|
||||||
} catch (ClassCastException e) {
|
} catch (ClassCastException e) {
|
||||||
@@ -153,82 +119,42 @@ public class PreferencesUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets an integer preference value.
|
|
||||||
*
|
|
||||||
* @param context the context
|
|
||||||
* @param keyId the key id
|
|
||||||
* @param value the value
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public static void setInt(Context context, int keyId, int value) {
|
public static void setInt(SharedPreferences sharedPreferences, Context context, int keyId, int value) {
|
||||||
SharedPreferences sharedPreferences = getSharedPreferences(context);
|
|
||||||
Editor editor = sharedPreferences.edit();
|
Editor editor = sharedPreferences.edit();
|
||||||
editor.putInt(getKey(context, keyId), value);
|
editor.putInt(getKey(context, keyId), value);
|
||||||
editor.apply();
|
editor.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a long preference value.
|
|
||||||
*
|
|
||||||
* @param context the context
|
|
||||||
* @param keyId the key id
|
|
||||||
* @param value the value
|
|
||||||
*/
|
|
||||||
//TODO Don't use; this function is only to be used TrackRecordingService and will be removed.
|
//TODO Don't use; this function is only to be used TrackRecordingService and will be removed.
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public static void setLong(Context context, int keyId, long value) {
|
public static void setLong(SharedPreferences sharedPreferences, Context context, int keyId, long value) {
|
||||||
SharedPreferences sharedPreferences = getSharedPreferences(context);
|
|
||||||
Editor editor = sharedPreferences.edit();
|
Editor editor = sharedPreferences.edit();
|
||||||
editor.putLong(getKey(context, keyId), value);
|
editor.putLong(getKey(context, keyId), value);
|
||||||
editor.apply();
|
editor.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
public static String getString(SharedPreferences sharedPreferences, Context context, int keyId, String defaultValue) {
|
||||||
public static String getString(Context context, int keyId, String defaultValue) {
|
|
||||||
SharedPreferences sharedPreferences = getSharedPreferences(context);
|
|
||||||
return sharedPreferences.getString(getKey(context, keyId), defaultValue);
|
return sharedPreferences.getString(getKey(context, keyId), defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getString(Context context, SharedPreferences sharedPreferences, int keyId, String defaultValue) {
|
|
||||||
return sharedPreferences.getString(getKey(context, keyId), defaultValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a string preference value.
|
|
||||||
*
|
|
||||||
* @param context the context
|
|
||||||
* @param keyId the key id
|
|
||||||
* @param value the value
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public static void setString(Context context, int keyId, String value) {
|
public static void setString(SharedPreferences sharedPreferences, Context context, int keyId, String value) {
|
||||||
SharedPreferences sharedPreferences = getSharedPreferences(context);
|
|
||||||
Editor editor = sharedPreferences.edit();
|
Editor editor = sharedPreferences.edit();
|
||||||
editor.putString(getKey(context, keyId), value);
|
editor.putString(getKey(context, keyId), value);
|
||||||
editor.apply();
|
editor.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public static boolean isMetricUnits(Context context) {
|
|
||||||
return isMetricUnits(getSharedPreferences(context), context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isMetricUnits(SharedPreferences sharedPreferences, Context context) {
|
public static boolean isMetricUnits(SharedPreferences sharedPreferences, Context context) {
|
||||||
final String STATS_UNIT = context.getString(R.string.stats_units_default);
|
final String STATS_UNIT = context.getString(R.string.stats_units_default);
|
||||||
return STATS_UNIT.equals(getString(context, sharedPreferences, R.string.stats_units_key, STATS_UNIT));
|
return STATS_UNIT.equals(getString(sharedPreferences, context, R.string.stats_units_key, STATS_UNIT));
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public static boolean isReportSpeed(Context context, String category) {
|
|
||||||
return isReportSpeed(getSharedPreferences(context), context, category);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isReportSpeed(SharedPreferences sharedPreferences, Context context, String category) {
|
public static boolean isReportSpeed(SharedPreferences sharedPreferences, Context context, String category) {
|
||||||
final String STATS_RATE_DEFAULT = context.getString(R.string.stats_rate_default);
|
final String STATS_RATE_DEFAULT = context.getString(R.string.stats_rate_default);
|
||||||
String currentStatsRate = getString(context, sharedPreferences, R.string.stats_rate_key, STATS_RATE_DEFAULT);
|
String currentStatsRate = getString(sharedPreferences, context, R.string.stats_rate_key, STATS_RATE_DEFAULT);
|
||||||
if (currentStatsRate.equals(getString(context, sharedPreferences, R.string.stats_rate_speed_or_pace_default, STATS_RATE_DEFAULT))) {
|
if (currentStatsRate.equals(getString(sharedPreferences, context, R.string.stats_rate_speed_or_pace_default, STATS_RATE_DEFAULT))) {
|
||||||
return TrackIconUtils.isSpeedIcon(context, category);
|
return TrackIconUtils.isSpeedIcon(context, category);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,8 +162,8 @@ public class PreferencesUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated //Use TrackRecordingService
|
@Deprecated //Use TrackRecordingService
|
||||||
public static boolean isRecordingTrackPaused(Context context) {
|
public static boolean isRecordingTrackPaused(SharedPreferences sharedPreferences, Context context) {
|
||||||
return getBoolean(context, R.string.recording_track_paused_key, isRecordingTrackPausedDefault(context));
|
return getBoolean(sharedPreferences, context, R.string.recording_track_paused_key, isRecordingTrackPausedDefault(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated //Use TrackRecordingService
|
@Deprecated //Use TrackRecordingService
|
||||||
@@ -246,9 +172,9 @@ public class PreferencesUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated //Use TrackRecordingService
|
@Deprecated //Use TrackRecordingService
|
||||||
public static void defaultRecordingTrackPaused(Context context) {
|
public static void defaultRecordingTrackPaused(SharedPreferences sharedPreferences, Context context) {
|
||||||
final boolean RECORDING_TRACK_PAUSED = context.getResources().getBoolean(R.bool.recording_track_paused_default);
|
final boolean RECORDING_TRACK_PAUSED = context.getResources().getBoolean(R.bool.recording_track_paused_default);
|
||||||
setBoolean(context, R.string.recording_track_paused_key, RECORDING_TRACK_PAUSED);
|
setBoolean(sharedPreferences, context, R.string.recording_track_paused_key, RECORDING_TRACK_PAUSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String getBluetoothSensorAddressNone(Context context) {
|
private static String getBluetoothSensorAddressNone(Context context) {
|
||||||
@@ -259,83 +185,74 @@ public class PreferencesUtils {
|
|||||||
return getBluetoothSensorAddressNone(context).equals(currentValue);
|
return getBluetoothSensorAddressNone(context).equals(currentValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getBluetoothHeartRateSensorAddress(Context context) {
|
public static String getBluetoothHeartRateSensorAddress(SharedPreferences sharedPreferences, Context context) {
|
||||||
return getString(context, R.string.settings_sensor_bluetooth_heart_rate_key, getBluetoothSensorAddressNone(context));
|
return getString(sharedPreferences, context, R.string.settings_sensor_bluetooth_heart_rate_key, getBluetoothSensorAddressNone(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getBluetoothCyclingCadenceSensorAddress(Context context) {
|
public static String getBluetoothCyclingCadenceSensorAddress(SharedPreferences sharedPreferences, Context context) {
|
||||||
return getString(context, R.string.settings_sensor_bluetooth_cycling_cadence_key, getBluetoothSensorAddressNone(context));
|
return getString(sharedPreferences, context, R.string.settings_sensor_bluetooth_cycling_cadence_key, getBluetoothSensorAddressNone(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getBluetoothCyclingSpeedSensorAddress(Context context) {
|
public static String getBluetoothCyclingSpeedSensorAddress(SharedPreferences sharedPreferences, Context context) {
|
||||||
return getString(context, R.string.settings_sensor_bluetooth_cycling_speed_key, getBluetoothSensorAddressNone(context));
|
return getString(sharedPreferences, context, R.string.settings_sensor_bluetooth_cycling_speed_key, getBluetoothSensorAddressNone(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getWheelCircumference(Context context) {
|
public static int getWheelCircumference(SharedPreferences sharedPreferences, Context context) {
|
||||||
final int DEFAULT = Integer.parseInt(context.getResources().getString(R.string.settings_sensor_bluetooth_cycling_speed_wheel_circumference_default));
|
final int DEFAULT = Integer.parseInt(context.getResources().getString(R.string.settings_sensor_bluetooth_cycling_speed_wheel_circumference_default));
|
||||||
return getInt(context, R.string.settings_sensor_bluetooth_cycling_speed_wheel_circumference_key, DEFAULT);
|
return getInt(sharedPreferences, context, R.string.settings_sensor_bluetooth_cycling_speed_wheel_circumference_key, DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isBluetoothCyclingPowerSensorAddressNone(Context context) {
|
public static String getBluetoothCyclingPowerSensorAddress(SharedPreferences sharedPreferences, Context context) {
|
||||||
return isBluetoothSensorAddressNone(context, getBluetoothCyclingPowerSensorAddress(context));
|
return getString(sharedPreferences, context, R.string.settings_sensor_bluetooth_cycling_power_key, getBluetoothSensorAddressNone(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getBluetoothCyclingPowerSensorAddress(Context context) {
|
public static boolean shouldShowStatsOnLockscreen(SharedPreferences sharedPreferences, Context context) {
|
||||||
return getString(context, R.string.settings_sensor_bluetooth_cycling_power_key, getBluetoothSensorAddressNone(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static boolean shouldShowStatsOnLockscreen(Context context) {
|
|
||||||
final boolean STATS_SHOW_ON_LOCKSCREEN_DEFAULT = context.getResources().getBoolean(R.bool.stats_show_on_lockscreen_while_recording_default);
|
final boolean STATS_SHOW_ON_LOCKSCREEN_DEFAULT = context.getResources().getBoolean(R.bool.stats_show_on_lockscreen_while_recording_default);
|
||||||
return getBoolean(context, R.string.stats_show_on_lockscreen_while_recording_key, STATS_SHOW_ON_LOCKSCREEN_DEFAULT);
|
return getBoolean(sharedPreferences, context, R.string.stats_show_on_lockscreen_while_recording_key, STATS_SHOW_ON_LOCKSCREEN_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean shouldKeepScreenOn(Context context) {
|
public static boolean shouldKeepScreenOn(SharedPreferences sharedPreferences, Context context) {
|
||||||
final boolean DEFAULT = context.getResources().getBoolean(R.bool.stats_keep_screen_on_while_recording_default);
|
final boolean DEFAULT = context.getResources().getBoolean(R.bool.stats_keep_screen_on_while_recording_default);
|
||||||
return getBoolean(context, R.string.stats_keep_screen_on_while_recording_key, DEFAULT);
|
return getBoolean(sharedPreferences, context, R.string.stats_keep_screen_on_while_recording_key, DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean shouldUseFullscreen(Context context) {
|
public static boolean shouldUseFullscreen(SharedPreferences sharedPreferences, Context context) {
|
||||||
final boolean DEFAULT = context.getResources().getBoolean(R.bool.stats_fullscreen_while_recording_default);
|
final boolean DEFAULT = context.getResources().getBoolean(R.bool.stats_fullscreen_while_recording_default);
|
||||||
return getBoolean(context, R.string.stats_fullscreen_while_recording_key, DEFAULT);
|
return getBoolean(sharedPreferences, context, R.string.stats_fullscreen_while_recording_key, DEFAULT);
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public static boolean isShowStatsElevation(Context context) {
|
|
||||||
return isShowStatsElevation(getSharedPreferences(context), context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isShowStatsElevation(SharedPreferences sharedPreferences, Context context) {
|
public static boolean isShowStatsElevation(SharedPreferences sharedPreferences, Context context) {
|
||||||
final boolean STATS_SHOW_ELEVATION = context.getResources().getBoolean(R.bool.stats_show_elevation_default);
|
final boolean STATS_SHOW_ELEVATION = context.getResources().getBoolean(R.bool.stats_show_elevation_default);
|
||||||
return getBoolean(context, sharedPreferences, R.string.stats_show_grade_elevation_key, STATS_SHOW_ELEVATION);
|
return getBoolean(sharedPreferences, context, R.string.stats_show_grade_elevation_key, STATS_SHOW_ELEVATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isStatsShowCoordinate(SharedPreferences sharedPreferences, Context context) {
|
public static boolean isStatsShowCoordinate(SharedPreferences sharedPreferences, Context context) {
|
||||||
final boolean STATS_SHOW_COORDINATE = context.getResources().getBoolean(R.bool.stats_show_coordinate_default);
|
final boolean STATS_SHOW_COORDINATE = context.getResources().getBoolean(R.bool.stats_show_coordinate_default);
|
||||||
return getBoolean(context, R.string.stats_show_coordinate_key, STATS_SHOW_COORDINATE);
|
return getBoolean(sharedPreferences, context, R.string.stats_show_coordinate_key, STATS_SHOW_COORDINATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getVoiceFrequency(Context context) {
|
public static int getVoiceFrequency(SharedPreferences sharedPreferences, Context context) {
|
||||||
final int VOICE_FREQUENCY_DEFAULT = Integer.parseInt(context.getResources().getString(R.string.voice_frequency_default));
|
final int VOICE_FREQUENCY_DEFAULT = Integer.parseInt(context.getResources().getString(R.string.voice_frequency_default));
|
||||||
return getInt(context, R.string.voice_frequency_key, VOICE_FREQUENCY_DEFAULT);
|
return getInt(sharedPreferences, context, R.string.voice_frequency_key, VOICE_FREQUENCY_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getRecordingDistanceInterval(Context context) {
|
public static int getRecordingDistanceInterval(SharedPreferences sharedPreferences, Context context) {
|
||||||
return getInt(context, R.string.recording_distance_interval_key, getRecordingDistanceIntervalDefault(context));
|
return getInt(sharedPreferences, context, R.string.recording_distance_interval_key, getRecordingDistanceIntervalDefault(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getRecordingDistanceIntervalDefault(Context context) {
|
public static int getRecordingDistanceIntervalDefault(Context context) {
|
||||||
return Integer.parseInt(context.getResources().getString(R.string.recording_distance_interval_default));
|
return Integer.parseInt(context.getResources().getString(R.string.recording_distance_interval_default));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getMaxRecordingDistance(Context context) {
|
public static int getMaxRecordingDistance(SharedPreferences sharedPreferences, Context context) {
|
||||||
final int MAX_RECORDING_DISTANCE = Integer.parseInt(context.getResources().getString(R.string.max_recording_distance_default));
|
final int MAX_RECORDING_DISTANCE = Integer.parseInt(context.getResources().getString(R.string.max_recording_distance_default));
|
||||||
return getInt(context, R.string.max_recording_distance_key, MAX_RECORDING_DISTANCE);
|
return getInt(sharedPreferences, context, R.string.max_recording_distance_key, MAX_RECORDING_DISTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getMinRecordingInterval(Context context) {
|
//TODO Duration
|
||||||
|
public static int getMinRecordingInterval(SharedPreferences sharedPreferences, Context context) {
|
||||||
final int MIN_RECORDING_INTERVAL = Integer.parseInt(context.getResources().getString(R.string.min_recording_interval_default));
|
final int MIN_RECORDING_INTERVAL = Integer.parseInt(context.getResources().getString(R.string.min_recording_interval_default));
|
||||||
return getInt(context, R.string.min_recording_interval_key, MIN_RECORDING_INTERVAL);
|
return getInt(sharedPreferences, context, R.string.min_recording_interval_key, MIN_RECORDING_INTERVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getMinRecordingIntervalAdaptAccuracy(Context context) {
|
public static int getMinRecordingIntervalAdaptAccuracy(Context context) {
|
||||||
@@ -350,19 +267,19 @@ public class PreferencesUtils {
|
|||||||
return Integer.parseInt(context.getResources().getString(R.string.min_recording_interval_default));
|
return Integer.parseInt(context.getResources().getString(R.string.min_recording_interval_default));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getRecordingGPSAccuracy(Context context) {
|
public static int getRecordingGPSAccuracy(SharedPreferences sharedPreferences, Context context) {
|
||||||
final int RECORDING_GPS_ACCURACY = Integer.parseInt(context.getResources().getString(R.string.recording_gps_accuracy_default));
|
final int RECORDING_GPS_ACCURACY = Integer.parseInt(context.getResources().getString(R.string.recording_gps_accuracy_default));
|
||||||
return getInt(context, R.string.recording_gps_accuracy_key, RECORDING_GPS_ACCURACY);
|
return getInt(sharedPreferences, context, R.string.recording_gps_accuracy_key, RECORDING_GPS_ACCURACY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean shouldInstantExportAfterWorkout(Context context) {
|
public static boolean shouldInstantExportAfterWorkout(SharedPreferences sharedPreferences, Context context) {
|
||||||
final boolean INSTANT_POST_WORKOUT_EXPORT_DEFAULT = context.getResources().getBoolean(R.bool.post_workout_export_enabled_default);
|
final boolean INSTANT_POST_WORKOUT_EXPORT_DEFAULT = context.getResources().getBoolean(R.bool.post_workout_export_enabled_default);
|
||||||
return getBoolean(context, R.string.post_workout_export_enabled_key, INSTANT_POST_WORKOUT_EXPORT_DEFAULT);
|
return getBoolean(sharedPreferences, context, R.string.post_workout_export_enabled_key, INSTANT_POST_WORKOUT_EXPORT_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TrackFileFormat getExportTrackFileFormat(Context context) {
|
public static TrackFileFormat getExportTrackFileFormat(SharedPreferences sharedPreferences, Context context) {
|
||||||
final String TRACKFILEFORMAT_NAME_DEFAULT = getString(context, R.string.export_trackfileformat_default, null);
|
final String TRACKFILEFORMAT_NAME_DEFAULT = getString(sharedPreferences, context, R.string.export_trackfileformat_default, null);
|
||||||
String trackFileFormatName = getString(context, R.string.export_trackfileformat_key, TRACKFILEFORMAT_NAME_DEFAULT);
|
String trackFileFormatName = getString(sharedPreferences, context, R.string.export_trackfileformat_key, TRACKFILEFORMAT_NAME_DEFAULT);
|
||||||
try {
|
try {
|
||||||
return TrackFileFormat.valueOf(trackFileFormatName);
|
return TrackFileFormat.valueOf(trackFileFormatName);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -370,24 +287,24 @@ public class PreferencesUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean getPreventReimportTracks(Context context) {
|
public static boolean getPreventReimportTracks(SharedPreferences sharedPreferences, Context context) {
|
||||||
final boolean defaultValue = getBoolean(context, R.bool.import_prevent_reimport_default, false);
|
final boolean defaultValue = getBoolean(sharedPreferences, context, R.bool.import_prevent_reimport_default, false);
|
||||||
return getBoolean(context, R.string.import_prevent_reimport_key, defaultValue);
|
return getBoolean(sharedPreferences, context, R.string.import_prevent_reimport_key, defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {@link androidx.appcompat.app.AppCompatDelegate}.MODE_*
|
* @return {@link androidx.appcompat.app.AppCompatDelegate}.MODE_*
|
||||||
*/
|
*/
|
||||||
public static int getDefaultNightMode(Context context) {
|
public static int getDefaultNightMode(SharedPreferences sharedPreferences, Context context) {
|
||||||
final String defaultValue = getKey(context, R.string.night_mode_default);
|
final String defaultValue = getKey(context, R.string.night_mode_default);
|
||||||
final String value = getString(context, R.string.night_mode_key, defaultValue);
|
final String value = getString(sharedPreferences, context, R.string.night_mode_key, defaultValue);
|
||||||
|
|
||||||
return Integer.parseInt(value);
|
return Integer.parseInt(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated //Use TrackRecordingService
|
@Deprecated //Use TrackRecordingService
|
||||||
public static boolean isRecording(Context context) {
|
public static boolean isRecording(SharedPreferences sharedPreferences, Context context) {
|
||||||
return isRecording(getRecordingTrackId(context));
|
return isRecording(getRecordingTrackId(context, sharedPreferences));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@@ -399,16 +316,19 @@ public class PreferencesUtils {
|
|||||||
return recordingTrackId.getId() != RECORDING_TRACK_ID_DEFAULT;
|
return recordingTrackId.getId() != RECORDING_TRACK_ID_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void resetPreferences(Context context, boolean readAgain) {
|
public static SharedPreferences resetPreferences(Context context, boolean readAgain) {
|
||||||
|
SharedPreferences sharedPreferences = getSharedPreferences(context);
|
||||||
if (readAgain) {
|
if (readAgain) {
|
||||||
// We want to really clear settings now.
|
// We want to really clear settings now.
|
||||||
getSharedPreferences(context).edit().clear().commit();
|
sharedPreferences.edit().clear().commit();
|
||||||
}
|
}
|
||||||
PreferenceManager.setDefaultValues(context, R.xml.settings, readAgain);
|
PreferenceManager.setDefaultValues(context, R.xml.settings, readAgain);
|
||||||
|
|
||||||
|
return sharedPreferences;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DocumentFile getDefaultExportDirectoryUri(Context context) {
|
public static DocumentFile getDefaultExportDirectoryUri(SharedPreferences sharedPreferences, Context context) {
|
||||||
String singleExportDirectorySettingsKey = getString(context, R.string.settings_default_export_directory_key, null);
|
String singleExportDirectorySettingsKey = getString(sharedPreferences, context, R.string.settings_default_export_directory_key, null);
|
||||||
if (singleExportDirectorySettingsKey == null) {
|
if (singleExportDirectorySettingsKey == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -420,12 +340,12 @@ public class PreferencesUtils {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setDefaultExportDirectoryUri(Context context, Uri directoryUri) {
|
public static void setDefaultExportDirectoryUri(SharedPreferences sharedPreferences, Context context, Uri directoryUri) {
|
||||||
String value = directoryUri != null ? directoryUri.toString() : null;
|
String value = directoryUri != null ? directoryUri.toString() : null;
|
||||||
setString(context, R.string.settings_default_export_directory_key, value);
|
setString(sharedPreferences, context, R.string.settings_default_export_directory_key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isDefaultExportDirectoryUri(Context context) {
|
public static boolean isDefaultExportDirectoryUri(SharedPreferences sharedPreferences, Context context) {
|
||||||
return getDefaultExportDirectoryUri(context) != null;
|
return getDefaultExportDirectoryUri(sharedPreferences, context) != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,8 +41,9 @@ public class TrackNameUtils {
|
|||||||
private TrackNameUtils() {
|
private TrackNameUtils() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO Should not access sharedPreferences; trackName should be an ENUM.
|
||||||
public static String getTrackName(Context context, Track.Id trackId, Instant startTime) {
|
public static String getTrackName(Context context, Track.Id trackId, Instant startTime) {
|
||||||
String trackName = PreferencesUtils.getString(context, R.string.track_name_key, context.getString(R.string.track_name_default));
|
String trackName = PreferencesUtils.getString(PreferencesUtils.getSharedPreferences(context), context, R.string.track_name_key, context.getString(R.string.track_name_default));
|
||||||
|
|
||||||
if (trackName.equals(context.getString(R.string.settings_recording_track_name_date_local_value))) {
|
if (trackName.equals(context.getString(R.string.settings_recording_track_name_date_local_value))) {
|
||||||
return StringUtils.formatDateTime(context, startTime);
|
return StringUtils.formatDateTime(context, startTime);
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public class IntervalStatistics {
|
|||||||
TrackPoint trackPoint = trackPoints.get(i);
|
TrackPoint trackPoint = trackPoints.get(i);
|
||||||
|
|
||||||
if (trackPoint.hasLocation() && prevTrackPoint.hasLocation()) {
|
if (trackPoint.hasLocation() && prevTrackPoint.hasLocation()) {
|
||||||
interval.distance_m += prevTrackPoint.distanceTo(trackPoint);
|
interval.distance_m += prevTrackPoint.distanceToPrevious(trackPoint);
|
||||||
interval.time = interval.time.plus(Duration.between(prevTrackPoint.getTime(), trackPoint.getTime()));
|
interval.time = interval.time.plus(Duration.between(prevTrackPoint.getTime(), trackPoint.getTime()));
|
||||||
interval.gain_m += trackPoint.hasElevationGain() ? trackPoint.getElevationGain() : 0;
|
interval.gain_m += trackPoint.hasElevationGain() ? trackPoint.getElevationGain() : 0;
|
||||||
interval.loss_m += trackPoint.hasElevationLoss() ? trackPoint.getElevationLoss() : 0;
|
interval.loss_m += trackPoint.hasElevationLoss() ? trackPoint.getElevationLoss() : 0;
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ public class SensorDataModel {
|
|||||||
this.sensorValue = StringUtils.formatDecimal(sensorValue, 0);
|
this.sensorValue = StringUtils.formatDecimal(sensorValue, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SensorDataModel(SensorData sensorData) {
|
public SensorDataModel(SensorData<Float> sensorData) {
|
||||||
this.sensorName = sensorData.getSensorNameOrAddress();
|
this.sensorName = sensorData.getSensorNameOrAddress();
|
||||||
this.sensorValue = sensorData.hasValue() && sensorData.isRecent() ? StringUtils.formatDecimal((float) sensorData.getValue(), 0) : null;
|
this.sensorValue = sensorData.hasValue() && sensorData.isRecent() ? StringUtils.formatDecimal(sensorData.getValue(), 0) : null;
|
||||||
if (sensorData instanceof SensorDataHeartRate) {
|
if (sensorData instanceof SensorDataHeartRate) {
|
||||||
this.labelId = R.string.sensor_state_heart_rate;
|
this.labelId = R.string.sensor_state_heart_rate;
|
||||||
this.unitId = R.string.sensor_unit_beats_per_minute;
|
this.unitId = R.string.sensor_unit_beats_per_minute;
|
||||||
|
|||||||
@@ -25,8 +25,9 @@
|
|||||||
android:id="@+id/stats_sensor_value"
|
android:id="@+id/stats_sensor_value"
|
||||||
style="@style/StatsLargeValue"
|
style="@style/StatsLargeValue"
|
||||||
android:value="@string/value_unknown"
|
android:value="@string/value_unknown"
|
||||||
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toStartOf="@id/stats_sensor_unit"
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_sensor_sensor_value"
|
app:layout_constraintTop_toBottomOf="@id/stats_sensor_sensor_value"
|
||||||
tools:text="90" />
|
tools:text="90" />
|
||||||
|
|
||||||
@@ -34,8 +35,8 @@
|
|||||||
android:id="@+id/stats_sensor_unit"
|
android:id="@+id/stats_sensor_unit"
|
||||||
style="@style/StatsUnit"
|
style="@style/StatsUnit"
|
||||||
tools:text="@string/sensor_unit_beats_per_minute"
|
tools:text="@string/sensor_unit_beats_per_minute"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toEndOf="@id/stats_sensor_value"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_sensor_value" />
|
app:layout_constraintBottom_toBottomOf="@id/stats_sensor_value" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -30,91 +30,124 @@
|
|||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
app:layout_constraintGuide_end="8dp" />
|
app:layout_constraintGuide_end="8dp" />
|
||||||
|
|
||||||
|
<!-- Activity information: icon, name, description and start datetime -->
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/stats_activity_type_icon"
|
||||||
|
style="@style/IconStats"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/guideline"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/stats_name_value"
|
||||||
|
tools:src="@drawable/ic_activity_bike_24dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/stats_name_value"
|
||||||
|
style="@style/TextLargeStats"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
app:layout_constrainedWidth="true"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/stats_activity_type_icon"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="Name of the activity" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/stats_description_value"
|
||||||
|
style="@style/TextMediumStats"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
app:layout_constrainedWidth="true"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/stats_name_value"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/stats_name_value"
|
||||||
|
tools:text="Here will be a description that could be really long and it would show completely without problems." />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/stats_start_datetime_value"
|
||||||
|
style="@style/TextSmallStats"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
app:layout_constrainedWidth="true"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/guideline"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/stats_description_barrier"
|
||||||
|
tools:text="Saturday 6th, 16:44" />
|
||||||
|
|
||||||
|
<!-- Barrier -->
|
||||||
|
<androidx.constraintlayout.widget.Barrier
|
||||||
|
android:id="@+id/stats_description_barrier"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:barrierDirection="bottom"
|
||||||
|
app:constraint_referenced_ids="stats_activity_type_icon,stats_name_value,stats_description_value" />
|
||||||
|
|
||||||
|
<!-- Horizontal line -->
|
||||||
|
<View
|
||||||
|
android:id="@+id/stats_information_horizontal_line"
|
||||||
|
style="@style/StatsHorizontalLine"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/guideline"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/stats_start_datetime_value" />
|
||||||
|
|
||||||
<!-- Distance -->
|
<!-- Distance -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_distance_label"
|
android:id="@+id/stats_distance_label"
|
||||||
style="@style/StatsLargeLabel"
|
style="@style/StatsLargeLabel"
|
||||||
android:text="@string/stats_distance"
|
android:text="@string/stats_distance"
|
||||||
app:layout_constrainedWidth="true"
|
app:layout_constrainedWidth="true"
|
||||||
app:layout_constraintStart_toEndOf="@+id/guideline"
|
app:layout_constraintStart_toEndOf="@id/guideline"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/guideline2"
|
app:layout_constraintEnd_toStartOf="@id/guideline2"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toBottomOf="@id/stats_information_horizontal_line" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_distance_value"
|
android:id="@+id/stats_distance_value"
|
||||||
style="@style/StatsLargeValue"
|
style="@style/StatsLargeValue"
|
||||||
android:value="@string/value_unknown"
|
android:value="@string/value_unknown"
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
app:layout_constraintStart_toEndOf="@+id/guideline"
|
app:layout_constraintStart_toEndOf="@id/guideline"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/stats_distance_unit"
|
app:layout_constraintEnd_toStartOf="@id/stats_distance_unit"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/stats_distance_label"
|
app:layout_constraintTop_toBottomOf="@id/stats_distance_label"
|
||||||
tools:text="100" />
|
tools:text="100" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_distance_unit"
|
android:id="@+id/stats_distance_unit"
|
||||||
style="@style/StatsUnit"
|
style="@style/StatsUnit"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/stats_distance_value"
|
app:layout_constraintBottom_toBottomOf="@id/stats_distance_value"
|
||||||
app:layout_constraintStart_toEndOf="@+id/stats_distance_value"
|
app:layout_constraintStart_toEndOf="@id/stats_distance_value"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/guideline2"
|
app:layout_constraintEnd_toStartOf="@id/guideline2"
|
||||||
tools:text="km" />
|
tools:text="km" />
|
||||||
|
|
||||||
<!-- Activity Type -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_activity_type_label"
|
|
||||||
style="@style/StatsLargeLabel"
|
|
||||||
android:text="@string/track_edit_activity_type_hint"
|
|
||||||
app:layout_constrainedWidth="true"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/guideline2"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/guideline3"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/stats_activity_type_icon"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/guideline2"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/guideline3"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/stats_distance_value"
|
|
||||||
app:layout_constraintTop_toTopOf="@+id/stats_distance_value"
|
|
||||||
app:tint="?android:textColorPrimary" />
|
|
||||||
|
|
||||||
<!-- Total time -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_total_time_label"
|
|
||||||
style="@style/StatsLargeLabel"
|
|
||||||
android:text="@string/stats_total_time"
|
|
||||||
app:layout_constrainedWidth="true"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/guideline"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/guideline2"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/stats_distance_value" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_total_time_value"
|
|
||||||
style="@style/StatsLargeValue"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/guideline"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/guideline2"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/stats_total_time_label"
|
|
||||||
tools:text="00:00:00" />
|
|
||||||
|
|
||||||
<!-- Moving time -->
|
<!-- Moving time -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_moving_time_label"
|
android:id="@+id/stats_moving_time_label"
|
||||||
style="@style/StatsLargeLabel"
|
style="@style/StatsLargeLabel"
|
||||||
android:text="@string/stats_moving_time"
|
android:text="@string/stats_moving_time"
|
||||||
app:layout_constrainedWidth="true"
|
app:layout_constrainedWidth="true"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/stats_total_time_label"
|
app:layout_constraintStart_toEndOf="@id/guideline2"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/guideline3"
|
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
||||||
app:layout_constraintStart_toEndOf="@+id/guideline2"
|
app:layout_constraintTop_toBottomOf="@id/stats_information_horizontal_line" />
|
||||||
app:layout_constraintTop_toTopOf="@+id/stats_total_time_label"
|
|
||||||
app:layout_constraintVertical_bias="1.0" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_moving_time_value"
|
android:id="@+id/stats_moving_time_value"
|
||||||
style="@style/StatsLargeValue"
|
style="@style/StatsLargeValue"
|
||||||
android:value="@string/value_unknown"
|
android:value="@string/value_unknown"
|
||||||
app:layout_constraintStart_toEndOf="@+id/guideline2"
|
app:layout_constraintStart_toEndOf="@id/guideline2"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/guideline3"
|
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/stats_moving_time_label"
|
app:layout_constraintTop_toBottomOf="@id/stats_moving_time_label"
|
||||||
|
tools:text="00:00:00" />
|
||||||
|
|
||||||
|
<!-- Total time -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/stats_total_time_label"
|
||||||
|
style="@style/StatsSmallLabel"
|
||||||
|
android:text="@string/stats_total_time"
|
||||||
|
app:layout_constrainedWidth="true"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/guideline2"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/stats_moving_time_value" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/stats_total_time_value"
|
||||||
|
style="@style/StatsSmallValue"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/guideline2"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/stats_total_time_label"
|
||||||
tools:text="00:00:00" />
|
tools:text="00:00:00" />
|
||||||
|
|
||||||
<!-- Barrier -->
|
<!-- Barrier -->
|
||||||
@@ -130,18 +163,74 @@
|
|||||||
android:id="@+id/stats_speed_horizontal_line"
|
android:id="@+id/stats_speed_horizontal_line"
|
||||||
style="@style/StatsHorizontalLine"
|
style="@style/StatsHorizontalLine"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
app:layout_constraintStart_toEndOf="@+id/guideline"
|
app:layout_constraintStart_toEndOf="@id/guideline"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/guideline3"
|
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/stats_time_barrier" />
|
app:layout_constraintTop_toBottomOf="@id/stats_time_barrier" />
|
||||||
|
|
||||||
|
<!-- Speed/Pace max -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/stats_max_speed_label"
|
||||||
|
style="@style/StatsLargeLabel"
|
||||||
|
app:layout_constrainedWidth="true"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/guideline"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/guideline2"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/stats_speed_horizontal_line"
|
||||||
|
tools:text="Max. Speed" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/stats_max_speed_value"
|
||||||
|
style="@style/StatsLargeValue"
|
||||||
|
android:value="@string/value_unknown"
|
||||||
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/guideline"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/stats_max_speed_unit"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/stats_max_speed_label"
|
||||||
|
tools:text="30.00" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/stats_max_speed_unit"
|
||||||
|
style="@style/StatsUnit"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/stats_max_speed_value"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/stats_max_speed_value"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/guideline2"
|
||||||
|
tools:text="km/h" />
|
||||||
|
|
||||||
|
<!-- Avg. moving speed/pace -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/stats_moving_speed_label"
|
||||||
|
style="@style/StatsLargeLabel"
|
||||||
|
app:layout_constrainedWidth="true"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/guideline2"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/stats_speed_horizontal_line"
|
||||||
|
tools:text="Avg. Moving Speed" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/stats_moving_speed_value"
|
||||||
|
style="@style/StatsLargeValue"
|
||||||
|
android:value="@string/value_unknown"
|
||||||
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/guideline2"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/stats_moving_speed_unit"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/stats_moving_speed_label"
|
||||||
|
tools:text="30.00" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/stats_moving_speed_unit"
|
||||||
|
style="@style/StatsUnit"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/stats_moving_speed_value"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/stats_moving_speed_value"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
||||||
|
tools:text="km/h" />
|
||||||
|
|
||||||
<!-- Average speed/pace -->
|
<!-- Average speed/pace -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_average_speed_label"
|
android:id="@+id/stats_average_speed_label"
|
||||||
style="@style/StatsSmallLabel"
|
style="@style/StatsSmallLabel"
|
||||||
app:layout_constrainedWidth="true"
|
app:layout_constrainedWidth="true"
|
||||||
app:layout_constraintStart_toEndOf="@+id/guideline2"
|
app:layout_constraintStart_toEndOf="@id/guideline2"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/guideline3"
|
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_speed_horizontal_line"
|
app:layout_constraintTop_toBottomOf="@id/stats_moving_speed_value"
|
||||||
tools:text="Avg. Speed" />
|
tools:text="Avg. Speed" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@@ -149,73 +238,17 @@
|
|||||||
style="@style/StatsSmallValue"
|
style="@style/StatsSmallValue"
|
||||||
android:value="@string/value_unknown"
|
android:value="@string/value_unknown"
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
app:layout_constraintStart_toEndOf="@+id/guideline2"
|
app:layout_constraintStart_toEndOf="@id/guideline2"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/stats_average_speed_unit"
|
app:layout_constraintEnd_toStartOf="@id/stats_average_speed_unit"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/stats_average_speed_label"
|
app:layout_constraintTop_toBottomOf="@id/stats_average_speed_label"
|
||||||
tools:text="30.00" />
|
tools:text="30.00" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_average_speed_unit"
|
android:id="@+id/stats_average_speed_unit"
|
||||||
style="@style/StatsUnit"
|
style="@style/StatsUnit"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/stats_average_speed_value"
|
app:layout_constraintBottom_toBottomOf="@id/stats_average_speed_value"
|
||||||
app:layout_constraintStart_toEndOf="@+id/stats_average_speed_value"
|
app:layout_constraintStart_toEndOf="@id/stats_average_speed_value"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/guideline3"
|
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
||||||
tools:text="km/h" />
|
|
||||||
|
|
||||||
<!-- Speed max -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_max_speed_label"
|
|
||||||
style="@style/StatsSmallLabel"
|
|
||||||
app:layout_constrainedWidth="true"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/guideline"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/guideline2"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_average_speed_value"
|
|
||||||
tools:text="Max. Speed" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_max_speed_value"
|
|
||||||
style="@style/StatsSmallValue"
|
|
||||||
android:value="@string/value_unknown"
|
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/guideline"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/stats_max_speed_unit"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/stats_max_speed_label"
|
|
||||||
tools:text="30.00" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_max_speed_unit"
|
|
||||||
style="@style/StatsUnit"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/stats_max_speed_value"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/stats_max_speed_value"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/guideline2"
|
|
||||||
tools:text="km/h" />
|
|
||||||
|
|
||||||
<!-- Moving speed max -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_moving_speed_label"
|
|
||||||
style="@style/StatsSmallLabel"
|
|
||||||
app:layout_constrainedWidth="true"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/guideline2"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/guideline3"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_average_speed_value"
|
|
||||||
tools:text="Max. Moving Speed" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_moving_speed_value"
|
|
||||||
style="@style/StatsSmallValue"
|
|
||||||
android:value="@string/value_unknown"
|
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/guideline2"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/stats_moving_speed_unit"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/stats_moving_speed_label"
|
|
||||||
tools:text="30.00" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_moving_speed_unit"
|
|
||||||
style="@style/StatsUnit"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/stats_moving_speed_value"
|
|
||||||
app:layout_constraintStart_toEndOf="@+id/stats_moving_speed_value"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/guideline3"
|
|
||||||
tools:text="km/h" />
|
tools:text="km/h" />
|
||||||
|
|
||||||
<!-- Barrier -->
|
<!-- Barrier -->
|
||||||
@@ -224,16 +257,16 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:barrierDirection="bottom"
|
app:barrierDirection="bottom"
|
||||||
app:constraint_referenced_ids="stats_moving_speed_value,stats_max_speed_value" />
|
app:constraint_referenced_ids="stats_max_speed_value,stats_moving_speed_value,stats_average_speed_value" />
|
||||||
|
|
||||||
<!-- Horizontal line -->
|
<!-- Horizontal line -->
|
||||||
<View
|
<View
|
||||||
android:id="@+id/stats_elevation_horizontal_line"
|
android:id="@+id/stats_elevation_horizontal_line"
|
||||||
style="@style/StatsHorizontalLine"
|
style="@style/StatsHorizontalLine"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
app:layout_constraintStart_toEndOf="@+id/guideline"
|
app:layout_constraintStart_toEndOf="@id/guideline"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/guideline3"
|
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/stats_speed_barrier" />
|
app:layout_constraintTop_toBottomOf="@id/stats_speed_barrier" />
|
||||||
|
|
||||||
<!-- Elevation gain and loss -->
|
<!-- Elevation gain and loss -->
|
||||||
<androidx.constraintlayout.widget.Group
|
<androidx.constraintlayout.widget.Group
|
||||||
@@ -244,56 +277,56 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_elevation_gain_label"
|
android:id="@+id/stats_elevation_gain_label"
|
||||||
style="@style/StatsSmallLabel"
|
style="@style/StatsLargeLabel"
|
||||||
android:text="@string/stats_gain"
|
android:text="@string/stats_gain"
|
||||||
app:layout_constrainedWidth="true"
|
app:layout_constrainedWidth="true"
|
||||||
app:layout_constraintStart_toEndOf="@+id/guideline"
|
app:layout_constraintStart_toEndOf="@id/guideline"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/guideline2"
|
app:layout_constraintEnd_toStartOf="@id/guideline2"
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_elevation_horizontal_line" />
|
app:layout_constraintTop_toBottomOf="@id/stats_elevation_horizontal_line" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_elevation_gain_value"
|
android:id="@+id/stats_elevation_gain_value"
|
||||||
style="@style/StatsSmallValue"
|
style="@style/StatsLargeValue"
|
||||||
android:value="@string/value_unknown"
|
android:value="@string/value_unknown"
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
app:layout_constraintStart_toEndOf="@+id/guideline"
|
app:layout_constraintStart_toEndOf="@id/guideline"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/stats_elevation_gain_unit"
|
app:layout_constraintEnd_toStartOf="@id/stats_elevation_gain_unit"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/stats_elevation_gain_label"
|
app:layout_constraintTop_toBottomOf="@id/stats_elevation_gain_label"
|
||||||
tools:text="100" />
|
tools:text="100" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_elevation_gain_unit"
|
android:id="@+id/stats_elevation_gain_unit"
|
||||||
style="@style/StatsUnit"
|
style="@style/StatsUnit"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/stats_elevation_gain_value"
|
app:layout_constraintBottom_toBottomOf="@id/stats_elevation_gain_value"
|
||||||
app:layout_constraintStart_toEndOf="@+id/stats_elevation_gain_value"
|
app:layout_constraintStart_toEndOf="@id/stats_elevation_gain_value"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/guideline2"
|
app:layout_constraintEnd_toStartOf="@id/guideline2"
|
||||||
tools:text="m" />
|
tools:text="m" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_elevation_loss_label"
|
android:id="@+id/stats_elevation_loss_label"
|
||||||
style="@style/StatsSmallLabel"
|
style="@style/StatsLargeLabel"
|
||||||
android:text="@string/stats_loss"
|
android:text="@string/stats_loss"
|
||||||
app:layout_constrainedWidth="true"
|
app:layout_constrainedWidth="true"
|
||||||
app:layout_constraintStart_toEndOf="@+id/guideline2"
|
app:layout_constraintStart_toEndOf="@id/guideline2"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/guideline3"
|
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_elevation_horizontal_line" />
|
app:layout_constraintTop_toBottomOf="@id/stats_elevation_horizontal_line" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_elevation_loss_value"
|
android:id="@+id/stats_elevation_loss_value"
|
||||||
style="@style/StatsSmallValue"
|
style="@style/StatsLargeValue"
|
||||||
android:value="@string/value_unknown"
|
android:value="@string/value_unknown"
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
app:layout_constraintStart_toEndOf="@+id/guideline2"
|
app:layout_constraintStart_toEndOf="@id/guideline2"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/stats_elevation_loss_unit"
|
app:layout_constraintEnd_toStartOf="@id/stats_elevation_loss_unit"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/stats_elevation_loss_label"
|
app:layout_constraintTop_toBottomOf="@id/stats_elevation_loss_label"
|
||||||
tools:text="100" />
|
tools:text="100" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_elevation_loss_unit"
|
android:id="@+id/stats_elevation_loss_unit"
|
||||||
style="@style/StatsUnit"
|
style="@style/StatsUnit"
|
||||||
app:layout_constraintBottom_toBottomOf="@+id/stats_elevation_loss_value"
|
app:layout_constraintBottom_toBottomOf="@id/stats_elevation_loss_value"
|
||||||
app:layout_constraintStart_toEndOf="@+id/stats_elevation_loss_value"
|
app:layout_constraintStart_toEndOf="@id/stats_elevation_loss_value"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/guideline3"
|
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
||||||
tools:text="m" />
|
tools:text="m" />
|
||||||
|
|
||||||
<!-- Barrier -->
|
<!-- Barrier -->
|
||||||
@@ -309,9 +342,9 @@
|
|||||||
android:id="@+id/stats_end_horizontal_line"
|
android:id="@+id/stats_end_horizontal_line"
|
||||||
style="@style/StatsHorizontalLine"
|
style="@style/StatsHorizontalLine"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
app:layout_constraintStart_toEndOf="@+id/guideline"
|
app:layout_constraintStart_toEndOf="@id/guideline"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/guideline3"
|
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/stats_elevation_barrier" />
|
app:layout_constraintTop_toBottomOf="@id/stats_elevation_barrier" />
|
||||||
|
|
||||||
<!-- Sensors data -->
|
<!-- Sensors data -->
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ limitations under the License.
|
|||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
<item
|
<item
|
||||||
android:id="@+id/track_list_search"
|
android:id="@+id/track_list_aggregated_stats"
|
||||||
android:title="@string/menu_search"
|
android:icon="@drawable/ic_statistics_24dp"
|
||||||
app:actionViewClass="androidx.appcompat.widget.SearchView"
|
android:title="@string/menu_aggregated_statistics"
|
||||||
app:showAsAction="ifRoom" />
|
app:showAsAction="ifRoom" />
|
||||||
<!-- Icon and title is overwritten by TrackListActivity -->
|
<!-- Icon and title is overwritten by TrackListActivity -->
|
||||||
<!-- Hide icon as workaround for https://github.com/OpenTracksApp/OpenTracks/issues/200 -->
|
<!-- Hide icon as workaround for https://github.com/OpenTracksApp/OpenTracks/issues/200 -->
|
||||||
@@ -29,9 +29,9 @@ limitations under the License.
|
|||||||
android:visible="false"
|
android:visible="false"
|
||||||
app:showAsAction="ifRoom" />
|
app:showAsAction="ifRoom" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/track_list_aggregated_stats"
|
android:id="@+id/track_list_search"
|
||||||
android:icon="@drawable/ic_statistics_24dp"
|
android:title="@string/menu_search"
|
||||||
android:title="@string/menu_aggregated_statistics"
|
app:actionViewClass="androidx.appcompat.widget.SearchView"
|
||||||
app:showAsAction="ifRoom" />
|
app:showAsAction="ifRoom" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/track_list_markers"
|
android:id="@+id/track_list_markers"
|
||||||
|
|||||||
@@ -32,45 +32,37 @@ limitations under the License.
|
|||||||
* vis spor på et kort (se nedenfor)</string>
|
* vis spor på et kort (se nedenfor)</string>
|
||||||
<string name="help_track_map_title">Hvordan viser man et spor på et kort?</string>
|
<string name="help_track_map_title">Hvordan viser man et spor på et kort?</string>
|
||||||
<string name="help_track_map_content">" Brug det lille kortikon.
|
<string name="help_track_map_content">" Brug det lille kortikon.
|
||||||
\n a) (live opdateringer) Installer <a href=\"https://github.com/OpenTracksApp/OSMDashboard\"> OSMDashboard </a>. Det giver online eller offline kort via <a href=\"https://www.openstreetmap.org\"> OpenStreetMap </a>.
|
\n a) (live opdateringer) Installer <a href=\"https://github.com/OpenTracksApp/OSMDashboard\"> OSMDashboard</a>. Det giver online eller offline kort via <a href=\"https://www.openstreetmap.org\">OpenStreetMap</a>.
|
||||||
\n Faktisk er OSMDashboard en separat app, der kun kan få adgang (midlertidigt) til dataene for spor, der skal vises.
|
\n Faktisk er OSMDashboard en separat app, der kun kan få adgang (midlertidigt) til dataene for spor, der skal vises.
|
||||||
\n b) Via en normal kortapplikation (f.eks. <a href=\"http://osmand.net/\"> OsmAnd </a> og <a href=\"https://maps.me/\"> MAPS.ME < / a>). Disse apps skal understøtte KMZ-filformatet (kun placeringer og tidsstempler). Faktisk skal en app understøtte <i> ACTION_VIEW </i> med MIME <i> -applikation / vnd.google-earth.kmz </i>. "</string>
|
\n b) Via en normal kortapplikation (f.e., <a href=\"http://osmand.net/\">OsmAnd</a> og <a href=\"https://maps.me/\">MAPS.ME< / a>). Disse apps skal understøtte KMZ fil formatet (kun placeringer og tidsstempler). Faktisk, skal en app understøtte <i>ACTION_VIEW</i> med MIME <i>applikation/vnd.google-earth.kmz </i>. "</string>
|
||||||
<string name="help_storage_pictures_title">Hvordan gemmer OpenTracks billeder, der blev taget som markører?</string>
|
<string name="help_storage_pictures_title">Hvordan gemmer OpenTracks billeder, der blev taget som markører?</string>
|
||||||
<string name="help_storage_pictures_content">Disse gemmes i appens interne lager (dvs. kun tilgængelig inden for OpenTracks).</string>
|
<string name="help_storage_pictures_content">Disse gemmes i appens interne lager (dvs. kun tilgængelig inden for OpenTracks).</string>
|
||||||
<string name="help_track_export_title">Hvordan kan jeg eksportere / dele indspillede numre?</string>
|
<string name="help_track_export_title">Hvordan kan jeg eksportere / dele indspillede numre?</string>
|
||||||
<string name="help_track_export_content">
|
<string name="help_track_export_content"> Spor kan eksporteres fra indstillingerne som KMZ, KML eller GPX. KMZ / KML alle data; GPX kun placeringer. Spor, der deles via <i>delingsikonet</i> deles som KMZ. </string>
|
||||||
Spor kan eksporteres fra indstillingerne som KMZ, KML eller GPX.
|
|
||||||
KMZ / KML alle data; GPX kun placeringer.
|
|
||||||
Spor, der deles via <i>delingsikonet</i> deles som KMZ.</string>
|
|
||||||
<string name="help_data_google_play_services_title">Kræver/bruger OpenTracks Google Play Service?</string>
|
<string name="help_data_google_play_services_title">Kræver/bruger OpenTracks Google Play Service?</string>
|
||||||
<string name="help_recording_title">Hvordan registrerer OpenTracks data?</string>
|
<string name="help_recording_title">Hvordan registrerer OpenTracks data?</string>
|
||||||
<string name="help_recording_content">
|
<string name="help_recording_content">
|
||||||
OpenTracks bruger enhedens GPS-sensor til at registrere placeringen kontinuerligt.
|
OpenTracks bruger enhedens GPS-sensor til at registrere placeringen kontinuerligt.
|
||||||
Hvis GPS-enheden rapporterer unøjagtige data (f.eks. Placering, hastighed, højde), kan OpenTracks ikke gøre noget ved det.</string>
|
Hvis GPS-enheden rapporterer unøjagtige data (f.eks. Placering, hastighed, højde), kan OpenTracks ikke gøre noget ved det.</string>
|
||||||
<string name="help_data_storage_title">Hvordan gemmer OpenTracks sensordata?</string>
|
<string name="help_data_storage_title">Hvordan gemmer OpenTracks sensordata?</string>
|
||||||
<string name="help_data_storage_content">
|
<string name="help_data_storage_content"> Sensordata gemmes pr. Optaget placering. Med hensyn til en pulssensor betyder det, at der kun er <i> en </i> måling af hjertefrekvensen lagret pr. Placering. Hvis du står stille eller er indendørs, registreres ingen sensordata (men de vil blive vist). </string>
|
||||||
Sensordata gemmes pr. Optaget placering.
|
|
||||||
Med hensyn til en pulssensor betyder det, at der kun er <i> en </i> måling af hjertefrekvensen lagret pr. Placering.
|
|
||||||
Hvis du står stille eller er indendørs, registreres ingen sensordata (men de vil blive vist).</string>
|
|
||||||
<string name="help_gps_troubleshooting_title">OpenTracks optager ikke placeringer?</string>
|
<string name="help_gps_troubleshooting_title">OpenTracks optager ikke placeringer?</string>
|
||||||
<string name="help_gps_troubleshooting_content">
|
<string name="help_gps_troubleshooting_content"> Hvad du kan gøre:
|
||||||
Hvad du kan gøre:\n
|
\n a) Kontroller, om GPS er aktiveret,
|
||||||
a) Kontroller, om GPS er aktiveret,\n
|
\n b) forbedre GPS-modtagelse (f.eks. gå udendørs),
|
||||||
b) forbedre GPS-modtagelse (f.eks. gå udendørs), \n
|
\n c) Kontroller, om du har appen <a href="https://f-droid.org/en/packages/com.android.gpstest.osmdroid/"> GPSTest </a> og
|
||||||
c) Kontroller, om du har appen <a href="https://f-droid.org/en/packages/com.android.gpstest.osmdroid/"> GPSTest </a> og \n
|
\n d) deaktiver strømbesparelse.
|
||||||
d) deaktiver strømbesparelse. \n
|
|
||||||
\n
|
\n
|
||||||
Hvis alt ikke hjælper, skal du rapportere en fejl.</string>
|
\n Hvis alt ikke hjælper, skal du rapportere en fejl. </string>
|
||||||
<string name="help_support_title">Hvordan kan jeg støtte OpenTracks?</string>
|
<string name="help_support_title">Hvordan kan jeg støtte OpenTracks?</string>
|
||||||
<string name="help_support_content">
|
<string name="help_support_content"> Du kan:
|
||||||
Du kan: \n
|
\n a) sprede ordet om OpenTracks,
|
||||||
a) sprede ordet om OpenTracks, \n
|
\n b) <a href="https://github.com/OpenTracksApp/OpenTracks/issues"> foreslå funktioner </a>,
|
||||||
b) <a href="https://github.com/OpenTracksApp/OpenTracks/issues"> foreslå funktioner </a>, \n
|
\n c) <a href="https://github.com/OpenTracksApp/OpenTracks/issues"> rapportfejl </a>,
|
||||||
c) <a href="https://github.com/OpenTracksApp/OpenTracks/issues"> rapportfejl </a>, \n
|
\n d) hjælp til softwareudvikling,
|
||||||
d) hjælp til softwareudvikling, \n
|
\n e) køb i <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore"> Google Play Store </a>,
|
||||||
e) køb i <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore"> Google Play Store </a>, \n
|
\n f) donere, og
|
||||||
f) donere, og \n
|
\n g) gør hvad du synes hjælper OpenTracks. </string>
|
||||||
g) gør hvad du synes hjælper OpenTracks.</string>
|
|
||||||
<string name="open_track_using_dashboard">Åben med OpenTracks-Dashboard</string>
|
<string name="open_track_using_dashboard">Åben med OpenTracks-Dashboard</string>
|
||||||
<string name="open_track_as_KMZ">Åben som KMZ</string>
|
<string name="open_track_as_KMZ">Åben som KMZ</string>
|
||||||
<string name="open_track_as_GPX">Åben som GPX</string>
|
<string name="open_track_as_GPX">Åben som GPX</string>
|
||||||
@@ -135,9 +127,9 @@ g) gør hvad du synes hjælper OpenTracks.</string>
|
|||||||
<string name="activity_type_trail_hiking">vandretur</string>
|
<string name="activity_type_trail_hiking">vandretur</string>
|
||||||
<string name="activity_type_trail_running">løb på sti</string>
|
<string name="activity_type_trail_running">løb på sti</string>
|
||||||
<string name="activity_type_train">tog</string>
|
<string name="activity_type_train">tog</string>
|
||||||
<string name="activity_type_ultimate_frisbee">ultimate frisbee</string>
|
<string name="activity_type_ultimate_frisbee">ultimativ frisbee</string>
|
||||||
<string name="activity_type_unknown">ukendt</string>
|
<string name="activity_type_unknown">ukendt</string>
|
||||||
<string name="activity_type_wakeboarding">wakeboarding</string>
|
<string name="activity_type_wakeboarding">vågneboarding</string>
|
||||||
<string name="activity_type_walking">til fods</string>
|
<string name="activity_type_walking">til fods</string>
|
||||||
<string name="activity_type_water_skiing">vandski</string>
|
<string name="activity_type_water_skiing">vandski</string>
|
||||||
<string name="activity_type_wind_surfing">windsurfing</string>
|
<string name="activity_type_wind_surfing">windsurfing</string>
|
||||||
@@ -178,7 +170,7 @@ g) gør hvad du synes hjælper OpenTracks.</string>
|
|||||||
<string name="description_total_distance">Samlet afstand: %1$.2f km (%2$.1f mil)</string>
|
<string name="description_total_distance">Samlet afstand: %1$.2f km (%2$.1f mil)</string>
|
||||||
<string name="description_total_time">Samlet tid: %1$s</string>
|
<string name="description_total_time">Samlet tid: %1$s</string>
|
||||||
<string name="description_track_point">Punkt</string>
|
<string name="description_track_point">Punkt</string>
|
||||||
<string name="description_track_segment">Segment</string>
|
<string name="description_track_segment">segment</string>
|
||||||
<!-- Export -->
|
<!-- Export -->
|
||||||
<string name="export_all_option">Alle som %1$s</string>
|
<string name="export_all_option">Alle som %1$s</string>
|
||||||
<string name="export_all_title">Eksportér til eksternt lager</string>
|
<string name="export_all_title">Eksportér til eksternt lager</string>
|
||||||
@@ -347,7 +339,7 @@ g) gør hvad du synes hjælper OpenTracks.</string>
|
|||||||
<string name="settings_reset_done">Alle indstillinger er blevet gendannet til standardværdierne</string>
|
<string name="settings_reset_done">Alle indstillinger er blevet gendannet til standardværdierne</string>
|
||||||
<string name="settings_error_initial_values_restored">Beklager, men der opstod en fejl. Alle indstillinger er vendt tilbage til standardværdierne.</string>
|
<string name="settings_error_initial_values_restored">Beklager, men der opstod en fejl. Alle indstillinger er vendt tilbage til standardværdierne.</string>
|
||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor">Sensor</string>
|
<string name="settings_sensor">sensor</string>
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<string name="settings_sensor_bluetooth_sensor">Bluetooth-sensor</string>
|
<string name="settings_sensor_bluetooth_sensor">Bluetooth-sensor</string>
|
||||||
<string name="settings_sensor_connecting">Tilsluttet %1$s</string>
|
<string name="settings_sensor_connecting">Tilsluttet %1$s</string>
|
||||||
@@ -360,8 +352,9 @@ g) gør hvad du synes hjælper OpenTracks.</string>
|
|||||||
<string name="settings_stats_units_title">Foretrukne enheder</string>
|
<string name="settings_stats_units_title">Foretrukne enheder</string>
|
||||||
<!-- Share Track -->
|
<!-- Share Track -->
|
||||||
<string name="share_track_share_file">Del rutefil</string>
|
<string name="share_track_share_file">Del rutefil</string>
|
||||||
<string name="share_track_share_file_body">Du kunne måske være interesseret i denne rute.\n\nDu kan bruge Google Earth eller anden
|
<string name="share_track_share_file_body">Jeg tror, du måske er interesseret i dette nummer.
|
||||||
kortlægningssoftware til at se ruten.\n\n%1$s</string>
|
\n
|
||||||
|
\n%1$s</string>
|
||||||
<string name="share_track_subject">Jeg vil gerne dele en rute med dig</string>
|
<string name="share_track_subject">Jeg vil gerne dele en rute med dig</string>
|
||||||
<!-- Stats -->
|
<!-- Stats -->
|
||||||
<string name="stats_average_moving_pace">Gns. bevægelsestempo</string>
|
<string name="stats_average_moving_pace">Gns. bevægelsestempo</string>
|
||||||
@@ -440,9 +433,9 @@ g) gør hvad du synes hjælper OpenTracks.</string>
|
|||||||
<string name="value_integer_meter_recommended">%1$d m (anbefalet)</string>
|
<string name="value_integer_meter_recommended">%1$d m (anbefalet)</string>
|
||||||
<string name="value_integer_mile">%1$d mil</string>
|
<string name="value_integer_mile">%1$d mil</string>
|
||||||
<string name="value_integer_mile_hour">%1$d mil/t</string>
|
<string name="value_integer_mile_hour">%1$d mil/t</string>
|
||||||
<string name="value_integer_minute">%1$d min.</string>
|
<string name="value_integer_minute">%1$d min</string>
|
||||||
<string name="value_integer_percent">%1$d %%</string>
|
<string name="value_integer_percent">%1$d %%</string>
|
||||||
<string name="value_integer_second">%1$d sek.</string>
|
<string name="value_integer_second">%1$d sek</string>
|
||||||
<string name="value_none">Ingen</string>
|
<string name="value_none">Ingen</string>
|
||||||
<string name="value_off">Fra</string>
|
<string name="value_off">Fra</string>
|
||||||
<string name="value_smallest">Mindste</string>
|
<string name="value_smallest">Mindste</string>
|
||||||
@@ -533,13 +526,13 @@ g) gør hvad du synes hjælper OpenTracks.</string>
|
|||||||
<string name="waypoint_type_pothole">hul i vejen</string>
|
<string name="waypoint_type_pothole">hul i vejen</string>
|
||||||
<string name="waypoint_type_railway_crossing">jernbaneoverskæring</string>
|
<string name="waypoint_type_railway_crossing">jernbaneoverskæring</string>
|
||||||
<string name="waypoint_type_restaurant">restaurant</string>
|
<string name="waypoint_type_restaurant">restaurant</string>
|
||||||
<string name="waypoint_type_shopping">shopping</string>
|
<string name="waypoint_type_shopping">handle ind</string>
|
||||||
<string name="waypoint_type_sight">udsigt</string>
|
<string name="waypoint_type_sight">udsigt</string>
|
||||||
<string name="waypoint_type_store">butik</string>
|
<string name="waypoint_type_store">butik</string>
|
||||||
<string name="waypoint_type_swimming_pool">swimmingpool</string>
|
<string name="waypoint_type_swimming_pool">swimmingpool</string>
|
||||||
<string name="waypoint_type_telephone">telefon</string>
|
<string name="waypoint_type_telephone">telefon</string>
|
||||||
<string name="waypoint_type_theater">teater</string>
|
<string name="waypoint_type_theater">teater</string>
|
||||||
<string name="waypoint_type_toilet">toilet</string>
|
<string name="waypoint_type_toilet">toilette</string>
|
||||||
<string name="waypoint_type_tourist_information">turistinformation</string>
|
<string name="waypoint_type_tourist_information">turistinformation</string>
|
||||||
<string name="waypoint_type_tree">træ</string>
|
<string name="waypoint_type_tree">træ</string>
|
||||||
<string name="waypoint_type_tunnel">tunnel</string>
|
<string name="waypoint_type_tunnel">tunnel</string>
|
||||||
@@ -549,4 +542,72 @@ g) gør hvad du synes hjælper OpenTracks.</string>
|
|||||||
<!-- Share image -->
|
<!-- Share image -->
|
||||||
<string name="share_image_subject">Jeg vil gerne dele et billede med dig</string>
|
<string name="share_image_subject">Jeg vil gerne dele et billede med dig</string>
|
||||||
<string name="share_image_body">Jeg tror, du måske er interesseret i dette billede.</string>
|
<string name="share_image_body">Jeg tror, du måske er interesseret i dette billede.</string>
|
||||||
|
<string name="open_track_as_trackfileformat">Åbn som %1$s</string>
|
||||||
|
<string name="activity_type_escooter">elektrisk scooter</string>
|
||||||
|
<string name="generic_click_twice_cancel">Klik tilbage igen for at annullere</string>
|
||||||
|
<string name="value_float_kilometer_hour">%1$.2f km/t</string>
|
||||||
|
<string name="import_unable_to_import_file">Kunne ikke importere filen:%1$s</string>
|
||||||
|
<string name="value_pace_mile">%1$d:%2$02d min/mi</string>
|
||||||
|
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
|
||||||
|
<string name="import_prevent_reimport">Du har indstillet forhindre genimport af spor</string>
|
||||||
|
<string name="settings_default_export_uri_title">Spor eksportmappe</string>
|
||||||
|
<string name="instant_export_enabled_summary">Eksporter spor til lagring, når optagelsen er færdig</string>
|
||||||
|
<string name="export_progress_summary_new_msg">Nye spor eksporteret</string>
|
||||||
|
<string name="instant_export_enabled_title">Øjeblikkelig eksport efter træning</string>
|
||||||
|
<string name="toast_message_instant_track_was_exported">Sidste spor eksporteret</string>
|
||||||
|
<string name="generic_separator_done_total">/</string>
|
||||||
|
<string name="generic_skip">Springe</string>
|
||||||
|
<string name="description_elevation_loss">Højdetab: %1$d m (%2$d ft)</string>
|
||||||
|
<string name="export_error_post_workout">Eksport efter træning mislykkedes. Kontroller eksportmappen.</string>
|
||||||
|
<string name="export_track_already_exists_msg">Sporet %1$s findes allerede i destinationsmappen.</string>
|
||||||
|
<string name="export_all_do_it_for_all">gør det for alle konflikter</string>
|
||||||
|
<string name="export_track_errors">Spor ikke eksporteret</string>
|
||||||
|
<string name="gps_disabled_msg">GPS deaktiveret</string>
|
||||||
|
<string name="gps_fixed_and_ready">GPS fast og klar</string>
|
||||||
|
<string name="import_no_kml_file_found">Ingen doc.kml-fil fundet i KMZ</string>
|
||||||
|
<string name="sensor_state_cadence_avg">Gennemsnitlig kadence</string>
|
||||||
|
<string name="sensor_state_cadence_max">Max kadence</string>
|
||||||
|
<string name="sensor_state_heart_rate_avg">Gns. Puls</string>
|
||||||
|
<string name="sensor_state_heart_rate_max">Maks. Puls</string>
|
||||||
|
<string name="sensor_state_power_avg">Gennemsnitlig strøm</string>
|
||||||
|
<string name="settings_default_trackfileformat">Eksport/del filformat</string>
|
||||||
|
<string name="settings_recording_fullscreen_on_while_recording_title">Fuld skærm</string>
|
||||||
|
<string name="settings_recording_fullscreen_on_while_recording_summary">Under optagelse, vises på fuld skærm.</string>
|
||||||
|
<string name="settings_night_mode_title">UI Tema</string>
|
||||||
|
<string name="settings_night_mode_option_system">Ordning</string>
|
||||||
|
<string name="settings_night_mode_option_day">Dag</string>
|
||||||
|
<string name="settings_night_mode_option_night">Nat</string>
|
||||||
|
<string name="settings_sensor_wheel_circumference">Hjulets omkreds (mm)</string>
|
||||||
|
<string name="stats_split_interval">Split, divide</string>
|
||||||
|
<string name="stats_intervals">divides</string>
|
||||||
|
<string name="interval_list_empty_message">Der er ikke noget interval endnu</string>
|
||||||
|
<string name="aggregated_stats_empty_message">Optag dit første spor for at se aggregerede statistikker</string>
|
||||||
|
<string name="track_detail_intervals_tab">Intervaller</string>
|
||||||
|
<string name="value_float_mile_hour">%1$.2f mph</string>
|
||||||
|
<string name="voice_pace_lap">Omgangstid på %1$s</string>
|
||||||
|
<string name="voice_speed_lap">Omgangshastighed på %1$s</string>
|
||||||
|
<string name="hold_to_pause">Hold nede for at holde pause</string>
|
||||||
|
<string name="hold_to_stop">Hold for at stoppe</string>
|
||||||
|
<string name="settings_prevent_reimport_tracks_title">Forhindre genimport af spor</string>
|
||||||
|
<plurals name="generic_completed_with_errors">
|
||||||
|
<item quantity="one">Afsluttet med en fejl</item>
|
||||||
|
<item quantity="other">Afsluttet med %1$d fejl</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="stats_loss">Tab</string>
|
||||||
|
<string name="export_progress_summary_overwrite_msg">Spor overskrevet</string>
|
||||||
|
<string name="export_progress_summary_skip_msg">Spor sprunget over</string>
|
||||||
|
<string name="export_progress_summary_errors_msg">Fejl</string>
|
||||||
|
<string name="generic_open_track">Åbn spor</string>
|
||||||
|
<string name="generic_completed">Afsluttet</string>
|
||||||
|
<string name="import_thread_interrupted">Tråden afbrudt</string>
|
||||||
|
<string name="import_unsupported_format">Ikke-understøttet filformat</string>
|
||||||
|
<string name="import_parser_error">Parserfejl:%1$s</string>
|
||||||
|
<string name="import_error_list_dialog_title">Filer ikke importeret</string>
|
||||||
|
<string name="import_progress_summary_ok_msg">Importerede filer</string>
|
||||||
|
<string name="import_progress_summary_exists_msg">Eksisterer allerede</string>
|
||||||
|
<string name="import_progress_summary_errors_msg">Fejl</string>
|
||||||
|
<string name="import_file_imported">Filen%1$s er importeret</string>
|
||||||
|
<string name="import_error_info">%1$s: %2$s</string>
|
||||||
|
<string name="generic_show_errors">Vis fejl</string>
|
||||||
|
<string name="generic_overwrite">Overskriv</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?><!--
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
Copyright 2010 Google Inc.
|
Copyright 2010 Google Inc.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -12,8 +13,7 @@ distributed under the License is distributed on an "AS IS" BASIS,
|
|||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
--><resources>
|
||||||
<resources>
|
|
||||||
<string name="about_preference_title">Über OpenTracks</string>
|
<string name="about_preference_title">Über OpenTracks</string>
|
||||||
<string name="about_description"><i>OpenTracks</i> ist eine Sport-Tracking-Anwendung, die Ihre Privatsphäre vollständig respektiert.</string>
|
<string name="about_description"><i>OpenTracks</i> ist eine Sport-Tracking-Anwendung, die Ihre Privatsphäre vollständig respektiert.</string>
|
||||||
<string name="about_url">Projekt-Website: <a href="%1$s">%1$s</a></string>
|
<string name="about_url">Projekt-Website: <a href="%1$s">%1$s</a></string>
|
||||||
@@ -30,7 +30,6 @@ limitations under the License.
|
|||||||
* Markierungen erstellen (inkl. Bilder)\n
|
* Markierungen erstellen (inkl. Bilder)\n
|
||||||
* arbeitet vollständig offline\n
|
* arbeitet vollständig offline\n
|
||||||
* Tracks auf einer Karte anzeigen (siehe unten)</string>
|
* Tracks auf einer Karte anzeigen (siehe unten)</string>
|
||||||
|
|
||||||
<string name="help_track_map_title">Wie wird ein Track auf einer Karte angezeigt?</string>
|
<string name="help_track_map_title">Wie wird ein Track auf einer Karte angezeigt?</string>
|
||||||
<string name="help_track_map_content">
|
<string name="help_track_map_content">
|
||||||
Verwende das kleine Kartensymbol.\n
|
Verwende das kleine Kartensymbol.\n
|
||||||
@@ -44,39 +43,28 @@ b)
|
|||||||
Über eine normale Kartenanwendung (z.B. <a href="http://osmand.net/">OsmAnd</a> und <a href="https://maps.me/">MAPS.ME</a>).
|
Über eine normale Kartenanwendung (z.B. <a href="http://osmand.net/">OsmAnd</a> und <a href="https://maps.me/">MAPS.ME</a>).
|
||||||
Diese Anwendungen müssen das KMZ-Dateiformat unterstützen (nur Orte und Zeitstempel).
|
Diese Anwendungen müssen das KMZ-Dateiformat unterstützen (nur Orte und Zeitstempel).
|
||||||
In der Tat muss eine App <i>ACTION_VIEW</i> mit MIME <i>application/vnd.google-earth.kmz</i> unterstützen.</string>
|
In der Tat muss eine App <i>ACTION_VIEW</i> mit MIME <i>application/vnd.google-earth.kmz</i> unterstützen.</string>
|
||||||
|
|
||||||
<string name="help_storage_pictures_title">Wie speichert OpenTracks Bilder, die als Markierungen aufgenommen wurden?</string>
|
<string name="help_storage_pictures_title">Wie speichert OpenTracks Bilder, die als Markierungen aufgenommen wurden?</string>
|
||||||
<string name="help_storage_pictures_content">Diese werden App-intern gespeichert (d.h. nur innerhalb von OpenTracks zugänglich).</string>
|
<string name="help_storage_pictures_content">Diese werden App-intern gespeichert (d.h. nur innerhalb von OpenTracks zugänglich).</string>
|
||||||
|
|
||||||
<string name="help_track_export_title">Wie kann ich aufgezeichnete Tracks exportieren/teilen?</string>
|
<string name="help_track_export_title">Wie kann ich aufgezeichnete Tracks exportieren/teilen?</string>
|
||||||
<string name="help_track_export_content">
|
<string name="help_track_export_content"> Tracks können aus den Einstellungen als KMZ, KML oder GPX exportiert werden. KMZ/KML alle Daten; GPX nur Standorte. Tracks, die über das Symbol <i>Teilen Icon</i> freigegeben werden, werden als KMZ freigegeben. </string>
|
||||||
Tracks können aus den Einstellungen als KMZ, KML oder GPX exportiert werden.
|
|
||||||
KMZ/KML alle Daten; GPX nur Standorte.
|
|
||||||
Tracks, die über das Symbol <i>Teilen Icon</i> freigegeben werden, werden als KMZ freigegeben.</string>
|
|
||||||
|
|
||||||
<string name="help_data_google_play_services_title">Benötigt/benutzt OpenTracks den Google Play Service?</string>
|
<string name="help_data_google_play_services_title">Benötigt/benutzt OpenTracks den Google Play Service?</string>
|
||||||
|
|
||||||
<string name="help_recording_title">Wie zeichnet OpenTracks Daten auf?</string>
|
<string name="help_recording_title">Wie zeichnet OpenTracks Daten auf?</string>
|
||||||
<string name="help_recording_content">
|
<string name="help_recording_content">
|
||||||
OpenTracks verwendet den GPS-Sensor des Geräts, um den Standort kontinuierlich aufzuzeichnen.
|
OpenTracks verwendet den GPS-Sensor des Geräts, um den Standort kontinuierlich aufzuzeichnen.
|
||||||
Meldet das GPS-Gerät ungenaue Daten (z.B. Standort, Geschwindigkeit, Höhe), kann OpenTracks nichts dagegen unternehmen.</string>
|
Meldet das GPS-Gerät ungenaue Daten (z.B. Standort, Geschwindigkeit, Höhe), kann OpenTracks nichts dagegen unternehmen.</string>
|
||||||
|
|
||||||
<string name="help_data_storage_title">Wie speichert OpenTracks Sensordaten?</string>
|
<string name="help_data_storage_title">Wie speichert OpenTracks Sensordaten?</string>
|
||||||
<string name="help_data_storage_content">
|
<string name="help_data_storage_content">
|
||||||
Sensordaten werden pro aufgezeichneter Stelle gespeichert.
|
Sensordaten werden pro aufgezeichneter Stelle gespeichert.
|
||||||
Bezogen auf einen Herzfrequenzsensor bedeutet dies, dass nur <i>eine</i>Herzfrequenzmessung pro Ort gespeichert wird.
|
Bezogen auf einen Herzfrequenzsensor bedeutet dies, dass nur <i>eine</i>Herzfrequenzmessung pro Ort gespeichert wird.
|
||||||
Wenn Du still stehst oder du dich in geschlossenen Räumen aufhälst, werden keine Sensordaten aufgezeichnet (aber angezeigt).</string>
|
Wenn Du still stehst oder du dich in geschlossenen Räumen aufhälst, werden keine Sensordaten aufgezeichnet (aber angezeigt).</string>
|
||||||
|
|
||||||
<string name="help_gps_troubleshooting_title">OpenTracks zeichnet keine Standorte auf?</string>
|
<string name="help_gps_troubleshooting_title">OpenTracks zeichnet keine Standorte auf?</string>
|
||||||
<string name="help_gps_troubleshooting_content">
|
<string name="help_gps_troubleshooting_content"> Was Du tun kannst:
|
||||||
Was Du tun kannst:\n
|
\n a) prüfen, ob GPS aktiviert ist,
|
||||||
a) prüfen, ob GPS aktiviert ist,\n
|
\n b) den GPS-Empfang verbessern (z.B. ins Freie gehen),
|
||||||
b) den GPS-Empfang verbessern (z.B. ins Freie gehen),\n
|
\n c) mit der <a href="https://f-droid.org/en/packages/com.android.gpstest.osmdroid/">GPSTest</a>-App das GPS testen, und
|
||||||
c) prüfen, ob mit <a href="https://f-droid.org/en/packages/com.android.gpstest.osmdroid/">GPSTest</a> app, und\n
|
\n d) Energiesparen deaktivieren.
|
||||||
d) Energiesparen deaktivieren.\n
|
|
||||||
\n
|
\n
|
||||||
Wenn alles nicht hilft, melde bitte einen Fehler.</string>
|
\n Wenn das alles nicht hilft, melde bitte einen Fehler. </string>
|
||||||
|
|
||||||
<string name="help_support_title">Wie kann ich OpenTracks unterstützen?</string>
|
<string name="help_support_title">Wie kann ich OpenTracks unterstützen?</string>
|
||||||
<string name="help_support_content">
|
<string name="help_support_content">
|
||||||
Du kannst:\n
|
Du kannst:\n
|
||||||
@@ -87,12 +75,10 @@ d) Hilfe bei der Software-Entwicklung,\n
|
|||||||
e) kaufen in <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore">Google Play Store</a>,\n
|
e) kaufen in <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore">Google Play Store</a>,\n
|
||||||
f) spenden, und\n
|
f) spenden, und\n
|
||||||
g) das tun, was Deiner Meinung nach OpenTracks hilft.</string>
|
g) das tun, was Deiner Meinung nach OpenTracks hilft.</string>
|
||||||
|
|
||||||
<string name="open_track_using_dashboard">Öffne mithilfe des OpenTracks-Dashboard</string>
|
<string name="open_track_using_dashboard">Öffne mithilfe des OpenTracks-Dashboard</string>
|
||||||
<string name="open_track_as_KMZ">Als KMZ öffnen</string>
|
<string name="open_track_as_KMZ">Als KMZ öffnen</string>
|
||||||
<string name="open_track_as_GPX">Als GPX öffnen</string>
|
<string name="open_track_as_GPX">Als GPX öffnen</string>
|
||||||
<string name="open_track_as_trackfileformat">Als %1$s öffnen</string>
|
<string name="open_track_as_trackfileformat">Als %1$s öffnen</string>
|
||||||
|
|
||||||
<!-- Activity Type -->
|
<!-- Activity Type -->
|
||||||
<string name="activity_type_airplane">Flugzeug</string>
|
<string name="activity_type_airplane">Flugzeug</string>
|
||||||
<string name="activity_type_atv">Quad</string>
|
<string name="activity_type_atv">Quad</string>
|
||||||
@@ -370,21 +356,20 @@ g) das tun, was Deiner Meinung nach OpenTracks hilft.</string>
|
|||||||
<string name="settings_sensor_bluetooth_sensor">Bluetooth-Sensor</string>
|
<string name="settings_sensor_bluetooth_sensor">Bluetooth-Sensor</string>
|
||||||
<string name="settings_sensor_connecting">Verbunden mit %1$s</string>
|
<string name="settings_sensor_connecting">Verbunden mit %1$s</string>
|
||||||
<string name="settings_sensor_disconnected">Verbindung getrennt von %1$s</string>
|
<string name="settings_sensor_disconnected">Verbindung getrennt von %1$s</string>
|
||||||
|
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Breiten-/Längengrad</string>
|
<string name="settings_stats_coordinate">Breiten-/Längengrad</string>
|
||||||
<string name="settings_stats_rate_title">Bevorzugtes Maß</string>
|
<string name="settings_stats_rate_title">Bevorzugtes Maß</string>
|
||||||
<string name="settings_stats_units_imperial">Englisch (mi, ft)</string>
|
<string name="settings_stats_units_imperial">Englisch (mi, ft)</string>
|
||||||
<string name="settings_stats_units_metric">Metrisch (km, m)</string>
|
<string name="settings_stats_units_metric">Metrisch (km, m)</string>
|
||||||
<string name="settings_stats_units_title">Bevorzugte Einheiten</string>
|
<string name="settings_stats_units_title">Bevorzugte Einheiten</string>
|
||||||
|
|
||||||
<!-- Share Track -->
|
<!-- Share Track -->
|
||||||
<string name="share_track_share_file">Track-Datei teilen</string>
|
<string name="share_track_share_file">Track-Datei teilen</string>
|
||||||
<string name="share_track_share_file_body">Dieser Track könnte dich interessieren.\n\nDu kannst ihn dir mit Google Earth oder einer anderen Kartierungssoftware ansehen.\n\n%1$s</string>
|
<string name="share_track_share_file_body">Dieser Track könnte dich interessieren.\n\nDu kannst ihn dir mit Google Earth oder einer anderen Kartierungssoftware ansehen.\n\n%1$s</string>
|
||||||
<string name="share_track_subject">Ich möchte einen Track mit dir teilen</string>
|
<string name="share_track_subject">Ich möchte einen Track mit dir teilen</string>
|
||||||
<!-- Stats -->
|
<!-- Stats -->
|
||||||
<string name="stats_average_moving_pace">Durchschnitt\n(Bewegung)</string>
|
<string name="stats_average_moving_pace">Durchschnitt\n(Bewegung)</string>
|
||||||
<string name="stats_average_moving_speed">Durchschnitt\n(Bewegung)</string>
|
<string name="stats_average_moving_speed">Durchschnittsgeshwindigkeit
|
||||||
|
\n(Bewegung)</string>
|
||||||
<string name="stats_average_pace">Durchschnitt</string>
|
<string name="stats_average_pace">Durchschnitt</string>
|
||||||
<string name="stats_average_speed">Durchschnitt</string>
|
<string name="stats_average_speed">Durchschnitt</string>
|
||||||
<string name="stats_elevation">Höhe</string>
|
<string name="stats_elevation">Höhe</string>
|
||||||
@@ -394,7 +379,7 @@ g) das tun, was Deiner Meinung nach OpenTracks hilft.</string>
|
|||||||
<string name="stats_latitude">Breitengrad</string>
|
<string name="stats_latitude">Breitengrad</string>
|
||||||
<string name="stats_longitude">Längengrad</string>
|
<string name="stats_longitude">Längengrad</string>
|
||||||
<string name="stats_max">Max.</string>
|
<string name="stats_max">Max.</string>
|
||||||
<string name="stats_max_speed">Max.</string>
|
<string name="stats_max_speed">Max. Geschwindigkeit</string>
|
||||||
<string name="stats_min">Min.</string>
|
<string name="stats_min">Min.</string>
|
||||||
<string name="stats_moving_time">Bewegungszeit</string>
|
<string name="stats_moving_time">Bewegungszeit</string>
|
||||||
<string name="stats_pace">Tempo</string>
|
<string name="stats_pace">Tempo</string>
|
||||||
@@ -570,5 +555,18 @@ g) das tun, was Deiner Meinung nach OpenTracks hilft.</string>
|
|||||||
<!-- Share image -->
|
<!-- Share image -->
|
||||||
<string name="share_image_subject">Ich möchte gerne ein Bild mit Dir teilen</string>
|
<string name="share_image_subject">Ich möchte gerne ein Bild mit Dir teilen</string>
|
||||||
<string name="share_image_body">Ich denke, dieses Bild könnte Dich interessieren.</string>
|
<string name="share_image_body">Ich denke, dieses Bild könnte Dich interessieren.</string>
|
||||||
|
<string name="settings_night_mode_title">UI Thema</string>
|
||||||
|
<string name="settings_night_mode_option_system">System</string>
|
||||||
|
<string name="settings_night_mode_option_day">Tag</string>
|
||||||
|
<string name="settings_night_mode_option_night">Nacht</string>
|
||||||
|
<string name="settings_sensor_wheel_circumference">Radumfang (mm)</string>
|
||||||
|
<string name="stats_loss">Abstieg</string>
|
||||||
|
<string name="hold_to_stop">Halten zum Anhalten</string>
|
||||||
|
<string name="import_progress_summary_errors_msg">Fehler</string>
|
||||||
|
<string name="import_progress_summary_exists_msg">Schon vorhanden</string>
|
||||||
|
<string name="export_track_errors">Tracks werden nicht exportiert</string>
|
||||||
|
<string name="settings_default_export_uri_title">Track Export Verzeichnis</string>
|
||||||
|
<string name="import_progress_summary_ok_msg">Dateien importiert</string>
|
||||||
|
<string name="export_all_do_it_for_all">für alle Konflikte anwenden</string>
|
||||||
|
<string name="export_progress_summary_new_msg">Neue Tracks exportiert</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -23,62 +23,45 @@ limitations under the License.
|
|||||||
<string name="about_libraries">Bibliotecas</string>
|
<string name="about_libraries">Bibliotecas</string>
|
||||||
<!-- Help -->
|
<!-- Help -->
|
||||||
<string name="help_feature_title">OpenTracks tiene las siguientes características:</string>
|
<string name="help_feature_title">OpenTracks tiene las siguientes características:</string>
|
||||||
<string name="help_feature_content">
|
<string name="help_feature_content">* crear pistas de GPS
|
||||||
* crear un seguimiento GPS *
|
\n* utilizar un sensor de frecuencia cardíaca (solo Bluetooth LE)
|
||||||
* usa un sensor de ritmo cardíaco (sólo Bluetooth LE) *
|
\n* Anuncios de voz (por tiempo o distancia)
|
||||||
* anuncios de voz (por tiempo o distancia)*
|
\n* crear marcadores (incluidas imágenes)
|
||||||
* crear marcadores (incluyendo imágenes) *
|
\n* funciona completamente sin conexión
|
||||||
* funciona completamente fuera de línea *
|
\n* mostrar pistas en un mapa (ver más abajo)</string>
|
||||||
* mostrar las pistas en un mapa (ver abajo)</string>
|
|
||||||
<string name="help_track_map_title">¿Cómo mostrar una pista en un mapa?</string>
|
<string name="help_track_map_title">¿Cómo mostrar una pista en un mapa?</string>
|
||||||
<string name="help_track_map_content">
|
<string name="help_track_map_content"> Usa el icono del mapa pequeño.
|
||||||
Usa el icono del mapa pequeño.
|
\na) (actualizaciones en vivo) Instalar <a href="https://github.com/OpenTracksApp/OSMDashboard">OSMDashboard</a>. Proporciona mapas en línea o fuera de línea a través de <a href="https://www.openstreetmap.org">OpenStreetMap</a>.
|
||||||
a)
|
\n En realidad, OSMDashboard es una aplicación independiente que sólo puede acceder (temporalmente) a los datos de las pist(as) que se van a mostrar.
|
||||||
(actualizaciones en vivo) Instalar <a href="https://github.com/OpenTracksApp/OSMDashboard">OSMDashboard</a>.
|
\n b) A través de una aplicación de mapas normal (por ejemplo, <a href="http://osmand.net/">OsmAnd</a> y <a href="https://maps.me/">MAPS.ME</a>). Estas aplicaciones necesitan soportar el formato de archivo KMZ (sólo las ubicaciones y las marcas de tiempo). De hecho, una aplicación necesita soportar <i>ACTION_VIEW</i> con MIME <i>application/vnd.google-earth.kmz</i>. </string>
|
||||||
Proporciona mapas en línea o fuera de línea a través de <a href="https://www.openstreetmap.org">OpenStreetMap</a>.\n
|
|
||||||
En realidad, OSMDashboard es una aplicación independiente que sólo puede acceder (temporalmente) a los datos de las pist(as) que se van a mostrar.
|
|
||||||
|
|
||||||
\n
|
|
||||||
b)
|
|
||||||
A través de una aplicación de mapas normal (por ejemplo, <a href="http://osmand.net/">OsmAnd</a> y <a href="https://maps.me/">MAPS.ME</a>).
|
|
||||||
Estas aplicaciones necesitan soportar el formato de archivo KMZ (sólo las ubicaciones y las marcas de tiempo).
|
|
||||||
De hecho, una aplicación necesita soportar <i>ACTION_VIEW</i> con MIME <i>application/vnd.google-earth.kmz</i>.</string>
|
|
||||||
<string name="help_storage_pictures_title">¿Cómo almacena OpenTracks las fotos que fueron tomadas como marcadores?</string>
|
<string name="help_storage_pictures_title">¿Cómo almacena OpenTracks las fotos que fueron tomadas como marcadores?</string>
|
||||||
<string name="help_storage_pictures_content">Estos se almacenan en el almacenamiento interno de la aplicación (es decir, sólo accesible dentro de OpenTracks).</string>
|
<string name="help_storage_pictures_content">Estos se almacenan en el almacenamiento interno de la aplicación (es decir, sólo accesible dentro de OpenTracks).</string>
|
||||||
<string name="help_track_export_title">¿Cómo puedo exportar/compartir las pistas grabadas?</string>
|
<string name="help_track_export_title">¿Cómo puedo exportar/compartir las pistas grabadas?</string>
|
||||||
<string name="help_track_export_content">
|
<string name="help_track_export_content"> Las pistas pueden ser exportadas desde los ajustes como KMZ, KML o GPX. KMZ/KML todos los datos; GPX sólo las ubicaciones. Las pistas compartidas a través del <i> icono de compartir </i> se comparten como KMZ. </string>
|
||||||
Las pistas pueden ser exportadas desde los ajustes como KMZ, KML o GPX.
|
|
||||||
KMZ/KML todos los datos; GPX sólo las ubicaciones.
|
|
||||||
Las pistas compartidas a través del <i> icono de compartir </i> se comparten como KMZ.</string>
|
|
||||||
<string name="help_data_google_play_services_title">¿Requiere OpenTracks usar el servicio de Google Play?</string>
|
<string name="help_data_google_play_services_title">¿Requiere OpenTracks usar el servicio de Google Play?</string>
|
||||||
<string name="help_recording_title">¿Cómo registra OpenTracks los datos?</string>
|
<string name="help_recording_title">¿Cómo registra OpenTracks los datos?</string>
|
||||||
<string name="help_recording_content">
|
<string name="help_recording_content">
|
||||||
OpenTracks utiliza el sensor GPS del dispositivo para registrar la ubicación de forma continua.
|
OpenTracks utiliza el sensor GPS del dispositivo para registrar la ubicación de forma continua.
|
||||||
Si el dispositivo GPS reporta datos inexactos (por ejemplo, ubicación, velocidad, elevación), OpenTracks no puede hacer nada al respecto.</string>
|
Si el dispositivo GPS reporta datos inexactos (por ejemplo, ubicación, velocidad, elevación), OpenTracks no puede hacer nada al respecto.</string>
|
||||||
<string name="help_data_storage_title">¿Cómo almacena OpenTracks los datos de los sensores?</string>
|
<string name="help_data_storage_title">¿Cómo almacena OpenTracks los datos de los sensores?</string>
|
||||||
<string name="help_data_storage_content">
|
<string name="help_data_storage_content"> Los datos de los sensores se almacenan por cada ubicación registrada. En términos de un sensor de frecuencia cardíaca, esto significa que sólo <i>uno</i> la medición de la frecuencia cardíaca se almacena por ubicación. Si está parado o en el interior, no se registrarán los datos del sensor (pero se mostrarán). </string>
|
||||||
Los datos de los sensores se almacenan por cada ubicación registrada.
|
|
||||||
En términos de un sensor de frecuencia cardíaca, esto significa que sólo <i>uno</i> la medición de la frecuencia cardíaca se almacena por ubicación.
|
|
||||||
Si está parado o en el interior, no se registrarán los datos del sensor (pero se mostrarán).</string>
|
|
||||||
<string name="help_gps_troubleshooting_title">OpenTracks no está grabando las localizaciones?</string>
|
<string name="help_gps_troubleshooting_title">OpenTracks no está grabando las localizaciones?</string>
|
||||||
<string name="help_gps_troubleshooting_content">
|
<string name="help_gps_troubleshooting_content"> Lo que puedes hacer:
|
||||||
Lo que puedes hacer...
|
\na) compruebe si el GPS está habilitado,
|
||||||
a) Comprobar si el GPS está activado.
|
\nb) mejorar la recepción del GPS (por ejemplo, salir al aire libre),
|
||||||
b) mejorar la recepción del GPS (por ejemplo, ir al exterior),\n
|
\nc) verifique con la aplicación <a href="https://f-droid.org/en/packages/com.android.gpstest.osmdroid/"> GPSTest </a>, y
|
||||||
c) comprueba si con <a href="https://f-droid.org/en/packages/com.android.gpstest.osmdroid/">GPSTest</a> app, y\n
|
\nd) desactivar el ahorro de energía.
|
||||||
d) desactivar el ahorro de energía.
|
|
||||||
\n
|
\n
|
||||||
Si todo no ayuda, por favor informe de un error.</string>
|
\nSi todo no ayuda, informe un error. </string>
|
||||||
<string name="help_support_title">¿Cómo puedo apoyar OpenTracks?</string>
|
<string name="help_support_title">¿Cómo puedo apoyar OpenTracks?</string>
|
||||||
<string name="help_support_content">
|
<string name="help_support_content"> Usted puede:
|
||||||
Puedes...
|
\n a) difundir la existencia de OpenTracks,
|
||||||
a) difundir la palabra sobre OpenTracks,...
|
\n b) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">proponer características</a>,
|
||||||
b) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">proponer características</a>,\n
|
\n c) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">reportar errores</a>,
|
||||||
c) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">report bugs</a>,\n
|
\n d) ayudar en el desarrollo del software,
|
||||||
d) ayudar en el desarrollo de software,\n
|
\n e) comprar en <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore">Google Play Store</a>,
|
||||||
e) comprar en <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore">Google Play Store</a>,\n
|
\n f) donar, y
|
||||||
f) donar, y
|
\n g) hacer lo que creas que ayuda a OpenTracks. </string>
|
||||||
g) haz lo que creas que ayude a OpenTracks.</string>
|
|
||||||
<!-- Activity Type -->
|
<!-- Activity Type -->
|
||||||
<string name="activity_type_airplane">avión</string>
|
<string name="activity_type_airplane">avión</string>
|
||||||
<string name="activity_type_atv">vehículos todoterreno</string>
|
<string name="activity_type_atv">vehículos todoterreno</string>
|
||||||
@@ -94,8 +77,8 @@ g) haz lo que creas que ayude a OpenTracks.</string>
|
|||||||
<string name="activity_type_driving">conducir</string>
|
<string name="activity_type_driving">conducir</string>
|
||||||
<string name="activity_type_driving_bus">ruta en autobús</string>
|
<string name="activity_type_driving_bus">ruta en autobús</string>
|
||||||
<string name="activity_type_driving_car">ruta en automóvil</string>
|
<string name="activity_type_driving_car">ruta en automóvil</string>
|
||||||
<string name="activity_type_ferry">ferry</string>
|
<string name="activity_type_ferry">balsa</string>
|
||||||
<string name="activity_type_frisbee">frisbee</string>
|
<string name="activity_type_frisbee">Friso</string>
|
||||||
<string name="activity_type_gliding">vuelo sin motor</string>
|
<string name="activity_type_gliding">vuelo sin motor</string>
|
||||||
<string name="activity_type_hang_gliding">vuelo en ala delta</string>
|
<string name="activity_type_hang_gliding">vuelo en ala delta</string>
|
||||||
<string name="activity_type_helicopter">helicóptero</string>
|
<string name="activity_type_helicopter">helicóptero</string>
|
||||||
@@ -301,14 +284,14 @@ g) haz lo que creas que ayude a OpenTracks.</string>
|
|||||||
<!-- Search -->
|
<!-- Search -->
|
||||||
<string name="search_global_description">Recorridos y marcadores</string>
|
<string name="search_global_description">Recorridos y marcadores</string>
|
||||||
<string name="search_list_empty_message">No hay rutas ni marcadores que coincidan con tu búsqueda</string>
|
<string name="search_list_empty_message">No hay rutas ni marcadores que coincidan con tu búsqueda</string>
|
||||||
<string name="search_list_marker_track_location">En la ruta \"%1$s\"</string>
|
<string name="search_list_marker_track_location">En la ruta \"%1$s\".</string>
|
||||||
<!-- Sensor State -->
|
<!-- Sensor State -->
|
||||||
<string name="sensor_state_battery">Nivel de batería</string>
|
<string name="sensor_state_battery">Nivel de batería</string>
|
||||||
<string name="sensor_state_cadence">Cadencia</string>
|
<string name="sensor_state_cadence">Cadencia</string>
|
||||||
<string name="sensor_state_cadence_value">%1$d rpm</string>
|
<string name="sensor_state_cadence_value">%1$d rym</string>
|
||||||
<string name="sensor_state_disconnected">Desconectado</string>
|
<string name="sensor_state_disconnected">Desconectado</string>
|
||||||
<string name="sensor_state_heart_rate">Frecuencia cardíaca</string>
|
<string name="sensor_state_heart_rate">Frecuencia cardíaca</string>
|
||||||
<string name="sensor_state_heart_rate_value">%1$d bpm</string>
|
<string name="sensor_state_heart_rate_value">%1$d ppm</string>
|
||||||
<string name="sensor_state_power">Potencia</string>
|
<string name="sensor_state_power">Potencia</string>
|
||||||
<string name="sensor_state_power_value">%1$d W</string>
|
<string name="sensor_state_power_value">%1$d W</string>
|
||||||
<string name="sensor_not_known">Sensor %1$s es desconocido. Por favor, compruebe la configuración.</string>
|
<string name="sensor_not_known">Sensor %1$s es desconocido. Por favor, compruebe la configuración.</string>
|
||||||
@@ -330,15 +313,15 @@ g) haz lo que creas que ayude a OpenTracks.</string>
|
|||||||
<string name="settings_recording">Grabación</string>
|
<string name="settings_recording">Grabación</string>
|
||||||
<string name="settings_recording_auto_resume_track_timeout_always_summary">Reanudar siempre una grabación después de reiniciar</string>
|
<string name="settings_recording_auto_resume_track_timeout_always_summary">Reanudar siempre una grabación después de reiniciar</string>
|
||||||
<string name="settings_recording_auto_resume_track_timeout_never_summary">No reanudar nunca una grabación después de reiniciar</string>
|
<string name="settings_recording_auto_resume_track_timeout_never_summary">No reanudar nunca una grabación después de reiniciar</string>
|
||||||
<string name="settings_recording_auto_resume_track_timeout_summary">Esta opción permite reanudar una grabación después de reiniciar si la última ubicación grabada se encuentra dentro de los últimos %1$s.</string>
|
<string name="settings_recording_auto_resume_track_timeout_summary">Esta opción permite reanudar una grabación después de reiniciar si la última ubicación grabada se encuentra dentro de los últimos %1$s</string>
|
||||||
<string name="settings_recording_auto_resume_track_timeout_title">Reanudación automática</string>
|
<string name="settings_recording_auto_resume_track_timeout_title">Reanudación automática</string>
|
||||||
<string name="settings_recording_default_activity_title">Actividad predeterminada</string>
|
<string name="settings_recording_default_activity_title">Actividad predeterminada</string>
|
||||||
<string name="settings_recording_location_frequency_summary">%1$s entre ubicaciones grabadas</string>
|
<string name="settings_recording_location_frequency_summary">%1$s entre ubicaciones grabadas</string>
|
||||||
<string name="settings_recording_max_recording_distance_summary">Esta opción permite crear un nuevo segmento si la distancia entre dos ubicaciones es superior a %1$s.</string>
|
<string name="settings_recording_max_recording_distance_summary">Esta opción permite crear un nuevo segmento si la distancia entre dos ubicaciones es superior a %1$s</string>
|
||||||
<string name="settings_recording_max_recording_distance_title">Distancia máxima</string>
|
<string name="settings_recording_max_recording_distance_title">Distancia máxima</string>
|
||||||
<string name="settings_recording_min_recording_distance_title">Intervalo de distancia</string>
|
<string name="settings_recording_min_recording_distance_title">Intervalo de distancia</string>
|
||||||
<string name="settings_recording_min_recording_interval_title">Intervalo de tiempo</string>
|
<string name="settings_recording_min_recording_interval_title">Intervalo de tiempo</string>
|
||||||
<string name="settings_recording_min_required_accuracy_summary">Esta opción permite ignorar la ubicación si su precisión es inferior a %1$s.</string>
|
<string name="settings_recording_min_required_accuracy_summary">Esta opción permite ignorar la ubicación si su precisión es inferior a %1$s</string>
|
||||||
<string name="settings_recording_min_required_accuracy_title">Exactitud del GPS</string>
|
<string name="settings_recording_min_required_accuracy_title">Exactitud del GPS</string>
|
||||||
<string name="settings_recording_track_name_date_iso_8601_option">Fecha (ISO 8601)</string>
|
<string name="settings_recording_track_name_date_iso_8601_option">Fecha (ISO 8601)</string>
|
||||||
<string name="settings_recording_track_name_date_local_option">Fecha (local)</string>
|
<string name="settings_recording_track_name_date_local_option">Fecha (local)</string>
|
||||||
@@ -351,7 +334,7 @@ g) haz lo que creas que ayude a OpenTracks.</string>
|
|||||||
<string name="settings_reset_done">Se han restablecido los valores predeterminados de todas las opciones de configuración</string>
|
<string name="settings_reset_done">Se han restablecido los valores predeterminados de todas las opciones de configuración</string>
|
||||||
<string name="settings_error_initial_values_restored">Lo siento, pero ha habido un error. Todos los ajustes se han vuelto a los valores predeterminados.</string>
|
<string name="settings_error_initial_values_restored">Lo siento, pero ha habido un error. Todos los ajustes se han vuelto a los valores predeterminados.</string>
|
||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor">Sensor</string>
|
<string name="settings_sensor">Objetivo</string>
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<string name="settings_sensor_bluetooth_sensor">Sensor Bluetooth</string>
|
<string name="settings_sensor_bluetooth_sensor">Sensor Bluetooth</string>
|
||||||
<string name="settings_sensor_connecting">Conectado a %1$s</string>
|
<string name="settings_sensor_connecting">Conectado a %1$s</string>
|
||||||
@@ -364,7 +347,9 @@ g) haz lo que creas que ayude a OpenTracks.</string>
|
|||||||
<string name="settings_stats_units_title">Unidades preferidas</string>
|
<string name="settings_stats_units_title">Unidades preferidas</string>
|
||||||
<!-- Share Track -->
|
<!-- Share Track -->
|
||||||
<string name="share_track_share_file">Compartir el archivo de la ruta</string>
|
<string name="share_track_share_file">Compartir el archivo de la ruta</string>
|
||||||
<string name="share_track_share_file_body">Creo que esta ruta te podría interesar.\n\nPara ver esta ruta, usa Google Earth u otro software de mapas.\n\n%1$s</string>
|
<string name="share_track_share_file_body">Creo que esta ruta te podría interesar.
|
||||||
|
\n
|
||||||
|
\n%1$s</string>
|
||||||
<string name="share_track_subject">Me gustaría compartir una ruta contigo</string>
|
<string name="share_track_subject">Me gustaría compartir una ruta contigo</string>
|
||||||
<!-- Stats -->
|
<!-- Stats -->
|
||||||
<string name="stats_average_moving_pace">Ritmo de movimiento medio</string>
|
<string name="stats_average_moving_pace">Ritmo de movimiento medio</string>
|
||||||
@@ -512,7 +497,7 @@ g) haz lo que creas que ayude a OpenTracks.</string>
|
|||||||
<string name="waypoint_type_convenience_store">tienda de barrio</string>
|
<string name="waypoint_type_convenience_store">tienda de barrio</string>
|
||||||
<string name="waypoint_type_drinking_water">agua potable</string>
|
<string name="waypoint_type_drinking_water">agua potable</string>
|
||||||
<string name="waypoint_type_falling_rocks">desprendimiento de rocas</string>
|
<string name="waypoint_type_falling_rocks">desprendimiento de rocas</string>
|
||||||
<string name="waypoint_type_ferry">ferry</string>
|
<string name="waypoint_type_ferry">barco</string>
|
||||||
<string name="waypoint_type_fire_place">chimenea</string>
|
<string name="waypoint_type_fire_place">chimenea</string>
|
||||||
<string name="waypoint_type_fire_station">parque de bomberos</string>
|
<string name="waypoint_type_fire_station">parque de bomberos</string>
|
||||||
<string name="waypoint_type_fishing">enclave pesquero</string>
|
<string name="waypoint_type_fishing">enclave pesquero</string>
|
||||||
@@ -574,13 +559,13 @@ g) haz lo que creas que ayude a OpenTracks.</string>
|
|||||||
<string name="settings_night_mode_option_day">Claro</string>
|
<string name="settings_night_mode_option_day">Claro</string>
|
||||||
<string name="settings_night_mode_option_night">Oscuro</string>
|
<string name="settings_night_mode_option_night">Oscuro</string>
|
||||||
<string name="settings_night_mode_title">Elegir un tema</string>
|
<string name="settings_night_mode_title">Elegir un tema</string>
|
||||||
<string name="settings_sensor_wheel_circumference">Circunferencia de rueda (mm)</string>
|
<string name="settings_sensor_wheel_circumference">Perímetro de la rueda (mm)</string>
|
||||||
<string name="stats_intervals">Intervalos</string>
|
<string name="stats_intervals">Intervalos</string>
|
||||||
<string name="stats_split_interval">Intervalo</string>
|
<string name="stats_split_interval">Intervalo</string>
|
||||||
<string name="track_detail_intervals_tab">Intervalos</string>
|
<string name="track_detail_intervals_tab">Intervalos</string>
|
||||||
<string name="aggregated_stats_empty_message">Graba tu primera pista para ver estadísticas agregadas</string>
|
<string name="aggregated_stats_empty_message">Graba tu primera pista para ver estadísticas agregadas</string>
|
||||||
<string name="voice_pace_lap">Tiempo de la vuelta %1$s</string>
|
<string name="voice_pace_lap">Tiempo de la vuelta %1$s</string>
|
||||||
<string name="hold_to_pause">Mantén pulsado para pausar la grabación</string>
|
<string name="hold_to_pause">Mantener en pausa</string>
|
||||||
<string name="instant_export_enabled_title">Exportación automática tras grabación</string>
|
<string name="instant_export_enabled_title">Exportación automática tras grabación</string>
|
||||||
<string name="settings_default_export_uri_title">Carpeta de pistas exportadas</string>
|
<string name="settings_default_export_uri_title">Carpeta de pistas exportadas</string>
|
||||||
<string name="open_track_using_dashboard">Abrir con OpenTracks-Dashboard</string>
|
<string name="open_track_using_dashboard">Abrir con OpenTracks-Dashboard</string>
|
||||||
@@ -596,7 +581,31 @@ g) haz lo que creas que ayude a OpenTracks.</string>
|
|||||||
<string name="settings_recording_fullscreen_on_while_recording_title">Pantalla completa</string>
|
<string name="settings_recording_fullscreen_on_while_recording_title">Pantalla completa</string>
|
||||||
<string name="interval_list_empty_message">No hay intervalos todavía</string>
|
<string name="interval_list_empty_message">No hay intervalos todavía</string>
|
||||||
<string name="voice_speed_lap">Velocidad de la vuelta %1$s</string>
|
<string name="voice_speed_lap">Velocidad de la vuelta %1$s</string>
|
||||||
<string name="hold_to_stop">Mantén pulsado para terminar la grabación</string>
|
<string name="hold_to_stop">Mantener para parar</string>
|
||||||
<string name="toast_message_instant_track_was_exported">Última pista exportada</string>
|
<string name="toast_message_instant_track_was_exported">Última pista exportada</string>
|
||||||
<string name="instant_export_enabled_summary">Exportar pista después de terminar la grabación</string>
|
<string name="instant_export_enabled_summary">Exportar pista después de terminar la grabación</string>
|
||||||
|
<string name="stats_loss">Pérdida</string>
|
||||||
|
<string name="settings_prevent_reimport_tracks_title">Impedir la reimportación de pistas</string>
|
||||||
|
<string name="sensor_state_power_avg">Potencia media</string>
|
||||||
|
<string name="sensor_state_heart_rate_max">Frecuencia cardíaca máxima</string>
|
||||||
|
<string name="sensor_state_heart_rate_avg">Ritmo cardíaco medio</string>
|
||||||
|
<string name="export_error_post_workout">La exportación de post-entrenamiento ha fallado, por favor compruebe el directorio de exportación.</string>
|
||||||
|
<string name="export_progress_summary_new_msg">Nuevas pistas exportadas</string>
|
||||||
|
<string name="import_thread_interrupted">Hilo interrumpido</string>
|
||||||
|
<string name="import_progress_summary_errors_msg">Errores</string>
|
||||||
|
<string name="import_progress_summary_ok_msg">Archivos importados</string>
|
||||||
|
<string name="description_elevation_loss">Pérdida de altura: %1$d m (%2$d pies)</string>
|
||||||
|
<string name="value_float_mile_hour">%1$.2f mph</string>
|
||||||
|
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
|
||||||
|
<string name="value_pace_mile">%1$d:%2$02d min/mi</string>
|
||||||
|
<string name="sensor_state_cadence_max">Cadencia máxima</string>
|
||||||
|
<string name="sensor_state_cadence_avg">Cadencia media</string>
|
||||||
|
<string name="value_float_kilometer_hour">%1$.2f kp/h</string>
|
||||||
|
<string name="export_progress_summary_overwrite_msg">Pistas sobrescritas</string>
|
||||||
|
<string name="export_progress_summary_skip_msg">Pistas omitidas</string>
|
||||||
|
<string name="export_progress_summary_errors_msg">Errores</string>
|
||||||
|
<string name="generic_open_track">Pista abierta</string>
|
||||||
|
<string name="import_progress_summary_exists_msg">Ya existen</string>
|
||||||
|
<string name="import_no_kml_file_found">No se ha encontrado ningún archivo doc.kml en KMZ</string>
|
||||||
|
<string name="import_prevent_reimport">Ha establecido impedir la reimportación de la pista</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?><!--
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
Copyright 2010 Google Inc.
|
Copyright 2010 Google Inc.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -12,8 +13,7 @@ distributed under the License is distributed on an "AS IS" BASIS,
|
|||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
--><resources>
|
||||||
<resources>
|
|
||||||
<string name="about_preference_title">Umbes OpenTracks</string>
|
<string name="about_preference_title">Umbes OpenTracks</string>
|
||||||
<string name="about_description"><i>OpenTracks</i> on spordi jälgimise rakendus, mis austab täielikult teie privaatsust.</string>
|
<string name="about_description"><i>OpenTracks</i> on spordi jälgimise rakendus, mis austab täielikult teie privaatsust.</string>
|
||||||
<string name="about_url">Projekti veebileht: <a href="%1$s">%1$s</a></string>
|
<string name="about_url">Projekti veebileht: <a href="%1$s">%1$s</a></string>
|
||||||
@@ -23,69 +23,45 @@ limitations under the License.
|
|||||||
<string name="about_libraries">Raamatukogud</string>
|
<string name="about_libraries">Raamatukogud</string>
|
||||||
<!-- Help -->
|
<!-- Help -->
|
||||||
<string name="help_feature_title">OpenTracks sellel on järgmised omadused:</string>
|
<string name="help_feature_title">OpenTracks sellel on järgmised omadused:</string>
|
||||||
<string name="help_feature_content">
|
<string name="help_feature_content">* loo GPS rajad
|
||||||
* GPS-radade loomine \ n
|
\n* kasutage südame löögisageduse andurit ( ainult Bluetooth LE)
|
||||||
* kasutage pulsisensorit (ainult Bluetooth LE) \ n
|
\n* häälteated (aja või vahemaa järgi)
|
||||||
* häälteated (aja või vahemaa järgi) \ n
|
\n* loo markerid (sh. digikuvat)
|
||||||
* loo markerid (koos piltidega) \ n
|
\n* töötab täiesti offline
|
||||||
* töötab täiesti võrguühenduseta \ n
|
\n* näita lugusid kaardil (vt allpool)</string>
|
||||||
* näidata radu kaardil (vt allpool)</string>
|
|
||||||
|
|
||||||
<string name="help_track_map_title">Kuidas näidata pala kaardil?</string>
|
<string name="help_track_map_title">Kuidas näidata pala kaardil?</string>
|
||||||
<string name="help_track_map_content">
|
<string name="help_track_map_content"> Kasutage väikest kaardisümbolit.
|
||||||
Kasutage väikest kaardiikooni. \n
|
\n a) (reaalajas uuendused) Installige <a href="https://github.com/OpenTracksApp/OSMDashboard">OSMDashboard</a>. See pakub online või offline-kaarte <a href="https://www.openstreetmap.org">OpenStreetMap</a> kaudu.
|
||||||
a)
|
\n Tegelikult on OSMDashboard eraldi rakendus, mis saab ainult (ajutiselt) juurdepääsu näidatavate rada(de) andmetele.
|
||||||
(reaalajas värskendused) Installige <a href="https://github.com/OpenTracksApp/OSMDashboard">OSMDashboard</a>.
|
\n b) Tavalise kaardirakenduse kaudu (nt <a href="http://osmand.net/">OsmAnd</a> ja <a href="https://maps.me/">MAPS.ME</a>). Need rakendused peavad toetama KMZ-failiformaati (ainult asukohad ja ajatemplid). Tegelikult peab rakendus toetama <i>ACTION_VIEW</i> koos MIME <i>application/vnd.google-earth.kmz</i>-ga. </string>
|
||||||
See pakub võrgu- või võrguühenduseta kaarte <a href="https://www.openstreetmap.org">OpenStreetMap</a> kaudu.\n
|
|
||||||
Tegelikult on OSMDashboard eraldiseisev rakendus, mis pääseb juurde (ajutiselt) ainult kuvatavate rada(de) andmetele.
|
|
||||||
\n
|
|
||||||
b) „Tavalise” kaardirakenduse (nt <a href="http://osmand.net/">OsmAnd</a> ja <a href="https://maps.me/">MAPS.ME</a>.
|
|
||||||
Need rakendused peavad toetama KMZ-failivormingut (ainult asukohad ja ajatemplid).
|
|
||||||
Tegelikult peab rakendus toetama rakendust MIME <i>application/vnd.google-earth.</i> <i>ACTION_VIEW</i>.</string>
|
|
||||||
|
|
||||||
<string name="help_storage_pictures_title">Kuidas OpenTracks salvestab markeritena tehtud pilte?</string>
|
<string name="help_storage_pictures_title">Kuidas OpenTracks salvestab markeritena tehtud pilte?</string>
|
||||||
<string name="help_storage_pictures_content">Neid hoitakse rakenduse sisemises salvestusruumis (st pääseb juurde ainult OpenTracks is).</string>
|
<string name="help_storage_pictures_content">Neid hoitakse rakenduse sisemises salvestusruumis (st pääseb juurde ainult OpenTracks is).</string>
|
||||||
|
|
||||||
<string name="help_track_export_title">Kuidas saab salvestatud lugusid eksportida / jagada?</string>
|
<string name="help_track_export_title">Kuidas saab salvestatud lugusid eksportida / jagada?</string>
|
||||||
<string name="help_track_export_content">
|
<string name="help_track_export_content"> Lugusid saab seadetest eksportida KMZ-, KML- või GPX-vormingus. KMZ / KML kõik andmed; Ainult GPX-i asukohad. Radasid, mis on jagatud <i> jagamise ikooni </i> kaudu, jagatakse KMZ-na. </string>
|
||||||
Lugusid saab seadetest eksportida KMZ-, KML- või GPX-vormingus.
|
|
||||||
KMZ / KML kõik andmed; Ainult GPX-i asukohad.
|
|
||||||
Radasid, mis on jagatud <i> jagamise ikooni </i> kaudu, jagatakse KMZ-na.</string>
|
|
||||||
|
|
||||||
<string name="help_data_google_play_services_title">Kas OpenTracks nõuab / kasutab Google Play teenust?</string>
|
<string name="help_data_google_play_services_title">Kas OpenTracks nõuab / kasutab Google Play teenust?</string>
|
||||||
|
|
||||||
<string name="help_recording_title">Kuidas OpenTracks andmeid registreerib?</string>
|
<string name="help_recording_title">Kuidas OpenTracks andmeid registreerib?</string>
|
||||||
<string name="help_recording_content">
|
<string name="help_recording_content">
|
||||||
OpenTracks kasutab seadme GPS-andurit asukoha pidevaks registreerimiseks.
|
OpenTracks kasutab seadme GPS-andurit asukoha pidevaks registreerimiseks.
|
||||||
Kui GPS-seade teatab ebatäpsetest andmetest (nt asukoht, kiirus, kõrgus), ei saa OpenTracks sellega midagi teha.</string>
|
Kui GPS-seade teatab ebatäpsetest andmetest (nt asukoht, kiirus, kõrgus), ei saa OpenTracks sellega midagi teha.</string>
|
||||||
|
|
||||||
<string name="help_data_storage_title">Kuidas OpenTracks sensori andmeid salvestab?</string>
|
<string name="help_data_storage_title">Kuidas OpenTracks sensori andmeid salvestab?</string>
|
||||||
<string name="help_data_storage_content">
|
<string name="help_data_storage_content"> Anduri andmed salvestatakse salvestatud asukoha kohta. Südame löögisageduse anduri puhul tähendab see, et asukoha kohta salvestatakse ainult <i>üks</i> südame löögisageduse mõõtmine. Kui seisate paigal või siseruumides, siis anduri andmeid ei registreerita (kuid need näidatakse). </string>
|
||||||
Anduri andmed salvestatakse salvestatud asukoha kohta.
|
|
||||||
Südame löögisageduse anduri puhul tähendab see, et asukoha kohta salvestatakse ainult <i>üks</i> südame löögisageduse mõõtmine.
|
|
||||||
Kui seisate paigal või siseruumides, siis anduri andmeid ei registreerita (kuid need näidatakse).</string>
|
|
||||||
|
|
||||||
<string name="help_gps_troubleshooting_title">OpenTracks ei salvesta asukohti?</string>
|
<string name="help_gps_troubleshooting_title">OpenTracks ei salvesta asukohti?</string>
|
||||||
<string name="help_gps_troubleshooting_content">
|
<string name="help_gps_troubleshooting_content"> Mida saate teha:
|
||||||
Mida saate teha: \ n
|
\na) kontrollige, kas GPS on lubatud,
|
||||||
a) kontrollige, kas GPS on lubatud, \ n
|
\nb) parandada GPS vastuvõtt (NT minna õues),
|
||||||
b) parandage GPS-vastuvõttu (nt käige õues), \ n
|
\nc) kontrollige <a href="https://f-droid.org/en/packages/com.android.gpstest.osmdroid /">GPSTest</a> app ja
|
||||||
c) kontrollige, kas rakendusega <a href="https://f-droid.org/en/packages/com.android.gpstest.osmdroid/"> GPSTest </a> ja \ n
|
\nd) keelata energiasäästu.
|
||||||
d) keelake energiasääst. \ n
|
\n
|
||||||
\ n
|
\nKui kõik ei aita, palun teatage veast. </string>
|
||||||
Kui kõik ei aita, teatage veast.</string>
|
|
||||||
|
|
||||||
<string name="help_support_title">Kuidas OpenTracks it toetada?</string>
|
<string name="help_support_title">Kuidas OpenTracks it toetada?</string>
|
||||||
<string name="help_support_content">
|
<string name="help_support_content"> Saate:
|
||||||
Saate: \ n
|
\n a) levitada OpenTracks\'i kohta sõna,
|
||||||
a) levitage sõna OpenTracks kohta, \ n
|
\n b) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">ettepanekuid teha</a>,
|
||||||
b) <a href="https://github.com/OpenTracksApp/OpenTracks/issues"> funktsioonide pakkumine </a>, \ n
|
\n c) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">raportida vigadest</a>,
|
||||||
c) <a href="https://github.com/OpenTracksApp/OpenTracks/issues"> teatage vigadest </a>, \ n
|
\n d) aidata tarkvara arendamisel,
|
||||||
d) abi tarkvara arendamisel, \ n
|
\n e) osta <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore">Google Play Store\'is</a>,
|
||||||
e) ostke sisse <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore"> Google Play pood </a>, \ n
|
\n f) annetada ja
|
||||||
f) annetama ja \ n
|
\n g) teha kõike, mis teie arvates aitab OpenTracks\'ile kaasa. </string>
|
||||||
g) tehke kõike, mis teie arvates OpenTracks aitab.</string>
|
|
||||||
|
|
||||||
<!-- Activity Type -->
|
<!-- Activity Type -->
|
||||||
<string name="activity_type_airplane">lennuk</string>
|
<string name="activity_type_airplane">lennuk</string>
|
||||||
<string name="activity_type_atv">ATV</string>
|
<string name="activity_type_atv">ATV</string>
|
||||||
@@ -147,7 +123,7 @@ g) tehke kõike, mis teie arvates OpenTracks aitab.</string>
|
|||||||
<string name="activity_type_trail_hiking">matkarajal matkamine</string>
|
<string name="activity_type_trail_hiking">matkarajal matkamine</string>
|
||||||
<string name="activity_type_trail_running">maastikujooks</string>
|
<string name="activity_type_trail_running">maastikujooks</string>
|
||||||
<string name="activity_type_train">rong</string>
|
<string name="activity_type_train">rong</string>
|
||||||
<string name="activity_type_ultimate_frisbee">ultimate frisbee</string>
|
<string name="activity_type_ultimate_frisbee">ülim frisbee</string>
|
||||||
<string name="activity_type_unknown">tundmatu</string>
|
<string name="activity_type_unknown">tundmatu</string>
|
||||||
<string name="activity_type_wakeboarding">veelauaga sõitmine</string>
|
<string name="activity_type_wakeboarding">veelauaga sõitmine</string>
|
||||||
<string name="activity_type_walking">kõndimine</string>
|
<string name="activity_type_walking">kõndimine</string>
|
||||||
@@ -239,7 +215,7 @@ g) tehke kõike, mis teie arvates OpenTracks aitab.</string>
|
|||||||
<!-- Image -->
|
<!-- Image -->
|
||||||
<string name="image_application">Rakendus</string>
|
<string name="image_application">Rakendus</string>
|
||||||
<string name="image_arrow">Nool</string>
|
<string name="image_arrow">Nool</string>
|
||||||
<string name="image_marker">Marker</string>
|
<string name="image_marker">Mark</string>
|
||||||
<string name="image_marker_count">Markerite arv</string>
|
<string name="image_marker_count">Markerite arv</string>
|
||||||
<string name="image_my_location">Minu asukoht</string>
|
<string name="image_my_location">Minu asukoht</string>
|
||||||
<string name="image_pause">Peata</string>
|
<string name="image_pause">Peata</string>
|
||||||
@@ -267,7 +243,7 @@ g) tehke kõike, mis teie arvates OpenTracks aitab.</string>
|
|||||||
<string name="marker_delete_multiple_confirm_message">Valitud markerid kustutatakse seadmest jäädavalt</string>
|
<string name="marker_delete_multiple_confirm_message">Valitud markerid kustutatakse seadmest jäädavalt</string>
|
||||||
<string name="marker_label_end">%1$s (Lõpp)</string>
|
<string name="marker_label_end">%1$s (Lõpp)</string>
|
||||||
<string name="marker_label_start">%1$s (Algus)</string>
|
<string name="marker_label_start">%1$s (Algus)</string>
|
||||||
<string name="marker_name_format">Marker %1$d</string>
|
<string name="marker_name_format">Mark %1$d</string>
|
||||||
<string name="marker_split_name_format">Jaotus %1$d</string>
|
<string name="marker_split_name_format">Jaotus %1$d</string>
|
||||||
<string name="marker_title">%1$d/%2$d</string>
|
<string name="marker_title">%1$d/%2$d</string>
|
||||||
<!-- Marker Detail -->
|
<!-- Marker Detail -->
|
||||||
@@ -311,7 +287,7 @@ g) tehke kõike, mis teie arvates OpenTracks aitab.</string>
|
|||||||
<!-- Sensor State -->
|
<!-- Sensor State -->
|
||||||
<string name="sensor_state_battery">Aku tase</string>
|
<string name="sensor_state_battery">Aku tase</string>
|
||||||
<string name="sensor_state_cadence">Rütm</string>
|
<string name="sensor_state_cadence">Rütm</string>
|
||||||
<string name="sensor_state_cadence_value">%1$d rpm</string>
|
<string name="sensor_state_cadence_value">%1$d p/min</string>
|
||||||
<string name="sensor_state_disconnected">Ühendus on katkestatud</string>
|
<string name="sensor_state_disconnected">Ühendus on katkestatud</string>
|
||||||
<string name="sensor_state_heart_rate">Pulsisagedus</string>
|
<string name="sensor_state_heart_rate">Pulsisagedus</string>
|
||||||
<string name="sensor_state_heart_rate_value">%1$d lööki minutis</string>
|
<string name="sensor_state_heart_rate_value">%1$d lööki minutis</string>
|
||||||
@@ -340,7 +316,7 @@ g) tehke kõike, mis teie arvates OpenTracks aitab.</string>
|
|||||||
<string name="settings_recording_auto_resume_track_timeout_title">Automaatne jätkamine</string>
|
<string name="settings_recording_auto_resume_track_timeout_title">Automaatne jätkamine</string>
|
||||||
<string name="settings_recording_default_activity_title">Tegevuse vaiketüüp</string>
|
<string name="settings_recording_default_activity_title">Tegevuse vaiketüüp</string>
|
||||||
<string name="settings_recording_location_frequency_summary">%1$s salvestatud asukohtade vahel</string>
|
<string name="settings_recording_location_frequency_summary">%1$s salvestatud asukohtade vahel</string>
|
||||||
<string name="settings_recording_max_recording_distance_summary">Kui vahemaa kahe asukoha vahel on üle %1$s, luuakse uus lõik.</string>
|
<string name="settings_recording_max_recording_distance_summary">Kui vahemaa kahe asukoha vahel on üle %1$s, luuakse uus lõik</string>
|
||||||
<string name="settings_recording_max_recording_distance_title">Max vahemaa</string>
|
<string name="settings_recording_max_recording_distance_title">Max vahemaa</string>
|
||||||
<string name="settings_recording_min_recording_distance_title">Salvestamiskauguse intervall</string>
|
<string name="settings_recording_min_recording_distance_title">Salvestamiskauguse intervall</string>
|
||||||
<string name="settings_recording_min_recording_interval_title">Salvestamisaja intervall</string>
|
<string name="settings_recording_min_recording_interval_title">Salvestamisaja intervall</string>
|
||||||
@@ -362,17 +338,17 @@ g) tehke kõike, mis teie arvates OpenTracks aitab.</string>
|
|||||||
<string name="settings_sensor_bluetooth_sensor">Bluetoothi andur</string>
|
<string name="settings_sensor_bluetooth_sensor">Bluetoothi andur</string>
|
||||||
<string name="settings_sensor_connecting">Ühendatud anduriga %1$s</string>
|
<string name="settings_sensor_connecting">Ühendatud anduriga %1$s</string>
|
||||||
<string name="settings_sensor_disconnected">Lahti ühendatud %1$s</string>
|
<string name="settings_sensor_disconnected">Lahti ühendatud %1$s</string>
|
||||||
|
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Laiuskraad/pikkuskraad</string>
|
<string name="settings_stats_coordinate">Laiuskraad/pikkuskraad</string>
|
||||||
<string name="settings_stats_rate_title">Eelistatud määr</string>
|
<string name="settings_stats_rate_title">Eelistatud määr</string>
|
||||||
<string name="settings_stats_units_imperial">Inglise mõõtühikud (miili, jalga)</string>
|
<string name="settings_stats_units_imperial">Inglise mõõtühikud (miili, jalga)</string>
|
||||||
<string name="settings_stats_units_metric">Meetermõõdustik (km, m)</string>
|
<string name="settings_stats_units_metric">Meetermõõdustik (km, m)</string>
|
||||||
<string name="settings_stats_units_title">Eelistatud ühikud</string>
|
<string name="settings_stats_units_title">Eelistatud ühikud</string>
|
||||||
|
|
||||||
<!-- Share Track -->
|
<!-- Share Track -->
|
||||||
<string name="share_track_share_file">Jagage rajafaili</string>
|
<string name="share_track_share_file">Jagage rajafaili</string>
|
||||||
<string name="share_track_share_file_body">Teile võib see rada huvi pakkuda.\n\nRaja vaatamiseks kasutage rakendust Google Earth või muud kaardistamistarkvara.\n\n%1$s</string>
|
<string name="share_track_share_file_body">Teile võib see rada huvi pakkuda.
|
||||||
|
\n
|
||||||
|
\n%1$s</string>
|
||||||
<string name="share_track_subject">Ma soovin teiega rada jagada</string>
|
<string name="share_track_subject">Ma soovin teiega rada jagada</string>
|
||||||
<!-- Stats -->
|
<!-- Stats -->
|
||||||
<string name="stats_average_moving_pace">Keskmine liikumistempo</string>
|
<string name="stats_average_moving_pace">Keskmine liikumistempo</string>
|
||||||
@@ -553,12 +529,82 @@ g) tehke kõike, mis teie arvates OpenTracks aitab.</string>
|
|||||||
<string name="waypoint_type_toilet">tualett</string>
|
<string name="waypoint_type_toilet">tualett</string>
|
||||||
<string name="waypoint_type_tourist_information">turismiinfo</string>
|
<string name="waypoint_type_tourist_information">turismiinfo</string>
|
||||||
<string name="waypoint_type_tree">puu</string>
|
<string name="waypoint_type_tree">puu</string>
|
||||||
<string name="waypoint_type_tunnel">tunnel</string>
|
<string name="waypoint_type_tunnel">tunnelit</string>
|
||||||
<string name="waypoint_type_waterfall">juga</string>
|
<string name="waypoint_type_waterfall">juga</string>
|
||||||
<string name="waypoint_type_water_fountain">purskkaev</string>
|
<string name="waypoint_type_water_fountain">purskkaev</string>
|
||||||
<string name="waypoint_type_waypoint">teekonnapunkt</string>
|
<string name="waypoint_type_waypoint">teekonnapunkt</string>
|
||||||
<!-- Share image -->
|
<!-- Share image -->
|
||||||
<string name="share_image_subject">Tahaksin teiega pilti jagada</string>
|
<string name="share_image_subject">Tahaksin teiega pilti jagada</string>
|
||||||
<string name="share_image_body">Ma arvan, et see pilt võiks teid huvitada.</string>
|
<string name="share_image_body">Ma arvan, et see pilt võiks teid huvitada.</string>
|
||||||
|
<string name="open_track_as_trackfileformat">Ava kui %1$s</string>
|
||||||
|
<string name="open_track_using_dashboard">Open kasutades OpenTracks-Dashboard</string>
|
||||||
|
<string name="activity_type_escooter">eskuuter</string>
|
||||||
|
<string name="open_track_as_GPX">Avatud kui GPX</string>
|
||||||
|
<string name="open_track_as_KMZ">Avatud kui KMZ</string>
|
||||||
|
<string name="description_elevation_loss">Kõrguse kadu: %1$d m (%2$d ft)</string>
|
||||||
|
<string name="export_all_do_it_for_all">tehke seda kõigi konfliktide jaoks</string>
|
||||||
|
<string name="export_error_post_workout">Treeningujärgne eksport nurjus, palun kontrolli ekspordikataloogi.</string>
|
||||||
|
<string name="import_thread_interrupted">Teema katkestatud</string>
|
||||||
|
<string name="import_parser_error">Parseri viga: %1$s</string>
|
||||||
|
<string name="import_unable_to_import_file">Faili importimine nurjus: %1$s</string>
|
||||||
|
<plurals name="generic_completed_with_errors">
|
||||||
|
<item quantity="one">Lõpetatud ühe veaga</item>
|
||||||
|
<item quantity="other">Lõpetatud %1$d vigadega</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="gps_fixed_and_ready">GPS fikseeritud ja valmis</string>
|
||||||
|
<string name="import_prevent_reimport">Olete määranud vältida re-import track</string>
|
||||||
|
<string name="generic_overwrite">Ülekirjutamine</string>
|
||||||
|
<string name="export_progress_summary_overwrite_msg">Ülekirjutatud lood</string>
|
||||||
|
<string name="export_track_errors">Palasid ei ekspordita</string>
|
||||||
|
<string name="export_track_already_exists_msg">Rada %1$s on sihtkataloogis juba olemas.</string>
|
||||||
|
<string name="aggregated_stats_empty_message">Salvestage oma esimene pala, et näha koondatud statistikat</string>
|
||||||
|
<string name="toast_message_instant_track_was_exported">Viimane eksporditud pala</string>
|
||||||
|
<string name="voice_pace_lap">Ringiaeg %1$s</string>
|
||||||
|
<string name="settings_prevent_reimport_tracks_title">Palade reimportimise vältimine</string>
|
||||||
|
<string name="settings_night_mode_option_night">Öö</string>
|
||||||
|
<string name="settings_night_mode_option_day">Päev</string>
|
||||||
|
<string name="settings_night_mode_option_system">Süsteem</string>
|
||||||
|
<string name="settings_night_mode_title">UI teema</string>
|
||||||
|
<string name="settings_recording_fullscreen_on_while_recording_summary">Salvestamise ajal esitada täisekraanil.</string>
|
||||||
|
<string name="settings_recording_fullscreen_on_while_recording_title">Täisekraan</string>
|
||||||
|
<string name="settings_default_trackfileformat">Failivormingu eksport/jagamine</string>
|
||||||
|
<string name="sensor_state_power_avg">Avg Võimsus</string>
|
||||||
|
<string name="sensor_state_heart_rate_max">Maksimaalne pulss</string>
|
||||||
|
<string name="sensor_state_heart_rate_avg">Keskmine pulsisagedus</string>
|
||||||
|
<string name="sensor_state_cadence_max">Max kadentsus</string>
|
||||||
|
<string name="sensor_state_cadence_avg">Keskmine kadentsus</string>
|
||||||
|
<string name="settings_sensor_wheel_circumference">Ratta ümbermõõt (mm)</string>
|
||||||
|
<string name="stats_loss">Kahjum</string>
|
||||||
|
<string name="track_detail_intervals_tab">Intervallid</string>
|
||||||
|
<string name="stats_split_interval">Jagatud intervall</string>
|
||||||
|
<string name="stats_intervals">Intervallid</string>
|
||||||
|
<string name="interval_list_empty_message">Ei ole ühtegi intervalli veel</string>
|
||||||
|
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
|
||||||
|
<string name="value_pace_mile">%1$d:%2$02d min/mi</string>
|
||||||
|
<string name="value_float_mile_hour">%1$.2f mph</string>
|
||||||
|
<string name="value_float_kilometer_hour">%1$.2f km/h</string>
|
||||||
|
<string name="voice_speed_lap">Ringi kiirus %1$s</string>
|
||||||
|
<string name="hold_to_stop">Hoidke lõpetada</string>
|
||||||
|
<string name="hold_to_pause">Hoidke pausi</string>
|
||||||
|
<string name="instant_export_enabled_summary">Ekspordi pala salvestusruumi pärast salvestamise lõpetamist</string>
|
||||||
|
<string name="settings_default_export_uri_title">Track ekspordi kataloog</string>
|
||||||
|
<string name="instant_export_enabled_title">Vahetu treeningujärgne eksport</string>
|
||||||
|
<string name="export_progress_summary_errors_msg">Viga</string>
|
||||||
|
<string name="export_progress_summary_skip_msg">Palad vahele</string>
|
||||||
|
<string name="export_progress_summary_new_msg">Uued palad eksporditud</string>
|
||||||
|
<string name="generic_open_track">Avatud rada</string>
|
||||||
|
<string name="generic_completed">Lõpetanud</string>
|
||||||
|
<string name="generic_click_twice_cancel">Tühistamiseks klõpsake uuesti</string>
|
||||||
|
<string name="gps_disabled_msg">GPS keelatud</string>
|
||||||
|
<string name="import_unsupported_format">Toetamata failivorming</string>
|
||||||
|
<string name="import_no_kml_file_found">Ei, doktor.KMZ-is leitud KML fail</string>
|
||||||
|
<string name="import_error_info">%1$s: %2$s</string>
|
||||||
|
<string name="import_error_list_dialog_title">Failid, mida ei impordita</string>
|
||||||
|
<string name="import_file_imported">Fail %1$s imporditud</string>
|
||||||
|
<string name="import_progress_summary_ok_msg">Imporditud failid</string>
|
||||||
|
<string name="import_progress_summary_exists_msg">Juba olemas</string>
|
||||||
|
<string name="generic_show_errors">Vigade Näitamine</string>
|
||||||
|
<string name="generic_separator_done_total">/</string>
|
||||||
|
<string name="generic_skip">Jäta</string>
|
||||||
|
<string name="import_progress_summary_errors_msg">Viga</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?><!--
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
Copyright 2010 Google Inc.
|
Copyright 2010 Google Inc.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -12,14 +13,13 @@ distributed under the License is distributed on an "AS IS" BASIS,
|
|||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
--><resources>
|
||||||
<resources>
|
|
||||||
<string name="about_preference_title">OpenTracks-i buruz</string>
|
<string name="about_preference_title">OpenTracks-i buruz</string>
|
||||||
<string name="about_description"><i> OpenTracks </i> kirol jarraipena egiteko aplikazioa da, zure pribatutasuna erabat errespetatzen duena.</string>
|
<string name="about_description"><i> OpenTracks </i> kirol jarraipena egiteko aplikazioa da, zure pribatutasuna erabat errespetatzen duena.</string>
|
||||||
<string name="about_url">Proiektuaren web orria: <a href="%1$s">%1$s</a></string>
|
<string name="about_url">Proiektuaren web orria: <a href="%1$s">%1$s</a></string>
|
||||||
<string name="about_version_name">Bertsioaren izena: %1$s</string>
|
<string name="about_version_name">Bertsioaren izena: %1$s</string>
|
||||||
<string name="about_version_code">Bertsio kodea: %1$d</string>
|
<string name="about_version_code">Bertsio kodea: %1$d</string>
|
||||||
<string name="about_history">OpenTracks <a href="https://code.google.com/archive/p/mytracks/"> <i> Google \ n MyTracks </i> </a> (horixe utzi zen 2016an).</string>
|
<string name="about_history">OpenTracks <a href="https://code.google.com/archive/p/mytracks/"> <i> Google n MyTracks </i> </a> (horixe utzi zen 2016an).</string>
|
||||||
<string name="about_libraries">Liburutegiak</string>
|
<string name="about_libraries">Liburutegiak</string>
|
||||||
<!-- Help -->
|
<!-- Help -->
|
||||||
<string name="help_feature_title">OpenTracks ek ezaugarri hauek ditu:</string>
|
<string name="help_feature_title">OpenTracks ek ezaugarri hauek ditu:</string>
|
||||||
@@ -30,60 +30,39 @@ limitations under the License.
|
|||||||
* Sortu markatzaileak (irudiak barne)\n
|
* Sortu markatzaileak (irudiak barne)\n
|
||||||
* guztiz lineaz kanpo funtzionatzen du\n
|
* guztiz lineaz kanpo funtzionatzen du\n
|
||||||
* Erakutsi ibilbideak mapa batean (ikusi azpian)</string>
|
* Erakutsi ibilbideak mapa batean (ikusi azpian)</string>
|
||||||
|
|
||||||
<string name="help_track_map_title">Nola erakutsi pista batean mapa batean?</string>
|
<string name="help_track_map_title">Nola erakutsi pista batean mapa batean?</string>
|
||||||
<string name="help_track_map_content">
|
<string name="help_track_map_content"> Erabili maparen ikono txikia.
|
||||||
Erabili maparen ikono txikia.\n
|
\n a) (zuzeneko eguneratzeak) Instalatu <a href="https://github.com/OpenTracksApp/OSMDashboard">OSMDashboard</a>. Lineako edo lineaz kanpoko mapak eskaintzen ditu <a href="https://www.openstreetmap.org">OpenStreetMap</a>.
|
||||||
a) (zuzeneko eguneratzeak) Instalatu <a href="https://github.com/OpenTracksApp/OSMDashboard">OSMDashboard</a>.
|
\n Egia esan, OSMDashboard erakundea da erakutsiko diren pista (k) datuetara sartzeko soilik (aldi baterako) sar daitekeena.
|
||||||
Lineako edo lineaz kanpoko mapak eskaintzen ditu <a href="https://www.openstreetmap.org">OpenStreetMap</a>.\n
|
\n b) Mapa aplikazio normal baten bidez (adibidez, <a href="http://osmand.net/">OsmAnd</a> eta <a href="https://maps.me/">MAPS.ME</a>). Aplikazio horiek KMZ fitxategi formatua onartzen dute (kokapenak eta timestamps soilik). Izan ere, aplikazio batek <i>ACTION_VIEW</i> onartzen du MIME <i>application/vnd.google-earth.kmz</i> rekin. </string>
|
||||||
Egia esan, OSMDashboard erakundea da erakutsiko diren pista (k) datuetara sartzeko soilik (aldi baterako) sar daitekeena.\n
|
|
||||||
b) Mapa aplikazio normal baten bidez (adibidez, <a href="http://osmand.net/">OsmAnd</a> eta <a href="https://maps.me/">MAPS.ME</a>).
|
|
||||||
Aplikazio horiek KMZ fitxategi formatua onartzen dute (kokapenak eta timestamps soilik).
|
|
||||||
Izan ere, aplikazio batek <i>ACTION_VIEW</i> onartzen du MIME <i>application/vnd.google-earth.kmz</i> rekin.</string>
|
|
||||||
|
|
||||||
<string name="help_storage_pictures_title">Nola gordetzen du OpenTracks markatzaile gisa ateratako argazkiak?</string>
|
<string name="help_storage_pictures_title">Nola gordetzen du OpenTracks markatzaile gisa ateratako argazkiak?</string>
|
||||||
<string name="help_storage_pictures_content">Aplikazioaren barne biltegian gordetzen dira (hau da, OpenTracks en soilik eskura daiteke).</string>
|
<string name="help_storage_pictures_content">Aplikazioaren barne biltegian gordetzen dira (hau da, OpenTracks en soilik eskura daiteke).</string>
|
||||||
|
|
||||||
<string name="help_track_export_title">Nola esportatu/berdinak diren ibilbideak grabatutako ibilbideak?</string>
|
<string name="help_track_export_title">Nola esportatu/berdinak diren ibilbideak grabatutako ibilbideak?</string>
|
||||||
<string name="help_track_export_content">
|
<string name="help_track_export_content"> Pistak Ezarpenetatik KMZ, KML edo GPX gisa esportatu daitezke. KMZ / KML datu guztiak; GPX kokapenak soilik. <i> Partekatutako ikonoa </i> bidez partekatutako ibilbideak KMZ gisa partekatzen dira. </string>
|
||||||
Pistak Ezarpenetatik KMZ, KML edo GPX gisa esportatu daitezke.
|
|
||||||
KMZ / KML datu guztiak; GPX kokapenak soilik.
|
|
||||||
<i> Partekatutako ikonoa </i> bidez partekatutako ibilbideak KMZ gisa partekatzen dira.</string>
|
|
||||||
|
|
||||||
<string name="help_data_google_play_services_title">OpenTracks-ek Google Play zerbitzua erabiltzea eskatzen al du?</string>
|
<string name="help_data_google_play_services_title">OpenTracks-ek Google Play zerbitzua erabiltzea eskatzen al du?</string>
|
||||||
|
|
||||||
<string name="help_recording_title">Nola grabatzen ditu OpenTracks datuak?</string>
|
<string name="help_recording_title">Nola grabatzen ditu OpenTracks datuak?</string>
|
||||||
<string name="help_recording_content">
|
<string name="help_recording_content">
|
||||||
OpenTracks gailuaren GPS sentsorea erabiltzen du kokapena etengabe grabatzeko.
|
OpenTracks gailuaren GPS sentsorea erabiltzen du kokapena etengabe grabatzeko.
|
||||||
GPS gailuak datu okerrak salatzen baditu (adibidez, kokapena, abiadura, kota), OpenTracks-ek ezin du ezer egin.</string>
|
GPS gailuak datu okerrak salatzen baditu (adibidez, kokapena, abiadura, kota), OpenTracks-ek ezin du ezer egin.</string>
|
||||||
|
|
||||||
<string name="help_data_storage_title">Nola gordetzen du OpenTracks ek sentsoreen datuak?</string>
|
<string name="help_data_storage_title">Nola gordetzen du OpenTracks ek sentsoreen datuak?</string>
|
||||||
<string name="help_data_storage_content">
|
<string name="help_data_storage_content"> Sentsoreen datuak grabatutako kokapen bakoitzeko gordetzen dira. Bihotz-maiztasuneko sentsoreari dagokionez, horrek esan nahi du <i> bat </i> bihotz-tasaren neurketa kokapen bakoitzean gordetzen dela. Geldirik egon edo barrualdean bazaude, ez da sentsoreen daturik grabatuko (baina erakutsiko da). </string>
|
||||||
Sentsoreen datuak grabatutako kokapen bakoitzeko gordetzen dira.
|
|
||||||
Bihotz-maiztasuneko sentsoreari dagokionez, horrek esan nahi du <i> bat </i> bihotz-tasaren neurketa kokapen bakoitzean gordetzen dela.
|
|
||||||
Geldirik egon edo barrualdean bazaude, ez da sentsoreen daturik grabatuko (baina erakutsiko da).</string>
|
|
||||||
|
|
||||||
<string name="help_gps_troubleshooting_title">OpenTracks ez dira kokapenak grabatzen?</string>
|
<string name="help_gps_troubleshooting_title">OpenTracks ez dira kokapenak grabatzen?</string>
|
||||||
<string name="help_gps_troubleshooting_content">
|
<string name="help_gps_troubleshooting_content"> Zer egin dezakezu:
|
||||||
Zer egin dezakezu: \n
|
\n a) egiaztatu GPSa gaituta dagoen ala ez,
|
||||||
a) egiaztatu GPSa gaituta dagoen ala ez, \n
|
\n b) GPS harrera hobetu (adibidez, kanpora joan),
|
||||||
b) GPS harrera hobetu (adibidez, kanpora joan), \n
|
\n c) egiaztatu <a href="https://f-droid.org/en/packages/com.android.gpstest.osmdroid/"> GPSTest </a> aplikazioarekin eta
|
||||||
c) egiaztatu <a href="https://f-droid.org/en/packages/com.android.gpstest.osmdroid/"> GPSTest </a> aplikazioarekin eta \n
|
\n d) desgaitu energia aurreztea.
|
||||||
d) desgaitu energia aurreztea. \n
|
|
||||||
\n
|
\n
|
||||||
Dena laguntzen ez baduzu, jakinarazi akats bat.</string>
|
\n Dena laguntzen ez baduzu, jakinarazi akats bat. </string>
|
||||||
|
|
||||||
<string name="help_support_title">Nola onartzen dut OpenTracks?</string>
|
<string name="help_support_title">Nola onartzen dut OpenTracks?</string>
|
||||||
<string name="help_support_content">
|
<string name="help_support_content"> Ahal izango duzu:
|
||||||
Aukera hau: \ n
|
\n a) buruz hitz zabaltzeko OpenTracks,
|
||||||
a) zabaldu OpenTracks-i buruzko hitza, \ n
|
\n b) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">proposatzen ezaugarriak</a>,
|
||||||
b) <a href="https://github.com/OpenTracksApp/OpenTracks/issues"> proposatu ezaugarriak </a>, \ n
|
\n c) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">txostena bugs</a>,
|
||||||
c) <a href="https://github.com/OpenTracksApp/OpenTracks/issues"> txostenen akatsak </a>, \ n
|
\n d) laguntza software garapena,
|
||||||
d) softwarearen garapenean laguntzeko, \ n
|
\n e) erosi <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore">Google Play Denda</a>,
|
||||||
e) erosi <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore"> Google Play Store </a>, \ n
|
\n f) eman, eta
|
||||||
f) eman, eta \ n
|
\n g) ez edozein dela uste duzu laguntzen OpenTracks. </string>
|
||||||
g) Egin uste duzu OpenTracks-ek laguntzen duela.</string>
|
|
||||||
|
|
||||||
<!-- Activity Type -->
|
<!-- Activity Type -->
|
||||||
<string name="activity_type_airplane">hegazkina</string>
|
<string name="activity_type_airplane">hegazkina</string>
|
||||||
<string name="activity_type_atv">Lurreko ibilgailu guztiak</string>
|
<string name="activity_type_atv">Lurreko ibilgailu guztiak</string>
|
||||||
@@ -257,7 +236,7 @@ g) Egin uste duzu OpenTracks-ek laguntzen duela.</string>
|
|||||||
<!-- Marker -->
|
<!-- Marker -->
|
||||||
<string name="marker_add_error">Ezin da markatzailea txertatu. Ez dago GPS seinalerik. Saiatu berriro.</string>
|
<string name="marker_add_error">Ezin da markatzailea txertatu. Ez dago GPS seinalerik. Saiatu berriro.</string>
|
||||||
<string name="marker_add_success">Markatzailea txertatu da</string>
|
<string name="marker_add_success">Markatzailea txertatu da</string>
|
||||||
<string name="marker_add_canceled">Bertan behera utzi da; ez da markatzailea gehitu.</string>
|
<string name="marker_add_canceled">Bertan behera utzi da; ez da markatzailea gehitu</string>
|
||||||
<string name="marker_add_photo_canceled">Ezeztatu, ez da argazki-markarik gehitu</string>
|
<string name="marker_add_photo_canceled">Ezeztatu, ez da argazki-markarik gehitu</string>
|
||||||
<string name="marker_delete_all_confirm_message">Ibilbideko markatzaile guztiak behin betiko ezabatuko dira gailutik</string>
|
<string name="marker_delete_all_confirm_message">Ibilbideko markatzaile guztiak behin betiko ezabatuko dira gailutik</string>
|
||||||
<string name="marker_delete_one_confirm_message">Markatzailea behin betiko ezabatuko da gailutik</string>
|
<string name="marker_delete_one_confirm_message">Markatzailea behin betiko ezabatuko da gailutik</string>
|
||||||
@@ -309,16 +288,16 @@ g) Egin uste duzu OpenTracks-ek laguntzen duela.</string>
|
|||||||
<!-- Sensor State -->
|
<!-- Sensor State -->
|
||||||
<string name="sensor_state_battery">Bateria maila</string>
|
<string name="sensor_state_battery">Bateria maila</string>
|
||||||
<string name="sensor_state_cadence">Erritmoa</string>
|
<string name="sensor_state_cadence">Erritmoa</string>
|
||||||
<string name="sensor_state_cadence_value">%1$d rpm</string>
|
<string name="sensor_state_cadence_value">%1$d mbi</string>
|
||||||
<string name="sensor_state_disconnected">Deskonektatuta</string>
|
<string name="sensor_state_disconnected">Deskonektatuta</string>
|
||||||
<string name="sensor_state_heart_rate">Maiztasun kardiakoa</string>
|
<string name="sensor_state_heart_rate">Maiztasun kardiakoa</string>
|
||||||
<string name="sensor_state_heart_rate_value">%1$d bpm</string>
|
<string name="sensor_state_heart_rate_value">%1$d mbb</string>
|
||||||
<string name="sensor_state_power">Potentzia</string>
|
<string name="sensor_state_power">Potentzia</string>
|
||||||
<string name="sensor_state_power_value">%1$d W</string>
|
<string name="sensor_state_power_value">%1$d W</string>
|
||||||
<string name="sensor_not_known">Sensor %1$s ezezaguna da. Egiaztatu ezarpenak.</string>
|
<string name="sensor_not_known">Sensor %1$s ezezaguna da. Egiaztatu ezarpenak.</string>
|
||||||
<string name="sensor_could_not_scan">Ezin izan da Bluetooth gailuak bilatu (%1$i errorea).</string>
|
<string name="sensor_could_not_scan">Ezin izan da Bluetooth gailuak bilatu (%1$i errorea).</string>
|
||||||
<string name="bluetooth_disabled">Mesedez, aktibatu Bluetooth.</string>
|
<string name="bluetooth_disabled">Mesedez, aktibatu Bluetooth.</string>
|
||||||
<string name="settings_not_while_recording">Ez dago erabilgarri ibilbidea grabatzen ari den bitartean.</string>
|
<string name="settings_not_while_recording">Ez dago erabilgarri ibilbidea grabatzen ari den bitartean</string>
|
||||||
<string name="settings_show">Erakutsi</string>
|
<string name="settings_show">Erakutsi</string>
|
||||||
<!-- Settings Advanced -->
|
<!-- Settings Advanced -->
|
||||||
<string name="settings_advanced">Aurreratua</string>
|
<string name="settings_advanced">Aurreratua</string>
|
||||||
@@ -360,17 +339,17 @@ g) Egin uste duzu OpenTracks-ek laguntzen duela.</string>
|
|||||||
<string name="settings_sensor_bluetooth_sensor">Bluetooth sentsorea</string>
|
<string name="settings_sensor_bluetooth_sensor">Bluetooth sentsorea</string>
|
||||||
<string name="settings_sensor_connecting">Honekin konektatuta: %1$s</string>
|
<string name="settings_sensor_connecting">Honekin konektatuta: %1$s</string>
|
||||||
<string name="settings_sensor_disconnected">Deskonektatuta %1$s</string>
|
<string name="settings_sensor_disconnected">Deskonektatuta %1$s</string>
|
||||||
|
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Latitudea/Longitudea</string>
|
<string name="settings_stats_coordinate">Latitudea/Longitudea</string>
|
||||||
<string name="settings_stats_rate_title">Erritmo hobetsia</string>
|
<string name="settings_stats_rate_title">Erritmo hobetsia</string>
|
||||||
<string name="settings_stats_units_imperial">Inperiala (mi, ft)</string>
|
<string name="settings_stats_units_imperial">Inperiala (mi, ft)</string>
|
||||||
<string name="settings_stats_units_metric">Metrikoa (km, m)</string>
|
<string name="settings_stats_units_metric">Metrikoa (km, m)</string>
|
||||||
<string name="settings_stats_units_title">Unitate hobetsiak</string>
|
<string name="settings_stats_units_title">Unitate hobetsiak</string>
|
||||||
|
|
||||||
<!-- Share Track -->
|
<!-- Share Track -->
|
||||||
<string name="share_track_share_file">Partekatu ibilbide-fitxategia</string>
|
<string name="share_track_share_file">Partekatu ibilbide-fitxategia</string>
|
||||||
<string name="share_track_share_file_body">Ibilbidea interesgarria gerta dakizukeela uste dut.\n\nIbilbidea ikusteko, erabili Google Earth edo beste kartografia-softwareren bat.\n\n%1$s</string>
|
<string name="share_track_share_file_body">Ibilbidea interesgarria gerta dakizukeela uste dut.
|
||||||
|
\n
|
||||||
|
\n%1$s</string>
|
||||||
<string name="share_track_subject">Bide bat partekatu nahi nuke zurekin</string>
|
<string name="share_track_subject">Bide bat partekatu nahi nuke zurekin</string>
|
||||||
<!-- Stats -->
|
<!-- Stats -->
|
||||||
<string name="stats_average_moving_pace">Batez besteko pausoa, mugitzerakoan</string>
|
<string name="stats_average_moving_pace">Batez besteko pausoa, mugitzerakoan</string>
|
||||||
@@ -489,7 +468,7 @@ g) Egin uste duzu OpenTracks-ek laguntzen duela.</string>
|
|||||||
<string name="voice_speed_miles_per_hour_other">%1$.1f milia orduko</string>
|
<string name="voice_speed_miles_per_hour_other">%1$.1f milia orduko</string>
|
||||||
<string name="voice_speed_miles_per_hour_two">2 milia orduko</string>
|
<string name="voice_speed_miles_per_hour_two">2 milia orduko</string>
|
||||||
<string name="voice_speed_miles_per_hour_zero">0 milia orduko</string>
|
<string name="voice_speed_miles_per_hour_zero">0 milia orduko</string>
|
||||||
<string name="voice_template">OpenTracks. Distantzia: %1$s. Denbora: %2$s. Abiadura: %3$s.</string>
|
<string name="voice_template">OpenTracks. Distantzia: %1$s. Denbora: %2$s. Abiadura: %3$s</string>
|
||||||
<string name="voice_total_distance_kilometers_few">distantzia, guztira: %1$.2f kilometro</string>
|
<string name="voice_total_distance_kilometers_few">distantzia, guztira: %1$.2f kilometro</string>
|
||||||
<string name="voice_total_distance_kilometers_many">distantzia, guztira: %1$.2f kilometro</string>
|
<string name="voice_total_distance_kilometers_many">distantzia, guztira: %1$.2f kilometro</string>
|
||||||
<string name="voice_total_distance_kilometers_one">distantzia, guztira: 1 kilometro</string>
|
<string name="voice_total_distance_kilometers_one">distantzia, guztira: 1 kilometro</string>
|
||||||
@@ -558,5 +537,78 @@ g) Egin uste duzu OpenTracks-ek laguntzen duela.</string>
|
|||||||
<!-- Share image -->
|
<!-- Share image -->
|
||||||
<string name="share_image_subject">Irudi bat zurekin partekatu nahi nuke</string>
|
<string name="share_image_subject">Irudi bat zurekin partekatu nahi nuke</string>
|
||||||
<string name="share_image_body">Irudi hau interesatuko zaizuela uste dut.</string>
|
<string name="share_image_body">Irudi hau interesatuko zaizuela uste dut.</string>
|
||||||
|
<string name="open_track_as_KMZ">Ireki gisa KMZ</string>
|
||||||
|
<string name="open_track_using_dashboard">Ireki erabiliz OpenTracks-Arbel</string>
|
||||||
|
<string name="open_track_as_trackfileformat">Ireki gisa %1$s</string>
|
||||||
|
<string name="activity_type_escooter">eskooterra</string>
|
||||||
|
<string name="settings_recording_fullscreen_on_while_recording_summary">Grabatzen ari zaren bitartean, pantaila osoan ikusi.</string>
|
||||||
|
<string name="settings_recording_fullscreen_on_while_recording_title">Pantaila osoa</string>
|
||||||
|
<string name="value_float_mile_hour">%1$.2f mph</string>
|
||||||
|
<string name="value_float_kilometer_hour">%1$.2f km/h</string>
|
||||||
|
<string name="value_pace_mile">%1$d:%2$02d min/mi</string>
|
||||||
|
<string name="settings_default_export_uri_title">Track esportazio-direktorioa</string>
|
||||||
|
<string name="instant_export_enabled_title">Berehalako post-entrenamendu esportatu</string>
|
||||||
|
<string name="instant_export_enabled_summary">Esportazio-pista biltegiratze ondoren grabaketa amaitu da</string>
|
||||||
|
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
|
||||||
|
<string name="interval_list_empty_message">Ez dira edozein tarte oraindik</string>
|
||||||
|
<string name="aggregated_stats_empty_message">Grabatu zure lehen pista ikusteko batzen estatistikak</string>
|
||||||
|
<string name="open_track_as_GPX">Ireki gisa GPX</string>
|
||||||
|
<string name="description_elevation_loss">Kota galera: %1$d m (%2$d ft)</string>
|
||||||
|
<string name="export_error_post_workout">Post-entrenamendu esportazio huts egin du, mesedez, egiaztatu esportazio direktorioa.</string>
|
||||||
|
<string name="export_progress_summary_new_msg">Pista berriak esportatutako</string>
|
||||||
|
<string name="export_progress_summary_overwrite_msg">Ibilbideak gainidatzi</string>
|
||||||
|
<string name="generic_overwrite">Gainidatzi</string>
|
||||||
|
<string name="generic_separator_done_total">/</string>
|
||||||
|
<string name="settings_sensor_wheel_circumference">Gurpila zirkunferentzia (mm)</string>
|
||||||
|
<string name="sensor_state_heart_rate_max">Max Bihotzean tasa</string>
|
||||||
|
<string name="import_thread_interrupted">Haria eten</string>
|
||||||
|
<string name="import_unsupported_format">Onartzen ez den fitxategi-formatua</string>
|
||||||
|
<string name="import_progress_summary_ok_msg">Fitxategiak inportatu</string>
|
||||||
|
<string name="export_track_already_exists_msg">Pista %1$s dagoeneko existitzen helmugara direktorioa.</string>
|
||||||
|
<string name="export_all_do_it_for_all">ez da gatazka guztiak</string>
|
||||||
|
<string name="export_track_errors">Ibilbideak ez esportatutako</string>
|
||||||
|
<string name="settings_prevent_reimport_tracks_title">Saihesteko re-inportazio ibilbideak</string>
|
||||||
|
<plurals name="generic_completed_with_errors">
|
||||||
|
<item quantity="one">Osatu bat errorea</item>
|
||||||
|
<item quantity="other">Bukatu %1$d akatsak</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="sensor_state_heart_rate_avg">Avg Bihotzean tasa</string>
|
||||||
|
<string name="sensor_state_cadence_max">Max Kadentzia</string>
|
||||||
|
<string name="sensor_state_cadence_avg">Avg Kadentzia</string>
|
||||||
|
<string name="settings_default_trackfileformat">Export/partekatzea fitxategi-formatua</string>
|
||||||
|
<string name="settings_night_mode_title">UI Gaia</string>
|
||||||
|
<string name="settings_night_mode_option_system">Sistema</string>
|
||||||
|
<string name="settings_night_mode_option_day">Egun</string>
|
||||||
|
<string name="settings_night_mode_option_night">Gauean</string>
|
||||||
|
<string name="sensor_state_power_avg">Avg Boterea</string>
|
||||||
|
<string name="track_detail_intervals_tab">Tarteak</string>
|
||||||
|
<string name="stats_split_interval">Zatitu tarte</string>
|
||||||
|
<string name="stats_loss">Galera</string>
|
||||||
|
<string name="stats_intervals">Tarteak</string>
|
||||||
|
<string name="voice_pace_lap">Itzulian-denbora %1$s</string>
|
||||||
|
<string name="voice_speed_lap">Itzulian abiadura %1$s</string>
|
||||||
|
<string name="toast_message_instant_track_was_exported">Azken pista esportatutako</string>
|
||||||
|
<string name="hold_to_pause">Eutsi eteteko</string>
|
||||||
|
<string name="hold_to_stop">Eutsi gelditzeko</string>
|
||||||
|
<string name="export_progress_summary_skip_msg">Ibilbideak saltatu</string>
|
||||||
|
<string name="export_progress_summary_errors_msg">Akatsak</string>
|
||||||
|
<string name="generic_open_track">Ireki Track</string>
|
||||||
|
<string name="generic_skip">Saltatzeko</string>
|
||||||
|
<string name="generic_show_errors">Erakutsi Akatsak</string>
|
||||||
|
<string name="generic_completed">Bukatu</string>
|
||||||
|
<string name="generic_click_twice_cancel">Egin klik berriro bertan behera uzteko</string>
|
||||||
|
<string name="gps_disabled_msg">GPS egokitua</string>
|
||||||
|
<string name="import_progress_summary_errors_msg">Akatsak</string>
|
||||||
|
<string name="import_parser_error">Analizatzailea errorea: %1$s</string>
|
||||||
|
<string name="import_unable_to_import_file">Ezin izan da inportazio fitxategia: %1$s</string>
|
||||||
|
<string name="import_no_kml_file_found">Ez doc.kml fitxategia aurkitu KMZ</string>
|
||||||
|
<string name="import_error_info">%1$s: %2$s</string>
|
||||||
|
<string name="import_progress_summary_exists_msg">Dagoeneko existitzen da</string>
|
||||||
|
<string name="import_prevent_reimport">Ezarri duzu saihesteko re-import track</string>
|
||||||
|
<string name="import_file_imported">File %1$s inportatutako</string>
|
||||||
|
<string name="import_error_list_dialog_title">Fitxategiak ez inportatutako</string>
|
||||||
|
<string name="gps_fixed_and_ready">GPS konpondu eta prest</string>
|
||||||
|
<string name="track_distance_notification">Distantzia: %1$s</string>
|
||||||
|
<string name="track_speed_notification">Abiadura: %1$s</string>
|
||||||
|
<string name="track_pace_notification">Erritmoa: %1$s</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -38,20 +38,14 @@ limitations under the License.
|
|||||||
<string name="help_storage_pictures_title">Miten OpenTracks tallentaa merkkeihin liittyen otetut kuvat?</string>
|
<string name="help_storage_pictures_title">Miten OpenTracks tallentaa merkkeihin liittyen otetut kuvat?</string>
|
||||||
<string name="help_storage_pictures_content">Ne säilytetään sovelluksen sisäisessä tallennustilassa (eli ne näkyvät vain OpenTracksin sisällä).</string>
|
<string name="help_storage_pictures_content">Ne säilytetään sovelluksen sisäisessä tallennustilassa (eli ne näkyvät vain OpenTracksin sisällä).</string>
|
||||||
<string name="help_track_export_title">Miten vien tai jaan tallennettuja reittejä?</string>
|
<string name="help_track_export_title">Miten vien tai jaan tallennettuja reittejä?</string>
|
||||||
<string name="help_track_export_content">
|
<string name="help_track_export_content"> Jäljet voi viedä asetuksista KMZ, KML tai GPX -muodossa. KMZ/KML sisältävät kaiken; GPX vain sijainnit. <i>Jakokuvakkeella</i> jaetut jäljet jaetaan KMZ-muodossa. </string>
|
||||||
Jäljet voi viedä asetuksista KMZ, KML tai GPX -muodossa.
|
|
||||||
KMZ/KML sisältävät kaiken; GPX vain sijainnit.
|
|
||||||
<i>Jakokuvakkeella</i> jaetut jäljet jaetaan KMZ-muodossa.</string>
|
|
||||||
<string name="help_data_google_play_services_title">Käyttääkö tai vaatiiko OpenTracks Google Play -palveluita?</string>
|
<string name="help_data_google_play_services_title">Käyttääkö tai vaatiiko OpenTracks Google Play -palveluita?</string>
|
||||||
<string name="help_recording_title">Miten OpenTracks tallentaa tietoja?</string>
|
<string name="help_recording_title">Miten OpenTracks tallentaa tietoja?</string>
|
||||||
<string name="help_recording_content">
|
<string name="help_recording_content">
|
||||||
OpenTracks käyttää laitteen GPS:ää paikkatietojen jatkuvaan tallentamiseen.
|
OpenTracks käyttää laitteen GPS:ää paikkatietojen jatkuvaan tallentamiseen.
|
||||||
Jos GPS raportoi epätarkkoja tietoja (sijainti, nopeus, korkeus) OpenTracks ei voi tehdä sille mitään.</string>
|
Jos GPS raportoi epätarkkoja tietoja (sijainti, nopeus, korkeus) OpenTracks ei voi tehdä sille mitään.</string>
|
||||||
<string name="help_data_storage_title">Miten OpenTracks tallentaa anturidatan?</string>
|
<string name="help_data_storage_title">Miten OpenTracks tallentaa anturidatan?</string>
|
||||||
<string name="help_data_storage_content">
|
<string name="help_data_storage_content"> Anturidata tallennetaan jokaiselle paikkapisteelle. Esimerkiksi sykemittarista tallennetaan vain <i>yksi</i> sykemittaus tallennettua paikkaa kohden. Jos olet paikallaan tai sisätiloissa, mitään anturidataa ei tallenneta (mutta se näytetään). </string>
|
||||||
Anturidata tallennetaan jokaiselle paikkapisteelle.
|
|
||||||
Esimerkiksi sykemittarista tallennetaan vain <i>yksi</i> sykemittaus tallennettua paikkaa kohden.
|
|
||||||
Jos olet paikallaan tai sisätiloissa, mitään anturidataa ei tallenneta (mutta se näytetään).</string>
|
|
||||||
<string name="help_gps_troubleshooting_title">Miksi OpenTracks ei tallenna sijaintia?</string>
|
<string name="help_gps_troubleshooting_title">Miksi OpenTracks ei tallenna sijaintia?</string>
|
||||||
<string name="help_gps_troubleshooting_content"> Mitä voit tehdä:
|
<string name="help_gps_troubleshooting_content"> Mitä voit tehdä:
|
||||||
\na) tarkista, onko GPS käytössä,
|
\na) tarkista, onko GPS käytössä,
|
||||||
@@ -61,15 +55,13 @@ limitations under the License.
|
|||||||
\n
|
\n
|
||||||
\nJos kaikki ei auta, ilmoita virheestä. </string>
|
\nJos kaikki ei auta, ilmoita virheestä. </string>
|
||||||
<string name="help_support_title">Miten voin tukea OpenTracksin kehitystä?</string>
|
<string name="help_support_title">Miten voin tukea OpenTracksin kehitystä?</string>
|
||||||
<string name="help_support_content">
|
<string name="help_support_content"> Voit:
|
||||||
Voit:\n
|
\n a) levittää sanaa OpenTracksista,
|
||||||
a) levittää sanaa OpenTracksista,\n
|
\n b) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">ehdottaa ominaisuuksia</a>,
|
||||||
b) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">ehdottaa ominaisuuksia</a>,\n
|
\n c) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">ilmoittaa ohjelmistovirheistä</a>,
|
||||||
c) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">ilmoittaa ohjelmistovirheistä</a>,\n
|
\n d) auttaa ohjelmiston kehittämisessä,
|
||||||
d) auttaa ohjelmiston kehittämisessä,\n
|
\n e) ostaa sovelluksen <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore">Google Play -kaupasta</a>,
|
||||||
e) ostaa sovelluksen <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore">Google Play -kaupasta</a>,\n
|
\n f) lahjoittaa ja g) tehdä mikä mielestäsi edistäisi OpenTracksia. </string>
|
||||||
f) lahjoittaa ja
|
|
||||||
g) tehdä mikä mielestäsi edistäisi OpenTracksia.</string>
|
|
||||||
<string name="open_track_using_dashboard">Avaa OpenTracks-Dashboardilla</string>
|
<string name="open_track_using_dashboard">Avaa OpenTracks-Dashboardilla</string>
|
||||||
<string name="open_track_as_KMZ">Avaa KMZ-muodossa</string>
|
<string name="open_track_as_KMZ">Avaa KMZ-muodossa</string>
|
||||||
<string name="open_track_as_GPX">Avaa GPX-muodossa</string>
|
<string name="open_track_as_GPX">Avaa GPX-muodossa</string>
|
||||||
@@ -90,7 +82,7 @@ limitations under the License.
|
|||||||
<string name="activity_type_driving_bus">bussilla ajo</string>
|
<string name="activity_type_driving_bus">bussilla ajo</string>
|
||||||
<string name="activity_type_driving_car">autolla ajo</string>
|
<string name="activity_type_driving_car">autolla ajo</string>
|
||||||
<string name="activity_type_ferry">lautta</string>
|
<string name="activity_type_ferry">lautta</string>
|
||||||
<string name="activity_type_frisbee">frisbee</string>
|
<string name="activity_type_frisbee">liitokiekko</string>
|
||||||
<string name="activity_type_gliding">liitely</string>
|
<string name="activity_type_gliding">liitely</string>
|
||||||
<string name="activity_type_hang_gliding">riippuliito</string>
|
<string name="activity_type_hang_gliding">riippuliito</string>
|
||||||
<string name="activity_type_helicopter">helikopteri</string>
|
<string name="activity_type_helicopter">helikopteri</string>
|
||||||
@@ -568,7 +560,7 @@ jotta ne voidaan tuoda kohteeseen %1$s.</string>
|
|||||||
<string name="instant_export_enabled_summary">Vie raita varastoon tallennuksen jälkeen on valmis</string>
|
<string name="instant_export_enabled_summary">Vie raita varastoon tallennuksen jälkeen on valmis</string>
|
||||||
<string name="voice_speed_lap">Kierrosnopeus %1$s</string>
|
<string name="voice_speed_lap">Kierrosnopeus %1$s</string>
|
||||||
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
|
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
|
||||||
<string name="settings_sensor_wheel_circumference">Pyörän koko (mm)</string>
|
<string name="settings_sensor_wheel_circumference">Pyörän ympärysmitta (mm)</string>
|
||||||
<string name="stats_intervals">Välein</string>
|
<string name="stats_intervals">Välein</string>
|
||||||
<string name="import_thread_interrupted">Lanka keskeytetty</string>
|
<string name="import_thread_interrupted">Lanka keskeytetty</string>
|
||||||
<string name="import_unsupported_format">Tukematon tiedostomuoto</string>
|
<string name="import_unsupported_format">Tukematon tiedostomuoto</string>
|
||||||
@@ -582,4 +574,41 @@ jotta ne voidaan tuoda kohteeseen %1$s.</string>
|
|||||||
<string name="import_progress_summary_ok_msg">Tuodut tiedostot</string>
|
<string name="import_progress_summary_ok_msg">Tuodut tiedostot</string>
|
||||||
<string name="import_progress_summary_exists_msg">Jo olemassa</string>
|
<string name="import_progress_summary_exists_msg">Jo olemassa</string>
|
||||||
<string name="import_progress_summary_errors_msg">Virhe</string>
|
<string name="import_progress_summary_errors_msg">Virhe</string>
|
||||||
|
<string name="generic_click_twice_cancel">Peruuta uudelleen napsauttamalla</string>
|
||||||
|
<string name="settings_recording_fullscreen_on_while_recording_title">Kokoruutu</string>
|
||||||
|
<string name="interval_list_empty_message">Ei ole mitään intervallia vielä</string>
|
||||||
|
<string name="export_error_post_workout">Treenin jälkeinen vienti epäonnistui, tarkista vientihakemisto.</string>
|
||||||
|
<string name="export_progress_summary_overwrite_msg">Kappaleet ylikirjoitettu</string>
|
||||||
|
<plurals name="generic_completed_with_errors">
|
||||||
|
<item quantity="one">Täydennetty yhdellä virheellä</item>
|
||||||
|
<item quantity="other">Täydennetty %1$d virheillä</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="export_track_already_exists_msg">Kappale %1$s on jo olemassa kohdehakemistossa.</string>
|
||||||
|
<string name="export_all_do_it_for_all">tee se kaikkien konfliktien vuoksi</string>
|
||||||
|
<string name="export_track_errors">Kappaleita ei viety</string>
|
||||||
|
<string name="settings_recording_fullscreen_on_while_recording_summary">Tallennuksen aikana, läsnä koko näytön.</string>
|
||||||
|
<string name="settings_night_mode_title">UI-teema</string>
|
||||||
|
<string name="settings_night_mode_option_system">Järjestelmä</string>
|
||||||
|
<string name="settings_night_mode_option_day">Päivä</string>
|
||||||
|
<string name="settings_night_mode_option_night">Yö</string>
|
||||||
|
<string name="export_progress_summary_new_msg">Uusia kappaleita viety</string>
|
||||||
|
<string name="export_progress_summary_skip_msg">Kappaleet ohitettu</string>
|
||||||
|
<string name="export_progress_summary_errors_msg">Virhe</string>
|
||||||
|
<string name="generic_overwrite">Korvata</string>
|
||||||
|
<string name="generic_skip">Ohittaa</string>
|
||||||
|
<string name="generic_separator_done_total">/</string>
|
||||||
|
<string name="generic_show_errors">Näytä Virheet</string>
|
||||||
|
<string name="gps_disabled_msg">GPS pois käytöstä</string>
|
||||||
|
<string name="generic_completed">Täydellinen</string>
|
||||||
|
<string name="sensor_state_power_avg">Avg Teho</string>
|
||||||
|
<string name="description_elevation_loss">Korkeussijaintitappio: %1$d m (%2$d ft)</string>
|
||||||
|
<string name="sensor_state_heart_rate_max">Maksimisyke</string>
|
||||||
|
<string name="sensor_state_heart_rate_avg">Avg syke</string>
|
||||||
|
<string name="value_float_kilometer_hour">%1$.2f k/t</string>
|
||||||
|
<string name="value_pace_mile">%1$d:%2$02d min/mailia</string>
|
||||||
|
<string name="activity_type_escooter">eskootteri</string>
|
||||||
|
<string name="sensor_state_cadence_avg">Keskim.Poljinnopeus</string>
|
||||||
|
<string name="sensor_state_cadence_max">Suurin Poljinnopeus</string>
|
||||||
|
<string name="value_float_mile_hour">%1$.2f mt</string>
|
||||||
|
<string name="generic_open_track">Avaa Raita</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -73,7 +73,7 @@ Infatti, un\'applicazione deve supportare <i>ACTION_VIEW</i> con MIME <i>applica
|
|||||||
<string name="activity_type_driving_bus">guidare autobus</string>
|
<string name="activity_type_driving_bus">guidare autobus</string>
|
||||||
<string name="activity_type_driving_car">guidare auto</string>
|
<string name="activity_type_driving_car">guidare auto</string>
|
||||||
<string name="activity_type_ferry">traghetto</string>
|
<string name="activity_type_ferry">traghetto</string>
|
||||||
<string name="activity_type_frisbee">frisbee</string>
|
<string name="activity_type_frisbee">di frisbee</string>
|
||||||
<string name="activity_type_gliding">aliante</string>
|
<string name="activity_type_gliding">aliante</string>
|
||||||
<string name="activity_type_hang_gliding">deltaplano</string>
|
<string name="activity_type_hang_gliding">deltaplano</string>
|
||||||
<string name="activity_type_helicopter">elicottero</string>
|
<string name="activity_type_helicopter">elicottero</string>
|
||||||
@@ -106,7 +106,7 @@ Infatti, un\'applicazione deve supportare <i>ACTION_VIEW</i> con MIME <i>applica
|
|||||||
<string name="activity_type_skate_boarding">skateboarding</string>
|
<string name="activity_type_skate_boarding">skateboarding</string>
|
||||||
<string name="activity_type_skating">pattinaggio</string>
|
<string name="activity_type_skating">pattinaggio</string>
|
||||||
<string name="activity_type_skiing">sci</string>
|
<string name="activity_type_skiing">sci</string>
|
||||||
<string name="activity_type_sky_jumping">sky jumping</string>
|
<string name="activity_type_sky_jumping">salto nel cielo</string>
|
||||||
<string name="activity_type_sled">slitta</string>
|
<string name="activity_type_sled">slitta</string>
|
||||||
<string name="activity_type_snow_boarding">snowboard</string>
|
<string name="activity_type_snow_boarding">snowboard</string>
|
||||||
<string name="activity_type_snow_shoeing">racchette da neve</string>
|
<string name="activity_type_snow_shoeing">racchette da neve</string>
|
||||||
@@ -118,7 +118,7 @@ Infatti, un\'applicazione deve supportare <i>ACTION_VIEW</i> con MIME <i>applica
|
|||||||
<string name="activity_type_trail_hiking">escursionismo su sentiero</string>
|
<string name="activity_type_trail_hiking">escursionismo su sentiero</string>
|
||||||
<string name="activity_type_trail_running">corsa campestre</string>
|
<string name="activity_type_trail_running">corsa campestre</string>
|
||||||
<string name="activity_type_train">treno</string>
|
<string name="activity_type_train">treno</string>
|
||||||
<string name="activity_type_ultimate_frisbee">ultimate frisbee</string>
|
<string name="activity_type_ultimate_frisbee">frisbee finale</string>
|
||||||
<string name="activity_type_unknown">sconosciuto</string>
|
<string name="activity_type_unknown">sconosciuto</string>
|
||||||
<string name="activity_type_wakeboarding">wakeboard</string>
|
<string name="activity_type_wakeboarding">wakeboard</string>
|
||||||
<string name="activity_type_walking">camminare</string>
|
<string name="activity_type_walking">camminare</string>
|
||||||
@@ -459,7 +459,7 @@ Infatti, un\'applicazione deve supportare <i>ACTION_VIEW</i> con MIME <i>applica
|
|||||||
<string name="waypoint_type_atm">Bancomat</string>
|
<string name="waypoint_type_atm">Bancomat</string>
|
||||||
<string name="waypoint_type_bank">banca</string>
|
<string name="waypoint_type_bank">banca</string>
|
||||||
<string name="waypoint_type_bar">bar</string>
|
<string name="waypoint_type_bar">bar</string>
|
||||||
<string name="waypoint_type_barbecue">barbecue</string>
|
<string name="waypoint_type_barbecue">grigliata</string>
|
||||||
<string name="waypoint_type_building">edificio</string>
|
<string name="waypoint_type_building">edificio</string>
|
||||||
<string name="waypoint_type_bus_stop">fermata dell\'autobus</string>
|
<string name="waypoint_type_bus_stop">fermata dell\'autobus</string>
|
||||||
<string name="waypoint_type_cafe">caffè</string>
|
<string name="waypoint_type_cafe">caffè</string>
|
||||||
@@ -503,7 +503,7 @@ Infatti, un\'applicazione deve supportare <i>ACTION_VIEW</i> con MIME <i>applica
|
|||||||
<string name="waypoint_type_toilet">toilette</string>
|
<string name="waypoint_type_toilet">toilette</string>
|
||||||
<string name="waypoint_type_tourist_information">informazioni turistiche</string>
|
<string name="waypoint_type_tourist_information">informazioni turistiche</string>
|
||||||
<string name="waypoint_type_tree">.</string>
|
<string name="waypoint_type_tree">.</string>
|
||||||
<string name="waypoint_type_tunnel">tunnel</string>
|
<string name="waypoint_type_tunnel">galleria</string>
|
||||||
<string name="waypoint_type_waterfall">cascata</string>
|
<string name="waypoint_type_waterfall">cascata</string>
|
||||||
<string name="waypoint_type_water_fountain">fontana ad acqua</string>
|
<string name="waypoint_type_water_fountain">fontana ad acqua</string>
|
||||||
<string name="waypoint_type_waypoint">tappa</string>
|
<string name="waypoint_type_waypoint">tappa</string>
|
||||||
@@ -603,4 +603,16 @@ Infatti, un\'applicazione deve supportare <i>ACTION_VIEW</i> con MIME <i>applica
|
|||||||
<string name="import_progress_summary_ok_msg">File importati</string>
|
<string name="import_progress_summary_ok_msg">File importati</string>
|
||||||
<string name="import_progress_summary_exists_msg">Esiste già</string>
|
<string name="import_progress_summary_exists_msg">Esiste già</string>
|
||||||
<string name="import_progress_summary_errors_msg">Errore</string>
|
<string name="import_progress_summary_errors_msg">Errore</string>
|
||||||
|
<string name="sensor_state_power_avg">Potenza media</string>
|
||||||
|
<string name="sensor_state_heart_rate_max">Frequenza cardiaca max</string>
|
||||||
|
<string name="value_pace_kilometer">%1$d:%2$02d min/cm</string>
|
||||||
|
<string name="value_float_kilometer_hour">%1$.2f cp/s</string>
|
||||||
|
<string name="stats_loss">Perdita</string>
|
||||||
|
<string name="settings_sensor_wheel_circumference">Circonferenza della ruota (mm)</string>
|
||||||
|
<string name="description_elevation_loss">Perdita di quota: %1$d m (%2$d ft)</string>
|
||||||
|
<string name="sensor_state_heart_rate_avg">Tasso cardiaco medio</string>
|
||||||
|
<string name="sensor_state_cadence_max">Cadenza max</string>
|
||||||
|
<string name="sensor_state_cadence_avg">Cadenza media</string>
|
||||||
|
<string name="value_float_mile_hour">%1$.2f mpo</string>
|
||||||
|
<string name="value_pace_mile">%1$d:%2$02d min/mi</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -603,4 +603,7 @@ limitations under the License.
|
|||||||
<string name="sensor_state_heart_rate_max">Maks puls</string>
|
<string name="sensor_state_heart_rate_max">Maks puls</string>
|
||||||
<string name="sensor_state_power_avg">Gjennomsnittlig effekt</string>
|
<string name="sensor_state_power_avg">Gjennomsnittlig effekt</string>
|
||||||
<string name="settings_sensor_wheel_circumference">Hjulomkrets (mm)</string>
|
<string name="settings_sensor_wheel_circumference">Hjulomkrets (mm)</string>
|
||||||
|
<string name="track_distance_notification">Distanse: %1$s</string>
|
||||||
|
<string name="track_speed_notification">Hastighet: %1$s</string>
|
||||||
|
<string name="track_pace_notification">Tempo: %1$s</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?><!--
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
Copyright 2010 Google Inc.
|
Copyright 2010 Google Inc.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -12,8 +13,7 @@ distributed under the License is distributed on an "AS IS" BASIS,
|
|||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
--><resources>
|
||||||
<resources>
|
|
||||||
<string name="about_preference_title">Over OpenTracks</string>
|
<string name="about_preference_title">Over OpenTracks</string>
|
||||||
<string name="about_description"><i>OpenTracks</i> is een sporttrackingapplicatie die uw privacy volledig respecteert.</string>
|
<string name="about_description"><i>OpenTracks</i> is een sporttrackingapplicatie die uw privacy volledig respecteert.</string>
|
||||||
<string name="about_url">Project webpagina: <a href="%1$s">%1$s</a></string>
|
<string name="about_url">Project webpagina: <a href="%1$s">%1$s</a></string>
|
||||||
@@ -23,71 +23,45 @@ limitations under the License.
|
|||||||
<string name="about_libraries">Bibliotheken</string>
|
<string name="about_libraries">Bibliotheken</string>
|
||||||
<!-- Help -->
|
<!-- Help -->
|
||||||
<string name="help_feature_title">OpenTracks heeft de volgende kenmerken:</string>
|
<string name="help_feature_title">OpenTracks heeft de volgende kenmerken:</string>
|
||||||
<string name="help_feature_content">
|
<string name="help_feature_content">* GPS tracks maken
|
||||||
* creëer GPS tracks
|
\n * een hartslagsensor gebruiken (alleen Bluetooth LE)
|
||||||
* gebruik een hartslagsensor (alleen Bluetooth LE)...
|
\n * spraakaankondigingen (op tijd of afstand)
|
||||||
* spraakaankondigingen (op tijd of afstand)...
|
\n * markers maken (incl. foto\'s)
|
||||||
* creëer markers (incl. fotos)
|
\n * werkt volledig offline
|
||||||
* werkt volledig offline
|
\n * toon tracks op een kaart (zie hieronder)</string>
|
||||||
* toon tracks op een kaart (zie hieronder)</string>
|
|
||||||
|
|
||||||
<string name="help_track_map_title">Hoe toon je een spoor op een kaart?</string>
|
<string name="help_track_map_title">Hoe toon je een spoor op een kaart?</string>
|
||||||
<string name="help_track_map_content">
|
<string name="help_track_map_content"> Gebruik het kleine kaartpictogram.
|
||||||
Gebruik het kleine kaarticoontje.
|
\n a) (live updates) Installeer <a href="https://github.com/OpenTracksApp/OSMDashboard">OSMDashboard</a>. Het biedt online of offline kaarten via <a href="https://www.openstreetmap.org">OpenStreetMap</a>.
|
||||||
a)
|
\n Eigenlijk is OSMDashboard een aparte app die alleen (tijdelijk) toegang heeft tot de gegevens van de track(s) die getoond gaan worden.
|
||||||
(live updates) Installeer <a href="https://github.com/OpenTracksApp/OSMDashboard">OSMDashboard</a>.
|
\n b) Via een normale kaartapplicatie (bijv. <a href="http://osmand.net/">OsmAnd</a> en <a href="https://maps.me/">MAPS.ME</a>). Deze apps moeten het KMZ-bestandsformaat ondersteunen (alleen locaties en tijdstempels). In feite moet een app <i>ACTION_VIEW</i> ondersteunen met MIME <i>application/vnd.google-earth.kmz</i>. </string>
|
||||||
Het biedt online of offline kaarten via <a href="https://www.openstreetmap.org">OpenStreetMap</a>.\n
|
|
||||||
Eigenlijk is OSMDashboard een aparte app die alleen (tijdelijk) toegang heeft tot de gegevens van track(s) die getoond gaan worden.
|
|
||||||
|
|
||||||
\n
|
|
||||||
b)
|
|
||||||
Via een normale kaarttoepassing (bijv. <a href="http://osmand.net/">OsmAnd</a> en <a href="https://maps.me/">MAPS.ME</a>).
|
|
||||||
Deze app moet het KMZ-bestandsformaat ondersteunen (alleen locaties en tijdstempels).
|
|
||||||
In feite moet een app <i>ACTION_VIEW</i> ondersteunen met MIME <i>application/vnd.google-earth.kmz</i>.</string>
|
|
||||||
|
|
||||||
<string name="help_storage_pictures_title">Hoe slaat OpenTracks fotos op die als markers zijn genomen?</string>
|
<string name="help_storage_pictures_title">Hoe slaat OpenTracks fotos op die als markers zijn genomen?</string>
|
||||||
<string name="help_storage_pictures_content">Deze worden opgeslagen in de interne opslag van de app (d.w.z. alleen toegankelijk binnen OpenTracks).</string>
|
<string name="help_storage_pictures_content">Deze worden opgeslagen in de interne opslag van de app (d.w.z. alleen toegankelijk binnen OpenTracks).</string>
|
||||||
|
|
||||||
<string name="help_track_export_title">Hoe kan ik opgenomen tracks exporteren/delen?</string>
|
<string name="help_track_export_title">Hoe kan ik opgenomen tracks exporteren/delen?</string>
|
||||||
<string name="help_track_export_content">
|
<string name="help_track_export_content"> Tracks kunnen worden geëxporteerd vanuit de instellingen als KMZ, KML of GPX. KMZ/KML alle gegevens; GPX alleen locaties. Tracks die worden gedeeld via het <i>share-icoontje</i> worden gedeeld als KMZ </string>
|
||||||
Tracks kunnen worden geëxporteerd vanuit de instellingen als KMZ, KML of GPX.
|
|
||||||
KMZ/KML alle gegevens; GPX alleen locaties.
|
|
||||||
Tracks die worden gedeeld via het <i>share-icoontje</i> worden gedeeld als KMZ.</string>
|
|
||||||
|
|
||||||
<string name="help_data_google_play_services_title">Heeft OpenTracks Google Play Service nodig/gebruikt?</string>
|
<string name="help_data_google_play_services_title">Heeft OpenTracks Google Play Service nodig/gebruikt?</string>
|
||||||
|
|
||||||
<string name="help_recording_title">Hoe legt OpenTracks gegevens vast?</string>
|
<string name="help_recording_title">Hoe legt OpenTracks gegevens vast?</string>
|
||||||
<string name="help_recording_content">
|
<string name="help_recording_content">
|
||||||
OpenTracks gebruikt de GPS-sensor van het apparaat om de locatie continu te registreren.
|
OpenTracks gebruikt de GPS-sensor van het apparaat om de locatie continu te registreren.
|
||||||
Als het GPS-apparaat onnauwkeurige gegevens rapporteert (bijv. locatie, snelheid, hoogte), kan OpenTracks daar niets aan doen.</string>
|
Als het GPS-apparaat onnauwkeurige gegevens rapporteert (bijv. locatie, snelheid, hoogte), kan OpenTracks daar niets aan doen.</string>
|
||||||
|
|
||||||
<string name="help_data_storage_title">Hoe slaat OpenTracks sensorgegevens op?</string>
|
<string name="help_data_storage_title">Hoe slaat OpenTracks sensorgegevens op?</string>
|
||||||
<string name="help_data_storage_content">
|
<string name="help_data_storage_content"> De sensorgegevens worden per opgenomen locatie opgeslagen. In termen van een hartslagsensor betekent dit dat slechts <i>een</i> hartslagmeting per locatie wordt opgeslagen. Als u stilstaat of binnenshuis bent, worden er geen sensorgegevens geregistreerd (maar wel getoond) </string>
|
||||||
De sensorgegevens worden per opgenomen locatie opgeslagen.
|
|
||||||
In termen van een hartslagsensor betekent dit dat slechts <i>een</i> hartslagmeting per locatie wordt opgeslagen.
|
|
||||||
Als u stilstaat of binnenshuis bent, worden er geen sensorgegevens geregistreerd (maar wel getoond).</string>
|
|
||||||
|
|
||||||
<string name="help_gps_troubleshooting_title">OpenTracks neemt geen locaties op?</string>
|
<string name="help_gps_troubleshooting_title">OpenTracks neemt geen locaties op?</string>
|
||||||
<string name="help_gps_troubleshooting_content">
|
<string name="help_gps_troubleshooting_content"> Wat u kunt doen:
|
||||||
Wat kun je doen?
|
\n a) Controleer of GPS is ingeschakeld,
|
||||||
a) controleer of de GPS is ingeschakeld.
|
\n b) verbeter de GPS-ontvangst (ga bijvoorbeeld naar buiten),
|
||||||
b) het verbeteren van de GPS-ontvangst (bijv. naar buiten gaan),\n
|
\n c) controleren met <a href="https://f-droid.org/en/packages/com.android.gpstest.osmdroid/">GPSTest</a> app, en
|
||||||
c) controleer of met <a href="https://f-droid.org/en/packages/com.android.gpstest.osmdroid/">GPSTest</a> app, en
|
\n d) schakel energiebesparing uit.
|
||||||
d) schakel stroombesparing uit.
|
|
||||||
\n
|
\n
|
||||||
Als alles niet helpt, meldt u dan alstublieft een bug.</string>
|
\n Als alles niet helpt, meld dan een bug. </string>
|
||||||
|
|
||||||
<string name="help_support_title">Hoe kan ik OpenTracks ondersteunen?</string>
|
<string name="help_support_title">Hoe kan ik OpenTracks ondersteunen?</string>
|
||||||
<string name="help_support_content">
|
<string name="help_support_content"> U kunt:
|
||||||
Je kunt...
|
\n a) het woord verspreiden over OpenTracks,
|
||||||
a) het woord verspreiden over OpenTracks, en...
|
\n b) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">functies voorstellen</a>,
|
||||||
b) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">voorstellen van functies</a>,\n
|
\n c) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">bugs melden</a>,
|
||||||
c) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">melding van bugs</a>,\n
|
\n d) helpen bij de ontwikkeling van software,
|
||||||
d) hulp bij de ontwikkeling van software.
|
\n e) kopen in <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore">Google Play Store</a>,
|
||||||
e) koop in <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore">Google Play Store</a>,\n
|
\n f) doneren, en
|
||||||
f) doneert u, en
|
\n g) doe wat u denkt dat OpenTracks helpt. </string>
|
||||||
g) doe wat je denkt dat OpenTracks helpt.</string>
|
|
||||||
|
|
||||||
<!-- Activity Type -->
|
<!-- Activity Type -->
|
||||||
<string name="activity_type_airplane">vliegtuig</string>
|
<string name="activity_type_airplane">vliegtuig</string>
|
||||||
<string name="activity_type_atv">quad</string>
|
<string name="activity_type_atv">quad</string>
|
||||||
@@ -104,7 +78,7 @@ g) doe wat je denkt dat OpenTracks helpt.</string>
|
|||||||
<string name="activity_type_driving_bus">bus besturen</string>
|
<string name="activity_type_driving_bus">bus besturen</string>
|
||||||
<string name="activity_type_driving_car">autorijden</string>
|
<string name="activity_type_driving_car">autorijden</string>
|
||||||
<string name="activity_type_ferry">veerboot</string>
|
<string name="activity_type_ferry">veerboot</string>
|
||||||
<string name="activity_type_frisbee">frisbee</string>
|
<string name="activity_type_frisbee">Frisbee</string>
|
||||||
<string name="activity_type_gliding">zweefvliegen</string>
|
<string name="activity_type_gliding">zweefvliegen</string>
|
||||||
<string name="activity_type_hang_gliding">deltavliegen</string>
|
<string name="activity_type_hang_gliding">deltavliegen</string>
|
||||||
<string name="activity_type_helicopter">helikopter</string>
|
<string name="activity_type_helicopter">helikopter</string>
|
||||||
@@ -149,7 +123,7 @@ g) doe wat je denkt dat OpenTracks helpt.</string>
|
|||||||
<string name="activity_type_trail_hiking">trektocht (pad)</string>
|
<string name="activity_type_trail_hiking">trektocht (pad)</string>
|
||||||
<string name="activity_type_trail_running">trailrunning</string>
|
<string name="activity_type_trail_running">trailrunning</string>
|
||||||
<string name="activity_type_train">trein</string>
|
<string name="activity_type_train">trein</string>
|
||||||
<string name="activity_type_ultimate_frisbee">ultimate frisbee</string>
|
<string name="activity_type_ultimate_frisbee">ultieme frisbee</string>
|
||||||
<string name="activity_type_unknown">onbekend</string>
|
<string name="activity_type_unknown">onbekend</string>
|
||||||
<string name="activity_type_wakeboarding">wakeboarden</string>
|
<string name="activity_type_wakeboarding">wakeboarden</string>
|
||||||
<string name="activity_type_walking">wandelen</string>
|
<string name="activity_type_walking">wandelen</string>
|
||||||
@@ -185,14 +159,14 @@ g) doe wat je denkt dat OpenTracks helpt.</string>
|
|||||||
<string name="description_sensor_cadence">Cadans (tpm)</string>
|
<string name="description_sensor_cadence">Cadans (tpm)</string>
|
||||||
<string name="description_sensor_heart_rate">Hartslag (spm)</string>
|
<string name="description_sensor_heart_rate">Hartslag (spm)</string>
|
||||||
<string name="description_sensor_power">Vermogen (W)</string>
|
<string name="description_sensor_power">Vermogen (W)</string>
|
||||||
<string name="description_default_speed_or_pace">By activity type</string>
|
<string name="description_default_speed_or_pace">Op type activiteit</string>
|
||||||
<string name="description_speed_imperial">Snelheid (mi/u)</string>
|
<string name="description_speed_imperial">Snelheid (mi/u)</string>
|
||||||
<string name="description_speed_metric">Snelheid (km/u)</string>
|
<string name="description_speed_metric">Snelheid (km/u)</string>
|
||||||
<string name="description_time">Tijd</string>
|
<string name="description_time">Tijd</string>
|
||||||
<string name="description_total_distance">Totale afstand: %1$.2f km (%2$.1f mi)</string>
|
<string name="description_total_distance">Totale afstand: %1$.2f km (%2$.1f mi)</string>
|
||||||
<string name="description_total_time">Totale tijd: %1$s</string>
|
<string name="description_total_time">Totale tijd: %1$s</string>
|
||||||
<string name="description_track_point">Punt</string>
|
<string name="description_track_point">Punt</string>
|
||||||
<string name="description_track_segment">Segment</string>
|
<string name="description_track_segment">segment</string>
|
||||||
<!-- Export -->
|
<!-- Export -->
|
||||||
<string name="export_all_option">Alles als %1$s</string>
|
<string name="export_all_option">Alles als %1$s</string>
|
||||||
<string name="export_all_title">Exporteren naar externe opslag</string>
|
<string name="export_all_title">Exporteren naar externe opslag</string>
|
||||||
@@ -331,7 +305,7 @@ g) doe wat je denkt dat OpenTracks helpt.</string>
|
|||||||
<string name="settings_chart_by_time">Op tijd</string>
|
<string name="settings_chart_by_time">Op tijd</string>
|
||||||
<string name="settings_chart_x_axis">X-as</string>
|
<string name="settings_chart_x_axis">X-as</string>
|
||||||
<!-- Settings Recording -->
|
<!-- Settings Recording -->
|
||||||
<string name="settings_recording_show_on_lockscreen_while_recording_title">Toon de statistieken op het slotscherm.</string>
|
<string name="settings_recording_show_on_lockscreen_while_recording_title">Toon de statistieken op het slotscherm</string>
|
||||||
<string name="settings_recording_show_on_lockscreen_while_recording_summary">Toon tijdens de opname de statistieken zonder het apparaat te ontgrendelen.</string>
|
<string name="settings_recording_show_on_lockscreen_while_recording_summary">Toon tijdens de opname de statistieken zonder het apparaat te ontgrendelen.</string>
|
||||||
<string name="settings_recording_keep_screen_on_while_recording_title">Houd het scherm aan</string>
|
<string name="settings_recording_keep_screen_on_while_recording_title">Houd het scherm aan</string>
|
||||||
<string name="settings_recording_keep_screen_on_while_recording_summary">Houd tijdens de opname het scherm aan.</string>
|
<string name="settings_recording_keep_screen_on_while_recording_summary">Houd tijdens de opname het scherm aan.</string>
|
||||||
@@ -359,22 +333,22 @@ g) doe wat je denkt dat OpenTracks helpt.</string>
|
|||||||
<string name="settings_reset_done">Voor alle instellingen zijn de standaardwaarden teruggezet</string>
|
<string name="settings_reset_done">Voor alle instellingen zijn de standaardwaarden teruggezet</string>
|
||||||
<string name="settings_error_initial_values_restored">Sorry, maar er is een fout gemaakt. Alle instellingen zijn teruggezet naar de standaardwaarden.</string>
|
<string name="settings_error_initial_values_restored">Sorry, maar er is een fout gemaakt. Alle instellingen zijn teruggezet naar de standaardwaarden.</string>
|
||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor">Sensor</string>
|
<string name="settings_sensor">sensor</string>
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<string name="settings_sensor_bluetooth_sensor">Bluetooth-sensor</string>
|
<string name="settings_sensor_bluetooth_sensor">Bluetooth-sensor</string>
|
||||||
<string name="settings_sensor_connecting">Verbonden met %1$s</string>
|
<string name="settings_sensor_connecting">Verbonden met %1$s</string>
|
||||||
<string name="settings_sensor_disconnected">Ontkoppeld van %1$s</string>
|
<string name="settings_sensor_disconnected">Ontkoppeld van %1$s</string>
|
||||||
|
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Breedte-/lengtegraad</string>
|
<string name="settings_stats_coordinate">Breedte-/lengtegraad</string>
|
||||||
<string name="settings_stats_rate_title">Voorkeursverhouding</string>
|
<string name="settings_stats_rate_title">Voorkeursverhouding</string>
|
||||||
<string name="settings_stats_units_imperial">Engels (mi, ft)</string>
|
<string name="settings_stats_units_imperial">Engels (mi, ft)</string>
|
||||||
<string name="settings_stats_units_metric">Metrisch (km, m)</string>
|
<string name="settings_stats_units_metric">Metrisch (km, m)</string>
|
||||||
<string name="settings_stats_units_title">Voorkeurseenheden</string>
|
<string name="settings_stats_units_title">Voorkeurseenheden</string>
|
||||||
|
|
||||||
<!-- Share Track -->
|
<!-- Share Track -->
|
||||||
<string name="share_track_share_file">Routebestand delen</string>
|
<string name="share_track_share_file">Routebestand delen</string>
|
||||||
<string name="share_track_share_file_body">Ik denk dat u misschien wel geïnteresseerd bent in deze route.\n\nAls u deze route wilt weergeven, kunt u Google Earth of andere kaartsoftware gebruiken.\n\n%1$s</string>
|
<string name="share_track_share_file_body">Ik denk dat u misschien wel geïnteresseerd bent in deze route.
|
||||||
|
\n
|
||||||
|
\n%1$s</string>
|
||||||
<string name="share_track_subject">Ik wil graag een route met u delen</string>
|
<string name="share_track_subject">Ik wil graag een route met u delen</string>
|
||||||
<!-- Stats -->
|
<!-- Stats -->
|
||||||
<string name="stats_average_moving_pace">Gem. verplaatsingstempo</string>
|
<string name="stats_average_moving_pace">Gem. verplaatsingstempo</string>
|
||||||
@@ -473,7 +447,7 @@ g) doe wat je denkt dat OpenTracks helpt.</string>
|
|||||||
<string name="voice_minutes_other">%1$d minuten</string>
|
<string name="voice_minutes_other">%1$d minuten</string>
|
||||||
<string name="voice_minutes_two">2 minuten</string>
|
<string name="voice_minutes_two">2 minuten</string>
|
||||||
<string name="voice_minutes_zero">0 minuten</string>
|
<string name="voice_minutes_zero">0 minuten</string>
|
||||||
<string name="voice_pace_per_kilometer">%1$s per kilometer</string>
|
<string name="voice_pace_per_kilometer">%1$s te kilometer</string>
|
||||||
<string name="voice_pace_per_mile">%1$s per mijl</string>
|
<string name="voice_pace_per_mile">%1$s per mijl</string>
|
||||||
<string name="voice_seconds_few">%1$d seconden</string>
|
<string name="voice_seconds_few">%1$d seconden</string>
|
||||||
<string name="voice_seconds_many">%1$d seconden</string>
|
<string name="voice_seconds_many">%1$d seconden</string>
|
||||||
@@ -511,7 +485,7 @@ g) doe wat je denkt dat OpenTracks helpt.</string>
|
|||||||
<string name="waypoint_type_atm">Pinautomaat</string>
|
<string name="waypoint_type_atm">Pinautomaat</string>
|
||||||
<string name="waypoint_type_bank">bank</string>
|
<string name="waypoint_type_bank">bank</string>
|
||||||
<string name="waypoint_type_bar">bar</string>
|
<string name="waypoint_type_bar">bar</string>
|
||||||
<string name="waypoint_type_barbecue">barbecue</string>
|
<string name="waypoint_type_barbecue">barbecueën</string>
|
||||||
<string name="waypoint_type_building">gebouw</string>
|
<string name="waypoint_type_building">gebouw</string>
|
||||||
<string name="waypoint_type_bus_stop">bushalte</string>
|
<string name="waypoint_type_bus_stop">bushalte</string>
|
||||||
<string name="waypoint_type_cafe">café</string>
|
<string name="waypoint_type_cafe">café</string>
|
||||||
@@ -551,16 +525,86 @@ g) doe wat je denkt dat OpenTracks helpt.</string>
|
|||||||
<string name="waypoint_type_store">winkel</string>
|
<string name="waypoint_type_store">winkel</string>
|
||||||
<string name="waypoint_type_swimming_pool">zwembad</string>
|
<string name="waypoint_type_swimming_pool">zwembad</string>
|
||||||
<string name="waypoint_type_telephone">telefoon</string>
|
<string name="waypoint_type_telephone">telefoon</string>
|
||||||
<string name="waypoint_type_theater">theater</string>
|
<string name="waypoint_type_theater">schouwburg</string>
|
||||||
<string name="waypoint_type_toilet">toilet</string>
|
<string name="waypoint_type_toilet">restroom</string>
|
||||||
<string name="waypoint_type_tourist_information">toeristische informatie</string>
|
<string name="waypoint_type_tourist_information">toeristische informatie</string>
|
||||||
<string name="waypoint_type_tree">boom</string>
|
<string name="waypoint_type_tree">boom</string>
|
||||||
<string name="waypoint_type_tunnel">tunnel</string>
|
<string name="waypoint_type_tunnel">schacht</string>
|
||||||
<string name="waypoint_type_waterfall">waterval</string>
|
<string name="waypoint_type_waterfall">waterval</string>
|
||||||
<string name="waypoint_type_water_fountain">waterfontein</string>
|
<string name="waypoint_type_water_fountain">waterfontein</string>
|
||||||
<string name="waypoint_type_waypoint">routepunt</string>
|
<string name="waypoint_type_waypoint">routepunt</string>
|
||||||
<!-- Share image -->
|
<!-- Share image -->
|
||||||
<string name="share_image_subject">Ik wil graag een beeld met u delen</string>
|
<string name="share_image_subject">Ik wil graag een beeld met u delen</string>
|
||||||
<string name="share_image_body">Ik denk dat je misschien geïnteresseerd bent in dit beeld.</string>
|
<string name="share_image_body">Ik denk dat je misschien geïnteresseerd bent in dit beeld.</string>
|
||||||
|
<string name="export_track_already_exists_msg">De track %1$s bestaat al in de doelmap.</string>
|
||||||
|
<string name="export_track_errors">Tracks niet geëxporteerd</string>
|
||||||
|
<string name="description_elevation_loss">Hoogteverlies: %1$d m (%2$d ft)</string>
|
||||||
|
<string name="export_error_post_workout">Post-workout export mislukt, controleer de export map.</string>
|
||||||
|
<string name="open_track_using_dashboard">Openen met behulp van OpenTracks-Dashboard</string>
|
||||||
|
<string name="open_track_as_KMZ">Openen als KMZ</string>
|
||||||
|
<string name="open_track_as_GPX">Openen als GPX</string>
|
||||||
|
<string name="open_track_as_trackfileformat">Openen als %1$s</string>
|
||||||
|
<string name="activity_type_escooter">scooter</string>
|
||||||
|
<string name="export_all_do_it_for_all">doe het voor alle conflicten</string>
|
||||||
|
<string name="export_progress_summary_new_msg">Nieuwe sporen geëxporteerd</string>
|
||||||
|
<string name="generic_click_twice_cancel">Klik nogmaals terug om te annuleren</string>
|
||||||
|
<string name="settings_default_export_uri_title">Spoor export map</string>
|
||||||
|
<string name="import_thread_interrupted">Draad onderbroken</string>
|
||||||
|
<string name="import_no_kml_file_found">Geen doc.kml bestand gevonden in KMZ</string>
|
||||||
|
<string name="settings_recording_fullscreen_on_while_recording_title">Volledig scherm</string>
|
||||||
|
<string name="gps_fixed_and_ready">GPS vast en klaar</string>
|
||||||
|
<string name="value_float_kilometer_hour">%1$.2f km/h</string>
|
||||||
|
<string name="aggregated_stats_empty_message">Neem uw eerste track op om geaggregeerde statistieken te zien</string>
|
||||||
|
<string name="track_detail_intervals_tab">Intervallen</string>
|
||||||
|
<string name="settings_sensor_wheel_circumference">Wielomtrek (mm)</string>
|
||||||
|
<string name="settings_prevent_reimport_tracks_title">Voorkom herinvoer van tracks</string>
|
||||||
|
<plurals name="generic_completed_with_errors">
|
||||||
|
<item quantity="one">Voltooid met één fout</item>
|
||||||
|
<item quantity="other">Afgerond met %1$d fouten</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="settings_recording_fullscreen_on_while_recording_summary">Tijdens opname, aanwezig in volledig scherm.</string>
|
||||||
|
<string name="settings_default_trackfileformat">Bestandsformaat exporteren/delen</string>
|
||||||
|
<string name="sensor_state_power_avg">Gem. Vermogen</string>
|
||||||
|
<string name="sensor_state_heart_rate_max">Max. Hartslag</string>
|
||||||
|
<string name="sensor_state_heart_rate_avg">Gem. Hartslag</string>
|
||||||
|
<string name="sensor_state_cadence_avg">Avg cadans</string>
|
||||||
|
<string name="sensor_state_cadence_max">Max. cadans</string>
|
||||||
|
<string name="settings_night_mode_option_night">Nacht</string>
|
||||||
|
<string name="settings_night_mode_option_day">Dag</string>
|
||||||
|
<string name="settings_night_mode_option_system">Systeem</string>
|
||||||
|
<string name="settings_night_mode_title">UI Thema</string>
|
||||||
|
<string name="stats_loss">Verlies</string>
|
||||||
|
<string name="value_float_mile_hour">%1$.2f mph</string>
|
||||||
|
<string name="interval_list_empty_message">Er zijn nog geen intervallen</string>
|
||||||
|
<string name="stats_split_interval">Gesplitst interval</string>
|
||||||
|
<string name="stats_intervals">Intervallen</string>
|
||||||
|
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
|
||||||
|
<string name="value_pace_mile">%1$d:%2$02d min/mi</string>
|
||||||
|
<string name="voice_pace_lap">Rondetijd van %1$s</string>
|
||||||
|
<string name="voice_speed_lap">Ronde snelheid van %1$s</string>
|
||||||
|
<string name="instant_export_enabled_title">Directe export na de training</string>
|
||||||
|
<string name="instant_export_enabled_summary">Exporteer track naar opslag nadat opname is voltooid</string>
|
||||||
|
<string name="toast_message_instant_track_was_exported">Laatste geëxporteerde track</string>
|
||||||
|
<string name="hold_to_pause">Vasthouden om te pauzeren</string>
|
||||||
|
<string name="export_progress_summary_skip_msg">Tracks overgeslagen</string>
|
||||||
|
<string name="export_progress_summary_overwrite_msg">Tracks overschreven</string>
|
||||||
|
<string name="export_progress_summary_errors_msg">Fouten</string>
|
||||||
|
<string name="generic_open_track">Open spoor</string>
|
||||||
|
<string name="generic_overwrite">Overschrijven</string>
|
||||||
|
<string name="generic_skip">Sla over.</string>
|
||||||
|
<string name="generic_separator_done_total">/</string>
|
||||||
|
<string name="generic_show_errors">Fouten tonen</string>
|
||||||
|
<string name="generic_completed">Voltooid</string>
|
||||||
|
<string name="import_unsupported_format">Niet-ondersteund bestandsformaat</string>
|
||||||
|
<string name="import_error_list_dialog_title">Bestanden niet geïmporteerd</string>
|
||||||
|
<string name="import_prevent_reimport">Jij hebt ingesteld voorkom her-import spoor</string>
|
||||||
|
<string name="import_progress_summary_ok_msg">Ingevoerde bestanden</string>
|
||||||
|
<string name="import_progress_summary_exists_msg">Bestaat reeds</string>
|
||||||
|
<string name="import_progress_summary_errors_msg">Fouten</string>
|
||||||
|
<string name="gps_disabled_msg">GPS uitgeschakeld</string>
|
||||||
|
<string name="import_parser_error">Parser fout: %1$s</string>
|
||||||
|
<string name="import_unable_to_import_file">Kan bestand niet importeren: %1$s</string>
|
||||||
|
<string name="import_error_info">%1$s: %2$s</string>
|
||||||
|
<string name="import_file_imported">Bestand %1$s geimporteerd</string>
|
||||||
|
<string name="hold_to_stop">Hou vast om te stoppen</string>
|
||||||
</resources>
|
</resources>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user