Compare commits

...

89 Commits

Author SHA1 Message Date
Dennis Guse 382acadc6a Release: v4.12.5 2024-07-06 13:33:08 +02:00
Dennis Guse 1ed807054b Bugfix: moving time was not computed.
Introduced in 6be9d2477c (first released in v4.9.0)

Fixes #1756.
2024-07-05 23:42:25 +02:00
Dennis Guse c96635c46b Upgrade to Gradlew 8.8 2024-07-05 07:29:50 +02:00
Michel CABILLOT 9b2c93f74f Translated using Weblate (French)
Currently translated at 92.4% (491 of 531 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/fr/
2024-06-27 06:51:38 +02:00
Fjuro e7a86b6aad Translated using Weblate (Czech)
Currently translated at 99.8% (530 of 531 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/cs/
2024-06-27 06:51:38 +02:00
dependabot[bot] b86f8c9a20 Bump androidx.test:rules from 1.6.0 to 1.6.1
Bumps androidx.test:rules from 1.6.0 to 1.6.1.

---
updated-dependencies:
- dependency-name: androidx.test:rules
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-27 06:51:33 +02:00
dependabot[bot] e9130f3402 Bump androidx.test:core from 1.6.0 to 1.6.1
Bumps androidx.test:core from 1.6.0 to 1.6.1.

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-27 06:47:48 +02:00
dependabot[bot] a08ec97c29 Bump androidx.test:runner from 1.6.0 to 1.6.1
Bumps androidx.test:runner from 1.6.0 to 1.6.1.

---
updated-dependencies:
- dependency-name: androidx.test:runner
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-27 06:47:40 +02:00
dependabot[bot] a6340d13fa Bump androidx.test.ext:junit from 1.2.0 to 1.2.1
Bumps androidx.test.ext:junit from 1.2.0 to 1.2.1.

---
updated-dependencies:
- dependency-name: androidx.test.ext:junit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-27 06:45:44 +02:00
dependabot[bot] dbbf6abcd6 Bump androidx.test.espresso:espresso-core from 3.6.0 to 3.6.1
Bumps androidx.test.espresso:espresso-core from 3.6.0 to 3.6.1.

---
updated-dependencies:
- dependency-name: androidx.test.espresso:espresso-core
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-27 06:45:28 +02:00
dependabot[bot] 683bf2d280 Bump androidx.test.espresso:espresso-core from 3.5.1 to 3.6.0
Bumps androidx.test.espresso:espresso-core from 3.5.1 to 3.6.0.

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-26 07:07:30 +02:00
dependabot[bot] 6c2377a8e8 Bump androidx.test:core from 1.5.0 to 1.6.0
Bumps androidx.test:core from 1.5.0 to 1.6.0.

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-25 06:39:36 +02:00
dependabot[bot] b6661ccafd Bump androidx.test:rules from 1.5.0 to 1.6.0
Bumps androidx.test:rules from 1.5.0 to 1.6.0.

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-25 06:39:29 +02:00
dependabot[bot] 932c142691 Bump androidx.test:orchestrator from 1.4.2 to 1.5.0
Bumps androidx.test:orchestrator from 1.4.2 to 1.5.0.

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-25 06:38:29 +02:00
dependabot[bot] 57918249bc Bump androidx.test.ext:junit from 1.1.5 to 1.2.0
Bumps androidx.test.ext:junit from 1.1.5 to 1.2.0.

---
updated-dependencies:
- dependency-name: androidx.test.ext:junit
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-25 06:38:16 +02:00
dependabot[bot] 3405eca556 Bump androidx.test:runner from 1.5.2 to 1.6.0
Bumps androidx.test:runner from 1.5.2 to 1.6.0.

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-25 06:37:55 +02:00
ovl-1 a932adde3f Translated using Weblate (Norwegian Bokmål)
Currently translated at 96.9% (515 of 531 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/nb_NO/
2024-06-21 11:09:19 +02:00
ovl-1 a03dfd81ac Translated using Weblate (Norwegian Bokmål)
Currently translated at 95.2% (506 of 531 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/nb_NO/
2024-06-14 05:09:49 +00:00
Stephan Paternotte 7550525462 Translated using Weblate (Dutch)
Currently translated at 100.0% (140 of 140 strings)

Translation: OpenTracks/App store metadata files
Translate-URL: https://hosted.weblate.org/projects/opentracks/app-store-metadata-files/nl/
2024-06-14 05:09:49 +00:00
Fjuro 5d70381b23 Translated using Weblate (Czech)
Currently translated at 100.0% (140 of 140 strings)

Translation: OpenTracks/App store metadata files
Translate-URL: https://hosted.weblate.org/projects/opentracks/app-store-metadata-files/cs/
2024-06-14 05:09:48 +00:00
dependabot[bot] 96a4cbf70d Bump com.android.tools.build:gradle from 8.4.2 to 8.5.0
Bumps com.android.tools.build:gradle from 8.4.2 to 8.5.0.

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-14 07:09:44 +02:00
dependabot[bot] 959aadbb62 Bump com.android.tools.build:gradle from 8.4.1 to 8.4.2
Bumps com.android.tools.build:gradle from 8.4.1 to 8.4.2.

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-11 06:07:51 +02:00
OMTDesign fa59752c04 Update README_TESTED_SENSORS.md
I have thoroughly tested the CYCPLUS H1 heart rate monitor in Opentracks, and I it works flawlessly. It tracks accurately and it pairs quickly with the app.
2024-06-07 10:06:19 +02:00
dependabot[bot] 5305ec3206 Bump androidx.appcompat:appcompat from 1.6.1 to 1.7.0
Bumps androidx.appcompat:appcompat from 1.6.1 to 1.7.0.

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-30 08:04:55 +02:00
dependabot[bot] 584339b7eb Bump reactivecircus/android-emulator-runner from 2.30.1 to 2.31.0
Bumps [reactivecircus/android-emulator-runner](https://github.com/reactivecircus/android-emulator-runner) from 2.30.1 to 2.31.0.
- [Release notes](https://github.com/reactivecircus/android-emulator-runner/releases)
- [Changelog](https://github.com/ReactiveCircus/android-emulator-runner/blob/main/CHANGELOG.md)
- [Commits](https://github.com/reactivecircus/android-emulator-runner/compare/v2.30.1...v2.31.0)

---
updated-dependencies:
- dependency-name: reactivecircus/android-emulator-runner
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-27 06:45:21 +02:00
Dennis Guse 151c3a79de Predictive back: for everything except import/export.
Fixes #1708.
2024-05-25 23:46:24 +02:00
Dennis Guse a90c7deb32 Release: v4.12.4 2024-05-25 22:03:52 +02:00
ovl-1 c3601e41cd Translated using Weblate (Norwegian Bokmål)
Currently translated at 94.9% (504 of 531 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/nb_NO/
2024-05-25 21:50:11 +02:00
Ghost of Sparta b3d98340dc Translated using Weblate (Hungarian)
Currently translated at 98.4% (523 of 531 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/hu/
2024-05-25 21:50:11 +02:00
josé m ebbd9c1535 Translated using Weblate (Galician)
Currently translated at 99.6% (529 of 531 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/gl/
2024-05-25 21:50:11 +02:00
ken-der-guru 14fc605c45 Translated using Weblate (German)
Currently translated at 98.4% (523 of 531 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/de/
2024-05-25 21:50:11 +02:00
Stephan Paternotte c5ca6644f4 Translated using Weblate (Dutch)
Currently translated at 99.8% (530 of 531 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/nl/
2024-05-25 21:50:11 +02:00
Ghost of Sparta e15c729c00 Translated using Weblate (Hungarian)
Currently translated at 98.1% (521 of 531 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/hu/
2024-05-25 21:50:11 +02:00
Fjuro 93c89690c9 Translated using Weblate (Czech)
Currently translated at 99.8% (530 of 531 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/cs/
2024-05-25 21:50:11 +02:00
Luna f3f05512c9 Translated using Weblate (Chinese (Traditional))
Currently translated at 96.4% (512 of 531 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/zh_Hant/
2024-05-25 21:50:11 +02:00
Luna d2fc2598d1 Translated using Weblate (Japanese)
Currently translated at 48.3% (257 of 531 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/ja/
2024-05-25 21:50:11 +02:00
Luna fd2d2c5820 Translated using Weblate (Finnish)
Currently translated at 88.5% (470 of 531 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/fi/
2024-05-25 21:50:11 +02:00
Luna 01f10bce24 Translated using Weblate (Basque)
Currently translated at 78.7% (418 of 531 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/eu/
2024-05-25 21:50:11 +02:00
Luna fd963b0fdb Translated using Weblate (German)
Currently translated at 97.1% (516 of 531 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/de/
2024-05-25 21:50:11 +02:00
Luna 0947405563 Translated using Weblate (English)
Currently translated at 99.8% (530 of 531 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/en/
2024-05-25 21:50:11 +02:00
Dennis Guse f595bc4d1e Bugfix: delete markers from list was broken.
Fixes #1915.
2024-05-25 21:50:05 +02:00
dependabot[bot] 4b26583c27 ---
updated-dependencies:
- dependency-name: com.android.tools.build:gradle
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-21 06:30:56 +02:00
Quentin 734d4e08e9 Translated using Weblate (French)
Currently translated at 93.1% (491 of 527 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/fr/
2024-05-13 07:10:12 +02:00
josé m 6615034314 Translated using Weblate (Galician)
Currently translated at 99.8% (526 of 527 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/gl/
2024-05-13 07:10:12 +02:00
Stephan Paternotte 039495d107 Translated using Weblate (Dutch)
Currently translated at 100.0% (139 of 139 strings)

Translation: OpenTracks/App store metadata files
Translate-URL: https://hosted.weblate.org/projects/opentracks/app-store-metadata-files/nl/
2024-05-13 07:10:12 +02:00
Stephan Paternotte 1d926d72a7 Translated using Weblate (Dutch)
Currently translated at 99.8% (526 of 527 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/nl/
2024-05-13 07:10:12 +02:00
josé m d1af0fa072 Translated using Weblate (Galician)
Currently translated at 99.4% (524 of 527 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/gl/
Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
2024-05-13 07:10:12 +02:00
gallegonovato ef802d1948 Translated using Weblate (Spanish)
Currently translated at 99.4% (524 of 527 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/es/
Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
2024-05-13 07:10:12 +02:00
Fjuro 322e91bc22 Translated using Weblate (Czech)
Currently translated at 99.8% (526 of 527 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (139 of 139 strings)

Co-authored-by: Fjuro <fjuro@alius.cz>
Translate-URL: https://hosted.weblate.org/projects/opentracks/app-store-metadata-files/cs/
Translate-URL: https://hosted.weblate.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/cs/
Translation: OpenTracks/App store metadata files
Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
2024-05-13 07:10:12 +02:00
dependabot[bot] 055f2beb1e Bump org.mockito:mockito-android from 5.11.0 to 5.12.0
Bumps [org.mockito:mockito-android](https://github.com/mockito/mockito) from 5.11.0 to 5.12.0.
- [Release notes](https://github.com/mockito/mockito/releases)
- [Commits](https://github.com/mockito/mockito/compare/v5.11.0...v5.12.0)

---
updated-dependencies:
- dependency-name: org.mockito:mockito-android
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-13 07:09:53 +02:00
Peter Hercek 6cfc05af82 support for lap cycling power in the announcer
Implements #1806
2024-05-12 15:32:23 +02:00
dependabot[bot] 70a2040142 Bump com.google.android.material:material from 1.11.0 to 1.12.0
Bumps [com.google.android.material:material](https://github.com/material-components/material-components-android) from 1.11.0 to 1.12.0.
- [Release notes](https://github.com/material-components/material-components-android/releases)
- [Commits](https://github.com/material-components/material-components-android/compare/1.11.0...1.12.0)

---
updated-dependencies:
- dependency-name: com.google.android.material:material
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-03 12:43:02 +02:00
dependabot[bot] 181e1a503c Bump androidx.core:core from 1.13.0 to 1.13.1
Bumps androidx.core:core from 1.13.0 to 1.13.1.

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-02 07:30:35 +02:00
Dennis Guse b08302237f READMEs: added reference to NoTrustIssues. 2024-05-01 20:02:43 +02:00
Dennis Guse 881f68c580 Upgrade to Gradlew 8.7.0 2024-05-01 19:52:58 +02:00
dm1cael a8a5aa4268 Announcements: add toggle to distance/speed unit announcement
Fixes #1805.
2024-05-01 19:23:26 +02:00
dependabot[bot] 9c8b9ca05d Bump com.android.tools.build:gradle from 8.3.2 to 8.4.0
Bumps com.android.tools.build:gradle from 8.3.2 to 8.4.0.

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-01 09:21:00 +02:00
Dennis Guse b70241c967 Upgrade to Gradlew 8.7.0 2024-05-01 09:11:12 +02:00
Dennis Guse a6f3c05e82 ExifTool now supports OpenTracks's GPX. 2024-04-29 07:53:25 +02:00
Stephan Paternotte f9640b0fb1 Translated using Weblate (Dutch)
Currently translated at 100.0% (138 of 138 strings)

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

Translation: OpenTracks/App store metadata files
Translate-URL: https://hosted.weblate.org/projects/opentracks/app-store-metadata-files/cs/
2024-04-28 11:09:07 +02:00
Dennis Guse 9e496f97c1 Release: v4.12.3 2024-04-28 11:02:07 +02:00
Dennis Guse 455c2fcf75 Bugfix: idle time should start also if the first trackpoint with a location is stored.
Identified in #1898.
2024-04-28 10:50:56 +02:00
Dennis Guse e590e4e07e Bugfix: overestimated distance.
A combination of idle trackpoint and stale GPS data, resulted in recording lat=0.0 and lng=0.0; and thus inflating distance as well as GPS-based speed.

Fixes #1898.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Translation: OpenTracks/App store metadata files
Translate-URL: https://hosted.weblate.org/projects/opentracks/app-store-metadata-files/cs/
2024-04-08 18:18:06 +02:00
Dennis Guse 52624b5cfe PublicAPI: add test for setting icon via parameter.
Follow-up to #1818.
2024-04-08 18:17:54 +02:00
Dennis Guse dfdbc373ff GPS: event-based using Raw.
Part of #1424.
2024-04-08 17:48:29 +02:00
Dennis Guse 1d0c6cdd92 Release: v4.12.1 2024-04-05 20:06:37 +02:00
Dennis Guse 4bfd65bb6d Bugfix: handle missing permissions properly.
Affected only SDK >= 33.

Fixes #1781.
2024-04-01 17:41:25 +02:00
Dennis Guse 48baece0e5 Bugfix: POST_NOTIFICATION permission is optional.
Affected only SDK >= 33.

Fixes #1880.
2024-04-01 17:12:53 +02:00
dependabot[bot] 3ac1226cdd Bump androidx.mediarouter:mediarouter from 1.6.0 to 1.7.0
Bumps androidx.mediarouter:mediarouter from 1.6.0 to 1.7.0.

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-21 05:58:13 +01:00
dependabot[bot] b4540121bb Bump com.android.tools.build:gradle from 8.3.0 to 8.3.1
Bumps com.android.tools.build:gradle from 8.3.0 to 8.3.1.

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-19 20:53:21 +01:00
79 changed files with 873 additions and 559 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
java-version: '17'
- name: run tests
uses: reactivecircus/android-emulator-runner@v2.30.1
uses: reactivecircus/android-emulator-runner@v2.31.0
with:
arch: x86_64
api-level: 34
+3 -1
View File
@@ -70,7 +70,7 @@ hosted.weblate.org</a>.
* export automatically after each recording (e.g., to sync via [Nextcloud](https://nextcloud.com/))
* avoid duplication: each exported file contain a random unique identifier (i.e., `opentracks:trackid`)
* __Altitude:__
* gain/loss via barometric sensor (if present)
* gain/loss via barometric sensor (internal if present or via Bluetooth's Environmental Sensing Service)
* shown in EGM2008 (above mean sea level); exported as WGS84
* __Bluetooth LE sensors:__
* heart rate
@@ -133,6 +133,8 @@ The Public API is disabled by default to protect the user's privacy, but it can
| [OsmAnd](https://github.com/osmandapp/OsmAnd) | ? | [no](https://github.com/osmandapp/OsmAnd/issues/15271) | [no](https://github.com/osmandapp/OsmAnd/issues/15271) |
| [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 |
## Dashboard API (incl. map)
+10 -1
View File
@@ -12,6 +12,7 @@
* Mi Band 3, Amazfit Band 5, Amazfit Bip. These devices are manufactured by Huami, and other Huami devices will very likely work. Theoretically, this sensor must be enabled, but testing reveals that it works even without enabling. For details on how to enable see [Gadgetbridge wiki](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Huami-Heartrate-measurement#bluetooth-heart-rate-sensor)
* Amazfit Neo. But first you have to enable "Discoverable" and "Activity heart rate sharing" in the official Zepp app. (after pairing with OpenTracks you can disable them again)
* Garmin HRM-Dual (Reference: 010-12883-00)
* CYCPLUS H1
## 0x1816: Cycling Cadence and Speed Service
@@ -60,7 +61,15 @@ We do not support type of movement (i.e., walking vs running).
* Stryd (incl. power)
* Wahoo Tickr X (Cadence appears to be reported in SPM rather than RPM)
## Tested Barometric Sensor Smartphones
## Barometer (gain/loss)
### 0x2A6D: Environmental Sensing Service
Sadly, Bluetooth sensors providing _air pressure_ via Environmental Sensing Service seem to be very rare.
* NoTrustIssues: https://github.com/OpenTracksApp/NoTrustIssues
An Android app that exposes the internal barometer via Environmental Sensing Service.
### Internal: tested Barometric Sensor Smartphones
OpenTracks derives the altitude gain and altitude loss using the internal barometric sensor of a device (if present).
However, barometric sensor seem to be prone to a lot of noise.
+14 -14
View File
@@ -6,7 +6,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.3.0'
classpath 'com.android.tools.build:gradle:8.5.0'
}
}
@@ -64,8 +64,8 @@ android {
defaultConfig {
applicationId "de.dennisguse.opentracks"
versionCode 5725
versionName "v4.12.0"
versionCode 5814
versionName "v4.12.5"
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
@@ -127,22 +127,22 @@ android {
dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
implementation 'androidx.appcompat:appcompat:1.6.1'
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 'com.google.android.material:material:1.11.0'
implementation 'com.google.android.material:material:1.12.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.core:core:1.12.0'
implementation 'androidx.core:core:1.13.1'
implementation 'androidx.core:core-splashscreen:1.0.1'
implementation 'androidx.mediarouter:mediarouter:1.6.0'
implementation 'androidx.mediarouter:mediarouter:1.7.0'
androidTestImplementation 'androidx.test:core:1.5.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test:rules:1.5.0'
androidTestImplementation 'androidx.test:runner:1.5.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation 'org.mockito:mockito-android:5.11.0'
androidTestImplementation 'androidx.test:core:1.6.1'
androidTestImplementation 'androidx.test.ext:junit:1.2.1'
androidTestImplementation 'androidx.test:rules:1.6.1'
androidTestImplementation 'androidx.test:runner:1.6.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
androidTestImplementation 'org.mockito:mockito-android:5.12.0'
androidTestUtil 'androidx.test:orchestrator:1.4.2'
androidTestUtil 'androidx.test:orchestrator:1.5.0'
}
@@ -0,0 +1,8 @@
v4.12.0: OpenTracks
Změny:
- Tmavý motiv pro obrazovky OLED (vyžaduje ruční restart)
- Změna uspořádání nastavení (GPS je senzor)
Vývojáři:
- Přidány skripty pro nahrání Fastlane na Obchod Play (překlady)
@@ -0,0 +1,5 @@
v4.12.1: OpenTracks
Oprava chyb:
- Android 14: nahlášení chybějících oprávnění (namísto nuceného pádu se stacktrace)
- POST_NOTIFICATION je volitelné
@@ -0,0 +1,4 @@
v4.12.2.: OpenTracks
Oprava chyvy:
- Umožnění spuštění senzorů před začátkem záznamu
@@ -0,0 +1,8 @@
v4.12.3: OpenTracks
Opraveny chyby:
- Používání funkcionality IDLE a GPS ukládalo souřadnice 0.0/0.0 a tím pádem přeceňovalo všechny statistiky (vzdálenost >10 000 km). (Vzniklo ve v4.12.0)
- Nečinnost: také spustit, pokud byla obdržena pouze jedna lokace.
Ohledně chyby přeceňování vzdálenosti: uložená data nebudou v OpenTracks opravena.
Doporučení: exportujte záznamy do KML/KMZ a nahraďte neplatné souřadnice.
@@ -0,0 +1,8 @@
v4.12.4: OpenTracks
Změny:
- Oznámení: jednotky lze vynechat
- Oznámení: přidán výkon pro jízdu na kole
Oprava chyby:
- Pád při odstranění značky ze seznamu
@@ -0,0 +1,15 @@
v3.0.0: OpenTracks
Første udgivelse af OpenTracks (dvs. hard fork fra MyTracks)
Ændringer:
- Omdøbt fra MyTracks til OpenTracks
- Tilføjet Bluetooth LE-pulssensor
- Fjernet alle funktioner, der kræver internetadgang
- Fjernet Google Maps-integration
- Fjernet brug af Google Play-tjenester
- ANT+ sensorer fjernet
- Fjernet klassiske Bluetooth-sensorer
- Fjernet Protobuf
- Fjernet kalorieberegning og aktivitetsberegning
- Fjernet MyTracks Service-API (dvs. ingen integration med andre apps)
@@ -1,11 +1,22 @@
OpenTracks er et program til sporing af sport, der fuldt ud respekterer dit privatliv.
En sporingsmakker, der respekterer dit privatliv.
Funktioner:
* Sport tracking: Spor dine sports- og udendørsaktiviteter
* Billeder og markører: Markér interessante steder under sporing
* Højdeforøgelse og -tab: via barometrisk sensor
* Højde vist i EGM2008 (over middelhavets overflade); eksporteret som WGS84
* Stemmemeddelelser
* Understøtter Bluetooth LE-sensorer: puls, hastighed og distance (cykling), kadence (cykling) og effektmåler (cykling)
* Eksport af data: Eksportér spor enten som KMZ (inkl. fotos), KML eller GPX
* Ingen internetadgang: Internet bruges ikke
Sports- og udendørsaktiviteter giver glæde, dygtighed og selvtillid.
Værdsæt dit helbred ved at holde styr på din træning.
Registrerer, mens du løber eller går, og giver dig en cykelcomputer med en større skærm til cykling.
Markér interessante steder undervejs med billeder.
Opbevar registrerede statistikker i detaljer til analyse.
Del kun de data, du ønsker, at andre skal have.
* Stemmemeddelelser.
* Understøtter Bluetooth LE-sensorer: puls, hastighed og distance (cykling), kadence (cykling) og effektmåler (cykling).
* Højdestigning og -fald: via barometrisk sensor.
* Højde vist i EGM2008 (over havets overflade); eksporteret som WGS84.
* Eksport af data i form af spor, enten som KMZ (inkl. fotos), KML eller GPX.
* Ingen internetadgang eller ekstra tilladelser.
* Mørkt og lyst tema, der respekterer systemindstillinger.
* Ingen reklamer.
Libre Software / Fri Software / Open Source
hvilket betyder, at du kan bruge, studere, ændre og dele kildekoden.
Licenseret Apache 2.0
@@ -1 +1 @@
En sportstracker, der respekterer dit privatliv fuldt ud.
En sportstracker, der respekterer dit privatliv.
@@ -0,0 +1,6 @@
v4.12.1: OpenTracks
Bugfix:
- Android 14: report missing permissions (instead of forced chrash with stacktrace)
- POST_NOTIFICATION is optional
@@ -0,0 +1,4 @@
v4.12.2.: OpenTracks
Bugfix:
- Allow to start sensors before recording
@@ -0,0 +1,8 @@
v4.12.3: OpenTracks
Bugfix:
- Using GPS and IDLE functionality stored coordinates 0.0/0.0 and thus overestimating all statistics (distance >10.000 km). (Introduced in v4.12.0)
- Idle: also trigger if only one location was received.
Regarding the overestimating distance bug: the stored data will not be fixed within OpenTracks.
Recommendation: export the as KML/KMZ and replace the invalid coordinates.
@@ -0,0 +1,8 @@
v4.12.4: OpenTracks
Changes:
- Announcements: units can be omitted
- Announcements: added lap cycling power
Bugfix:
- Delete markers from list crashed
@@ -0,0 +1,8 @@
v4.12.5: OpenTracks
Bugfix:
- Moving is now computed correctly again.
Was broken since v4.9.0 due to the introduction of idle functionality. See #1756.
Changes:
- Support for Predictive Back
@@ -0,0 +1,8 @@
v4.12.0: OpenTracks
Cambios:
- decorado escuro amigable con OLED (hai que reiniciar)
- nova orde nos axustes (GPS é un sensor)
Desenvolvemento:
- Engadidos scripts Fastlane para subir á PlayStore (traducións)
@@ -0,0 +1,8 @@
v4.12.0: OpenTracks
Veranderingen:
- OLED-vriendelijk donker thema (handmatige herstart vereist)
- Re-order instellingen (GPS is een sensor)
Ontwikkelaar:
- Scripts toegevoegd voor Fastlane om PlayStore te uploaden (vertalingen)
@@ -0,0 +1,5 @@
v4.12.1: OpenTracks
Bugfix:
- Android 14: ontbrekende rechten melden (in plaats van geforceerde chrash met stacktrace)
- POST_NOTIFICATION is optioneel
@@ -0,0 +1,4 @@
v4.12.2 .: OpenTracks
Bugfix:
- Toestaan dat sensoren voor de opname worden gestart
@@ -0,0 +1,8 @@
v4.12.3: OpenTracks
Bugfix:
- Gebruikmakend van GPS- en IDLE-functionaliteit opgeslagen coördinaten 0.0 / 0.0 en overschat zo alle statistieken (afstand >10.000 km). (Ingevoerd in v4.12.0)
- Idle: ook trigger als er maar één locatie is ontvangen.
Met betrekking tot de bug rond de overschatting van afstand: de opgeslagen gegevens worden niet binnen OpenTracks gecorrigeerd.
Aanbeveling: exporteer de als KML / KMZ en vervang de ongeldige coördinaten.
@@ -0,0 +1,8 @@
v4.12.4: OpenTracks
Veranderingen:
- Aankondigingen: eenheden kunnen worden weggelaten
- Aankondigingen: extra wielrenkracht
Bugfix:
- Markeringen verwijderen uit lijst gecrasht
@@ -0,0 +1,8 @@
v4.12.0: OpenTracks
更改:
- OLED 友好型暗色主题(需要手动重启)
- 重新排序设置(GPS 是一个传感器)
开发人员:
- 为 PlayStore 上传添加了 Fastlane 脚本(翻译)
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Vendored
+10 -10
View File
@@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@@ -65,6 +65,7 @@ import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingCadence;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingDistanceSpeed;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorCyclingPower;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorHeartRate;
import de.dennisguse.opentracks.sensors.sensorData.Raw;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
@@ -604,6 +605,6 @@ public class ExportImportTest {
mockAltitudeChange(trackPointCreator, altitudeGain);
trackPointCreator.setClock(time);
trackPointCreator.onChange(location);
trackPointCreator.getSensorManager().onChanged(new Raw<>(location));
}
}
@@ -1,18 +1,24 @@
package de.dennisguse.opentracks.publicapi;
import android.content.Context;
import android.content.Intent;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import androidx.test.rule.GrantPermissionRule;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.List;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.TestUtil;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.util.IntentUtils;
@@ -35,12 +41,23 @@ public class PublicApiTest {
@Test
public void StartStopTest() throws InterruptedException {
PreferencesUtils.setBoolean(R.string.publicapi_enabled_key, true);
context.startActivity(IntentUtils.newIntent(context, StartRecording.class));
Intent startIntent = IntentUtils.newIntent(context, StartRecording.class);
startIntent.putExtra("TRACK_NAME", "trackName");
startIntent.putExtra("TRACK_CATEGORY", "activityTypeLocalized");
startIntent.putExtra("TRACK_ICON", "airplane");
startIntent.putExtra("TRACK_DESCRIPTION", "description");
context.startActivity(startIntent);
Thread.sleep(5000);
context.startActivity(IntentUtils.newIntent(context, StopRecording.class));
List<Track> tracks = new ContentProviderUtils(context).getTracks();
Assert.assertEquals(1, tracks.size());
Track track = tracks.get(0);
Assert.assertEquals("trackName", track.getName());
Assert.assertEquals("activityTypeLocalized", track.getActivityTypeLocalized());
Assert.assertEquals("airplane", track.getActivityType().getId());
}
@Test
@@ -10,6 +10,7 @@ import android.os.Looper;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.MediumTest;
import androidx.test.rule.GrantPermissionRule;
import androidx.test.rule.ServiceTestRule;
import org.junit.AfterClass;
@@ -20,12 +21,14 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import java.time.Duration;
import java.time.Instant;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.TestUtil;
import de.dennisguse.opentracks.content.data.TestDataUtil;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.AltitudeGainLoss;
@@ -54,6 +57,9 @@ public class TrackRecordingServiceRecordingTest {
@Rule
public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(5, TimeUnit.SECONDS);
@Rule
public GrantPermissionRule mGrantPermissionRule = TestUtil.createGrantPermissionRule();
private final Context context = ApplicationProvider.getApplicationContext();
private ContentProviderUtils contentProviderUtils;
@@ -127,6 +133,47 @@ public class TrackRecordingServiceRecordingTest {
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
/**
* Test that an IDLE event, doesn't store invalid GPS-provided data.
*/
@MediumTest
@Test
public void recording_startIdle() throws InterruptedException {
// given
TrackPointCreator trackPointCreator = service.getTrackPointCreator();
String startTime = "2020-02-02T02:02:02Z";
trackPointCreator.setClock(startTime);
Track.Id trackId = service.startNewTrack();
String gps1 = "2020-02-02T02:02:03Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15);
String gps2 = "2020-02-02T02:02:04Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps2, 45.0, 35.0, 1, 15);
// when
String idleTime = "2020-02-02T02:02:17Z";
trackPointCreator.setClock("2020-02-02T02:02:17Z");
Thread.sleep(Duration.ofSeconds(15).toMillis());
// then
new TrackPointAssert().assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps1))
.setLatitude(45)
.setLongitude(35)
.setHorizontalAccuracy(Distance.of(1))
.setSpeed(Speed.of(15)),
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps2))
.setLatitude(45)
.setLongitude(35)
.setHorizontalAccuracy(Distance.of(1))
.setSpeed(Speed.of(15)),
new TrackPoint(TrackPoint.Type.IDLE, Instant.parse(idleTime))
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
@MediumTest
@Test
public void testRecording_startPauseResume() {
@@ -415,6 +462,10 @@ public class TrackRecordingServiceRecordingTest {
.setAltitudeGain(0f)
.setAltitudeLoss(0f),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
.setLatitude(45.00002)
.setLongitude(35)
.setHorizontalAccuracy(Distance.of(1))
.setSpeed(Speed.of(15))
.setAltitudeGain(0f)
.setAltitudeLoss(0f)
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
@@ -667,6 +718,9 @@ public class TrackRecordingServiceRecordingTest {
.setSpeed(Speed.of(5))
.setSensorDistance(Distance.of(0)),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
.setLatitude(45.001)
.setLongitude(35)
.setHorizontalAccuracy(Distance.of(1))
.setSensorDistance(Distance.of(11))
.setSpeed(Speed.of(5))
.setSensorDistance(Distance.of(0))
@@ -1,126 +0,0 @@
package de.dennisguse.opentracks.services.handlers;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.location.Location;
import android.os.Handler;
import android.os.Looper;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.time.Instant;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.settings.PreferencesUtils;
@RunWith(MockitoJUnitRunner.class)
public class GPSManagerTest {
private final Context context = ApplicationProvider.getApplicationContext();
@Mock
private TrackPointCreator trackPointCreator;
@InjectMocks
private GPSManager locationHandler;
@BeforeClass
public static void preSetUp() {
// Prepare looper for Android's message queue
if (Looper.myLooper() == null) Looper.prepare();
}
@Before
public void setUp() {
// Let's use default values.
PreferencesUtils.clear();
Mockito.when(trackPointCreator.createNow())
.thenReturn(Instant.now());
locationHandler.start(context, new Handler());
}
/**
* When a valid location changed in LocationHandler -> newTrackPoint service method is called.
*/
@Test
public void testOnLocationChanged_okay() {
// when
locationHandler.onLocationChanged(createLocation(45f, 35f, 3, 5, System.currentTimeMillis()));
// then
verify(trackPointCreator, times(1)).onChange(any(Location.class));
}
/**
* When location changed in LocationHandler with bad location -> newTrackPoint service method is not called.
*/
@Test
public void testOnLocationChanged_badLocation() {
// given
float latitude = 91f;
// when
// bad latitude
locationHandler.onLocationChanged(createLocation(latitude, 35f, 3, 5, System.currentTimeMillis()));
// then
verify(trackPointCreator, times(0)).onChange(any(Location.class));
}
/**
* When location changed in LocationHandler with poor accuracy -> newTrackPoint service method is not called.
*/
@Test
public void testOnLocationChanged_poorAccuracy() {
// given
Distance prefAccuracy = PreferencesUtils.getThresholdHorizontalAccuracy();
// when
locationHandler.onLocationChanged(createLocation(45f, 35f, (float) (prefAccuracy.toM() + 1), 5, System.currentTimeMillis()));
// then
// no newTrackPoint called
verify(trackPointCreator, times(0)).onChange(any(Location.class));
}
@Test
public void testOnLocationChanged_movingInaccurate() {
// when
locationHandler.onLocationChanged(createLocation(45.0, 35.0, 5, 15, System.currentTimeMillis()));
locationHandler.onLocationChanged(createLocation(45.1, 35.0, Long.MAX_VALUE, 15, System.currentTimeMillis()));
locationHandler.onLocationChanged(createLocation(45.2, 35.0, Long.MAX_VALUE, 15, System.currentTimeMillis()));
locationHandler.onLocationChanged(createLocation(45.3, 35.0, Long.MAX_VALUE, 15, System.currentTimeMillis()));
locationHandler.onLocationChanged(createLocation(99.0, 35.0, Long.MAX_VALUE, 15, System.currentTimeMillis()));
// then
verify(trackPointCreator, times(1)).onChange(any(Location.class));
}
/**
* Creates a location with parameters and returns the Location object.
*/
private static Location createLocation(double latitude, double longitude, float accuracy, long speed, long time) {
Location location = new Location("gps");
location.setLongitude(longitude);
location.setLatitude(latitude);
location.setAccuracy(accuracy);
location.setSpeed(speed);
location.setTime(time);
location.setBearing(3.0f);
return location;
}
}
@@ -1,7 +1,9 @@
package de.dennisguse.opentracks.stats;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -231,7 +233,7 @@ public class TrackStatisticsUpdaterTest {
));
// then
assertEquals(Duration.ofSeconds(40), subject.getTrackStatistics().getMovingTime());
assertEquals(Duration.ofSeconds(35), subject.getTrackStatistics().getMovingTime());
}
@Test
@@ -261,10 +263,67 @@ public class TrackStatisticsUpdaterTest {
));
// then
assertEquals(Duration.ofSeconds(45), subject.getTrackStatistics().getMovingTime());
assertEquals(Duration.ofSeconds(40), subject.getTrackStatistics().getMovingTime());
assertEquals(Distance.of(1040), subject.getTrackStatistics().getTotalDistance());
}
@Test
public void addTrackPoint_idle_remain_idle() {
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
// when
subject.addTrackPoint(new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochSecond(0)));
subject.addTrackPoint(
new TrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(10))
.setSensorDistance(Distance.of(10)));
subject.addTrackPoint(new TrackPoint(TrackPoint.Type.IDLE, Instant.ofEpochSecond(30)));
// then
assertTrue(subject.getTrackStatistics().isIdle());
assertEquals(Duration.ofSeconds(30), subject.getTrackStatistics().getMovingTime());
assertEquals(Duration.ofSeconds(30), subject.getTrackStatistics().getTotalTime());
assertEquals(Distance.of(10), subject.getTrackStatistics().getTotalDistance());
// when
subject.addTrackPoint(
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochSecond(40))
.setSensorDistance(Distance.of(0)));
// then
assertTrue(subject.getTrackStatistics().isIdle());
assertEquals(Duration.ofSeconds(30), subject.getTrackStatistics().getMovingTime());
assertEquals(Duration.ofSeconds(40), subject.getTrackStatistics().getTotalTime());
assertEquals(Distance.of(10), subject.getTrackStatistics().getTotalDistance());
// when
subject.addTrackPoint(
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochSecond(45))
.setSensorDistance(Distance.of(1)));
// then
assertTrue(subject.getTrackStatistics().isIdle());
assertEquals(Duration.ofSeconds(30), subject.getTrackStatistics().getMovingTime());
assertEquals(Duration.ofSeconds(45), subject.getTrackStatistics().getTotalTime());
assertEquals(Distance.of(11), subject.getTrackStatistics().getTotalDistance());
// when
subject.addTrackPoint(
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochSecond(50))
.setSensorDistance(Distance.of(10)));
// then
assertFalse(subject.getTrackStatistics().isIdle());
assertEquals(Duration.ofSeconds(30), subject.getTrackStatistics().getMovingTime());
assertEquals(Duration.ofSeconds(50), subject.getTrackStatistics().getTotalTime());
assertEquals(Distance.of(21), subject.getTrackStatistics().getTotalDistance());
// when
subject.addTrackPoint(new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochSecond(60)));
// then
assertFalse(subject.getTrackStatistics().isIdle());
assertEquals(Duration.ofSeconds(40), subject.getTrackStatistics().getMovingTime());
assertEquals(Duration.ofSeconds(60), subject.getTrackStatistics().getTotalTime());
assertEquals(Distance.of(21), subject.getTrackStatistics().getTotalDistance());
}
@Test
public void copy_constructor() {
// given
+3 -32
View File
@@ -323,42 +323,13 @@ limitations under the License.
</activity>
<activity android:name=".ui.markers.MarkerEditActivity" />
<activity android:name=".ui.markers.MarkerListActivity" />
<activity
android:name=".ui.markers.MarkerListActivity"
android:exported="true"
android:label="@string/menu_markers"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
<activity
android:name=".TrackListActivity"
android:exported="true"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
<activity android:name=".TrackListActivity" />
<activity android:name=".TrackRecordedActivity" />
<activity android:name=".TrackStoppedActivity" />
<activity
android:name=".TrackRecordingActivity"
android:parentActivityName=".TrackListActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".TrackListActivity" />
</activity>
<activity android:name=".TrackRecordingActivity" />
<activity android:name=".TrackEditActivity" />
@@ -16,7 +16,6 @@
package de.dennisguse.opentracks;
import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
@@ -26,7 +25,6 @@ import android.location.LocationManager;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@@ -34,12 +32,12 @@ import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.appcompat.widget.SearchView;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.google.android.material.button.MaterialButton;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
@@ -47,6 +45,7 @@ import java.util.Objects;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.databinding.TrackListBinding;
import de.dennisguse.opentracks.services.MissingPermissionException;
import de.dennisguse.opentracks.services.RecordingStatus;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
@@ -127,7 +126,6 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
};
// Menu items
private MenuItem searchMenuItem;
private String searchQuery;
@@ -159,7 +157,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
if (gpsStatusValue.isGpsStarted()) {
recordingStatusConnection.stopService(this);
} else {
TrackRecordingServiceConnection.executeForeground(this, (service, connection) -> service.tryStartSensors());
startSensorsOrRecording((service, connection) -> service.tryStartSensors());
}
}
});
@@ -178,7 +176,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
// Not Recording -> Recording
Log.i(TAG, "Starting recording");
updateGpsMenuItem(false, true);
TrackRecordingServiceConnection.executeForeground(this, (service, connection) -> {
startSensorsOrRecording((service, connection) -> {
Track.Id trackId = service.startNewTrack();
Intent newIntent = IntentUtils.newIntent(TrackListActivity.this, TrackRecordingActivity.class);
@@ -192,7 +190,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
}
// Recording -> Stop
ActivityUtils.vibrate(this, 1000);
ActivityUtils.vibrate(this, Duration.ofSeconds(1));
updateGpsMenuItem(false, false);
recordingStatusConnection.stopRecording(TrackListActivity.this);
viewBinding.trackListFabAction.setImageResource(R.drawable.ic_baseline_record_24);
@@ -247,6 +245,14 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
@Override
protected View getRootView() {
viewBinding = TrackListBinding.inflate(getLayoutInflater());
viewBinding.trackListSearchView.getEditText().setOnEditorActionListener((v, actionId, event) -> {
searchQuery = viewBinding.trackListSearchView.getEditText().getText().toString();
viewBinding.trackListSearchView.hide();
loadData();
return true;
});
return viewBinding.getRoot();
}
@@ -254,9 +260,6 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.track_list, menu);
searchMenuItem = menu.findItem(R.id.track_list_search);
ActivityUtils.configureSearchWidget(this, searchMenuItem);
return super.onCreateOptionsMenu(menu);
}
@@ -278,13 +281,6 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
return true;
}
if (item.getItemId() == R.id.track_list_search) {
SearchView searchView = (SearchView) searchMenuItem.getActionView();
searchView.setIconified(false);
searchMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
return true;
}
if (item.getItemId() == R.id.track_list_help) {
startActivity(IntentUtils.newIntent(this, HelpActivity.class));
return true;
@@ -293,42 +289,9 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
return super.onOptionsItemSelected(item);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_SEARCH && searchMenuItem != null) {
return true;
}
return super.onKeyUp(keyCode, event);
}
@Override
public void onBackPressed() {
SearchView searchView = (SearchView) searchMenuItem.getActionView();
if (!searchView.isIconified()) {
searchView.setIconified(true);
}
if (searchQuery != null) {
searchQuery = null;
loadData();
return;
}
super.onBackPressed();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
searchQuery = intent.getStringExtra(SearchManager.QUERY);
} else {
searchQuery = null;
}
}
private void loadData() {
viewBinding.trackListToolbar.setText(searchQuery);
viewBinding.trackListToolbar.setTitle(Objects.requireNonNullElseGet(searchQuery, () -> getString(R.string.app_name)));
Cursor tracks = new ContentProviderUtils(this).searchTracks(searchQuery);
@@ -445,4 +408,12 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
setFloatButton();
adapter.updateRecordingStatus(recordingStatus);
}
private void startSensorsOrRecording(TrackRecordingServiceConnection.Callback callback) {
try {
TrackRecordingServiceConnection.executeForeground(this, callback);
} catch (MissingPermissionException e) {
Toast.makeText(this, R.string.permission_recording_failed, Toast.LENGTH_LONG).show();
}
}
}
@@ -24,6 +24,7 @@ import androidx.viewpager2.adapter.FragmentStateAdapter;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.tabs.TabLayoutMediator;
import java.time.Duration;
import java.util.List;
import de.dennisguse.opentracks.chart.ChartFragment;
@@ -136,7 +137,7 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
viewBinding.trackRecordingFabAction.setBackgroundTintList(ContextCompat.getColorStateList(this, R.color.opentracks));
viewBinding.trackRecordingFabAction.setBackgroundColor(ContextCompat.getColor(this, R.color.opentracks));
viewBinding.trackRecordingFabAction.setOnLongClickListener((view) -> {
ActivityUtils.vibrate(this, 1000);
ActivityUtils.vibrate(this, Duration.ofSeconds(1));
trackRecordingServiceConnection.stopRecording(TrackRecordingActivity.this);
Intent newIntent = IntentUtils.newIntent(TrackRecordingActivity.this, TrackStoppedActivity.class)
.putExtra(TrackStoppedActivity.EXTRA_TRACK_ID, trackId);
@@ -110,15 +110,6 @@ public class TrackStoppedActivity extends AbstractTrackDeleteActivity implements
contentProviderUtils);
}
@Override
public void onBackPressed() {
if (isDiscarding) {
return;
}
super.onBackPressed();
resumeTrackAndFinish();
}
@Override
protected View getRootView() {
viewBinding = TrackStoppedBinding.inflate(getLayoutInflater());
@@ -130,6 +130,16 @@ public class Track {
this.trackStatistics = trackStatistics;
}
@Override
public String toString() {
return "Track{" +
"name='" + name + '\'' +
", description='" + description + '\'' +
", activityTypeLocalized='" + activityTypeLocalized + '\'' +
", activityType=" + activityType +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -135,6 +135,10 @@ public class TrackPoint {
return this;
}
public boolean isIdleTriggered() {
return type == Type.IDLE;
}
public boolean isSegmentManualStart() {
return type == Type.SEGMENT_START_MANUAL;
}
@@ -30,7 +30,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
@Override
public void onConnect(Aggregator<?, ?> aggregator) {
sensorDataSet.add(aggregator);
observer.onChange(new SensorDataSet(sensorDataSet));
}
@Override
@@ -42,13 +41,11 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
@Override
public void onDisconnect(Aggregator<?, ?> aggregator) {
sensorDataSet.add(aggregator);
observer.onChange(new SensorDataSet(sensorDataSet));
}
@Override
public void onRemove(Aggregator<?, ?> aggregator) {
sensorDataSet.remove(aggregator);
observer.onChange(new SensorDataSet(sensorDataSet));
}
};
@@ -67,7 +64,7 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
throw new RuntimeException("SensorManager cannot be started twice; stop first.");
}
gpsManager = new GPSManager(observer); //TODO Pass listener
gpsManager = new GPSManager(observer, listener);
altitudeSumManager = new GainManager(listener);
bluetoothSensorManager = new BluetoothRemoteSensorManager(context, handler, listener);
@@ -104,7 +101,6 @@ public class SensorManager implements SharedPreferences.OnSharedPreferenceChange
sensorDataSet.reset();
}
@Deprecated
@VisibleForTesting
public void onChanged(Raw<?> data) {
listener.onChange(data);
@@ -6,7 +6,7 @@ import java.time.Instant;
import de.dennisguse.opentracks.sensors.BluetoothRemoteSensorManager;
public abstract class Aggregator<Input extends Record, Output> {
public abstract class Aggregator<Input, Output> {
protected Raw<Input> previous;
@@ -44,7 +44,7 @@ public abstract class Aggregator<Input extends Record, Output> {
public Output getValue() {
if (!hasValue()) {
return null;
return null; //TODO Check if this is a good idea!
}
if (isRecent()) {
return value;
@@ -0,0 +1,31 @@
package de.dennisguse.opentracks.sensors.sensorData;
import android.location.Location;
import androidx.annotation.NonNull;
import java.util.Optional;
public class AggregatorGPS extends Aggregator<Location, Optional<Location>> {
public AggregatorGPS(String sensorAddress) {
super(sensorAddress);
}
@Override
protected void computeValue(Raw<Location> current) {
value = Optional.of(current.value());
}
@Override
public void reset() {
value = null;
}
@NonNull
@Override
protected Optional<Location> getNoneValue() {
return Optional.empty();
}
}
@@ -5,7 +5,7 @@ import androidx.annotation.NonNull;
import java.time.Instant;
public record Raw<T extends Record>(
public record Raw<T>(
@NonNull T value,
@NonNull Instant time
@@ -1,5 +1,6 @@
package de.dennisguse.opentracks.sensors.sensorData;
import android.location.Location;
import android.util.Log;
import android.util.Pair;
@@ -40,16 +41,20 @@ public final class SensorDataSet {
@VisibleForTesting
public AggregatorBarometer barometer;
public AggregatorGPS gps;
public SensorDataSet() {
}
public SensorDataSet(SensorDataSet toCopy) {
//TODO This is not a copy constructor anymore, but it should be - aggregators are no value objects
this.heartRate = toCopy.heartRate;
this.cyclingCadence = toCopy.cyclingCadence;
this.cyclingDistanceSpeed = toCopy.cyclingDistanceSpeed;
this.cyclingPower = toCopy.cyclingPower;
this.runningDistanceSpeedCadence = toCopy.runningDistanceSpeedCadence;
this.barometer = toCopy.barometer;
this.gps = toCopy.gps;
}
public Pair<HeartRate, String> getHeartRate() {
@@ -93,7 +98,7 @@ public final class SensorDataSet {
}
public void update(@NonNull Raw<?> data) {
Record value = data.value();
Object value = data.value();
if (value instanceof HeartRate) {
this.heartRate.add((Raw<HeartRate>) data);
@@ -122,6 +127,10 @@ public final class SensorDataSet {
this.barometer.add((Raw<AtmosphericPressure>) data);
return;
}
if (value instanceof Location) {
this.gps.add((Raw<Location>) data);
return;
}
throw new UnsupportedOperationException(data.getClass().getCanonicalName() + " " + data.value().getClass().getCanonicalName());
}
@@ -138,9 +147,15 @@ public final class SensorDataSet {
this.cyclingPower = null;
this.runningDistanceSpeedCadence = null;
this.barometer = null;
this.gps = null;
}
public void fillTrackPoint(TrackPoint trackPoint) {
if (gps != null && gps.hasValue()) {
gps.getValue()
.ifPresent(trackPoint::setLocation);
}
if (getHeartRate() != null) {
trackPoint.setHeartRate(getHeartRate().first);
}
@@ -180,6 +195,7 @@ public final class SensorDataSet {
if (cyclingPower != null) cyclingPower.reset();
if (runningDistanceSpeedCadence != null) runningDistanceSpeedCadence.reset();
if (barometer != null) barometer.reset();
if (gps != null) gps.reset();
}
private void set(@NonNull Aggregator<?, ?> type, @Nullable Aggregator<?, ?> sensorData) {
@@ -209,6 +225,10 @@ public final class SensorDataSet {
barometer = (AggregatorBarometer) sensorData;
return;
}
if (type instanceof AggregatorGPS) {
gps = (AggregatorGPS) sensorData;
return;
}
throw new UnsupportedOperationException(type.getClass().getCanonicalName());
}
@@ -0,0 +1,12 @@
package de.dennisguse.opentracks.services;
import de.dennisguse.opentracks.util.PermissionRequester;
public class MissingPermissionException extends RuntimeException {
private final PermissionRequester permissionRequester;
public MissingPermissionException(PermissionRequester permissionRequester) {
this.permissionRequester = permissionRequester;
}
}
@@ -197,6 +197,9 @@ public class TrackRecordingManager implements SharedPreferences.OnSharedPreferen
if (trackPoint.hasLocation() && lastStoredTrackPointWithLocation == null) {
insertTrackPoint(trackPoint, true);
handler.removeCallbacks(ON_IDLE);
handler.postDelayed(ON_IDLE, idleDuration.toMillis());
return true;
}
@@ -20,7 +20,6 @@ import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ServiceInfo;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager.WakeLock;
@@ -46,7 +45,6 @@ import de.dennisguse.opentracks.services.announcement.VoiceAnnouncementManager;
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.util.PermissionRequester;
import de.dennisguse.opentracks.util.SystemUtils;
public class TrackRecordingService extends Service implements TrackPointCreator.Callback, SharedPreferences.OnSharedPreferenceChangeListener, TrackRecordingManager.IdleObserver {
@@ -213,12 +211,6 @@ public class TrackRecordingService extends Service implements TrackPointCreator.
wakeLock = SystemUtils.acquireWakeLock(this, wakeLock);
trackPointCreator.start(this, handler);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
if (!PermissionRequester.RECORDING.hasPermission(this)) {
throw new RuntimeException("Android14: Please grant permissions LOCATION and NEARBY DEVICES (manually)");
}
}
ServiceCompat.startForeground(this, TrackRecordingServiceNotificationManager.NOTIFICATION_ID, notificationManager.setGPSonlyStarted(this), ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION + ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE);
}
@@ -20,6 +20,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Build;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
import android.os.RemoteException;
@@ -29,6 +30,7 @@ import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import de.dennisguse.opentracks.BuildConfig;
import de.dennisguse.opentracks.util.PermissionRequester;
/**
* Wrapper for the track recording service.
@@ -157,6 +159,12 @@ public class TrackRecordingServiceConnection {
}
public static void executeForeground(Context context, Callback callback) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
if (!PermissionRequester.RECORDING.hasPermission(context)) {
throw new MissingPermissionException(PermissionRequester.RECORDING);
}
}
Callback withUnbind = (service, connection) -> {
callback.onConnected(service, connection);
connection.unbind(context);
@@ -4,9 +4,11 @@ import static android.text.Spanned.SPAN_INCLUSIVE_EXCLUSIVE;
import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceAverageHeartRate;
import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceAverageSpeedPace;
import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceLapHeartRate;
import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceLapPower;
import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceLapSpeedPace;
import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceMovingTime;
import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceTotalDistance;
import static de.dennisguse.opentracks.settings.PreferencesUtils.shouldVoiceAnnounceUnit;
import android.content.Context;
import android.icu.text.MessageFormat;
@@ -22,11 +24,13 @@ import java.util.Map;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Power;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.settings.UnitSystem;
import de.dennisguse.opentracks.stats.SensorStatistics;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.ui.intervals.IntervalStatistics;
import de.dennisguse.opentracks.util.StringUtils;
class VoiceAnnouncementUtils {
@@ -44,34 +48,37 @@ class VoiceAnnouncementUtils {
Speed averageMovingSpeed = trackStatistics.getAverageMovingSpeed();
Speed currentDistancePerTime = currentInterval != null ? currentInterval.getSpeed() : null;
int perUnitStringId;
int distanceId;
int speedId;
String unitDistanceTTS;
String unitSpeedTTS;
switch (unitSystem) {
case METRIC -> {
perUnitStringId = R.string.voice_per_kilometer;
distanceId = R.string.voiceDistanceKilometersPlural;
speedId = R.string.voiceSpeedKilometersPerHourPlural;
unitDistanceTTS = "kilometer";
unitSpeedTTS = "kilometer per hour";
int perUnitStringId = R.string.empty;
int distanceId = R.string.voiceDistance;
int speedId = R.string.voiceSpeed;
String unitDistanceTTS = StringUtils.EMPTY;
String unitSpeedTTS = StringUtils.EMPTY;
if(shouldVoiceAnnounceUnit()) {
switch (unitSystem) {
case METRIC -> {
perUnitStringId = R.string.voice_per_kilometer;
distanceId = R.string.voiceDistanceKilometersPlural;
speedId = R.string.voiceSpeedKilometersPerHourPlural;
unitDistanceTTS = "kilometer";
unitSpeedTTS = "kilometer per hour";
}
case IMPERIAL_FEET, IMPERIAL_METER -> {
perUnitStringId = R.string.voice_per_mile;
distanceId = R.string.voiceDistanceMilesPlural;
speedId = R.string.voiceSpeedMilesPerHourPlural;
unitDistanceTTS = "mile";
unitSpeedTTS = "mile per hour";
}
case NAUTICAL_IMPERIAL -> {
perUnitStringId = R.string.voice_per_nautical_mile;
distanceId = R.string.voiceDistanceNauticalMilesPlural;
speedId = R.string.voiceSpeedMKnotsPlural;
unitDistanceTTS = "nautical mile";
unitSpeedTTS = "knots";
}
default -> throw new RuntimeException("Not implemented");
}
case IMPERIAL_FEET, IMPERIAL_METER -> {
perUnitStringId = R.string.voice_per_mile;
distanceId = R.string.voiceDistanceMilesPlural;
speedId = R.string.voiceSpeedMilesPerHourPlural;
unitDistanceTTS = "mile";
unitSpeedTTS = "mile per hour";
}
case NAUTICAL_IMPERIAL -> {
perUnitStringId = R.string.voice_per_nautical_mile;
distanceId = R.string.voiceDistanceNauticalMilesPlural;
speedId = R.string.voiceSpeedMKnotsPlural;
unitDistanceTTS = "nautical mile";
unitSpeedTTS = "knots";
}
default -> throw new RuntimeException("Not implemented");
}
double distanceInUnit = totalDistance.toKM_Miles(unitSystem);
@@ -154,6 +161,19 @@ class VoiceAnnouncementUtils {
builder.append(".");
}
if (shouldVoiceAnnounceLapPower() && currentInterval != null && currentInterval.hasAveragePower()) {
int currentPower = Math.round(currentInterval.getAveragePower().getW());
if(shouldVoiceAnnounceUnit()) {
String template = context.getResources().getString(R.string.power_x_watt);
builder.append(" ")
.append(MessageFormat.format(template, Map.of("x", currentPower)));
} else {
builder.append(" ").append(context.getString(R.string.power)).append(" ");
builder.append(String.valueOf(currentPower));
}
builder.append(".");
}
return builder;
}
@@ -20,6 +20,9 @@ import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.sensors.SensorConnector;
import de.dennisguse.opentracks.sensors.SensorManager;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorGPS;
import de.dennisguse.opentracks.sensors.sensorData.Raw;
import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.util.LocationUtils;
import de.dennisguse.opentracks.util.PermissionRequester;
@@ -32,6 +35,8 @@ public class GPSManager implements SensorConnector, LocationListenerCompat, GpsS
private static final String LOCATION_PROVIDER = LocationManager.GPS_PROVIDER;
private TrackPointCreator trackPointCreator;
private SensorManager.SensorDataChangedObserver listener;
private Context context;
private Handler handler;
@@ -40,8 +45,9 @@ public class GPSManager implements SensorConnector, LocationListenerCompat, GpsS
private Duration gpsInterval;
private Distance thresholdHorizontalAccuracy;
public GPSManager(TrackPointCreator trackPointCreator) {
public GPSManager(TrackPointCreator trackPointCreator, SensorManager.SensorDataChangedObserver listener) {
this.trackPointCreator = trackPointCreator;
this.listener = listener;
}
public void start(@NonNull Context context, @NonNull Handler handler) {
@@ -52,6 +58,9 @@ public class GPSManager implements SensorConnector, LocationListenerCompat, GpsS
gpsStatusManager = new GpsStatusManager(context, this, handler);
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
listener.onConnect(new AggregatorGPS("internal"));
registerLocationListener();
gpsStatusManager.start();
}
@@ -72,6 +81,9 @@ public class GPSManager implements SensorConnector, LocationListenerCompat, GpsS
gpsStatusManager.stop();
gpsStatusManager = null;
listener.onDisconnect(new AggregatorGPS("internal"));
listener = null;
trackPointCreator = null;
}
@@ -126,7 +138,7 @@ public class GPSManager implements SensorConnector, LocationListenerCompat, GpsS
return;
}
trackPointCreator.onChange(location);
listener.onChange(new Raw<>(location));
}
@Override
@@ -2,7 +2,6 @@ package de.dennisguse.opentracks.services.handlers;
import android.content.Context;
import android.content.SharedPreferences;
import android.location.Location;
import android.os.Handler;
import android.util.Log;
import android.util.Pair;
@@ -69,10 +68,6 @@ public class TrackPointCreator implements SharedPreferences.OnSharedPreferenceCh
this.context = null;
}
public synchronized void onChange(@NonNull Location location) {
onNewTrackPoint(new TrackPoint(location, createNow()));
}
/**
* Got a new TrackPoint from Bluetooth only; contains no GPS location.
*/
@@ -333,6 +333,10 @@ public class PreferencesUtils {
return getBoolean(R.string.voice_announce_idle_key, true);
}
public static boolean shouldVoiceAnnounceUnit() {
return getBoolean(R.string.voice_announce_unit_key, true);
}
public static Duration getVoiceAnnouncementFrequency() {
final int DEFAULT = Integer.parseInt(resources.getString(R.string.voice_announcement_frequency_default));
int value = getInt(R.string.voice_announcement_frequency_key, DEFAULT);
@@ -430,6 +434,10 @@ public class PreferencesUtils {
return getBoolean(R.string.voice_announce_lap_heart_rate_key, false);
}
public static boolean shouldVoiceAnnounceLapPower() {
return getBoolean(R.string.voice_announce_lap_power_key, false);
}
@VisibleForTesting
public static void setVoiceAnnounceLapHeartRate(boolean value) {
setBoolean(R.string.voice_announce_lap_heart_rate_key, value);
@@ -26,6 +26,7 @@ import java.time.Instant;
import de.dennisguse.opentracks.data.models.Altitude;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.HeartRate;
import de.dennisguse.opentracks.data.models.Power;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
@@ -60,6 +61,7 @@ public class TrackStatistics {
private Float totalAltitudeLoss_m = null;
// The average heart rate seen on this track
private HeartRate avgHeartRate = null;
private Power avgPower = null;
private boolean isIdle;
@@ -83,6 +85,7 @@ public class TrackStatistics {
totalAltitudeGain_m = other.totalAltitudeGain_m;
totalAltitudeLoss_m = other.totalAltitudeLoss_m;
avgHeartRate = other.avgHeartRate;
avgPower = other.avgPower;
isIdle = other.isIdle;
}
@@ -104,6 +107,7 @@ public class TrackStatistics {
*
* @param other another statistics data object
*/
//TODO Should be refactored to append only [mainly due to isIdle] (NOTE: This requires to use a custom value object for AggregatedStatistics; this is anyhow recommended).
public void merge(TrackStatistics other) {
if (startTime == null) {
startTime = other.startTime;
@@ -116,6 +120,8 @@ public class TrackStatistics {
stopTime = stopTime.isAfter(other.stopTime) ? stopTime : other.stopTime;
}
isIdle = other.isIdle; //TODO This implicitly assumes append mode.
if (avgHeartRate == null) {
avgHeartRate = other.avgHeartRate;
} else {
@@ -129,6 +135,19 @@ public class TrackStatistics {
}
}
if (avgPower == null) {
avgPower = other.avgPower;
} else {
if (other.avgPower != null) {
// Using total time as weights for the averaging.
// Important to do this before total time is updated
avgPower = Power.of(
(totalTime.getSeconds() * avgPower.getW() + other.totalTime.getSeconds() * other.avgPower.getW())
/ (totalTime.getSeconds() + other.totalTime.getSeconds())
);
}
}
totalDistance = totalDistance.plus(other.totalDistance);
totalTime = totalTime.plus(other.totalTime);
movingTime = movingTime.plus(other.movingTime);
@@ -270,6 +289,15 @@ public class TrackStatistics {
return avgHeartRate;
}
public boolean hasPower() {
return avgPower != null;
}
@Nullable
public Power getAveragePower() {
return avgPower;
}
/**
* Gets the average speed.
* This calculation only takes into account the displacement until the last point that was accounted for in statistics.
@@ -333,6 +361,12 @@ public class TrackStatistics {
}
}
public void setAveragePower(Power power) {
if (power != null) {
avgPower = power;
}
}
public boolean hasTotalAltitudeGain() {
return totalAltitudeGain_m != null;
}
@@ -23,8 +23,10 @@ import java.util.List;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.HeartRate;
import de.dennisguse.opentracks.data.models.Power;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.settings.PreferencesUtils;
/**
* Updater for {@link TrackStatistics}.
@@ -43,6 +45,8 @@ public class TrackStatisticsUpdater {
private float averageHeartRateBPM;
private Duration totalHeartRateDuration = Duration.ZERO;
private float averagePowerW;
private Duration totalPowerDuration = Duration.ZERO;
// The current segment's statistics
private final TrackStatistics currentSegment;
@@ -53,11 +57,6 @@ public class TrackStatisticsUpdater {
this(new TrackStatistics());
}
/**
* Creates a new{@link TrackStatisticsUpdater} with a {@link TrackStatisticsUpdater} already existed.
*
* @param trackStatistics a {@link TrackStatisticsUpdater}
*/
public TrackStatisticsUpdater(TrackStatistics trackStatistics) {
this.trackStatistics = trackStatistics;
this.currentSegment = new TrackStatistics();
@@ -84,9 +83,6 @@ public class TrackStatisticsUpdater {
trackPoints.stream().forEachOrdered(this::addTrackPoint);
}
/**
*
*/
public void addTrackPoint(TrackPoint trackPoint) {
if (trackPoint.isSegmentManualStart()) {
reset(trackPoint);
@@ -125,6 +121,17 @@ public class TrackStatisticsUpdater {
currentSegment.setAverageHeartRate(HeartRate.of(averageHeartRateBPM));
}
// Update power
if (trackPoint.hasPower() && lastTrackPoint != null) {
Duration trackPointDuration = Duration.between(lastTrackPoint.getTime(), trackPoint.getTime());
Duration newTotalDuration = totalPowerDuration.plus(trackPointDuration);
averagePowerW = (totalPowerDuration.toMillis() * averagePowerW + trackPointDuration.toMillis() * trackPoint.getPower().getW()) / newTotalDuration.toMillis();
totalPowerDuration = newTotalDuration;
currentSegment.setAveragePower(Power.of(averagePowerW));
}
{
// Update total distance
Distance movingDistance = null;
@@ -137,18 +144,23 @@ public class TrackStatisticsUpdater {
movingDistance = trackPoint.distanceToPrevious(lastTrackPoint);
}
if (movingDistance != null) {
currentSegment.setIdle(false);
currentSegment.addTotalDistance(movingDistance);
}
if (!currentSegment.isIdle() && !trackPoint.isSegmentManualStart()) {
if (lastTrackPoint != null) {
if (!currentSegment.isIdle()) {
if (!trackPoint.isSegmentManualStart() && lastTrackPoint != null) {
currentSegment.addMovingTime(trackPoint, lastTrackPoint);
}
}
if (trackPoint.getType() == TrackPoint.Type.IDLE) {
if (trackPoint.isIdleTriggered()) {
currentSegment.setIdle(true);
} else if (currentSegment.isIdle()) {
// Shall we switch to non-idle?
if (movingDistance != null
&& movingDistance.greaterOrEqualThan(PreferencesUtils.getRecordingDistanceInterval())) {
currentSegment.setIdle(false);
}
}
if (trackPoint.hasSpeed()) {
@@ -9,6 +9,7 @@ import java.util.List;
import de.dennisguse.opentracks.data.TrackPointIterator;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.HeartRate;
import de.dennisguse.opentracks.data.models.Power;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.stats.TrackStatistics;
@@ -103,6 +104,7 @@ public class IntervalStatistics {
private Float gain_m;
private Float loss_m;
private HeartRate avgHeartRate;
private Power avgPower;
public Interval() {
}
@@ -118,6 +120,7 @@ public class IntervalStatistics {
gain_m = i.gain_m;
loss_m = i.loss_m;
avgHeartRate = i.avgHeartRate;
avgPower = i.avgPower;
}
public Interval(Interval i) {
@@ -126,6 +129,7 @@ public class IntervalStatistics {
gain_m = i.gain_m;
loss_m = i.loss_m;
avgHeartRate = i.avgHeartRate;
avgPower = i.avgPower;
}
public Distance getDistance() {
@@ -160,12 +164,21 @@ public class IntervalStatistics {
return avgHeartRate;
}
public boolean hasAveragePower() {
return avgPower != null;
}
public Power getAveragePower() {
return avgPower;
}
private void add(TrackStatistics trackStatistics, @Nullable TrackPoint lastTrackPoint) {
distance = distance.plus(trackStatistics.getTotalDistance());
time = time.plus(trackStatistics.getTotalTime());
gain_m = trackStatistics.hasTotalAltitudeGain() ? trackStatistics.getTotalAltitudeGain() : gain_m;
loss_m = trackStatistics.hasTotalAltitudeLoss() ? trackStatistics.getTotalAltitudeLoss() : loss_m;
avgHeartRate = trackStatistics.getAverageHeartRate();
avgPower = trackStatistics.getAveragePower();
if (lastTrackPoint == null) {
return;
}
@@ -183,6 +196,7 @@ public class IntervalStatistics {
gain_m = trackStatistics.hasTotalAltitudeGain() ? trackStatistics.getTotalAltitudeGain() : gain_m;
loss_m = trackStatistics.hasTotalAltitudeLoss() ? trackStatistics.getTotalAltitudeLoss() : loss_m;
avgHeartRate = trackStatistics.getAverageHeartRate();
avgPower = trackStatistics.getAveragePower();
}
}
}
@@ -16,7 +16,6 @@
package de.dennisguse.opentracks.ui.markers;
import android.app.SearchManager;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
@@ -24,7 +23,7 @@ import android.view.MenuItem;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.SearchView;
import androidx.annotation.UiThread;
import androidx.recyclerview.widget.LinearLayoutManager;
import java.util.List;
@@ -48,7 +47,7 @@ import de.dennisguse.opentracks.util.IntentUtils;
*
* @author Leif Hendrik Wilden
*/
public class MarkerListActivity extends AbstractActivity {
public class MarkerListActivity extends AbstractActivity implements DeleteMarkerDialogFragment.DeleteMarkerCaller {
public static final String EXTRA_TRACK_ID = "track_id";
@@ -94,7 +93,6 @@ public class MarkerListActivity extends AbstractActivity {
}
};
private MenuItem insertMarkerMenuItem;
private MenuItem searchMenuItem;
private String searchQuery;
@@ -152,6 +150,14 @@ public class MarkerListActivity extends AbstractActivity {
@Override
protected View getRootView() {
viewBinding = MarkerListBinding.inflate(getLayoutInflater());
viewBinding.markerListSearchView.getEditText().setOnEditorActionListener((v, actionId, event) -> {
searchQuery = viewBinding.markerListSearchView.getEditText().getText().toString();
viewBinding.markerListSearchView.hide();
loadData();
return true;
});
return viewBinding.getRoot();
}
@@ -161,9 +167,6 @@ public class MarkerListActivity extends AbstractActivity {
insertMarkerMenuItem = menu.findItem(R.id.marker_list_insert_marker);
searchMenuItem = menu.findItem(R.id.marker_list_search);
ActivityUtils.configureSearchWidget(this, searchMenuItem);
return super.onCreateOptionsMenu(menu);
}
@@ -235,34 +238,10 @@ public class MarkerListActivity extends AbstractActivity {
return false;
}
@Override
public void onBackPressed() {
SearchView searchView = (SearchView) searchMenuItem.getActionView();
if (!searchView.isIconified()) {
searchView.setIconified(true);
}
if (searchQuery != null) {
searchQuery = null;
loadData();
return;
}
super.onBackPressed();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
searchQuery = intent.getStringExtra(SearchManager.QUERY);
} else {
searchQuery = null;
}
}
@UiThread
private void loadData() {
viewBinding.markerListToolbar.setText(searchQuery);
viewBinding.markerListToolbar.setTitle(Objects.requireNonNullElseGet(searchQuery, () -> getString(R.string.menu_markers)));
List<Marker> markers = contentProviderUtils.searchMarkers(trackId, searchQuery);
@@ -281,4 +260,9 @@ public class MarkerListActivity extends AbstractActivity {
private void onRecordingStatusChanged(RecordingStatus status) {
recordingStatus = status;
}
@Override
public void onMarkerDeleted() {
runOnUiThread(this::loadData);
}
}
@@ -2,42 +2,26 @@ package de.dennisguse.opentracks.ui.util;
import static android.content.Context.VIBRATOR_SERVICE;
import android.app.Activity;
import android.app.SearchManager;
import android.content.Context;
import android.os.Build;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.SearchView;
import java.time.Duration;
public class ActivityUtils {
private static final String TAG = ActivityUtils.class.getSimpleName();
public static SearchView configureSearchWidget(Activity activity, final MenuItem menuItem) {
final SearchView searchView = (SearchView) menuItem.getActionView();
SearchManager searchManager = (SearchManager) activity.getSystemService(Context.SEARCH_SERVICE);
if (searchManager != null) {
//NOTE: Use searchManager.getSearchableInfo(new ComponentName(activity, SearchActivity.class)) if another activity should handle the search
searchView.setSearchableInfo(searchManager.getSearchableInfo(activity.getComponentName()));
} else {
Log.w(TAG, "Could not retrieve SearchManager.");
}
searchView.setSubmitButtonEnabled(true);
return searchView;
}
public static void vibrate(@NonNull Context context, int milliseconds) {
public static void vibrate(@NonNull Context context, Duration duration) {
final Vibrator vibrator = (Vibrator) context.getSystemService(VIBRATOR_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
vibrator.vibrate(VibrationEffect.createOneShot(milliseconds, VibrationEffect.DEFAULT_AMPLITUDE));
vibrator.vibrate(VibrationEffect.createOneShot(duration.toMillis(), VibrationEffect.DEFAULT_AMPLITUDE));
} else {
vibrator.vibrate(milliseconds);
vibrator.vibrate(duration.toMillis());
}
}
@@ -95,7 +95,7 @@ public class PermissionRequester {
ArrayList<String> recording = new ArrayList<>(GPS_PERMISSION);
recording.addAll(BLUETOOTH_PERMISSIONS);
RECORDING_PERMISSIONS = Collections.unmodifiableList(recording);
RECORDING_PERMISSIONS = Collections.unmodifiableList(new ArrayList<>(recording));
recording.addAll(NOTIFICATION_PERMISSIONS);
@@ -57,6 +57,7 @@ import de.dennisguse.opentracks.settings.UnitSystem;
public class StringUtils {
private static final String TAG = StringUtils.class.getSimpleName();
public static final String EMPTY = "";
private StringUtils() {
}
+12 -2
View File
@@ -22,14 +22,24 @@ limitations under the License.
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
<com.google.android.material.search.SearchBar
android:id="@+id/marker_list_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="@drawable/ic_marker_show_24dp"
app:title="@string/menu_markers" />
app:layout_behavior="@string/searchbar_scrolling_view_behavior"
app:menu="@menu/marker_list" />
</com.google.android.material.appbar.AppBarLayout>
<com.google.android.material.search.SearchView
android:id="@+id/marker_list_search_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="@string/menu_search"
app:layout_anchor="@id/marker_list_toolbar">
<!-- Search suggestions/results go here (ScrollView, RecyclerView, etc.). -->
</com.google.android.material.search.SearchView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
+11 -2
View File
@@ -22,15 +22,24 @@ limitations under the License.
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
<com.google.android.material.search.SearchBar
android:id="@+id/track_list_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="@drawable/ic_logo_color_24dp"
app:title="@string/app_name"
app:layout_behavior="@string/searchbar_scrolling_view_behavior"
app:menu="@menu/track_list" />
</com.google.android.material.appbar.AppBarLayout>
<com.google.android.material.search.SearchView
android:id="@+id/track_list_search_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="@string/menu_search"
app:layout_anchor="@id/track_list_toolbar">
<!-- Search suggestions/results go here (ScrollView, RecyclerView, etc.). -->
</com.google.android.material.search.SearchView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
+1 -6
View File
@@ -17,12 +17,7 @@ limitations under the License.
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/marker_list_insert_marker"
android:icon="@drawable/ic_marker_show_24dp"
android:icon="@drawable/ic_marker_add_24dp"
android:title="@string/menu_insert_marker"
app:showAsAction="ifRoom" />
<item
android:id="@+id/marker_list_search"
android:title="@string/menu_search"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="ifRoom" />
</menu>
+2 -7
View File
@@ -15,12 +15,6 @@ limitations under the License.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<!-- TODO SearchAction is only working if it is shown as action. However, only two slots are available. See #757. -->
<item
android:id="@+id/track_list_search"
android:title="@string/menu_search"
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="ifRoom" />
<item
android:id="@+id/track_list_markers"
android:icon="@drawable/ic_marker_show_24dp"
@@ -29,7 +23,8 @@ limitations under the License.
<item
android:id="@+id/track_list_settings"
android:icon="@drawable/ic_settings_24dp"
android:title="@string/menu_settings" />
android:title="@string/menu_settings"
app:showAsAction="ifRoom" />
<item
android:id="@+id/track_list_help"
android:icon="@drawable/ic_help_24dp"
+11 -4
View File
@@ -37,12 +37,12 @@ limitations under the License.
<string name="help_storage_pictures_title">Jak ukládá OpenTracks obrázky pořízené jako značky na cestě\?</string>
<string name="help_storage_pictures_content">Jsou uloženy v interním úložišti aplikace (tj. přístupné pouze v rámci OpenTracks).</string>
<string name="help_track_export_title">Jak mohu exportovat/sdílet zaznamenané stopy\?</string>
<string name="help_track_export_content"> \u0020Trasy lze exportovat z Nastavení jako KMZ, KML nebo GPX. \u0020KMZ a KML obsahuje všechna data, GPX pouze polohu. \u0020Trasy sdílené pomocí <i>ikony sdílení</i> jsou sdíleny jako KMZ. \u0020</string>
<string name="help_track_export_content"> Trasy lze exportovat z Nastavení jako KMZ, KML nebo GPX. KMZ a KML obsahuje všechna data, GPX pouze polohu. Trasy sdílené pomocí <i>ikony sdílení</i> jsou sdíleny jako KMZ. </string>
<string name="help_data_google_play_services_title">Vyžaduje/používá OpenTracks službu Google Play\?</string>
<string name="help_recording_title">Jak OpenTracks zaznamenává data?</string>
<string name="help_recording_content">OpenTracks používá GPS senzor zařízení k nepřetržitému zaznamenávání polohy. Pokud zařízení GPS hlásí nepřesná data (např. polohu, rychlost, nadmořskou výšku), OpenTracks s tím nemůže nic udělat.</string>
<string name="help_data_storage_title">Jak OpenTracks ukládá data ze senzorů\?</string>
<string name="help_data_storage_content"> \u0020Data senzoru se ukládají na zaznamenané místo. \u0020Pokud jde o snímač srdeční frekvence, znamená to, že na každé místo je uloženo pouze <i> jedno </i> měření srdeční frekvence. \u0020Pokud stojíte v klidu nebo jste uvnitř, nebudou zaznamenána žádná data ze senzorů (ale budou zobrazena). \u0020</string>
<string name="help_data_storage_content"> Data senzorů se ukládají na zaznamenané místo. Pokud jde o snímač srdeční frekvence, znamená to, že na každé místo je uloženo pouze <i>jedno</i> měření srdeční frekvence. Pokud stojíte v klidu nebo jste uvnitř, nebudou zaznamenána žádná data ze senzorů (ale budou zobrazena). </string>
<string name="help_gps_troubleshooting_title">OpenTracks nezaznamenává místa?</string>
<string name="help_gps_troubleshooting_content"> \u0020Co můžete udělat:
\n \u0020a) zkontrolujte zda je zapnuta GPS,
@@ -419,14 +419,14 @@ limitations under the License.
<item quantity="other">Ukončeno s %1$d chybami</item>
</plurals>
<string name="import_progress_summary_errors_msg">Chyba</string>
<string name="settings_prevent_reimport_tracks_title">Zabraňte opětovnému importu aktivit</string>
<string name="settings_prevent_reimport_tracks_title">Zabránit opětov. importu stop</string>
<string name="export_progress_summary_errors_msg">Chyba</string>
<string name="export_progress_summary_skip_msg">Soubory přeskočeny</string>
<string name="export_progress_summary_overwrite_msg">Soubory přepsány</string>
<string name="export_progress_summary_new_msg">Nové soubory exportovány</string>
<string name="import_progress_summary_exists_msg">Existovat</string>
<string name="import_progress_summary_ok_msg">Importované soubory</string>
<string name="generic_open_track">Otevřená trať</string>
<string name="generic_open_track">Otevřít stopu</string>
<string name="sensor_state_power_avg">Prům. výkon</string>
<string name="sensor_state_heart_rate_max">Maximální srdeční frekvence</string>
<string name="sensor_state_heart_rate_avg">Avg srdeční frekvence</string>
@@ -601,4 +601,11 @@ limitations under the License.
<string name="settings_recording_location_distance_summary">%1$s mezi zaznamenanými polohami</string>
<string name="settings_theme_switch_restart">Změna motivu může vyžadovat ruční restart.</string>
<string name="settings_night_mode_option_night_oled">Noční (OLED)</string>
<string name="settings_announcements_unit">Jednotka vzdálenosti/rychlosti</string>
<string name="voiceSpeed">{n, plural, =1 {1} few {{n,number}} other {{n,number,#.0}} }</string>
<string name="voiceDistance">{n, plural, =1 {1 } few {{n,number}} other {{n,number,#.0}} }</string>
<string name="voice_announce_lap_power_key">voiceAnnounceLapPower</string>
<string name="power">Výkon</string>
<string name="settings_announcements_lap_power">Výkon kola</string>
<string name="power_x_watt">Výkon {x, plural, =1 {1 watt} few {# watty} other {# wattů} }</string>
</resources>
+1 -1
View File
@@ -16,7 +16,7 @@ limitations under the License.
--><resources>
<string name="about_preference_title">Om OpenTracks</string>
<string name="about_description"><i> OpenTracks </i> er en sportstracker, der fuldt ud respekterer dit privatliv.</string>
<string name="about_url">Projekthjemmeside: <a href="%1$s">%1$s</a></string>
<string name="about_url">Projektets hjemmeside: <a href="%1$s">%1$s</a></string>
<string name="about_version_name">Versionsnavn: %1$s</string>
<string name="about_version_code">Versionskode: %1$d</string>
<string name="about_history">OpenTracks er en forgrening fra <a href="https://code.google.com/archive/p/mytracks/"> <i> Googles MyTracks </i> </a> (afviklet i 2016).</string>
+33 -10
View File
@@ -23,13 +23,12 @@ limitations under the License.
<string name="about_libraries">Bibliotheken</string>
<!-- Help -->
<string name="help_feature_title">OpenTracks hat die folgenden Funktionen:</string>
<string name="help_feature_content">
* GPS-Tracks erstellen\n
* einen Herzfrequenzsensor verwenden (nur Bluetooth LE)\n
* Sprachansagen (nach Zeit oder Entfernung)\n
* Markierungen erstellen (inkl. Bilder)\n
* arbeitet vollständig offline\n
* Tracks auf einer Karte anzeigen (siehe unten)</string>
<string name="help_feature_content">* GPS-Tracks erstellen
\n* einen Herzfrequenzsensor verwenden (nur Bluetooth LE)
\n* Sprachansagen (nach Zeit oder Entfernung)
\n* Markierungen erstellen (inkl. Bilder)
\n* arbeitet vollständig offline
\n* 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_content"> Verwende das kleine Kartensymbol.
\n a) (Live-Aktualisierungen) Installiere <a href="https://github.com/OpenTracksApp/OSMDashboard">OSMDashboard</a>. OSMDashboard stellt Online- oder Offline-Karten über <a href="https://www.openstreetmap.org">OpenStreetMap</a>.
@@ -243,7 +242,7 @@ Meldet das GPS-Gerät ungenaue Daten (z.B. Standort, Geschwindigkeit, Höhe), ka
<string name="settings_recording_keep_screen_on_while_recording_title">Bildschirm eingeschaltet lassen</string>
<string name="settings_recording_keep_screen_on_while_recording_summary">Lasse während der Aufnahme den Bildschirm eingeschaltet.</string>
<string name="settings_recording_default_activity_title">Standardaktivität</string>
<string name="settings_recording_location_frequency_summary">Entfernungs-/Zeitintervall %1$s zwischen zwei Standortaufzeichnungen</string>
<string name="settings_recording_location_frequency_summary">%1$s zwischen Standort Überprüfungen</string>
<string name="settings_recording_max_recording_distance_summary">Ein neues Segment wird erstellt, wenn die Entfernung zwischen zwei Standorten mehr als %1$s beträgt</string>
<string name="settings_recording_max_recording_distance_title">Max. Entfernung</string>
<string name="settings_recording_min_recording_distance_title">Aufzeichnungsintervall</string>
@@ -490,7 +489,7 @@ Meldet das GPS-Gerät ungenaue Daten (z.B. Standort, Geschwindigkeit, Höhe), ka
<string name="menu_select_layout">Wähle Layout</string>
<string name="generic_choose_an_option">Wähle eine Option</string>
<string name="settings_gps_sensor">GPS</string>
<string name="settings_import_export_title">Import/Export</string>
<string name="settings_import_export_title">Import und Export</string>
<string name="settings_sensors_title">Sensoren</string>
<string name="settings_sensors_summary">Fahrradsensoren, Radumfang und Lauf-Sensoren</string>
<string name="settings_announcements_statistics_title">Sprachansagen</string>
@@ -532,7 +531,7 @@ Meldet das GPS-Gerät ungenaue Daten (z.B. Standort, Geschwindigkeit, Höhe), ka
<string name="export_dir_not_writable">" (nicht schreibbar)"</string>
<string name="stats_clock">Uhr</string>
<string name="image_discard">Verwerfen</string>
<string name="settings_announcements_distance_frequency">Entfernungsintervall</string>
<string name="settings_announcements_distance_frequency">Runden Länge</string>
<string name="settings_public_api_enabled_title">Öffentliche API</string>
<string name="track_discarding">Verwerfe Track</string>
<string name="average_heart_rate">Durchschnittlicher Puls</string>
@@ -618,4 +617,28 @@ Meldet das GPS-Gerät ungenaue Daten (z.B. Standort, Geschwindigkeit, Höhe), ka
<string name="settings_recording_min_required_accuracy_summary">Ort wird ignoriert wenn seine Genauigkeit über %1$s liegt</string>
<string name="settings_sensor_bluetooth_service_filter_title">Bluetooth Geräte filtern</string>
<string name="settings_sensor_bluetooth_service_filter_off">Alle verfügbaren Bluetooth Geräte anzeigen</string>
<string name="settings_theme_switch_restart">Themenänderungen können einen manuellen Neustart erfordern.</string>
<string name="settings_recording_idle_timeout_title">Stillstand Schwelle</string>
<string name="settings_night_mode_option_night_oled">Nacht (OLED freundlich)</string>
<string name="sensor_state_pressure">Barometer</string>
<string name="bluetooth_sensor_summary">%1$s (%2$s)</string>
<string name="settings_announcements_idle_category_title">Stillstand Benachrichtigung</string>
<string name="settings_announcements_idle_title">Stillstand</string>
<string name="settings_ui_dynamic_colors_title">Dynamische Farben</string>
<string name="value_internal_sensor">Interner Sensor</string>
<string name="permission_recording_failed">OpenTracks benötigt die Berechtigubg, auf Ihren Standort sowie nahe gelegene Geräte zuzugreifen.</string>
<string name="sensor_state_power_max">Maximale Leistung</string>
<string name="sensor_state_power_unit">W</string>
<string name="settings_recording_title">Aufnahme</string>
<string name="settings_ui_dynamic_colors_summary">Verwenden Sie benutzerdefinierte dynamische Farben (nur Android 12+; erfordert einen manuellen Neustart)</string>
<string name="value_int_seconds">%1$d s (empfohlen)</string>
<string name="sensor_state_cadence_unit">Drehzahl</string>
<string name="sensor_state_heart_rate_unit">bpm</string>
<string name="activity_type_kickscooter">Roller</string>
<string name="settings_recording_location_distance_summary">%1$s zwischen aufgezeichneten Orten</string>
<string name="voiceSpeedMKnotsPlural">{n, plural, =1 {1 Knoten} other {{n,number,#.0} Knoten} }</string>
<string name="voiceSpeed">{n, plural, =1 {1} other {{n,number,#.0}} }</string>
<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>
</resources>
+4 -1
View File
@@ -520,7 +520,7 @@ limitations under the License.
<string name="settings_gps_sensor">GPS</string>
<string name="settings_announcements_statistics_title">Avisos de voz</string>
<string name="settings_units_category">Unidades</string>
<string name="settings_import_export_title">Importar/Exportar</string>
<string name="settings_import_export_title">Importar y exportar</string>
<string name="stats_custom_layout_default_layout">Diseño predeterminado</string>
<string name="custom_layout_select_layout">Seleccionar diseño</string>
<string name="custom_layout_list_edit_already_exists">El nombre de este diseño ya existe</string>
@@ -654,4 +654,7 @@ limitations under the License.
<string name="bluetooth_sensor_summary">%1$s (%2$s)</string>
<string name="settings_recording_min_sampling_interval_title">Intervalo de muestreo</string>
<string name="settings_recording_location_distance_summary">%1$s entre lugares registrados</string>
<string name="settings_theme_switch_restart">Los cambios del tema pueden requerir un reinicio manual.</string>
<string name="settings_night_mode_option_night_oled">Oscuro (compatible con OLED)</string>
<string name="settings_announcements_unit">Unidad de distancia/velocidad</string>
</resources>
+6 -7
View File
@@ -23,13 +23,12 @@ limitations under the License.
<string name="about_libraries">Liburutegiak</string>
<!-- Help -->
<string name="help_feature_title">OpenTracks ek ezaugarri hauek ditu:</string>
<string name="help_feature_content">
* GPS ibilbideak sortu\n
* erabili bihotz-maiztasuneko sentsorea (Bluetooth LE soilik)\n
* ahots iragarpenak (denboraren edo distantziaren arabera)\n
* Sortu markatzaileak (irudiak barne)\n
* guztiz lineaz kanpo funtzionatzen du\n
* Erakutsi ibilbideak mapa batean (ikusi azpian)</string>
<string name="help_feature_content">* GPS ibilbideak sortu
\n * erabili bihotz-maiztasuneko sentsorea (Bluetooth LE soilik)
\n * ahots iragarpenak (denboraren edo distantziaren arabera)
\n * Sortu markatzaileak (irudiak barne)
\n * guztiz lineaz kanpo funtzionatzen du
\n * 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_content"> Erabili maparen ikono txikia.
\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>.
+6 -7
View File
@@ -23,13 +23,12 @@ limitations under the License.
<string name="about_libraries">Kirjastot</string>
<!-- Help -->
<string name="help_feature_title">OpenTracksissa on seuraavat ominaisuudet:</string>
<string name="help_feature_content">
* luo GPS-reittejä\n
* käytä sykeanturia (vain Bluetooth LE)\n
* ääni-ilmoitukset (ajan tai etäisyyden perusteella)\n
* luo merkkejä (mukaan lukien kuvia)\n
* toimii täysin ilman verkkoyhteyttä\n
* näytä jäljet kartalla (ks. alla)</string>
<string name="help_feature_content">* luo GPS-reittejä
\n * käytä sykeanturia (vain Bluetooth LE)
\n * ääni-ilmoitukset (ajan tai etäisyyden perusteella)
\n * luo merkkejä (mukaan lukien kuvia)
\n * toimii täysin ilman verkkoyhteyttä
\n * näytä jäljet kartalla (ks. alla)</string>
<string name="help_track_map_title">Miten näyttää rata kartalla\?</string>
<string name="help_track_map_content"> Käytä pientä karttakuvaketta.
\n a) (live-päivityksiä) Asenna <a href="https://github.com/OpenTracksApp/OSMDashboard">OSMDashboard</a>. Se tarjoaa online-tai offline-karttoja kautta <a href="https://www.openstreetmap.org">OpenStreetMap</a>.
+31 -10
View File
@@ -16,7 +16,7 @@ limitations under the License.
--><resources>
<string name="about_preference_title">À propos d\'OpenTracks</string>
<string name="about_description"><i>OpenTracks</i> est une application de suivi sportif qui respecte totalement votre vie privée.</string>
<string name="about_url">Page web du projet : <a href="%1$s">%1$s</a></string>
<string name="about_url">Page web du projet : <a href="%1$s">%1$s</a></string>
<string name="about_version_name">Nom de la version : %1$s</string>
<string name="about_version_code">Code de version : %1$d</string>
<string name="about_history">OpenTracks est une bifurcation de <a href="https://code.google.com/archive/p/mytracks/"><i>Google\'s MyTracks</i></a> (abandonné en 2016).</string>
@@ -30,10 +30,10 @@ limitations under the License.
\n* Fonctionne complètement hors ligne
\n* Affichage des traces sur une carte (voir ci-dessous)</string>
<string name="help_track_map_title">Comment afficher un tracé sur une carte \?</string>
<string name="help_track_map_content"> Utilisez la petite icône en forme de carte.
\na) (Actualisation en direct) Installez <a href="https://github.com/OpenTracksApp/OSMDashboard">OSMDashboard</a>. Il fournit des cartes en ligne ou hors ligne grâce à <a href="https://www.openstreetmap.org ">OpenStreetMap</a>.
\nOSMDashboard est en réalité une application séparée qui n\'accéder (temporairement) qu\'aux données des tracés qui vont être affichées.
\nb) Via une application cartographique standard (p. ex. <a href="http://osmand.net/">OsmAnd</a> ou <a href="https://maps.me/">MAPS.ME</a> ). L’application doit prendre en charge le format de fichier KMZ (uniquement les lieux et les horodatages). Plus précisément, l\'application doit prendre en charge <i>ACTION_VIEW</i> avec le type MIME <i>application/vnd.google-earth.kmz</i>. </string>
<string name="help_track_map_content"> \u0020Utilisez la petite icône en forme de carte.
\n \u0020 \u0020a) \u0020 \u0020(Actualisation en direct) Installez <a href="https://github.com/OpenTracksApp/OSMDashboard">OSMDashboard</a>. \u0020 \u0020Il fournit des cartes en ligne ou hors ligne grâce à <a href="https://www.openstreetmap.org ">OpenStreetMap</a>.
\n \u0020 \u0020OSMDashboard est en réalité une application séparée qui n\'accéder (temporairement) qu\'aux données des tracés qui vont être affichées. \u0020
\n \u0020 \u0020b) \u0020 Via une application cartographique standard (p. ex. <a href="http://osmand.net/">OsmAnd</a> ou <a href="https://maps.me/">MAPS.ME</a> ). \u0020 L’application doit prendre en charge le format de fichier KMZ (uniquement les lieux et les horodatages). \u0020 Plus précisément, l\'application doit prendre en charge <i>ACTION_VIEW</i> avec le type MIME <i>application/vnd.google-earth.kmz</i>. \u0020</string>
<string name="help_storage_pictures_title">Comment OpenTracks stocke-t-il les photos qui ont été prises en tant que repère \?</string>
<string name="help_storage_pictures_content">Elles sont enregistrées dans le stockage interne de l\'application (c\'est-à-dire uniquement accessible dans OpenTracks).</string>
<string name="help_track_export_title">Comment puis-je exporter/partager des tracés enregistrées \?</string>
@@ -143,8 +143,8 @@ Si le dispositif GPS signale des données inexactes (par exemple, la localisatio
<string name="description_max_speed">Vitesse max. : %1$.2f km/h (%2$.1f mi/h)</string>
<string name="description_min_altitude">Élévation min. : %1$d m (%2$d pi)</string>
<string name="description_moving_time">Durée en déplacement : %1$s</string>
<string name="description_pace_imperial">Vitesse (min/mi)</string>
<string name="description_pace_metric">Vitesse (min/km)</string>
<string name="description_pace_imperial">Allure (min/mi)</string>
<string name="description_pace_metric">Allure (min/km)</string>
<string name="description_recorded_time">Date d\'enregistrement : %1$s</string>
<string name="description_speed_ms">Vitesse (m/s)</string>
<string name="description_sensor_cadence">Cadence (tr/min)</string>
@@ -410,7 +410,7 @@ Si le dispositif GPS signale des données inexactes (par exemple, la localisatio
<!-- Share image -->
<string name="share_image_subject">J aimerais partager une image avec vous</string>
<string name="share_image_body">Je pense que cette image pourrait vous intéresser.</string>
<string name="track_pace_notification">Vitesse : %1$s</string>
<string name="track_pace_notification">Allure : %1$s</string>
<string name="track_speed_notification">Vitesse : %1$s</string>
<string name="track_detail_intervals_tab">Intervalles</string>
<string name="interval_list_empty_message">Il n\'y a pas encore d\'intervalle</string>
@@ -494,12 +494,12 @@ Si le dispositif GPS signale des données inexactes (par exemple, la localisatio
<string name="settings_announcements_totaltime_frequency">Intervalle de temps</string>
<string name="settings_announcements_distance_frequency">Intervalle de distance</string>
<string name="settings_layout_reset_confirm_title">Réinitialiser vos dispositions \?</string>
<string name="settings_layout_reset_done">Tous les paramètres pas défaut sont revenus à leur valeur par défaut</string>
<string name="settings_layout_reset_done">Tous les paramètres par défaut sont revenus à leur valeur par défaut</string>
<string name="settings_all_reset">Réinitialiser</string>
<string name="location_coordinate">%1$s°</string>
<string name="location_latitude_longitude">%1$s, %2$s</string>
<string name="permission_bluetooth_failed">OpenTracks a besoin de la permission d\'utiliser le Bluetooth.</string>
<string name="settings_recording_customize_layout_select_columns">Champs de données pas rangée</string>
<string name="settings_recording_customize_layout_select_columns">Champs de données par rangée</string>
<string name="field_set_primary">Principal</string>
<string name="value_float_kilometer_hour_recommended">%1$.1f km/h (recommandé)</string>
<string name="value_float_mile_hour">%1$.1f mi/h</string>
@@ -637,4 +637,25 @@ Si le dispositif GPS signale des données inexactes (par exemple, la localisatio
<string name="settings_sensor_heart_rate_max">Zones : fréquence cardiaque maximale (bpm)</string>
<string name="settings_sensor_bluetooth_service_filter_title">Filtrer les périphériques Bluetooth</string>
<string name="settings_sensor_bluetooth_service_filter_off">Afficher tout les périphériques Bluetooth découverts</string>
<string name="settings_recording_location_distance_summary">%1$s entre chaque localisation enregistrée</string>
<string name="sensor_state_pressure">Baromètre</string>
<string name="sensor_state_power_max">Puissance maximale</string>
<string name="sensor_state_power_unit">W</string>
<string name="bluetooth_sensor_summary">%1$s (%2$s)</string>
<string name="settings_announcements_idle_category_title">Alertes de mise en veille</string>
<string name="settings_recording_title">Enregistrement</string>
<string name="settings_theme_switch_restart">Le changement de thème peut nécessiter un redémarrage manuel.</string>
<string name="settings_ui_dynamic_colors_summary">Utiliser des couleurs dynamiques définies par l\'utilisateur (Android 12+ uniquement ; requiert un redémarrage manuel)</string>
<string name="settings_recording_idle_timeout_title">Délai avant mise en veille</string>
<string name="settings_night_mode_option_night_oled">Sombre (compatible OLED)</string>
<string name="settings_announcements_unit">Unité de Distance/Vitesse</string>
<string name="value_internal_sensor">Capteur interne</string>
<string name="value_int_seconds">%1$d s (recommandé)</string>
<string name="voiceIdle">Mise en veille.</string>
<string name="settings_recording_min_sampling_interval_title">Fréquence d\'échantillonnage</string>
<string name="sensor_state_cadence_unit">rpm</string>
<string name="sensor_state_heart_rate_unit">bpm</string>
<string name="settings_announcements_idle_title">En veille</string>
<string name="settings_ui_dynamic_colors_title">Couleurs dynamiques</string>
<string name="permission_recording_failed">OpenTracks a besoin de la permission d\'accéder à votre localisation ainsi qu\'aux appareils à proximité.</string>
</resources>
+33 -27
View File
@@ -24,49 +24,49 @@ limitations under the License.
<!-- Help -->
<string name="help_feature_title">Características de OpenTracks:</string>
<string name="help_feature_content">* crear rutas GPS
\n * usar monitor do pulso cardíaco (só Bluetooth LE)
\n * anuncios por voz (de tempo ou distancia)
\n * crear marcadores (incl. fotos)
\n * funciona sen precisar conexión á rede
\n * mostra as rutas nun mapa (ver abaixo)</string>
\n* usar monitor do pulso cardíaco (só Bluetooth LE)
\n* anuncios por voz (de tempo ou distancia)
\n* crear marcadores (incl. fotos)
\n* funciona sen precisar conexión á rede
\n* mostra as rutas nun mapa (ver abaixo)</string>
<string name="help_track_map_title">Como mostrar a ruta no mapa\?</string>
<string name="help_track_map_content"> Usa a icona do mapa pequeno.
\n a) (actualizacións en directo) Instala <a href="https://github.com/OpenTracksApp/OSMDashboard">OSMDashboard</a>. Proporciona mapas en liña ou sen conexión grazas a <a href="https://www.openstreetmap.org">OpenStreetMap</a>.
\n En realidade, OSMDashboard é unha aplicación independente que só pode acceder (temporalmente) aos datos das pistas que se amosarán.
\n b) A través dunha aplicación de mapa normal (por exemplo, <a href="http://osmand.net/">OsmAnd</a> e <a href="https://maps.me/">MAPS.ME</a>). Estas aplicacións precisan admitir o formato de ficheiro KMZ (só localizacións e marcas de tempo). De feito, unha aplicación ten que admitir <i>ACTION_VIEW</i> con MIME <i>application/vnd.google-earth.kmz</i>. </string>
<string name="help_track_map_content"> \u0020Usa a icona do mapa pequeno.
\n a) (actualizacións en directo) Instala <a href="https://github.com/OpenTracksApp/OSMDashboard">OSMDashboard</a>. Proporciona mapas en liña ou sen conexión grazas a <a href="https://www.openstreetmap.org">OpenStreetMap</a>.
\n En realidade, OSMDashboard é unha aplicación independente que só pode acceder (temporalmente) aos datos das pistas que se amosarán.
\n b) A través dunha aplicación de mapa normal (por exemplo, <a href="http://osmand.net/">OsmAnd</a> e <a href="https://maps.me/">MAPS.ME</a>). Estas aplicacións precisan admitir o formato de ficheiro KMZ (só localizacións e marcas de tempo). De feito, unha aplicación ten que admitir <i>ACTION_VIEW</i> con MIME <i>application/vnd.google-earth.kmz</i>. \u0020</string>
<string name="help_storage_pictures_title">De que xeito garda OpenTracks as fotos tomadas como marcadores\?</string>
<string name="help_storage_pictures_content">Gárdanse na almacenaxe interna da app (só accesible desde OpenTracks).</string>
<string name="help_track_export_title">De que xeito exporto/importo as rutas gravadas\?</string>
<string name="help_track_export_content"> \u0020As rutas pódense exportar desde os Axustes como KMZ, KML ou GPX. \u0020KMZ/KML inclúe todos os datos; GPX só localización. \u0020As rutas compartidas a través da <i>icona compartir</i> compártense como KMZ. \u0020</string>
<string name="help_track_export_content"> As rutas pódense exportar desde os Axustes como KMZ, KML ou GPX. KMZ/KML inclúe todos os datos; GPX só localización. As rutas compartidas a través da <i>icona compartir</i> compártense como KMZ. </string>
<string name="help_data_google_play_services_title">OpenTracks precisa/utiliza Google Play Service\?</string>
<string name="help_recording_title">Como grava OpenTracks os datos\?</string>
<string name="help_recording_content">
OpenTracks usa o sensor GPS do dispositivo para gravar a localización de xeito contínuo.
Se o GPS informa sobre datos pouco precisos (ex.: localización, velocidade, elevación), OpenTracks non pode facer nada ao respecto.</string>
<string name="help_data_storage_title">De que xeito garda OpenTracks os datos dos sensores\?</string>
<string name="help_data_storage_content"> \u0020Os datos dos sensores gárdanse asociados á localización. \u0020 Respecto do ritmo cardíaco, significa que só se garda <i>unha medida</i> asociada a unha localización. \u0020 Se te detés ou estás en interiores, non se gardarán datos do sensor (mais serán mostrados). \u0020</string>
<string name="help_data_storage_content"> Os datos dos sensores gárdanse asociados á localización. Respecto do ritmo cardíaco, significa que só se garda <i>unha medida</i> asociada a unha localización. \u0020Se te detés ou estás en interiores, non se gardarán datos do sensor (mais serán mostrados). </string>
<string name="help_gps_troubleshooting_title">OpenTracks non grava as localizacións\?</string>
<string name="help_gps_troubleshooting_content"> Podes intentar:
\n a) mira que o GPS esté activado,
\n b) mellora a recepción GPS (ex. sae ao exterior),
\n c) comprobaa coa app <a href="https://f-droid.org/en/packages/com.android.gpstest.osmdroid/">GPSTest</a>, e
\n d) desactiva o aforro de enerxía.
\n
\n Se isto non axuda, infórmanos do problema. </string>
<string name="help_gps_troubleshooting_content"> \u0020Podes intentar:
\n a) mira que o GPS esté activado,
\n b) mellora a recepción GPS (ex. sae ao exterior),
\n c) comprobaa coa app <a href="https://f-droid.org/en/packages/com.android.gpstest.osmdroid/">GPSTest</a>, e
\n d) desactiva o aforro de enerxía.
\n
\n Se isto non axuda, infórmanos do problema. \u0020</string>
<string name="help_support_title">Como podo axudar a OpenTracks\?</string>
<string name="help_support_content"> Podes:
\n a) falar de OpenTracks coas túas amizades,
\n b) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">propoñer novas funcións</a>,
\n c) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">informar de fallos</a>,
\n d) axudar no desenvolvemento,
\n e) mercar a app na <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore">Google Play Store</a>,
\n f) facer unha doazón, e
\n g) calquera cousa que estimes axuda a OpenTracks. </string>
<string name="help_support_content"> \u0020Podes:
\n a) falar de OpenTracks coas túas amizades,
\n b) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">propoñer novas funcións</a>,
\n c) <a href="https://github.com/OpenTracksApp/OpenTracks/issues">informar de fallos</a>,
\n d) axudar no desenvolvemento,
\n e) mercar a app na <a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore">Google Play Store</a>,
\n f) facer unha doazón, e
\n g) calquera cousa que estimes axuda a OpenTracks. \u0020</string>
<string name="open_track_as_trackfileformat">Abrir como %1$s</string>
<!-- Activity Type -->
<string name="activity_type_airplane">avión</string>
<string name="activity_type_atv">Quad</string>
<string name="activity_type_biking">ciclismo</string>
<string name="activity_type_biking">ir en bici</string>
<string name="activity_type_blimp">dirixible</string>
<string name="activity_type_boat">barco</string>
<string name="activity_type_climbing">escalada</string>
@@ -603,4 +603,10 @@ Se o GPS informa sobre datos pouco precisos (ex.: localización, velocidade, ele
<string name="settings_recording_location_distance_summary">%1$s entre posicións gravadas</string>
<string name="settings_theme_switch_restart">Os cambios de decorado poderían requerir reinicio.</string>
<string name="settings_night_mode_option_night_oled">Noite (para OLED)</string>
<string name="settings_announcements_unit">Unidades de distancia/velocidade</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_announcements_lap_power">Potencia na volta</string>
<string name="power">Potencia</string>
<string name="power_x_watt">Potencia {x, plural, =1 {1 watio} other {# watios} }</string>
</resources>
+5 -1
View File
@@ -558,7 +558,7 @@ limitations under the License.
<string name="report_bug">Hibajelentés</string>
<string name="select_show_on_map_behavior">A „megjelenítés a térképen” viselkedés választása</string>
<string name="image_discard">Eldobás</string>
<string name="settings_import_export_title">Importálás/exportálás</string>
<string name="settings_import_export_title">Importálás és exportálás</string>
<string name="generic_undo">Visszavonás</string>
<string name="settings_sensor_heart_rate_max">Zónák: maximális pulzusszám (bpm)</string>
<string name="settings_public_api_disabled_toast">Az OpenTracks nyilvános API-ja le van tiltva: a beállításokban engedélyezhető.</string>
@@ -596,4 +596,8 @@ limitations under the License.
<string name="help_data_google_play_services_content">Nem</string>
<string name="settings_theme_switch_restart">A témaváltoztatások kézi újraindítást igényelnek.</string>
<string name="settings_night_mode_option_night_oled">Éjszaka (kímélő OLED)</string>
<string name="settings_announcements_unit">Távolság/sebesség egység</string>
<string name="power">Erő</string>
<string name="voiceSpeed">{n,number,#.0}</string>
<string name="settings_announcements_lap_power">Kör teljesítmény</string>
</resources>
+5
View File
@@ -306,10 +306,15 @@ limitations under the License.
<string name="waypoint_type_water_fountain">噴水</string>
<string name="waypoint_type_waypoint">地点</string>
<string name="help_feature_content">"* GPS トラックを作成します
\n
\n * 心拍センサーを使用します (Bluetooth LE のみ)
\n
\n * 音声アナウンス(時間または距離)
\n
\n * マーカーの作成 (写真を含む)
\n
\n * 完全にオフラインで動作します
\n
\n * 地図上にトラックを表示します (下記を参照)"</string>
<string name="help_data_google_play_services_content">いいえ</string>
</resources>
+20 -3
View File
@@ -175,7 +175,7 @@ limitations under the License.
<string name="settings_chart_by_distance">Etter avstand</string>
<string name="settings_chart_by_time">Etter tid</string>
<string name="settings_recording_default_activity_title">Forvalgt aktivitetstype</string>
<string name="settings_recording_location_frequency_summary">%1$s mellom registrerte posisjoner</string>
<string name="settings_recording_location_frequency_summary">%1$s mellom posisjonskontroller</string>
<string name="settings_recording_max_recording_distance_summary">Det blir opprettet et nytt segment hvis avstanden mellom to posisjoner er større enn %1$s</string>
<string name="settings_recording_max_recording_distance_title">Maks. avstand</string>
<string name="settings_recording_min_recording_distance_title">Avstandsintervall for opptak</string>
@@ -455,7 +455,7 @@ limitations under the License.
<string name="field_set_secondary">Sekundær</string>
<string name="field_remove_from_layout">Fjern</string>
<string name="settings_announcements_totaltime_frequency">Tidsintervall</string>
<string name="settings_announcements_distance_frequency">Distanseintervall</string>
<string name="settings_announcements_distance_frequency">Rundelengde</string>
<string name="permission_bluetooth_failed">OpenTracks krever tillatelse til å bruke Blåtann.</string>
<string name="permission_bluetooth_failed_rejected">Du må manuelt gi OpenTracks tilgang til «enheter i nærheten» i systeminnstillingene.</string>
<string name="settings_generic_sensor">Generisk</string>
@@ -479,7 +479,7 @@ limitations under the License.
<string name="settings_sensors_title">Sensorer</string>
<string name="settings_announcements_statistics_title">Statistikkmeldinger</string>
<string name="settings_announcements_summary">Tid, distanse, talehastighet</string>
<string name="settings_import_export_title">Import/eksport</string>
<string name="settings_import_export_title">Import og eksport</string>
<string name="settings_import_export_summary">Import, eksport, auto-eksport</string>
<string name="settings_units_category">Enheter</string>
<string name="settings_activity_defaults_category">Aktivitetens forvalg</string>
@@ -580,4 +580,21 @@ limitations under the License.
<string name="settings_announcements_idle_title">Inaktivitet</string>
<string name="settings_recording_idle_timeout_title">Inaktivitetsterskel</string>
<string name="activity_type_kickscooter">sparkesykkel</string>
<string name="settings_recording_title">Opptak</string>
<string name="settings_ui_dynamic_colors_title">Dynamiske farger</string>
<string name="settings_ui_dynamic_colors_summary">Bruk brukerdefinerte dynamiske farger (kun Android 12+; krever manuell omstart)</string>
<string name="settings_night_mode_option_night_oled">Natt (OLED-vennlig)</string>
<string name="settings_announcements_unit">Distanse/hastighet-enhet</string>
<string name="settings_recording_location_distance_summary">%1$s mellom registrerte posisjoner</string>
<string name="settings_announcements_lap_power">Runde-kraft</string>
<string name="power_x_watt">Kraft {x, plural, =1 {1 watt} other {# watt} }</string>
<string name="power">Kraft</string>
<string name="settings_theme_switch_restart">Temaendringer kan kreve en manuell omstart.</string>
<string name="value_internal_sensor">Intern sensor</string>
<string name="sensor_state_pressure">Barometer</string>
<string name="sensor_state_power_unit">W</string>
<string name="bluetooth_sensor_summary">%1$s (%2$s)</string>
<string name="settings_sensor_bluetooth_service_filter_title">Filtrer Bluetooth-enheter</string>
<string name="settings_sensor_bluetooth_service_filter_off">Vis alle Bluetooth-enheter som kan oppdages</string>
<string name="permission_recording_failed">OpenTracks krever tillatelse for å få tilgang til posisjonen din samt enheter i nærheten.</string>
</resources>
+14 -7
View File
@@ -24,11 +24,11 @@ limitations under the License.
<!-- Help -->
<string name="help_feature_title">OpenTracks heeft de volgende kenmerken:</string>
<string name="help_feature_content">* GPS-tracks aanmaken
\n * een hartslagsensor gebruiken (alleen Bluetooth LE)
\n * spraakaankondigingen (op tijd of afstand)
\n * markereringen aanmaken (incl. foto\'s)
\n * werkt volledig offline
\n * toon tracks op een kaart (zie hieronder)</string>
\n* een hartslagsensor gebruiken (alleen Bluetooth LE)
\n* spraakaankondigingen (op tijd of afstand)
\n* markereringen aanmaken (incl. foto\'s)
\n* werkt volledig offline
\n* toon tracks op een kaart (zie hieronder)</string>
<string name="help_track_map_title">Hoe wordt een spoor op een kaart weergegeven\?</string>
<string name="help_track_map_content"> \u0020Gebruik het kleine kaartpictogram.
\n \u0020a) \u0020(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>.
@@ -37,14 +37,14 @@ limitations under the License.
<string name="help_storage_pictures_title">Hoe slaat OpenTracks foto\'s op die als markeringen 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_track_export_title">Hoe kan ik opgenomen tracks exporteren/delen?</string>
<string name="help_track_export_content"> \u0020Tracks kunnen worden geëxporteerd vanuit de instellingen als KMZ, KML of GPX. KMZ/KML alle gegevens; GPX alleen locaties. \u0020Tracks die worden gedeeld via het <i>share-icoontje</i> worden gedeeld als KMZ \u0020</string>
<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>
<string name="help_data_google_play_services_title">Vereist/gebruikt OpenTracks Google Play Service\?</string>
<string name="help_recording_title">Hoe legt OpenTracks gegevens vast?</string>
<string name="help_recording_content">
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>
<string name="help_data_storage_title">Hoe slaat OpenTracks sensorgegevens op?</string>
<string name="help_data_storage_content"> \u0020De 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) \u0020</string>
<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>
<string name="help_gps_troubleshooting_title">OpenTracks neemt geen locaties op?</string>
<string name="help_gps_troubleshooting_content"> \u0020Wat u kunt doen:
\n \u0020a) Controleer of GPS is ingeschakeld,
@@ -602,4 +602,11 @@ Als het GPS-apparaat onnauwkeurige gegevens rapporteert (bijv. locatie, snelheid
<string name="settings_recording_min_sampling_interval_title">Interval van metingen</string>
<string name="settings_theme_switch_restart">Themawijzigingen kunnen een handmatige herstart verlangen.</string>
<string name="settings_night_mode_option_night_oled">Nacht (OLED-vriendelijk)</string>
<string name="settings_announcements_unit">Afstand-/snelheidseenheid</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="voice_announce_lap_power_key">voiceAnnounceLapPower</string>
<string name="power">Power</string>
<string name="settings_announcements_lap_power">Lap power</string>
<string name="power_x_watt">Power {x, plural, =1 {1 watt} other {# watt} }</string>
</resources>
+1 -5
View File
@@ -38,11 +38,7 @@ limitations under the License.
<string name="help_storage_pictures_title">OpenTracks 如何存儲作為標記拍攝的照片?</string>
<string name="help_storage_pictures_content">這些儲存在應用程序內部儲存區中 (即,只能在 OpenTracks 中存取)。</string>
<string name="help_track_export_title">如何匯出/分享 紀錄的蹤跡?</string>
<string name="help_track_export_content">
可以從設定匯出蹤跡為 KMZ、KML 或 GPX。
KMZ/KML 全部資料;GPX 只有位置。
通過<i>分享圖示</i>以分享蹤跡為 KMZ。
</string>
<string name="help_track_export_content"> \u0020可以從設定匯出蹤跡為 KMZ、KML 或 GPX。 \u0020KMZ/KML 全部資料;GPX 只有位置。 \u0020通過<i>分享圖示</i>以分享蹤跡為 KMZ。 \u0020</string>
<string name="help_data_google_play_services_title">OpenTracks 是否需要/使用 Google Play 服務?</string>
<string name="help_data_google_play_services_content">否</string>
<string name="help_recording_title">OpenTracks 是如何記錄資料的?</string>
+4 -2
View File
@@ -481,7 +481,7 @@ limitations under the License.
<string name="settings_ui_title">用户界面</string>
<string name="settings_ui_summary">外观,记录中布局,主题</string>
<string name="settings_gps_sensor">GPS</string>
<string name="settings_import_export_title">导入/导出</string>
<string name="settings_import_export_title">导入与导出</string>
<string name="settings_activity_defaults_category">活动默认</string>
<string name="settings_announcements_totaltime_frequency">时间间隔</string>
<string name="settings_announcements_distance_frequency">每圈长度</string>
@@ -549,7 +549,7 @@ limitations under the License.
<string name="generic_undo">撤销</string>
<string name="generic_dismiss">关闭</string>
<string name="settings_defaults_title">默认的单位和活动类型</string>
<string name="settings_sensors_title">蓝牙传感器</string>
<string name="settings_sensors_title">传感器</string>
<string name="settings_sensors_summary">自行车传感器,车轮周长,跑步传感器</string>
<string name="settings_announcements_statistics_title">语音播报</string>
<string name="settings_reset_summary">将设置重置为默认值</string>
@@ -632,4 +632,6 @@ limitations under the License.
<string name="bluetooth_sensor_summary">%1$s (%2$s)</string>
<string name="settings_recording_min_sampling_interval_title">采样时间间隔</string>
<string name="settings_recording_location_distance_summary">每隔%1$s记录地点之间</string>
<string name="settings_theme_switch_restart">主题变更可能需要手动重启。</string>
<string name="settings_night_mode_option_night_oled">黑夜模式(OLED优化)</string>
</resources>
+2
View File
@@ -250,6 +250,8 @@
<bool name="voice_announce_average_speed_pace_default" translatable="false">true</bool>
<string name="voice_announce_lap_speed_pace_key" translatable="false">voiceAnnounceLapSpeedPace</string>
<bool name="voice_announce_lap_speed_pace_default" translatable="false">true</bool>
<string name="voice_announce_unit_key" translatable="false">voiceAnnounceUnit</string>
<bool name="voice_announce_unit_default" translatable="false">true</bool>
<string name="voice_announce_average_heart_rate_key" translatable="false">voiceAnnounceAverageHeartRate</string>
<bool name="voice_announce_average_heart_rate_default" translatable="false">false</bool>
+35 -62
View File
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?><!--
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2010 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,11 +13,11 @@ distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
--><resources>
<string name="empty"/>
<string name="about_preference_title">About OpenTracks</string>
<string name="about_description"><i>OpenTracks</i> is a sport tracking application that completely respects your privacy.</string>
<string name="about_url">Project web page: <a href="%1$s">%1$s</a></string>
<string name="about_url">Project webpage: <a href="%1$s">%1$s</a></string>
<string name="about_version_name">Version name: %1$s</string>
<string name="about_version_code">Version code: %1$d</string>
<string name="about_history">OpenTracks is a fork of <a href="https://code.google.com/archive/p/mytracks/"><i>Google\'s MyTracks</i></a> (discontinued in 2016).</string>
@@ -24,15 +25,12 @@ limitations under the License.
<string name="about_libraries">Libraries</string>
<!-- Help -->
<string name="help_feature_title">OpenTracks has the following features:</string>
<string name="help_feature_content">
* create GPS tracks\n
* use a heart rate sensor (Bluetooth LE only)\n
* voice announcements (by time or distance)\n
* create markers (incl. pictures)\n
* works completely offline\n
* show tracks on a map (see below)
</string>
<string name="help_feature_content">* create GPS tracks
\n* use a heart rate sensor (Bluetooth LE only)
\n* voice announcements (by time or distance)
\n* create markers (incl. pictures)
\n* works completely offline
\n* show tracks on a map (see below)</string>
<string name="help_track_map_title">How to show a track on a map?</string>
<string name="help_track_map_content">
Use the small map icon.\n
@@ -47,33 +45,19 @@ limitations under the License.
These apps need to support the KMZ file format (only locations and timestamps).
In fact, an app needs to support <i>ACTION_VIEW</i> with MIME <i>application/vnd.google-earth.kmz</i>.
</string>
<string name="help_storage_pictures_title">How does OpenTracks store pictures that were taken as markers?</string>
<string name="help_storage_pictures_content">These are stored in the app internal storage (i.e., only accessible within OpenTracks).</string>
<string name="help_track_export_title">How can I export/share recorded tracks?</string>
<string name="help_track_export_content">
Tracks can be exported from the Settings as KMZ, KML, or GPX.
KMZ/KML all data; GPX only locations.
Tracks shared via the <i>share icon</i> are shared as KMZ.
</string>
<string name="help_track_export_content"> Tracks can be exported from the Settings as KMZ, KML, or GPX. KMZ/KML all data; GPX only locations. Tracks shared via the <i>share icon</i> are shared as KMZ. </string>
<string name="help_data_google_play_services_title">Does OpenTracks require/use Google Play Service?</string>
<string name="help_data_google_play_services_content">No</string>
<string name="help_recording_title">How does OpenTracks record data?</string>
<string name="help_recording_content">
OpenTracks uses the GPS sensor of the device to record the location continuously.
If the GPS device reports inaccurate data (e.g., location, speed, elevation), OpenTracks cannot do anything about it.
</string>
<string name="help_data_storage_title">How does OpenTracks store sensor data?</string>
<string name="help_data_storage_content">
Sensor data is stored per recorded location.
In terms of a heart rate sensor, this means that only <i>one</i> heart rate measurement is stored per location.
If you are standing still or are indoors, no sensor data will be recorded (but it will be shown).
</string>
<string name="help_data_storage_content"> Sensor data is stored per recorded location. In terms of a heart rate sensor, this means that only <i>one</i> heart rate measurement is stored per location. If you are standing still or are indoors, no sensor data will be recorded (but it will be shown). </string>
<string name="help_gps_troubleshooting_title">OpenTracks is not recording locations?</string>
<string name="help_gps_troubleshooting_content">
What you can do:\n
@@ -84,7 +68,6 @@ limitations under the License.
\n
If everything does not help please report a bug.
</string>
<string name="help_support_title">How can I support OpenTracks?</string>
<string name="help_support_content">
You can:\n
@@ -96,9 +79,7 @@ limitations under the License.
f) donate, and\n
g) do whatever you think helps OpenTracks.
</string>
<string name="open_track_as_trackfileformat">Open as %1$s</string>
<!-- Activity Type -->
<string name="activity_type_airplane">airplane</string>
<string name="activity_type_atv">ATV</string>
@@ -208,7 +189,7 @@ limitations under the License.
<string name="export_error_post_workout">Post-workout export failed, please check the export directory.</string>
<string name="export_cannot_write_to_dir">Cannot write to export directory.</string>
<string name="export_dir_not_writable">" (not writable!)"</string>
<string name="export_progress_message">Exporting to %1$s&#8230;</string>
<string name="export_progress_message">Exporting to %1$s…</string>
<string name="export_track_already_exists_msg">The file %1$s already exists at the destination directory.</string>
<string name="export_all_do_it_for_all">do it for all conflicts</string>
<string name="export_track_errors">Files not exported</string>
@@ -225,7 +206,7 @@ limitations under the License.
<string name="generic_name">Name</string>
<string name="generic_name_line">Name: %1$s</string>
<string name="generic_open_track">Open Track</string>
<string name="generic_recording">Recording&#8230;</string>
<string name="generic_recording">Recording…</string>
<string name="generic_save">Save</string>
<string name="generic_tracks">Tracks</string>
<string name="generic_overwrite">Overwrite</string>
@@ -272,7 +253,7 @@ limitations under the License.
<string name="import_error_list_dialog_title">Files not imported</string>
<string name="import_file_imported">File %1$s imported</string>
<string name="import_prevent_reimport">You have set prevent re-import track</string>
<string name="import_progress_message">Importing from %1$s&#8230;</string>
<string name="import_progress_message">Importing from %1$s…</string>
<string name="import_progress_summary_ok_msg">Files imported</string>
<string name="import_progress_summary_exists_msg">Already exists</string>
<string name="import_progress_summary_errors_msg">Errors</string>
@@ -338,36 +319,24 @@ limitations under the License.
<string name="sensor_could_not_scan">Could not scan for Bluetooth devices (error %1$i).</string>
<string name="bluetooth_disabled">Please enable Bluetooth.</string>
<string name="bluetooth_sensor_summary">%1$s (%2$s)</string>
<string name="settings_open_tracks_summary">All About OpenTracks Project</string>
<string name="settings_defaults_title">Default Units and Activity</string>
<string name="settings_defaults_summary">Preferred Units, Default Activity, Track Default Name</string>
<string name="settings_ui_title">User Interface</string>
<string name="settings_ui_summary">Appearance, Recording Layout, Theme</string>
<string name="settings_gps_sensor">GPS</string>
<string name="settings_gps_summary">Time interval, Distance interval, Max Distance, Accuracy</string>
<string name="settings_sensors_title">Sensors</string>
<string name="settings_sensors_summary">Cycling Sensors, Wheel Circumference, Running Sensors</string>
<string name="settings_announcements_idle_category_title">Idle Announcements</string>
<string name="settings_announcements_idle_title">Idle</string>
<string name="settings_announcements_statistics_title">Statistics Announcements</string>
<string name="settings_announcements_summary">Time, Distance, Voice Speed</string>
<string name="settings_import_export_title">Import and Export</string>
<string name="settings_import_export_summary">Import, Export, Auto Export</string>
<string name="settings_units_category">Units</string>
<string name="settings_activity_defaults_category">Activity\'s Defaults</string>
<string name="settings_reset_summary">Reset Settings to Default Values</string>
<!-- Settings Advanced -->
<string name="settings_advanced">Advanced</string>
<string name="settings_default_trackfileformat">Export/sharing file format</string>
@@ -406,14 +375,13 @@ limitations under the License.
<string name="settings_night_mode_option_day">Day</string>
<string name="settings_night_mode_option_night">Night</string>
<string name="settings_night_mode_option_night_oled">Night (OLED friendly)</string>
<string name="settings_announcements_totaltime_frequency">Time interval</string>
<string name="settings_announcements_distance_frequency">Lap length</string>
<string name="settings_announcements_average_heart_rate">Average heart rate</string>
<string name="settings_announcements_lap_heart_rate">Lap heart rate</string>
<string name="settings_announcements_average_speed_pace">Average speed/pace</string>
<string name="settings_announcements_lap_speed_pace">Lap speed/pace</string>
<string name="settings_announcements_unit">Distance/speed unit</string>
<!-- Custom Layout -->
@@ -437,7 +405,6 @@ limitations under the License.
<string name="settings_generic_sensor">Generic</string>
<string name="settings_cycling_sensor">Cycling</string>
<string name="settings_running_sensor">Running</string>
<string name="settings_sensor_cycling_distance_speed">Distance and Speed</string>
<string name="settings_sensor_cycling_cadence">Cadence</string>
<string name="settings_sensor_running_speed_and_cadence">Distance, Speed, and Cadence</string>
@@ -445,9 +412,7 @@ limitations under the License.
<string name="settings_sensor_bluetooth_service_filter_title">Filter Bluetooth Devices</string>
<string name="settings_sensor_bluetooth_service_filter_on">Only show Bluetooth devices that announce required services</string>
<string name="settings_sensor_bluetooth_service_filter_off">Show all discoverable Bluetooth devices</string>
<string name="settings_sensor_heart_rate_max">Zones: maximum Heart rate (bpm)</string>
<!-- Settings Stats -->
<string name="settings_stats_rate_title">Preferred rate</string>
<string name="settings_stats_units_imperial">Imperial (mi, ft)</string>
@@ -455,7 +420,6 @@ limitations under the License.
<string name="settings_stats_units_metric">Metric (km, m)</string>
<string name="settings_stats_units_nautical">Nautical (NM, ft)</string>
<string name="settings_stats_units_title">Preferred units</string>
<!-- Settings public api -->
<string name="settings_api_title">Public API</string>
<string name="settings_api_summary">Remote control and statistics API for other apps</string>
@@ -467,11 +431,9 @@ limitations under the License.
<string name="settings_public_api_dashboard_enabled_title">Automatic data transfer</string>
<string name="settings_public_api_dashboard_enabled_summary_on">An application that started a recording can also access the recorded data.</string>
<string name="settings_public_api_dashboard_enabled_summary_off">Recorded data will not be shared automatically with other applications.</string>
<!-- Settings import/export -->
<string name="settings_import_section">Import</string>
<string name="settings_export_section">Export</string>
<string name="settings_prevent_reimport_tracks_title">Prevent re-import of tracks</string>
<!-- Share Track -->
<string name="share_track_share_file_body">I think you might be interested in this track.\n\n%1$s</string>
@@ -510,7 +472,7 @@ limitations under the License.
<string name="track_delete_one_confirm_message">The track and its markers will be permanently deleted from the device.</string>
<string name="track_delete_one_confirm_title">Delete track?</string>
<string name="track_delete_multiple_confirm_message">The selected tracks and their markers will be permanently deleted from the device.</string>
<string name="track_delete_progress_message">Deleting&#8230;</string>
<string name="track_delete_progress_message">Deleting…</string>
<string name="track_delete_number_of_tracks">%1$d tracks</string>
<string name="track_delete_not_recording">This track cannot be deleted as it is currently recorded.</string>
<string name="track_discarding">Discarding Track</string>
@@ -602,6 +564,12 @@ limitations under the License.
other {{n,number,#.0} knots}
}
</string>
<string name="voiceSpeed">
{n, plural,
=1 {1}
other {{n,number,#.0}}
}
</string>
<string name="voice_on_device_speaker_title">Use the device\'s speaker</string>
<string name="voice_per_kilometer">per kilometer</string>
<string name="voice_per_mile">per mile</string>
@@ -629,6 +597,12 @@ limitations under the License.
other {{n,number,#.0} nautical miles}
}
</string>
<string name="voiceDistance">
{n, plural,
=1 {1 }
other {{n,number,#.0}}
}
</string>
<string name="average_heart_rate">Average heart rate</string>
<string name="current_heart_rate">Current heart rate</string>
<!-- Waypoint Type -->
@@ -686,12 +660,9 @@ limitations under the License.
<!-- Share image -->
<string name="share_image_subject">I would like to share an image with you</string>
<string name="share_image_body">I think you might be interested in this image.</string>
<string name="hold_to_stop">Hold to stop</string>
<string name="instant_export_enabled_summary">Export track to storage after recording is finished</string>
<string name="instant_export_enabled_title">Instant post-workout export</string>
<string name="settings_default_export_uri_title">Track export directory</string>
<!-- Fields -->
<string name="field_set_primary">Primary</string>
@@ -703,14 +674,16 @@ limitations under the License.
<string name="error_crash_title">%1$s crashed</string>
<string name="share_crash_report">Share crash report</string>
<string name="report_bug">Report bug</string>
<string name="select_show_on_map_behavior">Select \"show on map\" behavior</string>
<string name="show_on_map_format_ask">Ask</string>
<string name="show_on_dashboard">OpenTracks Dashboard API</string>
<string name="show_on_dashboard_not_installed">No application supporting OpenTracks Dashboard API installed.</string>
<string name="always">Always</string>
<string name="introduction_osm_dashboard">OpenTracks itself does not provide a map. Please install OSMDashboard to view your recordings on a map.</string>
<string name="settings_recording_min_sampling_interval_title">Sampling time interval</string>
<string name="settings_recording_location_distance_summary">%1$s between recorded locations</string>
</resources>
<string name="voice_announce_lap_power_key">voiceAnnounceLapPower</string>
<string name="settings_announcements_lap_power">Lap power</string>
<string name="power_x_watt">Power {x, plural, =1 {1 watt} other {# watts} }</string>
<string name="power">Power</string>
</resources>
+21 -12
View File
@@ -25,6 +25,13 @@
</PreferenceCategory>
<PreferenceCategory android:title="@string/settings_announcements_statistics_title">
<SwitchPreferenceCompat
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:defaultValue="@bool/voice_announce_unit_default"
android:key="@string/voice_announce_unit_key"
android:title="@string/settings_announcements_unit" />
<ListPreference
android:defaultValue="@string/voice_announcement_frequency_default"
android:entryValues="@array/voice_announcement_frequency_values"
@@ -32,13 +39,6 @@
android:title="@string/settings_announcements_totaltime_frequency"
app:useSimpleSummaryProvider="true" />
<ListPreference
android:defaultValue="@string/voice_announcement_distance_default"
android:entryValues="@array/voice_announcement_distance_values"
android:key="@string/voice_announcement_distance_key"
android:title="@string/settings_announcements_distance_frequency"
app:useSimpleSummaryProvider="true" />
<SwitchPreferenceCompat
android:defaultValue="@bool/voice_announce_total_distance_default"
android:key="@string/voice_announce_total_distance_key"
@@ -54,20 +54,29 @@
android:key="@string/voice_announce_average_speed_pace_key"
android:title="@string/settings_announcements_average_speed_pace" />
<SwitchPreferenceCompat
android:defaultValue="@bool/voice_announce_lap_speed_pace_default"
android:key="@string/voice_announce_lap_speed_pace_key"
android:title="@string/settings_announcements_lap_speed_pace" />
<SwitchPreferenceCompat
android:defaultValue="@bool/voice_announce_average_heart_rate_default"
android:key="@string/voice_announce_average_heart_rate_key"
android:title="@string/settings_announcements_average_heart_rate" />
<ListPreference
android:defaultValue="@string/voice_announcement_distance_default"
android:entryValues="@array/voice_announcement_distance_values"
android:key="@string/voice_announcement_distance_key"
android:title="@string/settings_announcements_distance_frequency"
app:useSimpleSummaryProvider="true" />
<SwitchPreferenceCompat
android:defaultValue="@bool/voice_announce_lap_speed_pace_default"
android:key="@string/voice_announce_lap_speed_pace_key"
android:title="@string/settings_announcements_lap_speed_pace" />
<SwitchPreferenceCompat
android:defaultValue="@bool/voice_announce_lap_heart_rate_default"
android:key="@string/voice_announce_lap_heart_rate_key"
android:title="@string/settings_announcements_lap_heart_rate" />
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="@string/voice_announce_lap_power_key"
android:title="@string/settings_announcements_lap_power" />
</PreferenceCategory>
</PreferenceScreen>