Compare commits

...

224 Commits

Author SHA1 Message Date
Dennis Guse b83f57bd20 Dashboard API: provide version 2 again (required by OSMDashboard until v6.4.1).
Part of #2265.
2026-02-08 19:38:34 +01:00
Dennis Guse b65d83010d Bugfix: ShareContentProvider should report contentType for all Uris (not only TrackFileFormat).
Part of #2265.
2026-02-08 18:11:52 +01:00
Dennis Guse 1a5d06f9c6 Cleanup: renamed IntentDashboardUtils.java to DataProvider. 2026-02-07 19:20:48 +01:00
Dennis Guse 723c21d7ec Dashboard API: add tests for column names.
Part of #2265.
2026-02-07 09:39:23 +01:00
Dennis Guse 8fe0c3be7d Bugfix: update data for UI immediately after starting recording. 2026-02-06 18:54:32 +01:00
Dennis Guse e64792bf3f Resetting preferences requires clearing and naming each preference file explicitly. 2026-02-06 18:54:18 +01:00
Dennis Guse 21bafff761 TrackRecordingService should start UI timer at the end of startRecording. 2026-02-06 18:54:06 +01:00
Dennis Guse c33c2de51d Cleanup: EspressoUI should always lookup UI elements. 2026-02-06 18:53:55 +01:00
Dennis Guse a6b11c1c37 Release: v4.25.1 2026-02-01 22:05:05 +01:00
Dennis Guse 315788308b Bumping DashboardAPI to version 3.
Fixes #2255.
2026-02-01 20:15:24 +01:00
Dennis Guse 547c1c5c65 Rename MarkerColumns.
Fixes #2255.
2026-02-01 20:15:24 +01:00
tace16 69efd6fb82 Translated using Weblate (Tamil)
Currently translated at 100.0% (545 of 545 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/ta/
2026-01-31 18:08:56 +01:00
ghose 3a0524f96d Translated using Weblate (Galician)
Currently translated at 100.0% (545 of 545 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/gl/
2026-01-31 18:08:56 +01:00
Priit Jõerüüt 05456b44ef Translated using Weblate (Estonian)
Currently translated at 100.0% (545 of 545 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/et/
2026-01-31 18:08:56 +01:00
tace16 b449dad619 Translated using Weblate (Tamil)
Currently translated at 100.0% (179 of 179 strings)

Translation: OpenTracks/App store metadata files
Translate-URL: https://translate.codeberg.org/projects/opentracks/app-store-metadata-files/ta/
2026-01-31 18:08:56 +01:00
SomeTr ccefe36489 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (545 of 545 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/uk/
2026-01-31 18:08:56 +01:00
ovl-005 90e9ab6d2a Translated using Weblate (Norwegian Bokmål)
Currently translated at 98.1% (535 of 545 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/nb_NO/
2026-01-31 18:08:56 +01:00
Outbreak2096 d1061fa6cd Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 88.8% (159 of 179 strings)

Translation: OpenTracks/App store metadata files
Translate-URL: https://translate.codeberg.org/projects/opentracks/app-store-metadata-files/zh_Hans/
2026-01-31 18:08:56 +01:00
Outbreak2096 c0c813001f Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (545 of 545 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/zh_Hans/
2026-01-31 18:08:56 +01:00
Outbreak2096 51498bbcf9 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (542 of 542 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/zh_Hans/
2026-01-31 18:08:56 +01:00
CI/CD Bot by pstorch 4ef1fcefbc Update dependency gradle to v9.3.1 2026-01-29 15:35:43 +00:00
CI/CD Bot by pstorch 9a572130a7 Update dependency androidx.work:work-runtime to v2.11.1 2026-01-29 00:34:18 +00:00
Dennis Guse e931f5ab7c Reproducible build: for naming the APK use the actual versionCode.
Fixes #2252.
2026-01-23 15:11:37 +01:00
Dennis Guse 9affe28fad Release: v4.25.0 2026-01-21 18:33:40 +01:00
Dennis Guse 4905a37951 Build scripts: add some error handling. 2026-01-21 18:33:20 +01:00
Dennis Guse 439671d0a4 Build scripts: add some error handling. 2026-01-18 15:49:41 +01:00
Dennis Guse 825e8dda6e Revert "Translated using Weblate (English (en_001))"
This reverts commit 99a9248b27.
2026-01-18 10:13:00 +01:00
Dennis Guse 661c839c78 Update README_TESTED_SENSORS.md
Assioma Pro MX-2

Fixes #2246.
2026-01-18 10:08:42 +01:00
Dennis Guse 8eb42a7ecb Upgrade to Android Gradle Plugin 9.0: removing applicationVariants 2026-01-17 22:58:17 +01:00
CI/CD Bot by pstorch 660a55ff5a Update dependency gradle to v9.3.0 2026-01-16 12:45:31 +00:00
CI/CD Bot by pstorch 958697bcb3 Update dependency com.android.tools.build:gradle to v9 2026-01-15 17:42:07 +00:00
ntd 6029eb0317 Translated using Weblate (Italian)
Currently translated at 100.0% (542 of 542 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/it/
2026-01-10 21:48:12 +01:00
ntd 8b56d53a6a Translated using Weblate (Italian)
Currently translated at 3.9% (7 of 178 strings)

Translation: OpenTracks/App store metadata files
Translate-URL: https://translate.codeberg.org/projects/opentracks/app-store-metadata-files/it/
2026-01-10 21:48:12 +01:00
Dennis Guse e9deebea6c Refactor: RecordingLayout. 2026-01-10 21:43:54 +01:00
Dennis Guse 54844b9a9a Sensor: add temperature.
Fixes #2241.
2026-01-10 21:43:54 +01:00
Dennis Guse 738201c1c2 Cleanup. 2026-01-04 09:57:05 +01:00
discollizard 48b6be0bd1 record button moved to the middle of the screen
Part of #2199
2026-01-03 18:40:17 -03:00
Priit Jõerüüt 6b924cd936 Translated using Weblate (Estonian)
Currently translated at 100.0% (542 of 542 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/et/
2026-01-02 19:56:27 +01:00
discollizard 5f083de530 adjusted distance time and markers to be horizontally consistent
formatter

initial date and time are always visible in the list while recording
2026-01-02 15:31:42 -03:00
Matt Votava 278f6323f1 track import: get extension from file name, not URI
When importing tracks from nextcloud, the URI for a file may be something like

content://org.nextcloud.documents/tree/7keh3ot7zmiaxecoktv6bfn6gdygt2lg%2F707/document/7keh3ot7zmiaxecoktv6bfn6gdygt2lg%2F745

The URI contains no ".", so getExtension() would return the whole URI as the extension, resulting in an "Unsupported file format" error.

To fix this, also pass DocumentFile.getName() to the ImportWorker.
2025-12-28 01:30:10 -08:00
Dennis Guse 5baa8fa21e Cleanup: KMLTrackImporter doesn't need Position at first. 2025-12-28 08:59:19 +01:00
Dennis Guse 707f4add71 Cleanup: GpsStatusManager only needs Position. 2025-12-28 08:59:19 +01:00
Dennis Guse b583f8f23d Sticker: added printable PDF 2025-12-27 08:38:01 +01:00
Priit Jõerüüt c847f622e4 Translated using Weblate (Estonian)
Currently translated at 91.3% (495 of 542 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/et/
2025-12-27 07:35:12 +01:00
Priit Jõerüüt 70dd58f484 Translated using Weblate (Estonian)
Currently translated at 78.9% (428 of 542 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/et/
2025-12-27 07:35:12 +01:00
Dennis Guse 015352c989 TrackPoint is now a record. 2025-12-24 17:15:19 +01:00
Dennis Guse 42ae582cd8 Release: v4.24.2 2025-12-19 22:14:30 +01:00
frazou 6e0ad50397 Translated using Weblate (French)
Currently translated at 100.0% (544 of 544 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/fr/
2025-12-13 12:35:09 +01:00
Dennis Guse d43efad52a Bugfix: crash on select all tracks or all markers.
Fixes #2231.
2025-12-12 21:59:45 +01:00
Dennis Guse 693904529d Release: v4.24.1 2025-12-11 22:46:23 +01:00
Dennis Guse 08143a546a Bugfix: marker.icon column is still used by OSMDashboard v6.4.1
Fixes https://codeberg.org/OpenTracksApp/OSMDashboard/issues/552
2025-12-11 22:44:44 +01:00
Dennis Guse eb49156ee7 Bugfix: crash when using number as default track name.
Fixes #2229.
2025-12-11 18:24:47 +01:00
CI/CD Bot by pstorch 51c03d8d75 Update dependency com.android.tools.build:gradle to v8.13.2 2025-12-11 05:33:57 +00:00
CI/CD Bot by pstorch 666cbbad68 Update dependency org.mockito:mockito-android to v5.21.0 2025-12-09 19:34:11 +00:00
Dennis Guse 1cbc93c303 Release: v4.24.0 2025-12-09 07:41:29 +01:00
frazou afd1232940 Fix null race-condition for heart rate sensor data
The previous implementation was technically safe because the sensor
never had null values. Now that it can, the calls to getHeartRate
must be stored instead of repeated to avoid a race condition where the
sensor data become null between the null-check and the second call
2025-12-07 19:16:42 +01:00
frazou a3407ccbea Add an optional filter for invalid (0 bpm) heart rate readings 2025-12-07 19:16:42 +01:00
yosoyalguien c259f9b8bd Translated using Weblate (Spanish (Latin America))
Currently translated at 84.0% (457 of 544 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/es_419/
2025-12-07 12:15:12 +01:00
Stzyxh b1a556bf91 Translated using Weblate (German)
Currently translated at 6.2% (11 of 175 strings)

Translation: OpenTracks/App store metadata files
Translate-URL: https://translate.codeberg.org/projects/opentracks/app-store-metadata-files/de/
2025-12-07 12:15:12 +01:00
tace16 ab70874d59 Translated using Weblate (Tamil)
Currently translated at 100.0% (175 of 175 strings)

Translation: OpenTracks/App store metadata files
Translate-URL: https://translate.codeberg.org/projects/opentracks/app-store-metadata-files/ta/
2025-12-07 12:15:12 +01:00
Dennis Guse e6367b1dfa Cleanup: inline SelectionData. 2025-12-06 11:46:44 +01:00
Dennis Guse 8db381c448 Cleanup. 2025-12-06 10:25:11 +01:00
Dennis Guse ef111b7959 Cleanup: removed import functionality for legacy format (coordinates 100 and 200 where special).
Deadline was EOF 2021.
2025-12-06 10:23:21 +01:00
Dennis Guse 56c6cb1f19 Cleanup: removed CachedTrackPointsIndexes.
Caching already happens in SQLite.getColumnIndexOrThrow().
2025-12-06 10:05:24 +01:00
Dennis Guse 874c5eb8ae Cleanup. 2025-12-06 09:36:04 +01:00
Dennis Guse 1a087b1117 Bugfix: icon for activity motor bike was wrong. 2025-12-06 09:34:17 +01:00
Dennis Guse 3120cd8da0 README: description for KML/KMZ vs. GPX. 2025-12-06 09:31:36 +01:00
Dennis Guse 4263c000c0 Show coordinates with always with 5 decimals. 2025-12-06 09:18:06 +01:00
Dennis Guse f4073ead63 Removed KMZ export without photos. 2025-12-06 09:03:03 +01:00
Dennis Guse 2f90784442 Cleanup. 2025-12-06 08:47:06 +01:00
Dennis Guse 2cab394d03 Cleanup. 2025-12-06 08:41:57 +01:00
Dennis Guse 55f1bcb30b PublicAPI: StartRecording does not overwrite Track defaults if no data was provided.
Fixes #2214.
2025-12-06 08:34:17 +01:00
Dennis Guse 33a17784e6 Re-enable marker photo sharing.
Don't recall why it was disabled.
2025-12-06 08:27:48 +01:00
Dennis Guse 7cb97b0e6b Cleanup: use try-with-resources. 2025-12-06 08:27:01 +01:00
Dennis Guse 1cb3db496a Cleanup. 2025-12-05 08:05:25 +01:00
Dennis Guse d49d6c9857 Cleanup: AutoCloseableIterator now handles the cursor. 2025-12-05 08:05:25 +01:00
Dennis Guse 12f0c3313f ContentProviderUtils.searchMarkers uses MarkerIterator. 2025-12-05 08:05:25 +01:00
Dennis Guse a78e059612 Cleanup: ChartView doesn't show any Markers since a while.
Drawing Markers was removed in d8eed2ccc9
2025-12-05 08:05:25 +01:00
Dennis Guse 0774ee512f Cleanup: clarify options for Marker.TypeLocalized. 2025-12-05 08:05:25 +01:00
Dennis Guse 4c55468571 TrackList now has an AutoClosableIterator. 2025-12-05 08:05:25 +01:00
Dennis Guse 201f2d1b27 Cleanup: renaming Marker.category to typeLocalized. 2025-12-05 08:05:25 +01:00
Dennis Guse 595ad7f7b5 Marker list: split category and description into two fields. 2025-12-05 08:05:25 +01:00
Dennis Guse d518507193 Cleanup: use TextUtils.isEmpty(). 2025-12-05 08:05:25 +01:00
Dennis Guse 888f59133d Track list: split activity type localized and description into two fields. 2025-12-05 08:05:25 +01:00
Dennis Guse 5bb5b3b344 Track.ActivityType and Marker.Category are shown not wrapped in [] anymore. 2025-12-05 08:05:25 +01:00
Dennis Guse b584a95c9c Bugfix: crash when opening Marker Detail.
Introduced in 5b4b54694c
2025-12-05 08:05:25 +01:00
Dennis Guse 9ba152c469 Cleanup: use Position instead of Android's location. 2025-12-05 08:05:25 +01:00
Dennis Guse 1191f2e1e2 Cleanup: remove unused imports. 2025-12-05 08:05:25 +01:00
frazou e5aed794ba Fix idle discrepancy in UI 2025-11-30 22:49:50 +01:00
Dennis Guse 7956063598 Cleanup: Marker.icon was not used anymore. 2025-11-30 16:51:02 +01:00
Dennis Guse 0f356de2ca Gradle: add managed device. 2025-11-30 16:51:02 +01:00
Dennis Guse 5b4b54694c Marker is now a record. 2025-11-30 16:51:02 +01:00
Dennis Guse 9c271972d2 Cleanup. 2025-11-30 16:51:02 +01:00
CI/CD Bot by pstorch 744f11eaa0 Update actions/checkout action to v6 2025-11-30 14:34:10 +00:00
tace16 3c16f67882 Translated using Weblate (Tamil)
Currently translated at 100.0% (544 of 544 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/ta/
2025-11-27 20:48:11 +01:00
Dennis Guse 12d1a50995 Track is now a record.
Create Track directly.
2025-11-27 20:34:51 +01:00
Dennis Guse 21404fed50 Track is now a record.
Create Track directly.
2025-11-27 20:11:53 +01:00
Dennis Guse 990c91f978 Track is now a record. 2025-11-27 19:35:05 +01:00
Dennis Guse 6a262426a5 Delete all tracks (trackpoints and markers) works via cascade. 2025-11-27 17:14:11 +01:00
Dennis Guse 1b2998f423 CustomContentProvider: limit URIs for updates. 2025-11-27 17:14:11 +01:00
Dennis Guse d24dd2b005 Cleanup. 2025-11-27 17:14:11 +01:00
Dennis Guse 341fd02f9a Cleanup. 2025-11-26 22:48:00 +01:00
Dennis Guse 6833ea7282 Use MarkerIterator for TrackDataHub. 2025-11-26 22:46:39 +01:00
Dennis Guse a1da53864e Use MarkerIterator for MarkerDetailActivity. 2025-11-26 22:10:53 +01:00
Dennis Guse 28d49de047 Cleanup: removed ContentProviderUtils.getMarkers(). 2025-11-26 21:51:07 +01:00
Dennis Guse 4ae9d24960 Implemented MarkerIterator. 2025-11-26 21:42:11 +01:00
Dennis Guse 0b0b1a0d8d Cleanup. 2025-11-26 20:07:39 +01:00
Dennis Guse 090cdbf712 Cleanup: ContentProviderUtils.getMarkerCursor() has an optional parameter. 2025-11-26 20:05:27 +01:00
Dennis Guse 8258d607c3 Cleanup: ContentProviderUtils.getMarkerCursor() had an unused parameter. 2025-11-26 19:56:32 +01:00
Dennis Guse 686a2a9b8f Cleanup: removed method that was only used for testing in ContentProviderUtils. 2025-11-25 19:34:41 +01:00
Dennis Guse 7ddb6b32bb Cleanup: TrackDataHub doesn't need to query the id of the last TrackPoint. 2025-11-25 18:46:20 +01:00
Dennis Guse 5cd639c852 Cleanup: TrackDataHub only needs in-sample. 2025-11-25 18:42:02 +01:00
Dennis Guse ae9906fb18 Cleanup. 2025-11-25 07:40:01 +01:00
Dennis Guse 96bcac397b Cleanup. 2025-11-25 07:31:49 +01:00
Dennis Guse d7b207afac Cleanup: trackStatistics were already updated. 2025-11-25 07:31:49 +01:00
Dennis Guse 1672ba99ad Cleanup: in TrackImporter create Track object when all data got loaded. 2025-11-25 07:31:49 +01:00
Dennis Guse a6d4a05839 Statistics requires startTime and stopTime.
This is now enforced for import as wells.
2025-11-25 07:31:48 +01:00
Dennis Guse 860b90da37 Cleanup ExportImportTest. 2025-11-24 19:38:33 +01:00
Dennis Guse 46d7385d25 Cleanup RecordingData. 2025-11-22 18:22:00 +01:00
Dennis Guse 25fbd9490c Cleanup RecordingData. 2025-11-22 18:06:48 +01:00
Dennis Guse 6d33adffce Move temp functionality into TrackStatisticsUpdater. 2025-11-22 17:49:35 +01:00
Dennis Guse 92cecb6f3a For TrackStatisticsUpdater there may no pre-existing Statistics. 2025-11-22 13:14:50 +01:00
Dennis Guse e6bdc9a41d Altitude extremities is now null instead of (0,0) if no altitude was received (yet). 2025-11-22 13:03:52 +01:00
Dennis Guse e234e9c493 Only execute VoiceAnnouncementUtilsTest for SDK34+. 2025-11-22 12:56:17 +01:00
Dennis Guse 73d6ca6ca6 Cleanup: SegmentStatisticUpdater is always initialized. 2025-11-21 16:30:29 +01:00
Dennis Guse 1ef7a6ecc4 Move .merge() from SegmentStatisticUpdater to Statistics.
This is a functional change as maxSpeed is now determined by Segment (rather than the joined Segment).
2025-11-21 16:15:18 +01:00
Dennis Guse 94a0b57362 Simplify construction of TrackStatisticsUpdater. 2025-11-21 13:37:14 +01:00
Dennis Guse 4ebaf366d6 TrackStatisticsUpdater only needs one SegmentStatisticUpdater. 2025-11-21 13:37:14 +01:00
Dennis Guse 911f2c525f Move isIdle to TrackStatisticsUpdater. 2025-11-21 13:37:14 +01:00
CI/CD Bot by pstorch a310f773a1 Update dependency com.android.tools.build:gradle to v8.13.1 2025-11-20 05:33:43 +01:00
Dennis Guse 8a247e5b38 Cleanup: TrackStatisticsUpdater. 2025-11-17 22:22:44 +01:00
Dennis Guse 1045ade71a Cleanup: SegmentStatisticUpdater. 2025-11-17 22:22:44 +01:00
Dennis Guse 4307dceb70 Cleanup: rename to totalDuration and movingDuration. 2025-11-17 22:22:44 +01:00
Dennis Guse 59ea50b96f Cleanup: SegmentStatisticUpdater. 2025-11-17 22:22:44 +01:00
Dennis Guse 8d015fee6c Cleanup: SegmentStatisticUpdater. 2025-11-17 22:22:44 +01:00
Dennis Guse 653352255e Cleanup: SegmentStatisticUpdater. 2025-11-17 22:22:44 +01:00
Dennis Guse ebcdd87481 Cleanup: use Duration.ZERO. 2025-11-17 22:22:44 +01:00
Stzyxh 8d1af8f2cf Translated using Weblate (German)
Currently translated at 5.1% (9 of 175 strings)

Translation: OpenTracks/App store metadata files
Translate-URL: https://translate.codeberg.org/projects/opentracks/app-store-metadata-files/de/
2025-11-17 22:22:12 +01:00
CI/CD Bot by pstorch 766739c222 Update dependency gradle to v9.2.1 2025-11-17 14:35:53 +00:00
Dennis Guse 54fa6aa3e2 Add GPX.Studio to README. 2025-11-16 15:17:15 +01:00
SomeTr 1dc737410b Translated using Weblate (Ukrainian)
Currently translated at 99.8% (543 of 544 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/uk/
2025-11-10 00:09:55 +00:00
ghose 4093899a82 Translated using Weblate (Galician)
Currently translated at 17.7% (31 of 175 strings)

Translation: OpenTracks/App store metadata files
Translate-URL: https://translate.codeberg.org/projects/opentracks/app-store-metadata-files/gl/
2025-11-10 00:09:55 +00:00
Dennis Guse 9236eb6944 AndroidStudio: set line width (for autoformatting) to 200. 2025-11-09 22:45:50 +01:00
Dennis Guse 9f00b0606b Revert "AndroidStudio: set line width (for autoformatting) to 200."
This reverts commit 95b27f66fb.
2025-11-09 22:45:41 +01:00
SomeTr 20a18b86dc Translated using Weblate (Ukrainian)
Currently translated at 99.4% (541 of 544 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/uk/
2025-11-08 23:09:40 +00:00
alecsargent 34cfc235c3 Translated using Weblate (Spanish (Latin America))
Currently translated at 83.6% (455 of 544 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/es_419/
2025-11-08 23:09:40 +00:00
CI/CD Bot by pstorch f733d18a60 Add renovate.json 2025-11-08 20:33:45 +00:00
Dennis Guse 221b61c7f1 Aggregate statistics are now computed in the database. 2025-11-06 21:54:30 +01:00
Dennis Guse ca64f2c749 Tracks table: remove unused columns and rename existing columns. 2025-11-06 21:54:30 +01:00
Dennis Guse 3d083928eb Cleanup. 2025-11-06 21:54:30 +01:00
Dennis Guse f47ab142f2 Upgrade to Gradlew 9.2.0 2025-11-06 21:54:30 +01:00
Dennis Guse 6e4d46a14d Distance.ZERO as constant. 2025-11-06 21:54:30 +01:00
Dennis Guse fffeb40200 Speed.ZERO as constant. 2025-11-06 21:54:30 +01:00
Dennis Guse a5e5d0ca51 AggregatedStatistics: compute without SegmentStatisticUpdater. 2025-11-06 21:54:30 +01:00
Dennis Guse 7791ff8659 Cleanup: Track simplify constructors. 2025-11-06 21:54:30 +01:00
Dennis Guse 3db0a53377 Release: v4.23.2 2025-11-06 21:41:13 +01:00
Dennis Guse 58dac8b706 Translations 2025-11-06 18:12:42 +01:00
Codeberg Translate f29b6d4088 Merge remote-tracking branch 'origin/main' 2025-11-05 21:38:42 +00:00
ghose 80fb4f9998 Translated using Weblate (Galician)
Currently translated at 100.0% (544 of 544 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/gl/
2025-11-05 21:38:39 +00:00
Dennis Guse 6340e55fff Bump org.mockito:mockito-android from 5.19.0 to 5.20.0 2025-11-05 21:34:54 +01:00
Dennis Guse 625549d381 Bump androidx.work:work-runtime from 2.10.5 to 2.11.0 2025-11-05 21:34:23 +01:00
Dennis Guse 7d9878b32e Bump androidx.core:core-location-altitude from 1.0.0-alpha03 to 1.0.0-beta01 2025-11-05 21:33:47 +01:00
Dennis Guse a5553211af Bump androidx.core:core-splashscreen from 1.0.1 to 1.2.0 2025-11-05 21:33:15 +01:00
Dennis Guse 044e84154c Bugfix: crash in settings.
Introduced in 696939112a
2025-11-05 21:31:40 +01:00
Outbreak2096 f61d718b2d Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (544 of 544 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/zh_Hans/
2025-11-04 06:06:45 +00:00
Codeberg Translate c7a54dcee8 Merge remote-tracking branch 'origin/main' 2025-11-03 00:23:28 +00:00
Eryk Michalak 3dc2ee3462 Translated using Weblate (Polish)
Currently translated at 93.9% (511 of 544 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/pl/
2025-11-03 00:23:26 +00:00
Stzyxh 6817ff3234 Translated using Weblate (German)
Currently translated at 4.5% (8 of 174 strings)

Translation: OpenTracks/App store metadata files
Translate-URL: https://translate.codeberg.org/projects/opentracks/app-store-metadata-files/de/
2025-11-03 00:23:22 +00:00
Codeberg Translate fb0400001a Merge remote-tracking branch 'origin/main' 2025-11-01 10:10:24 +00:00
ovl-005 16591b3e80 Translated using Weblate (Norwegian Bokmål)
Currently translated at 98.3% (534 of 543 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/nb_NO/
2025-11-01 10:09:54 +00:00
Dennis Guse 28da32f573 Fixed TrackRecordingServiceRecordingTest: disable the real GPS (finally). 2025-11-01 10:13:52 +01:00
Dennis Guse c687308d97 Move WakeLock to SensorManager (was TrackRecordingService). 2025-11-01 09:56:31 +01:00
Dennis Guse 65c8e8542e Cleanup: pass RecordingData to VoiceAnnouncementManager. 2025-11-01 09:30:47 +01:00
Dennis Guse ca4cb648e7 Predictive back: shown also for TrackRecordedActivity.
However: the shared element animation needed to be removed. ActivityOptions.makeSceneTransitionAnimation() seems to overwrite the predictive back animation.
2025-11-01 08:49:08 +01:00
Dennis Guse 53240c3d1a IntervalStatisticsUpdater exposes Statistics (instead of Interval). 2025-10-31 19:00:32 +01:00
Dennis Guse 95b27f66fb AndroidStudio: set line width (for autoformatting) to 200. 2025-10-31 18:34:07 +01:00
Dennis Guse f31e146cda Cleanup: TrackPoint uses AltitudeGainLoss. 2025-10-30 22:33:00 +01:00
Dennis Guse 696939112a Cleanup: Statistics doesn't need isIdle.
isIdle is only used by SegmentStatisticsUpdater.
2025-10-30 21:52:00 +01:00
Dennis Guse 73ce97a63e VoiceAnnouncementUtilsTest do not store data. 2025-10-30 21:45:03 +01:00
Dennis Guse 5988ae3d3f VoiceAnnouncementUtilsTest do not use SegmentStatisticsUpdater. 2025-10-30 21:30:01 +01:00
Dennis Guse 58655814b2 VoiceAnnouncementManager should close TrackPointIterator to avoid memory leaks. 2025-10-30 07:54:05 +01:00
Dennis Guse 11f1b6e72d Cleanup: TrackPointIterator is now package private. 2025-10-30 07:54:05 +01:00
Dennis Guse 8f537f33a7 Cleanup: removed Track.setTrackStatistics(SegmentStatisticsUpdater). 2025-10-30 07:54:05 +01:00
Dennis Guse 4db72230ff Refactored VoiceAnnouncementUtilsTest. 2025-10-30 07:54:05 +01:00
Dennis Guse fd92793c2a Test: IntervalStatisticsUpdaterTest doesn't store data anymore. 2025-10-30 07:54:05 +01:00
Dennis Guse 05e45b6870 TrackStatisticsUpdater now provides Statistics.
Used for non-testing code.
2025-10-30 07:54:04 +01:00
Dennis Guse 7521f906ed IntervalStatisticsUpdater now uses Statistics. 2025-10-30 07:54:04 +01:00
Dennis Guse 3222a0c497 Rename IntervalStatistics to IntervalStatisticsUpdater. 2025-10-30 07:54:04 +01:00
Dennis Guse caf3d957cd Cleanup: SegmentStatisticUpdaterTest uses Statistic. 2025-10-30 07:54:04 +01:00
Dennis Guse 005d00cfaa Cleanup: SegmentStatisticUpdaterTest. 2025-10-30 07:54:04 +01:00
Dennis Guse c227d54f26 Cleanup: SegmentStatisticUpdater and Track do not need equal(). 2025-10-30 07:54:04 +01:00
Dennis Guse bc62320b9f Track only has Statistics (instead of SegmentStatisticsUpdater). 2025-10-30 07:54:04 +01:00
Dennis Guse 0ad32f676c Create SegmentStatisticUpdater by passing Statistics (2/2). 2025-10-30 07:54:04 +01:00
Dennis Guse fff5f2d406 Create SegmentStatisticUpdater by passing Statistics (1/2). 2025-10-30 07:54:04 +01:00
Dennis Guse be653b73ee Added value object: AltitudeExtremities. 2025-10-30 07:54:04 +01:00
Dennis Guse 4580f2a7bb ContentProviderUtils use Statistics for saving. 2025-10-30 07:54:04 +01:00
Dennis Guse 5dd56892fb Cleanup: move Statistics to package models. 2025-10-30 07:54:04 +01:00
Dennis Guse e3460d94ed Statistics: used when only the data is needed (instead of passing SegmentStatisticUpdater). 2025-10-30 07:54:04 +01:00
Dennis Guse 920ad5129a Introduced Statistics as a value object. 2025-10-30 07:54:04 +01:00
Dennis Guse fba08fe8dd Cleanup: rename TrackStatistics to SegmentStatisticsUpdater. 2025-10-30 07:54:04 +01:00
Dennis Guse 5746a41905 Release: v4.23.1 2025-10-30 07:48:12 +01:00
Dennis Guse 361ae909e7 Bugfix: post-recording workout crashes.
Fixes #2180.

Introduced in 02a77e5ce7
2025-10-29 22:14:46 +01:00
Dennis Guse 4b59660ea1 Revert "Allow adding newly developed UI Components to existing custom layouts."
This reverts commit daa4689f44.
2025-10-29 22:14:12 +01:00
SomeTr cabf5d238e Translated using Weblate (Ukrainian)
Currently translated at 94.6% (514 of 543 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/uk/
2025-10-28 17:35:25 +01:00
Outbreak2096 9c902b89ed Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (543 of 543 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/zh_Hans/
2025-10-28 17:35:25 +01:00
Claudinux c31b8a5802 Translated using Weblate (Italian)
Currently translated at 100.0% (543 of 543 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/it/
2025-10-28 17:35:25 +01:00
SomeTr 901c548d13 Translated using Weblate (Ukrainian)
Currently translated at 94.4% (513 of 543 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/uk/
2025-10-28 17:35:25 +01:00
SomeTr b77de1e10d Translated using Weblate (Ukrainian)
Currently translated at 94.2% (512 of 543 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/uk/
2025-10-28 17:35:25 +01:00
SomeTr b8c7fba7d8 Translated using Weblate (Ukrainian)
Currently translated at 94.2% (512 of 543 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/uk/
2025-10-28 17:35:25 +01:00
ghose 466719fbc8 Translated using Weblate (Galician)
Currently translated at 100.0% (543 of 543 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/gl/
2025-10-28 17:35:25 +01:00
ghose 4f0ab71503 Translated using Weblate (Galician)
Currently translated at 100.0% (541 of 541 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/gl/
2025-10-28 17:35:25 +01:00
Jeff Shelley daa4689f44 Allow adding newly developed UI Components to existing custom layouts.
Fixes #2176.
2025-10-28 09:51:51 -05:00
Jeff Shelley 023a5aa221 added new UI component which shows elapsed segment time 2025-10-28 09:51:29 -05:00
SomeTr 291633c1d5 Translated using Weblate (Ukrainian)
Currently translated at 94.6% (514 of 543 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/uk/
2025-10-28 07:53:05 +00:00
Codeberg Translate 00990076fb Merge remote-tracking branch 'origin/main' 2025-10-28 05:27:33 +00:00
Outbreak2096 e672df7a60 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (543 of 543 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/zh_Hans/
2025-10-28 05:27:31 +00:00
Claudinux 82eb237117 Translated using Weblate (Italian)
Currently translated at 100.0% (543 of 543 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/it/
2025-10-28 05:27:31 +00:00
Peter Storch 832005565a run forgejo actions on pull requests from forks (#2183)
Reviewed-on: https://codeberg.org/OpenTracksApp/OpenTracks/pulls/2183
Co-authored-by: Peter Storch <peter.storch@tuta.io>
Co-committed-by: Peter Storch <peter.storch@tuta.io>
2025-10-27 20:58:18 +01:00
SomeTr 894699f009 Translated using Weblate (Ukrainian)
Currently translated at 94.4% (513 of 543 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/uk/
2025-10-26 21:02:55 +00:00
SomeTr f45dba258b Translated using Weblate (Ukrainian)
Currently translated at 94.2% (512 of 543 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/uk/
2025-10-26 20:23:21 +00:00
SomeTr 17be49af70 Translated using Weblate (Ukrainian)
Currently translated at 94.2% (512 of 543 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/uk/
2025-10-26 13:17:55 +00:00
ghose e91d36fc16 Translated using Weblate (Galician)
Currently translated at 100.0% (543 of 543 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/gl/
2025-10-26 13:17:55 +00:00
ghose 56f333180b Translated using Weblate (Galician)
Currently translated at 100.0% (541 of 541 strings)

Translation: OpenTracks/opentracks.src-main-res-values-strings-xml--main
Translate-URL: https://translate.codeberg.org/projects/opentracks/opentracks-src-main-res-values-strings-xml-main/gl/
2025-10-25 17:24:16 +00:00
Dennis Guse 9af8b0d353 Cleanup. 2025-10-24 22:26:08 +02:00
284 changed files with 7735 additions and 7035 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = false
max_line_length = 100
max_line_length = 200
tab_width = 4
ij_continuation_indent_size = 8
ij_formatter_off_tag = @formatter:off
+7 -3
View File
@@ -1,5 +1,9 @@
name: Android Test
on: [push]
on:
push:
branches:
- main
pull_request:
jobs:
lint:
@@ -9,7 +13,7 @@ jobs:
image: 'ubuntu:android-24.04'
steps:
- name: Checkout sources
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 1
@@ -23,7 +27,7 @@ jobs:
image: 'ubuntu:android-24.04'
steps:
- name: Checkout sources
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 1
+8 -6
View File
@@ -40,8 +40,7 @@ _OpenTracks_ is a sport tracking application that completely respects your priva
</tr>
</table>
Translations are hosted on <a href="https://translate.codeberg.org/engage/opentracks/">
translate.codeberg.org/projects/opentracks/</a>.
Translations are hosted on <a href="https://translate.codeberg.org/engage/opentracks/">translate.codeberg.org/projects/opentracks/</a>.
<a href="https://translate.codeberg.org/engage/opentracks/">
<img src="https://translate.codeberg.org/widget/opentracks/opentracks-src-main-res-values-strings-xml-main/horizontal-auto.svg" alt="Translation status" />
</a>
@@ -112,8 +111,7 @@ The API is disabled by default to protect the user's privacy, but it can easily
`Classes`:
* **Start a recording:** `de.dennisguse.opentracks.publicapi.StartRecording`
* Set track data: `TRACK_NAME`, `TRACK_DESCRIPTION`, `TRACK_CATEGORY`, and `TRACK_ICON` (
non-localized identifier
see [/src/main/java/de/dennisguse/opentracks/util/TrackIconUtils.java#L38](/src/main/java/de/dennisguse/opentracks/util/TrackIconUtils.java#L38)).
see `ActivityType.id` defined in [/src/main/java/de/dennisguse/opentracks/util/TrackIconUtils.java#L38](/src/main/java/de/dennisguse/opentracks/data/model/ActivityType.java)).
NOTE: if `TRACK_ICON` is not present, `TRACK_CATEGORY` will be used to determine the icon (
localized).
* Send recorded data to another application via _Dashboard API_: `STATS_TARGET_PACKAGE` and
@@ -134,6 +132,10 @@ adb shell am start -n "de.dennisguse.opentracks.playstore/de.dennisguse.opentrac
```
## File formats compatibility with open-source software
KML/KMZ can be used to export indoor activities (no GPS present).
GPX exports only those points that have a GPS coordinate present (sensor data is aggregated though).
| | [GPX 1.1](https://www.topografix.com/GPX/1/1/) | [KML 2.3](https://docs.opengeospatial.org/is/12-007r2/12-007r2.html) | [KMZ 2.3](https://docs.opengeospatial.org/is/12-007r2/12-007r2.html) |
|-----------------------------------------------------------|--------------------------------------------------------------------------------|----------------------------------------------------------------------|----------------------------------------------------------------------|
| [OpenLayers 7.1.0](https://openlayers.org/) | ? | [no](https://github.com/openlayers/openlayers/issues/14104) | [no](https://github.com/openlayers/openlayers/issues/14104) |
@@ -143,8 +145,8 @@ adb shell am start -n "de.dennisguse.opentracks.playstore/de.dennisguse.opentrac
| [FitTrackee](https://github.com/SamR1/FitTrackee) | yes | n/a | n/a |
| [SportsTracker](https://github.com/ssaring/sportstracker) | yes, [single tracks only](https://github.com/ssaring/sportstracker/issues/260) | no | no |
| [ExifTool](https://exiftool.org) | [yes](https://exiftool.org/forum/index.php?topic=15972.0) | no | no |
| [Wanderer](https://wanderer.to/) | yes | yes | yes |
| [Wanderer](https://wanderer.to/) | yes | yes | yes |
| [GPX.Studio]https://gpx.studio/) | yes | no | no |
## Dashboard API (incl. map)
+4 -1
View File
@@ -44,7 +44,10 @@ However, often only one value is provided.
We only support _Instantaneous Power_.
For cycling (incl. cadence):
* Assioma Duo Powermeter
* Assioma
* Duo Powermeter
* Pro MX-2
* Elite drivo II
* QUARQ Red DZero Powermeter
* Tacx Satori Smart
+2 -5
View File
@@ -11,9 +11,6 @@ CHANGELOG_FILE="$CHANGELOG_DIR/$VERSIONID.txt"
git diff --exit-code || echo -e "\nWARNING WARNING WARNING WARNING WARNING: this branch contains uncommit changes."
#TODO Execute all tests: we are destroying data, running on a real device.
# ./gradlew connectedCheck
# Changelog
echo -e "\nPrevious changelog\n------------"
PREVIOUS_CHANGELOG=$(find "$CHANGELOG_DIR" -iname "[[:digit:]]**.txt" | sort -n | tail -1)
@@ -34,8 +31,8 @@ gedit -w "$CHANGELOG_FILE"
git add "$CHANGELOG_FILE"
echo "Updating build.gradle"
sed -i s/versionCode\ .*/versionCode\ "$VERSIONID"/g build.gradle
sed -i s/versionName\ .*/versionName\ "\"$VERSIONNAME\""/g build.gradle
sed -i -e "s/versionCode\ [0-9]\{1,\}/versionCode\ $VERSIONID/g" build.gradle
sed -i -e "s/versionName\ \"v[0-9\.]\{1,\}\"/versionName\ \"$VERSIONNAME\"/g" build.gradle
git diff
+7 -2
View File
@@ -6,8 +6,13 @@ export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64/
JAVA_VERSION=`java --version`
if [[ $JAVA_VERSION != "openjdk 21."* ]]; then
echo "OpenJDK version should be 21.X"
exit -1;
echo -e "OpenJDK version should be 21.X"
fi
git diff --exit-code || echo -e "\nWARNING WARNING WARNING WARNING WARNING: this branch contains uncommit changes."
if [[ $(git log "$(git describe --tags --abbrev=0)..HEAD" --no-merges --oneline | wc -l) -gt 0 ]]; then
echo -e "No version tag for this commit; please use RELEASE.sh";
fi
RELEASE_STORE_PASSWORD=
+31 -25
View File
@@ -6,7 +6,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.11.1'
classpath 'com.android.tools.build:gradle:9.0.0'
}
}
@@ -21,7 +21,7 @@ def getVersionName = { ->
return 'git describe --tags'.execute().text.trim()
}
def getVersionCode = { ->
def getVersionCodeNightly = { ->
return Integer.valueOf('git rev-list HEAD --count'.execute().text.trim())
}
@@ -38,6 +38,7 @@ android {
buildFeatures {
viewBinding = true
buildConfig = true
resValues = true
}
androidResources {
@@ -46,8 +47,8 @@ android {
defaultConfig {
applicationId 'de.dennisguse.opentracks'
versionCode 6338
versionName "v4.23.0"
versionCode 6554
versionName "v4.25.1"
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
@@ -57,6 +58,17 @@ android {
testInstrumentationRunner 'de.dennisguse.opentracks.TestRunner'
testInstrumentationRunnerArguments clearPackageData: 'true'
}
testOptions {
managedDevices {
localDevices {
mediumPhone {
device = "Medium Phone"
apiLevel = 35
systemImageSource = "aosp"
}
}
}
}
signingConfigs {
nightly {
if (System.getProperty('nightly_store_file') != null) {
@@ -95,12 +107,19 @@ android {
nightly {
dimension 'version'
applicationId 'de.dennisguse.opentracks.nightly'
resValue 'string', 'applicationId', 'de.dennisguse.opentracks.nightly'
versionCode getVersionCodeNightly()
versionName getVersionName()
base.archivesName = "de.dennisguse.opentracks.nightly_${getVersionCodeNightly()}"
signingConfig = signingConfigs.nightly
}
irreproducible {
// Non-reproducible: https://f-droid.org/de/packages/de.dennisguse.opentracks/
dimension 'version'
applicationId 'de.dennisguse.opentracks'
resValue 'string', 'applicationId', 'de.dennisguse.opentracks'
versionNameSuffix 'irreproducible'
}
reproducible {
@@ -109,27 +128,14 @@ android {
// PlayStore: https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore
dimension 'version'
applicationId 'de.dennisguse.opentracks.playstore'
resValue 'string', 'applicationId', 'de.dennisguse.opentracks.playstore'
base.archivesName = "de.dennisguse.opentracks.playstore_${getVersionName()}_${android.defaultConfig.versionCode}"
signingConfig = signingConfigs.release
}
}
applicationVariants.configureEach { variant ->
variant.resValue 'string', 'applicationId', variant.applicationId
variant.outputs.configureEach {
if (variant.flavorName == 'nightly') {
setVersionCodeOverride(getVersionCode())
setVersionNameOverride(getVersionName())
}
if (variant.flavorName == 'reproducible') {
outputFileName = "${applicationId}_${variant.versionName}.apk"
} else {
outputFileName = "${applicationId}_${variant.versionCode}.apk"
}
}
}
dependenciesInfo {
// Disables dependency metadata when building APKs.
includeInApk = false
@@ -149,17 +155,17 @@ dependencies {
implementation 'com.google.android.material:material:1.13.0'
implementation 'androidx.constraintlayout:constraintlayout:2.2.1'
implementation 'androidx.core:core:1.17.0'
implementation 'androidx.core:core-splashscreen:1.0.1'
implementation 'androidx.core:core-splashscreen:1.2.0'
implementation 'androidx.mediarouter:mediarouter:1.8.1'
implementation 'androidx.core:core-location-altitude:1.0.0-alpha03'
implementation 'androidx.work:work-runtime:2.10.5'
implementation 'androidx.core:core-location-altitude:1.0.0-beta01'
implementation 'androidx.work:work-runtime:2.11.1'
androidTestImplementation 'androidx.test:core:1.7.0'
androidTestImplementation 'androidx.test.ext:junit:1.3.0'
androidTestImplementation 'androidx.test:rules:1.7.0'
androidTestImplementation 'androidx.test:runner:1.7.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.7.0'
androidTestImplementation 'org.mockito:mockito-android:5.19.0'
androidTestImplementation 'org.mockito:mockito-android:5.21.0'
androidTestUtil 'androidx.test:orchestrator:1.6.1'
}
@@ -0,0 +1,17 @@
v3.0.1: OpenTracks
Änderungen:
- Markierungen teilen
- Umstrukturierte Einstellungen
- Zurück-Schaltfläche in der Aktionsleiste entfernt
- Export: Option zur Einstellung der Fotogröße entfernt
- Export: KML als Format ist jetzt auswählbar
Fehlerbehebungen:
- Exportverzeichnis ist jetzt /OpenTracks/
- Querformatmodus stürzt nicht mehr ab
- KML/KMZ-Export behoben
Entwickler:
- Tests sind ausführbar (aber viele schlagen fehl)
- Kontinuierliche Integration mit TravisCI aktiviert (keine Tests)
@@ -0,0 +1,14 @@
v3.1.0: OpenTracks
Änderungen:
- Anzeige der Strecke in Karten-Apps hinzugefügt (getestet mit OsmAnd und Maps.ME)
- Während der Verfolgung werden Streckenstatistiken angezeigt, ohne das Gerät entsperren zu müssen
- Querformat für die Detailansicht der Strecke entfernt (war fehlerhaft)
- Verlauf der Suchvorschläge entfernt
Fehlerbehebung:
- Speicherberechtigung für „Alle importieren/Alle exportieren” anfordern
Entwickler:
- Upgrade auf Gradle 5.6
- Release-Builds nicht minimieren
@@ -0,0 +1,10 @@
v4.23.0: OpenTracks
Änderungen:
- Benutzeroberfläche: Durchschnittsgeschwindigkeit des aktuellen Segments hinzugefügt
(derzeit nur in neuen Layouts verfügbar)
- Durch Klicken auf die Benachrichtigung wird die eigentliche Aufzeichnungs-Benutzeroberfläche geöffnet
Entwickler:
- Veralteter JobIntentService durch WorkManager ersetzt
- Verwende .isEmpty() außer für CharSequence und Stream.toList()
@@ -0,0 +1,8 @@
v4.23.1: OpenTracks
Änderungen:
- Neue UI-Komponente zur Anzeige der verstrichenen Zeit im aktuellen Segment
Fehlerbehebung:
- Sofortiger Export nach Workout abgestürzt (eingeführt in v4.23.0)
@@ -0,0 +1,10 @@
v4.23.2: OpenTracks
Änderungen:
- Vorausschauende Rückwärtsfunktion funktioniert vollständig
Fehlerbehebung:
- Absturz im Zusammenhang mit dem Dateinamen der Strecke in den Einstellungen behoben
Entwickler:
- Datenklasse für Statistiken eingeführt
@@ -0,0 +1,7 @@
v4.23.1: OpenTracks
Changes:
- New UI component to show elapsed time in the current segment
Bugfix:
- Instant post-workout export crashed (introduced in v4.23.0)
@@ -0,0 +1,10 @@
v4.23.2: OpenTracks
Changes:
- Predictive back works completely
Bugfix:
- Fixed in crash related to the track filename in the settings
Developer:
- Introduced data class for Statistics
@@ -0,0 +1,15 @@
v4.24.0: OpenTracks
Changes:
- PublicAPI: start track only sets field if data is present
- Marker photos can be shared again
- Removed KMZ without photos
- Heart rate of 0.0 is treated as invalid (except for SensorStatistics)
- Removed import workaround for special coordinates (100/200)
(was used by MyTracks to export/import special trackpoints)
Developer:
- Track and Marker are records
- AggregatedStatistics are computed in database
- Split into TrackStatisticsUpdater and SegmentStatisticUpdater
- Introduced Iterator classes (instead of passing Cursor or List)
@@ -0,0 +1,6 @@
v4.24.1: OpenTracks
Bugfix:
- Restore compatibility with OSM Dashboard v6.4.1 and earlier (introduced in v4.24.0)
- Crash when using default track name by number (introduced in v4.24.0)
@@ -0,0 +1,4 @@
v4.24.2: OpenTracks
Bugfix:
- Crash when select all (introduced in v4.24.0)
@@ -0,0 +1,13 @@
v4.25.0: OpenTracks
Changes:
- Record button is centered
- Support for BLE thermometer (Environmental Sensing)
Bugfix:
- On import: get type from filename (not URI)
Developer:
- TrackPoint is a record
- Update to Android Gradle Plugin 9.0
@@ -0,0 +1,7 @@
v4.25.1: OpenTracks
Bugfix:
- Since v4.24.0, the API for transferring data to OSM Dashboard was broken.
Sadly, the changes in OpenTracks could not be reverted.
Thus, the protocol version was bumped to 3.
This requires updating OSM Dashboard to a version AFTER v6.5.7.
@@ -0,0 +1,10 @@
v4.23.2: OpenTracks
Cambios:
- a volta predictiva funciona
Arranxo:
- do fallo que daba relacionado co nome do ficheiro nos axustes
Desenvolvemento:
- Engádese data class para as Estatísticas
@@ -4,7 +4,7 @@ Modifiche:
- Velocità degli annunci vocali configurabile
- API <26: L'icona del lanciatore omette lo sfondo
Bugfix:
Correzioni:
- UI di registrazione: mostra i valori corretti
- Registrazione UI: mostra (di nuovo) l'altitudine in EGM2008
@@ -1,4 +1,4 @@
v4.22.1: OpenTracks
Modiciche:
Modifiche:
- Primo rilascio da Codeberg
@@ -1,4 +1,4 @@
v4.22.2: OpenTracks
Correzione di errori:
Correzioni:
- L'impostazione degli annunci vocali per l'ora e l'unità di misura è stata collegata
@@ -3,7 +3,7 @@
Modifiche:
-
Correzioni di errori:
Correzioni:
-
Sviluppatore:
@@ -1 +1 @@
Un tracker sportivo che rispetta completamente la tua privacy.
Un tracker sportivo che rispetta la tua privacy.
@@ -1,6 +1,6 @@
v3.0.0: Opentracks
v3.0.0: திறந்தபாதைகள்
ஓபன்ட்ராக்சின் முதல் வெளியீடு (அதாவது, மைட்ராக்சிலிருந்து ஆர்ட் ஃபோர்க்)
திறந்தபாதைகளின் முதல் வெளியீடு (அதாவது, மைட்ராக்சிலிருந்து ஆர்ட் ஃபோர்க்)
மாற்றங்கள்:
- மைட்ராக்சிலிருந்து ஓபன்ட்ராக்சுக்கு மறுபெயரிடப்பட்டது
@@ -1,4 +1,4 @@
v3.8.0: Opentracks
v3.8.0: திறந்தபாதைகள்
மாற்றத்தை உடைத்தல்:
- சிபிஎக்ச் இறக்குமதி/ஏற்றுமதி விரைவு, கேடென்ச் மற்றும் ஆர்ட்ரேட் டிராக் பாயிண்ட் எக்ச்டென்சன்/வி 2 வழியாக
@@ -6,7 +6,7 @@ v3.8.0: Opentracks
மாற்றங்கள்:
- டாச்போர்டு ஏபிஐ: குறிப்பான்களுக்கான அணுகலை வழங்குதல் (ஓபன்ட்ராக்சில் காண்பிக்க திரும்பப்பெறுதல்)
- புதிய மார்க்கர் படவுரு (ஆரஞ்சு புச் முள், எச்.வி.சி)
- இறக்குமதிக்கான கோப்புகளை கோப்பு மேலாளர் வழியாக தேர்ந்தெடுக்கலாம்
- இறக்குமதிக்கான கோப்புகளைக் கோப்பு மேலாளர் வழியாகத் தேர்ந்தெடுக்கலாம்
பிழைத்திருத்தங்கள்:
- ஒருங்கிணைந்த புள்ளிவிவரங்கள் இடைமுகம் விருப்பமான விகிதத்தை மதிக்கிறது
@@ -1,4 +1,4 @@
v3.9.0: Opentracks
v3.9.0: திறந்தபாதைகள்
மாற்றங்கள்:
- தடங்களை அவற்றின் UUID உடன் ஏற்றுமதி செய்யுங்கள்
@@ -1,4 +1,4 @@
v3.12.0: ஓபன்ட்ராக்ச்
v3.12.0: திறந்தபாதைகள்
மாற்றங்கள்:
- ஊடலை சென்சார் முகவரிகள்
@@ -1,4 +1,4 @@
v3.15.0: ஓபன்ட்ராக்ச்
v3.15.0: திறந்தபாதைகள்
எச்சரிக்கை:
இந்த வெளியீடு மாற்ற முடியாத தரவுத்தள மாற்றங்களைப் பயன்படுத்துகிறது.
@@ -14,7 +14,7 @@ v3.15.0: ஓபன்ட்ராக்ச்
(தயவுசெய்து OSMDashboard 2.10.0 ஐ மேம்படுத்தவும்)
மாற்றங்கள்:
- KML/KMZ சரியாக காப்புப் பிரதி எடுக்கவும் மீட்டமைக்கவும் பயன்படுத்தலாம் (புள்ளிவிவரங்கள் உட்பட)
- KML/KMZ சரியாகக் காப்புப் பிரதி எடுக்கவும் மீட்டமைக்கவும் பயன்படுத்தலாம் (புள்ளிவிவரங்கள் உட்பட)
டெவலப்பர்:
- மறுவேலை செய்யப்பட்ட தட பிரிவு மற்றும் அது சேமிப்பு (முன்னர் இடைநிறுத்தம்/மீண்டும் மார்க்கர்)
@@ -1,4 +1,4 @@
v3.16.0: ஓபன்ட்ராக்ச்
v3.16.0: திறந்தபாதைகள்
மாற்றங்கள்:
- சைக்கிள் ஓட்டுதல்: பி.எல்.இ வேக சென்சாரிலிருந்து தூரத்தைப் பெறுங்கள்
@@ -1,4 +1,4 @@
v3.17.0: Opentracks
v3.17.0: திறந்தபாதைகள்
மாற்றங்கள்:
- கயாக்கிங்கிற்கு ஐகானைச் சேர்க்கவும்
@@ -1,4 +1,4 @@
v3.18.0: ஓபன்ட்ராக்ச்
v3.18.0: திறந்தபாதைகள்
மாற்றங்கள்:
- உயரம் EGM2008 இல் காட்டப்பட்டுள்ளது (WGS84 எனச் சேமிக்கப்படுகிறது/ஏற்றுமதி செய்யப்படுகிறது)
@@ -1,4 +1,4 @@
v3.18.3: ஓபன்ட்ராக்ச்
v3.18.3: திறந்தபாதைகள்
மாற்றங்கள்:
- KML பாகுபடுத்தலுக்கு/GX: KOURS இன் ஆர்டர் தேவையில்லை
@@ -1,4 +1,4 @@
v3.18.6: Opentracks
v3.18.6: திறந்தபாதைகள்
மாற்றங்கள்:
- "வரைபடத்தில் காட்டு"- KMZ க்கு பதிலாக KML வழியாகச் செயல்பாடு
@@ -1,4 +1,4 @@
v3.19.0: Opentracks
v3.19.0: திறந்தபாதைகள்
மாற்றங்கள்:
- இயங்கும் விரைவு மற்றும் கேடென்ச் (ஆர்.சி.எச்) சென்சார்களுக்கான உதவி செயல்படுத்தப்பட்டது
@@ -1,4 +1,4 @@
v3.20.2: ஓபன்ட்ராக்ச்
v3.20.2: திறந்தபாதைகள்
மாற்றங்கள்:
- மிதவைகளுக்குப் பதிலாக உயரத்தை ஆதாயம் மற்றும் இழப்பு என்பது எண்கள்
@@ -1,4 +1,4 @@
v3.21.0: Opentracks
v3.21.0: திறந்தபாதைகள்
மாற்றங்கள்:
- பதிவு செய்யும்போது: டிராக் பாயிண்டுகளின் செயலற்ற அல்லாத உருவாக்கத்தை அகற்று
@@ -1,4 +1,4 @@
v3.24.0: Opentracks
v3.24.0: திறந்தபாதைகள்
மாற்றங்கள்:
- சி.பி.எச் விருப்பமானது (உட்புற பயன்பாட்டிற்கும்): தூரத்தை வழங்கும் பி.எல்.இ சென்சார்களைப் பயன்படுத்தினால் பயன்படுத்தப்பட்டால்
@@ -1,4 +1,4 @@
v3.24.1: Opentracks
v3.24.1: திறந்தபாதைகள்
மாற்றங்கள்:
- பிற பயன்பாடுகளிலிருந்து பதிவுகளைத் தொடங்க பநிஇ சேர்க்கப்பட்டது (இயல்பாக முடக்கப்பட்டுள்ளது)
@@ -1,8 +1,8 @@
V3.27.0: Opentracks
V3.27.0: திறந்தபாதைகள்
மாற்றங்கள்:
- குரல் அன்னியூசென்ச்: 100 மீ, 200 மீ மற்றும் 500 மீ
- இடைவெளி: 100 மீ மற்றும் 500 மீ சேர்க்கவும்
- இடைவெளி: 100 மீ மற்றும் 500 மீ சேர்
- கடிகாரம் இப்போது விநாடிகளையும் காட்டுகிறது
- சி.பி.எக்ச், கே.எம்.எல், கே.எம்.இசட்: கிடைமட்ட துல்லியத்தை ஏற்றுமதி செய்து இறக்குமதி செய்க
- சி.பி.எக்ச்: கிளச்ட்ரச்ட் நீட்டிப்பு வழியாக ஒட்டுமொத்த தூரத்தை ஏற்றுமதி செய்யுங்கள்
@@ -1,4 +1,4 @@
v4.0.0: Opentracks
v4.0.0: திறந்தபாதைகள்
மாற்றங்கள்:
- கீழ் பயன்பாட்டு பட்டியுடன் இடைமுகம் மறுசீரமைப்பு.
@@ -1,4 +1,4 @@
V4.0.1: Opentracks
V4.0.1: திறந்தபாதைகள்
மாற்றங்கள்:
- குரல் அறிவிப்புகள் இப்போது கட்டமைக்கப்படுகின்றன
@@ -1,4 +1,4 @@
V4.9.0: Opentracks
V4.9.0: திறந்தபாதைகள்
குறிப்பு: மாற்றத்தை உடைத்தல்
@@ -1,4 +1,4 @@
V4.10.0: Opentracks
V4.10.0: திறந்தபாதைகள்
மாற்றங்கள்:
- BLE சுற்றுச்சூழல் உணர்திறன் (காற்றழுத்தமானி) வழியாக உதவி ஆதாயம்/இழப்பு
@@ -1,4 +1,4 @@
v4.13.0: ஓபன்ட்ராக்ச்
v4.13.0: திறந்தபாதைகள்
மாற்றங்கள்:
- பொது பநிஇ வழியாகக் குறிப்பான்களை உருவாக்க முடியும்
@@ -0,0 +1,4 @@
v4.22.0: OpenTracks
மாற்றங்கள்:
- https://codeberg.org/OpenTracksApp/OpenTracks க்கு இடம்பெயர்தல்
@@ -0,0 +1,4 @@
v4.22.1: OpenTracks
மாற்றங்கள்:
- கோட்பெர்க் வழியாக முதல் வெளியீடு
@@ -0,0 +1,3 @@
v4.22.2: திறந்தபாதைகள்
பிழைத்திருத்தம்:
- நேரம் மற்றும் அலகுக்கான குரல் அறிவிப்பு அமைப்பு இணைக்கப்பட்டது
@@ -0,0 +1,10 @@
v4.23.0: OpenTracks
மாற்றங்கள்:
- UI: தற்போதைய பிரிவின் சராசரி வேகத்தைச் சேர்த்தது
(தற்போது புதிய தளவமைப்புகளில் மட்டுமே கிடைக்கிறது)
- அறிவிப்பைக் சொடுக்கு செய்வதன் மூலம் உண்மையான பதிவு இடைமுகம் திறக்கும்
டெவலப்பர்:
- நிராகரிக்கப்பட்ட JobIntentService, WorkManager உடன் மாற்றப்பட்டது
- CharSequence மற்றும் Stream.toList() தவிர .isEmpty() ஐப் பயன்படுத்தவும்
@@ -0,0 +1,7 @@
v4.23.1: OpenTracks
மாற்றங்கள்:
- தற்போதைய பிரிவில் கழிந்த நேரத்தைக் காட்ட புதிய இடைமுகம் கூறு
பிழைத்திருத்தம்:
- உடற்பயிற்சிக்குப் பிந்தைய உடனடி ஏற்றுமதி செயலிழந்தது (v4.23.0 இல் அறிமுகப்படுத்தப்பட்டது)
@@ -0,0 +1,10 @@
v4.23.2: OpenTracks
மாற்றங்கள்:
- முன்கணிப்பு முற்றிலும் வேலை செய்கிறது
பிழைத்திருத்தம்:
- அமைப்புகளில் டிராக் கோப்புப் பெயருடன் தொடர்புடைய செயலிழப்பில் சரி செய்யப்பட்டது
டெவலப்பர்:
- புள்ளிவிவரங்களுக்கான தரவு வகுப்பு அறிமுகப்படுத்தப்பட்டது
@@ -0,0 +1,15 @@
v4.24.0: OpenTracks
மாற்றங்கள்:
- PublicAPI: தரவு இருந்தால் ஸ்டார்ட் டிராக் மட்டுமே புலத்தை அமைக்கும்
- மார்க்கர் புகைப்படங்களை மீண்டும் பகிரலாம்
- புகைப்படங்கள் இல்லாமல் KMZ அகற்றப்பட்டது
- இதயத் துடிப்பு 0.0 தவறானதாகக் கருதப்படுகிறது (சென்சார் ஸ்டாடிஸ்டிக்ஸ் தவிர)
- சிறப்பு ஒருங்கிணைப்புகளுக்கான இறக்குமதி தீர்வு நீக்கப்பட்டது (100/200)
(சிறப்பு டிராக் பாயிண்ட்களை ஏற்றுமதி/இறக்குமதி செய்ய MyTracks பயன்படுத்தியது)
டெவலப்பர்:
- ட்ராக் மற்றும் மார்க்கர் பதிவுகள்
- திரட்டப்பட்ட புள்ளிவிவரங்கள் தரவுத்தளத்தில் கணக்கிடப்படுகின்றன
- TrackStatisticsUpdater மற்றும் SegmentStatisticUpdater எனப் பிரிக்கவும்
- அறிமுகப்படுத்தப்பட்ட இட்டரேட்டர் வகுப்புகள் (கர்சர் அல்லது பட்டியலைக் கடந்து செல்வதற்குப் பதிலாக)
@@ -0,0 +1,5 @@
v4.24.1: OpenTracks
பிழைத்திருத்தம்:
- OSM டாஷ்போர்டு v6.4.1 மற்றும் அதற்கு முந்தையவற்றுடன் இணக்கத்தன்மையை மீட்டெடுக்கவும் (v4.24.0 இல் அறிமுகப்படுத்தப்பட்டது)
- எண்ணின்படி இயல்புநிலை ட்ராக் பெயரைப் பயன்படுத்தும்போது செயலிழக்கிறது (v4.24.0 இல் அறிமுகப்படுத்தப்பட்டது)
@@ -0,0 +1,4 @@
v4.24.2: OpenTracks
பிழைத்திருத்தம்:
- அனைத்தையும் தேர்ந்தெடுக்கும்போது செயலிழக்க (v4.24.0 இல் அறிமுகப்படுத்தப்பட்டது)
@@ -0,0 +1,12 @@
v4.25.0: OpenTracks
மாற்றங்கள்:
- பதிவுப் பொத்தான் மையமாக உள்ளது
- BLE தெர்மோமீட்டருக்கான ஆதரவு (சுற்றுச்சூழல் உணர்தல்)
பிழைத்திருத்தம்:
- இறக்குமதியில்: கோப்பு பெயரிலிருந்து வகையைப் பெறுங்கள் (URI அல்ல)
டெவலப்பர்:
- TrackPoint ஒரு பதிவு
- Android Gradle செருகுநிரல் 9.0 க்கு புதுப்பிக்கவும்
@@ -17,6 +17,6 @@
* 深色和浅色主题,跟随系统设置。
* 无广告。
‌自由软件/开放源代码
自由软件/开放源代码
意味着您可以使用、研究、修改和分享源代码。
采用 Apache 2.0 许可
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-9.0.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Vendored
-3
View File
@@ -114,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM.
@@ -172,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -212,7 +210,6 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
Vendored
+93 -94
View File
@@ -1,94 +1,93 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
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
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
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
:execute
@rem Setup the command line
set CLASSPATH=
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
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
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
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
:execute
@rem Setup the command line
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
Binary file not shown.
+3
View File
@@ -0,0 +1,3 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
}
@@ -36,7 +36,8 @@ public class EspressoDeleteTrackTest {
@Test
public void espressoDeleteTrackTest() {
// TrackListActivity: start recording
onView(withId(R.id.track_list_fab_action)).perform(click());
onView(withId(R.id.track_list_fab_action))
.perform(click());
// TrackRecordingActivity
onView(withId(R.id.track_recording_fab_action))
@@ -46,13 +47,14 @@ public class EspressoDeleteTrackTest {
.perform(longClick());
// TrackStoppedActivity
onView(withId(R.id.finish_button)).perform(click());
onView(withId(R.id.finish_button))
.perform(click());
// select track
onView(allOf(withParent(withId(R.id.track_list)), withParentIndex(0))).perform(longClick());
onView(allOf(withParent(withId(R.id.track_list)), withParentIndex(0)))
.perform(longClick());
// open menu and delete selected track
//TODO openActionBarOverflowOrOptionsMenu(); doesn't work
onView(
allOf(withContentDescription("More options"),
childAtPosition(
@@ -63,9 +65,11 @@ public class EspressoDeleteTrackTest {
isDisplayed()))
.perform(click());
onView(withText("Delete")).perform(click());
onView(withText("Delete"))
.perform(click());
onView(withText("OK")).perform(click());
onView(withText("OK"))
.perform(click());
// tracklist is empty now
onView(allOf(withText("Start recording your next adventure here"), isDisplayed()));
@@ -15,7 +15,6 @@ import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;
import static de.dennisguse.opentracks.util.EspressoUtils.waitFor;
import androidx.test.espresso.ViewInteraction;
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
@@ -45,41 +44,43 @@ public class EspressoEditTrackRecordingTest {
public void espressoEditTrackRecordingTest() {
{
// TrackListActivity: start recording
ViewInteraction fabRecordButton = onView(withId(R.id.track_list_fab_action));
fabRecordButton.perform(click());
onView(withId(R.id.track_list_fab_action))
.perform(click());
}
{
// TrackRecordingActivity
ViewInteraction trackControllerStopButton = onView(withId(R.id.track_recording_fab_action));
// wait; stay recording
trackControllerStopButton.perform(waitFor(4000));
onView(withId(R.id.track_recording_fab_action))
.perform(waitFor(4000));
// open menu
openContextualActionModeOverflowMenu();
// Click the item.
onView(withText(R.string.menu_edit)).perform(click());
onView(withText(R.string.menu_edit))
.perform(click());
// change name for "New Name"
ViewInteraction textInputEditText = onView(withId(R.id.track_edit_name));
textInputEditText.perform(scrollTo(), replaceText("New Name"));
onView(withId(R.id.track_edit_name))
.perform(scrollTo(), replaceText("New Name"));
ViewInteraction textInputEditText2 = onView(allOf(withId(R.id.track_edit_name), withText("New Name"), isDisplayed()));
textInputEditText2.perform(closeSoftKeyboard());
onView(allOf(withId(R.id.track_edit_name), withText("New Name"), isDisplayed()))
.perform(closeSoftKeyboard());
// save edition
ViewInteraction appCompatButton = onView(withId(R.id.track_edit_save));
appCompatButton.perform(click());
onView(withId(R.id.track_edit_save))
.perform(click());
// stop;
trackControllerStopButton.perform(longClick());
onView(withId(R.id.track_recording_fab_action))
.perform(longClick());
// it's on track stopped activity and there are two buttons
ViewInteraction resumeButton = onView(withId(R.id.resume_button));
resumeButton.check(matches(isDisplayed()));
ViewInteraction finishButton = onView(withId(R.id.finish_button));
finishButton.check(matches(isDisplayed()));
onView(withId(R.id.resume_button))
.check(matches(isDisplayed()));
onView(withId(R.id.finish_button))
.check(matches(isDisplayed()));
}
}
}
@@ -37,8 +37,8 @@ public class EspressoUITest {
public void record_stop_resume_stop_finish() {
{
// TrackListActivity: start recording
ViewInteraction trackControllerRecordButton = onView(withId(R.id.track_list_fab_action));
trackControllerRecordButton.perform(click());
onView(withId(R.id.track_list_fab_action))
.perform(click());
}
{
// TrackRecordingActivity: wait to record some time and then stop
@@ -66,13 +66,12 @@ public class EspressoUITest {
public void record_move_through_tabs() {
{
// TrackListActivity: start recording
ViewInteraction trackControllerRecordButton = onView(withId(R.id.track_list_fab_action));
trackControllerRecordButton.perform(click());
onView(withId(R.id.track_list_fab_action))
.perform(click());
}
{
// TrackRecordingActivity
ViewInteraction tabLayout = onView(withId(R.id.track_detail_activity_tablayout));
ViewInteraction trackControllerStopButton = onView(withId(R.id.track_recording_fab_action));
tabLayout.perform(selectTabAtIndex(1));
tabLayout.perform(waitFor(1000));
@@ -87,7 +86,8 @@ public class EspressoUITest {
tabLayout.perform(waitFor(1000));
// stop
trackControllerStopButton.perform(longClick());
onView(withId(R.id.track_recording_fab_action)).
perform(longClick());
}
}
@@ -1,99 +0,0 @@
package de.dennisguse.opentracks.chart;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.time.Duration;
import de.dennisguse.opentracks.data.models.Altitude;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.settings.UnitSystem;
import de.dennisguse.opentracks.stats.TrackStatistics;
@RunWith(AndroidJUnit4.class)
public class ChartPointTest {
@Test
public void create_by_time() {
// given
TrackStatistics statistics = new TrackStatistics();
statistics.setTotalTime(Duration.ofSeconds(1000));
// when
ChartPoint point = ChartPoint.create(statistics, TrackStubUtils.createDefaultTrackPoint(), Speed.of(0), false, UnitSystem.IMPERIAL_FEET);
// then
assertEquals(1000000, (long) point.timeOrDistance());
}
@Test
public void create_by_distance() {
// given
TrackStatistics statistics = new TrackStatistics();
statistics.setTotalDistance(Distance.of(1000));
// when
ChartPoint point = ChartPoint.create(statistics, TrackStubUtils.createDefaultTrackPoint(), Speed.of(0), true, UnitSystem.METRIC);
// then
assertEquals(1, (long) point.timeOrDistance());
}
@Test
public void create_get_altitude_speed_and_pace() {
// given
TrackStatistics statistics = new TrackStatistics();
TrackPoint trackPoint = TrackStubUtils.createDefaultTrackPoint()
.setAltitude(Altitude.EGM2008.of(50));
// when
ChartPoint point = ChartPoint.create(statistics, trackPoint, Speed.of(10), false, UnitSystem.METRIC);
// then
assertEquals(50, point.altitude(), 0.01);
assertEquals(36, point.speed(), 0.01);
assertEquals(1.66, point.pace(), 0.01);
}
@Test
public void create_sensorNotAvailable() {
// given
TrackStatistics statistics = new TrackStatistics();
TrackPoint trackPoint = TrackStubUtils.createDefaultTrackPoint()
.setAltitude(Altitude.EGM2008.of(50));
// when
ChartPoint point = ChartPoint.create(statistics, trackPoint, Speed.of(10), false, UnitSystem.METRIC);
// then
assertNull(point.heartRate());
assertNull(point.cadence());
assertNull(point.power());
}
@Test
public void create_sensorAvailable() {
// given
TrackPoint trackPoint = TrackStubUtils.createDefaultTrackPoint()
.setAltitude(Altitude.EGM2008.of(50))
.setHeartRate(100f)
.setCadence(101f)
.setPower(102f);
TrackStatistics statistics = new TrackStatistics();
// when
ChartPoint point = ChartPoint.create(statistics, trackPoint, Speed.of(10), false, UnitSystem.METRIC);
// then
assertEquals(100.0, point.heartRate(), 0.01);
assertEquals(101.0, point.cadence(), 0.01);
assertEquals(102.0, point.power(), 0.01);
}
}
@@ -1,70 +0,0 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* 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.
*/
package de.dennisguse.opentracks.chart;
import java.time.Instant;
import de.dennisguse.opentracks.data.models.Altitude;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Position;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.TrackPoint;
/**
* Commons utilities for creating stubs of track, location.
*
* @author Youtao Liu
*/
//TODO Move to ChartPointTest
class TrackStubUtils {
public static final double INITIAL_ALTITUDE = 22;
public static final long INITIAL_TIME = 1000L;
private static final double INITIAL_LATITUDE = 22;
private static final double INITIAL_LONGITUDE = 22;
private static final Distance INITIAL_ACCURACY = Distance.of(5);
private static final Speed INITIAL_SPEED = Speed.of(10);
private static final float INITIAL_BEARING = 3.0f;
/**
* Create a MyTracks location with default values.
*
* @return a track stub.
*/
public static TrackPoint createDefaultTrackPoint() {
return createDefaultTrackPoint(INITIAL_LATITUDE, INITIAL_LONGITUDE, INITIAL_ALTITUDE);
}
/**
* Creates a {@link TrackPoint} stub with specified values.
*
* @return a SensorDataSetLocation stub.
*/
private static TrackPoint createDefaultTrackPoint(double latitude, double longitude, double altitude) {
return new TrackPoint(TrackPoint.Type.TRACKPOINT,
new Position(
Instant.ofEpochMilli(INITIAL_TIME),
latitude,
longitude,
INITIAL_ACCURACY,
Altitude.WGS84.of(altitude),
INITIAL_ACCURACY,
INITIAL_BEARING,
INITIAL_SPEED
));
}
}
@@ -6,22 +6,28 @@ import android.util.Pair;
import java.io.File;
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.MarkerIterator;
import de.dennisguse.opentracks.data.TrackPointIterator;
import de.dennisguse.opentracks.data.models.ActivityType;
import de.dennisguse.opentracks.data.models.Altitude;
import de.dennisguse.opentracks.data.models.AltitudeGainLoss;
import de.dennisguse.opentracks.data.models.Cadence;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.HeartRate;
import de.dennisguse.opentracks.data.models.Marker;
import de.dennisguse.opentracks.data.models.Position;
import de.dennisguse.opentracks.data.models.Power;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Statistics;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
import de.dennisguse.opentracks.ui.markers.MarkerUtils;
import de.dennisguse.opentracks.util.FileUtils;
@@ -37,11 +43,15 @@ public class TestDataUtil {
* Create a track without any trackPoints.
*/
public static Track createTrack(Track.Id trackId) {
Track track = new Track();
track.setId(trackId);
track.setName("Test: " + trackId.id());
return track;
return new Track(
trackId,
UUID.randomUUID(),
"Test: " + trackId.id(),
"",
"",
ActivityType.UNKNOWN,
ZoneOffset.UTC,
Statistics.DEFAULT);
}
/**
@@ -85,14 +95,10 @@ public class TestDataUtil {
createTrackPoint(i, TrackPoint.Type.SEGMENT_END_MANUAL)
);
//TODO Use TrackStatisticsUpdater
TrackStatistics stats = new TrackStatistics();
stats.setTotalDistance(Distance.of(0));
stats.setTotalTime(Duration.ofMillis(0));
List<Marker> markers = List.of(
new Marker(trackId, trackPoints.get(1), "Marker 1", "Marker description 1", "Marker category 3", "", null),
new Marker(trackId, trackPoints.get(4), "Marker 2", "Marker description 2", "Marker category 3", "", null),
new Marker(trackId, trackPoints.get(5), "Marker 3", "Marker description 3", "Marker category 3", "", null)
new Marker(null, trackId, "Marker 1", "Marker description 1", "Marker typeLocalized 3", trackPoints.get(1).position(), null),
new Marker(null, trackId, "Marker 2", "Marker description 2", "Marker typeLocalized 3", trackPoints.get(4).position(), null),
new Marker(null, trackId, "Marker 3", "Marker description 3", "Marker typeLocalized 3", trackPoints.get(5).position(), null)
);
return new TrackData(track, trackPoints, markers);
@@ -110,8 +116,10 @@ public class TestDataUtil {
return pair.first;
}
public static TrackPoint createTrackPoint(int i) {
TrackPoint trackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT,
public static TrackPoint createTrackPoint(int i, TrackPoint.Type type, AltitudeGainLoss altitudeGainLoss) {
return new TrackPoint(
null,
type,
new Position(
Instant.ofEpochSecond(i),
INITIAL_LATITUDE + (double) i / 10000.0,
@@ -121,22 +129,25 @@ public class TestDataUtil {
null,
null,
Speed.of(5f + (i / 10f))
));
trackPoint.setHeartRate(100f + i % 80);
trackPoint.setCadence(300f + i);
trackPoint.setPower(400f + i);
trackPoint.setAltitudeGain(ALTITUDE_GAIN);
trackPoint.setAltitudeLoss(ALTITUDE_LOSS);
return trackPoint;
),
null,
HeartRate.of(100f + i % 80),
null,
Cadence.of(300f + i),
Power.of(400f + i),
altitudeGainLoss
);
}
public static TrackPoint createTrackPoint(int i, TrackPoint.Type type) {
TrackPoint trackPoint = createTrackPoint(i);
trackPoint.setType(type);
return trackPoint;
return createTrackPoint(i, TrackPoint.Type.TRACKPOINT, new AltitudeGainLoss(ALTITUDE_GAIN, ALTITUDE_LOSS));
}
public static TrackPoint createTrackPoint(int i) {
return createTrackPoint(i, TrackPoint.Type.TRACKPOINT);
}
/**
* Inserts a track with locations into the database.
*
@@ -145,45 +156,41 @@ public class TestDataUtil {
*/
public static void insertTrackWithLocations(ContentProviderUtils contentProviderUtils, Track track, List<TrackPoint> trackPoints) {
contentProviderUtils.insertTrack(track);
contentProviderUtils.bulkInsertTrackPoint(trackPoints, track.getId());
contentProviderUtils.bulkInsertTrackPoint(trackPoints, track.id());
}
public static Marker createMarkerWithPhoto(Context context, Track.Id trackId, TrackPoint trackPoint) throws IOException {
return createMarkerWithPhoto(context, trackId, trackPoint, "Marker description");
}
public static Marker createMarkerWithPhoto(Context context, Track.Id trackId, TrackPoint trackPoint, String description) throws IOException {
File dstFile = new File(MarkerUtils.getImageUrl(context, trackId));
dstFile.createNewFile();
Uri photoUri = FileUtils.getUriForFile(context, dstFile);
//TODO Use TrackStatisticsUpdater
TrackStatistics stats = new TrackStatistics();
stats.setTotalDistance(Distance.of(0));
stats.setTotalTime(Duration.ofMillis(0));
return new Marker(trackId, trackPoint, "Marker name", "Marker description", "Marker category", "", photoUri);
return new Marker(
null,
trackId,
"Marker name",
description,
"Marker typeLocalized",
trackPoint.position(),
photoUri);
}
public static List<TrackPoint> getTrackPoints(ContentProviderUtils contentProviderUtils, Track.Id trackId) {
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointIterator(trackId, null)) {
ArrayList<TrackPoint> trackPoints = new ArrayList<>();
while (trackPointIterator.hasNext()) {
trackPoints.add(trackPointIterator.next());
}
trackPointIterator.forEachRemaining(trackPoints::add);
return trackPoints;
}
}
public static Pair<Track.Id, TrackStatistics> buildTrackWithTrackPoints(ContentProviderUtils contentProviderUtils, int numberOfPoints) {
Track dummyTrack = new Track();
dummyTrack.setId(new Track.Id(System.currentTimeMillis()));
dummyTrack.setName("Dummy Track");
contentProviderUtils.insertTrack(dummyTrack);
TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater();
for (int i = 0; i < numberOfPoints; i++) {
TrackPoint tp = TestDataUtil.createTrackPoint(i);
contentProviderUtils.insertTrackPoint(tp, dummyTrack.getId());
trackStatisticsUpdater.addTrackPoint(tp);
public static List<Marker> getMarkers(ContentProviderUtils contentProviderUtils, Track.Id trackId) {
try (MarkerIterator trackPointIterator = contentProviderUtils.getMarkerIterator(trackId)) {
ArrayList<Marker> markers = new ArrayList<>();
trackPointIterator.forEachRemaining(markers::add);
return markers;
}
dummyTrack.setTrackStatistics(trackStatisticsUpdater.getTrackStatistics());
contentProviderUtils.updateTrack(dummyTrack);
return new Pair<>(dummyTrack.getId(), trackStatisticsUpdater.getTrackStatistics());
}
}
@@ -6,8 +6,12 @@ import java.util.ArrayList;
import java.util.List;
import de.dennisguse.opentracks.data.models.Altitude;
import de.dennisguse.opentracks.data.models.AltitudeGainLoss;
import de.dennisguse.opentracks.data.models.Cadence;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.HeartRate;
import de.dennisguse.opentracks.data.models.Position;
import de.dennisguse.opentracks.data.models.Power;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.TrackPoint;
@@ -20,7 +24,9 @@ public class TestSensorDataUtil {
sensorDataList.add(new TestSensorDataUtil.SensorData(time, hr, cadence, power, type));
int i = trackPointList.size() + 1;
TrackPoint tp = new TrackPoint(type,
TrackPoint tp = new TrackPoint(
null,
type,
new Position(
time,
TestDataUtil.INITIAL_LATITUDE + (double) i / 10000.0,
@@ -30,19 +36,15 @@ public class TestSensorDataUtil {
null,
null,
Speed.of(5f + (i / 10f))
)
),
null,
HeartRate.ofOrNull(hr),
null,
cadence != null ? Cadence.of(cadence) : null,
power != null ? Power.of(power) : null,
new AltitudeGainLoss(3, 3)
);
if (hr != null) {
tp.setHeartRate(hr);
}
if (cadence != null) {
tp.setCadence(cadence);
}
if (power != null) {
tp.setPower(power);
}
tp.setAltitudeGain(3f);
tp.setAltitudeLoss(3f);
trackPointList.add(tp);
}
@@ -1,73 +0,0 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* 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.
*/
package de.dennisguse.opentracks.data;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.content.ContentUris;
import android.content.Context;
import android.net.Uri;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
import org.junit.Test;
import de.dennisguse.opentracks.data.tables.MarkerColumns;
import de.dennisguse.opentracks.data.tables.TrackPointsColumns;
import de.dennisguse.opentracks.data.tables.TracksColumns;
/**
* Tests {@link CustomContentProvider}.
*
* @author Youtao Liu
*/
public class CustomContentProviderTest {
private CustomContentProvider customContentProvider;
private final Context context = ApplicationProvider.getApplicationContext();
@Before
public void setUp() {
customContentProvider = new CustomContentProvider() {
};
}
/**
* Tests {@link CustomContentProvider#onCreate(android.content.Context)}.
*/
@Test
public void testOnCreate() {
assertTrue(customContentProvider.onCreate(context));
}
/**
* Tests {@link CustomContentProvider#getType(Uri)}.
*/
@Test
public void testGetType() {
assertEquals(TracksColumns.CONTENT_TYPE, customContentProvider.getType(TracksColumns.CONTENT_URI));
assertEquals(TracksColumns.CONTENT_ITEMTYPE, customContentProvider.getType(ContentUris.appendId(TracksColumns.CONTENT_URI.buildUpon(), 1).build()));
assertEquals(TrackPointsColumns.CONTENT_TYPE, customContentProvider.getType(TrackPointsColumns.CONTENT_URI_BY_ID));
assertEquals(TrackPointsColumns.CONTENT_ITEMTYPE, customContentProvider.getType(ContentUris.appendId(TrackPointsColumns.CONTENT_URI_BY_TRACKID.buildUpon(), 1).build()));
assertEquals(MarkerColumns.CONTENT_TYPE, customContentProvider.getType(MarkerColumns.CONTENT_URI));
assertEquals(MarkerColumns.CONTENT_ITEMTYPE, customContentProvider.getType(ContentUris.appendId(MarkerColumns.CONTENT_URI.buildUpon(), 1).build()));
}
}
@@ -27,7 +27,6 @@ import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.location.Location;
import android.util.Pair;
import androidx.test.core.app.ApplicationProvider;
@@ -42,6 +41,7 @@ import java.io.File;
import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
@@ -50,19 +50,26 @@ import java.util.UUID;
import de.dennisguse.opentracks.content.data.TestDataUtil;
import de.dennisguse.opentracks.content.data.TestSensorDataUtil;
import de.dennisguse.opentracks.data.models.ActivityType;
import de.dennisguse.opentracks.data.models.Altitude;
import de.dennisguse.opentracks.data.models.AltitudeExtremities;
import de.dennisguse.opentracks.data.models.AltitudeGainLoss;
import de.dennisguse.opentracks.data.models.Cadence;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.HeartRate;
import de.dennisguse.opentracks.data.models.Marker;
import de.dennisguse.opentracks.data.models.MarkerBuilder;
import de.dennisguse.opentracks.data.models.Position;
import de.dennisguse.opentracks.data.models.Power;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Statistics;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackBuilder;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.data.statistics.SensorStatistics;
import de.dennisguse.opentracks.data.tables.MarkerColumns;
import de.dennisguse.opentracks.data.tables.TrackPointsColumns;
import de.dennisguse.opentracks.data.tables.TracksColumns;
import de.dennisguse.opentracks.stats.SensorStatistics;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.util.FileUtils;
/**
@@ -114,24 +121,32 @@ public class CustomContentProviderUtilsTest {
private void testIterator(Track.Id trackId, int numPoints) {
TrackPoint.Id lastPointId = initializeTrack(trackId, numPoints);
List<TrackPoint> locations = new ArrayList<>(numPoints);
try (TrackPointIterator it = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
try (TrackPointIterator it = contentProviderUtils.getTrackPointIterator(trackId, null)) {
while (it.hasNext()) {
TrackPoint trackPoint = it.next();
assertNotNull(trackPoint);
locations.add(trackPoint);
// Make sure the IDs are returned in the right order.
assertEquals(lastPointId.id() - numPoints + locations.size(), trackPoint.getId().id());
assertEquals(lastPointId.id() - numPoints + locations.size(), trackPoint.id().id());
}
assertEquals(numPoints, locations.size());
}
}
private TrackPoint.Id initializeTrack(Track.Id id, int numPoints) {
Track track = new Track();
track.setId(id);
track.setName("Test: " + id.id());
contentProviderUtils.insertTrack(track);
track = contentProviderUtils.getTrack(id);
Track createdTrack = new Track(
id,
UUID.randomUUID(),
"Test: " + id,
"",
"",
ActivityType.UNKNOWN,
ZoneOffset.UTC,
Statistics.DEFAULT);
contentProviderUtils.insertTrack(createdTrack);
Track track = contentProviderUtils.getTrack(id);
assertNotNull(track);
List<TrackPoint> trackPoints = new ArrayList<>(numPoints);
@@ -152,10 +167,10 @@ public class CustomContentProviderUtilsTest {
// Load all inserted trackPoints.
TrackPoint.Id lastPointId = null;
int counter = 0;
try (TrackPointIterator it = contentProviderUtils.getTrackPointLocationIterator(id, null)) {
try (TrackPointIterator it = contentProviderUtils.getTrackPointIterator(id, null)) {
while (it.hasNext()) {
TrackPoint trackPoint = it.next();
lastPointId = trackPoint.getId();
lastPointId = trackPoint.id();
counter++;
}
}
@@ -193,8 +208,8 @@ public class CustomContentProviderUtilsTest {
when(cursorMock.getString(columnIndex)).thenReturn(name);
Track track = ContentProviderUtils.createTrack(cursorMock);
assertEquals(trackId, track.getId());
assertEquals(name, track.getName());
assertEquals(trackId, track.id());
assertEquals(name, track.name());
}
private void assertCount(int trackCount, int trackPointCount, int markerCount) {
@@ -219,8 +234,15 @@ public class CustomContentProviderUtilsTest {
Track.Id trackId = new Track.Id(System.currentTimeMillis());
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
Marker marker = new Marker(trackId, contentProviderUtils.getLastValidTrackPoint(trackId));
contentProviderUtils.insertMarker(marker);
contentProviderUtils.insertMarker(new Marker(
null,
trackId,
"",
"",
"",
getLastValidTrackPoint(trackId).position(),
null
));
assertCount(1, 10, 1);
@@ -238,14 +260,14 @@ public class CustomContentProviderUtilsTest {
public void testDeleteAllTracks_withMarkerAndPhoto() throws IOException {
// Insert track, points and marker with photo at first.
Track.Id trackId = new Track.Id(System.currentTimeMillis());
Track track = TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
TrackPoint trackPoint = contentProviderUtils.getLastValidTrackPoint(trackId);
TrackPoint trackPoint = getLastValidTrackPoint(trackId);
Marker marker = TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint);
contentProviderUtils.insertMarker(marker);
assertCount(1, 10, 1);
assertTrue(marker.hasPhoto());
assertNotNull(marker.photoUrl());
File dir = FileUtils.getPhotoDir(context, trackId);
assertTrue(dir.isDirectory());
assertEquals(1, dir.list().length);
@@ -275,8 +297,15 @@ public class CustomContentProviderUtilsTest {
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId2, 10);
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId3, 10);
Marker marker = new Marker(trackId1, contentProviderUtils.getLastValidTrackPoint(trackId2));
contentProviderUtils.insertMarker(marker);
contentProviderUtils.insertMarker(new Marker(
null,
trackId1,
"",
"",
"",
getLastValidTrackPoint(trackId1).position(),
null
));
assertCount(3, 30, 1);
@@ -303,19 +332,19 @@ public class CustomContentProviderUtilsTest {
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId3, 10);
// Insert a marker in tracks trackId and trackId + 1.
TrackPoint trackPoint1 = contentProviderUtils.getLastValidTrackPoint(trackId1);
TrackPoint trackPoint1 = getLastValidTrackPoint(trackId1);
Marker marker1 = TestDataUtil.createMarkerWithPhoto(context, trackId1, trackPoint1);
contentProviderUtils.insertMarker(marker1);
File dir1 = FileUtils.getPhotoDir(context, trackId1);
TrackPoint trackPoint2 = contentProviderUtils.getLastValidTrackPoint(trackId2);
TrackPoint trackPoint2 = getLastValidTrackPoint(trackId2);
Marker marker2 = TestDataUtil.createMarkerWithPhoto(context, trackId2, trackPoint2);
contentProviderUtils.insertMarker(marker2);
File dir2 = FileUtils.getPhotoDir(context, trackId2);
// Check.
assertCount(3, 30, 2);
assertTrue(marker1.hasPhoto());
assertNotNull(marker1.photoUrl());
assertTrue(dir1.isDirectory());
assertEquals(1, dir1.list().length);
assertTrue(dir1.exists());
@@ -347,7 +376,7 @@ public class CustomContentProviderUtilsTest {
// then
assertEquals(initialTrackNumber + 1, allTracks.size());
assertEquals(trackId, allTracks.get(allTracks.size() - 1).getId());
assertEquals(trackId, allTracks.get(allTracks.size() - 1).id());
}
/**
@@ -374,61 +403,57 @@ public class CustomContentProviderUtilsTest {
contentProviderUtils.insertTrack(track);
// when / then
assertNotNull(contentProviderUtils.getTrack(track.getUuid()));
assertNotNull(contentProviderUtils.getTrack(track.uuid()));
}
/**
* Tests the method {@link ContentProviderUtils#updateTrack(Track)}
*/
@Test
public void testUpdateTrack() {
// given
Track.Id trackId = new Track.Id(System.currentTimeMillis());
Track track = TestDataUtil.createTrack(trackId);
TrackBuilder track = new TrackBuilder(TestDataUtil.createTrack(trackId));
String nameOld = "name1";
String nameNew = "name2";
track.setName(nameOld);
// when / then
contentProviderUtils.insertTrack(track);
assertEquals(nameOld, contentProviderUtils.getTrack(trackId).getName());
contentProviderUtils.insertTrack(track.getTrack());
assertEquals(nameOld, contentProviderUtils.getTrack(trackId).name());
track.setName(nameNew);
contentProviderUtils.updateTrack(track);
assertEquals(nameNew, contentProviderUtils.getTrack(trackId).getName());
contentProviderUtils.updateTrack(track.getTrack());
assertEquals(nameNew, contentProviderUtils.getTrack(trackId).name());
}
/**
* Tests the method {@link ContentProviderUtils#createContentValues(Marker)}.
*/
@Test
public void testCreateContentValues_marker() {
Track.Id trackId = new Track.Id(System.currentTimeMillis());
Pair<Track, List<TrackPoint>> track = TestDataUtil.createTrack(trackId, 10);
TrackBuilder trackBuilder = new TrackBuilder(track.first);
// AverageSpeed
TrackStatistics statistics = new TrackStatistics();
statistics.setStartTime(Instant.ofEpochMilli(1000));
statistics.setStopTime(Instant.ofEpochMilli(2500));
statistics.setTotalTime(Duration.ofMillis(1500));
statistics.setMovingTime(Duration.ofMillis(700));
statistics.setTotalDistance(Distance.of(750.0));
statistics.setTotalAltitudeGain(50.0f);
statistics.setMaxSpeed(Speed.of(60.0));
statistics.setMaxAltitude(1250.0);
statistics.setMinAltitude(1200.0);
trackBuilder.setStatistics(new Statistics(
Instant.ofEpochMilli(1000),
Instant.ofEpochMilli(2500),
Duration.ofMillis(1500),
Duration.ofMillis(700),
Distance.of(750),
Speed.of(60),
new AltitudeExtremities(1250, 1200),
new AltitudeGainLoss(50, 50),
null,
null
));
contentProviderUtils.insertTrack(trackBuilder.getTrack());
track.first.setTrackStatistics(statistics);
contentProviderUtils.insertTrack(track.first);
Marker marker = new Marker(trackId, track.second.get(0));
MarkerBuilder marker = new MarkerBuilder(trackId, track.second.get(0));
marker.setDescription(TEST_DESC);
contentProviderUtils.insertMarker(marker);
contentProviderUtils.insertMarker(marker.getMarker());
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(contentResolverMock);
Marker.Id markerId = new Marker.Id(System.currentTimeMillis());
marker.setId(markerId);
ContentValues contentValues = contentProviderUtils.createContentValues(marker);
ContentValues contentValues = contentProviderUtils.createContentValues(marker.getMarker(), trackId);
assertEquals(markerId.id(), contentValues.get(MarkerColumns._ID));
assertEquals((int) (TestDataUtil.INITIAL_LONGITUDE * 1000000), contentValues.get(MarkerColumns.LONGITUDE));
assertEquals(TEST_DESC, contentValues.get(MarkerColumns.DESCRIPTION));
@@ -445,15 +470,18 @@ public class CustomContentProviderUtilsTest {
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
// Insert at first.
Marker marker1 = new Marker(trackId, contentProviderUtils.getLastValidTrackPoint(trackId));
marker1.setDescription(TEST_DESC);
contentProviderUtils.insertMarker(marker1);
Marker.Id marker1Id = contentProviderUtils.insertMarker(new Marker(
null,
trackId,
"",
TEST_DESC,
"",
getLastValidTrackPoint(trackId).position(),
null
));
// Check insert was done.
assertEquals(1, contentProviderUtils.getMarkers(trackId).size());
// Get marker id that needs to delete.
Marker.Id marker1Id = contentProviderUtils.insertMarker(marker1);
assertEquals(1, TestDataUtil.getMarkers(contentProviderUtils, trackId).size());
// Delete
contentProviderUtils.deleteMarker(context, marker1Id);
@@ -472,18 +500,18 @@ public class CustomContentProviderUtilsTest {
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
// Insert at first.
TrackPoint trackPoint = contentProviderUtils.getLastValidTrackPoint(trackId);
TrackPoint trackPoint = getLastValidTrackPoint(trackId);
Marker marker1 = TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint);
contentProviderUtils.insertMarker(marker1);
// Check insert was done.
assertEquals(1, contentProviderUtils.getMarkers(trackId).size());
assertEquals(1, TestDataUtil.getMarkers(contentProviderUtils, trackId).size());
// Get marker id that needs to delete.
Marker.Id marker1Id = contentProviderUtils.insertMarker(marker1);
// Check marker has photo and it's in the external storage.
assertTrue(marker1.hasPhoto());
assertNotNull(marker1.photoUrl());
File dir = FileUtils.getPhotoDir(context, trackId);
assertTrue(dir.isDirectory());
assertEquals(1, dir.list().length);
@@ -522,20 +550,31 @@ public class CustomContentProviderUtilsTest {
// TestDataUtil.insertTrackWithLocations(contentProviderUtils, track);
// Insert at first.
Marker marker1 = new Marker(trackId, contentProviderUtils.getLastValidTrackPoint(trackId));
marker1.setDescription(MOCK_DESC);
Marker.Id marker1Id = contentProviderUtils.insertMarker(marker1);
Marker marker2 = new Marker(trackId, contentProviderUtils.getLastValidTrackPoint(trackId));
marker2.setDescription(MOCK_DESC);
Marker.Id marker2Id = contentProviderUtils.insertMarker(marker2);
Marker.Id marker1Id = contentProviderUtils.insertMarker(new Marker(
null,
trackId,
"",
MOCK_DESC,
"",
getLastValidTrackPoint(trackId).position(),
null
));
Marker.Id marker2Id = contentProviderUtils.insertMarker(new Marker(
null,
trackId,
"",
MOCK_DESC,
"",
getLastValidTrackPoint(trackId).position(),
null
));
// Delete
assertNotNull(contentProviderUtils.getMarker(marker1Id));
contentProviderUtils.deleteMarker(context, marker1Id);
assertNull(contentProviderUtils.getMarker(marker1Id));
assertEquals(MOCK_DESC, contentProviderUtils.getMarker(marker2Id).getDescription());
assertEquals(MOCK_DESC, contentProviderUtils.getMarker(marker2Id).description());
}
/**
@@ -546,14 +585,17 @@ public class CustomContentProviderUtilsTest {
Track.Id trackId = new Track.Id(System.currentTimeMillis());
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
Marker marker1 = new Marker(trackId, contentProviderUtils.getLastValidTrackPoint(trackId));
Marker marker2 = new Marker(trackId, contentProviderUtils.getLastValidTrackPoint(trackId));
Marker marker3 = new Marker(trackId, contentProviderUtils.getLastValidTrackPoint(trackId));
Marker marker4 = new Marker(trackId, contentProviderUtils.getLastValidTrackPoint(trackId));
contentProviderUtils.insertMarker(marker1);
contentProviderUtils.insertMarker(marker2);
contentProviderUtils.insertMarker(marker3);
contentProviderUtils.insertMarker(marker4);
for (int i = 0; i < 4; i++) {
contentProviderUtils.insertMarker(new Marker(
null,
trackId,
"",
MOCK_DESC,
"",
getLastValidTrackPoint(trackId).position(),
null
));
}
assertEquals(Integer.valueOf(4), contentProviderUtils.getNextMarkerNumber(trackId));
}
@@ -567,11 +609,18 @@ public class CustomContentProviderUtilsTest {
Track.Id trackId = new Track.Id(System.currentTimeMillis());
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
Marker marker = new Marker(trackId, contentProviderUtils.getLastValidTrackPoint(trackId));
marker.setDescription(TEST_DESC);
Marker.Id markerId = contentProviderUtils.insertMarker(marker);
Marker.Id markerId = contentProviderUtils.insertMarker(
new Marker(
null,
trackId,
"",
TEST_DESC,
"",
getLastValidTrackPoint(trackId).position(),
null
));
assertEquals(TEST_DESC, contentProviderUtils.getMarker(markerId).getDescription());
assertEquals(TEST_DESC, contentProviderUtils.getMarker(markerId).description());
}
/**
@@ -583,16 +632,29 @@ public class CustomContentProviderUtilsTest {
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
// Insert at first.
Marker marker = new Marker(trackId, contentProviderUtils.getLastValidTrackPoint(trackId));
marker.setDescription(TEST_DESC);
Marker.Id markerId = contentProviderUtils.insertMarker(marker);
Marker.Id markerId = contentProviderUtils.insertMarker(
new Marker(
null,
trackId,
"",
TEST_DESC,
"",
getLastValidTrackPoint(trackId).position(),
null
));
// Update
marker = contentProviderUtils.getMarker(markerId);
marker.setDescription(TEST_DESC_NEW);
contentProviderUtils.updateMarker(context, marker);
contentProviderUtils.updateMarker(context, new Marker(
markerId,
trackId,
"",
TEST_DESC_NEW,
"",
getLastValidTrackPoint(trackId).position(),
null
));
assertEquals(TEST_DESC_NEW, contentProviderUtils.getMarker(markerId).getDescription());
assertEquals(TEST_DESC_NEW, contentProviderUtils.getMarker(markerId).description());
}
/**
@@ -606,10 +668,8 @@ public class CustomContentProviderUtilsTest {
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
// Insert at first.
TrackPoint trackPoint = contentProviderUtils.getLastValidTrackPoint(trackId);
Marker marker = TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint);
marker.setDescription(TEST_DESC);
Marker.Id markerId = contentProviderUtils.insertMarker(marker);
TrackPoint trackPoint = getLastValidTrackPoint(trackId);
Marker.Id markerId = contentProviderUtils.insertMarker(TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint, TEST_DESC));
File dir = new File(FileUtils.getPhotoDir(context), "" + trackId.id());
assertTrue(dir.exists());
@@ -617,14 +677,13 @@ public class CustomContentProviderUtilsTest {
assertEquals(1, dir.list().length);
// Update
marker = contentProviderUtils.getMarker(markerId);
MarkerBuilder marker = new MarkerBuilder(contentProviderUtils.getMarker(markerId));
marker.setName(TEST_NAME_NEW);
marker.setDescription(TEST_DESC_NEW);
contentProviderUtils.updateMarker(context, marker);
contentProviderUtils.updateMarker(context, marker.getMarker());
assertEquals(TEST_NAME_NEW, contentProviderUtils.getMarker(markerId).getName());
assertEquals(TEST_DESC_NEW, contentProviderUtils.getMarker(markerId).getDescription());
assertTrue(marker.hasPhoto());
assertEquals(TEST_NAME_NEW, contentProviderUtils.getMarker(markerId).name());
assertEquals(TEST_DESC_NEW, contentProviderUtils.getMarker(markerId).description());
assertTrue(dir.exists());
assertTrue(dir.isDirectory());
assertEquals(1, dir.list().length);
@@ -641,9 +700,8 @@ public class CustomContentProviderUtilsTest {
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
// Insert at first.
TrackPoint trackPoint = contentProviderUtils.getLastValidTrackPoint(trackId);
Marker marker = TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint);
marker.setDescription(TEST_DESC);
TrackPoint trackPoint = getLastValidTrackPoint(trackId);
Marker marker = TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint, TEST_DESC);
Marker.Id markerId = contentProviderUtils.insertMarker(marker);
File dir = new File(FileUtils.getPhotoDir(context), "" + trackId.id());
@@ -652,15 +710,14 @@ public class CustomContentProviderUtilsTest {
assertEquals(1, dir.list().length);
// Update
marker = contentProviderUtils.getMarker(markerId);
marker.setName(TEST_NAME_NEW);
marker.setDescription(TEST_DESC_NEW);
marker.setPhotoUrl(null);
contentProviderUtils.updateMarker(context, marker);
MarkerBuilder markerBuilder = new MarkerBuilder(contentProviderUtils.getMarker(markerId));
markerBuilder.setName(TEST_NAME_NEW);
markerBuilder.setDescription(TEST_DESC_NEW);
markerBuilder.setPhotoUrl(null);
contentProviderUtils.updateMarker(context, markerBuilder.getMarker());
assertEquals(TEST_NAME_NEW, contentProviderUtils.getMarker(markerId).getName());
assertEquals(TEST_DESC_NEW, contentProviderUtils.getMarker(markerId).getDescription());
assertFalse(marker.hasPhoto());
assertEquals(TEST_NAME_NEW, contentProviderUtils.getMarker(markerId).name());
assertEquals(TEST_DESC_NEW, contentProviderUtils.getMarker(markerId).description());
assertFalse(dir.exists());
}
@@ -675,11 +732,9 @@ public class CustomContentProviderUtilsTest {
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
// Insert two markers with photos.
TrackPoint trackPoint = contentProviderUtils.getLastValidTrackPoint(trackId);
Marker marker = TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint);
marker.setDescription(TEST_DESC);
Marker otherMarker = TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint);
otherMarker.setDescription(TEST_DESC);
TrackPoint trackPoint = getLastValidTrackPoint(trackId);
Marker marker = TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint, TEST_DESC);
Marker otherMarker = TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint, TEST_DESC);
Marker.Id markerId = contentProviderUtils.insertMarker(marker);
contentProviderUtils.insertMarker(otherMarker);
@@ -689,12 +744,14 @@ public class CustomContentProviderUtilsTest {
assertEquals(2, dir.list().length);
// Update one marker deleting photo.
marker = contentProviderUtils.getMarker(markerId);
marker.setPhotoUrl(null);
contentProviderUtils.updateMarker(context, marker);
MarkerBuilder markerBuilder = new MarkerBuilder(contentProviderUtils.getMarker(markerId));
markerBuilder.setPhotoUrl(null);
contentProviderUtils.updateMarker(context, markerBuilder.getMarker());
assertEquals(TEST_DESC, contentProviderUtils.getMarker(markerId).getDescription());
assertFalse(marker.hasPhoto());
// then
marker = contentProviderUtils.getMarker(markerId);
assertEquals(TEST_DESC, contentProviderUtils.getMarker(markerId).description());
assertNull(marker.photoUrl());
assertTrue(dir.exists());
assertTrue(dir.isDirectory());
assertEquals(1, dir.list().length);
@@ -725,50 +782,6 @@ public class CustomContentProviderUtilsTest {
}
}
/**
* Tests the method {@link ContentProviderUtils#createTrackPoint(Cursor)}.
*/
//TODO incomplete
@Test
public void testCreateTrackPoint() {
// given
when(cursorMock.getColumnIndex(TrackPointsColumns._ID)).thenReturn(1);
when(cursorMock.getColumnIndexOrThrow(TrackPointsColumns.LONGITUDE)).thenReturn(2);
when(cursorMock.isNull(2)).thenReturn(false);
int longitude = 11;
when(cursorMock.getInt(2)).thenReturn(longitude * 1000000);
when(cursorMock.getColumnIndexOrThrow(TrackPointsColumns.LATITUDE)).thenReturn(3);
when(cursorMock.isNull(3)).thenReturn(false);
int latitude = 22;
when(cursorMock.getInt(3)).thenReturn(latitude * 1000000);
when(cursorMock.getColumnIndexOrThrow(TrackPointsColumns.TIME)).thenReturn(4);
when(cursorMock.isNull(4)).thenReturn(false);
long time = System.currentTimeMillis();
when(cursorMock.getLong(4)).thenReturn(time);
when(cursorMock.getColumnIndexOrThrow(TrackPointsColumns.SPEED)).thenReturn(5);
when(cursorMock.isNull(5)).thenReturn(false);
float speed = 2.2f;
when(cursorMock.getFloat(5)).thenReturn(speed);
when(cursorMock.getColumnIndexOrThrow(TrackPointsColumns.SENSOR_HEARTRATE)).thenReturn(6);
when(cursorMock.isNull(6)).thenReturn(false);
when(cursorMock.getFloat(6)).thenReturn(75f);
// when
TrackPoint trackPoint = contentProviderUtils.createTrackPoint(cursorMock);
// then
assertEquals(latitude, trackPoint.getPosition().latitude(), 0.01);
assertEquals(longitude, trackPoint.getPosition().longitude(), 0.01);
assertEquals(time, trackPoint.getTime().toEpochMilli());
assertEquals(speed, trackPoint.getSpeed().toMPS(), 0.01);
assertEquals(HeartRate.of(75f), trackPoint.getHeartRate());
}
/**
* Tests the method
* {@link ContentProviderUtils#insertTrackPoint(TrackPoint, Track.Id)}.
@@ -777,7 +790,7 @@ public class CustomContentProviderUtilsTest {
public void testInsertTrackPoint() {
// Insert track, point at first.
Track.Id trackId = new Track.Id(System.currentTimeMillis());
Track track = TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
contentProviderUtils.insertTrackPoint(TestDataUtil.createTrackPoint(22), trackId);
// when
@@ -791,35 +804,29 @@ public class CustomContentProviderUtilsTest {
public void testInsertAndLoadTrackPoint() {
// given
Track.Id trackId = new Track.Id(System.currentTimeMillis());
Track track = TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
TrackPoint trackPoint = TestDataUtil.createTrackPoint(5);
trackPoint.setHeartRate(1F);
trackPoint.setCadence(2F);
trackPoint.setPower(3F);
TrackPoint trackPoint = new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
TestDataUtil.createTrackPoint(5).position(),
null,
HeartRate.of(1),
null,
Cadence.of(2),
Power.of(3),
null
);
// when
contentProviderUtils.insertTrackPoint(trackPoint, trackId);
// then
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
assertTrue(trackPoints.get(10).hasHeartRate());
assertEquals(trackPoint.getHeartRate(), trackPoints.get(10).getHeartRate());
assertEquals(trackPoint.getCadence(), trackPoints.get(10).getCadence());
assertEquals(trackPoint.getPower(), trackPoints.get(10).getPower());
}
/**
* Tests the method {@link ContentProviderUtils#getLastValidTrackPoint(Track.Id)}.
*/
@Test
public void testGetLastValidTrackPoint() {
// Insert track, points at first.
Track.Id trackId = new Track.Id(System.currentTimeMillis());
Track track = TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
TrackPoint lastTrackPoint = contentProviderUtils.getLastValidTrackPoint(trackId);
checkLocation(9, lastTrackPoint.getLocation());
assertNotNull(trackPoints.get(10).heartRate());
assertEquals(trackPoint.heartRate(), trackPoints.get(10).heartRate());
assertEquals(trackPoint.cadence(), trackPoints.get(10).cadence());
assertEquals(trackPoint.power(), trackPoints.get(10).power());
}
@Test
@@ -830,7 +837,7 @@ public class CustomContentProviderUtilsTest {
contentProviderUtils.insertTrack(track.first);
List<TrackPoint.Id> trackpointIds = track.second.stream()
.map(it -> ContentUris.parseId(contentProviderUtils.insertTrackPoint(it, track.first.getId())))
.map(it -> ContentUris.parseId(contentProviderUtils.insertTrackPoint(it, track.first.id())))
.map(TrackPoint.Id::new).toList();
// when
@@ -841,45 +848,36 @@ public class CustomContentProviderUtilsTest {
}
@Test
public void testGetTrackPointLocationIterator_asc() {
public void testGetTrackPointIterator_asc() {
// given
Track.Id trackId = new Track.Id(System.currentTimeMillis());
Pair<Track, List<TrackPoint>> track = TestDataUtil.createTrack(trackId, 10);
contentProviderUtils.insertTrack(track.first);
List<TrackPoint.Id> trackpointIds = track.second.stream()
.map(it -> ContentUris.parseId(contentProviderUtils.insertTrackPoint(it, track.first.getId())))
.map(it -> ContentUris.parseId(contentProviderUtils.insertTrackPoint(it, track.first.id())))
.map(TrackPoint.Id::new).toList();
TrackPoint.Id startTrackPointId = trackpointIds.get(0);
// when
TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, trackpointIds.get(0));
TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointIterator(trackId, trackpointIds.get(0));
// then
for (int i = 0; i < trackpointIds.size(); i++) {
assertTrue(trackPointIterator.hasNext());
TrackPoint trackPoint = trackPointIterator.next();
assertEquals(startTrackPointId.id() + i, trackPoint.getId().id());
assertEquals(startTrackPointId.id() + i, trackPoint.id().id());
checkLocation(i, trackPoint.getLocation());
Position position = trackPoint.position();
assertEquals(TestDataUtil.INITIAL_LATITUDE + i / 10000.0, position.latitude(), 0.01);
assertEquals(TestDataUtil.INITIAL_LONGITUDE - i / 10000.0, position.longitude(), 0.01);
assertEquals(i / 100.0, position.horizontalAccuracy().distance_m(), 0.01);
assertEquals(i * TestDataUtil.ALTITUDE_INTERVAL, position.altitude().toM(), 0.01);
}
assertFalse(trackPointIterator.hasNext());
}
/**
* Checks the value of a location.
*
* @param i the index of this location which created in the method {@link TestDataUtil#createTrack(Track.Id, int)}
* @param location the location to be checked
*/
private void checkLocation(int i, Location location) {
assertEquals(TestDataUtil.INITIAL_LATITUDE + (double) i / 10000.0, location.getLatitude(), 0.01);
assertEquals(TestDataUtil.INITIAL_LONGITUDE - (double) i / 10000.0, location.getLongitude(), 0.01);
assertEquals((float) i / 100.0f, location.getAccuracy(), 0.01);
assertEquals(i * TestDataUtil.ALTITUDE_INTERVAL, location.getAltitude(), 0.01);
}
@Test
public void testFormatIdListForUri() {
assertEquals("", ContentProviderUtils.formatIdListForUri());
@@ -891,11 +889,18 @@ public class CustomContentProviderUtilsTest {
public void testGetSensorStats_noSensorData() {
// given
List<TrackPoint> trackPointList = new ArrayList<>();
TrackPoint trackPoint = TestDataUtil.createTrackPoint(1);
trackPoint.setType(TrackPoint.Type.TRACKPOINT);
trackPoint.setPower(null);
trackPoint.setCadence(null);
trackPoint.setHeartRate(null);
TrackPoint trackPoint = new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
TestDataUtil.createTrackPoint(1).position(),
null,
null,
null,
null,
null,
null
);
trackPointList.add(trackPoint);
Track.Id trackId = new Track.Id(System.currentTimeMillis());
Track track = TestDataUtil.createTrack(trackId);
@@ -1219,4 +1224,19 @@ public class CustomContentProviderUtilsTest {
public void testGetSensorStats_withSeveralRandomStartSegments() {
testGetSensorStats_randomData(5000, true);
}
private TrackPoint getLastValidTrackPoint(Track.Id trackId) {
try (TrackPointIterator trackPointsCursor = contentProviderUtils.getTrackPointIterator(trackId, null)) {
List<TrackPoint> trackpoints = new ArrayList<>();
while (trackPointsCursor.hasNext())
trackpoints.add(trackPointsCursor.next());
trackpoints = trackpoints.reversed();
return trackpoints.reversed()
.stream()
.filter(it -> List.of(TrackPoint.Type.TRACKPOINT, TrackPoint.Type.SEGMENT_START_AUTOMATIC).contains(it.type()))
.findFirst().orElseThrow();
}
}
}
@@ -100,18 +100,18 @@ public class CustomSQLiteOpenHelperTest {
// Open database with SQL upgrade
Map<String, String> tableByUpgrade;
Map<String, String> indicesByUpgrade;
try (SQLiteDatabase dbUpgraded = new CustomSQLiteOpenHelper(context, DATABASE_NAME).getReadableDatabase()) {
tableByUpgrade = getSQL(dbUpgraded, "table");
indicesByUpgrade = getSQL(dbUpgraded, "index");
try (CustomSQLiteOpenHelper dbUpgraded = new CustomSQLiteOpenHelper(context, DATABASE_NAME)) {
tableByUpgrade = getSQL(dbUpgraded.getReadableDatabase(), "table");
indicesByUpgrade = getSQL(dbUpgraded.getReadableDatabase(), "index");
}
context.deleteDatabase(DATABASE_NAME);
// Open database via creation script
Map<String, String> tablesByCreate;
Map<String, String> indicesByCreate;
try (SQLiteDatabase dbCreated = new CustomSQLiteOpenHelper(context, DATABASE_NAME).getReadableDatabase()) {
tablesByCreate = getSQL(dbCreated, "table");
indicesByCreate = getSQL(dbCreated, "index");
try (CustomSQLiteOpenHelper dbCreated = new CustomSQLiteOpenHelper(context, DATABASE_NAME)) {
tablesByCreate = getSQL(dbCreated.getReadableDatabase(), "table");
indicesByCreate = getSQL(dbCreated.getReadableDatabase(), "index");
}
@@ -134,14 +134,16 @@ public class CustomSQLiteOpenHelperTest {
@Test
public void onDowngrade_ToVersion23() {
// Create most recent database schema
new CustomSQLiteOpenHelper(context, DATABASE_NAME).getReadableDatabase().close();
try(CustomSQLiteOpenHelper db = new CustomSQLiteOpenHelper(context, DATABASE_NAME)) {
db.getReadableDatabase();
}
// Downgrade schema to version 23 (base version)
Map<String, String> tablesByDowngrade;
Map<String, String> indicesByDowngrade;
try (SQLiteDatabase db = new CustomSQLiteOpenHelper(context, DATABASE_NAME, 23).getReadableDatabase()) {
tablesByDowngrade = getSQL(db, "table");
indicesByDowngrade = getSQL(db, "index");
try (CustomSQLiteOpenHelper db = new CustomSQLiteOpenHelper(context, DATABASE_NAME, 23)) {
tablesByDowngrade = getSQL(db.getReadableDatabase(), "table");
indicesByDowngrade = getSQL(db.getReadableDatabase(), "index");
}
// then - verify table structure
@@ -155,9 +157,9 @@ public class CustomSQLiteOpenHelperTest {
@Test
public void track_uuid_unique() {
try (SQLiteDatabase db = new CustomSQLiteOpenHelper(context, DATABASE_NAME).getWritableDatabase()) {
db.execSQL("INSERT INTO tracks (uuid) VALUES (0x00)");
db.execSQL("INSERT INTO tracks (uuid) VALUES (0x00)");
try (CustomSQLiteOpenHelper db = new CustomSQLiteOpenHelper(context, DATABASE_NAME)) {
db.getWritableDatabase().execSQL("INSERT INTO tracks (uuid) VALUES (0x00)");
db.getWritableDatabase().execSQL("INSERT INTO tracks (uuid) VALUES (0x00)");
fail("unique constraint not enforced");
} catch (SQLiteConstraintException e) {
assertTrue(e.getMessage().contains("UNIQUE constraint failed: tracks.uuid"));
@@ -168,7 +170,8 @@ public class CustomSQLiteOpenHelperTest {
public void upgrade_data_to_30() {
// given: a track in version 29
createVersion23();
try (SQLiteDatabase db29 = new CustomSQLiteOpenHelper(context, DATABASE_NAME, 29).getWritableDatabase()) {
try (CustomSQLiteOpenHelper db = new CustomSQLiteOpenHelper(context, DATABASE_NAME, 29)) {
SQLiteDatabase db29 = db.getWritableDatabase();
db29.beginTransaction();
db29.execSQL("INSERT INTO tracks (_id) VALUES (1)");
@@ -201,7 +204,8 @@ public class CustomSQLiteOpenHelperTest {
}
// when / then
try (SQLiteDatabase db30 = new CustomSQLiteOpenHelper(context, DATABASE_NAME, 30).getWritableDatabase()) {
try (CustomSQLiteOpenHelper db = new CustomSQLiteOpenHelper(context, DATABASE_NAME, 30)) {
SQLiteDatabase db30 = db.getWritableDatabase();
{
// Track 1
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
@@ -261,7 +265,7 @@ public class CustomSQLiteOpenHelperTest {
private void createVersion23() {
// Manually create database schema with version 23 (base version)
SQLiteDatabase dbBase = new SQLiteOpenHelper(context, DATABASE_NAME, null, 23) {
try(SQLiteOpenHelper dbBase = new SQLiteOpenHelper(context, DATABASE_NAME, null, 23) {
@Override
public void onCreate(SQLiteDatabase db) {
}
@@ -269,12 +273,10 @@ public class CustomSQLiteOpenHelperTest {
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}.getWritableDatabase();
dbBase.execSQL(TRACKS_CREATE_TABLE_V23);
dbBase.execSQL(TRACKPOINTS_CREATE_TABLE_V23);
dbBase.execSQL(WAYPOINTS_CREATE_TABLE_V23);
dbBase.close();
}) {
dbBase.getWritableDatabase().execSQL(TRACKS_CREATE_TABLE_V23);
dbBase.getWritableDatabase().execSQL(TRACKPOINTS_CREATE_TABLE_V23);
dbBase.getWritableDatabase().execSQL(WAYPOINTS_CREATE_TABLE_V23);
}
}
}
@@ -9,6 +9,7 @@ import org.junit.runner.RunWith;
import java.time.Duration;
import java.time.Instant;
import java.util.List;
import de.dennisguse.opentracks.data.models.Track;
@@ -20,7 +21,7 @@ public class TrackSelectionTest extends TestCase {
TrackSelection filter = new TrackSelection();
// when
SelectionData selection = filter.buildSelection();
ContentProviderUtils.SelectionData selection = filter.buildSelection();
// Then
assertNull(selection.selection());
@@ -34,12 +35,11 @@ public class TrackSelectionTest extends TestCase {
TrackSelection filter = new TrackSelection().addTrackId(trackId);
// when
SelectionData selection = filter.buildSelection();
ContentProviderUtils.SelectionData selection = filter.buildSelection();
// Then
assertEquals("_id IN (?)", selection.selection());
assertEquals(1, selection.selectionArgs().length);
assertEquals("1", selection.selectionArgs()[0]);
assertEquals(List.of("1"), selection.selectionArgs());
}
@Test
@@ -54,28 +54,24 @@ public class TrackSelectionTest extends TestCase {
.addTrackId(trackId3);
// when
SelectionData selection = filter.buildSelection();
ContentProviderUtils.SelectionData selection = filter.buildSelection();
// Then
assertEquals("_id IN (?,?,?)", selection.selection());
assertEquals(3, selection.selectionArgs().length);
assertEquals("1", selection.selectionArgs()[0]);
assertEquals("2", selection.selectionArgs()[1]);
assertEquals("3", selection.selectionArgs()[2]);
assertEquals(List.of("1", "2", "3"), selection.selectionArgs());
}
@Test
public void testFilterBuildSelection_onlyOneCategory() {
public void testFilterBuildSelection_onlyOneactivity_type_localized() {
// given
TrackSelection filter = new TrackSelection().addActivityType("running");
// when
SelectionData selection = filter.buildSelection();
ContentProviderUtils.SelectionData selection = filter.buildSelection();
// Then
assertEquals("category IN (?)", selection.selection());
assertEquals(1, selection.selectionArgs().length);
assertEquals("running", selection.selectionArgs()[0]);
assertEquals("activity_type_localized IN (?)", selection.selection());
assertEquals(List.of("running"), selection.selectionArgs());
}
@Test
@@ -88,15 +84,11 @@ public class TrackSelectionTest extends TestCase {
.addActivityType("trail walking");
// when
SelectionData selection = filter.buildSelection();
ContentProviderUtils.SelectionData selection = filter.buildSelection();
// Then
assertEquals("category IN (?,?,?,?)", selection.selection());
assertEquals(4, selection.selectionArgs().length);
assertEquals("running", selection.selectionArgs()[0]);
assertEquals("road biking", selection.selectionArgs()[1]);
assertEquals("mountain biking", selection.selectionArgs()[2]);
assertEquals("trail walking", selection.selectionArgs()[3]);
assertEquals("activity_type_localized IN (?,?,?,?)", selection.selection());
assertEquals(List.of("running", "road biking", "mountain biking", "trail walking"), selection.selectionArgs());
}
@Test
@@ -109,9 +101,9 @@ public class TrackSelectionTest extends TestCase {
TrackSelection filterOk = new TrackSelection().addDateRange(instant, instant.plus(Duration.ofDays(1)));
// when
SelectionData selectionWrong1 = filterWrong1.buildSelection();
SelectionData selectionWrong2 = filterWrong2.buildSelection();
SelectionData selectionOk = filterOk.buildSelection();
ContentProviderUtils.SelectionData selectionWrong1 = filterWrong1.buildSelection();
ContentProviderUtils.SelectionData selectionWrong2 = filterWrong2.buildSelection();
ContentProviderUtils.SelectionData selectionOk = filterOk.buildSelection();
// Then
assertNull(selectionWrong1.selection());
@@ -120,10 +112,8 @@ public class TrackSelectionTest extends TestCase {
assertNull(selectionWrong2.selection());
assertNull(selectionWrong2.selectionArgs());
assertEquals("starttime BETWEEN ? AND ?", selectionOk.selection());
assertEquals(2, selectionOk.selectionArgs().length);
assertEquals(selectionOk.selectionArgs()[0], Long.toString(instant.toEpochMilli()));
assertEquals(selectionOk.selectionArgs()[1], Long.toString(instant.toEpochMilli() + oneDay));
assertEquals("time_start BETWEEN ? AND ?", selectionOk.selection());
assertEquals(List.of(Long.toString(instant.toEpochMilli()), Long.toString(instant.toEpochMilli() + oneDay)) , selectionOk.selectionArgs());
}
@Test
@@ -140,16 +130,11 @@ public class TrackSelectionTest extends TestCase {
.addActivityType("road biking");
// when
SelectionData selection = filter.buildSelection();
ContentProviderUtils.SelectionData selection = filter.buildSelection();
// Then
assertEquals("_id IN (?,?,?) AND category IN (?,?)", selection.selection());
assertEquals(5, selection.selectionArgs().length);
assertEquals("1", selection.selectionArgs()[0]);
assertEquals("2", selection.selectionArgs()[1]);
assertEquals("3", selection.selectionArgs()[2]);
assertEquals("running", selection.selectionArgs()[3]);
assertEquals("road biking", selection.selectionArgs()[4]);
assertEquals("_id IN (?,?,?) AND activity_type_localized IN (?,?)", selection.selection());
assertEquals(List.of("1", "2", "3", "running", "road biking"), selection.selectionArgs());
}
@Test
@@ -169,16 +154,11 @@ public class TrackSelectionTest extends TestCase {
.addDateRange(instant, instant.plusMillis(oneDay));
// when
SelectionData selection = filter.buildSelection();
ContentProviderUtils.SelectionData selection = filter.buildSelection();
// Then
assertEquals("_id IN (?,?,?) AND starttime BETWEEN ? AND ?", selection.selection());
assertEquals(5, selection.selectionArgs().length);
assertEquals("1", selection.selectionArgs()[0]);
assertEquals("2", selection.selectionArgs()[1]);
assertEquals("3", selection.selectionArgs()[2]);
assertEquals(selection.selectionArgs()[3], Long.toString(instant.toEpochMilli()));
assertEquals(selection.selectionArgs()[4], Long.toString(instant.toEpochMilli() + oneDay));
assertEquals("_id IN (?,?,?) AND time_start BETWEEN ? AND ?", selection.selection());
assertEquals(List.of("1", "2", "3", Long.toString(instant.toEpochMilli()), Long.toString(instant.toEpochMilli() + oneDay)), selection.selectionArgs());
}
@Test
@@ -193,14 +173,10 @@ public class TrackSelectionTest extends TestCase {
.addDateRange(instant, instant.plusMillis(oneDay));
// when
SelectionData selection = filter.buildSelection();
ContentProviderUtils.SelectionData selection = filter.buildSelection();
// Then
assertEquals("category IN (?,?) AND starttime BETWEEN ? AND ?", selection.selection());
assertEquals(4, selection.selectionArgs().length);
assertEquals("running", selection.selectionArgs()[0]);
assertEquals("road biking", selection.selectionArgs()[1]);
assertEquals(selection.selectionArgs()[2], Long.toString(instant.toEpochMilli()));
assertEquals(selection.selectionArgs()[3], Long.toString(instant.toEpochMilli() + oneDay));
assertEquals("activity_type_localized IN (?,?) AND time_start BETWEEN ? AND ?", selection.selection());
assertEquals(List.of("running", "road biking", Long.toString(instant.toEpochMilli()), Long.toString(instant.toEpochMilli() + oneDay)), selection.selectionArgs());
}
}
@@ -13,7 +13,7 @@ import de.dennisguse.opentracks.data.models.TrackPoint;
public class TrackPointTest {
@Test
public void distanceToPrevious() {
public void distanceToPrevious_gps() {
TrackPoint tp1 = new TrackPoint(TrackPoint.Type.TRACKPOINT,
new Position(
Instant.ofEpochMilli(0),
@@ -38,20 +38,123 @@ public class TrackPointTest {
// without sensor distance
assertEquals(11.13, tp2.distanceToPrevious(tp1).toM(), 0.01);
}
@Test
public void distanceToPrevious_sensor_distance_first() {
TrackPoint tp1 = new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.ofEpochMilli(0),
0d,
0.0001,
null,
null,
null,
null,
null),
Distance.of(5),
null,
null,
null,
null,
null
);
TrackPoint tp2 = new TrackPoint(TrackPoint.Type.TRACKPOINT,
new Position(
Instant.ofEpochMilli(1),
0d,
0.0002,
null,
null,
null,
null,
null));
// tp1 has sensor distance
tp1.setSensorDistance(Distance.of(5));
tp1.setSensorDistance(null);
assertEquals(11.13, tp2.distanceToPrevious(tp1).toM(), 0.01);
}
@Test
public void distanceToPrevious_sensor_distance_second() {
TrackPoint tp1 = new TrackPoint(TrackPoint.Type.TRACKPOINT,
new Position(
Instant.ofEpochMilli(0),
0d,
0.0001,
null,
null,
null,
null,
null));
TrackPoint tp2 = new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.ofEpochMilli(1),
0d,
0.0002,
null,
null,
null,
null,
null),
Distance.of(5),
null,
null,
null,
null,
null);
// tp2 has sensor distance
tp1.setSensorDistance(null);
tp2.setSensorDistance(Distance.of(5));
assertEquals(5, tp2.distanceToPrevious(tp1).toM(), 0.01);
}
@Test
public void distanceToPrevious_sensor_distance_both() {
TrackPoint tp1 = new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.ofEpochMilli(0),
0d,
0.0001,
null,
null,
null,
null,
null),
Distance.of(10),
null,
null,
null,
null,
null
);
TrackPoint tp2 = new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.ofEpochMilli(1),
0d,
0.0002,
null,
null,
null,
null,
null),
Distance.of(5),
null,
null,
null,
null,
null);
// tp1 and tp2 have sensor distance
tp1.setSensorDistance(Distance.of(10));
tp2.setSensorDistance(Distance.of(5));
assertEquals(5, tp2.distanceToPrevious(tp1).toM(), 0.01);
}
}
@@ -28,7 +28,7 @@ public class SpeedFormatterTest {
assertEquals("4:59", formatter.getSpeedParts(Speed.of(3.34)).first);
assertEquals("5:00", formatter.getSpeedParts(Speed.of(3.33)).first);
assertEquals("min/km", formatter.getSpeedParts(Speed.zero()).second);
assertEquals("min/km", formatter.getSpeedParts(Speed.ZERO).second);
}
@Test
@@ -39,7 +39,7 @@ public class SpeedFormatterTest {
.build(context);
assertEquals("8:02", formatter.getSpeedParts(Speed.of(3.34)).first);
assertEquals("min/mi", formatter.getSpeedParts(Speed.zero()).second);
assertEquals("min/mi", formatter.getSpeedParts(Speed.ZERO).second);
}
@Test
@@ -50,7 +50,7 @@ public class SpeedFormatterTest {
.build(context);
assertEquals("9:14", formatter.getSpeedParts(Speed.of(3.34)).first);
assertEquals("min/NM", formatter.getSpeedParts(Speed.zero()).second);
assertEquals("min/NM", formatter.getSpeedParts(Speed.ZERO).second);
}
@Test
@@ -61,7 +61,7 @@ public class SpeedFormatterTest {
.build(context);
assertEquals("11.9", formatter.getSpeedParts(Speed.of(3.31)).first);
assertEquals("km/h", formatter.getSpeedParts(Speed.zero()).second);
assertEquals("km/h", formatter.getSpeedParts(Speed.ZERO).second);
}
@Test
@@ -72,7 +72,7 @@ public class SpeedFormatterTest {
.build(context);
assertEquals("7.5", formatter.getSpeedParts(Speed.of(3.34)).first);
assertEquals("mph", formatter.getSpeedParts(Speed.zero()).second);
assertEquals("mph", formatter.getSpeedParts(Speed.ZERO).second);
}
@Test
@@ -83,7 +83,7 @@ public class SpeedFormatterTest {
.build(context);
assertEquals("6.5", formatter.getSpeedParts(Speed.of(3.34)).first);
assertEquals("kn", formatter.getSpeedParts(Speed.zero()).second);
assertEquals("kn", formatter.getSpeedParts(Speed.ZERO).second);
}
@Test
@@ -0,0 +1,65 @@
package de.dennisguse.opentracks.data.models;
import static org.junit.Assert.assertEquals;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.time.Duration;
import java.time.Instant;
@RunWith(AndroidJUnit4.class)
public class StatisticsTest {
@Test
public void testMerge() {
// given
Statistics subject = new Statistics(
Instant.ofEpochMilli(1000),
Instant.ofEpochMilli(2500),
Duration.ofMillis(1500),
Duration.ofMillis(700),
Distance.of(750.0),
Speed.of(60.0),
new AltitudeExtremities(1200, 1250),
new AltitudeGainLoss(50, 0),
HeartRate.of(100),
null
);
Statistics append = new Statistics(
Instant.ofEpochMilli(3000),
Instant.ofEpochMilli(4000),
Duration.ofMillis(1000),
Duration.ofMillis(600),
Distance.of(350.0),
Speed.of(30.0),
new AltitudeExtremities(2800.0, 3575.0),
new AltitudeGainLoss(850, 0),
HeartRate.of(200),
null
);
// when
Statistics result = subject.merge(append);
// then
assertEquals(
new Statistics(
Instant.ofEpochMilli(1000),
Instant.ofEpochMilli(4000),
Duration.ofMillis(2500),
Duration.ofMillis(1300),
Distance.of(1100),
Speed.of(60),
new AltitudeExtremities(1200, 3575),
new AltitudeGainLoss(900, 0),
HeartRate.of(150),
null
)
, result
);
}
}
@@ -4,11 +4,13 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import de.dennisguse.opentracks.data.models.ActivityType;
import de.dennisguse.opentracks.data.models.Statistics;
import de.dennisguse.opentracks.data.models.Track;
//TODO Merge with TrackFilenameGeneratorTest whenever Junit5 gets available.
@@ -33,12 +35,18 @@ public class TrackFilenameGenerator2Test {
@Test(expected = TrackFilenameGenerator.TemplateInvalidException.class)
public void testFilenameTemplate() {
// given
Track track = new Track();
track.setName("Best Track");
track.setUuid(UUID.fromString("f81d4fae-7dec-11d0-a765-00a0c91e6bf6"));
track.getTrackStatistics().setStartTime(Instant.parse("2020-02-02T02:02:02Z"));
Track track = new Track(
null,
UUID.fromString("f81d4fae-7dec-11d0-a765-00a0c91e6bf6"),
"Berlin",
"",
"",
ActivityType.CYCLING,
ZoneOffset.UTC,
Statistics.DEFAULT
);
// when
String filename = subject.format(track, TrackFileFormat.GPX);
subject.format(track, TrackFileFormat.GPX);
}
}
@@ -10,6 +10,7 @@ import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.Arrays;
import java.util.Collection;
import java.util.TimeZone;
@@ -17,6 +18,7 @@ import java.util.UUID;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.TimezoneRule;
import de.dennisguse.opentracks.data.models.Statistics;
import de.dennisguse.opentracks.data.models.Track;
@RunWith(Parameterized.class)
@@ -47,10 +49,16 @@ public class TrackFilenameGeneratorTest {
@Test
public void testFilenameTemplate() {
// given
Track track = new Track();
track.setName("Best Track");
track.setUuid(UUID.fromString("0000fee0-0000-1000-8000-00805f9b34fb"));
track.getTrackStatistics().setStartTime(Instant.parse("2020-02-02T02:02:02Z"));
Track track = new Track(
null,
UUID.fromString("0000fee0-0000-1000-8000-00805f9b34fb"),
"Best Track",
"",
"",
null,
ZoneOffset.UTC,
new Statistics(Instant.parse("2020-02-02T02:02:02Z"), Instant.parse("2020-02-02T02:02:02Z"), null, null, null, null, null, null, null, null)
);
// when
String filename = subject.format(track, TrackFileFormat.GPX);
@@ -1,7 +1,6 @@
package de.dennisguse.opentracks.io.file.importer;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -27,7 +26,6 @@ import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import java.io.BufferedReader;
import java.io.File;
@@ -52,6 +50,7 @@ import de.dennisguse.opentracks.content.data.TestDataUtil;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.ActivityType;
import de.dennisguse.opentracks.data.models.Altitude;
import de.dennisguse.opentracks.data.models.AltitudeExtremities;
import de.dennisguse.opentracks.data.models.AltitudeGainLoss;
import de.dennisguse.opentracks.data.models.Cadence;
import de.dennisguse.opentracks.data.models.Distance;
@@ -60,22 +59,25 @@ import de.dennisguse.opentracks.data.models.Marker;
import de.dennisguse.opentracks.data.models.Position;
import de.dennisguse.opentracks.data.models.Power;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Statistics;
import de.dennisguse.opentracks.data.models.Temperature;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackBuilder;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.io.file.TrackFileFormat;
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
import de.dennisguse.opentracks.sensors.BluetoothHandlerManagerCyclingPower;
import de.dennisguse.opentracks.sensors.BluetoothHandlerCyclingPower;
import de.dennisguse.opentracks.sensors.sensorData.Aggregator;
import de.dennisguse.opentracks.sensors.sensorData.AggregatorBarometer;
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.AggregatorTemperature;
import de.dennisguse.opentracks.sensors.sensorData.Raw;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataAggregator;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
import de.dennisguse.opentracks.stats.TrackStatistics;
/**
* Export a track to {@link TrackFileFormat} and verify that the import is identical.
@@ -122,11 +124,13 @@ public class ExportImportTest {
private TrackImporter trackImporter;
@Before
public void fileSetup() throws IOException {
public void fileSetup() throws IOException, TimeoutException {
tmpFile = File.createTempFile("test", "test", context.getFilesDir());
tmpFileUri = Uri.fromFile(tmpFile);
trackImporter = new TrackImporter(context, contentProviderUtils, Distance.of(200), true);
setUp();
}
@After
@@ -150,24 +154,50 @@ public class ExportImportTest {
Distance sensorDistance = Distance.of(10); // recording distance interval
sendLocation(trackPointCreator, "2020-02-02T02:02:03Z", 3.1234567, 14.0014567, 10, 13, 15, 1020.25, 1f);
contentProviderUtils.insertMarker(new Marker(trackId, service.getLastStoredTrackPointWithLocation(), "Marker 1", "Marker 1 desc", "Marker 1 category", null, null));
contentProviderUtils.insertMarker(
new Marker(
null,
trackId,
"Marker 1",
"Marker 1 desc",
"Marker 1 typeLocalized",
new Position(
Instant.parse("2020-02-02T02:02:03Z"),
3.1234567, 14.0014567,
Distance.of(10),
Altitude.WGS84.of(1020.25),
Distance.of(13),
null,
Speed.of(15)
),
null
));
// A sensor-only TrackPoint
trackPointCreator.setClock("2020-02-02T02:02:04Z");
mockSensorData(trackPointCreator, 15f, sensorDistance, 66f, 3f, 50f, 1f);
mockSensorData(trackPointCreator, 15f, sensorDistance, 66f, 3f, 50f, 1f, 27);
trackPointCreator.setClock("2020-02-02T02:02:14Z");
mockSensorData(trackPointCreator, 15f, null, 67f, 3f, 50f, null);
trackPointCreator.setClock("2020-02-02T02:02:14Z"); //ignored
mockSensorData(trackPointCreator, 15f, null, 67f, 3f, 50f, null, 28);
trackPointCreator.setClock("2020-02-02T02:02:15Z");
mockSensorData(trackPointCreator, null, null, 68f, 3f, 50f, null);
mockSensorData(trackPointCreator, null, null, 68f, 3f, 50f, null, 29);
trackPointCreator.setClock("2020-02-02T02:02:16Z");
mockSensorData(trackPointCreator, 5f, Distance.of(2), 69f, 3f, 50f, null); // Distance will be added to next TrackPoint
mockSensorData(trackPointCreator, 5f, Distance.of(2), 69f, 3f, 50f, null, 30); //Distance will be added to next TrackPoint
sendLocation(trackPointCreator, "2020-02-02T02:02:17Z", 3.1234567, 14.0014567, 10, 13, 15, 1020.25, 0f);
contentProviderUtils.insertMarker(new Marker(trackId, service.getLastStoredTrackPointWithLocation(), "Marker 2", "Marker 2 desc", "Marker 2 category", null, null));
contentProviderUtils.insertMarker(
new Marker(
null,
trackId,
"Marker 2",
"Marker 2 desc",
"Marker 2 typeLocalized",
service.getLastStoredTrackPointWithLocation().position(),
null
));
trackPointCreator.setClock("2020-02-02T02:02:18Z");
trackPointCreator.getSensorManager().sensorDataSet = new SensorDataSet(trackPointCreator);
trackPointCreator.getSensorManager().sensorDataAggregator = new SensorDataAggregator();
service.endCurrentTrack();
trackPointCreator.setClock("2020-02-02T02:03:20Z");
@@ -182,129 +212,170 @@ public class ExportImportTest {
sendLocation(trackPointCreator, "2020-02-02T02:03:50Z", 3.1234567, 16.001, 10, 27, 15, 999.123, 0f);
trackPointCreator.getSensorManager().sensorDataSet = new SensorDataSet(trackPointCreator);
trackPointCreator.getSensorManager().sensorDataAggregator = new SensorDataAggregator();
trackPointCreator.setClock("2020-02-02T02:04:00Z");
service.endCurrentTrack();
Track track = contentProviderUtils.getTrack(trackId);
track.setActivityType(TRACK_ACTIVITY_TYPE);
track.setActivityTypeLocalized(TRACK_ACTIVITY_TYPE_LOCALIZED);
track.setDescription(TRACK_DESCRIPTION);
contentProviderUtils.updateTrack(track);
TrackBuilder trackBuilder = new TrackBuilder(contentProviderUtils.getTrack(trackId));
trackBuilder.setActivityType(TRACK_ACTIVITY_TYPE);
trackBuilder.setActivityTypeLocalized(TRACK_ACTIVITY_TYPE_LOCALIZED);
trackBuilder.setDescription(TRACK_DESCRIPTION);
contentProviderUtils.updateTrack(trackBuilder.getTrack());
track = contentProviderUtils.getTrack(trackId);
trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
markers = contentProviderUtils.getMarkers(trackId);
markers = TestDataUtil.getMarkers(contentProviderUtils, trackId);
}
@LargeTest
@Test
public void track() throws TimeoutException {
setUp();
Track track = contentProviderUtils.getTrack(trackId);
TrackStatistics trackStatistics = track.getTrackStatistics();
Statistics trackStatistics = track.statistics();
assertEquals(ZoneOffset.of("+01:00"), track.getZoneOffset());
assertEquals(Instant.parse("2020-02-02T02:02:02Z"), trackStatistics.getStartTime());
assertEquals(Instant.parse("2020-02-02T02:04:00Z"), trackStatistics.getStopTime());
assertEquals(Duration.ofSeconds(56), trackStatistics.getTotalTime());
assertEquals(Duration.ofSeconds(26), trackStatistics.getMovingTime()); //TODO Likely too low
// Distance
assertEquals(222049.34375, trackStatistics.getTotalDistance().toM(), 0.01); //TODO Too low
// Speed
assertEquals(8540.359, trackStatistics.getMaxSpeed().toMPS(), 0.01);
assertEquals(3965.166, trackStatistics.getAverageSpeed().toMPS(), 0.01);
assertEquals(8540.359, trackStatistics.getAverageMovingSpeed().toMPS(), 0.01);
// Altitude
assertEquals(999.122, trackStatistics.getMinAltitude(), 0.01);
assertEquals(1020.25, trackStatistics.getMaxAltitude(), 0.01);
assertEquals(2, trackStatistics.getTotalAltitudeGain(), 0.01);
assertEquals(2, trackStatistics.getTotalAltitudeLoss(), 0.01);
assertEquals(ZoneOffset.of("+01:00"), track.zoneOffset());
List<TrackPoint> actual = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
new TrackPointAssert().assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse("2020-02-02T02:02:02Z")),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse("2020-02-02T02:02:03Z"),
3.123456, 14.001456, Distance.of(10),
Altitude.WGS84.of(1020.25), null,
null,
Speed.of(15)))
.setAltitudeLoss(1f)
.setAltitudeGain(1f),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
Instant.parse("2020-02-02T02:02:04Z"))
.setSensorDistance(Distance.of(10))
.setSpeed(Speed.of(15))
.setHeartRate(HeartRate.of(66))
.setCadence(3)
.setPower(50)
.setAltitudeLoss(1f)
.setAltitudeGain(1f),
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse("2020-02-02T02:02:15Z"))
.setHeartRate(HeartRate.of(68))
.setCadence(3)
.setPower(50),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
Speed.of(15)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(1, 1)
),
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse("2020-02-02T02:02:04Z"),
null, null, null,
null, null,
null,
Speed.of(15)),
Distance.of(10),
HeartRate.of(66),
Temperature.of(27),
Cadence.of(3),
Power.of(50),
new AltitudeGainLoss(1, 1)
),
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
Position.of(Instant.parse("2020-02-02T02:02:15Z")),
null,
HeartRate.of(68),
Temperature.of(29),
Cadence.of(3),
Power.of(50),
null
),
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse("2020-02-02T02:02:17Z"),
3.123456, 14.001456, Distance.of(10),
Altitude.WGS84.of(1020.25), null,
null,
Speed.of(5)))
.setSensorDistance(Distance.of(2))
.setAltitudeLoss(0f)
.setAltitudeGain(0f)
.setHeartRate(HeartRate.of(69))
.setCadence(3)
.setPower(50),
Speed.of(5)),
Distance.of(2),
HeartRate.of(69),
Temperature.of(30),
Cadence.of(3),
Power.of(50),
new AltitudeGainLoss(0, 0)
),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse("2020-02-02T02:02:18Z")),
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse("2020-02-02T02:03:20Z")),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse("2020-02-02T02:03:21Z"),
3.123456, 14.002456, Distance.of(10),
Altitude.WGS84.of(999.1229858398438), null,
null,
Speed.of(15)))
.setAltitudeLoss(0f)
.setAltitudeGain(0f),
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC,
Speed.of(15)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0)
),
new TrackPoint(
null,
TrackPoint.Type.SEGMENT_START_AUTOMATIC,
new Position(Instant.parse("2020-02-02T02:03:22Z"),
3.123456, 16d, Distance.of(10),
Altitude.WGS84.of(999.1229858398438), null,
null,
Speed.of(15)))
.setAltitudeLoss(0f)
.setAltitudeGain(0f),
new TrackPoint(TrackPoint.Type.IDLE, Instant.parse("2020-02-02T02:03:30Z"))
.setAltitudeLoss(0f)
.setAltitudeGain(0f),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
Speed.of(15)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0)
),
new TrackPoint(
null,
TrackPoint.Type.IDLE,
Position.of(Instant.parse("2020-02-02T02:03:30Z")),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0)
),
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse("2020-02-02T02:03:50Z"),
3.123456, 16.001, Distance.of(10),
Altitude.WGS84.of(999.1229858398438), null,
null, Speed.of(15)))
.setAltitudeLoss(0f)
.setAltitudeGain(0f),
null, Speed.of(15)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0)),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse("2020-02-02T02:04:00Z"))
), actual);
assertEquals(new Statistics(
Instant.parse("2020-02-02T02:02:02Z"),
Instant.parse("2020-02-02T02:04:00Z"),
Duration.ofSeconds(56),
Duration.ofSeconds(26), //TODO Likely too low
Distance.of(222049.34375), //TODO Too low
Speed.of(22203.734375),
new AltitudeExtremities(999.1229858398438, 1020.25),
new AltitudeGainLoss(2, 2),
null,
null
),
trackStatistics);
}
//TODO Does not test marker images
@LargeTest
@Test
public void kmz_with_trackdetail_and_sensordata() throws TimeoutException, IOException {
setUp();
public void kmz_with_trackdetail_and_sensordata() throws IOException {
// given
Track track = contentProviderUtils.getTrack(trackId);
@@ -323,41 +394,32 @@ public class ExportImportTest {
// 1. track
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
assertNotNull(importedTrack);
assertEquals(track.getActivityType(), importedTrack.getActivityType());
assertEquals(track.getActivityTypeLocalized(), importedTrack.getActivityTypeLocalized());
assertEquals(track.getDescription(), importedTrack.getDescription());
assertEquals(track.getName(), importedTrack.getName());
assertEquals(track.activityType(), importedTrack.activityType());
assertEquals(track.activityTypeLocalized(), importedTrack.activityTypeLocalized());
assertEquals(track.description(), importedTrack.description());
assertEquals(track.name(), importedTrack.name());
// 2. trackpoints
TrackPointAssert a = new TrackPointAssert();
List<TrackPoint> actual = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
a.assertEquals(trackPoints, actual);
new TrackPointAssert().assertEquals(trackPoints, actual);
// 3. trackstatistics
TrackStatistics importedTrackStatistics = importedTrack.getTrackStatistics();
// Time
assertEquals(track.getZoneOffset(), importedTrack.getZoneOffset());
assertEquals(Instant.parse("2020-02-02T02:02:02Z"), importedTrackStatistics.getStartTime());
assertEquals(Instant.parse("2020-02-02T02:04:00Z"), importedTrackStatistics.getStopTime());
assertEquals(Duration.ofSeconds(56), importedTrackStatistics.getTotalTime());
assertEquals(Duration.ofSeconds(26), importedTrackStatistics.getMovingTime());
// Distance
assertEquals(222049.421, importedTrackStatistics.getTotalDistance().toM(), 0.01);
// Speed
assertEquals(8540.362, importedTrackStatistics.getMaxSpeed().toMPS(), 0.01);
assertEquals(3965.168, importedTrackStatistics.getAverageSpeed().toMPS(), 0.01);
assertEquals(8540.362, importedTrackStatistics.getAverageMovingSpeed().toMPS(), 0.01);
// Altitude
assertEquals(999.122, importedTrackStatistics.getMinAltitude(), 0.01);
assertEquals(1020.25, importedTrackStatistics.getMaxAltitude(), 0.01);
assertEquals(2, importedTrackStatistics.getTotalAltitudeGain(), 0.01);
assertEquals(2, importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
Statistics importedTrackStatistics = importedTrack.statistics();
assertEquals(track.zoneOffset(), importedTrack.zoneOffset());
assertEquals(new Statistics(
Instant.parse("2020-02-02T02:02:02Z"),
Instant.parse("2020-02-02T02:04:00Z"),
Duration.ofSeconds(56),
Duration.ofSeconds(26), //TODO Likely too low
Distance.of(222049.421875), //TODO Too low
Speed.of(22203.7421875),
new AltitudeExtremities(999.1229858398438, 1020.25),
new AltitudeGainLoss(2, 2),
null,
null
),
importedTrackStatistics);
// 4. markers
assertMarkers();
@@ -365,9 +427,7 @@ public class ExportImportTest {
@LargeTest
@Test(expected = ImportAlreadyExistsException.class)
public void kml_with_trackdetail_and_sensordata_duplicate_trackUUID() throws TimeoutException, IOException {
setUp();
public void kml_with_trackdetail_and_sensordata_duplicate_trackUUID() throws IOException {
// given
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
editor.putBoolean(context.getString(R.string.import_prevent_reimport_key), true);
@@ -392,8 +452,6 @@ public class ExportImportTest {
@LargeTest
@Test
public void gpx() throws TimeoutException, IOException {
setUp();
// given
Track track = contentProviderUtils.getTrack(trackId);
@@ -413,10 +471,10 @@ public class ExportImportTest {
// 1. track
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
assertNotNull(importedTrack);
assertEquals(track.getActivityType(), importedTrack.getActivityType());
assertEquals(track.getActivityTypeLocalized(), importedTrack.getActivityTypeLocalized());
assertEquals(track.getDescription(), importedTrack.getDescription());
assertEquals(track.getName(), importedTrack.getName());
assertEquals(track.activityType(), importedTrack.activityType());
assertEquals(track.activityTypeLocalized(), importedTrack.activityTypeLocalized());
assertEquals(track.description(), importedTrack.description());
assertEquals(track.name(), importedTrack.name());
// 2. trackpoints
// The GPX exporter does not support exporting TrackPoints without lat/lng.
@@ -426,82 +484,105 @@ public class ExportImportTest {
.setDelta(0.05); // speed is not fully
List<TrackPoint> actual = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
a.assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC,
new TrackPoint(
null,
TrackPoint.Type.SEGMENT_START_AUTOMATIC,
new Position(
Instant.parse("2020-02-02T02:02:03Z"),
3.123456, 14.001456d, Distance.of(10),
Altitude.WGS84.of(1020.2), null,
null,
Speed.of(15)))
.setAltitudeLoss(1f)
.setAltitudeGain(1f),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
Speed.of(15)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(1, 1)
),
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse("2020-02-02T02:02:17Z"),
3.123456, 14.001456, Distance.of(10),
Altitude.WGS84.of(1020.2), null,
null,
Speed.of(5)))
.setAltitudeLoss(1f)
.setAltitudeGain(1f)
.setSensorDistance(Distance.of(12))
.setHeartRate(69)
.setPower(50f)
.setCadence(3f),
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC,
Speed.of(5)),
Distance.of(12),
HeartRate.of(69),
Temperature.of(30),
Cadence.of(3),
Power.of(50),
new AltitudeGainLoss(1, 1)
),
new TrackPoint(
null,
TrackPoint.Type.SEGMENT_START_AUTOMATIC,
new Position(
Instant.parse("2020-02-02T02:03:21Z"),
3.123456, 14.002456, Distance.of(10),
Altitude.WGS84.of(999.0999755859375), null,
null,
Speed.of(15)))
.setAltitudeLoss(0f)
.setAltitudeGain(0f),
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC,
Speed.of(15)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0)
),
new TrackPoint(
null,
TrackPoint.Type.SEGMENT_START_AUTOMATIC,
new Position(
Instant.parse("2020-02-02T02:03:22Z"),
3.123456, 16d, Distance.of(10),
Altitude.WGS84.of(999.0999755859375), null,
null,
Speed.of(15)))
.setAltitudeLoss(0f)
.setAltitudeGain(0f),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
Speed.of(15)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0)
),
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse("2020-02-02T02:03:50Z"),
3.123456, 16.001, Distance.of(10),
Altitude.WGS84.of(999.0999755859375), null,
null,
Speed.of(10)))
.setAltitudeLoss(0f)
.setAltitudeGain(0f)
.setSpeed(Speed.of(15))
Speed.of(15)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0)
)
), actual);
// 3. trackstatistics
TrackStatistics importedTrackStatistics = importedTrack.getTrackStatistics();
assertEquals(track.zoneOffset(), importedTrack.zoneOffset());
// Time
assertEquals(track.getZoneOffset(), importedTrack.getZoneOffset());
assertEquals(Instant.parse("2020-02-02T02:02:03Z"), importedTrackStatistics.getStartTime());
assertEquals(Instant.parse("2020-02-02T02:03:50Z"), importedTrackStatistics.getStopTime());
assertEquals(Duration.ofSeconds(107), importedTrackStatistics.getTotalTime());
assertEquals(Duration.ofSeconds(107), importedTrackStatistics.getMovingTime());
// Distance
assertEquals(222271.734, importedTrackStatistics.getTotalDistance().toM(), 0.01);
// Speed
assertEquals(2077.305, importedTrackStatistics.getMaxSpeed().toMPS(), 0.01);
assertEquals(2077.305, importedTrackStatistics.getAverageSpeed().toMPS(), 0.01);
assertEquals(2077.305, importedTrackStatistics.getAverageMovingSpeed().toMPS(), 0.01);
// Altitude
assertEquals(999.099, importedTrackStatistics.getMinAltitude(), 0.01);
assertEquals(1020.2, importedTrackStatistics.getMaxAltitude(), 0.01);
assertEquals(2, importedTrackStatistics.getTotalAltitudeGain(), 0.01);
assertEquals(2, importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
Statistics importedTrackStatistics = importedTrack.statistics();
assertEquals(new Statistics(
Instant.parse("2020-02-02T02:02:03Z"),
Instant.parse("2020-02-02T02:03:50Z"),
Duration.ofSeconds(107),
Duration.ofSeconds(107),
Distance.of(222271.734375),
Speed.of(2077.305908203125),
new AltitudeExtremities(999.0999755859375, 1020.2000122070312),
new AltitudeGainLoss(2, 2),
null,
null
),
importedTrackStatistics);
// 4. markers
assertMarkers();
@@ -509,9 +590,7 @@ public class ExportImportTest {
@LargeTest
@Test(expected = ImportAlreadyExistsException.class)
public void gpx_duplicate_trackUUID() throws TimeoutException, IOException {
setUp();
public void gpx_duplicate_trackUUID() throws IOException {
// given
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
editor.putBoolean(context.getString(R.string.import_prevent_reimport_key), true);
@@ -537,9 +616,7 @@ public class ExportImportTest {
@LargeTest
@Test
public void csv_export_only() throws TimeoutException, IOException {
setUp();
public void csv_export_only() throws IOException {
// given
Track track = contentProviderUtils.getTrack(trackId);
@@ -566,35 +643,34 @@ public class ExportImportTest {
}
private void assertMarkers() {
assertEquals(markers.size(), contentProviderUtils.getMarkers(importTrackId).size());
List<Marker> importedMarkers = TestDataUtil.getMarkers(contentProviderUtils, importTrackId);
assertEquals(markers.size(), importedMarkers.size());
List<Marker> importedMarkers = contentProviderUtils.getMarkers(importTrackId);
for (int i = 0; i < markers.size(); i++) {
Marker marker = markers.get(i);
Marker importMarker = importedMarkers.get(i);
assertEquals(marker.getCategory(), importMarker.getCategory());
assertEquals(marker.getDescription(), importMarker.getDescription());
// assertEquals(marker.getIcon(), importMarker.getIcon()); // TODO for KML
assertEquals(marker.getName(), importMarker.getName());
assertFalse(importMarker.hasPhoto());
assertEquals(marker.typeLocalized(), importMarker.typeLocalized());
assertEquals(marker.description(), importMarker.description());
assertEquals(marker.name(), importMarker.name());
assertNull(importMarker.photoUrl());
assertEquals(marker.getPosition().latitude(), importMarker.getPosition().latitude(), 0.001);
assertEquals(marker.getPosition().longitude(), importMarker.getPosition().longitude(), 0.001);
assertEquals(marker.getPosition().altitude().toM(), importMarker.getPosition().altitude().toM(), 0.1);
assertEquals(marker.position().latitude(), importMarker.position().latitude(), 0.001);
assertEquals(marker.position().longitude(), importMarker.position().longitude(), 0.001);
assertEquals(marker.position().altitude().toM(), importMarker.position().altitude().toM(), 0.1);
}
}
private void mockSensorData(TrackPointCreator trackPointCreator, Float speed, Distance distance, float heartRate, float cadence, Float power, Float altitudeGain) {
SensorDataSet sensorDataSet = trackPointCreator.getSensorManager().sensorDataSet;
private void mockSensorData(TrackPointCreator trackPointCreator, Float speed, Distance distance, float heartRate, float cadence, Float power, Float altitudeGain, float temperature) {
SensorDataAggregator sensorDataAggregator = trackPointCreator.getSensorManager().sensorDataAggregator;
AggregatorCyclingPower cyclingPower = new AggregatorCyclingPower("", "");
cyclingPower.add(new Raw<>(trackPointCreator.createNow(), new BluetoothHandlerManagerCyclingPower.Data(Power.of(power), null)));
sensorDataSet.add(cyclingPower);
cyclingPower.add(new Raw<>(trackPointCreator.createNow(), new BluetoothHandlerCyclingPower.Data(Power.of(power), null)));
sensorDataAggregator.add(cyclingPower);
AggregatorHeartRate avgHeartRate = new AggregatorHeartRate("", "");
avgHeartRate.add(new Raw<>(trackPointCreator.createNow(), HeartRate.of(heartRate)));
sensorDataSet.add(avgHeartRate);
sensorDataAggregator.add(avgHeartRate);
AggregatorCyclingCadence cyclingCadence = new AggregatorCyclingCadence("", "") {
@NonNull
@@ -608,33 +684,65 @@ public class ExportImportTest {
return true;
}
};
sensorDataSet.add(cyclingCadence);
sensorDataAggregator.add(cyclingCadence);
if (distance != null && speed != null) {
AggregatorCyclingDistanceSpeed distanceSpeed = Mockito.mock(AggregatorCyclingDistanceSpeed.class);
Mockito.when(distanceSpeed.hasReceivedData()).thenReturn(true);
Mockito.when(distanceSpeed.getAggregatedValue(Mockito.any())).thenReturn(new AggregatorCyclingDistanceSpeed.Data(null, distance, Speed.of(speed)));
sensorDataSet.add(distanceSpeed);
AggregatorCyclingDistanceSpeed aggregatorCyclingDistanceSpeed = new AggregatorCyclingDistanceSpeed("", "") {
@NonNull
@Override
public Data getAggregatedValue(Instant now) {
return new AggregatorCyclingDistanceSpeed.Data(null, distance, Speed.of(speed));
}
@Override
public boolean hasReceivedData() {
return true;
}
};
sensorDataAggregator.add(aggregatorCyclingDistanceSpeed);
} else {
sensorDataSet.add(new AggregatorCyclingDistanceSpeed("", ""));
sensorDataAggregator.add(new AggregatorCyclingDistanceSpeed("", ""));
}
mockAltitudeChange(trackPointCreator, altitudeGain);
trackPointCreator.onChange(sensorDataSet);
sensorDataAggregator.add(new AggregatorTemperature("", "'") {
@NonNull
@Override
public Temperature getAggregatedValue(Instant now) {
return Temperature.of(temperature);
}
@Override
public boolean hasReceivedData() {
return true;
}
});
trackPointCreator.onChange();
}
private void mockAltitudeChange(TrackPointCreator trackPointCreator, Float altitudeGain) {
SensorDataSet sensorDataSet = trackPointCreator.getSensorManager().sensorDataSet;
SensorDataAggregator sensorDataAggregator = trackPointCreator.getSensorManager().sensorDataAggregator;
if (altitudeGain != null) {
AggregatorBarometer barometer = Mockito.mock(AggregatorBarometer.class);
Mockito.when(barometer.hasReceivedData()).thenReturn(true);
Mockito.when(barometer.getAggregatedValue(Mockito.any())).thenReturn(new AltitudeGainLoss(altitudeGain, altitudeGain));
sensorDataSet.add(barometer);
} else {
sensorDataSet.add(new AggregatorBarometer("test", null));
if (altitudeGain == null) {
sensorDataAggregator.add(new AggregatorBarometer("test", null));
return;
}
AggregatorBarometer aggregatorBarometer = new AggregatorBarometer("", "") {
@NonNull
@Override
public AltitudeGainLoss getAggregatedValue(Instant now) {
return new AltitudeGainLoss(altitudeGain, altitudeGain);
}
@Override
public boolean hasReceivedData() {
return true;
}
};
sensorDataAggregator.add(aggregatorBarometer);
}
private void sendLocation(TrackPointCreator trackPointCreator, String time, double latitude, double longitude, float accuracy, float verticalAccuracy, float speed, double altitude, Float altitudeGain) {
@@ -27,14 +27,18 @@ import de.dennisguse.opentracks.content.data.TestDataUtil;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.ActivityType;
import de.dennisguse.opentracks.data.models.Altitude;
import de.dennisguse.opentracks.data.models.AltitudeGainLoss;
import de.dennisguse.opentracks.data.models.Cadence;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.HeartRate;
import de.dennisguse.opentracks.data.models.Position;
import de.dennisguse.opentracks.data.models.Power;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Statistics;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.io.file.TrackFileFormat;
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
import de.dennisguse.opentracks.stats.TrackStatistics;
/**
* Test that legacy KML/GPX formats can still be imported.
@@ -61,73 +65,6 @@ public class GPXTrackImporterTest {
}
}
/**
* Check that data that contains pause (lat=100, lng=0) and resume (lat=200, lng=0) locations are restored to a segment break.
*/
@LargeTest
@Test
public void gpx_with_pause_resume() throws IOException {
// given
XMLImporter importer = new XMLImporter(new GPXTrackImporter(context, trackImporter));
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.legacy_gpx_pause_resume);
// when
// 1. import
importTrackId = importer.importFile(inputStream).get(0);
// then
// 2. track
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
assertNotNull(importedTrack);
assertEquals(ActivityType.UNKNOWN, importedTrack.getActivityType());
assertEquals("the category", importedTrack.getActivityTypeLocalized());
assertEquals("the description", importedTrack.getDescription());
assertEquals("2021-01-07 22:51", importedTrack.getName());
assertEquals(ActivityType.UNKNOWN, importedTrack.getActivityType());
//TODO Check trackstatistics
// 3. trackpoints
List<TrackPoint> importedTrackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
assertEquals(6, importedTrackPoints.size());
// first segment
TrackPointAssert a = new TrackPointAssert();
a.assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC,
new Position(
Instant.parse("2021-01-07T21:51:59.179Z"),
3d, 14d, null,
Altitude.WGS84.of(10), null,
null,
null)),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse("2021-01-07T21:52:00.653Z"),
3d, 14.001, null,
Altitude.WGS84.of(10), null,
null,
Speed.of(75.4192))),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse("2021-01-07T21:52:01.010Z"),
3d, 14.002, null,
Altitude.WGS84.of(10), null,
null, Speed.of(311.3948))),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse("2021-01-07T21:52:02.658Z")),
// created resume trackpoint with time of next valid trackpoint
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse("2021-01-07T21:52:03.873Z")),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse("2021-01-07T21:52:04.103Z"),
3d, 14.003, null,
Altitude.WGS84.of(10), null,
null,
null))
), importedTrackPoints);
}
@LargeTest
@Test
public void gpx_without_speed() throws IOException {
@@ -143,15 +80,15 @@ public class GPXTrackImporterTest {
// 2. track
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
assertNotNull(importedTrack);
assertEquals("", importedTrack.getActivityTypeLocalized());
assertEquals("", importedTrack.getDescription());
assertEquals("20210907_213924.gpx", importedTrack.getName());
assertEquals(ActivityType.UNKNOWN, importedTrack.getActivityType());
assertEquals("", importedTrack.activityTypeLocalized());
assertEquals("", importedTrack.description());
assertEquals("20210907_213924.gpx", importedTrack.name());
assertEquals(ActivityType.UNKNOWN, importedTrack.activityType());
// 3. trackstatistics
TrackStatistics trackStatistics = importedTrack.getTrackStatistics();
assertEquals(0.75, trackStatistics.getMaxSpeed().toMPS(), 0.01);
assertEquals(Duration.ofSeconds(101), trackStatistics.getMovingTime());
Statistics trackStatistics = importedTrack.statistics();
assertEquals(0.75, trackStatistics.maxSpeed().toMPS(), 0.01);
assertEquals(Duration.ofSeconds(101), trackStatistics.movingDuration());
// 4. trackpoints
List<TrackPoint> importedTrackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
@@ -198,15 +135,15 @@ public class GPXTrackImporterTest {
// 2. track
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
assertNotNull(importedTrack);
assertEquals("", importedTrack.getActivityTypeLocalized());
assertEquals("", importedTrack.getDescription());
assertEquals("20210907_213924.gpx", importedTrack.getName());
assertEquals(ActivityType.UNKNOWN, importedTrack.getActivityType());
assertEquals("", importedTrack.activityTypeLocalized());
assertEquals("", importedTrack.description());
assertEquals("20210907_213924.gpx", importedTrack.name());
assertEquals(ActivityType.UNKNOWN, importedTrack.activityType());
// 3. trackstatistics
TrackStatistics trackStatistics = importedTrack.getTrackStatistics();
assertEquals(5.0, trackStatistics.getMaxSpeed().toMPS(), 0.01);
assertEquals(Duration.ofSeconds(101), trackStatistics.getMovingTime());
Statistics trackStatistics = importedTrack.statistics();
assertEquals(5.0, trackStatistics.maxSpeed().toMPS(), 0.01);
assertEquals(Duration.ofSeconds(101), trackStatistics.movingDuration());
// 4. trackpoints
List<TrackPoint> importedTrackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
@@ -260,56 +197,86 @@ public class GPXTrackImporterTest {
TrackPointAssert a = new TrackPointAssert()
.setDelta(0.05); // speed is not fully
a.assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC,
new TrackPoint(
null,
TrackPoint.Type.SEGMENT_START_AUTOMATIC,
new Position(
Instant.parse("2020-02-02T02:02:03Z"),
3d, 14d, Distance.of(10),
Altitude.WGS84.of(10), null,
null,
Speed.of(15)))
.setAltitudeLoss(1f)
.setAltitudeGain(1f),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
Speed.of(15)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(1, 1)
),
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse("2020-02-02T02:02:17Z"),
3d, 14.001, Distance.of(10),
Altitude.WGS84.of(10), null,
null,
Speed.of(5)))
.setAltitudeLoss(1f)
.setAltitudeGain(1f)
.setSensorDistance(Distance.of(12))
.setHeartRate(69)
.setPower(50f)
.setCadence(3f),
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC,
Speed.of(5)),
Distance.of(12),
HeartRate.of(69),
null,
Cadence.of(3),
Power.of(50),
new AltitudeGainLoss(1, 1)
),
new TrackPoint(
null,
TrackPoint.Type.SEGMENT_START_AUTOMATIC,
new Position(
Instant.parse("2020-02-02T02:03:21Z"),
3d, 14.002, Distance.of(10),
Altitude.WGS84.of(10), null,
null,
Speed.of(15)))
.setAltitudeLoss(0f)
.setAltitudeGain(0f),
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC,
Speed.of(15)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0)
),
new TrackPoint(
null,
TrackPoint.Type.SEGMENT_START_AUTOMATIC,
new Position(
Instant.parse("2020-02-02T02:03:22Z"),
3d, 16d, Distance.of(10),
Altitude.WGS84.of(10), null,
null,
Speed.of(15)))
.setAltitudeLoss(0f)
.setAltitudeGain(0f),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
Speed.of(15)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0)
),
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse("2020-02-02T02:03:50Z"),
3d, 16.001, Distance.of(10),
Altitude.WGS84.of(10), null,
null,
Speed.of(10)))
.setAltitudeLoss(0f)
.setAltitudeGain(0f)
.setSpeed(Speed.of(15))
Speed.of(15)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0)
)
), actual);
}
@@ -319,19 +286,19 @@ public class GPXTrackImporterTest {
// given
XMLImporter importer = new XMLImporter(new GPXTrackImporter(context, trackImporter));
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.gpx_timezone);
InputStream inputStreamExpected = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.gpx_timezone);
try (InputStream inputStreamExpected = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.test.R.raw.gpx_timezone)) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
// when
// 1. import
importTrackId = importer.importFile(inputStream).get(0);
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
// when
// 1. import
importTrackId = importer.importFile(inputStream).get(0);
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
TrackExporter trackExporter = TrackFileFormat.GPX.createTrackExporter(context, contentProviderUtils);
trackExporter.writeTrack(List.of(importedTrack), outputStream);
TrackExporter trackExporter = TrackFileFormat.GPX.createTrackExporter(context, contentProviderUtils);
trackExporter.writeTrack(List.of(importedTrack), outputStream);
// then
assertEquals(new String(inputStreamExpected.readAllBytes(), StandardCharsets.UTF_8), outputStream.toString());
// then
assertEquals(new String(inputStreamExpected.readAllBytes(), StandardCharsets.UTF_8), outputStream.toString());
}
}
}
@@ -73,13 +73,13 @@ public class KMLTrackImporterTest {
// 1. track
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
assertNotNull(importedTrack);
assertEquals("", importedTrack.getActivityTypeLocalized());
assertEquals("", importedTrack.getDescription());
assertEquals("", importedTrack.getName());
assertEquals(ActivityType.UNKNOWN, importedTrack.getActivityType());
assertEquals("", importedTrack.activityTypeLocalized());
assertEquals("", importedTrack.description());
assertEquals("", importedTrack.name());
assertEquals(ActivityType.UNKNOWN, importedTrack.activityType());
// 2. markers
assertEquals(0, contentProviderUtils.getMarkers(importTrackId).size());
assertEquals(0, TestDataUtil.getMarkers(contentProviderUtils, importTrackId).size());
// 3. trackpoints
List<TrackPoint> importedTrackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
@@ -129,13 +129,13 @@ public class KMLTrackImporterTest {
// 1. track
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
assertNotNull(importedTrack);
assertEquals("", importedTrack.getActivityTypeLocalized());
assertEquals("", importedTrack.getDescription());
assertEquals("", importedTrack.getName());
assertEquals(ActivityType.UNKNOWN, importedTrack.getActivityType());
assertEquals("", importedTrack.activityTypeLocalized());
assertEquals("", importedTrack.description());
assertEquals("", importedTrack.name());
assertEquals(ActivityType.UNKNOWN, importedTrack.activityType());
// 2. markers
assertEquals(0, contentProviderUtils.getMarkers(importTrackId).size());
assertEquals(0, TestDataUtil.getMarkers(contentProviderUtils, importTrackId).size());
// 3. trackpoints
List<TrackPoint> importedTrackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
@@ -170,13 +170,14 @@ public class KMLTrackImporterTest {
// 1. track
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
assertNotNull(importedTrack);
assertEquals("unknown", importedTrack.getActivityTypeLocalized());
assertEquals("Test Track", importedTrack.getDescription());
assertEquals("2020-11-28 18:06", importedTrack.getName());
assertEquals(ActivityType.UNKNOWN, importedTrack.getActivityType());
assertEquals("unknown", importedTrack.activityTypeLocalized());
assertEquals("Test Track", importedTrack.description());
assertEquals("2020-11-28 18:06", importedTrack.name());
assertEquals(ActivityType.UNKNOWN, importedTrack.activityType());
// 2. markers
assertEquals(1, contentProviderUtils.getMarkers(importTrackId).size());
//TODO Check actual content (Marker should be record for this)
assertEquals(1, TestDataUtil.getMarkers(contentProviderUtils, importTrackId).size());
// 3. trackpoints
List<TrackPoint> importedTrackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
@@ -189,24 +190,21 @@ public class KMLTrackImporterTest {
12.340097, 1.234156, null,
Altitude.WGS84.of(469.286376953125), null,
null,
Speed.of(0.539)))
.setAltitudeGain(0f),
Speed.of(0.539))),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse("2020-11-28T17:06:25.448Z"),
12.340036, 1.23415, null,
Altitude.WGS84.of(439.1626281738281), null,
null,
Speed.of(0.1577)))
.setAltitudeGain(0f),
Speed.of(0.1577))),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse("2020-11-28T17:06:47.888Z"),
12.340057, 1.23405, null,
Altitude.WGS84.of(421.8070983886719), null,
null,
Speed.of(0)))
.setAltitudeGain(0f),
Speed.ZERO)),
// created resume trackpoint with time of next valid trackpoint
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC,
new Position(
@@ -214,24 +212,21 @@ public class KMLTrackImporterTest {
12.340057, 1.23405, null,
Altitude.WGS84.of(419.93902587890625), null,
null,
Speed.of(0)))
.setAltitudeGain(0f),
Speed.ZERO)),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse("2020-11-28T17:06:56.905Z"),
12.340057, 1.23405, null,
Altitude.WGS84.of(419.9036560058594), null,
null,
Speed.of(0)))
.setAltitudeGain(0f),
Speed.ZERO)),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse("2020-11-28T17:07:20.870Z"),
12.340082, 1.234046, null,
Altitude.WGS84.of(417.99432373046875), null,
null,
Speed.of(0)))
.setAltitudeGain(0f)
Speed.ZERO))
), importedTrackPoints);
}
@@ -16,61 +16,47 @@ public class TrackPointAssert {
public void assertEquals(TrackPoint expected, TrackPoint actual) {
Assert.assertEquals("time", expected.getTime(), actual.getTime());
Assert.assertEquals("type", expected.getType(), actual.getType());
Assert.assertEquals("type", expected.type(), actual.type());
Assert.assertEquals("has location,", expected.hasLocation(), actual.hasLocation());
if (expected.hasLocation()) {
Assert.assertEquals("latitude", expected.getPosition().latitude(), actual.getPosition().latitude(), 0.001);
Assert.assertEquals("longitude", expected.getPosition().longitude(), actual.getPosition().longitude(), 0.001);
Assert.assertEquals("has location,", expected.position().hasLocation(), actual.position().hasLocation());
if (expected.position().hasLocation()) {
Assert.assertEquals("latitude", expected.position().latitude(), actual.position().latitude(), 0.001);
Assert.assertEquals("longitude", expected.position().longitude(), actual.position().longitude(), 0.001);
}
Assert.assertEquals("has altitude", expected.hasAltitude(), actual.hasAltitude());
if (expected.hasAltitude()) {
Assert.assertEquals("altitude", expected.getAltitude().toM(), actual.getAltitude().toM(), delta);
Assert.assertEquals("has altitude", expected.position().hasAltitude(), actual.position().hasAltitude());
if (expected.position().hasAltitude()) {
Assert.assertEquals("altitude", expected.position().altitude().toM(), actual.position().altitude().toM(), delta);
}
Assert.assertEquals("has altitudeGain", expected.hasAltitudeGain(), actual.hasAltitudeGain());
if (expected.hasAltitudeGain()) {
Assert.assertEquals("altitudeGain", expected.getAltitudeGain(), actual.getAltitudeGain(), delta);
}
Assert.assertEquals("has altitudeLoss", expected.hasAltitudeLoss(), actual.hasAltitudeLoss());
if (expected.hasAltitudeLoss()) {
Assert.assertEquals("altitudeLoss", expected.getAltitudeLoss(), actual.getAltitudeLoss(), delta);
Assert.assertEquals("altitudeGainLoss", expected.altitudeGainLoss(), actual.altitudeGainLoss());
Assert.assertEquals("has speed", expected.position().hasSpeed(), actual.position().hasSpeed());
if (expected.position().hasSpeed()) {
Assert.assertEquals("speed", expected.position().speed().toMPS(), actual.position().speed().toMPS(), delta);
}
Assert.assertEquals("has speed", expected.hasSpeed(), actual.hasSpeed());
if (expected.hasSpeed()) {
Assert.assertEquals("speed", expected.getSpeed().toMPS(), actual.getSpeed().toMPS(), delta);
Assert.assertEquals("has horizontalAccuracy", expected.position().hasHorizontalAccuracy(), actual.position().hasHorizontalAccuracy());
if (expected.position().hasHorizontalAccuracy()) {
Assert.assertEquals("horizontalAccuracy", expected.position().horizontalAccuracy().toM(), actual.position().horizontalAccuracy().toM(), delta);
}
Assert.assertEquals("has verticalAccuracy", expected.position().hasVerticalAccuracy(), actual.position().hasVerticalAccuracy());
if (expected.position().hasVerticalAccuracy()) {
Assert.assertEquals("verticalAccuracy", expected.position().verticalAccuracy().toM(), actual.position().verticalAccuracy().toM(), delta);
}
Assert.assertEquals("has horizontalAccuracy", expected.hasHorizontalAccuracy(), actual.hasHorizontalAccuracy());
if (expected.hasHorizontalAccuracy()) {
Assert.assertEquals("horizontalAccuracy", expected.getHorizontalAccuracy().toM(), actual.getHorizontalAccuracy().toM(), delta);
}
Assert.assertEquals("has verticalAccuracy", expected.hasVerticalAccuracy(), actual.hasVerticalAccuracy());
if (expected.hasVerticalAccuracy()) {
Assert.assertEquals("verticalAccuracy", expected.getVerticalAccuracy().toM(), actual.getVerticalAccuracy().toM(), delta);
Assert.assertEquals("has sensorDistance", expected.sensorDistance() != null, actual.sensorDistance() != null);
if (expected.sensorDistance() != null) {
Assert.assertEquals("sensorDistance", expected.sensorDistance().toM(), actual.sensorDistance().toM(), delta);
}
Assert.assertEquals("has sensorDistance", expected.hasSensorDistance(), actual.hasSensorDistance());
if (expected.hasSensorDistance()) {
Assert.assertEquals("sensorDistance", expected.getSensorDistance().toM(), actual.getSensorDistance().toM(), delta);
}
Assert.assertEquals("heartRate", expected.heartRate(), actual.heartRate());
Assert.assertEquals("has heartrate", expected.hasHeartRate(), actual.hasHeartRate());
if (expected.hasHeartRate()) {
Assert.assertEquals("heartrate", expected.getHeartRate(), actual.getHeartRate());
}
Assert.assertEquals("temperature", expected.temperature(), actual.temperature());
Assert.assertEquals("has power", expected.hasPower(), actual.hasPower());
if (expected.hasPower()) {
Assert.assertEquals("power", expected.getPower(), actual.getPower());
}
Assert.assertEquals("power", expected.power(), actual.power());
Assert.assertEquals("has cadence", expected.hasCadence(), actual.hasCadence());
if (expected.hasCadence()) {
Assert.assertEquals("cadence", expected.getCadence(), actual.getCadence());
}
Assert.assertEquals("cadence", expected.cadence(), actual.cadence());
}
public void assertEquals(List<TrackPoint> expected, List<TrackPoint> actual) {
@@ -0,0 +1,224 @@
package de.dennisguse.opentracks.publicapi;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import de.dennisguse.opentracks.data.ContentProviderUtils;
@RunWith(AndroidJUnit4.class)
public class DataProviderTest {
private final ContentResolver resolver = ApplicationProvider.getApplicationContext().getContentResolver();
@Test
public void supportsVersion2_tracks() {
// given
Uri uri = Uri.parse(ContentProviderUtils.CONTENT_BASE_URI + "/dashboard/tracks/1");
String[] expectedTracksColumns = new String[]{
"_id",
"name",
"description",
"category",
"activity_type_localized",
"starttime",
"stoptime",
"totaltime",
"movingtime",
"totaldistance",
"maxspeed",
"avgspeed",
"avgmovingspeed",
"minelevation",
"maxelevation",
"elevationgain",
"elevationloss"
};
// when
try (Cursor cursor = resolver.query(
uri,
expectedTracksColumns,
null,
null,
null
)) {
// then
assertEquals("vnd.android.cursor.dir/vnd.de.dennisguse.track", resolver.getType(uri));
assertNotNull(cursor);
assertArrayEquals(expectedTracksColumns, cursor.getColumnNames());
}
}
@Test
public void supportsVersion2_trackpoints() {
// given
Uri uri = Uri.parse(ContentProviderUtils.CONTENT_BASE_URI + "/dashboard/trackpoints/1");
String[] expectedTrackpointsColumns = {
"_id",
"trackid",
"latitude",
"longitude",
"time",
"type",
"speed"
};
// when
try (Cursor cursor = resolver.query(
uri,
expectedTrackpointsColumns,
null,
null,
null
)) {
// then
assertEquals("vnd.android.cursor.dir/vnd.de.dennisguse.trackpoint", resolver.getType(uri));
assertNotNull(cursor);
assertArrayEquals(expectedTrackpointsColumns, cursor.getColumnNames());
}
}
@Test
public void supportsVersion2_markers() {
// given
Uri uri = Uri.parse(ContentProviderUtils.CONTENT_BASE_URI + "/dashboard/markers/1");
String[] expectedMarkersColumns = {
"_id",
"name",
"description",
"category",
"trackid",
"longitude",
"latitude",
"photoUrl",
"icon"
};
// when
try (Cursor cursor = resolver.query(
uri,
expectedMarkersColumns,
null,
null,
null
)) {
// then
assertEquals("vnd.android.cursor.dir/vnd.de.dennisguse.waypoint", resolver.getType(uri));
assertNotNull(cursor);
assertArrayEquals(expectedMarkersColumns, cursor.getColumnNames());
}
}
@Test
public void supportsVersion3_tracks() {
// given
Uri uri = Uri.parse(ContentProviderUtils.CONTENT_BASE_URI + "/dashboard/tracks/1");
String[] expectedTracksColumns = {
"_id",
"name",
"description",
"activity_type",
"activity_type_localized",
"time_start",
"time_stop",
"duration_total",
"duration_moving",
"distance",
"speed_max",
"altitude_min",
"altitude_max",
"altitude_gain",
"altitude_loss"
};
// when
try (Cursor cursor = resolver.query(
uri,
expectedTracksColumns,
null,
null,
null
)) {
// then
assertEquals("vnd.android.cursor.dir/vnd.de.dennisguse.track", resolver.getType(uri));
assertNotNull(cursor);
assertArrayEquals(expectedTracksColumns, cursor.getColumnNames());
}
}
@Test
public void supportsVersion3_trackpoints() {
//given
Uri uri = Uri.parse(ContentProviderUtils.CONTENT_BASE_URI + "/dashboard/trackpoints/1");
String[] expectedTrackpointsColumns = {
"_id",
"trackid",
"latitude",
"longitude",
"time",
"type",
"speed"
};
// when
try (Cursor cursor = resolver.query(
uri,
expectedTrackpointsColumns,
null,
null,
null
)) {
//then
assertEquals("vnd.android.cursor.dir/vnd.de.dennisguse.trackpoint", resolver.getType(uri));
assertNotNull(cursor);
assertArrayEquals(expectedTrackpointsColumns, cursor.getColumnNames());
}
}
@Test
public void supportsVersion3_markers() {
// given
Uri uri = Uri.parse(ContentProviderUtils.CONTENT_BASE_URI + "/dashboard/markers/1");
String[] expectedMarkersColumns = {
"_id",
"name",
"description",
"marker_type_localized",
"trackid",
"latitude",
"longitude",
"photoUrl"
};
// when
try (Cursor cursor = resolver.query(
uri,
expectedMarkersColumns,
null,
null,
null
)) {
// then
assertEquals("vnd.android.cursor.dir/vnd.de.dennisguse.waypoint", resolver.getType(uri));
assertNotNull(cursor);
assertArrayEquals(expectedMarkersColumns, cursor.getColumnNames());
}
}
}
@@ -49,9 +49,9 @@ public class PublicApiTest {
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());
Assert.assertEquals("trackName", track.name());
Assert.assertEquals("activityTypeLocalized", track.activityTypeLocalized());
Assert.assertEquals("airplane", track.activityType().getId());
}
@Test
@@ -10,11 +10,11 @@ public class BluetoothHandlerCyclingPowerTest {
@Test
public void parseCyclingPower_power() {
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothHandlerManagerCyclingPower.CYCLING_POWER.serviceUUID(), 0, 0);
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothHandlerCyclingPower.CYCLING_POWER.serviceUUID(), 0, 0);
characteristic.setValue(new byte[]{0, 0, 40, 0});
// when
BluetoothHandlerManagerCyclingPower.Data powerCadence = BluetoothHandlerManagerCyclingPower.parseCyclingPower(characteristic);
BluetoothHandlerCyclingPower.Data powerCadence = BluetoothHandlerCyclingPower.parseCyclingPower(characteristic);
// then
assertEquals(40, powerCadence.power().getW(), 0.01);
@@ -22,11 +22,11 @@ public class BluetoothHandlerCyclingPowerTest {
@Test
public void parseCyclingPower_power_with_cadence() {
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothHandlerManagerCyclingPower.CYCLING_POWER.serviceUUID(), 0, 0);
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothHandlerCyclingPower.CYCLING_POWER.serviceUUID(), 0, 0);
characteristic.setValue(new byte[]{0x2C, 0x00, 0x00, 0x00, (byte) 0x9F, 0x00, 0x0C, 0x00, (byte) 0xE5, 0x42});
// when
BluetoothHandlerManagerCyclingPower.Data powerCadence = BluetoothHandlerManagerCyclingPower.parseCyclingPower(characteristic);
BluetoothHandlerCyclingPower.Data powerCadence = BluetoothHandlerCyclingPower.parseCyclingPower(characteristic);
// then
assertEquals(0, powerCadence.power().getW(), 0.01);
@@ -8,16 +8,16 @@ import org.junit.Test;
import de.dennisguse.opentracks.data.models.HeartRate;
public class BluetoothHandlerManagerHeartRateTest {
public class BluetoothHandlerHeartRateTest {
@Test
public void parseHeartRate_uint8() {
// given
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothHandlerManagerHeartRate.HEARTRATE.serviceUUID(), 0, 0);
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothHandlerHeartRate.HEARTRATE.serviceUUID(), 0, 0);
characteristic.setValue(new byte[]{0x02, 0x3C});
// when
HeartRate heartRate = BluetoothHandlerManagerHeartRate.parseHeartRate(characteristic);
HeartRate heartRate = BluetoothHandlerHeartRate.parseHeartRate(characteristic);
// then
assertEquals(HeartRate.of(60), heartRate);
@@ -26,11 +26,11 @@ public class BluetoothHandlerManagerHeartRateTest {
@Test
public void parseHeartRate_uint16() {
// given
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothHandlerManagerHeartRate.HEARTRATE.serviceUUID(), 0, 0);
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothHandlerHeartRate.HEARTRATE.serviceUUID(), 0, 0);
characteristic.setValue(new byte[]{0x01, 0x01, 0x01});
// when
HeartRate heartRate = BluetoothHandlerManagerHeartRate.parseHeartRate(characteristic);
HeartRate heartRate = BluetoothHandlerHeartRate.parseHeartRate(characteristic);
// then
assertEquals(HeartRate.of(257), heartRate);
@@ -28,7 +28,6 @@ import java.util.List;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Position;
import de.dennisguse.opentracks.data.models.TrackPoint;
@RunWith(AndroidJUnit4.class)
public class GpsStatusTest {
@@ -82,16 +81,16 @@ public class GpsStatusTest {
// when / then
subject.start();
subject.onNewTrackPoint(new TrackPoint(TrackPoint.Type.TRACKPOINT, Position.of(badFix, Instant.now())));
subject.onNewTrackPoint(Position.of(badFix, Instant.now()));
assertEquals(List.of(GPS_ENABLED, GPS_SIGNAL_BAD), statusList);
subject.onNewTrackPoint(new TrackPoint(TrackPoint.Type.TRACKPOINT, Position.of(ok, Instant.now())));
subject.onNewTrackPoint(Position.of(ok, Instant.now()));
assertEquals(List.of(GPS_ENABLED, GPS_SIGNAL_BAD, GPS_SIGNAL_FIX), statusList);
subject.onNewTrackPoint(new TrackPoint(TrackPoint.Type.TRACKPOINT, Position.of(ok, Instant.now())));
subject.onNewTrackPoint(Position.of(ok, Instant.now()));
assertEquals(List.of(GPS_ENABLED, GPS_SIGNAL_BAD, GPS_SIGNAL_FIX), statusList);
subject.onNewTrackPoint(new TrackPoint(TrackPoint.Type.TRACKPOINT, Position.of(badFix, Instant.now())));
subject.onNewTrackPoint(Position.of(badFix, Instant.now()));
assertEquals(List.of(GPS_ENABLED, GPS_SIGNAL_BAD, GPS_SIGNAL_FIX, GPS_SIGNAL_BAD), statusList);
}
@@ -106,13 +105,13 @@ public class GpsStatusTest {
// when / then
subject.start();
subject.onNewTrackPoint(new TrackPoint(TrackPoint.Type.TRACKPOINT, Position.of(ok, Instant.now().minusMillis(1000))));
subject.onNewTrackPoint(Position.of(ok, Instant.now().minusMillis(1000)));
assertEquals(List.of(GPS_ENABLED, GPS_SIGNAL_FIX), statusList);
subject.determineGpsStatusByTime(Instant.now());
assertEquals(List.of(GPS_ENABLED, GPS_SIGNAL_FIX, GPS_SIGNAL_LOST), statusList);
subject.onNewTrackPoint(new TrackPoint(TrackPoint.Type.TRACKPOINT, Position.of(ok, Instant.now())));
subject.onNewTrackPoint(Position.of(ok, Instant.now()));
assertEquals(List.of(GPS_ENABLED, GPS_SIGNAL_FIX, GPS_SIGNAL_LOST, GPS_SIGNAL_FIX), statusList);
}
@@ -133,13 +132,13 @@ public class GpsStatusTest {
Thread.sleep(100);
assertEquals(List.of(GPS_ENABLED), statusList);
subject.onNewTrackPoint(new TrackPoint(TrackPoint.Type.TRACKPOINT, Position.of(ok, Instant.now())));
subject.onNewTrackPoint(Position.of(ok, Instant.now()));
assertEquals(List.of(GPS_ENABLED, GPS_SIGNAL_FIX), statusList);
Thread.sleep(100);
assertEquals(List.of(GPS_ENABLED, GPS_SIGNAL_FIX, GPS_SIGNAL_LOST), statusList);
subject.onNewTrackPoint(new TrackPoint(TrackPoint.Type.TRACKPOINT, Position.of(badFix, Instant.now())));
subject.onNewTrackPoint(Position.of(badFix, Instant.now()));
assertEquals(List.of(GPS_ENABLED, GPS_SIGNAL_FIX, GPS_SIGNAL_LOST, GPS_SIGNAL_BAD), statusList);
Thread.sleep(100);
@@ -125,6 +125,6 @@ public class SensorDataCyclingTest {
// TODO See #953
// assertEquals(2, current.getValue().getDistance().toM(), 0.01);
// assertEquals(2, current.getValue().getSpeed().toMPS(), 0.01);
assertEquals(new AggregatorCyclingDistanceSpeed.Data(Distance.of(0), Distance.of(0), Speed.of(0)), current.getAggregatedValue(Instant.MIN));
assertEquals(new AggregatorCyclingDistanceSpeed.Data(Distance.ZERO, Distance.ZERO, Speed.ZERO), current.getAggregatedValue(Instant.MIN));
}
}
@@ -16,24 +16,24 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.time.ZoneOffset;
import java.util.UUID;
import de.dennisguse.opentracks.data.models.ActivityType;
import de.dennisguse.opentracks.data.models.Altitude;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Position;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Statistics;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.settings.UnitSystem;
import de.dennisguse.opentracks.stats.TrackStatistics;
@RunWith(MockitoJUnitRunner.class)
public class TrackRecordingServiceNotificationManagerTest {
private final Context context = ApplicationProvider.getApplicationContext();
@Mock
private TrackPoint trackPointMock;
@Mock
private TrackStatistics trackStatisticsMock;
@Mock
private NotificationCompat.Builder notificationCompatBuilder;
@@ -42,18 +42,32 @@ public class TrackRecordingServiceNotificationManagerTest {
@Test
public void updateLocation_triggersAlertOnlyOnFirstInaccurateLocation() {
when(trackPointMock.hasHorizontalAccuracy()).thenReturn(true);
when(trackPointMock.getHorizontalAccuracy()).thenReturn(Distance.of(999f));
when(trackPointMock.getSpeed()).thenReturn(Speed.of(0));
when(trackStatisticsMock.getTotalDistance()).thenReturn(Distance.of(0));
TrackPoint trackPointMock = new TrackPoint(TrackPoint.Type.TRACKPOINT,
new Position(
null,
null, null, Distance.of(999f),
Altitude.WGS84.of(10), null,
null,
Speed.ZERO)
);
when(notificationCompatBuilder.setOnlyAlertOnce(anyBoolean()))
.thenReturn(notificationCompatBuilder);
TrackRecordingServiceNotificationManager subject = new TrackRecordingServiceNotificationManager(notificationManager, notificationCompatBuilder);
subject.setUnitSystem(UnitSystem.METRIC);
Track track = new Track();
track.setTrackStatistics(trackStatisticsMock);
Track track = new Track(
null,
UUID.fromString("f81d4fae-7dec-11d0-a765-00a0c91e6bf6"),
"Berlin",
"",
"",
ActivityType.CYCLING,
ZoneOffset.UTC,
Statistics.DEFAULT
);
RecordingData data = new RecordingData(track, trackPointMock, null, null);
// when
@@ -5,8 +5,12 @@ import static org.junit.Assert.assertFalse;
import android.content.Context;
import android.content.Intent;
import android.location.Location;
import android.location.LocationManager;
import android.os.Looper;
import androidx.annotation.NonNull;
import androidx.core.location.LocationManagerCompat;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.MediumTest;
@@ -31,10 +35,12 @@ 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;
import de.dennisguse.opentracks.data.models.Cadence;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.HeartRate;
import de.dennisguse.opentracks.data.models.Position;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Statistics;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.io.file.importer.TrackPointAssert;
@@ -46,11 +52,7 @@ import de.dennisguse.opentracks.sensors.sensorData.AggregatorRunning;
import de.dennisguse.opentracks.sensors.sensorData.Raw;
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
import de.dennisguse.opentracks.settings.PreferencesUtils;
import de.dennisguse.opentracks.stats.TrackStatistics;
/**
* Tests insert location.
*/
@RunWith(AndroidJUnit4.class)
public class TrackRecordingServiceRecordingTest {
@@ -106,8 +108,8 @@ public class TrackRecordingServiceRecordingTest {
// then
assertEquals(new TrackStatistics(startTime, startTime, 0, 0, 0, 0, null, null)
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
assertEquals(new Statistics(Instant.parse(startTime), Instant.parse(startTime), Duration.ZERO, Duration.ZERO, Distance.ZERO, Speed.ZERO, null, null, null, null)
, contentProviderUtils.getTrack(trackId).statistics());
new TrackPointAssert().assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime))
@@ -120,14 +122,21 @@ public class TrackRecordingServiceRecordingTest {
service.endCurrentTrack();
// then
assertEquals(new TrackStatistics(startTime, stopTime, 0, 1, 1, 0, 0f, 0f)
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
assertEquals(new Statistics(Instant.parse(startTime), Instant.parse(stopTime), Duration.ofSeconds(1), Duration.ofSeconds(1), Distance.ZERO, Speed.ZERO, null, new AltitudeGainLoss(0, 0), null, null)
, contentProviderUtils.getTrack(trackId).statistics());
new TrackPointAssert().assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
.setAltitudeGain(0f)
.setAltitudeLoss(0f)
new TrackPoint(
null,
TrackPoint.Type.SEGMENT_END_MANUAL,
Position.of(Instant.parse(stopTime)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0))
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
@@ -143,10 +152,14 @@ public class TrackRecordingServiceRecordingTest {
String startTime = "2020-02-02T02:02:02Z";
trackPointCreator.setClock(startTime);
Track.Id trackId = service.startNewTrack();
//We do not want the real GPS to interfere.
LocationManagerCompat.removeUpdates((LocationManager) context.getSystemService(Context.LOCATION_SERVICE), trackPointCreator.getSensorManager().getGpsManager());
String gps1 = "2020-02-02T02:02:03Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15);
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);
sendGPSLocation(trackPointCreator, gps2, 45.0, 35.0, 1, 15);
// when
String idleTime = "2020-02-02T02:02:17Z";
@@ -192,14 +205,21 @@ public class TrackRecordingServiceRecordingTest {
service.endCurrentTrack();
// then
assertEquals(new TrackStatistics(startTime, pauseTime, 0, 1, 1, 0, 0f, 0f)
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
assertEquals(new Statistics(Instant.parse(startTime), Instant.parse(pauseTime), Duration.ofSeconds(1), Duration.ofSeconds(1), Distance.ZERO, Speed.ZERO, null, new AltitudeGainLoss(0, 0), null, null)
, contentProviderUtils.getTrack(trackId).statistics());
new TrackPointAssert().assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(pauseTime))
.setAltitudeGain(0f)
.setAltitudeLoss(0f)
new TrackPoint(
null,
TrackPoint.Type.SEGMENT_END_MANUAL,
Position.of(Instant.parse(pauseTime)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0))
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
//when
@@ -208,14 +228,22 @@ public class TrackRecordingServiceRecordingTest {
service.resumeTrack(trackId);
// then
assertEquals(new TrackStatistics(startTime, resumeTime, 0, 1, 1, 0, 0f, 0f)
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
assertEquals(new Statistics(Instant.parse(startTime), Instant.parse(resumeTime), Duration.ofSeconds(1), Duration.ofSeconds(1), Distance.ZERO, Speed.ZERO, null, new AltitudeGainLoss(0, 0), null, null)
, contentProviderUtils.getTrack(trackId).statistics());
new TrackPointAssert().assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(pauseTime))
.setAltitudeGain(0f)
.setAltitudeLoss(0f),
new TrackPoint(
null,
TrackPoint.Type.SEGMENT_END_MANUAL,
Position.of(Instant.parse(pauseTime)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0)
),
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(resumeTime))
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
@@ -247,9 +275,16 @@ public class TrackRecordingServiceRecordingTest {
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
new TrackPointAssert().assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(starTime)),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(pauseTime))
.setAltitudeGain(0f)
.setAltitudeLoss(0f)
new TrackPoint(
null,
TrackPoint.Type.SEGMENT_END_MANUAL,
Position.of(Instant.parse(pauseTime)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0))
), trackPoints);
}
@@ -277,9 +312,17 @@ public class TrackRecordingServiceRecordingTest {
// then
new TrackPointAssert().assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
.setAltitudeGain(0f)
.setAltitudeLoss(0f),
new TrackPoint(
null,
TrackPoint.Type.SEGMENT_END_MANUAL,
Position.of(Instant.parse(stopTime)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0)
),
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(resumeTime))
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
@@ -296,7 +339,7 @@ public class TrackRecordingServiceRecordingTest {
mockAltitudeChange(trackPointCreator, 0);
SensorManager sensorManager = trackPointCreator.getSensorManager();
sensorManager.sensorDataSet.add(new AggregatorHeartRate("", ""));
sensorManager.sensorDataAggregator.add(new AggregatorHeartRate("", ""));
// when
String sensor1 = "2020-02-02T02:02:03Z";
trackPointCreator.setClock(sensor1);
@@ -314,14 +357,28 @@ public class TrackRecordingServiceRecordingTest {
// then
new TrackPointAssert().assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(sensor3))
.setAltitudeGain(0f)
.setAltitudeLoss(0f)
.setHeartRate(HeartRate.of(7)),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
.setAltitudeGain(0f)
.setAltitudeLoss(0f)
.setHeartRate(HeartRate.of(7))
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
Position.of(Instant.parse(sensor3)),
null,
HeartRate.of(7),
null,
null,
null,
new AltitudeGainLoss(0, 0)
),
new TrackPoint(
null,
TrackPoint.Type.SEGMENT_END_MANUAL,
Position.of(Instant.parse(stopTime)),
null,
HeartRate.of(7),
null,
null,
null,
new AltitudeGainLoss(0, 0)
)
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
@@ -338,28 +395,27 @@ public class TrackRecordingServiceRecordingTest {
// when
String gps1 = "2020-02-02T02:02:03Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15);
sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15);
// then
assertEquals(new TrackStatistics(startTime, gps1, 0, 1, 1, 15, 0f, 0f)
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
assertEquals(new Statistics(Instant.parse(startTime), Instant.parse(gps1), Duration.ofSeconds(1), Duration.ofSeconds(1), Distance.ZERO, Speed.of(15), null, new AltitudeGainLoss(0, 0), null, null)
, contentProviderUtils.getTrack(trackId).statistics());
// when
String gps2 = "2020-02-02T02:02:06Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps2, 45.0001, 35.0, 1, 15);
sendGPSLocation(trackPointCreator, gps2, 45.0001, 35.0, 1, 15);
// then
assertEquals(new TrackStatistics(startTime, gps2, 11.113178253173828f, 4, 4, 15, 0f, 0f)
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
assertEquals(new Statistics(Instant.parse(startTime), Instant.parse(gps2), Duration.ofSeconds(4), Duration.ofSeconds(4), Distance.of(11.113178253173828), Speed.of(15), null, new AltitudeGainLoss(0, 0), null, null)
, contentProviderUtils.getTrack(trackId).statistics());
// when
String gps3 = "2020-02-02T02:02:08Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps3, 45.0002, 35.0, 1, 15);
sendGPSLocation(trackPointCreator, gps3, 45.0002, 35.0, 1, 15);
// then
assertEquals(new TrackStatistics(startTime, gps3, 22.226356506347656, 6, 6, 15, 0f, 0f)
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
assertEquals(new Statistics(Instant.parse(startTime), Instant.parse(gps3), Duration.ofSeconds(6), Duration.ofSeconds(6), Distance.of(22.226356506347656), Speed.of(15), null, new AltitudeGainLoss(0, 0), null, null)
, contentProviderUtils.getTrack(trackId).statistics());
// when
String stopTime = "2020-02-02T02:02:12Z";
@@ -367,41 +423,70 @@ public class TrackRecordingServiceRecordingTest {
service.endCurrentTrack();
// then
assertEquals(new TrackStatistics(startTime, stopTime, 22.226356506347656, 10, 10, 15, 0f, 0f)
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
assertEquals(new Statistics(Instant.parse(startTime), Instant.parse(stopTime), Duration.ofSeconds(10), Duration.ofSeconds(10), Distance.of(22.226356506347656), Speed.of(15), null, new AltitudeGainLoss(0, 0), null, null)
, contentProviderUtils.getTrack(trackId).statistics());
new TrackPointAssert().assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse(gps1),
45d, 35d, Distance.of(1),
null, null,
null,
Speed.of(15)))
.setAltitudeGain(0f)
.setAltitudeLoss(0f),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
Speed.of(15)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0)
),
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse(gps2),
45.001, 35d, Distance.of(1),
null, null,
null,
Speed.of(15)))
.setAltitudeGain(0f)
.setAltitudeLoss(0f),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
Speed.of(15)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0)
),
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse(gps3),
45.001, 35d, Distance.of(1),
null, null,
null,
Speed.of(15)))
.setAltitudeGain(0f)
.setAltitudeLoss(0f),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
.setAltitudeGain(0f)
.setAltitudeLoss(0f)
Speed.of(15)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0)
),
new TrackPoint(
null,
TrackPoint.Type.SEGMENT_END_MANUAL,
Position.of(Instant.parse(stopTime)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0)
)
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
@@ -417,25 +502,25 @@ public class TrackRecordingServiceRecordingTest {
// when
String gps1 = "2020-02-02T02:02:03Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15);
sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15);
// then
TrackStatistics gps1Statistics = new TrackStatistics(startTime, gps1, 0, 1, 1, 15, 0f, 0f);
assertEquals(gps1Statistics, contentProviderUtils.getTrack(trackId).getTrackStatistics());
Statistics gps1Statistics = new Statistics(Instant.parse(startTime), Instant.parse(gps1), Duration.ofSeconds(1), Duration.ofSeconds(1), Distance.ZERO, Speed.of(15), null, new AltitudeGainLoss(0, 0), null, null);
assertEquals(gps1Statistics, contentProviderUtils.getTrack(trackId).statistics());
// when
String gps2 = "2020-02-02T02:02:06Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps2, 45.00001, 35.0, 1, 15);
sendGPSLocation(trackPointCreator, gps2, 45.00001, 35.0, 1, 15);
// then
assertEquals(gps1Statistics, contentProviderUtils.getTrack(trackId).getTrackStatistics());
assertEquals(gps1Statistics, contentProviderUtils.getTrack(trackId).statistics());
// when
String gps3 = "2020-02-02T02:02:08Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps3, 45.00002, 35.0, 1, 15);
sendGPSLocation(trackPointCreator, gps3, 45.00002, 35.0, 1, 15);
// then
assertEquals(gps1Statistics, contentProviderUtils.getTrack(trackId).getTrackStatistics());
assertEquals(gps1Statistics, contentProviderUtils.getTrack(trackId).statistics());
// when
String stopTime = "2020-02-02T02:02:12Z";
@@ -443,38 +528,59 @@ public class TrackRecordingServiceRecordingTest {
service.endCurrentTrack();
// then
assertEquals(new TrackStatistics(startTime, stopTime, 2.222635507583618, 10, 10, 15, 0f, 0f)
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
assertEquals(new Statistics(Instant.parse(startTime), Instant.parse(stopTime), Duration.ofSeconds(10), Duration.ofSeconds(10), Distance.of(2.222635507583618), Speed.of(15), null, new AltitudeGainLoss(0, 0), null, null)
, contentProviderUtils.getTrack(trackId).statistics());
new TrackPointAssert().assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse(gps1),
45d, 35d, Distance.of(1),
null, null,
null,
Speed.of(15)))
.setAltitudeGain(0f)
.setAltitudeLoss(0f),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
Speed.of(15)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0)
),
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse(gps3),
45.00002, 35d, Distance.of(1),
null, null,
null,
Speed.of(15)))
.setAltitudeGain(0f)
.setAltitudeLoss(0f),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL,
Speed.of(15)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0)
),
new TrackPoint(
null,
TrackPoint.Type.SEGMENT_END_MANUAL,
new Position(
Instant.parse(stopTime),
45.00002, 35d, Distance.of(1),
null, null,
null,
Speed.of(15)))
.setAltitudeGain(0f)
.setAltitudeLoss(0f)
Speed.of(15)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0)
)
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
@@ -491,15 +597,15 @@ public class TrackRecordingServiceRecordingTest {
// when
String gps1 = "2020-02-02T02:02:03Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15);
sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15);
// when - will be ignored
String gps2 = "2020-02-02T02:02:04Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps2, 45.0, 35.0, 1, 15);
sendGPSLocation(trackPointCreator, gps2, 45.0, 35.0, 1, 15);
// when
String gps3 = "2020-02-02T02:02:05Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps3, 45.0001, 35.0, 1, 15);
sendGPSLocation(trackPointCreator, gps3, 45.0001, 35.0, 1, 15);
// when
String stopTime = "2020-02-02T02:02:12Z";
@@ -509,27 +615,47 @@ public class TrackRecordingServiceRecordingTest {
// then
new TrackPointAssert().assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse(gps1),
45d, 35d, Distance.of(1),
null, null,
null,
Speed.of(15)))
.setAltitudeGain(0f)
.setAltitudeLoss(0f),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
Speed.of(15)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0)
),
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse(gps3),
45d, 35d, Distance.of(1),
null, null,
null,
Speed.of(15)))
.setAltitudeGain(0f)
.setAltitudeLoss(0f),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
.setAltitudeGain(0f)
.setAltitudeLoss(0f)
Speed.of(15)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0)),
new TrackPoint(
null,
TrackPoint.Type.SEGMENT_END_MANUAL,
Position.of(Instant.parse(stopTime)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0))
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
@@ -545,19 +671,19 @@ public class TrackRecordingServiceRecordingTest {
// when
String gps1 = "2020-02-02T02:02:03Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 100, 15);
sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 100, 15);
// then
TrackStatistics startStatistics = new TrackStatistics(startTime, startTime, 0, 0, 0, 0, null, null);
assertEquals(startStatistics, contentProviderUtils.getTrack(trackId).getTrackStatistics());
Statistics startStatistics = new Statistics(Instant.parse(startTime), Instant.parse(startTime), Duration.ZERO, Duration.ZERO, Distance.ZERO, Speed.ZERO, null, null, null, null);
assertEquals(startStatistics, contentProviderUtils.getTrack(trackId).statistics());
// when
String gps2 = "2020-02-02T02:02:06Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps2, 45.1, 35.0, 100, 15);
sendGPSLocation(trackPointCreator, gps2, 45.1, 35.0, 100, 15);
// then
assertEquals(startStatistics, contentProviderUtils.getTrack(trackId).getTrackStatistics());
assertEquals(startStatistics, contentProviderUtils.getTrack(trackId).statistics());
// when
@@ -566,16 +692,22 @@ public class TrackRecordingServiceRecordingTest {
service.endCurrentTrack();
// then
assertEquals(new TrackStatistics(startTime, stopTime, 0, 10, 10, 0, 0f, 0f)
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
assertEquals(new Statistics(Instant.parse(startTime), Instant.parse(stopTime), Duration.ofSeconds(10), Duration.ofSeconds(10), Distance.ZERO, Speed.ZERO, null, new AltitudeGainLoss(0, 0), null, null)
, contentProviderUtils.getTrack(trackId).statistics());
// then
new TrackPointAssert().assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
.setAltitudeGain(0f)
.setAltitudeLoss(0f)
new TrackPoint(
null,
TrackPoint.Type.SEGMENT_END_MANUAL,
Position.of(Instant.parse(stopTime)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0))
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
@@ -591,18 +723,19 @@ public class TrackRecordingServiceRecordingTest {
// when
String gps1 = "2020-02-02T02:02:03Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15);
sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15);
// then
assertEquals(new TrackStatistics(startTime, gps1, 0, 1, 1, 15, 0f, 0f), contentProviderUtils.getTrack(trackId).getTrackStatistics());
assertEquals(new Statistics(Instant.parse(startTime), Instant.parse(gps1), Duration.ofSeconds(1), Duration.ofSeconds(1), Distance.ZERO, Speed.of(15), null, new AltitudeGainLoss(0, 0), null, null)
, contentProviderUtils.getTrack(trackId).statistics());
// when
String gps2 = "2020-02-02T02:02:06Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps2, 45.1, 35.0, 1, 15);
sendGPSLocation(trackPointCreator, gps2, 45.1, 35.0, 1, 15);
// then
assertEquals(new TrackStatistics(startTime, gps2, 11113.275390625, 4, 4, 2778.31884765625f, 0f, 0f).toString(), contentProviderUtils.getTrack(trackId).getTrackStatistics().toString());
assertEquals(new Statistics(Instant.parse(startTime), Instant.parse(gps2), Duration.ofSeconds(4), Duration.ofSeconds(4), Distance.of(11113.275390625), Speed.of(2778.31884765625f), null, new AltitudeGainLoss(0, 0), null, null)
, contentProviderUtils.getTrack(trackId).statistics());
// when
String stopTime = "2020-02-02T02:02:12Z";
@@ -610,33 +743,55 @@ public class TrackRecordingServiceRecordingTest {
service.endCurrentTrack();
// then
assertEquals(new TrackStatistics(startTime, stopTime, 11113.275390625, 10, 10, 1111.3275390625f, 0f, 0f).toString(), contentProviderUtils.getTrack(trackId).getTrackStatistics().toString());
assertEquals(new Statistics(Instant.parse(startTime), Instant.parse(stopTime), Duration.ofSeconds(10), Duration.ofSeconds(10), Distance.of(11113.275390625), Speed.of(1111.3275146484375), null, new AltitudeGainLoss(0, 0), null, null)
, contentProviderUtils.getTrack(trackId).statistics());
// then
new TrackPointAssert().assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse(gps1),
45d, 35d, Distance.of(1),
null, null,
null,
Speed.of(15)))
.setAltitudeGain(0f)
.setAltitudeLoss(0f),
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC,
Speed.of(15)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0)
),
new TrackPoint(
null,
TrackPoint.Type.SEGMENT_START_AUTOMATIC,
new Position(
Instant.parse(gps2),
45.1, 35d, Distance.of(1),
null, null,
null,
Speed.of(15)))
.setAltitudeGain(0f)
.setAltitudeLoss(0f),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
.setAltitudeGain(0f)
.setAltitudeLoss(0f)
Speed.of(15)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0)
),
new TrackPoint(
null,
TrackPoint.Type.SEGMENT_END_MANUAL,
Position.of(Instant.parse(stopTime)),
null,
null,
null,
null,
null,
new AltitudeGainLoss(0, 0))
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
@@ -654,49 +809,49 @@ public class TrackRecordingServiceRecordingTest {
Track.Id trackId = service.startNewTrack();
SensorManager sensorManager = trackPointCreator.getSensorManager();
sensorManager.sensorDataSet.add(new AggregatorRunning("", ""));
sensorManager.sensorDataSet.barometer = null;
sensorManager.sensorDataAggregator.add(new AggregatorRunning("", ""));
sensorManager.sensorDataAggregator.barometer = null;
// when
String sensor1 = "2020-02-02T02:02:03Z";
trackPointCreator.setClock(sensor1);
sensorManager.onChanged(new Raw<>(sensor1, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), null, Distance.of(0)))); //Should be ignored
sensorManager.onChanged(new Raw<>(sensor1, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(1), Distance.ZERO))); //Should be ignored
// when
String sensor2 = "2020-02-02T02:02:04Z";
trackPointCreator.setClock(sensor2);
sensorManager.onChanged(new Raw<>(sensor2, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), null, Distance.of(2))));
sensorManager.onChanged(new Raw<>(sensor2, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(2), Distance.of(2))));
// when
String gps1 = "2020-02-02T02:02:05Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15);
sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15);
// when
String sensor3 = "2020-02-02T02:02:06Z";
trackPointCreator.setClock(sensor3);
sensorManager.onChanged(new Raw<>(sensor3, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), null, Distance.of(12))));
sensorManager.onChanged(new Raw<>(sensor3, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(3), Distance.of(12))));
// when
String sensor4 = "2020-02-02T02:02:07Z";
trackPointCreator.setClock(sensor4);
sensorManager.onChanged(new Raw<>(sensor4, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), null, Distance.of(14)))); //Should be ignored
sensorManager.onChanged(new Raw<>(sensor4, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(4), Distance.of(14)))); //Should be ignored
// when
String gps2 = "2020-02-02T02:02:08Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps2, 45.0, 35.0, 4, 15); //Should be ignored
sendGPSLocation(trackPointCreator, gps2, 45.0, 35.0, 4, 15); //Should be ignored
// when
String sensor5 = "2020-02-02T02:02:10Z";
trackPointCreator.setClock(sensor5);
sensorManager.onChanged(new Raw<>(sensor5, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), null, Distance.of(16)))); //Should be ignored
sensorManager.onChanged(new Raw<>(sensor5, new BluetoothHandlerRunningSpeedAndCadence.Data(Speed.of(5), Cadence.of(5), Distance.of(16)))); //Should be ignored
// when
String gps3 = "2020-02-02T02:02:12Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps3, 45.001, 35.0, 1, 15);
sendGPSLocation(trackPointCreator, gps3, 45.001, 35.0, 1, 15);
// when
String gps4 = "2020-02-02T02:02:14Z";
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps4, 45.001, 35.0, 1, 15);
sendGPSLocation(trackPointCreator, gps4, 45.001, 35.0, 1, 15);
// when
@@ -707,58 +862,129 @@ public class TrackRecordingServiceRecordingTest {
// then
new TrackPointAssert().assertEquals(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(sensor2)) //First moving TrackPoint: store as the time might be interesting.
.setSpeed(Speed.of(5))
.setSensorDistance(Distance.of(2)),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
new TrackPoint( //First moving TrackPoint: stored as the time might be interesting.
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse(sensor2),
null, null, null,
null, null,
null,
Speed.of(5)),
Distance.of(2),
null,
null,
Cadence.of(2),
null,
null
),
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse(gps1),
45d, 35d, Distance.of(1),
null, null,
null,
Speed.of(5)))
.setSensorDistance(Distance.of(0)),
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(sensor3))
.setSpeed(Speed.of(5))
.setSensorDistance(Distance.of(10)),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
Speed.of(5)),
Distance.ZERO,
null,
null,
Cadence.of(2),
null,
null
),
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse(sensor3),
null, null, null,
null, null,
null,
Speed.of(5)),
Distance.of(10),
null,
null,
Cadence.of(3),
null,
null
),
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse(gps3),
45.001, 35d, Distance.of(1),
null, null,
null,
Speed.of(5)))
.setSensorDistance(Distance.of(4.0)),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
Speed.of(5)),
Distance.of(4.0),
null,
null,
Cadence.of(5),
null,
null
),
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse(gps4),
45.001, 35d, Distance.of(1),
null, null,
null,
Speed.of(5)))
.setSensorDistance(Distance.of(0)),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL,
Speed.of(5)),
Distance.ZERO,
null,
null,
Cadence.of(5),
null,
null
),
new TrackPoint(
null,
TrackPoint.Type.SEGMENT_END_MANUAL,
new Position(
Instant.parse(stopTime),
45.001, 35d, Distance.of(1),
null, null,
null,
Speed.of(0))) //Sensor data is now outdated, but we do not fall back to GPS.
.setSensorDistance(Distance.of(0))
Speed.ZERO), //Sensor data is now outdated, but we do not fall back to GPS.
Distance.ZERO,
null,
null,
Cadence.of(0), //TODO This could be null, right?
null,
null
)
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
private void mockAltitudeChange(TrackPointCreator trackPointCreator, float altitudeGain) {
trackPointCreator.getSensorManager().sensorDataSet.barometer = new AggregatorBarometer("", "") {
trackPointCreator.getSensorManager().sensorDataAggregator.barometer = new AggregatorBarometer("", "") {
@Override
public boolean hasReceivedData() {
return true;
}
@NonNull
@Override
public AltitudeGainLoss getAggregatedValue(Instant now) {
return new AltitudeGainLoss(altitudeGain, altitudeGain);
}
};
}
private static void sendGPSLocation(TrackPointCreator trackPointCreator, String time, double latitude, double longitude, float accuracy, long speed) {
Location location = new Location("mock");
location.setTime(1L); // Should be ignored anyhow.
location.setLatitude(latitude);
location.setLongitude(longitude);
location.setAccuracy(accuracy);
location.setSpeed(speed);
trackPointCreator.setClock(time);
trackPointCreator.getSensorManager().getGpsManager().onLocationChanged(location);
}
}
@@ -45,13 +45,13 @@ import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import de.dennisguse.opentracks.TestUtil;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.sensors.GpsStatusValue;
/**
* Testing the states of TrackRecordingService.
* As states are checked against MutableLiveData that are updated via `postValue()` (is asynchronous to be inform other Threads), Thread.sleep() is required.
*/
@RunWith(AndroidJUnit4.class)
public class TrackRecordingServiceStateMachineTest {
@@ -60,7 +60,7 @@ public class TrackRecordingServiceStateMachineTest {
public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(5, TimeUnit.SECONDS);
@Rule
public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
public GrantPermissionRule mRuntimePermissionRule = TestUtil.createGrantPermissionRule();
private final Context context = ApplicationProvider.getApplicationContext();
private ContentProviderUtils contentProviderUtils;
@@ -111,84 +111,77 @@ public class TrackRecordingServiceStateMachineTest {
// then
assertFalse(service.isRecording());
assertEquals(TrackRecordingService.STATUS_DEFAULT, service.getRecordingStatusObservable().getValue());
assertEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertEquals(RecordingData.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertEquals(GpsStatusValue.GPS_NONE, service.getGpsStatusObservable().getValue());
}
@MediumTest
@Test
public void gps_startStop() throws InterruptedException {
public void gps_startStop() {
// given
assertEquals(GpsStatusValue.GPS_NONE, service.getGpsStatusObservable().getValue());
// when
service.tryStartSensors();
Thread.sleep(1000);
// then
assertEquals(TrackRecordingService.STATUS_DEFAULT, service.getRecordingStatusObservable().getValue());
assertEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertEquals(RecordingData.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertEquals(GpsStatusValue.GPS_ENABLED, service.getGpsStatusObservable().getValue());
// when
service.stopSensors();
Thread.sleep(1000);
// then
assertEquals(TrackRecordingService.STATUS_DEFAULT, service.getRecordingStatusObservable().getValue());
assertEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertEquals(RecordingData.NOT_RECORDING, service.getRecordingDataObservable().getValue());
// assertEquals(GpsStatusValue.GPS_NONE, service.getGpsStatusObservable().getValue()); TODO BUG: GPS can only be stopped if a service is recording.
}
@MediumTest
@Test
public void recording_startStopResume_no_data() throws InterruptedException {
public void recording_startStopResume_no_data() {
// given
assertFalse(service.isRecording());
// when
Track.Id trackId = service.startNewTrack();
Thread.sleep(1000);
// then
assertTrue(service.isRecording());
assertEquals(new RecordingStatus(trackId), service.getRecordingStatusObservable().getValue());
assertNotEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertNotEquals(RecordingData.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertEquals(GpsStatusValue.GPS_ENABLED, service.getGpsStatusObservable().getValue());
service.endCurrentTrack();
// when
service.resumeTrack(trackId);
Thread.sleep(1000);
// then
assertTrue(service.isRecording());
assertEquals(new RecordingStatus(trackId), service.getRecordingStatusObservable().getValue());
assertNotEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertNotEquals(RecordingData.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertEquals(GpsStatusValue.GPS_ENABLED, service.getGpsStatusObservable().getValue());
// when
service.endCurrentTrack();
Thread.sleep(1000);
// then
assertFalse(service.isRecording());
assertEquals(TrackRecordingService.STATUS_DEFAULT, service.getRecordingStatusObservable().getValue());
assertNotEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertNotEquals(RecordingData.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertEquals(GpsStatusValue.GPS_NONE, service.getGpsStatusObservable().getValue());
// when
service.resumeTrack(trackId);
Thread.sleep(1000);
// then
assertTrue(service.isRecording());
assertEquals(new RecordingStatus(trackId), service.getRecordingStatusObservable().getValue());
Thread.sleep(1000); //TODO Figure out why we need to wait here until the update is happening
assertNotEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertNotEquals(RecordingData.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertEquals(GpsStatusValue.GPS_ENABLED, service.getGpsStatusObservable().getValue());
}
@@ -198,7 +191,7 @@ public class TrackRecordingServiceStateMachineTest {
// given
assertFalse(service.isRecording());
assertEquals(TrackRecordingService.STATUS_DEFAULT, service.getRecordingStatusObservable().getValue());
assertEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertEquals(RecordingData.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertEquals(GpsStatusValue.GPS_NONE, service.getGpsStatusObservable().getValue());
// when
@@ -207,59 +200,55 @@ public class TrackRecordingServiceStateMachineTest {
// then
assertFalse(service.isRecording());
assertEquals(TrackRecordingService.STATUS_DEFAULT, service.getRecordingStatusObservable().getValue());
assertEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertEquals(RecordingData.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertEquals(GpsStatusValue.GPS_NONE, service.getGpsStatusObservable().getValue());
}
@MediumTest
@Test
public void cannotEnd_without_starting() throws InterruptedException {
public void cannotEnd_without_starting() {
// given
assertFalse(service.isRecording());
assertEquals(TrackRecordingService.STATUS_DEFAULT, service.getRecordingStatusObservable().getValue());
assertEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertEquals(RecordingData.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertEquals(GpsStatusValue.GPS_NONE, service.getGpsStatusObservable().getValue());
// when
service.endCurrentTrack();
Thread.sleep(1000);
// then
assertEquals(TrackRecordingService.STATUS_DEFAULT, service.getRecordingStatusObservable().getValue());
assertEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertEquals(RecordingData.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertEquals(GpsStatusValue.GPS_NONE, service.getGpsStatusObservable().getValue());
}
@Ignore("TODO Bug: GPS can be stopped although the current track is recording")
@MediumTest
@Test
public void recording_stopGPS_noop() throws InterruptedException {
public void recording_stopGPS_noop() {
// given
Track.Id trackId = service.startNewTrack();
assertEquals(GpsStatusValue.GPS_ENABLED, service.getGpsStatusObservable().getValue());
// when
service.stopSensors(); //TODO Should be ignored as service is recording
Thread.sleep(1000);
// then
assertTrue(service.isRecording());
assertEquals(new RecordingStatus(trackId), service.getRecordingStatusObservable().getValue());
Thread.sleep(1000); //TODO Figure out why we need to wait here until the update is happening
assertNotEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertNotEquals(RecordingData.NOT_RECORDING, service.getRecordingDataObservable().getValue());
assertEquals(GpsStatusValue.GPS_ENABLED, service.getGpsStatusObservable().getValue());
}
@MediumTest
@Test
public void recording_startRecording_alreadyRecording() throws InterruptedException {
public void recording_startRecording_alreadyRecording() {
// given
Track.Id trackId = service.startNewTrack();
assertTrue(service.isRecording());
// when
Track.Id newTrackId = service.startNewTrack();
Thread.sleep(1000);
// then
assertNotNull(trackId);
@@ -1,20 +0,0 @@
package de.dennisguse.opentracks.services;
import android.location.Location;
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
public class TrackRecordingServiceTestUtils {
static void sendGPSLocation(TrackPointCreator trackPointCreator, String time, double latitude, double longitude, float accuracy, long speed) {
Location location = new Location("mock");
location.setTime(1L); // Should be ignored anyhow.
location.setLatitude(latitude);
location.setLongitude(longitude);
location.setAccuracy(accuracy);
location.setSpeed(speed);
trackPointCreator.setClock(time);
trackPointCreator.getSensorManager().getGpsManager().onLocationChanged(location);
}
}
@@ -21,8 +21,8 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Statistics;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.stats.TrackStatistics;
@RunWith(AndroidJUnit4.class)
public class VoiceAnnouncementManagerTest {
@@ -54,13 +54,32 @@ public class VoiceAnnouncementManagerTest {
voiceAnnouncementManager.setFrequency(Distance.ofKilometer(5));
// when
TrackStatistics statistics = new TrackStatistics();
statistics.setTotalDistance(Distance.ofKilometer(13));
voiceAnnouncementManager.start(statistics);
voiceAnnouncementManager.start(new Statistics(
null,
null,
Duration.ofSeconds(91),
Duration.ZERO,
Distance.ofKilometer(13),
null,
null,
null,
null,
null
));
assertEquals(Distance.of(15000), voiceAnnouncementManager.getNextTotalDistance());
statistics.setTotalDistance(Distance.of(15100));
voiceAnnouncementManager.start(statistics);
voiceAnnouncementManager.start(new Statistics(
null,
null,
Duration.ofSeconds(91),
Duration.ZERO,
Distance.of(15000),
null,
null,
null,
null,
null
));
assertEquals(Distance.of(20000), voiceAnnouncementManager.getNextTotalDistance());
}
@@ -73,14 +92,37 @@ public class VoiceAnnouncementManagerTest {
VoiceAnnouncementManager voiceAnnouncementManager = new VoiceAnnouncementManager(service);
voiceAnnouncementManager.setFrequency(Duration.ofSeconds(5));
Statistics first = new Statistics(
null,
null,
Duration.ofSeconds(91),
Duration.ZERO,
Distance.ZERO,
null,
null,
null,
null,
null
);
Statistics second = new Statistics(
null,
null,
Duration.ofSeconds(95),
Duration.ZERO,
Distance.ZERO,
null,
null,
null,
null,
null
);
// when
TrackStatistics statistics = new TrackStatistics();
statistics.setTotalTime(Duration.ofSeconds(91));
voiceAnnouncementManager.start(statistics);
voiceAnnouncementManager.start(first);
assertEquals(Duration.ofSeconds(95), voiceAnnouncementManager.getNextTotalTime());
statistics.setTotalTime(Duration.ofSeconds(95));
voiceAnnouncementManager.start(statistics);
voiceAnnouncementManager.start(second);
assertEquals(Duration.ofSeconds(100), voiceAnnouncementManager.getNextTotalTime());
}
@@ -1,7 +1,6 @@
package de.dennisguse.opentracks.services.announcement;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import android.content.Context;
import android.icu.text.MessageFormat;
@@ -10,33 +9,39 @@ import android.util.Pair;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SdkSuppress;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Map;
import de.dennisguse.opentracks.LocaleRule;
import de.dennisguse.opentracks.content.data.TestDataUtil;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.TrackPointIterator;
import de.dennisguse.opentracks.data.models.ActivityType;
import de.dennisguse.opentracks.data.models.AltitudeGainLoss;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.HeartRate;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Statistics;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.data.statistics.SensorStatistics;
import de.dennisguse.opentracks.sensors.sensorData.SensorData;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet;
import de.dennisguse.opentracks.settings.PreferencesUtils;
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.ui.intervals.IntervalStatisticsUpdater;
//Due to DateTimeFormatter using NBSP, these tests only work in SDK34+
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
@RunWith(AndroidJUnit4.class)
public class VoiceAnnouncementUtilsTest {
@@ -44,12 +49,9 @@ public class VoiceAnnouncementUtilsTest {
public final LocaleRule mLocaleRule = new LocaleRule(Locale.ENGLISH);
private final Context context = ApplicationProvider.getApplicationContext();
private ContentProviderUtils contentProviderUtils;
@Before
public void setUp() {
contentProviderUtils = new ContentProviderUtils(context);
PreferencesUtils.setVoiceAnnounceHeartRateCurrent(false);
PreferencesUtils.setVoiceAnnounceLapHeartRate(false);
PreferencesUtils.setVoiceAnnounceAverageHeartRate(false);
@@ -59,26 +61,38 @@ public class VoiceAnnouncementUtilsTest {
PreferencesUtils.setVoiceAnnounceLapSpeedPace(true);
}
@Test
public void sdkRequirement() {
assertFalse("Due to DateTimeFormatter using NBSP, these tests only work in SDK34+", Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
}
@Test
public void getAnnouncement_metric_speed() {
TrackStatistics stats = new TrackStatistics();
stats.setStartTime(Instant.EPOCH);
stats.setTotalDistance(Distance.of(20000));
stats.setTotalTime(Duration.ofHours(2).plusMinutes(5).plusSeconds(10));
stats.setMovingTime(Duration.ofHours(1).plusMinutes(5).plusSeconds(10));
stats.setMaxSpeed(Speed.of(100));
stats.setTotalAltitudeGain(6000f);
Track track = new Track(
null,
null,
"",
"",
"",
ActivityType.AIRPLANE,
ZoneOffset.UTC,
new Statistics(
Instant.EPOCH,
Instant.EPOCH,
Duration.ofHours(2).plusMinutes(5).plusSeconds(10),
Duration.ofHours(1).plusMinutes(5).plusSeconds(10),
Distance.of(20000),
Speed.of(100),
null,
null,
null,
null
));
Track track = new Track();
track.setTrackStatistics(stats);
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
SensorDataSet dataSet = new SensorDataSet(
null,
null,
null,
new SensorData<>(HeartRate.of(60), "unused"),
null, null,
null,
null
);
// when
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, true, null, null).toString();
@@ -89,19 +103,36 @@ public class VoiceAnnouncementUtilsTest {
@Test
public void getAnnouncement_metric_speed_rounding_check() {
TrackStatistics stats = new TrackStatistics();
stats.setStartTime(Instant.EPOCH);
stats.setTotalDistance(Distance.of(20000));
stats.setTotalTime(Duration.ofHours(1).plusMinutes(5).plusSeconds(10));
stats.setMovingTime(Duration.ofHours(1).plusSeconds(1));
stats.setMaxSpeed(Speed.of(100));
stats.setTotalAltitudeGain(6000f);
Track track = new Track(
null,
null,
"",
"",
"",
ActivityType.AIRPLANE,
ZoneOffset.UTC,
new Statistics(
Instant.EPOCH,
Instant.EPOCH,
Duration.ofHours(2).plusMinutes(5).plusSeconds(10),
Duration.ofHours(1).plusSeconds(1),
Distance.of(20000),
Speed.of(100),
null,
new AltitudeGainLoss(6000, 6000),
null,
null
));
Track track = new Track();
track.setTrackStatistics(stats);
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
SensorDataSet dataSet = new SensorDataSet(
null,
null,
null,
new SensorData<>(HeartRate.of(60), "unused"),
null, null,
null,
null
);
// when
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, true, null, null).toString();
@@ -112,19 +143,36 @@ public class VoiceAnnouncementUtilsTest {
@Test
public void getAnnouncement_metric_distance_rounding_check() {
TrackStatistics stats = new TrackStatistics();
stats.setStartTime(Instant.EPOCH);
stats.setTotalDistance(Distance.of(19999));
stats.setTotalTime(Duration.ofHours(1).plusMinutes(5).plusSeconds(10));
stats.setMovingTime(Duration.ofHours(1));
stats.setMaxSpeed(Speed.of(100));
stats.setTotalAltitudeGain(6000f);
Track track = new Track(
null,
null,
"",
"",
"",
ActivityType.AIRPLANE,
ZoneOffset.UTC,
new Statistics(
Instant.EPOCH,
Instant.EPOCH,
Duration.ofHours(2).plusMinutes(5).plusSeconds(10),
Duration.ofHours(1),
Distance.of(19999),
Speed.of(100),
null,
new AltitudeGainLoss(6000, 6000),
null,
null
));
Track track = new Track();
track.setTrackStatistics(stats);
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
SensorDataSet dataSet = new SensorDataSet(
null,
null,
null,
new SensorData<>(HeartRate.of(60), "unused"),
null, null,
null,
null
);
// when
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, true, null, null).toString();
@@ -135,19 +183,36 @@ public class VoiceAnnouncementUtilsTest {
@Test
public void getAnnouncement_metric_distance_rounding_check_two() {
TrackStatistics stats = new TrackStatistics();
stats.setStartTime(Instant.EPOCH);
stats.setTotalDistance(Distance.of(19900));
stats.setTotalTime(Duration.ofHours(1).plusMinutes(5).plusSeconds(10));
stats.setMovingTime(Duration.ofHours(1));
stats.setMaxSpeed(Speed.of(100));
stats.setTotalAltitudeGain(6000f);
Track track = new Track(
null,
null,
"",
"",
"",
ActivityType.AIRPLANE,
ZoneOffset.UTC,
new Statistics(
Instant.EPOCH,
Instant.EPOCH,
Duration.ofHours(2).plusMinutes(5).plusSeconds(10),
Duration.ofHours(1),
Distance.of(19900),
Speed.of(100),
null,
new AltitudeGainLoss(6000, 6000),
null,
null
));
Track track = new Track();
track.setTrackStatistics(stats);
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
SensorDataSet dataSet = new SensorDataSet(
null,
null,
null,
new SensorData<>(HeartRate.of(60), "unused"),
null, null,
null,
null
);
// when
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, true, null, null).toString();
@@ -159,26 +224,20 @@ public class VoiceAnnouncementUtilsTest {
@Test
public void getAnnouncement_withInterval_metric_speed() {
// given
int numberOfPoints = 1000;
Pair<Track.Id, TrackStatistics> trackWithStats = TestDataUtil.buildTrackWithTrackPoints(contentProviderUtils, numberOfPoints);
Track.Id trackId = trackWithStats.first;
TrackStatistics stats = trackWithStats.second;
IntervalStatistics.Interval lastInterval;
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
assertEquals(numberOfPoints, trackPointIterator.getCount());
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000));
intervalStatistics.addTrackPoints(trackPointIterator);
lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
}
Pair<Track, Statistics> data = buildTrackWithTrackPoints();
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
Track track = new Track();
track.setTrackStatistics(stats);
SensorDataSet dataSet = new SensorDataSet(
null,
null,
null,
new SensorData<>(HeartRate.of(60), "unused"),
null, null,
null,
null
);
// when
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, true, lastInterval, null).toString();
String announcement = VoiceAnnouncementUtils.createStatistics(context, data.first, dataSet, UnitSystem.METRIC, true, data.second, null).toString();
// then
assertEquals("12:16 AM. Total distance 14.2 kilometers. 16 minutes 39 seconds. Average moving speed 51.2 kilometers per hour. Lap speed 51.2 kilometers per hour.", announcement);
@@ -186,19 +245,36 @@ public class VoiceAnnouncementUtilsTest {
@Test
public void getAnnouncement_metric_pace() {
TrackStatistics stats = new TrackStatistics();
stats.setStartTime(Instant.EPOCH);
stats.setTotalDistance(Distance.of(20000));
stats.setTotalTime(Duration.ofHours(2).plusMinutes(5).plusSeconds(10));
stats.setMovingTime(Duration.ofHours(1).plusMinutes(5).plusSeconds(10));
stats.setMaxSpeed(Speed.of(100));
stats.setTotalAltitudeGain(6000f);
Track track = new Track(
null,
null,
"",
"",
"",
ActivityType.AIRPLANE,
ZoneOffset.UTC,
new Statistics(
Instant.EPOCH,
Instant.EPOCH,
Duration.ofHours(2).plusMinutes(5).plusSeconds(10),
Duration.ofHours(1).plusMinutes(5).plusSeconds(10),
Distance.of(20000),
Speed.of(100),
null,
new AltitudeGainLoss(6000, 6000),
null,
null
));
Track track = new Track();
track.setTrackStatistics(stats);
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
SensorDataSet dataSet = new SensorDataSet(
null,
null,
null,
new SensorData<>(HeartRate.of(60), "unused"),
null, null,
null,
null
);
// when
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, false, null, null).toString();
@@ -210,26 +286,20 @@ public class VoiceAnnouncementUtilsTest {
@Test
public void getAnnouncement_withInterval_metric_pace() {
// given
int numberOfPoints = 1000;
Pair<Track.Id, TrackStatistics> trackWithStats = TestDataUtil.buildTrackWithTrackPoints(contentProviderUtils, numberOfPoints);
Track.Id trackId = trackWithStats.first;
TrackStatistics stats = trackWithStats.second;
IntervalStatistics.Interval lastInterval;
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
assertEquals(numberOfPoints, trackPointIterator.getCount());
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000));
intervalStatistics.addTrackPoints(trackPointIterator);
lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
}
Pair<Track, Statistics> data = buildTrackWithTrackPoints();
Track track = new Track();
track.setTrackStatistics(stats);
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
SensorDataSet dataSet = new SensorDataSet(
null,
null,
null,
new SensorData<>(HeartRate.of(60), "unused"),
null, null,
null,
null
);
// when
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, false, lastInterval, null).toString();
String announcement = VoiceAnnouncementUtils.createStatistics(context, data.first, dataSet, UnitSystem.METRIC, false, data.second, null).toString();
// then
assertEquals("12:16 AM. Total distance 14.2 kilometers. 16 minutes 39 seconds. Pace 1 minute 10 seconds per kilometer. Lap time 1 minute 10 seconds per kilometer.", announcement);
@@ -237,19 +307,36 @@ public class VoiceAnnouncementUtilsTest {
@Test
public void getAnnouncement_imperial_speed() {
TrackStatistics stats = new TrackStatistics();
stats.setStartTime(Instant.EPOCH);
stats.setTotalDistance(Distance.of(20000));
stats.setTotalTime(Duration.ofHours(2).plusMinutes(5).plusSeconds(10));
stats.setMovingTime(Duration.ofHours(1).plusMinutes(5).plusSeconds(10));
stats.setMaxSpeed(Speed.of(100));
stats.setTotalAltitudeGain(6000f);
Track track = new Track(
null,
null,
"",
"",
"",
ActivityType.AIRPLANE,
ZoneOffset.UTC,
new Statistics(
Instant.EPOCH,
Instant.EPOCH,
Duration.ofHours(2).plusMinutes(5).plusSeconds(10),
Duration.ofHours(1).plusMinutes(5).plusSeconds(10),
Distance.of(20000),
Speed.of(100),
null,
new AltitudeGainLoss(6000, 6000),
null,
null
));
Track track = new Track();
track.setTrackStatistics(stats);
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
SensorDataSet dataSet = new SensorDataSet(
null,
null,
null,
new SensorData<>(HeartRate.of(60), "unused"),
null, null,
null,
null
);
// when
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.IMPERIAL_FEET, true, null, null).toString();
@@ -260,17 +347,36 @@ public class VoiceAnnouncementUtilsTest {
@Test
public void getAnnouncement_imperial_speed_1() {
TrackStatistics stats = new TrackStatistics();
stats.setStartTime(Instant.EPOCH);
stats.setTotalDistance(Distance.ofMile(1.1));
stats.setTotalTime(Duration.ofHours(2).plusMinutes(5).plusSeconds(10));
stats.setMovingTime(Duration.ofHours(1));
Track track = new Track(
null,
null,
"",
"",
"",
ActivityType.AIRPLANE,
ZoneOffset.UTC,
new Statistics(
Instant.EPOCH,
Instant.EPOCH,
Duration.ofHours(2).plusMinutes(5).plusSeconds(10),
Duration.ofHours(1),
Distance.ofMile(1.1),
null,
null,
null,
null,
null
));
Track track = new Track();
track.setTrackStatistics(stats);
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
SensorDataSet dataSet = new SensorDataSet(
null,
null,
null,
new SensorData<>(HeartRate.of(60), "unused"),
null, null,
null,
null
);
// when
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.IMPERIAL_FEET, true, null, null).toString();
@@ -281,17 +387,36 @@ public class VoiceAnnouncementUtilsTest {
@Test
public void getAnnouncement_imperial_meter_speed_1() {
TrackStatistics stats = new TrackStatistics();
stats.setStartTime(Instant.EPOCH);
stats.setTotalDistance(Distance.ofMile(1.1));
stats.setTotalTime(Duration.ofHours(2).plusMinutes(5).plusSeconds(10));
stats.setMovingTime(Duration.ofHours(1));
Track track = new Track(
null,
null,
"",
"",
"",
ActivityType.AIRPLANE,
ZoneOffset.UTC,
new Statistics(
Instant.EPOCH,
Instant.EPOCH,
Duration.ofHours(2).plusMinutes(5).plusSeconds(10),
Duration.ofHours(1),
Distance.ofMile(1.1),
null,
null,
null,
null,
null
));
Track track = new Track();
track.setTrackStatistics(stats);
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
SensorDataSet dataSet = new SensorDataSet(
null,
null,
null,
new SensorData<>(HeartRate.of(60), "unused"),
null, null,
null,
null
);
// when
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.IMPERIAL_METER, true, null, null).toString();
@@ -302,17 +427,36 @@ public class VoiceAnnouncementUtilsTest {
@Test
public void getAnnouncement_metric_speed_1() {
TrackStatistics stats = new TrackStatistics();
stats.setStartTime(Instant.EPOCH);
stats.setTotalDistance(Distance.ofKilometer(1.1));
stats.setTotalTime(Duration.ofHours(2).plusMinutes(5).plusSeconds(10));
stats.setMovingTime(Duration.ofHours(1));
Track track = new Track(
null,
null,
"",
"",
"",
ActivityType.AIRPLANE,
ZoneOffset.UTC,
new Statistics(
Instant.EPOCH,
Instant.EPOCH,
Duration.ofHours(2).plusMinutes(5).plusSeconds(10),
Duration.ofHours(1),
Distance.ofKilometer(1.1),
null,
null,
null,
null,
null
));
Track track = new Track();
track.setTrackStatistics(stats);
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
SensorDataSet dataSet = new SensorDataSet(
null,
null,
null,
new SensorData<>(HeartRate.of(60), "unused"),
null, null,
null,
null
);
// when
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, true, null, null).toString();
@@ -324,26 +468,20 @@ public class VoiceAnnouncementUtilsTest {
@Test
public void getAnnouncement_withInterval_imperial_speed() {
// given
int numberOfPoints = 1000;
Pair<Track.Id, TrackStatistics> trackWithStats = TestDataUtil.buildTrackWithTrackPoints(contentProviderUtils, numberOfPoints);
Track.Id trackId = trackWithStats.first;
TrackStatistics stats = trackWithStats.second;
IntervalStatistics.Interval lastInterval;
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
assertEquals(numberOfPoints, trackPointIterator.getCount());
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000));
intervalStatistics.addTrackPoints(trackPointIterator);
lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
}
Pair<Track, Statistics> data = buildTrackWithTrackPoints();
Track track = new Track();
track.setTrackStatistics(stats);
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
SensorDataSet dataSet = new SensorDataSet(
null,
null,
null,
new SensorData<>(HeartRate.of(60), "unused"),
null, null,
null,
null
);
// when
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.IMPERIAL_FEET, true, lastInterval, null).toString();
String announcement = VoiceAnnouncementUtils.createStatistics(context, data.first, dataSet, UnitSystem.IMPERIAL_FEET, true, data.second, null).toString();
// then
assertEquals("12:16 AM. Total distance 8.8 miles. 16 minutes 39 seconds. Average moving speed 31.8 miles per hour. Lap speed 31.8 miles per hour.", announcement);
@@ -351,19 +489,36 @@ public class VoiceAnnouncementUtilsTest {
@Test
public void getAnnouncement_imperial_pace() {
TrackStatistics stats = new TrackStatistics();
stats.setStartTime(Instant.EPOCH);
stats.setTotalDistance(Distance.of(20000));
stats.setTotalTime(Duration.ofHours(2).plusMinutes(5).plusSeconds(10));
stats.setMovingTime(Duration.ofHours(1).plusMinutes(5).plusSeconds(10));
stats.setMaxSpeed(Speed.of(100));
stats.setTotalAltitudeGain(6000f);
Track track = new Track(
null,
null,
"",
"",
"",
ActivityType.AIRPLANE,
ZoneOffset.UTC,
new Statistics(
Instant.EPOCH,
Instant.EPOCH,
Duration.ofHours(2).plusMinutes(5).plusSeconds(10),
Duration.ofHours(1).plusMinutes(5).plusSeconds(10),
Distance.of(20000),
Speed.of(100),
null,
new AltitudeGainLoss(6000, 6000),
null,
null
));
Track track = new Track();
track.setTrackStatistics(stats);
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
SensorDataSet dataSet = new SensorDataSet(
null,
null,
null,
new SensorData<>(HeartRate.of(60), "unused"),
null, null,
null,
null
);
// when
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.IMPERIAL_FEET, false, null, null).toString();
@@ -375,26 +530,20 @@ public class VoiceAnnouncementUtilsTest {
@Test
public void getAnnouncement_withInterval_imperial_pace() {
// given
int numberOfPoints = 1000;
Pair<Track.Id, TrackStatistics> trackWithStats = TestDataUtil.buildTrackWithTrackPoints(contentProviderUtils, numberOfPoints);
Track.Id trackId = trackWithStats.first;
TrackStatistics stats = trackWithStats.second;
IntervalStatistics.Interval lastInterval;
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
assertEquals(numberOfPoints, trackPointIterator.getCount());
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000));
intervalStatistics.addTrackPoints(trackPointIterator);
lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
}
Pair<Track, Statistics> data = buildTrackWithTrackPoints();
Track track = new Track();
track.setTrackStatistics(stats);
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
SensorDataSet dataSet = new SensorDataSet(
null,
null,
null,
new SensorData<>(HeartRate.of(60), "unused"),
null, null,
null,
null
);
// when
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.IMPERIAL_FEET, false, lastInterval, null).toString();
String announcement = VoiceAnnouncementUtils.createStatistics(context, data.first, dataSet, UnitSystem.IMPERIAL_FEET, false, data.second, null).toString();
// then
assertEquals("12:16 AM. Total distance 8.8 miles. 16 minutes 39 seconds. Pace 1 minute 53 seconds per mile. Lap time 1 minute 53 seconds per mile.", announcement);
@@ -402,31 +551,26 @@ public class VoiceAnnouncementUtilsTest {
@Test
public void getAnnouncement_heart_rate_and_sensor_statistics() {
// given
PreferencesUtils.setVoiceAnnounceAverageHeartRate(true);
PreferencesUtils.setVoiceAnnounceLapHeartRate(true);
int numberOfPoints = 1000;
Pair<Track.Id, TrackStatistics> trackWithStats = TestDataUtil.buildTrackWithTrackPoints(contentProviderUtils, numberOfPoints);
Track.Id trackId = trackWithStats.first;
TrackStatistics stats = trackWithStats.second;
IntervalStatistics.Interval lastInterval;
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
assertEquals(numberOfPoints, trackPointIterator.getCount());
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000));
intervalStatistics.addTrackPoints(trackPointIterator);
lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
}
Pair<Track, Statistics> data = buildTrackWithTrackPoints();
SensorStatistics sensorStatistics = new SensorStatistics(HeartRate.of(180f), HeartRate.of(180f), null, null, null, null);
Track track = new Track();
track.setTrackStatistics(stats);
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
SensorDataSet dataSet = new SensorDataSet(
null,
null,
null,
new SensorData<>(HeartRate.of(60), "unused"),
null, null,
null,
null
);
// when
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, true, lastInterval, sensorStatistics).toString();
String announcement = VoiceAnnouncementUtils.createStatistics(context, data.first, dataSet, UnitSystem.METRIC, true, data.second, sensorStatistics).toString();
// then
assertEquals("12:16 AM. Total distance 14.2 kilometers. 16 minutes 39 seconds. Average moving speed 51.2 kilometers per hour. Lap speed 51.2 kilometers per hour. Average heart rate 180 bpm. Lap heart rate 133 bpm.", announcement);
@@ -434,6 +578,7 @@ public class VoiceAnnouncementUtilsTest {
@Test
public void getAnnouncement_heart_rate() {
// given
PreferencesUtils.setVoiceAnnounceHeartRateCurrent(true);
PreferencesUtils.setVoiceAnnounceLapHeartRate(true);
PreferencesUtils.setVoiceAnnounceAverageHeartRate(true);
@@ -443,28 +588,22 @@ public class VoiceAnnouncementUtilsTest {
PreferencesUtils.setVoiceAnnounceAverageSpeedPace(false);
PreferencesUtils.setVoiceAnnounceLapSpeedPace(false);
int numberOfPoints = 1000;
Pair<Track.Id, TrackStatistics> trackWithStats = TestDataUtil.buildTrackWithTrackPoints(contentProviderUtils, numberOfPoints);
Track.Id trackId = trackWithStats.first;
TrackStatistics stats = trackWithStats.second;
IntervalStatistics.Interval lastInterval;
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
assertEquals(numberOfPoints, trackPointIterator.getCount());
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000));
intervalStatistics.addTrackPoints(trackPointIterator);
lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
}
Pair<Track, Statistics> data = buildTrackWithTrackPoints();
SensorStatistics sensorStatistics = new SensorStatistics(HeartRate.of(180f), HeartRate.of(180f), null, null, null, null);
Track track = new Track();
track.setTrackStatistics(stats);
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
SensorDataSet dataSet = new SensorDataSet(
null,
null,
null,
new SensorData<>(HeartRate.of(60), "unused"),
null, null,
null,
null
);
// when
String announcement = VoiceAnnouncementUtils.createStatistics(context, track, dataSet, UnitSystem.METRIC, true, lastInterval, sensorStatistics).toString();
String announcement = VoiceAnnouncementUtils.createStatistics(context, data.first, dataSet, UnitSystem.METRIC, true, data.second, sensorStatistics).toString();
// then
assertEquals("12:16 AM. Current heart rate 60 bpm. Average heart rate 180 bpm. Lap heart rate 133 bpm.", announcement);
@@ -484,4 +623,40 @@ public class VoiceAnnouncementUtilsTest {
assertEquals("1.1 miles", MessageFormat.format(template, Map.of("n", 1.11)));
assertEquals("1.2 miles", MessageFormat.format(template, Map.of("n", 1.18)));
}
private static Pair<Track, Statistics> buildTrackWithTrackPoints() {
int numberOfPoints = 1000;
ArrayList<TrackPoint> trackPoints = new ArrayList<>();
for (int i = 0; i < numberOfPoints; i++) {
trackPoints.add(TestDataUtil.createTrackPoint(i));
}
IntervalStatisticsUpdater intervalStatistics = new IntervalStatisticsUpdater(Distance.of(1000));
intervalStatistics.addTrackPoints(trackPoints.iterator());
Statistics lastInterval = intervalStatistics.getLastInterval();
Track track = new Track(
null,
null,
"",
"",
"",
ActivityType.AIRPLANE,
ZoneOffset.UTC,
new Statistics(
Instant.EPOCH,
Instant.EPOCH.plusSeconds(999),
Duration.ofMinutes(16).plusSeconds(39),
Duration.ofMinutes(16).plusSeconds(39),
Distance.of(14208),
Speed.of(104),
null,
null,
null,
null
));
return new Pair<>(track, lastInterval);
}
}
@@ -60,8 +60,7 @@ public class PreferencesOpenHelperTest {
// when update to version 2
PreferencesOpenHelper.newInstance(2).check();
String updatedOldCustomLayoutCsv = context.getString(R.string.activity_type_unknown) + ";"
+ PreferencesUtils.getLayoutColumnsByDefault() + ";distance,1,1,0;speed,1,1,0;";
String updatedOldCustomLayoutCsv = context.getString(R.string.activity_type_unknown) + ";2;distance,1,1,0;speed,1,1,0;";
// then there should be one layout with old custom layout that has the new CSV value.
List<RecordingLayout> recordingLayouts = PreferencesUtils.getAllCustomLayouts();
@@ -110,7 +109,7 @@ public class PreferencesOpenHelperTest {
PreferencesOpenHelper.newInstance(1).check();
// then custom layout should be equals to default layout.
RecordingLayout defaultRecordingLayout = RecordingLayoutIO.fromCsv(PreferencesUtils.buildDefaultLayout(), resources);
RecordingLayout defaultRecordingLayout = RecordingLayoutIO.fromCsvLine(PreferencesUtils.buildDefaultLayout(), resources);
List<RecordingLayout> customRecordingLayout = PreferencesUtils.getAllCustomLayouts();
assertEquals(1, customRecordingLayout.size());
@@ -210,7 +210,7 @@ public class PreferencesUtilsTest {
String csv = sharedPreferences.getString(context.getString(R.string.stats_custom_layouts_key), null);
assertNotNull(csv);
assertEquals(csv,
"road cycling;" + PreferencesUtils.getLayoutColumnsByDefault() + ";"
"road cycling;2;"
+ context.getString(R.string.stats_custom_layout_moving_time_key) + ",1,1,0;"
+ context.getString(R.string.stats_custom_layout_distance_key) + ",1,0,0;"
+ context.getString(R.string.stats_custom_layout_average_moving_speed_key) + ",0,1,0;"
@@ -258,8 +258,8 @@ public class PreferencesUtilsTest {
+ context.getString(R.string.stats_custom_layout_speed_key) + ",0,0;";
List<RecordingLayout> layoutsToBeUpdated = new ArrayList<>();
layoutsToBeUpdated.add(RecordingLayoutIO.fromCsv(cyclingProfileUpdated, resources));
layoutsToBeUpdated.add(RecordingLayoutIO.fromCsv(runningProfile, resources));
layoutsToBeUpdated.add(RecordingLayoutIO.fromCsvLine(cyclingProfileUpdated, resources));
layoutsToBeUpdated.add(RecordingLayoutIO.fromCsvLine(runningProfile, resources));
PreferencesUtils.updateCustomLayouts(layoutsToBeUpdated);
@@ -303,7 +303,7 @@ public class PreferencesUtilsTest {
+ context.getString(R.string.stats_custom_layout_distance_key) + ",0,0;"
+ context.getString(R.string.stats_custom_layout_average_moving_speed_key) + ",0,0;"
+ context.getString(R.string.stats_custom_layout_speed_key) + ",0,0;";
RecordingLayout recordingLayoutToBeUpdated = RecordingLayoutIO.fromCsv(cyclingProfileUpdated, resources);
RecordingLayout recordingLayoutToBeUpdated = RecordingLayoutIO.fromCsvLine(cyclingProfileUpdated, resources);
PreferencesUtils.updateCustomLayout(recordingLayoutToBeUpdated);
// then only updated profile is modified in the custom layouts
@@ -18,8 +18,6 @@ package de.dennisguse.opentracks.share;
import static org.junit.Assert.assertEquals;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -32,14 +30,17 @@ import java.time.Duration;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Locale;
import de.dennisguse.opentracks.LocaleRule;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.data.models.AltitudeExtremities;
import de.dennisguse.opentracks.data.models.AltitudeGainLoss;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Statistics;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.util.StringUtils;
/**
@@ -56,8 +57,6 @@ public class TrackShareSummaryGeneratorTest {
private static final Instant START_TIME = Instant.ofEpochMilli(1288721514000L);
private TrackShareSummaryGenerator descriptionGenerator;
private final Context context = ApplicationProvider.getApplicationContext();
@Before
public void setUp() {
descriptionGenerator = new TrackShareSummaryGenerator(ApplicationProvider.getApplicationContext());
@@ -65,19 +64,27 @@ public class TrackShareSummaryGeneratorTest {
@Test
public void testGenerateTrackDescription() {
Track track = new Track();
TrackStatistics stats = new TrackStatistics();
stats.setTotalDistance(Distance.of(20000));
stats.setTotalTime(Duration.ofMillis(600000));
stats.setMovingTime(Duration.ofMillis(300000));
stats.setMaxSpeed(Speed.of(100));
stats.setMaxAltitude(550);
stats.setMinAltitude(-500);
stats.setTotalAltitudeGain(6000f);
stats.setTotalAltitudeLoss(6000f);
stats.setStartTime(START_TIME);
track.setTrackStatistics(stats);
track.setActivityTypeLocalized("hiking");
Track track = new Track(
null,
null,
"",
"",
"hiking",
null,
ZoneOffset.UTC,
new Statistics(
START_TIME,
START_TIME,
Duration.ofSeconds(600),
Duration.ofSeconds(300),
Distance.of(20000),
Speed.of(100),
new AltitudeExtremities(-500, 550),
new AltitudeGainLoss(6000, 6000),
null,
null
));
String expected = //"Created by"
"OpenTracks (Debug)\n\n"
+ "Name: -\n"
@@ -1,128 +0,0 @@
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* 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.
*/
package de.dennisguse.opentracks.stats;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.time.Duration;
import java.time.Instant;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.HeartRate;
import de.dennisguse.opentracks.data.models.Speed;
/**
* Tests for {@link TrackStatistics}.
* This only tests non-trivial pieces of that class.
*
* @author Rodrigo Damazio
*/
@RunWith(AndroidJUnit4.class)
public class TrackStatisticsTest {
private TrackStatistics statistics;
@Before
public void setUp() {
statistics = new TrackStatistics();
}
@Test
public void testMerge_no_data() {
// given
TrackStatistics statistics2 = new TrackStatistics();
// when
statistics.merge(statistics2);
// then
assertNull(statistics.getStartTime());
assertNull(statistics.getStopTime());
assertEquals(Duration.ofSeconds(0), statistics.getMovingTime());
assertEquals(Duration.ofSeconds(0), statistics.getTotalTime());
assertNull(statistics.getTotalAltitudeGain());
assertNull(statistics.getTotalAltitudeLoss());
assertEquals(Double.NEGATIVE_INFINITY, statistics.getMaxAltitude(), 0.0);
assertEquals(Double.POSITIVE_INFINITY, statistics.getMinAltitude(), 0.0);
assertEquals(0.0, statistics.getMaxSpeed().toMPS(), 0.0);
assertEquals(0.0, statistics.getAverageSpeed().toMPS(), 0.0);
assertEquals(0.0, statistics.getAverageMovingSpeed().toMPS(), 0.0);
assertNull(statistics.getAverageHeartRate());
}
@Test
public void testMerge() {
// given
TrackStatistics statistics2 = new TrackStatistics();
statistics.setStartTime(Instant.ofEpochMilli(1000)); // Resulting start time
statistics.setStopTime(Instant.ofEpochMilli(2500));
statistics2.setStartTime(Instant.ofEpochMilli(3000));
statistics2.setStopTime(Instant.ofEpochMilli(4000)); // Resulting stop time
statistics.setTotalTime(Duration.ofMillis(1500));
statistics2.setTotalTime(Duration.ofMillis(1000)); // Result: 1500+1000
statistics.setMovingTime(Duration.ofMillis(700));
statistics2.setMovingTime(Duration.ofMillis(600)); // Result: 700+600
statistics.setTotalDistance(Distance.of(750.0));
statistics2.setTotalDistance(Distance.of(350.0)); // Result: 750+350
statistics.setTotalAltitudeGain(50.0f);
statistics2.setTotalAltitudeGain(850.0f); // Result: 850+50
statistics.setMaxSpeed(Speed.of(60.0)); // Resulting max speed
statistics2.setMaxSpeed(Speed.of(30.0));
statistics.setMaxAltitude(1250.0);
statistics.setMinAltitude(1200.0); // Resulting min altitude
statistics2.setMaxAltitude(3575.0); // Resulting max altitude
statistics2.setMinAltitude(2800.0);
statistics.setAverageHeartRate(HeartRate.of(100f));
statistics2.setAverageHeartRate(HeartRate.of(200f));
// when
statistics.merge(statistics2);
// then
assertEquals(Instant.ofEpochMilli(1000), statistics.getStartTime());
assertEquals(Instant.ofEpochMilli(4000), statistics.getStopTime());
assertEquals(Duration.ofMillis(2500), statistics.getTotalTime());
assertEquals(Duration.ofMillis(1300), statistics.getMovingTime());
assertEquals(1100.0, statistics.getTotalDistance().toM(), 0.001);
assertEquals(900.0, statistics.getTotalAltitudeGain(), 0.001);
assertEquals(Speed.of(statistics.getTotalDistance(), statistics.getMovingTime()).toMPS(), statistics.getMaxSpeed().toMPS(), 0.001);
assertEquals(1200.0, statistics.getMinAltitude(), 0.001);
assertEquals(3575.0, statistics.getMaxAltitude(), 0.001);
assertEquals(150.0, statistics.getAverageHeartRate().getBPM(), 0.001);
}
@Test
public void testGetAverageSpeed() {
statistics.setTotalDistance(Distance.of(1000.0));
statistics.setTotalTime(Duration.ofMillis(50000));
assertEquals(20.0, statistics.getAverageSpeed().toMPS(), 0.001);
}
@Test
public void testGetAverageMovingSpeed() {
statistics.setTotalDistance(Distance.of(1000.0));
statistics.setMovingTime(Duration.ofMillis(20000));
assertEquals(50.0, statistics.getAverageMovingSpeed().toMPS(), 0.001);
}
}
@@ -2,7 +2,6 @@ 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;
@@ -16,36 +15,21 @@ import java.util.List;
import de.dennisguse.opentracks.content.data.TestDataUtil;
import de.dennisguse.opentracks.data.models.Altitude;
import de.dennisguse.opentracks.data.models.AltitudeExtremities;
import de.dennisguse.opentracks.data.models.AltitudeGainLoss;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.HeartRate;
import de.dennisguse.opentracks.data.models.Position;
import de.dennisguse.opentracks.data.models.Power;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Statistics;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.data.statistics.TrackStatisticsUpdater;
@RunWith(AndroidJUnit4.class)
public class TrackStatisticsUpdaterTest {
@Test
public void empty() {
// when
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
// then
TrackStatistics statistics = subject.getTrackStatistics();
assertNull(statistics.getStartTime());
assertNull(statistics.getStopTime());
assertEquals(Duration.ZERO, statistics.getTotalTime());
assertEquals(Duration.ZERO, statistics.getMovingTime());
assertEquals(Speed.of(0), statistics.getAverageSpeed());
assertEquals(Speed.of(0), statistics.getAverageMovingSpeed());
assertEquals(Speed.of(0), statistics.getMaxSpeed());
assertNull(statistics.getTotalAltitudeGain());
assertNull(statistics.getTotalAltitudeLoss());
assertNull(statistics.getAverageHeartRate());
}
@Test
public void startTime() {
// given
@@ -53,24 +37,24 @@ public class TrackStatisticsUpdaterTest {
TrackPoint tp = new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, startTime);
// when
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
subject.addTrackPoint(tp);
TrackStatisticsUpdater subject = new TrackStatisticsUpdater(tp);
// then
TrackStatistics statistics = subject.getTrackStatistics();
assertEquals(startTime, statistics.getStartTime());
assertEquals(startTime, statistics.getStopTime());
assertEquals(Duration.ZERO, statistics.getTotalTime());
assertEquals(Duration.ZERO, statistics.getMovingTime());
assertEquals(Speed.of(0), statistics.getAverageSpeed());
assertEquals(Speed.of(0), statistics.getAverageMovingSpeed());
assertEquals(Speed.of(0), statistics.getMaxSpeed());
assertNull(statistics.getTotalAltitudeGain());
assertNull(statistics.getTotalAltitudeLoss());
assertNull(statistics.getAverageHeartRate());
assertEquals(
new Statistics(
startTime,
startTime,
Duration.ZERO,
Duration.ZERO,
Distance.ZERO,
Speed.ZERO,
null,
null,
null,
null
),
subject.getTrackStatistics()
);
}
@Test
@@ -79,154 +63,149 @@ public class TrackStatisticsUpdaterTest {
TestDataUtil.TrackData data = TestDataUtil.createTestingTrack(new Track.Id(1));
// when
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
data.trackPoints().forEach(subject::addTrackPoint);
TrackStatisticsUpdater subject = new TrackStatisticsUpdater(data.trackPoints());
// then
TrackStatistics statistics = subject.getTrackStatistics();
assertEquals(142.26, statistics.getTotalDistance().toM(), 0.01);
assertEquals(Duration.ofSeconds(12), statistics.getTotalTime());
assertEquals(Duration.ofSeconds(12), statistics.getMovingTime());
assertEquals(2.5, statistics.getMinAltitude(), 0.01);
assertEquals(32.5, statistics.getMaxAltitude(), 0.01);
assertEquals(36, statistics.getTotalAltitudeGain(), 0.01);
assertEquals(36, statistics.getTotalAltitudeLoss(), 0.01);
assertEquals(11.85, statistics.getMaxSpeed().toMPS(), 0.01);
assertEquals(11.85, statistics.getAverageMovingSpeed().toMPS(), 0.01);
assertEquals(11.85, statistics.getAverageSpeed().toMPS(), 0.01);
assertEquals(106.834f, statistics.getAverageHeartRate().getBPM(), 0.01);
Statistics result = subject.getTrackStatistics();
assertEquals(
new Statistics(
Instant.EPOCH,
Instant.EPOCH.plusSeconds(13),
Duration.ofSeconds(12),
Duration.ofSeconds(12),
Distance.of(142.2637701034546),
Speed.of(12.448093056678772),
new AltitudeExtremities(2.5, 32.5),
new AltitudeGainLoss(36, 36),
HeartRate.of(106.833336f),
Power.of(405.2778f)
),
result
);
}
@Test
public void addTrackPoint_distance_from_GPS_moving() {
// given
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
TrackPoint tp1 = new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochMilli(1000));
TrackPoint tp2 = createTrackPoint(0, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(2000));
TrackPoint tp3 = createTrackPoint(0.00001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000));
tp3.setSpeed(Speed.of(5f));
TrackPoint tp3 = createTrackPoint(0.00001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000), Speed.of(5f), null);
// when
subject.addTrackPoint(tp1);
subject.addTrackPoint(tp2);
subject.addTrackPoint(tp3);
TrackStatisticsUpdater subject = new TrackStatisticsUpdater(List.of(tp1, tp2, tp3));
// then
assertEquals(1.10, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
assertEquals(Distance.of(1.1057428121566772), subject.getTrackStatistics().totalDistance());
}
@Test
public void addTrackPoint_distance_from_GPS_moving_and_sensor_moving() {
// given
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
TrackPoint tp1 = new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochMilli(1000));
TrackPoint tp2 = createTrackPoint(0, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(2000));
tp2.setSpeed(Speed.of(5f));
TrackPoint tp3 = createTrackPoint(0.001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000));
tp3.setSpeed(Speed.of(5f));
TrackPoint tp4 = createTrackPoint(0.001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(4000));
tp4.setSpeed(Speed.of(5f));
tp4.setSensorDistance(Distance.of(5f));
TrackPoint tp5 = new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochMilli(5000));
tp5.setSensorDistance(Distance.of(10f));
TrackPoint tp2 = createTrackPoint(0, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(2000), Speed.of(5f), null);
TrackPoint tp3 = createTrackPoint(0.001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000), Speed.of(5f), null);
TrackPoint tp4 = createTrackPoint(0.001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(4000), Speed.of(5f), Distance.of(5));
TrackPoint tp5 = new TrackPoint(null,
TrackPoint.Type.SEGMENT_END_MANUAL,
Position.of(Instant.ofEpochMilli(5000)),
Distance.of(10f),
null,
null,
null,
null,
null);
// when
subject.addTrackPoint(tp1);
subject.addTrackPoint(tp2);
subject.addTrackPoint(tp3);
TrackStatisticsUpdater subject = new TrackStatisticsUpdater(List.of(tp1, tp2, tp3));
// then
assertEquals(110.57, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
assertEquals(Distance.of(110.57427215576172), subject.getTrackStatistics().totalDistance());
// when
subject.addTrackPoint(tp4);
subject.addTrackPoint(tp5);
// then
assertEquals(125.57, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
assertEquals(Distance.of(125.57427215576172), subject.getTrackStatistics().totalDistance());
}
@Test
public void addTrackPoint_distance_from_GPS_moving_and_sensor_disconnecting() {
// given
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
TrackPoint tp1 = new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochMilli(1000));
TrackPoint tp2 = createTrackPoint(0, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(2000));
tp2.setSpeed(Speed.of(5f));
TrackPoint tp3 = createTrackPoint(0.00001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000));
tp3.setSensorDistance(Distance.of(5f));
tp3.setSpeed(Speed.of(5f));
TrackPoint tp4 = createTrackPoint(0.0005, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(4000));
tp4.setSpeed(Speed.of(5f));
TrackPoint tp2 = createTrackPoint(0, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(2000), Speed.of(5f), null);
TrackPoint tp3 = createTrackPoint(0.00001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000), Speed.of(5f), Distance.of(5));
TrackPoint tp4 = createTrackPoint(0.0005, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(4000), Speed.of(5f), null);
TrackPoint tp5 = new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochMilli(5000));
// when
subject.addTrackPoint(tp1);
subject.addTrackPoint(tp2);
subject.addTrackPoint(tp3);
TrackStatisticsUpdater subject = new TrackStatisticsUpdater(List.of(tp1, tp2, tp3));
// then
assertEquals(5, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
assertEquals(Distance.of(5), subject.getTrackStatistics().totalDistance());
// when
subject.addTrackPoint(tp4);
subject.addTrackPoint(tp5);
// then
assertEquals(59.18, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
assertEquals(Distance.of(59.181396484375), subject.getTrackStatistics().totalDistance());
}
@Test
public void addTrackPoint_maxSpeed_multiple_segments() {
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
assertEquals(Speed.of(0f), subject.getTrackStatistics().getMaxSpeed());
subject.addTrackPoints(List.of(
TrackStatisticsUpdater subject = new TrackStatisticsUpdater(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochSecond(0)),
createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(1))
.setSpeed(Speed.of(2f)),
createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(2))
.setSpeed(Speed.of(2f)),
createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(1), Speed.of(2), null),
createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(2), Speed.of(2), null),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochSecond(4))
));
assertEquals(Speed.of(2f), subject.getTrackStatistics().getMaxSpeed());
assertEquals(Speed.of(2), subject.getTrackStatistics().maxSpeed());
// when
subject.addTrackPoints(List.of(
List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochSecond(5)),
createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(6))
.setSpeed(Speed.of(1f)),
createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(7))
.setSpeed(Speed.of(1f)),
createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(6), Speed.of(1), null),
createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(7), Speed.of(1), null),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochSecond(8))
));
).forEach(subject::addTrackPoint);
// then
assertEquals(Speed.of(2f), subject.getTrackStatistics().getMaxSpeed());
assertEquals(Speed.of(2f), subject.getTrackStatistics().maxSpeed());
}
@Test
public void addTrackPoint_idle_withoutDistance() {
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
// when
subject.addTrackPoints(List.of(
TrackStatisticsUpdater subject = new TrackStatisticsUpdater(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochSecond(0)),
createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(1))
.setSpeed(Speed.of(2f)),
createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(2))
.setSpeed(Speed.of(2f)),
createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(1), Speed.of(2), null),
createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(2), Speed.of(2), null),
new TrackPoint(TrackPoint.Type.IDLE, Instant.ofEpochSecond(30)),
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochSecond(40))
.setHeartRate(50),
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochSecond(45))
.setHeartRate(50),
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
Position.of(Instant.ofEpochSecond(40)),
null,
HeartRate.of(50),
null,
null,
null,
null
),
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
Position.of(Instant.ofEpochSecond(45)),
null,
HeartRate.of(50),
null,
null,
null,
null
),
createTrackPoint(0, 1, Altitude.WGS84.of(0), Instant.ofEpochSecond(50)),
createTrackPoint(0, 2, Altitude.WGS84.of(0), Instant.ofEpochSecond(55)),
@@ -234,128 +213,195 @@ public class TrackStatisticsUpdaterTest {
));
// then
assertEquals(Duration.ofSeconds(35), subject.getTrackStatistics().getMovingTime());
assertEquals(Duration.ofSeconds(35), subject.getTrackStatistics().movingDuration());
}
@Test
public void addTrackPoint_idle_withDistance() {
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
// when
subject.addTrackPoints(List.of(
TrackStatisticsUpdater subject = new TrackStatisticsUpdater(List.of(
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochSecond(0)),
createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(1))
.setSensorDistance(Distance.of(10)),
createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(2))
.setSensorDistance(Distance.of(10)),
new TrackPoint(TrackPoint.Type.IDLE, Instant.ofEpochSecond(30))
.setSensorDistance(Distance.ofKilometer(1)),
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochSecond(40))
.setHeartRate(50),
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochSecond(45))
.setHeartRate(50),
createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(50))
.setSensorDistance(Distance.of(10)),
createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(55))
.setSensorDistance(Distance.of(10)),
createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(1), null, Distance.of(10)),
createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(2), null, Distance.of(10)),
new TrackPoint(
null,
TrackPoint.Type.IDLE,
Position.of(Instant.ofEpochSecond(30)),
Distance.ofKilometer(1),
null,
null,
null,
null,
null
),
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
Position.of(Instant.ofEpochSecond(40)),
null,
HeartRate.of(50),
null,
null,
null,
null
),
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
Position.of(Instant.ofEpochSecond(45)),
null,
HeartRate.of(50),
null,
null,
null,
null
),
createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(50), null, Distance.of(10)),
createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(55), null, Distance.of(10)),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochSecond(60))
));
// then
assertEquals(Duration.ofSeconds(40), subject.getTrackStatistics().getMovingTime());
assertEquals(Distance.of(1040), subject.getTrackStatistics().getTotalDistance());
assertEquals(Duration.ofSeconds(40), subject.getTrackStatistics().movingDuration());
assertEquals(Distance.of(1040), subject.getTrackStatistics().totalDistance());
}
@Test
public void addTrackPoint_idle_remain_idle() {
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
// when
subject.addTrackPoint(new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochSecond(0)));
TrackStatisticsUpdater subject = new TrackStatisticsUpdater(new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochSecond(0)));
subject.addTrackPoint(
createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(10))
.setSensorDistance(Distance.of(10)));
createTrackPoint(0, 0, Altitude.WGS84.of(0), Instant.ofEpochSecond(10), null, 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());
assertTrue(subject.isIdle());
assertEquals(Duration.ofSeconds(30), subject.getTrackStatistics().movingDuration());
assertEquals(Duration.ofSeconds(30), subject.getTrackStatistics().totalDuration());
assertEquals(Distance.of(10), subject.getTrackStatistics().totalDistance());
// when
subject.addTrackPoint(
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochSecond(40))
.setSensorDistance(Distance.of(0)));
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
Position.of(Instant.ofEpochSecond(40)),
Distance.ZERO,
null,
null,
null,
null,
null
)
);
// 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());
assertTrue(subject.isIdle());
assertEquals(Duration.ofSeconds(30), subject.getTrackStatistics().movingDuration());
assertEquals(Duration.ofSeconds(40), subject.getTrackStatistics().totalDuration());
assertEquals(Distance.of(10), subject.getTrackStatistics().totalDistance());
// when
subject.addTrackPoint(
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochSecond(45))
.setSensorDistance(Distance.of(1)));
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
Position.of(Instant.ofEpochSecond(45)),
Distance.of(1),
null,
null,
null,
null,
null
)
);
// 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());
assertTrue(subject.isIdle());
assertEquals(Duration.ofSeconds(30), subject.getTrackStatistics().movingDuration());
assertEquals(Duration.ofSeconds(45), subject.getTrackStatistics().totalDuration());
assertEquals(Distance.of(11), subject.getTrackStatistics().totalDistance());
// when
subject.addTrackPoint(
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochSecond(50))
.setSensorDistance(Distance.of(10)));
new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
Position.of(Instant.ofEpochSecond(50)),
Distance.of(10),
null,
null,
null,
null,
null
)
);
// 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());
assertFalse(subject.isIdle());
assertEquals(Duration.ofSeconds(30), subject.getTrackStatistics().movingDuration());
assertEquals(Duration.ofSeconds(50), subject.getTrackStatistics().totalDuration());
assertEquals(Distance.of(21), subject.getTrackStatistics().totalDistance());
// 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());
assertFalse(subject.isIdle());
assertEquals(Duration.ofSeconds(40), subject.getTrackStatistics().movingDuration());
assertEquals(Duration.ofSeconds(60), subject.getTrackStatistics().totalDuration());
assertEquals(Distance.of(21), subject.getTrackStatistics().totalDistance());
}
@Test
public void copy_constructor() {
// given
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
TrackPoint tp1 = new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochMilli(1000));
TrackPoint tp2 = createTrackPoint(0, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(2000));
tp2.setSpeed(Speed.of(5f));
TrackPoint tp3 = createTrackPoint(0.00001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000));
tp3.setSpeed(Speed.of(5f));
TrackPoint tp4 = createTrackPoint(0.0005, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(4000));
tp4.setSpeed(Speed.of(5f));
TrackPoint tp2 = createTrackPoint(0, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(2000), Speed.of(5f), null);
TrackPoint tp3 = createTrackPoint(0.00001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000), Speed.of(5f), null);
TrackPoint tp4 = createTrackPoint(0.0005, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(4000), Speed.of(5f), null);
TrackPoint tp5 = new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochMilli(5000));
subject.addTrackPoint(tp1);
subject.addTrackPoint(tp2);
subject.addTrackPoint(tp3);
subject.addTrackPoint(tp4);
TrackStatisticsUpdater initial = new TrackStatisticsUpdater(List.of(tp1, tp2, tp3, tp4));
// when
TrackStatisticsUpdater copy = new TrackStatisticsUpdater(subject);
subject.addTrackPoint(tp5);
copy.addTrackPoint(tp5);
TrackStatisticsUpdater subject = new TrackStatisticsUpdater(initial, tp5);
// then
assertEquals(55.287, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
assertEquals(55.287, copy.getTrackStatistics().getTotalDistance().toM(), 0.01);
assertEquals(new Statistics(
Instant.ofEpochMilli(1000),
Instant.ofEpochMilli(4000),
Duration.ofSeconds(3),
Duration.ofSeconds(3),
Distance.of(55.28713929653168),
Speed.of(18.429046432177227),
new AltitudeExtremities(5, 5),
null,
null,
null
), initial.getTrackStatistics());
assertEquals(new Statistics(
Instant.ofEpochMilli(1000),
Instant.ofEpochMilli(5000),
Duration.ofSeconds(4),
Duration.ofSeconds(4),
Distance.of(55.28713929653168),
Speed.of(18.429046432177227),
new AltitudeExtremities(5, 5),
null,
null,
null
), subject.getTrackStatistics());
}
public TrackPoint createTrackPoint(double latitude, double longitude, Altitude altitude, Instant time) {
return new TrackPoint(TrackPoint.Type.TRACKPOINT,
return createTrackPoint(latitude, longitude, altitude, time, null, null);
}
public TrackPoint createTrackPoint(double latitude, double longitude, Altitude altitude, Instant time, Speed speed, Distance sensorDistance) {
return new TrackPoint(
null,
TrackPoint.Type.TRACKPOINT,
new Position(
time,
latitude,
@@ -364,7 +410,14 @@ public class TrackStatisticsUpdaterTest {
altitude,
null,
null,
null
));
speed
),
sensorDistance,
null,
null,
null,
null,
null
);
}
}

Some files were not shown because too many files have changed in this diff Show More