forked from upstream-mirrors/OpenTracks
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6656c9ab92 | |||
| af6baeab9f | |||
| 9b4d3a4718 | |||
| 942b29aa25 | |||
| 18e18353e7 | |||
| 8c8fe9f22d | |||
| 648c106f7f | |||
| bb86ab927c | |||
| 9150318ef9 | |||
| b98a0a0283 | |||
| 71f1049642 | |||
| 6185154af9 | |||
| b4ccdcf4a2 | |||
| 681b987927 | |||
| ed163b2083 | |||
| 77ccbe7004 | |||
| 247a5f342a | |||
| 7b9b1d3c95 | |||
| 44fe4f8818 | |||
| 1f55729b71 | |||
| 8592375edc | |||
| 2c1ffd5fa1 | |||
| 2672602a71 | |||
| 9e0553d5d6 | |||
| 5b7bc4ea24 | |||
| f4a477b99d | |||
| c9a2b31866 | |||
| 4412a6a698 |
@@ -27,7 +27,7 @@ jobs:
|
||||
sudo udevadm trigger --name-match=kvm
|
||||
|
||||
- name: run tests
|
||||
uses: reactivecircus/android-emulator-runner@v2.33.0
|
||||
uses: reactivecircus/android-emulator-runner@v2.34.0
|
||||
with:
|
||||
arch: x86_64
|
||||
api-level: 34
|
||||
|
||||
@@ -100,8 +100,8 @@ __Only required permissions:__
|
||||
|
||||
### Public API
|
||||
|
||||
OpenTracks includes an API for starting/stopping recording by another installed application (e.g., [Automate](https://llamalab.com/automate/), [Tasker](https://tasker.joaoapps.com), or [Easer](https://github.com/renyuneyun/Easer)).
|
||||
The API can be invoked by sending an explicit Intent to start an activity.
|
||||
OpenTracks includes an API for starting/stopping recording by another installed application (e.g., [Automate](https://llamalab.com/automate/), [Tasker](https://tasker.joaoapps.com), or [Easer](https://github.com/renyuneyun/Easer)).
|
||||
The API is disabled by default to protect the user's privacy, but it can easily be enabled in the settings. Once enabled, the API can be invoked by sending an explicit Intent to start an activity.
|
||||
|
||||
`Package` (depends on the variant installed):
|
||||
* F-Droid: `de.dennisguse.opentracks`
|
||||
@@ -121,9 +121,17 @@ The API can be invoked by sending an explicit Intent to start an activity.
|
||||
* **Stop a recording:** `de.dennisguse.opentracks.publicapi.StopRecording`
|
||||
* **Create a marker:** `de.dennisguse.opentracks.publicapi.CreateMarker`
|
||||
|
||||
For testing via adb: `adb shell am start -e someParameter someValue -n "package/class"`
|
||||
For testing the API using adb, the general command syntax is:
|
||||
|
||||
The Public API is disabled by default to protect the user's privacy, but it can easily be enabled in the settings.
|
||||
```shell
|
||||
adb shell am start -e someParameter someValue -n "package/class"
|
||||
```
|
||||
|
||||
Depending on the package and class, a complete command could look something like this:
|
||||
|
||||
```shell
|
||||
adb shell am start -n "de.dennisguse.opentracks.playstore/de.dennisguse.opentracks.publicapi.StartRecording"
|
||||
```
|
||||
|
||||
## File formats compatibility with open-source software
|
||||
| | [GPX 1.1](https://www.topografix.com/GPX/1/1/) | [KML 2.3](https://docs.opengeospatial.org/is/12-007r2/12-007r2.html) | [KMZ 2.3](https://docs.opengeospatial.org/is/12-007r2/12-007r2.html) |
|
||||
@@ -135,6 +143,7 @@ The Public API is disabled by default to protect the user's privacy, but it can
|
||||
| [FitTrackee](https://github.com/SamR1/FitTrackee) | yes | n/a | n/a |
|
||||
| [SportsTracker](https://github.com/ssaring/sportstracker) | yes, [single tracks only](https://github.com/ssaring/sportstracker/issues/260) | no | no |
|
||||
| [ExifTool](https://exiftool.org) | [yes](https://exiftool.org/forum/index.php?topic=15972.0) | no | no |
|
||||
| [Wanderer](https://wanderer.to/) | yes | yes | yes |
|
||||
|
||||
|
||||
## Dashboard API (incl. map)
|
||||
|
||||
+9
-9
@@ -6,7 +6,7 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.9.0'
|
||||
classpath 'com.android.tools.build:gradle:8.10.0'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ android {
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
compileSdk = 35
|
||||
compileSdk = 36
|
||||
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
@@ -46,13 +46,13 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
applicationId 'de.dennisguse.opentracks'
|
||||
versionCode 6102
|
||||
versionName "v4.19.0"
|
||||
versionCode 6130
|
||||
versionName "v4.19.3"
|
||||
|
||||
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
|
||||
|
||||
minSdk = 26
|
||||
targetSdk = 35
|
||||
targetSdk = 36
|
||||
|
||||
testInstrumentationRunner 'de.dennisguse.opentracks.TestRunner'
|
||||
testInstrumentationRunnerArguments clearPackageData: 'true'
|
||||
@@ -144,11 +144,11 @@ dependencies {
|
||||
|
||||
implementation 'androidx.appcompat:appcompat:1.7.0'
|
||||
implementation 'androidx.preference:preference:1.2.1'
|
||||
implementation 'androidx.documentfile:documentfile:1.0.1'
|
||||
implementation 'androidx.gridlayout:gridlayout:1.0.0'
|
||||
implementation 'androidx.documentfile:documentfile:1.1.0'
|
||||
implementation 'androidx.gridlayout:gridlayout:1.1.0'
|
||||
implementation 'com.google.android.material:material:1.12.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.2.1'
|
||||
implementation 'androidx.core:core:1.15.0'
|
||||
implementation 'androidx.core:core:1.16.0'
|
||||
implementation 'androidx.core:core-splashscreen:1.0.1'
|
||||
implementation 'androidx.mediarouter:mediarouter:1.7.0'
|
||||
implementation 'androidx.core:core-location-altitude:1.0.0-alpha03'
|
||||
@@ -158,7 +158,7 @@ dependencies {
|
||||
androidTestImplementation 'androidx.test:rules:1.6.1'
|
||||
androidTestImplementation 'androidx.test:runner:1.6.2'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
|
||||
androidTestImplementation 'org.mockito:mockito-android:5.16.0'
|
||||
androidTestImplementation 'org.mockito:mockito-android:5.18.0'
|
||||
|
||||
androidTestUtil 'androidx.test:orchestrator:1.5.1'
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
v4.18.0: OpenTracks
|
||||
|
||||
Změny:
|
||||
- Varování o zakázané poloze lze vypnout
|
||||
|
||||
Oprava chyby:
|
||||
- BottomAppBar překrýval obsah
|
||||
|
||||
Vývojář:
|
||||
- Použití zaznamenané pozice namísto polohy systému Android
|
||||
- Předělány agregátory senzorů
|
||||
@@ -0,0 +1,4 @@
|
||||
v4.19.1: OpenTracks
|
||||
|
||||
Bugfix:
|
||||
- Exported GPX files missed one schemaLocation
|
||||
@@ -0,0 +1,5 @@
|
||||
v4.19.2: OpenTracks
|
||||
|
||||
Bugfix:
|
||||
- Fix crash due to faulty translations
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
v4.19.3: OpenTracks
|
||||
|
||||
Bugfix:
|
||||
- Fix CSV export for altitude (was cut at 1000m)
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
v4.18.0: OpenTracks
|
||||
|
||||
Athruithe:
|
||||
- Is féidir rabhadh faoi mhíchumas GPS a dhíchumasú
|
||||
|
||||
Ceartúchán Bug:
|
||||
- Ábhar forluiteach BottomAppBar
|
||||
|
||||
Forbróir:
|
||||
- Úsáid taifead Seasamh in ionad Android suíomh
|
||||
- Comhbhailitheoirí braite athfhachtóirithe
|
||||
@@ -0,0 +1,11 @@
|
||||
v4.18.0: OpenTracks
|
||||
|
||||
Wijzigingen:
|
||||
- GPS uitgeschakeld waarschuwing kan worden uitgeschakeld
|
||||
|
||||
Bugfix:
|
||||
- BottomAppBar overlapte inhoud
|
||||
|
||||
Ontwikkelaar:
|
||||
- Gebruik recordpositie in plaats van Android-locatie
|
||||
- Gerefactoreerde sensor-aggregators
|
||||
@@ -0,0 +1,11 @@
|
||||
v4.18.0: OpenTracks
|
||||
|
||||
更改:
|
||||
- GPS 禁用警告可被禁用
|
||||
|
||||
错误修复:
|
||||
- BottomAppBar 重叠内容
|
||||
|
||||
开发相关:
|
||||
- 使用记录位置代替 Android 位置
|
||||
- 重构了传感器聚合器
|
||||
+67
-44
@@ -18,6 +18,7 @@ import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.rule.GrantPermissionRule;
|
||||
import androidx.test.rule.ServiceTestRule;
|
||||
|
||||
import org.junit.After;
|
||||
@@ -45,6 +46,7 @@ import java.util.concurrent.TimeoutException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import de.dennisguse.opentracks.R;
|
||||
import de.dennisguse.opentracks.TestUtil;
|
||||
import de.dennisguse.opentracks.TimezoneRule;
|
||||
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||
@@ -87,6 +89,9 @@ public class ExportImportTest {
|
||||
@Rule
|
||||
public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(5, TimeUnit.SECONDS);
|
||||
|
||||
@Rule
|
||||
public GrantPermissionRule mGrantPermissionRule = TestUtil.createGrantPermissionRule();
|
||||
|
||||
//For csv_export_only() as we the timezone is hardcoded in the expectation.
|
||||
@Rule
|
||||
public TimezoneRule timezoneRule = new TimezoneRule(TimeZone.getTimeZone("Europe/Berlin"));
|
||||
@@ -144,7 +149,7 @@ public class ExportImportTest {
|
||||
|
||||
Distance sensorDistance = Distance.of(10); // recording distance interval
|
||||
|
||||
sendLocation(trackPointCreator, "2020-02-02T02:02:03Z", 3, 14, 10, 13, 15, 10, 1f);
|
||||
sendLocation(trackPointCreator, "2020-02-02T02:02:03Z", 3.1234567, 14.0014567, 10, 13, 15, 1020.25, 1f);
|
||||
contentProviderUtils.insertMarker(new Marker(trackId, service.getLastStoredTrackPointWithLocation(), "Marker 1", "Marker 1 desc", "Marker 1 category", null, null));
|
||||
|
||||
// A sensor-only TrackPoint
|
||||
@@ -155,11 +160,10 @@ public class ExportImportTest {
|
||||
mockSensorData(trackPointCreator, 15f, null, 67f, 3f, 50f, null);
|
||||
trackPointCreator.setClock("2020-02-02T02:02:15Z");
|
||||
mockSensorData(trackPointCreator, null, null, 68f, 3f, 50f, null);
|
||||
|
||||
trackPointCreator.setClock("2020-02-02T02:02:16Z");
|
||||
mockSensorData(trackPointCreator, 5f, Distance.of(2), 69f, 3f, 50f, null); // Distance will be added to next TrackPoint
|
||||
|
||||
sendLocation(trackPointCreator, "2020-02-02T02:02:17Z", 3, 14.001, 10, 13, 15, 10, 0f);
|
||||
sendLocation(trackPointCreator, "2020-02-02T02:02:17Z", 3.1234567, 14.0014567, 10, 13, 15, 1020.25, 0f);
|
||||
contentProviderUtils.insertMarker(new Marker(trackId, service.getLastStoredTrackPointWithLocation(), "Marker 2", "Marker 2 desc", "Marker 2 category", null, null));
|
||||
|
||||
trackPointCreator.setClock("2020-02-02T02:02:18Z");
|
||||
@@ -169,14 +173,14 @@ public class ExportImportTest {
|
||||
trackPointCreator.setClock("2020-02-02T02:03:20Z");
|
||||
service.resumeTrack(trackId);
|
||||
|
||||
sendLocation(trackPointCreator, "2020-02-02T02:03:21Z", 3, 14.002, 10, 13, 15, 10, 0f);
|
||||
sendLocation(trackPointCreator, "2020-02-02T02:03:21Z", 3.1234567, 14.0024567, 10, 13, 15, 999.123, 0f);
|
||||
|
||||
sendLocation(trackPointCreator, "2020-02-02T02:03:22Z", 3, 16, 10, 13, 15, 10, 0f);
|
||||
sendLocation(trackPointCreator, "2020-02-02T02:03:22Z", 3.1234567, 16, 10, 13, 15, 999.123, 0f);
|
||||
|
||||
trackPointCreator.setClock("2020-02-02T02:03:30Z");
|
||||
service.getTrackRecordingManager().onIdle();
|
||||
|
||||
sendLocation(trackPointCreator, "2020-02-02T02:03:50Z", 3, 16.001, 10, 27, 15, 10, 0f);
|
||||
sendLocation(trackPointCreator, "2020-02-02T02:03:50Z", 3.1234567, 16.001, 10, 27, 15, 999.123, 0f);
|
||||
|
||||
trackPointCreator.getSensorManager().sensorDataSet = new SensorDataSet(trackPointCreator);
|
||||
trackPointCreator.setClock("2020-02-02T02:04:00Z");
|
||||
@@ -209,16 +213,16 @@ public class ExportImportTest {
|
||||
assertEquals(Duration.ofSeconds(26), trackStatistics.getMovingTime()); //TODO Likely too low
|
||||
|
||||
// Distance
|
||||
assertEquals(222125.53125, trackStatistics.getTotalDistance().toM(), 0.01); //TODO Too low
|
||||
assertEquals(222049.34375, trackStatistics.getTotalDistance().toM(), 0.01); //TODO Too low
|
||||
|
||||
// Speed
|
||||
assertEquals(8543.29, trackStatistics.getMaxSpeed().toMPS(), 0.01);
|
||||
assertEquals(3966.52, trackStatistics.getAverageSpeed().toMPS(), 0.01);
|
||||
assertEquals(8543.28, trackStatistics.getAverageMovingSpeed().toMPS(), 0.01);
|
||||
assertEquals(8540.359, trackStatistics.getMaxSpeed().toMPS(), 0.01);
|
||||
assertEquals(3965.166, trackStatistics.getAverageSpeed().toMPS(), 0.01);
|
||||
assertEquals(8540.359, trackStatistics.getAverageMovingSpeed().toMPS(), 0.01);
|
||||
|
||||
// Altitude
|
||||
assertEquals(10, trackStatistics.getMinAltitude(), 0.01);
|
||||
assertEquals(10, trackStatistics.getMaxAltitude(), 0.01);
|
||||
assertEquals(999.122, trackStatistics.getMinAltitude(), 0.01);
|
||||
assertEquals(1020.25, trackStatistics.getMaxAltitude(), 0.01);
|
||||
|
||||
assertEquals(2, trackStatistics.getTotalAltitudeGain(), 0.01);
|
||||
assertEquals(2, trackStatistics.getTotalAltitudeLoss(), 0.01);
|
||||
@@ -229,8 +233,8 @@ public class ExportImportTest {
|
||||
new TrackPoint(TrackPoint.Type.TRACKPOINT,
|
||||
new Position(
|
||||
Instant.parse("2020-02-02T02:02:03Z"),
|
||||
3d, 14d, Distance.of(10),
|
||||
Altitude.WGS84.of(10), null,
|
||||
3.123456, 14.001456, Distance.of(10),
|
||||
Altitude.WGS84.of(1020.25), null,
|
||||
null,
|
||||
Speed.of(15)))
|
||||
.setAltitudeLoss(1f)
|
||||
@@ -251,8 +255,8 @@ public class ExportImportTest {
|
||||
new TrackPoint(TrackPoint.Type.TRACKPOINT,
|
||||
new Position(
|
||||
Instant.parse("2020-02-02T02:02:17Z"),
|
||||
3d, 14.001, Distance.of(10),
|
||||
Altitude.WGS84.of(10), null,
|
||||
3.123456, 14.001456, Distance.of(10),
|
||||
Altitude.WGS84.of(1020.25), null,
|
||||
null,
|
||||
Speed.of(5)))
|
||||
.setSensorDistance(Distance.of(2))
|
||||
@@ -266,16 +270,16 @@ public class ExportImportTest {
|
||||
new TrackPoint(TrackPoint.Type.TRACKPOINT,
|
||||
new Position(
|
||||
Instant.parse("2020-02-02T02:03:21Z"),
|
||||
3d, 14.002d, Distance.of(10),
|
||||
Altitude.WGS84.of(10), null,
|
||||
3.123456, 14.002456, Distance.of(10),
|
||||
Altitude.WGS84.of(999.1229858398438), null,
|
||||
null,
|
||||
Speed.of(15)))
|
||||
.setAltitudeLoss(0f)
|
||||
.setAltitudeGain(0f),
|
||||
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC,
|
||||
new Position(Instant.parse("2020-02-02T02:03:22Z"),
|
||||
3d, 16d, Distance.of(10),
|
||||
Altitude.WGS84.of(10), null,
|
||||
3.123456, 16d, Distance.of(10),
|
||||
Altitude.WGS84.of(999.1229858398438), null,
|
||||
null,
|
||||
Speed.of(15)))
|
||||
.setAltitudeLoss(0f)
|
||||
@@ -286,8 +290,8 @@ public class ExportImportTest {
|
||||
new TrackPoint(TrackPoint.Type.TRACKPOINT,
|
||||
new Position(
|
||||
Instant.parse("2020-02-02T02:03:50Z"),
|
||||
3d, 16.001, Distance.of(10),
|
||||
Altitude.WGS84.of(10), null,
|
||||
3.123456, 16.001, Distance.of(10),
|
||||
Altitude.WGS84.of(999.1229858398438), null,
|
||||
null, Speed.of(15)))
|
||||
.setAltitudeLoss(0f)
|
||||
.setAltitudeGain(0f),
|
||||
@@ -312,7 +316,7 @@ public class ExportImportTest {
|
||||
contentProviderUtils.deleteTrack(context, trackId);
|
||||
|
||||
// 2. import
|
||||
KmzTrackImporter importer = new KmzTrackImporter(context, trackImporter);
|
||||
KMZTrackImporter importer = new KMZTrackImporter(context, trackImporter);
|
||||
importTrackId = importer.importFile(tmpFileUri).get(0);
|
||||
|
||||
// then
|
||||
@@ -334,7 +338,26 @@ public class ExportImportTest {
|
||||
|
||||
// Time
|
||||
assertEquals(track.getZoneOffset(), importedTrack.getZoneOffset());
|
||||
assertEquals(track.getTrackStatistics(), importedTrackStatistics);
|
||||
assertEquals(Instant.parse("2020-02-02T02:02:02Z"), importedTrackStatistics.getStartTime());
|
||||
assertEquals(Instant.parse("2020-02-02T02:04:00Z"), importedTrackStatistics.getStopTime());
|
||||
|
||||
assertEquals(Duration.ofSeconds(56), importedTrackStatistics.getTotalTime());
|
||||
assertEquals(Duration.ofSeconds(26), importedTrackStatistics.getMovingTime());
|
||||
|
||||
// Distance
|
||||
assertEquals(222049.421, importedTrackStatistics.getTotalDistance().toM(), 0.01);
|
||||
|
||||
// Speed
|
||||
assertEquals(8540.362, importedTrackStatistics.getMaxSpeed().toMPS(), 0.01);
|
||||
assertEquals(3965.168, importedTrackStatistics.getAverageSpeed().toMPS(), 0.01);
|
||||
assertEquals(8540.362, importedTrackStatistics.getAverageMovingSpeed().toMPS(), 0.01);
|
||||
|
||||
// Altitude
|
||||
assertEquals(999.122, importedTrackStatistics.getMinAltitude(), 0.01);
|
||||
assertEquals(1020.25, importedTrackStatistics.getMaxAltitude(), 0.01);
|
||||
assertEquals(2, importedTrackStatistics.getTotalAltitudeGain(), 0.01);
|
||||
assertEquals(2, importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
|
||||
|
||||
|
||||
// 4. markers
|
||||
assertMarkers();
|
||||
@@ -358,7 +381,7 @@ public class ExportImportTest {
|
||||
|
||||
// 2. import
|
||||
InputStream inputStream = context.getContentResolver().openInputStream(tmpFileUri);
|
||||
XMLImporter importer = new XMLImporter(new KmlTrackImporter(context, trackImporter));
|
||||
XMLImporter importer = new XMLImporter(new KMLTrackImporter(context, trackImporter));
|
||||
importTrackId = importer.importFile(inputStream).get(0);
|
||||
|
||||
// then
|
||||
@@ -383,7 +406,7 @@ public class ExportImportTest {
|
||||
|
||||
// 2. import
|
||||
InputStream inputStream = context.getContentResolver().openInputStream(tmpFileUri);
|
||||
XMLImporter importer = new XMLImporter(new GpxTrackImporter(context, trackImporter));
|
||||
XMLImporter importer = new XMLImporter(new GPXTrackImporter(context, trackImporter));
|
||||
importTrackId = importer.importFile(inputStream).get(0);
|
||||
|
||||
// then
|
||||
@@ -406,8 +429,8 @@ public class ExportImportTest {
|
||||
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC,
|
||||
new Position(
|
||||
Instant.parse("2020-02-02T02:02:03Z"),
|
||||
3d, 14d, Distance.of(10),
|
||||
Altitude.WGS84.of(10), null,
|
||||
3.123456, 14.001456d, Distance.of(10),
|
||||
Altitude.WGS84.of(1020.2), null,
|
||||
null,
|
||||
Speed.of(15)))
|
||||
.setAltitudeLoss(1f)
|
||||
@@ -415,8 +438,8 @@ public class ExportImportTest {
|
||||
new TrackPoint(TrackPoint.Type.TRACKPOINT,
|
||||
new Position(
|
||||
Instant.parse("2020-02-02T02:02:17Z"),
|
||||
3d, 14.001, Distance.of(10),
|
||||
Altitude.WGS84.of(10), null,
|
||||
3.123456, 14.001456, Distance.of(10),
|
||||
Altitude.WGS84.of(1020.2), null,
|
||||
null,
|
||||
Speed.of(5)))
|
||||
.setAltitudeLoss(1f)
|
||||
@@ -428,8 +451,8 @@ public class ExportImportTest {
|
||||
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC,
|
||||
new Position(
|
||||
Instant.parse("2020-02-02T02:03:21Z"),
|
||||
3d, 14.002, Distance.of(10),
|
||||
Altitude.WGS84.of(10), null,
|
||||
3.123456, 14.002456, Distance.of(10),
|
||||
Altitude.WGS84.of(999.0999755859375), null,
|
||||
null,
|
||||
Speed.of(15)))
|
||||
.setAltitudeLoss(0f)
|
||||
@@ -437,8 +460,8 @@ public class ExportImportTest {
|
||||
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC,
|
||||
new Position(
|
||||
Instant.parse("2020-02-02T02:03:22Z"),
|
||||
3d, 16d, Distance.of(10),
|
||||
Altitude.WGS84.of(10), null,
|
||||
3.123456, 16d, Distance.of(10),
|
||||
Altitude.WGS84.of(999.0999755859375), null,
|
||||
null,
|
||||
Speed.of(15)))
|
||||
.setAltitudeLoss(0f)
|
||||
@@ -446,8 +469,8 @@ public class ExportImportTest {
|
||||
new TrackPoint(TrackPoint.Type.TRACKPOINT,
|
||||
new Position(
|
||||
Instant.parse("2020-02-02T02:03:50Z"),
|
||||
3d, 16.001, Distance.of(10),
|
||||
Altitude.WGS84.of(10), null,
|
||||
3.123456, 16.001, Distance.of(10),
|
||||
Altitude.WGS84.of(999.0999755859375), null,
|
||||
null,
|
||||
Speed.of(10)))
|
||||
.setAltitudeLoss(0f)
|
||||
@@ -467,16 +490,16 @@ public class ExportImportTest {
|
||||
assertEquals(Duration.ofSeconds(107), importedTrackStatistics.getMovingTime());
|
||||
|
||||
// Distance
|
||||
assertEquals(222347.85, importedTrackStatistics.getTotalDistance().toM(), 0.01);
|
||||
assertEquals(222271.734, importedTrackStatistics.getTotalDistance().toM(), 0.01);
|
||||
|
||||
// Speed
|
||||
assertEquals(2078.01, importedTrackStatistics.getMaxSpeed().toMPS(), 0.01);
|
||||
assertEquals(2078.01, importedTrackStatistics.getAverageSpeed().toMPS(), 0.01);
|
||||
assertEquals(2078.01, importedTrackStatistics.getAverageMovingSpeed().toMPS(), 0.01);
|
||||
assertEquals(2077.305, importedTrackStatistics.getMaxSpeed().toMPS(), 0.01);
|
||||
assertEquals(2077.305, importedTrackStatistics.getAverageSpeed().toMPS(), 0.01);
|
||||
assertEquals(2077.305, importedTrackStatistics.getAverageMovingSpeed().toMPS(), 0.01);
|
||||
|
||||
// Altitude
|
||||
assertEquals(10, importedTrackStatistics.getMinAltitude(), 0.01);
|
||||
assertEquals(10, importedTrackStatistics.getMaxAltitude(), 0.01);
|
||||
assertEquals(999.099, importedTrackStatistics.getMinAltitude(), 0.01);
|
||||
assertEquals(1020.2, importedTrackStatistics.getMaxAltitude(), 0.01);
|
||||
assertEquals(2, importedTrackStatistics.getTotalAltitudeGain(), 0.01);
|
||||
assertEquals(2, importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
|
||||
|
||||
@@ -503,7 +526,7 @@ public class ExportImportTest {
|
||||
|
||||
// 2. import
|
||||
InputStream inputStream = context.getContentResolver().openInputStream(tmpFileUri);
|
||||
XMLImporter importer = new XMLImporter(new GpxTrackImporter(context, trackImporter));
|
||||
XMLImporter importer = new XMLImporter(new GPXTrackImporter(context, trackImporter));
|
||||
importTrackId = importer.importFile(inputStream).get(0);
|
||||
|
||||
// then
|
||||
@@ -614,7 +637,7 @@ public class ExportImportTest {
|
||||
}
|
||||
}
|
||||
|
||||
private void sendLocation(TrackPointCreator trackPointCreator, String time, double latitude, double longitude, float accuracy, float verticalAccuracy, float speed, float altitude, Float altitudeGain) {
|
||||
private void sendLocation(TrackPointCreator trackPointCreator, String time, double latitude, double longitude, float accuracy, float verticalAccuracy, float speed, double altitude, Float altitudeGain) {
|
||||
Location location = new Location("mock");
|
||||
location.setLatitude(latitude);
|
||||
location.setLongitude(longitude);
|
||||
|
||||
+5
-5
@@ -68,7 +68,7 @@ public class GPXTrackImporterTest {
|
||||
@Test
|
||||
public void gpx_with_pause_resume() throws IOException {
|
||||
// given
|
||||
XMLImporter importer = new XMLImporter(new GpxTrackImporter(context, trackImporter));
|
||||
XMLImporter importer = new XMLImporter(new GPXTrackImporter(context, trackImporter));
|
||||
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.legacy_gpx_pause_resume);
|
||||
|
||||
// when
|
||||
@@ -132,7 +132,7 @@ public class GPXTrackImporterTest {
|
||||
@Test
|
||||
public void gpx_without_speed() throws IOException {
|
||||
// given
|
||||
XMLImporter importer = new XMLImporter(new GpxTrackImporter(context, trackImporter));
|
||||
XMLImporter importer = new XMLImporter(new GPXTrackImporter(context, trackImporter));
|
||||
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.gpx11_without_speed);
|
||||
|
||||
// when
|
||||
@@ -187,7 +187,7 @@ public class GPXTrackImporterTest {
|
||||
@Test
|
||||
public void gpx_speed_no_namespace() throws IOException {
|
||||
// given
|
||||
XMLImporter importer = new XMLImporter(new GpxTrackImporter(context, trackImporter));
|
||||
XMLImporter importer = new XMLImporter(new GPXTrackImporter(context, trackImporter));
|
||||
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.gpx11_with_speed_no_namespace);
|
||||
|
||||
// when
|
||||
@@ -246,7 +246,7 @@ public class GPXTrackImporterTest {
|
||||
@Test
|
||||
public void gpx_legacy_trackpointextension() throws IOException {
|
||||
// given
|
||||
XMLImporter importer = new XMLImporter(new GpxTrackImporter(context, trackImporter));
|
||||
XMLImporter importer = new XMLImporter(new GPXTrackImporter(context, trackImporter));
|
||||
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.legacy_gpx_trackpointextensions_incorrect);
|
||||
|
||||
// when
|
||||
@@ -317,7 +317,7 @@ public class GPXTrackImporterTest {
|
||||
@Test
|
||||
public void importExportTest_timezone() throws IOException {
|
||||
// given
|
||||
XMLImporter importer = new XMLImporter(new GpxTrackImporter(context, trackImporter));
|
||||
XMLImporter importer = new XMLImporter(new GPXTrackImporter(context, trackImporter));
|
||||
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.gpx_timezone);
|
||||
InputStream inputStreamExpected = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.gpx_timezone);
|
||||
|
||||
|
||||
+5
-5
@@ -62,7 +62,7 @@ public class KMLTrackImporterTest {
|
||||
@Test
|
||||
public void kml22_order_location_and_when() throws IOException {
|
||||
// given
|
||||
XMLImporter importer = new XMLImporter(new KmlTrackImporter(context, trackImporter));
|
||||
XMLImporter importer = new XMLImporter(new KMLTrackImporter(context, trackImporter));
|
||||
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.kml22_order_location_and_when);
|
||||
|
||||
// when
|
||||
@@ -118,7 +118,7 @@ public class KMLTrackImporterTest {
|
||||
@Test
|
||||
public void kml22_time_decreases() throws IOException {
|
||||
// given
|
||||
XMLImporter importer = new XMLImporter(new KmlTrackImporter(context, trackImporter));
|
||||
XMLImporter importer = new XMLImporter(new KMLTrackImporter(context, trackImporter));
|
||||
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.kml22_time_decreases);
|
||||
|
||||
// when
|
||||
@@ -159,7 +159,7 @@ public class KMLTrackImporterTest {
|
||||
@Test
|
||||
public void kml22_with_statistics_marker() throws IOException {
|
||||
// given
|
||||
XMLImporter importer = new XMLImporter(new KmlTrackImporter(context, trackImporter));
|
||||
XMLImporter importer = new XMLImporter(new KMLTrackImporter(context, trackImporter));
|
||||
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.legacy_kml22_statistics_marker);
|
||||
|
||||
// when
|
||||
@@ -243,7 +243,7 @@ public class KMLTrackImporterTest {
|
||||
@Test(expected = ImportParserException.class)
|
||||
public void kml_without_locations() throws IOException {
|
||||
// given
|
||||
XMLImporter importer = new XMLImporter(new KmlTrackImporter(context, trackImporter));
|
||||
XMLImporter importer = new XMLImporter(new KMLTrackImporter(context, trackImporter));
|
||||
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.kml22_without_locations);
|
||||
|
||||
// when
|
||||
@@ -254,7 +254,7 @@ public class KMLTrackImporterTest {
|
||||
@Test(expected = ImportParserException.class)
|
||||
public void kml_when_locations_different() throws IOException {
|
||||
// given
|
||||
XMLImporter importer = new XMLImporter(new KmlTrackImporter(context, trackImporter));
|
||||
XMLImporter importer = new XMLImporter(new KMLTrackImporter(context, trackImporter));
|
||||
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.kml22_when_locations_different);
|
||||
|
||||
// when
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#time,trackpoint_type,latitude,longitude,altitude,accuracy_horizontal,accuracy_vertical,speed,altitude_gain,altitude_loss,sensor_distance,heartrate,cadence,power
|
||||
"2020-02-02T03:02:02+01:00","SEGMENT_START_MANUAL",,,,,,,,,,,,
|
||||
"2020-02-02T03:02:03+01:00","TRACKPOINT",3,14,10,10,,54,1,1,,,,
|
||||
"2020-02-02T03:02:03+01:00","TRACKPOINT",3.123456,14.001456,1020.2,10,,54,1,1,,,,
|
||||
"2020-02-02T03:02:04+01:00","TRACKPOINT",,,,,,54,1,1,10,66,3,50
|
||||
"2020-02-02T03:02:15+01:00","TRACKPOINT",,,,,,,,,,68,3,50
|
||||
"2020-02-02T03:02:17+01:00","TRACKPOINT",3,14.001,10,10,,18,0,0,2,69,3,50
|
||||
"2020-02-02T03:02:17+01:00","TRACKPOINT",3.123456,14.001456,1020.2,10,,18,0,0,2,69,3,50
|
||||
"2020-02-02T03:02:18+01:00","SEGMENT_END_MANUAL",,,,,,,,,,,,
|
||||
"2020-02-02T03:03:20+01:00","SEGMENT_START_MANUAL",,,,,,,,,,,,
|
||||
"2020-02-02T03:03:21+01:00","TRACKPOINT",3,14.002,10,10,,54,0,0,,,,
|
||||
"2020-02-02T03:03:22+01:00","SEGMENT_START_AUTOMATIC",3,16,10,10,,54,0,0,,,,
|
||||
"2020-02-02T03:03:21+01:00","TRACKPOINT",3.123456,14.002456,999.1,10,,54,0,0,,,,
|
||||
"2020-02-02T03:03:22+01:00","SEGMENT_START_AUTOMATIC",3.123456,16,999.1,10,,54,0,0,,,,
|
||||
"2020-02-02T03:03:30+01:00","IDLE",,,,,,,0,0,,,,
|
||||
"2020-02-02T03:03:50+01:00","TRACKPOINT",3,16.001,10,10,,54,0,0,,,,
|
||||
"2020-02-02T03:03:50+01:00","TRACKPOINT",3.123456,16.001,999.1,10,,54,0,0,,,,
|
||||
"2020-02-02T03:04:00+01:00","SEGMENT_END_MANUAL",,,,,,,,,,,,
|
||||
|
@@ -10,7 +10,7 @@ xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v2"
|
||||
xmlns:gpxtrkx="http://www.garmin.com/xmlschemas/TrackStatsExtension/v1"
|
||||
xmlns:cluetrust="http://www.cluetrust.com/Schemas/"
|
||||
xmlns:pwr="http://www.garmin.com/xmlschemas/PowerExtension/v1"
|
||||
xsi:schemaLocation="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.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://www.garmin.com/xmlschemas/TrackStatsExtension/v1 http://www.cluetrust.com/Schemas https://www.cluetrust.com/Schemas/gpxdata10.xsd http://opentracksapp.com/xmlschemas/v1 http://opentracksapp.com/xmlschemas/OpenTracks_v1.xsd">
|
||||
xsi:schemaLocation="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.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://www.garmin.com/xmlschemas/TrackStatsExtension/v1 https://www8.garmin.com/xmlschemas/TrackStatsExtension.xsd http://www.cluetrust.com/Schemas https://www.cluetrust.com/Schemas/gpxdata10.xsd http://opentracksapp.com/xmlschemas/v1 http://opentracksapp.com/xmlschemas/OpenTracks_v1.xsd">
|
||||
<wpt lat="3" lon="14">
|
||||
<ele>10</ele>
|
||||
<time>2021-01-07T21:51:59.179+01:15</time>
|
||||
|
||||
@@ -15,7 +15,7 @@ import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||
import de.dennisguse.opentracks.io.file.exporter.CSVTrackExporter;
|
||||
import de.dennisguse.opentracks.io.file.exporter.GPXTrackExporter;
|
||||
import de.dennisguse.opentracks.io.file.exporter.KMLTrackExporter;
|
||||
import de.dennisguse.opentracks.io.file.exporter.KmzTrackExporter;
|
||||
import de.dennisguse.opentracks.io.file.exporter.KMZTrackExporter;
|
||||
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
|
||||
|
||||
/**
|
||||
@@ -33,7 +33,7 @@ public enum TrackFileFormat {
|
||||
|
||||
@Override
|
||||
public String getMimeType() {
|
||||
return MIME_KML;
|
||||
return "application/vnd.google-earth.kml+xml";
|
||||
}
|
||||
|
||||
public String getExtension() {
|
||||
@@ -49,12 +49,12 @@ public enum TrackFileFormat {
|
||||
@Override
|
||||
public TrackExporter createTrackExporter(@NonNull Context context, @NonNull ContentProviderUtils contentProviderUtils) {
|
||||
KMLTrackExporter exporter = new KMLTrackExporter(context, contentProviderUtils, exportPhotos);
|
||||
return new KmzTrackExporter(context, contentProviderUtils, exporter, exportPhotos);
|
||||
return new KMZTrackExporter(context, contentProviderUtils, exporter, exportPhotos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMimeType() {
|
||||
return MIME_KMZ;
|
||||
return "application/vnd.google-earth.kmz";
|
||||
}
|
||||
|
||||
public String getExtension() {
|
||||
@@ -74,12 +74,12 @@ public enum TrackFileFormat {
|
||||
@Override
|
||||
public TrackExporter createTrackExporter(@NonNull Context context, @NonNull ContentProviderUtils contentProviderUtils) {
|
||||
KMLTrackExporter exporter = new KMLTrackExporter(context, contentProviderUtils, exportPhotos);
|
||||
return new KmzTrackExporter(context, contentProviderUtils, exporter, exportPhotos);
|
||||
return new KMZTrackExporter(context, contentProviderUtils, exporter, exportPhotos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMimeType() {
|
||||
return MIME_KMZ;
|
||||
return KMZ_WITH_TRACKDETAIL_AND_SENSORDATA.getMimeType();
|
||||
}
|
||||
|
||||
public String getExtension() {
|
||||
@@ -126,17 +126,13 @@ public enum TrackFileFormat {
|
||||
}
|
||||
};
|
||||
|
||||
private static final String MIME_KMZ = "application/vnd.google-earth.kmz";
|
||||
|
||||
private static final String MIME_KML = "application/vnd.google-earth.kml+xml";
|
||||
|
||||
private final String preferenceId;
|
||||
|
||||
TrackFileFormat(String preferenceId) {
|
||||
this.preferenceId = preferenceId;
|
||||
}
|
||||
|
||||
public static Map<String, String> toPreferenceIdLabelMap(final Resources resources, final TrackFileFormat ... trackFileFormats) {
|
||||
public static Map<String, String> toPreferenceIdLabelMap(final Resources resources, final TrackFileFormat... trackFileFormats) {
|
||||
Map<String, String> preferenceIdLabelMap = new LinkedHashMap<>(trackFileFormats.length);
|
||||
for (TrackFileFormat trackFileFormat : trackFileFormats) {
|
||||
String trackFileFormatUpperCase = trackFileFormat.getExtension().toUpperCase(Locale.US); //ASCII upper case
|
||||
|
||||
@@ -60,7 +60,6 @@ public class CSVTrackExporter implements TrackExporter {
|
||||
ALTITUDE_FORMAT.setGroupingUsed(false);
|
||||
|
||||
COORDINATE_FORMAT.setMaximumFractionDigits(6);
|
||||
COORDINATE_FORMAT.setMaximumIntegerDigits(3);
|
||||
COORDINATE_FORMAT.setGroupingUsed(false);
|
||||
|
||||
SPEED_FORMAT.setMaximumFractionDigits(2);
|
||||
@@ -94,17 +93,17 @@ public class CSVTrackExporter implements TrackExporter {
|
||||
new Column("trackpoint_type", t -> quote(t.getType().name())),
|
||||
new Column("latitude", t -> t.hasLocation() ? COORDINATE_FORMAT.format(t.getLatitude()) : ""),
|
||||
new Column("longitude", t -> t.hasLocation() ? COORDINATE_FORMAT.format(t.getLongitude()) : ""),
|
||||
new Column("altitude", t -> t.hasAltitude() ? COORDINATE_FORMAT.format(t.getAltitude().toM()) : ""),
|
||||
new Column("altitude", t -> t.hasAltitude() ? ALTITUDE_FORMAT.format(t.getAltitude().toM()) : ""),
|
||||
new Column("accuracy_horizontal", t -> t.hasHorizontalAccuracy() ? DISTANCE_FORMAT.format(t.getHorizontalAccuracy().toM()) : ""),
|
||||
new Column("accuracy_vertical", t -> t.hasVerticalAccuracy() ? DISTANCE_FORMAT.format(t.getVerticalAccuracy().toM()) : ""),
|
||||
|
||||
new Column("speed", t -> t.hasSpeed() ? SPEED_FORMAT.format(t.getSpeed().toKMH()) : ""),
|
||||
new Column("altitude_gain", t -> t.hasAltitudeGain() ? DISTANCE_FORMAT.format(t.getAltitudeGain()) : ""),
|
||||
new Column("altitude_loss", t -> t.hasAltitudeLoss() ? DISTANCE_FORMAT.format(t.getAltitudeLoss()) : ""),
|
||||
new Column("altitude_gain", t -> t.hasAltitudeGain() ? ALTITUDE_FORMAT.format(t.getAltitudeGain()) : ""),
|
||||
new Column("altitude_loss", t -> t.hasAltitudeLoss() ? ALTITUDE_FORMAT.format(t.getAltitudeLoss()) : ""),
|
||||
new Column("sensor_distance", t -> t.hasSensorDistance() ? DISTANCE_FORMAT.format(t.getSensorDistance().toM()) : ""),
|
||||
new Column("heartrate", t -> t.hasHeartRate() ? HEARTRATE_FORMAT.format(t.getHeartRate().getBPM()) : ""),
|
||||
new Column("cadence", t -> t.hasCadence() ? CADENCE_FORMAT.format(t.getCadence().getRPM()) : ""),
|
||||
new Column("power", t -> t.hasPower() ? ALTITUDE_FORMAT.format(t.getPower().getW()) : ""));
|
||||
new Column("power", t -> t.hasPower() ? POWER_FORMAT.format(t.getPower().getW()) : ""));
|
||||
|
||||
try {
|
||||
prepare(outputStream);
|
||||
@@ -136,7 +135,7 @@ public class CSVTrackExporter implements TrackExporter {
|
||||
while (trackPointIterator.hasNext()) {
|
||||
if (Thread.interrupted()) throw new InterruptedException();
|
||||
|
||||
writeTrackPoint(columns, trackPointIterator.next());
|
||||
writeTrackPoint(columns, trackPointIterator.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,6 @@ public class GPXTrackExporter implements TrackExporter {
|
||||
try {
|
||||
prepare(outputStream);
|
||||
writeHeader();
|
||||
|
||||
for (Track track : tracks) {
|
||||
writeMarkers(track);
|
||||
}
|
||||
@@ -200,17 +199,17 @@ public class GPXTrackExporter implements TrackExporter {
|
||||
}
|
||||
}
|
||||
|
||||
public void prepare(OutputStream outputStream) {
|
||||
private void prepare(OutputStream outputStream) {
|
||||
this.printWriter = new PrintWriter(outputStream);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
private void close() {
|
||||
printWriter.flush();
|
||||
printWriter = null;
|
||||
}
|
||||
|
||||
|
||||
public void writeHeader() {
|
||||
private void writeHeader() {
|
||||
printWriter.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
printWriter.println("<gpx");
|
||||
printWriter.println("version=\"1.1\"");
|
||||
@@ -228,12 +227,12 @@ public class GPXTrackExporter implements TrackExporter {
|
||||
+ " 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/PowerExtension/v1 https://www8.garmin.com/xmlschemas/PowerExtensionv1.xsd"
|
||||
+ " http://www.garmin.com/xmlschemas/TrackStatsExtension/v1"
|
||||
+ " http://www.garmin.com/xmlschemas/TrackStatsExtension/v1 https://www8.garmin.com/xmlschemas/TrackStatsExtension.xsd"
|
||||
+ " http://www.cluetrust.com/Schemas https://www.cluetrust.com/Schemas/gpxdata10.xsd"
|
||||
+ " http://opentracksapp.com/xmlschemas/v1 http://opentracksapp.com/xmlschemas/OpenTracks_v1.xsd\">");
|
||||
}
|
||||
|
||||
public void writeFooter() {
|
||||
private void writeFooter() {
|
||||
printWriter.println("</gpx>");
|
||||
}
|
||||
|
||||
@@ -253,7 +252,7 @@ public class GPXTrackExporter implements TrackExporter {
|
||||
}
|
||||
}
|
||||
|
||||
public void writeMarker(ZoneOffset zoneOffset, Marker marker) {
|
||||
private void writeMarker(ZoneOffset zoneOffset, Marker marker) {
|
||||
printWriter.println("<wpt " + formatLocation(marker.getLatitude(), marker.getLongitude()) + ">");
|
||||
if (marker.hasAltitude()) {
|
||||
printWriter.println("<ele>" + ALTITUDE_FORMAT.format(marker.getAltitude().toM()) + "</ele>");
|
||||
@@ -265,7 +264,7 @@ public class GPXTrackExporter implements TrackExporter {
|
||||
printWriter.println("</wpt>");
|
||||
}
|
||||
|
||||
public void writeBeginTrack(Track track) {
|
||||
private void writeBeginTrack(Track track) {
|
||||
printWriter.println("<trk>");
|
||||
printWriter.println("<name>" + StringUtils.formatCData(track.getName()) + "</name>");
|
||||
printWriter.println("<desc>" + StringUtils.formatCData(track.getDescription()) + "</desc>");
|
||||
@@ -297,19 +296,19 @@ public class GPXTrackExporter implements TrackExporter {
|
||||
printWriter.println("</extensions>");
|
||||
}
|
||||
|
||||
public void writeEndTrack() {
|
||||
private void writeEndTrack() {
|
||||
printWriter.println("</trk>");
|
||||
}
|
||||
|
||||
public void writeOpenSegment() {
|
||||
private void writeOpenSegment() {
|
||||
printWriter.println("<trkseg>");
|
||||
}
|
||||
|
||||
public void writeCloseSegment() {
|
||||
private void writeCloseSegment() {
|
||||
printWriter.println("</trkseg>");
|
||||
}
|
||||
|
||||
public Distance writeTrackPoint(ZoneOffset zoneOffset, TrackPoint trackPoint, List<TrackPoint> sensorPoints, Distance trackDistance) {
|
||||
private Distance writeTrackPoint(ZoneOffset zoneOffset, TrackPoint trackPoint, List<TrackPoint> sensorPoints, Distance trackDistance) {
|
||||
Distance cumulativeDistance;
|
||||
|
||||
printWriter.println("<trkpt " + formatLocation(trackPoint.getLatitude(), trackPoint.getLongitude()) + ">");
|
||||
|
||||
@@ -107,6 +107,7 @@ public class KMLTrackExporter implements TrackExporter {
|
||||
this.contentProviderUtils = contentProviderUtils;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean writeTrack(List<Track> tracks, @NonNull OutputStream outputStream) {
|
||||
try {
|
||||
prepare(outputStream);
|
||||
@@ -444,7 +445,7 @@ public class KMLTrackExporter implements TrackExporter {
|
||||
writeTypeLocalized(marker.getCategory());
|
||||
|
||||
if (exportPhotos) {
|
||||
printWriter.println("<Icon><href>" + KmzTrackExporter.buildKmzImageFilePath(marker) + "</href></Icon>");
|
||||
printWriter.println("<Icon><href>" + KMZTrackExporter.buildKmzImageFilePath(marker) + "</href></Icon>");
|
||||
}
|
||||
|
||||
printWriter.print("<ViewVolume>");
|
||||
|
||||
+3
-3
@@ -43,12 +43,12 @@ import de.dennisguse.opentracks.util.FileUtils;
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class KmzTrackExporter implements TrackExporter {
|
||||
public class KMZTrackExporter implements TrackExporter {
|
||||
|
||||
private static final String KMZ_IMAGES_DIR = "images";
|
||||
public static final String KMZ_KML_FILE = "doc.kml";
|
||||
|
||||
private static final String TAG = KmzTrackExporter.class.getSimpleName();
|
||||
private static final String TAG = KMZTrackExporter.class.getSimpleName();
|
||||
private static final int BUFFER_SIZE = 4096;
|
||||
|
||||
private final ContentProviderUtils contentProviderUtils;
|
||||
@@ -57,7 +57,7 @@ public class KmzTrackExporter implements TrackExporter {
|
||||
private final boolean exportPhotos;
|
||||
private final Context context;
|
||||
|
||||
public KmzTrackExporter(Context context, ContentProviderUtils contentProviderUtils, KMLTrackExporter trackExporter, boolean exportPhotos) {
|
||||
public KMZTrackExporter(Context context, ContentProviderUtils contentProviderUtils, KMLTrackExporter trackExporter, boolean exportPhotos) {
|
||||
this.context = context;
|
||||
this.contentProviderUtils = contentProviderUtils;
|
||||
this.fileTrackExporter = trackExporter;
|
||||
+3
-3
@@ -52,9 +52,9 @@ import de.dennisguse.opentracks.util.StringUtils;
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class GpxTrackImporter extends DefaultHandler implements XMLImporter.TrackParser {
|
||||
public class GPXTrackImporter extends DefaultHandler implements XMLImporter.TrackParser {
|
||||
|
||||
private static final String TAG = GpxTrackImporter.class.getSimpleName();
|
||||
private static final String TAG = GPXTrackImporter.class.getSimpleName();
|
||||
|
||||
private static final String TAG_DESCRIPTION = "desc";
|
||||
private static final String TAG_ALTITUDE = "ele";
|
||||
@@ -123,7 +123,7 @@ public class GpxTrackImporter extends DefaultHandler implements XMLImporter.Trac
|
||||
|
||||
private final TrackImporter trackImporter;
|
||||
|
||||
public GpxTrackImporter(Context context, TrackImporter trackImporter) {
|
||||
public GPXTrackImporter(Context context, TrackImporter trackImporter) {
|
||||
this.context = context;
|
||||
this.trackImporter = trackImporter;
|
||||
}
|
||||
@@ -54,17 +54,16 @@ public class ImportService extends JobIntentService {
|
||||
String fileExtension = FileUtils.getExtension(file);
|
||||
try {
|
||||
Distance maxRecordingDistance = PreferencesUtils.getMaxRecordingDistance();
|
||||
Distance recordingDistanceInterval = PreferencesUtils.getRecordingDistanceInterval();
|
||||
boolean preventReimport = PreferencesUtils.getPreventReimportTracks();
|
||||
|
||||
TrackImporter trackImporter = new TrackImporter(this, new ContentProviderUtils(this), maxRecordingDistance, preventReimport);
|
||||
|
||||
if (TrackFileFormat.GPX.getExtension().equals(fileExtension)) {
|
||||
trackIds.addAll(new XMLImporter(new GpxTrackImporter(this, trackImporter)).importFile(this, file.getUri()));
|
||||
trackIds.addAll(new XMLImporter(new GPXTrackImporter(this, trackImporter)).importFile(this, file.getUri()));
|
||||
} else if (TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA.getExtension().equals(fileExtension)) {
|
||||
trackIds.addAll(new XMLImporter(new KmlTrackImporter(this, trackImporter)).importFile(this, file.getUri()));
|
||||
trackIds.addAll(new XMLImporter(new KMLTrackImporter(this, trackImporter)).importFile(this, file.getUri()));
|
||||
} else if (TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA_AND_PICTURES.getExtension().equals(fileExtension)) {
|
||||
trackIds.addAll(new KmzTrackImporter(this, trackImporter).importFile(file.getUri()));
|
||||
trackIds.addAll(new KMZTrackImporter(this, trackImporter).importFile(file.getUri()));
|
||||
} else {
|
||||
Log.d(TAG, "Unsupported file format.");
|
||||
sendResult(ImportServiceResultReceiver.RESULT_CODE_ERROR, null, file, getString(R.string.import_unsupported_format));
|
||||
|
||||
+3
-3
@@ -47,9 +47,9 @@ import de.dennisguse.opentracks.util.StringUtils;
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class KmlTrackImporter extends DefaultHandler implements XMLImporter.TrackParser {
|
||||
public class KMLTrackImporter extends DefaultHandler implements XMLImporter.TrackParser {
|
||||
|
||||
private static final String TAG = KmlTrackImporter.class.getSimpleName();
|
||||
private static final String TAG = KMLTrackImporter.class.getSimpleName();
|
||||
|
||||
private static final String MARKER_STYLE = "#" + KMLTrackExporter.MARKER_STYLE;
|
||||
|
||||
@@ -128,7 +128,7 @@ public class KmlTrackImporter extends DefaultHandler implements XMLImporter.Trac
|
||||
|
||||
private final TrackImporter trackImporter;
|
||||
|
||||
public KmlTrackImporter(Context context, TrackImporter trackImporter) {
|
||||
public KMLTrackImporter(Context context, TrackImporter trackImporter) {
|
||||
this.context = context;
|
||||
this.trackImporter = trackImporter;
|
||||
}
|
||||
+4
-4
@@ -44,9 +44,9 @@ import de.dennisguse.opentracks.util.FileUtils;
|
||||
*
|
||||
* @author Jimmy Shih
|
||||
*/
|
||||
public class KmzTrackImporter {
|
||||
public class KMZTrackImporter {
|
||||
|
||||
private static final String TAG = KmzTrackImporter.class.getSimpleName();
|
||||
private static final String TAG = KMZTrackImporter.class.getSimpleName();
|
||||
|
||||
private static final String KML_FILE_EXTENSION = ".kml";
|
||||
|
||||
@@ -55,7 +55,7 @@ public class KmzTrackImporter {
|
||||
private final Context context;
|
||||
private final TrackImporter trackImporter;
|
||||
|
||||
public KmzTrackImporter(Context context, TrackImporter trackImporter) {
|
||||
public KMZTrackImporter(Context context, TrackImporter trackImporter) {
|
||||
this.context = context;
|
||||
this.trackImporter = trackImporter;
|
||||
}
|
||||
@@ -211,7 +211,7 @@ public class KmzTrackImporter {
|
||||
}
|
||||
|
||||
private List<Track.Id> parseKml(ZipInputStream zipInputStream) throws IOException {
|
||||
XMLImporter kmlFileTrackImporter = new XMLImporter(new KmlTrackImporter(context, trackImporter));
|
||||
XMLImporter kmlFileTrackImporter = new XMLImporter(new KMLTrackImporter(context, trackImporter));
|
||||
|
||||
InputStream nonClosableInputStream = new FilterInputStream(zipInputStream) {
|
||||
@Override
|
||||
@@ -233,7 +233,7 @@ public class TrackImporter {
|
||||
* @param externalPhotoUrl the file name
|
||||
*/
|
||||
private Uri getInternalPhotoUrl(@NonNull Track.Id trackId, @NonNull Uri externalPhotoUrl) {
|
||||
String importFileName = KmzTrackImporter.importNameForFilename(externalPhotoUrl.toString());
|
||||
String importFileName = KMZTrackImporter.importNameForFilename(externalPhotoUrl.toString());
|
||||
File file = MarkerUtils.buildInternalPhotoFile(context, trackId, Uri.parse(importFileName));
|
||||
if (file != null) {
|
||||
return FileUtils.getUriForFile(context, file);
|
||||
|
||||
@@ -47,7 +47,7 @@ public class XMLImporter {
|
||||
return parser.getImportTrackIds();
|
||||
} catch (SAXException | ParserConfigurationException | ParsingException e) {
|
||||
Log.e(TAG, "Unable to import file", e);
|
||||
if (parser.getImportTrackIds().size() > 0) {
|
||||
if (!parser.getImportTrackIds().isEmpty()) {
|
||||
parser.cleanImport();
|
||||
}
|
||||
throw new ImportParserException(e);
|
||||
|
||||
@@ -3,24 +3,14 @@
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/export_activity_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:title="@string/custom_layout_list_title" />
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<LinearLayout android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="60dp">
|
||||
android:paddingBottom="?attr/actionBarSize">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/rows_options_layout"
|
||||
@@ -50,16 +40,16 @@
|
||||
android:id="@+id/recycler_view_visible"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/recycler_view_not_visible" />
|
||||
app:layout_constraintBottom_toTopOf="@id/recycler_view_not_visible"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_view_not_visible"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/recycler_view_visible"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/recycler_view_visible" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
@@ -1,16 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/export_activity_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:title="@string/custom_layout_list_title" />
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<LinearLayout xmlns:tools="http://schemas.android.com/tools"
|
||||
android:paddingTop="?attr/actionBarSize"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="60dp">
|
||||
android:fitsSystemWindows="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/custom_layout_list_add_linear_layout"
|
||||
@@ -18,25 +30,24 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginBottom="50dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/custom_layout_list_input_layout"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
app:errorEnabled="true"
|
||||
android:layout_margin="16dp">
|
||||
android:layout_margin="16dp"
|
||||
app:errorEnabled="true">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/custom_layout_list_edit_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textCapSentences"
|
||||
android:hint="@string/custom_layout_list_edit_name"
|
||||
android:imeOptions="actionDone"
|
||||
android:hint="@string/custom_layout_list_edit_name" />
|
||||
android:inputType="textCapSentences" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
@@ -50,9 +61,9 @@
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/custom_layout_list_cancel_button"
|
||||
style="@style/Widget.Material3.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Widget.Material3.Button.TextButton"
|
||||
android:text="@android:string/cancel" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
|
||||
@@ -21,7 +21,6 @@ limitations under the License.
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="90dp"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
@@ -32,6 +31,7 @@ limitations under the License.
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/track_detail_activity_view_pager"
|
||||
android:layout_width="match_parent"
|
||||
android:paddingBottom="?attr/actionBarSize"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="90dp"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
@@ -20,6 +19,7 @@
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/track_recording_coordinator_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:paddingBottom="?attr/actionBarSize"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
|
||||
@@ -637,7 +637,7 @@ Meldet das GPS-Gerät ungenaue Daten (z.B. Standort, Geschwindigkeit, Höhe), ka
|
||||
<string name="settings_announcements_unit">Distanz/Geschwindigkeits Einheit</string>
|
||||
<string name="power_x_watt">Leistung {x, plural, =1 {1 Watt} other {# Watt} }</string>
|
||||
<string name="power">Leistung</string>
|
||||
<string name="voiceDistance">{n, plural, =1 {1 } anderes {{n,number,#.0}} }</string>
|
||||
<string name="voiceDistance">{n, plural, =1 {1 } other {{n,number,#.0}} }</string>
|
||||
<string name="settings_recording_min_sampling_interval_title">Abtastzeitintervall</string>
|
||||
<string name="voiceIdle">Untätig werden.</string>
|
||||
<string name="voice_announce_lap_power_key">StimmeAnkündigungLapPower</string>
|
||||
|
||||
@@ -657,11 +657,11 @@ Si le dispositif GPS signale des données inexactes (par exemple, la localisatio
|
||||
<string name="permission_recording_failed">OpenTracks a besoin de la permission d\'accéder à votre localisation ainsi qu\'aux appareils à proximité.</string>
|
||||
<string name="create_marker_error">Impossible de créer un marqueur. Veuillez réessayer.</string>
|
||||
<string name="power">Puissance</string>
|
||||
<string name="power_x_watt">Puissance {x, plural, =1 {1 watt} autres {# watt} }</string>
|
||||
<string name="power_x_watt">Puissance {x, plural, =1 {1 watt} other {# watt} }</string>
|
||||
<string name="settings_announcements_lap_power">Puissance par tour</string>
|
||||
<string name="activity_type_kickscooter">trottinette</string>
|
||||
<string name="voiceSpeed">{n, plural, =1 {1} autres {{n,number,#.0}} }</string>
|
||||
<string name="voiceDistance">{n, plural, =1 {1 } autres {{n,number,#.0}} }</string>
|
||||
<string name="voiceSpeed">{n, plural, =1 {1} other {{n,number,#.0}} }</string>
|
||||
<string name="voiceDistance">{n, plural, =1 {1 } other {{n,number,#.0}} }</string>
|
||||
<string name="settings_locale_system_default">Paramètres par défaut du système</string>
|
||||
<string name="settings_locale_title">Langue</string>
|
||||
<string name="stats_gain_loss">Gain et perte</string>
|
||||
|
||||
@@ -507,11 +507,11 @@
|
||||
<string name="settings_announcements_unit">Aonad faid/luas</string>
|
||||
<string name="value_internal_sensor">Braiteoir inmheánach</string>
|
||||
<string name="voiceIdle">Ag éirí díomhaoin.</string>
|
||||
<string name="voiceSecondsPlural">{n, iolra, =1 {1 soicind} eile {{ n,uimhir} soicind} }</string>
|
||||
<string name="voiceSpeedKilometersPerHourPlural">{n, iolra, =1 {1 chiliméadar in aghaidh na huaire} eile {{ n,uimhir, #.0} ciliméadar san uair} }</string>
|
||||
<string name="voiceSpeedMKnotsPlural">{n, iolra, =1 {1 snaidhm} eile {{ n,uimhir, #.0} snaidhm} }</string>
|
||||
<string name="voiceDistanceNauticalMilesPlural">{n, iolra, =1 {1 mhuirmhíle} eile {{ n,uimhir, #.0} muirmhíle} }</string>
|
||||
<string name="voiceDistance">{n, iolra, =1 {1 } eile {{ n,uimhir, #.0}} }</string>
|
||||
<string name="voiceSecondsPlural">{n, plural, =1 {1 soicind} other {{ n,number} soicind} }</string>
|
||||
<string name="voiceSpeedKilometersPerHourPlural">{n, plural, =1 {1 chiliméadar in aghaidh na huaire} other {{ n,number, #.0} ciliméadar san uair} }</string>
|
||||
<string name="voiceSpeedMKnotsPlural">{n, plural, =1 {1 snaidhm} other {{ n,number, #.0} snaidhm} }</string>
|
||||
<string name="voiceDistanceNauticalMilesPlural">{n, plural, =1 {1 mhuirmhíle} other {{ n,number, #.0} muirmhíle} }</string>
|
||||
<string name="voiceDistance">{n, plural, =1 {1 } other {{ n,number, #.0}} }</string>
|
||||
<string name="settings_recording_min_sampling_interval_title">Eatramh ama samplála</string>
|
||||
<string name="sensor_state_cadence_unit">rpm</string>
|
||||
<string name="sensor_state_heart_rate_unit">bpm</string>
|
||||
@@ -527,20 +527,20 @@
|
||||
<string name="settings_api_summary">Cianrialú agus staitisticí API le haghaidh aipeanna eile</string>
|
||||
<string name="create_marker_error">Ní féidir marcóir a chruthú. Déan iarracht arís.</string>
|
||||
<string name="sensor_state_power_unit">W</string>
|
||||
<string name="voiceMinutesPlural">{n, iolra, =1 {1 nóiméad} eile {{ n,uimhir} nóiméad} }</string>
|
||||
<string name="voiceDistanceKilometersPlural">{n, iolra, =1 {1 chiliméadar} eile {{ n,uimhir, #.0} ciliméadar} }</string>
|
||||
<string name="voiceMinutesPlural">{n, plural, =1 {1 nóiméad} other {{ n,number} nóiméad} }</string>
|
||||
<string name="voiceDistanceKilometersPlural">{n, plural, =1 {1 chiliméadar} other {{ n,number, #.0} ciliméadar} }</string>
|
||||
<string name="sensor_state_power_max">Cumhacht Max</string>
|
||||
<string name="bluetooth_sensor_summary">%1$s (%2$s)</string>
|
||||
<string name="voiceHoursPlural">{n, iolra, =1 {1 uair} eile {{ n,uimhir} uair an chloig} }</string>
|
||||
<string name="voiceDistanceMilesPlural">{n, iolra, =1 {1 mhíle} eile {{ n,uimhir, #.0} míle} }</string>
|
||||
<string name="voiceHoursPlural">{n, plural, =1 {1 uair} other {{ n,number} uair an chloig} }</string>
|
||||
<string name="voiceDistanceMilesPlural">{n, plural, =1 {1 mhíle} other {{ n,number, #.0} míle} }</string>
|
||||
<string name="no_compatible_camera_installed">Níl feidhmchlár ceamara comhoiriúnach suiteáilte</string>
|
||||
<string name="voiceSpeedMilesPerHourPlural">{n, iolra, =1 {1 mhíle san uair} eile {{ n,uimhir, #.0} míle san uair} }</string>
|
||||
<string name="voiceSpeed">{n, iolra, =1 {1} eile {{ n,uimhir, #.0}} }</string>
|
||||
<string name="voiceSpeedMilesPerHourPlural">{n, plural, =1 {1 mhíle san uair} other {{ n,number, #.0} míle san uair} }</string>
|
||||
<string name="voiceSpeed">{n, plural, =1 {1} other {{ n,number, #.0}} }</string>
|
||||
<string name="voice_on_device_speaker_title">Úsáid cainteoir an ghléis</string>
|
||||
<string name="no_compatible_gallery_installed">Níl feidhmchlár gailearaí íomhá comhoiriúnach suiteáilte</string>
|
||||
<string name="settings_recording_location_distance_summary">%1$s idir suíomhanna taifeadta</string>
|
||||
<string name="settings_announcements_lap_power">Cumhacht glúine</string>
|
||||
<string name="power_x_watt">Cumhacht {x, iolra, = 1 {1 vata} eile {# vata} }</string>
|
||||
<string name="power_x_watt">Cumhacht {x, plural, = 1 {1 vata} other {# vata} }</string>
|
||||
<string name="empty">" "</string>
|
||||
<string name="settings_locale_system_default">Réamhshocrú córais</string>
|
||||
<string name="settings_locale_title">Teanga</string>
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
<string name="settings_recording_location_distance_summary">பதிவுசெய்யப்பட்ட இடங்களுக்கு இடையில் %1$s</string>
|
||||
<string name="voice_announce_lap_power_key">VoiceAnnouncelappower</string>
|
||||
<string name="settings_announcements_lap_power">மடியில் ஆற்றல்</string>
|
||||
<string name="power_x_watt">ஆற்றல் {x, பன்மை, = 1 {1 watt} பிற {# வாட்ச்}}</string>
|
||||
<string name="power_x_watt">ஆற்றல் {x, plural, = 1 {1 watt} other {# வாட்ச்}}</string>
|
||||
<string name="power">விசை</string>
|
||||
<string name="help_feature_content">* சி.பி.எச் தடங்களை உருவாக்கவும்\n * இதய துடிப்பு சென்சார் பயன்படுத்தவும் (புளூடூத் லு மட்டும்)\n * குரல் அறிவிப்புகள் (நேரம் அல்லது தூரத்தின் அடிப்படையில்)\n * குறிப்பான்களை உருவாக்கு (படங்கள் உள்ளிட்டவை)\n * முற்றிலும் ஆஃப்லைனில் வேலை செய்கிறது\n * வரைபடத்தில் தடங்களைக் காண்பி (கீழே காண்க)</string>
|
||||
<string name="help_track_map_title">வரைபடத்தில் ஒரு பாதையை எவ்வாறு காண்பிப்பது?</string>
|
||||
@@ -411,13 +411,13 @@
|
||||
<string name="value_smallest_recommended">சிறியது (பரிந்துரைக்கப்படுகிறது)</string>
|
||||
<string name="value_int_seconds">%1$d கள் (பரிந்துரைக்கப்படுகிறது)</string>
|
||||
<string name="voiceIdle">சும்மா ஆக.</string>
|
||||
<string name="voiceHoursPlural">{n, பன்மை, = 1 {1 hour} பிற {{n, எண்} மணிநேரம்}}</string>
|
||||
<string name="voiceMinutesPlural">{n, பன்மை, = 1 {1 minute} பிற {{n, எண்} நிமிடங்கள்}}</string>
|
||||
<string name="voiceSecondsPlural">{n, பன்மை, = 1 {1 second} பிற {{n, எண்} விநாடிகள்}}</string>
|
||||
<string name="voiceSpeedKilometersPerHourPlural">{n, பன்மை, = 1 {1 kilometer per hour} பிற {{n, எண்,#. 0} ஒரு மணி நேரத்திற்கு கிலோமீட்டர்}}</string>
|
||||
<string name="voiceSpeedMKnotsPlural">{n, பன்மை, = 1 {1 knot} பிற {{n, எண்,#. 0} முடிச்சுகள்}}</string>
|
||||
<string name="voiceSpeedMilesPerHourPlural">{n, பன்மை, = 1 {1 mile per hour} பிற {{n, எண்,#. 0} ஒரு மணி நேரத்திற்கு மைல்கள்}}</string>
|
||||
<string name="voiceSpeed">{n, பன்மை, = 1 {1} பிற {{n, எண்,#. 0}}}</string>
|
||||
<string name="voiceHoursPlural">{n, plural, = 1 {1 hour} other {{n,number} மணிநேரம்}}</string>
|
||||
<string name="voiceMinutesPlural">{n, plural, = 1 {1 minute} other {{n,number} நிமிடங்கள்}}</string>
|
||||
<string name="voiceSecondsPlural">{n, plural, = 1 {1 second} other {{n,number} விநாடிகள்}}</string>
|
||||
<string name="voiceSpeedKilometersPerHourPlural">{n, plural, = 1 {1 kilometer per hour} other {{n,number,#. 0} ஒரு மணி நேரத்திற்கு கிலோமீட்டர்}}</string>
|
||||
<string name="voiceSpeedMKnotsPlural">{n, plural, = 1 {1 knot} other {{n,number,#. 0} முடிச்சுகள்}}</string>
|
||||
<string name="voiceSpeedMilesPerHourPlural">{n, plural, = 1 {1 mile per hour} other {{n,number,#. 0} ஒரு மணி நேரத்திற்கு மைல்கள்}}</string>
|
||||
<string name="voiceSpeed">{n, plural, = 1 {1} other {{n,number,#. 0}}}</string>
|
||||
<string name="voice_on_device_speaker_title">சாதனத்தின் ச்பீக்கரைப் பயன்படுத்தவும்</string>
|
||||
<string name="voice_per_kilometer">ஒரு கிலோமீட்டருக்கு</string>
|
||||
<string name="voice_per_nautical_mile">ஒரு கடல் மைலுக்கு</string>
|
||||
@@ -426,10 +426,10 @@
|
||||
<string name="lap_speed">மடியில் விரைவு</string>
|
||||
<string name="speed">சராசரி நகரும் விரைவு</string>
|
||||
<string name="total_distance">மொத்த தூரம்</string>
|
||||
<string name="voiceDistanceKilometersPlural">{n, பன்மை, = 1 {1 kilometer} பிற {{n, எண்,#. 0} கிலோமீட்டர்}}</string>
|
||||
<string name="voiceDistanceMilesPlural">{n, பன்மை, = 1 {1 mile} பிற {{n, எண்,#. 0} மைல்கள்}}</string>
|
||||
<string name="voiceDistanceNauticalMilesPlural">{n, பன்மை, = 1 {1 nautical mile} பிற {{n, எண்,#. 0} கடல் மைல்கள்}}</string>
|
||||
<string name="voiceDistance">{n, பன்மை, = 1 {1 } பிற {{n, எண்,#. 0}}}</string>
|
||||
<string name="voiceDistanceKilometersPlural">{n, plural, = 1 {1 kilometer} other {{n,number,#. 0} கிலோமீட்டர்}}</string>
|
||||
<string name="voiceDistanceMilesPlural">{n, plural, = 1 {1 mile} other {{n,number,#. 0} மைல்கள்}}</string>
|
||||
<string name="voiceDistanceNauticalMilesPlural">{n, plural, = 1 {1 nautical mile} other {{n,number,#. 0} கடல் மைல்கள்}}</string>
|
||||
<string name="voiceDistance">{n, plural, = 1 {1 } other {{n,number,#. 0}}}</string>
|
||||
<string name="average_heart_rate">சராசரி இதய துடிப்பு</string>
|
||||
<string name="current_heart_rate">தற்போதைய இதய துடிப்பு</string>
|
||||
<string name="lap_heart_rate">மடியில் இதய துடிப்பு</string>
|
||||
|
||||
Reference in New Issue
Block a user