Compare commits

...

222 Commits

Author SHA1 Message Date
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
Dennis Guse 57c0750980 Release: v4.23.0 2025-10-24 10:23:14 +02:00
Dennis Guse 8e36ee2e7d Cleanup: TrackRecordingServiceNotificationManager uses RecordingData. 2025-10-24 10:19:43 +02:00
Dennis Guse ec2e527fd1 Cleanup. 2025-10-24 10:04:04 +02:00
Dennis Guse d968e5d0c1 Notification opens recording UI.
Features was removed as it broke occasionally and re-implemented after refactoring.

Fixes #1156.
2025-10-22 23:25:55 +02:00
Dennis Guse 4257f21cae Fixed tests.
Missed in1fa76301e23bf709402c19838efea597e7e38ca7
2025-10-22 23:24:13 +02:00
Dennis Guse 26e7059af2 Cleanup. 2025-10-22 22:49:20 +02:00
Jeff Shelley 94595f2a1f Added support for average pace of the current segment 2025-10-21 19:34:19 -05:00
Dennis Guse 1fa76301e2 Cleanup: TrackShareSummaryGenerator (was DescriptionGenerator) now only produces plaintext (HTML was not used anymore). 2025-10-20 09:15:39 +02:00
Dennis Guse ce2c608cc9 Cleanup: TrackStatistics has altitudeExtremities or not. 2025-10-19 22:27:11 +02:00
Dennis Guse 916f26dfda Merge pull request 'Cleanup' (#2173) from cleanup into main
Reviewed-on: https://codeberg.org/OpenTracksApp/OpenTracks/pulls/2173
2025-10-19 18:43:38 +02:00
Dennis Guse a108edc125 Bump androidx.work:work-runtime from 2.10.2 to 2.10.5 2025-10-19 18:28:13 +02:00
Dennis Guse 1a1a8a851b Cleanup: use Stream.toList()
Replaces Stream.collect(Collection.toList() | Collectors.toCollection()).
2025-10-19 18:26:49 +02:00
Dennis Guse ddd1efeb58 Cleanup: use .isEmpty() (except for CharSequence and StringBuilder as it requires SDK33). 2025-10-19 18:26:48 +02:00
Dennis Guse 6c30dd8509 Lists should show vertical scrolling indicator (was lost by switching to RecyclerView). 2025-10-19 17:59:47 +02:00
Dennis Guse 21fe59f32c Cleanup: SDK_INT is always >= Android O. 2025-10-19 17:48:23 +02:00
Dennis Guse f79b2b51c8 Cleanup: use correct order for assert in tests. 2025-10-18 21:48:45 +02:00
Dennis Guse b16e9ad964 Cleanup: UintUtilsTest was only partly executed. 2025-10-18 21:41:46 +02:00
Dennis Guse 65f8ba16b3 Cleanup: RecyclerViewSwipeDeleteCallback.onChildDraw() should only call super once. 2025-10-18 21:28:49 +02:00
Dennis Guse 9b48993cd0 Cleanup. 2025-10-18 21:27:31 +02:00
Dennis Guse 54cec3e821 Cleanup: limit method visibility. 2025-10-18 21:10:26 +02:00
Dennis Guse daeb972c8a Cleanup: simplify stream by using List operations (desugar). 2025-10-18 21:10:26 +02:00
Dennis Guse 73872e8926 Cleanup. 2025-10-18 21:09:21 +02:00
Dennis Guse c15fa21a56 Cleanup: use viewHolder.getAbsoluteAdapterPosition(). 2025-10-18 09:40:56 +02:00
Dennis Guse e9d1080e5d Cleanup: SpeedFormatter doesn't support decimal places. 2025-10-18 09:40:54 +02:00
Claudinux d0b3f45151 Translated using Weblate (Italian)
Currently translated at 4.0% (7 of 172 strings)

Translation: OpenTracks/App store metadata files
Translate-URL: https://translate.codeberg.org/projects/opentracks/app-store-metadata-files/it/
2025-10-16 21:50:25 +02:00
happylocalisation 32b0b02d28 Added translation using Weblate (English (Middle)) 2025-10-16 21:50:25 +02:00
Dennis Guse d6617f61b7 Cleanup: use PreferenceUtils.isKey(List). 2025-10-15 18:10:35 +02:00
Dennis Guse b5180f235f Cleanup: StatisticsUtils were unused. 2025-10-15 18:10:15 +02:00
Dennis Guse e879eedbd6 Migrate ImportService to WorkManager.
Part of #1315.
2025-10-15 17:25:48 +02:00
Dennis Guse c7ca6800f7 Cleanup: ImportActivity. 2025-10-15 09:02:49 +02:00
Dennis Guse fed884a6ce ExportActivity inherits AbstractActivity. 2025-10-15 08:40:19 +02:00
Dennis Guse 02a77e5ce7 Migrate ExportService to WorkManager.
Part of #1315.
2025-10-14 22:45:00 +02:00
Dennis Guse 6f97399aeb Migrate TrackDeletionService to WorkManager.
Part of #1315.
2025-10-14 19:13:10 +02:00
pstorch 1c4f0e67ab Merge pull request 'use forgejo runner with simple unit tests' (#2159) from connected_check into main
Reviewed-on: https://codeberg.org/OpenTracksApp/OpenTracks/pulls/2159
2025-10-13 11:27:17 +02:00
Peter Storch ebed386d96 use forgejo runners with unit tests 2025-10-12 17:39:35 +02:00
Dennis Guse e44f63feb7 Merge remote-tracking branch 'weblate/main' 2025-09-25 19:08:49 +02:00
SomeTr e72d2a750c Translated using Weblate (Ukrainian)
Currently translated at 93.5% (507 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/uk/
2025-09-22 10:09:12 +00:00
Claudinux 81f6bbe955 Translated using Weblate (Italian)
Currently translated at 3.5% (6 of 171 strings)

Translation: OpenTracks/App store metadata files
Translate-URL: https://translate.codeberg.org/projects/opentracks/app-store-metadata-files/it/
2025-09-09 15:09:10 +00:00
mikini c162c0a0ff Translated using Weblate (Danish)
Currently translated at 97.4% (528 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/da/
2025-09-07 08:51:08 +00:00
Outbreak2096 385d05dcdb 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/
2025-09-07 08:51:08 +00:00
Claudinux 308ce4ac07 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/
2025-09-07 08:51:08 +00:00
Outbreak2096 f8a0241e1f Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 93.5% (159 of 170 strings)

Translation: OpenTracks/App store metadata files
Translate-URL: https://translate.codeberg.org/projects/opentracks/app-store-metadata-files/zh_Hans/
2025-09-07 08:51:08 +00:00
Claudinux c74a5c8749 Translated using Weblate (Italian)
Currently translated at 2.9% (5 of 170 strings)

Translation: OpenTracks/App store metadata files
Translate-URL: https://translate.codeberg.org/projects/opentracks/app-store-metadata-files/it/
2025-09-07 08:51:08 +00:00
Claudinux defdd49a65 Translated using Weblate (Italian)
Currently translated at 97.4% (528 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/
2025-09-07 08:51:08 +00:00
281 changed files with 5653 additions and 6438 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
+36
View File
@@ -0,0 +1,36 @@
name: Android Test
on:
push:
branches:
- main
pull_request:
jobs:
lint:
name: Android Lint
runs-on: docker
container:
image: 'ubuntu:android-24.04'
steps:
- name: Checkout sources
uses: actions/checkout@v6
with:
fetch-depth: 1
- name: Lint
shell: bash
run: ./gradlew lint
android-check:
runs-on: docker
container:
image: 'ubuntu:android-24.04'
steps:
- name: Checkout sources
uses: actions/checkout@v6
with:
fetch-depth: 1
- name: Test
shell: bash
run: ./gradlew testNightlyDebugUnitTest --stacktrace
-10
View File
@@ -1,10 +0,0 @@
steps:
build:
when:
event: [ push ]
image: androidsdk/android-31
commands:
- apt-get update
- apt-get install -y openjdk-17-jdk-headless
- update-java-alternatives -a
- ./gradlew lint
-10
View File
@@ -1,10 +0,0 @@
steps:
build:
when:
event: [ push ]
image: androidsdk/android-31
commands:
- apt-get update
- apt-get install -y openjdk-17-jdk-headless
- update-java-alternatives -a
- ./gradlew testNightlyDebugUnitTest --stacktrace
+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)
+18 -6
View File
@@ -6,7 +6,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.11.1'
classpath 'com.android.tools.build:gradle:8.13.2'
}
}
@@ -46,8 +46,8 @@ android {
defaultConfig {
applicationId 'de.dennisguse.opentracks'
versionCode 6294
versionName "v4.22.2"
versionCode 6516
versionName "v4.24.2"
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
@@ -57,6 +57,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) {
@@ -149,16 +160,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.core:core-location-altitude:1.0.0-beta01'
implementation 'androidx.work:work-runtime:2.11.0'
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,10 @@
v4.23.0: OpenTracks
Changes:
- UI: added average pace of current segment
(currently only available in new layouts)
- Clicking on notification opens actual recording UI
Developer:
- Deprecated JobIntentService replaced with WorkManager
- Use .isEmpty() except for CharSequence and Stream.toList()
@@ -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,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
@@ -0,0 +1,4 @@
v4.22.0: OpenTracks
Modifiche:
- Migrazione a https://codeberg.org/OpenTracksApp/OpenTracks
@@ -0,0 +1,4 @@
v4.22.1: OpenTracks
Modiciche:
- Primo rilascio da Codeberg
@@ -0,0 +1,4 @@
v4.22.2: OpenTracks
Correzione di errori:
- L'impostazione degli annunci vocali per l'ora e l'unità di misura è stata collegata
@@ -0,0 +1,10 @@
(versionName): OpenTracks
Modifiche:
-
Correzioni di errori:
-
Sviluppatore:
-
@@ -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
மாற்றங்கள்:
- முன்கணிப்பு முற்றிலும் வேலை செய்கிறது
பிழைத்திருத்தம்:
- அமைப்புகளில் டிராக் கோப்புப் பெயருடன் தொடர்புடைய செயலிழப்பில் சரி செய்யப்பட்டது
டெவலப்பர்:
- புள்ளிவிவரங்களுக்கான தரவு வகுப்பு அறிமுகப்படுத்தப்பட்டது
@@ -1,22 +1,22 @@
一款尊重您的隐私的运动追踪应用。
尊重您隐私的运动追踪伙伴。
健康幸福的生活总少不了各种运动和户外活动。
运动与户外活动能带来快乐、提升技能、增强自信。
使用本应用,您可以保持对您的训练数据的有效追踪,为您的健康助力。
本应用可以在您跑步或散步时记录数据,也可以在您骑车时作为一个大屏幕自行车电脑。
您可以为路上的有趣位置创建标记,还可以用图片作为标记。
您的数据会被详尽地记录下来,供您查阅分析。
您的数据只会分享给您想要分享给的人。
通过跟踪训练数据,珍视您的健康。
记录您的跑步或步行数据,并提供大屏的专用骑行码表。
用照片标记沿途有趣的地点。
保留详细记录的统计数据以供分析。
仅分享您愿意公开的数据。
* 语音播报
* 支持蓝牙LE传感器:心率、速度和距离(骑车)、踏频(骑车)和功率计(骑车)。
* 海拔增减:通过气压传感器。
* EGM2008 海拔显示(平均海平面以上);导出为 WGS84。
* 导出路线数据,支持 KMZ(包括照片)、KML 和 GPX 格式。
* 不需要联网,不需要额外权限。
* 语音播报。
* 支持蓝牙低功耗传感器:心率、速度和距离(骑行)、踏频(骑行)、功率计(骑行)。
* 海拔上升和下降:通过气压传感器。
* 采用 EGM2008 显示海拔(平均海平面以上);导出为 WGS84。
* 以 KMZ(含照片)、KML 或 GPX 格式导出轨迹数据。
* 无需互联网访问或额外权限。
* 深色和浅色主题,跟随系统设置。
* 没有广告。
* 无广告。
本应用是开源软件
意味着您可以使用、学习、修改和分发本应用的源代码。
本应用使用 Apache 2.0 协议发布。
‌自由软件/开放源代码
意味着您可以使用、研究、修改和分享源代码。
采用 Apache 2.0 许可
@@ -1 +1 @@
一款尊重您的隐私的运动追踪应用。
尊重您隐私的运动追踪伙伴。
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.2.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
+3
View File
@@ -0,0 +1,3 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
}
@@ -52,7 +52,6 @@ public class EspressoDeleteTrackTest {
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(
@@ -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,24 @@ 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.Distance;
import de.dennisguse.opentracks.data.models.Marker;
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.stats.TrackStatistics;
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
import de.dennisguse.opentracks.ui.markers.MarkerUtils;
import de.dennisguse.opentracks.util.FileUtils;
@@ -37,11 +39,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 +91,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).getPosition(), null),
new Marker(null, trackId, "Marker 2", "Marker description 2", "Marker typeLocalized 3", trackPoints.get(4).getPosition(), null),
new Marker(null, trackId, "Marker 3", "Marker description 3", "Marker typeLocalized 3", trackPoints.get(5).getPosition(), null)
);
return new TrackData(track, trackPoints, markers);
@@ -126,8 +128,7 @@ public class TestDataUtil {
trackPoint.setHeartRate(100f + i % 80);
trackPoint.setCadence(300f + i);
trackPoint.setPower(400f + i);
trackPoint.setAltitudeGain(ALTITUDE_GAIN);
trackPoint.setAltitudeLoss(ALTITUDE_LOSS);
trackPoint.setAltitudeGainLoss(ALTITUDE_GAIN, ALTITUDE_LOSS);
return trackPoint;
}
@@ -145,45 +146,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.getPosition(),
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());
}
}
@@ -41,8 +41,7 @@ public class TestSensorDataUtil {
if (power != null) {
tp.setPower(power);
}
tp.setAltitudeGain(3f);
tp.setAltitudeLoss(3f);
tp.setAltitudeGainLoss(3, 3);
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,28 +41,32 @@ 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;
import java.util.Random;
import java.util.UUID;
import java.util.stream.Collectors;
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.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.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.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.data.statistics.SensorStatistics;
import de.dennisguse.opentracks.util.FileUtils;
/**
@@ -115,7 +118,7 @@ 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);
@@ -128,11 +131,19 @@ public class CustomContentProviderUtilsTest {
}
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);
@@ -153,7 +164,7 @@ 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();
@@ -194,8 +205,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) {
@@ -220,8 +231,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).getPosition(),
null
));
assertCount(1, 10, 1);
@@ -239,14 +257,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);
@@ -276,8 +294,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).getPosition(),
null
));
assertCount(3, 30, 1);
@@ -304,19 +329,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());
@@ -348,7 +373,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());
}
/**
@@ -375,61 +400,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));
@@ -446,15 +467,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).getPosition(),
null
));
// Check insert was done.
assertEquals(contentProviderUtils.getMarkers(trackId).size(), 1);
// 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);
@@ -473,18 +497,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(contentProviderUtils.getMarkers(trackId).size(), 1);
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);
@@ -523,20 +547,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).getPosition(),
null
));
Marker.Id marker2Id = contentProviderUtils.insertMarker(new Marker(
null,
trackId,
"",
MOCK_DESC,
"",
getLastValidTrackPoint(trackId).getPosition(),
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());
}
/**
@@ -547,14 +582,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).getPosition(),
null
));
}
assertEquals(Integer.valueOf(4), contentProviderUtils.getNextMarkerNumber(trackId));
}
@@ -568,11 +606,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).getPosition(),
null
));
assertEquals(TEST_DESC, contentProviderUtils.getMarker(markerId).getDescription());
assertEquals(TEST_DESC, contentProviderUtils.getMarker(markerId).description());
}
/**
@@ -584,16 +629,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).getPosition(),
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).getPosition(),
null
));
assertEquals(TEST_DESC_NEW, contentProviderUtils.getMarker(markerId).getDescription());
assertEquals(TEST_DESC_NEW, contentProviderUtils.getMarker(markerId).description());
}
/**
@@ -607,10 +665,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());
@@ -618,14 +674,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);
@@ -642,9 +697,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());
@@ -653,15 +707,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());
}
@@ -676,11 +729,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);
@@ -690,12 +741,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);
@@ -726,50 +779,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)}.
@@ -778,7 +787,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
@@ -792,7 +801,7 @@ 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);
@@ -810,19 +819,6 @@ public class CustomContentProviderUtilsTest {
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());
}
@Test
public void testGetTrackPointCursor_asc() {
// given
@@ -831,8 +827,8 @@ 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(TrackPoint.Id::new).collect(Collectors.toList());
.map(it -> ContentUris.parseId(contentProviderUtils.insertTrackPoint(it, track.first.id())))
.map(TrackPoint.Id::new).toList();
// when
try (Cursor cursor = contentProviderUtils.getTrackPointCursor(trackId, trackpointIds.get(8))) {
@@ -842,20 +838,20 @@ 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(TrackPoint.Id::new).collect(Collectors.toList());
.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++) {
@@ -863,24 +859,15 @@ public class CustomContentProviderUtilsTest {
TrackPoint trackPoint = trackPointIterator.next();
assertEquals(startTrackPointId.id() + i, trackPoint.getId().id());
checkLocation(i, trackPoint.getLocation());
Position position = trackPoint.getPosition();
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());
@@ -1220,4 +1207,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.getType()))
.findFirst().orElseThrow();
}
}
}
@@ -48,10 +48,8 @@ public class CustomSQLiteOpenHelperTest {
public static Map<String, String> getSQL(SQLiteDatabase db, String type) {
HashMap<String, String> sqlMap = new HashMap<>();
try (Cursor cursor = db.query("sqlite_master", new String[]{"name", "SQL"}, "type=?", new String[]{type}, null, null, "name")) {
if (cursor != null) {
while (cursor.moveToNext()) {
sqlMap.put(cursor.getString(0), cursor.getString(1));
}
while (cursor.moveToNext()) {
sqlMap.put(cursor.getString(0), cursor.getString(1));
}
}
return sqlMap;
@@ -64,12 +62,10 @@ public class CustomSQLiteOpenHelperTest {
*/
private static boolean hasSqlCreate(SQLiteDatabase db, String sqlCreate) {
try (Cursor cursor = db.rawQuery("SELECT SQL FROM sqlite_master", null)) {
if (cursor != null) {
while (cursor.moveToNext()) {
String sql = cursor.getString(0);
if (sqlCreate.equals(sql)) {
return true;
}
while (cursor.moveToNext()) {
String sql = cursor.getString(0);
if (sqlCreate.equals(sql)) {
return true;
}
}
}
@@ -104,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");
}
@@ -138,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
@@ -159,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"));
@@ -172,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)");
@@ -205,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();
@@ -265,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) {
}
@@ -273,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(selection.selection(), "_id IN (?)");
assertEquals(selection.selectionArgs().length, 1);
assertEquals(selection.selectionArgs()[0], "1");
assertEquals("_id IN (?)", selection.selection());
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(selection.selection(), "_id IN (?,?,?)");
assertEquals(selection.selectionArgs().length, 3);
assertEquals(selection.selectionArgs()[0], "1");
assertEquals(selection.selectionArgs()[1], "2");
assertEquals(selection.selectionArgs()[2], "3");
assertEquals("_id IN (?,?,?)", selection.selection());
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(selection.selection(), "category IN (?)");
assertEquals(selection.selectionArgs().length, 1);
assertEquals(selection.selectionArgs()[0], "running");
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(selection.selection(), "category IN (?,?,?,?)");
assertEquals(selection.selectionArgs().length, 4);
assertEquals(selection.selectionArgs()[0], "running");
assertEquals(selection.selectionArgs()[1], "road biking");
assertEquals(selection.selectionArgs()[2], "mountain biking");
assertEquals(selection.selectionArgs()[3], "trail walking");
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(selectionOk.selection(), "starttime BETWEEN ? AND ?");
assertEquals(selectionOk.selectionArgs().length, 2);
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(selection.selection(), "_id IN (?,?,?) AND category IN (?,?)");
assertEquals(selection.selectionArgs().length, 5);
assertEquals(selection.selectionArgs()[0], "1");
assertEquals(selection.selectionArgs()[1], "2");
assertEquals(selection.selectionArgs()[2], "3");
assertEquals(selection.selectionArgs()[3], "running");
assertEquals(selection.selectionArgs()[4], "road biking");
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(selection.selection(), "_id IN (?,?,?) AND starttime BETWEEN ? AND ?");
assertEquals(selection.selectionArgs().length, 5);
assertEquals(selection.selectionArgs()[0], "1");
assertEquals(selection.selectionArgs()[1], "2");
assertEquals(selection.selectionArgs()[2], "3");
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(selection.selection(), "category IN (?,?) AND starttime BETWEEN ? AND ?");
assertEquals(selection.selectionArgs().length, 4);
assertEquals(selection.selectionArgs()[0], "running");
assertEquals(selection.selectionArgs()[1], "road biking");
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());
}
}
@@ -21,7 +21,7 @@ public class DistanceFormatterTest {
@Test
public void testFormatDistance_metric() {
DistanceFormatter formatter = DistanceFormatter.Builder()
.setDecimalCount(2)
.setDecimalPlaces(2)
.setUnit(UnitSystem.METRIC)
.build(context);
@@ -34,7 +34,7 @@ public class DistanceFormatterTest {
@Test
public void testFormatDistance_imperial() {
DistanceFormatter formatter = DistanceFormatter.Builder()
.setDecimalCount(2)
.setDecimalPlaces(2)
.setUnit(UnitSystem.IMPERIAL_FEET)
.build(context);
@@ -47,7 +47,7 @@ public class DistanceFormatterTest {
@Test
public void testFormatDistance_nautical() {
DistanceFormatter formatter = DistanceFormatter.Builder()
.setDecimalCount(2)
.setDecimalPlaces(2)
.setUnit(UnitSystem.NAUTICAL_IMPERIAL)
.build(context);
@@ -21,7 +21,6 @@ public class SpeedFormatterTest {
@Test
public void testGetSpeedParts_pace_metric() {
SpeedFormatter formatter = SpeedFormatter.Builder()
.setDecimalCount(2)
.setUnit(UnitSystem.METRIC)
.setReportSpeedOrPace(false)
.build(context);
@@ -29,73 +28,67 @@ 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
public void testGetSpeedParts_pace_imperial() {
SpeedFormatter formatter = SpeedFormatter.Builder()
.setDecimalCount(2)
.setUnit(UnitSystem.IMPERIAL_FEET)
.setReportSpeedOrPace(false)
.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
public void testGetSpeedParts_pace_nautical() {
SpeedFormatter formatter = SpeedFormatter.Builder()
.setDecimalCount(2)
.setUnit(UnitSystem.NAUTICAL_IMPERIAL)
.setReportSpeedOrPace(false)
.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
public void testGetSpeedParts_speed_metric() {
SpeedFormatter formatter = SpeedFormatter.Builder()
.setDecimalCount(2)
.setUnit(UnitSystem.METRIC)
.setReportSpeedOrPace(true)
.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
public void testGetSpeedParts_speed_imperial() {
SpeedFormatter formatter = SpeedFormatter.Builder()
.setDecimalCount(2)
.setUnit(UnitSystem.IMPERIAL_FEET)
.setReportSpeedOrPace(true)
.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
public void testGetSpeedParts_speed_nautical() {
SpeedFormatter formatter = SpeedFormatter.Builder()
.setDecimalCount(2)
.setUnit(UnitSystem.NAUTICAL_IMPERIAL)
.setReportSpeedOrPace(true)
.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
public void testFormatSpeed() {
SpeedFormatter formatter = SpeedFormatter.Builder()
.setDecimalCount(2)
.setUnit(UnitSystem.METRIC)
.setReportSpeedOrPace(false)
.build(context);
@@ -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;
@@ -52,6 +51,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,7 +60,9 @@ 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.TrackBuilder;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.io.file.TrackFileFormat;
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
@@ -75,7 +77,6 @@ import de.dennisguse.opentracks.sensors.sensorData.Raw;
import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet;
import de.dennisguse.opentracks.services.TrackRecordingService;
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
import de.dennisguse.opentracks.stats.TrackStatistics;
/**
* Export a track to {@link TrackFileFormat} and verify that the import is identical.
@@ -150,7 +151,16 @@ 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",
service.getLastStoredTrackPointWithLocation().getPosition(),
null
));
// A sensor-only TrackPoint
trackPointCreator.setClock("2020-02-02T02:02:04Z");
@@ -164,7 +174,16 @@ public class ExportImportTest {
mockSensorData(trackPointCreator, 5f, Distance.of(2), 69f, 3f, 50f, null); // Distance will be added to next TrackPoint
sendLocation(trackPointCreator, "2020-02-02T02:02:17Z", 3.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().getPosition(),
null
));
trackPointCreator.setClock("2020-02-02T02:02:18Z");
trackPointCreator.getSensorManager().sensorDataSet = new SensorDataSet(trackPointCreator);
@@ -186,15 +205,14 @@ public class ExportImportTest {
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
@@ -203,29 +221,23 @@ public class ExportImportTest {
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(ZoneOffset.of("+01:00"), track.zoneOffset());
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(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);
List<TrackPoint> actual = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
new TrackPointAssert().assertEquals(List.of(
@@ -237,17 +249,14 @@ public class ExportImportTest {
Altitude.WGS84.of(1020.25), null,
null,
Speed.of(15)))
.setAltitudeLoss(1f)
.setAltitudeGain(1f),
.setAltitudeGainLoss(1, 1),
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),
.setPower(50).setAltitudeGainLoss(1, 1),
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse("2020-02-02T02:02:15Z"))
.setHeartRate(HeartRate.of(68))
.setCadence(3)
@@ -260,8 +269,7 @@ public class ExportImportTest {
null,
Speed.of(5)))
.setSensorDistance(Distance.of(2))
.setAltitudeLoss(0f)
.setAltitudeGain(0f)
.setAltitudeGainLoss(0, 0)
.setHeartRate(HeartRate.of(69))
.setCadence(3)
.setPower(50),
@@ -274,27 +282,23 @@ public class ExportImportTest {
Altitude.WGS84.of(999.1229858398438), null,
null,
Speed.of(15)))
.setAltitudeLoss(0f)
.setAltitudeGain(0f),
.setAltitudeGainLoss(0, 0),
new TrackPoint(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),
.setAltitudeGainLoss(0, 0),
new TrackPoint(TrackPoint.Type.IDLE, Instant.parse("2020-02-02T02:03:30Z"))
.setAltitudeLoss(0f)
.setAltitudeGain(0f),
.setAltitudeGainLoss(0, 0),
new TrackPoint(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),
.setAltitudeGainLoss(0, 0),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse("2020-02-02T02:04:00Z"))
), actual);
}
@@ -323,41 +327,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();
@@ -413,10 +408,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.
@@ -433,8 +428,7 @@ public class ExportImportTest {
Altitude.WGS84.of(1020.2), null,
null,
Speed.of(15)))
.setAltitudeLoss(1f)
.setAltitudeGain(1f),
.setAltitudeGainLoss(1, 1),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse("2020-02-02T02:02:17Z"),
@@ -442,8 +436,7 @@ public class ExportImportTest {
Altitude.WGS84.of(1020.2), null,
null,
Speed.of(5)))
.setAltitudeLoss(1f)
.setAltitudeGain(1f)
.setAltitudeGainLoss(1, 1)
.setSensorDistance(Distance.of(12))
.setHeartRate(69)
.setPower(50f)
@@ -455,8 +448,7 @@ public class ExportImportTest {
Altitude.WGS84.of(999.0999755859375), null,
null,
Speed.of(15)))
.setAltitudeLoss(0f)
.setAltitudeGain(0f),
.setAltitudeGainLoss(0, 0),
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC,
new Position(
Instant.parse("2020-02-02T02:03:22Z"),
@@ -464,8 +456,7 @@ public class ExportImportTest {
Altitude.WGS84.of(999.0999755859375), null,
null,
Speed.of(15)))
.setAltitudeLoss(0f)
.setAltitudeGain(0f),
.setAltitudeGainLoss(0, 0),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse("2020-02-02T02:03:50Z"),
@@ -473,35 +464,27 @@ public class ExportImportTest {
Altitude.WGS84.of(999.0999755859375), null,
null,
Speed.of(10)))
.setAltitudeLoss(0f)
.setAltitudeGain(0f)
.setAltitudeGainLoss(0, 0)
.setSpeed(Speed.of(15))
), 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();
@@ -566,21 +549,20 @@ 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);
}
}
@@ -30,11 +30,11 @@ 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.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 +61,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 +76,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 +131,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);
@@ -267,8 +200,7 @@ public class GPXTrackImporterTest {
Altitude.WGS84.of(10), null,
null,
Speed.of(15)))
.setAltitudeLoss(1f)
.setAltitudeGain(1f),
.setAltitudeGainLoss(1, 1),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse("2020-02-02T02:02:17Z"),
@@ -276,8 +208,7 @@ public class GPXTrackImporterTest {
Altitude.WGS84.of(10), null,
null,
Speed.of(5)))
.setAltitudeLoss(1f)
.setAltitudeGain(1f)
.setAltitudeGainLoss(1, 1)
.setSensorDistance(Distance.of(12))
.setHeartRate(69)
.setPower(50f)
@@ -289,8 +220,7 @@ public class GPXTrackImporterTest {
Altitude.WGS84.of(10), null,
null,
Speed.of(15)))
.setAltitudeLoss(0f)
.setAltitudeGain(0f),
.setAltitudeGainLoss(0, 0),
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC,
new Position(
Instant.parse("2020-02-02T02:03:22Z"),
@@ -298,8 +228,7 @@ public class GPXTrackImporterTest {
Altitude.WGS84.of(10), null,
null,
Speed.of(15)))
.setAltitudeLoss(0f)
.setAltitudeGain(0f),
.setAltitudeGainLoss(0, 0),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse("2020-02-02T02:03:50Z"),
@@ -307,8 +236,7 @@ public class GPXTrackImporterTest {
Altitude.WGS84.of(10), null,
null,
Speed.of(10)))
.setAltitudeLoss(0f)
.setAltitudeGain(0f)
.setAltitudeGainLoss(0, 0)
.setSpeed(Speed.of(15))
), actual);
}
@@ -319,19 +247,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);
}
@@ -29,13 +29,9 @@ public class TrackPointAssert {
Assert.assertEquals("altitude", expected.getAltitude().toM(), actual.getAltitude().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("has altitudeGainLoss", expected.hasAltitudeGainLoss(), actual.hasAltitudeGainLoss());
if (expected.hasAltitudeGainLoss()) {
Assert.assertEquals("altitudeGainLoss", expected.getAltitudeGainLoss(), actual.getAltitudeGainLoss());
}
Assert.assertEquals("has speed", expected.hasSpeed(), actual.hasSpeed());
@@ -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
@@ -1,50 +1,54 @@
package de.dennisguse.opentracks.sensors;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import org.junit.Test;
public class UintUtilsTest {
@Test
public void diff() {
public void diff_uint16_valid() {
assertEquals(0, UintUtils.diff(1, 1, UintUtils.UINT16_MAX));
assertEquals(1, UintUtils.diff(2, 1, UintUtils.UINT16_MAX));
assertEquals(3, UintUtils.diff(5, 2, UintUtils.UINT16_MAX));
assertEquals(65535, UintUtils.diff(1, 2, UintUtils.UINT16_MAX)); /* unsigned 16 arithmetic is modulo UINT16_MAX + 1, not modulo UINT16_MAX */
assertEquals(65530, UintUtils.diff(UintUtils.UINT16_MAX, 5, UintUtils.UINT16_MAX));
}
@Test
public void diff_uint16_invalid() {
/* Test modulo arithmetic for arguments that are out of range */
assertThrows(RuntimeException.class, () -> UintUtils.diff(65537, 1, UintUtils.UINT16_MAX));
assertThrows(RuntimeException.class, () -> UintUtils.diff(1, 65537, UintUtils.UINT16_MAX));
assertThrows(RuntimeException.class, () -> UintUtils.diff(65537, 65537, UintUtils.UINT16_MAX));
assertThrows(RuntimeException.class, () -> UintUtils.diff(-65535, 1, UintUtils.UINT16_MAX));
assertThrows(RuntimeException.class, () -> UintUtils.diff(1, -65535, UintUtils.UINT16_MAX));
assertThrows(RuntimeException.class, () -> UintUtils.diff(-65535, -65535, UintUtils.UINT16_MAX));
assertThrows(RuntimeException.class, () -> UintUtils.diff(-65535, 65537, UintUtils.UINT16_MAX));
assertThrows(RuntimeException.class, () -> UintUtils.diff(65537, -65535, UintUtils.UINT16_MAX));
}
if (false) { /* false means UintUtils.diff() throws if arguments out of range */
assertEquals(0, UintUtils.diff(65537, 1, UintUtils.UINT16_MAX));
assertEquals(0, UintUtils.diff(1, 65537, UintUtils.UINT16_MAX));
assertEquals(0, UintUtils.diff(65537, 65537, UintUtils.UINT16_MAX));
assertEquals(0, UintUtils.diff(-65535, 1, UintUtils.UINT16_MAX));
assertEquals(0, UintUtils.diff(1, -65535, UintUtils.UINT16_MAX));
assertEquals(0, UintUtils.diff(-65535, -65535, UintUtils.UINT16_MAX));
assertEquals(0, UintUtils.diff(-65535, 65537, UintUtils.UINT16_MAX));
assertEquals(0, UintUtils.diff(65537, -65535, UintUtils.UINT16_MAX));
}
/* The following tests are the above, but for 32-bit unsigned. */
@Test
public void diff_uint32() {
assertEquals(0, UintUtils.diff(1, 1, UintUtils.UINT32_MAX));
assertEquals(1, UintUtils.diff(2, 1, UintUtils.UINT32_MAX));
assertEquals(3, UintUtils.diff(5, 2, UintUtils.UINT32_MAX));
assertEquals(4294967295L, UintUtils.diff(1, 2, UintUtils.UINT32_MAX));
assertEquals(4294967290L, UintUtils.diff(UintUtils.UINT32_MAX, 5, UintUtils.UINT32_MAX));
}
if (false) { /* false means UintUtils.diff() throws if arguments out of range */
assertEquals(0, UintUtils.diff(4294967297L, 1, UintUtils.UINT32_MAX));
assertEquals(0, UintUtils.diff(1, 4294967297L, UintUtils.UINT32_MAX));
assertEquals(0, UintUtils.diff(4294967297L, 4294967297L, UintUtils.UINT32_MAX));
assertEquals(0, UintUtils.diff(-4294967295L, 1, UintUtils.UINT32_MAX));
assertEquals(0, UintUtils.diff(1, -4294967295L, UintUtils.UINT32_MAX));
assertEquals(0, UintUtils.diff(-4294967295L, -4294967295L, UintUtils.UINT32_MAX));
assertEquals(0, UintUtils.diff(-4294967295L, 4294967297L, UintUtils.UINT32_MAX));
assertEquals(0, UintUtils.diff(65537, -4294967297L, UintUtils.UINT32_MAX));
}
@Test
public void diff_unint32_invalid() {
/* Test modulo arithmetic for arguments that are out of range */
assertThrows(RuntimeException.class, () -> UintUtils.diff(4294967297L, 1, UintUtils.UINT32_MAX));
assertThrows(RuntimeException.class, () -> UintUtils.diff(1, 4294967297L, UintUtils.UINT32_MAX));
assertThrows(RuntimeException.class, () -> UintUtils.diff(4294967297L, 4294967297L, UintUtils.UINT32_MAX));
assertThrows(RuntimeException.class, () -> UintUtils.diff(-4294967295L, 1, UintUtils.UINT32_MAX));
assertThrows(RuntimeException.class, () -> UintUtils.diff(1, -4294967295L, UintUtils.UINT32_MAX));
assertThrows(RuntimeException.class, () -> UintUtils.diff(-4294967295L, -4294967295L, UintUtils.UINT32_MAX));
assertThrows(RuntimeException.class, () -> UintUtils.diff(-4294967295L, 4294967297L, UintUtils.UINT32_MAX));
assertThrows(RuntimeException.class, () -> UintUtils.diff(65537, -4294967297L, UintUtils.UINT32_MAX));
}
@Test
@@ -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,23 +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;
@@ -41,21 +42,39 @@ 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(
null,
UUID.fromString("f81d4fae-7dec-11d0-a765-00a0c91e6bf6"),
"Berlin",
"",
"",
ActivityType.CYCLING,
ZoneOffset.UTC,
Statistics.DEFAULT
);
RecordingData data = new RecordingData(track, trackPointMock, null, null);
// when
subject.updateTrackPoint(context, trackStatisticsMock, trackPointMock, Distance.of(100));
subject.updateTrackPoint(context, trackStatisticsMock, trackPointMock, Distance.of(100));
subject.updateTrackPoint(context, trackStatisticsMock, trackPointMock, Distance.of(1000));
subject.updateTrackPoint(context, trackStatisticsMock, trackPointMock, Distance.of(100));
subject.updateTrackPoint(context, data, Distance.of(100));
subject.updateTrackPoint(context, data, Distance.of(100));
subject.updateTrackPoint(context, data, Distance.of(1000));
subject.updateTrackPoint(context, data, Distance.of(100));
// then
verify(notificationCompatBuilder, times(6)).setOnlyAlertOnce(true);
@@ -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;
@@ -35,6 +39,7 @@ 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 +51,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 +107,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 +121,13 @@ 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)
.setAltitudeGainLoss(0, 0)
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
@@ -143,10 +143,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 +196,13 @@ 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)
.setAltitudeGainLoss(0, 0)
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
//when
@@ -208,14 +211,13 @@ 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),
.setAltitudeGainLoss(0, 0),
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(resumeTime))
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
@@ -248,8 +250,7 @@ public class TrackRecordingServiceRecordingTest {
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)
.setAltitudeGainLoss(0, 0)
), trackPoints);
}
@@ -278,8 +279,7 @@ public class TrackRecordingServiceRecordingTest {
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),
.setAltitudeGainLoss(0, 0),
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(resumeTime))
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
@@ -315,12 +315,10 @@ public class TrackRecordingServiceRecordingTest {
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)
.setAltitudeGainLoss(0, 0)
.setHeartRate(HeartRate.of(7)),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
.setAltitudeGain(0f)
.setAltitudeLoss(0f)
.setAltitudeGainLoss(0, 0)
.setHeartRate(HeartRate.of(7))
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
@@ -338,28 +336,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,8 +364,8 @@ 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)),
@@ -379,8 +376,7 @@ public class TrackRecordingServiceRecordingTest {
null, null,
null,
Speed.of(15)))
.setAltitudeGain(0f)
.setAltitudeLoss(0f),
.setAltitudeGainLoss(0, 0),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse(gps2),
@@ -388,8 +384,7 @@ public class TrackRecordingServiceRecordingTest {
null, null,
null,
Speed.of(15)))
.setAltitudeGain(0f)
.setAltitudeLoss(0f),
.setAltitudeGainLoss(0, 0),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse(gps3),
@@ -397,11 +392,9 @@ public class TrackRecordingServiceRecordingTest {
null, null,
null,
Speed.of(15)))
.setAltitudeGain(0f)
.setAltitudeLoss(0f),
.setAltitudeGainLoss(0, 0),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
.setAltitudeGain(0f)
.setAltitudeLoss(0f)
.setAltitudeGainLoss(0, 0)
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
@@ -417,25 +410,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,8 +436,8 @@ 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)),
@@ -455,8 +448,7 @@ public class TrackRecordingServiceRecordingTest {
null, null,
null,
Speed.of(15)))
.setAltitudeGain(0f)
.setAltitudeLoss(0f),
.setAltitudeGainLoss(0, 0),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse(gps3),
@@ -464,8 +456,7 @@ public class TrackRecordingServiceRecordingTest {
null, null,
null,
Speed.of(15)))
.setAltitudeGain(0f)
.setAltitudeLoss(0f),
.setAltitudeGainLoss(0, 0),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL,
new Position(
Instant.parse(stopTime),
@@ -473,8 +464,7 @@ public class TrackRecordingServiceRecordingTest {
null, null,
null,
Speed.of(15)))
.setAltitudeGain(0f)
.setAltitudeLoss(0f)
.setAltitudeGainLoss(0, 0)
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
@@ -491,15 +481,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";
@@ -516,8 +506,7 @@ public class TrackRecordingServiceRecordingTest {
null, null,
null,
Speed.of(15)))
.setAltitudeGain(0f)
.setAltitudeLoss(0f),
.setAltitudeGainLoss(0, 0),
new TrackPoint(TrackPoint.Type.TRACKPOINT,
new Position(
Instant.parse(gps3),
@@ -525,11 +514,9 @@ public class TrackRecordingServiceRecordingTest {
null, null,
null,
Speed.of(15)))
.setAltitudeGain(0f)
.setAltitudeLoss(0f),
.setAltitudeGainLoss(0, 0),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
.setAltitudeGain(0f)
.setAltitudeLoss(0f)
.setAltitudeGainLoss(0, 0)
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
@@ -545,19 +532,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 +553,14 @@ 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)
.setAltitudeGainLoss(0, 0)
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
@@ -591,18 +576,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,7 +596,8 @@ 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
@@ -623,8 +610,7 @@ public class TrackRecordingServiceRecordingTest {
null, null,
null,
Speed.of(15)))
.setAltitudeGain(0f)
.setAltitudeLoss(0f),
.setAltitudeGainLoss(0, 0),
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC,
new Position(
Instant.parse(gps2),
@@ -632,11 +618,9 @@ public class TrackRecordingServiceRecordingTest {
null, null,
null,
Speed.of(15)))
.setAltitudeGain(0f)
.setAltitudeLoss(0f),
.setAltitudeGainLoss(0, 0),
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
.setAltitudeGain(0f)
.setAltitudeLoss(0f)
.setAltitudeGainLoss(0, 0)
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
@@ -660,7 +644,7 @@ public class TrackRecordingServiceRecordingTest {
// 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), null, Distance.ZERO))); //Should be ignored
// when
String sensor2 = "2020-02-02T02:02:04Z";
@@ -669,7 +653,7 @@ public class TrackRecordingServiceRecordingTest {
// 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";
@@ -683,7 +667,7 @@ public class TrackRecordingServiceRecordingTest {
// 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";
@@ -692,11 +676,11 @@ public class TrackRecordingServiceRecordingTest {
// 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
@@ -717,7 +701,7 @@ public class TrackRecordingServiceRecordingTest {
null, null,
null,
Speed.of(5)))
.setSensorDistance(Distance.of(0)),
.setSensorDistance(Distance.ZERO),
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(sensor3))
.setSpeed(Speed.of(5))
.setSensorDistance(Distance.of(10)),
@@ -736,15 +720,15 @@ public class TrackRecordingServiceRecordingTest {
null, null,
null,
Speed.of(5)))
.setSensorDistance(Distance.of(0)),
.setSensorDistance(Distance.ZERO),
new TrackPoint(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.
.setSensorDistance(Distance.ZERO)
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
}
@@ -755,10 +739,23 @@ public class TrackRecordingServiceRecordingTest {
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);
}
}
@@ -111,7 +111,7 @@ 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());
}
@@ -127,7 +127,7 @@ public class TrackRecordingServiceStateMachineTest {
// 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
@@ -136,7 +136,7 @@ public class TrackRecordingServiceStateMachineTest {
// 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.
}
@@ -153,7 +153,7 @@ public class TrackRecordingServiceStateMachineTest {
// 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();
@@ -165,7 +165,7 @@ public class TrackRecordingServiceStateMachineTest {
// 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());
@@ -176,7 +176,7 @@ public class TrackRecordingServiceStateMachineTest {
// 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());
@@ -188,7 +188,7 @@ public class TrackRecordingServiceStateMachineTest {
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 +198,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,7 +207,7 @@ 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());
}
@@ -217,7 +217,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
@@ -226,7 +226,7 @@ public class TrackRecordingServiceStateMachineTest {
// 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());
}
@@ -246,7 +246,7 @@ public class TrackRecordingServiceStateMachineTest {
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());
}
@@ -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,6 +9,7 @@ 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;
@@ -19,24 +19,29 @@ 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.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.data.statistics.SensorStatistics;
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,23 +61,28 @@ 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();
track.setTrackStatistics(stats);
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
));
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
@@ -89,16 +96,26 @@ 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();
track.setTrackStatistics(stats);
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
));
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
@@ -112,16 +129,26 @@ 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();
track.setTrackStatistics(stats);
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
));
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
@@ -135,16 +162,26 @@ 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();
track.setTrackStatistics(stats);
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
));
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
@@ -159,26 +196,13 @@ 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(trackPointIterator.getCount(), numberOfPoints);
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);
// 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,16 +210,26 @@ 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();
track.setTrackStatistics(stats);
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
));
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
@@ -210,26 +244,13 @@ 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(trackPointIterator.getCount(), numberOfPoints);
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000));
intervalStatistics.addTrackPoints(trackPointIterator);
lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
}
Track track = new Track();
track.setTrackStatistics(stats);
Pair<Track, Statistics> data = buildTrackWithTrackPoints();
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
// 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,16 +258,26 @@ 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();
track.setTrackStatistics(stats);
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
));
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
@@ -260,14 +291,26 @@ 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();
track.setTrackStatistics(stats);
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
));
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
@@ -281,14 +324,26 @@ 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();
track.setTrackStatistics(stats);
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
));
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
@@ -302,14 +357,26 @@ 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();
track.setTrackStatistics(stats);
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
));
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
@@ -324,26 +391,13 @@ 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(trackPointIterator.getCount(), numberOfPoints);
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000));
intervalStatistics.addTrackPoints(trackPointIterator);
lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
}
Track track = new Track();
track.setTrackStatistics(stats);
Pair<Track, Statistics> data = buildTrackWithTrackPoints();
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
// 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,16 +405,26 @@ 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();
track.setTrackStatistics(stats);
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
));
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
@@ -375,26 +439,13 @@ 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(trackPointIterator.getCount(), numberOfPoints);
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000));
intervalStatistics.addTrackPoints(trackPointIterator);
lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
}
Track track = new Track();
track.setTrackStatistics(stats);
Pair<Track, Statistics> data = buildTrackWithTrackPoints();
SensorDataSet dataSet = Mockito.mock(SensorDataSet.class);
Mockito.when(dataSet.getHeartRate()).thenReturn(new Pair<>(HeartRate.of(60), "unused"));
// 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 +453,19 @@ 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(trackPointIterator.getCount(), numberOfPoints);
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"));
// 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 +473,7 @@ public class VoiceAnnouncementUtilsTest {
@Test
public void getAnnouncement_heart_rate() {
// given
PreferencesUtils.setVoiceAnnounceHeartRateCurrent(true);
PreferencesUtils.setVoiceAnnounceLapHeartRate(true);
PreferencesUtils.setVoiceAnnounceAverageHeartRate(true);
@@ -443,28 +483,15 @@ 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(trackPointIterator.getCount(), numberOfPoints);
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"));
// 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 +511,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);
}
}
@@ -41,7 +41,7 @@ public class PreferencesOpenHelperTest {
// then there should be one layout with old custom layout that has the new CSV value.
List<RecordingLayout> recordingLayouts = PreferencesUtils.getAllCustomLayouts();
assertNotNull(recordingLayouts);
assertEquals(recordingLayouts.size(), 1);
assertEquals(1, recordingLayouts.size());
assertEquals(recordingLayouts.get(0).toCsv(), PreferencesUtils.getCustomLayout().toCsv());
}
@@ -66,7 +66,7 @@ public class PreferencesOpenHelperTest {
// then there should be one layout with old custom layout that has the new CSV value.
List<RecordingLayout> recordingLayouts = PreferencesUtils.getAllCustomLayouts();
assertNotNull(recordingLayouts);
assertEquals(recordingLayouts.size(), 1);
assertEquals(1, recordingLayouts.size());
assertEquals(recordingLayouts.get(0).toCsv(), updatedOldCustomLayoutCsv);
}
@@ -90,8 +90,8 @@ public class PreferencesOpenHelperTest {
// then there should be one layout with old custom layout that has the new CSV value.
List<RecordingLayout> recordingLayouts = PreferencesUtils.getAllCustomLayouts();
assertNotNull(recordingLayouts);
assertEquals(recordingLayouts.size(), 1);
assertEquals(recordingLayouts.get(0).toCsv(), updatedOldCustomLayoutCsv);
assertEquals(1, recordingLayouts.size());
assertEquals(updatedOldCustomLayoutCsv, recordingLayouts.get(0).toCsv());
}
@Test
@@ -113,7 +113,7 @@ public class PreferencesOpenHelperTest {
RecordingLayout defaultRecordingLayout = RecordingLayoutIO.fromCsv(PreferencesUtils.buildDefaultLayout(), resources);
List<RecordingLayout> customRecordingLayout = PreferencesUtils.getAllCustomLayouts();
assertEquals(customRecordingLayout.size(), 1);
assertEquals(1, customRecordingLayout.size());
assertEquals(defaultRecordingLayout.toCsv(), customRecordingLayout.get(0).toCsv());
}
}
@@ -89,8 +89,8 @@ public class PreferencesUtilsTest {
List<RecordingLayout> recordingLayouts = PreferencesUtils.getAllCustomLayouts();
// then
assertEquals(recordingLayouts.size(), 1);
assertTrue(recordingLayouts.get(0).getFields().size() > 0);
assertEquals(1, recordingLayouts.size());
assertFalse(recordingLayouts.get(0).getFields().isEmpty());
assertEquals(recordingLayouts.get(0).getName(), context.getString(R.string.stats_custom_layout_default_layout));
assertTrue(recordingLayouts.get(0).getFields().stream().anyMatch(DataField::isVisible));
}
@@ -107,7 +107,7 @@ public class PreferencesUtilsTest {
RecordingLayout recordingLayout = PreferencesUtils.getCustomLayout();
// then
assertTrue(recordingLayout.getFields().size() > 0);
assertFalse(recordingLayout.getFields().isEmpty());
assertEquals(recordingLayout.getName(), context.getString(R.string.stats_custom_layout_default_layout));
assertTrue(recordingLayout.getFields().stream().anyMatch(DataField::isVisible));
}
@@ -130,9 +130,9 @@ public class PreferencesUtilsTest {
RecordingLayout recordingLayout = PreferencesUtils.getCustomLayout();
// then
assertEquals(recordingLayout.getFields().size(), 4);
assertEquals(recordingLayout.getName(), "run");
assertEquals(recordingLayout.getColumnsPerRow(), 2);
assertEquals(4, recordingLayout.getFields().size());
assertEquals("run", recordingLayout.getName());
assertEquals(2, recordingLayout.getColumnsPerRow());
assertEquals(recordingLayout.getFields().get(0).getKey(), context.getString(R.string.stats_custom_layout_moving_time_key));
assertTrue(recordingLayout.getFields().get(0).isVisible());
@@ -169,9 +169,9 @@ public class PreferencesUtilsTest {
RecordingLayout recordingLayout = PreferencesUtils.getCustomLayout();
// then
assertEquals(recordingLayout.getFields().size(), 4);
assertEquals(recordingLayout.getName(), "walking");
assertEquals(recordingLayout.getColumnsPerRow(), 2);
assertEquals(4, recordingLayout.getFields().size());
assertEquals("walking", recordingLayout.getName());
assertEquals(2, recordingLayout.getColumnsPerRow());
assertEquals(recordingLayout.getFields().get(0).getKey(), context.getString(R.string.stats_custom_layout_moving_time_key));
assertTrue(recordingLayout.getFields().get(0).isVisible());
@@ -266,11 +266,11 @@ public class PreferencesUtilsTest {
// then only updated profile is modified in the custom layouts
List<RecordingLayout> layoutsAfter = PreferencesUtils.getAllCustomLayouts();
assertEquals(layoutsBefore.size(), 2);
assertEquals(layoutsAfter.size(), 2);
assertEquals(2, layoutsBefore.size());
assertEquals(2, layoutsAfter.size());
assertEquals(layoutsBefore.get(0).getFields().stream().filter(DataField::isVisible).count(), 4);
assertEquals(layoutsAfter.get(0).getFields().stream().filter(DataField::isVisible).count(), 1);
assertEquals(4, layoutsBefore.get(0).getFields().stream().filter(DataField::isVisible).count());
assertEquals(1, layoutsAfter.get(0).getFields().stream().filter(DataField::isVisible).count());
}
@Test
@@ -309,11 +309,11 @@ public class PreferencesUtilsTest {
// then only updated profile is modified in the custom layouts
List<RecordingLayout> layoutsAfter = PreferencesUtils.getAllCustomLayouts();
assertEquals(layoutsBefore.size(), 2);
assertEquals(layoutsAfter.size(), 2);
assertEquals(2, layoutsBefore.size());
assertEquals(2, layoutsAfter.size());
assertEquals(layoutsBefore.get(0).getFields().stream().filter(DataField::isVisible).count(), 4);
assertEquals(layoutsAfter.get(0).getFields().stream().filter(DataField::isVisible).count(), 1);
assertEquals(4, layoutsBefore.get(0).getFields().stream().filter(DataField::isVisible).count());
assertEquals(1, layoutsAfter.get(0).getFields().stream().filter(DataField::isVisible).count());
}
@Test
@@ -341,6 +341,6 @@ public class PreferencesUtilsTest {
RecordingLayout recordingLayout = PreferencesUtils.getCustomLayout();
// then the first one was returned
assertEquals(recordingLayout.getName(), "cycling");
assertEquals("cycling", recordingLayout.getName());
}
}
@@ -1,193 +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.share;
import static org.junit.Assert.assertEquals;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.time.Duration;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.util.Locale;
import de.dennisguse.opentracks.LocaleRule;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.data.models.Distance;
import de.dennisguse.opentracks.data.models.Speed;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.stats.TrackStatistics;
import de.dennisguse.opentracks.util.StringUtils;
/**
* Tests for {@link DescriptionGenerator}.
*
* @author Jimmy Shih
*/
@RunWith(AndroidJUnit4.class)
public class DescriptionGeneratorTest {
@Rule
public final LocaleRule mLocaleRule = new LocaleRule(Locale.ENGLISH);
private static final Instant START_TIME = Instant.ofEpochMilli(1288721514000L);
private DescriptionGenerator descriptionGenerator;
private final Context context = ApplicationProvider.getApplicationContext();
@Before
public void setUp() {
descriptionGenerator = new DescriptionGenerator(ApplicationProvider.getApplicationContext());
}
/**
* Tests {@link DescriptionGenerator#generateTrackDescription(Track, boolean)}.
*/
@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");
String expected = //"Created by"
"<a href='https://codeberg.org/OpenTracksApp/OpenTracks'>OpenTracks (Debug)</a><p>"
+ "Name: -<br>"
+ "Activity type: hiking<br>"
+ "Description: -<br>"
+ "Total distance: 20.00 km (12.4 mi)<br>"
+ "Total time: 10:00<br>"
+ "Moving time: 05:00<br>"
+ "Average speed: 120.00 km/h (74.6 mi/h)<br>"
+ "Average moving speed: 240.00 km/h (149.1 mi/h)<br>"
+ "Max speed: 360.00 km/h (223.7 mi/h)<br>"
+ "Average pace: 0:30 min/km (0:48 min/mi)<br>"
+ "Average moving pace: 0:15 min/km (0:24 min/mi)<br>"
+ "Fastest pace: 0:10 min/km (0:16 min/mi)<br>"
+ "Max elevation: 550 m (1804 ft)<br>"
+ "Min elevation: -500 m (-1640 ft)<br>"
+ "Elevation gain: 6000 m (19685 ft)<br>"
+ "Elevation loss: 6000 m (19685 ft)<br>"
+ "Recorded: " + StringUtils.formatDateTimeWithOffset(OffsetDateTime.ofInstant(START_TIME, ZoneId.systemDefault())) + "<br>";
assertEquals(expected, descriptionGenerator.generateTrackDescription(track, true));
}
@Test
public void testGenerateTrackDescriptionWithoutMaxMinAltitude() {
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(Double.POSITIVE_INFINITY);
stats.setMinAltitude(Double.NEGATIVE_INFINITY);
stats.setTotalAltitudeGain(6000f);
stats.setTotalAltitudeLoss(6000f);
stats.setStartTime(START_TIME);
track.setTrackStatistics(stats);
track.setActivityTypeLocalized("hiking");
String expected = //"Created by"
"<a href='https://codeberg.org/OpenTracksApp/OpenTracks'>OpenTracks (Debug)</a><p>"
+ "Name: -<br>"
+ "Activity type: hiking<br>"
+ "Description: -<br>"
+ "Total distance: 20.00 km (12.4 mi)<br>"
+ "Total time: 10:00<br>"
+ "Moving time: 05:00<br>"
+ "Average speed: 120.00 km/h (74.6 mi/h)<br>"
+ "Average moving speed: 240.00 km/h (149.1 mi/h)<br>"
+ "Max speed: 360.00 km/h (223.7 mi/h)<br>"
+ "Average pace: 0:30 min/km (0:48 min/mi)<br>"
+ "Average moving pace: 0:15 min/km (0:24 min/mi)<br>"
+ "Fastest pace: 0:10 min/km (0:16 min/mi)<br>"
+ "Elevation gain: 6000 m (19685 ft)<br>"
+ "Elevation loss: 6000 m (19685 ft)<br>"
+ "Recorded: " + StringUtils.formatDateTimeWithOffset(OffsetDateTime.ofInstant(START_TIME, ZoneId.systemDefault())) + "<br>";
assertEquals(expected, descriptionGenerator.generateTrackDescription(track, true));
}
/**
* Tests {@link DescriptionGenerator#writeDistance(Distance, StringBuilder, int, String)}.
*/
@Test
public void testWriteDistance() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writeDistance(Distance.of(1100), builder, R.string.description_total_distance, "<br>");
assertEquals("Total distance: 1.10 km (0.7 mi)<br>", builder.toString());
}
/**
* Tests {@link DescriptionGenerator#writeTime(Duration, StringBuilder, int, String)}.
*/
@Test
public void testWriteTime() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writeTime(Duration.ofMillis(1000), builder, R.string.description_total_time, "<br>");
assertEquals("Total time: 00:01<br>", builder.toString());
}
/**
* Tests {@link DescriptionGenerator#writeSpeed(Speed, StringBuilder, int, String)}.
*/
@Test
public void testWriteSpeed() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writeSpeed(Speed.of(1.1), builder, R.string.description_average_speed, "\n");
assertEquals("Average speed: 3.96 km/h (2.5 mi/h)\n", builder.toString());
}
/**
* Tests {@link DescriptionGenerator#writeAltitude(double, StringBuilder, int, String)}.
*/
@Test
public void testWriteAltitude() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writeAltitude(4.2, builder, R.string.description_min_altitude, "<br>");
assertEquals("Min elevation: 4 m (14 ft)<br>", builder.toString());
}
/**
* Tests {@link DescriptionGenerator#writePace(Speed, StringBuilder, int, String)}.
*/
@Test
public void testWritePace() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writePace(Speed.of(1.1), builder, R.string.description_average_pace_in_minute, "\n");
assertEquals("Average pace: 15:09 min/km (24:23 min/mi)\n", builder.toString());
}
}
@@ -0,0 +1,145 @@
/*
* 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.share;
import static org.junit.Assert.assertEquals;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
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.util.StringUtils;
/**
* Tests for {@link TrackShareSummaryGenerator}.
*
* @author Jimmy Shih
*/
@RunWith(AndroidJUnit4.class)
public class TrackShareSummaryGeneratorTest {
@Rule
public final LocaleRule mLocaleRule = new LocaleRule(Locale.ENGLISH);
private static final Instant START_TIME = Instant.ofEpochMilli(1288721514000L);
private TrackShareSummaryGenerator descriptionGenerator;
@Before
public void setUp() {
descriptionGenerator = new TrackShareSummaryGenerator(ApplicationProvider.getApplicationContext());
}
@Test
public void testGenerateTrackDescription() {
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"
+ "Activity type: hiking\n"
+ "Description: -\n"
+ "Total distance: 20.00 km (12.4 mi)\n"
+ "Total time: 10:00\n"
+ "Moving time: 05:00\n"
+ "Average speed: 120.00 km/h (74.6 mi/h)\n"
+ "Average moving speed: 240.00 km/h (149.1 mi/h)\n"
+ "Max speed: 360.00 km/h (223.7 mi/h)\n"
+ "Average pace: 0:30 min/km (0:48 min/mi)\n"
+ "Average moving pace: 0:15 min/km (0:24 min/mi)\n"
+ "Fastest pace: 0:10 min/km (0:16 min/mi)\n"
+ "Max elevation: 550 m (1804 ft)\n"
+ "Min elevation: -500 m (-1640 ft)\n"
+ "Elevation gain: 6000 m (19685 ft)\n"
+ "Elevation loss: 6000 m (19685 ft)\n"
+ "Recorded: " + StringUtils.formatDateTimeWithOffset(OffsetDateTime.ofInstant(START_TIME, ZoneId.systemDefault())) + "\n";
assertEquals(expected, descriptionGenerator.generateTrackDescription(track));
}
@Test
public void testWriteDistance() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writeDistance(Distance.of(1100), builder, R.string.description_total_distance);
assertEquals("Total distance: 1.10 km (0.7 mi)\n", builder.toString());
}
@Test
public void testWriteTime() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writeTime(Duration.ofMillis(1000), builder, R.string.description_total_time);
assertEquals("Total time: 00:01\n", builder.toString());
}
@Test
public void testWriteSpeed() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writeSpeed(Speed.of(1.1), builder, R.string.description_average_speed);
assertEquals("Average speed: 3.96 km/h (2.5 mi/h)\n", builder.toString());
}
@Test
public void testWriteAltitude() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writeAltitude(4.2, builder, R.string.description_min_altitude);
assertEquals("Min elevation: 4 m (14 ft)\n", builder.toString());
}
@Test
public void testWritePace() {
StringBuilder builder = new StringBuilder();
descriptionGenerator.writePace(Speed.of(1.1), builder, R.string.description_average_pace_in_minute);
assertEquals("Average pace: 15:09 min/km (24:23 min/mi)\n", builder.toString());
}
}
@@ -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,50 +63,45 @@ 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));
// 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));
@@ -135,26 +114,22 @@ public class TrackStatisticsUpdaterTest {
tp5.setSensorDistance(Distance.of(10f));
// 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));
@@ -166,27 +141,22 @@ public class TrackStatisticsUpdaterTest {
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)),
@@ -194,28 +164,26 @@ public class TrackStatisticsUpdaterTest {
.setSpeed(Speed.of(2f)),
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)),
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)),
@@ -234,15 +202,13 @@ 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)),
@@ -264,72 +230,69 @@ public class TrackStatisticsUpdaterTest {
));
// 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)));
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)));
.setSensorDistance(Distance.ZERO));
// 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)));
// 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)));
// 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));
@@ -339,19 +302,36 @@ public class TrackStatisticsUpdaterTest {
tp4.setSpeed(Speed.of(5f));
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) {
@@ -1,250 +1,182 @@
package de.dennisguse.opentracks.ui.aggregatedStatistics;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.time.Duration;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.List;
import java.util.UUID;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.data.AggregatedStatistic;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.TrackSelection;
import de.dennisguse.opentracks.data.models.ActivityType;
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;
@RunWith(JUnit4.class)
public class AggregatedStatisticsTest {
private final Context context = ApplicationProvider.getApplicationContext();
private static Track createTrack(Context context, Distance totalDistance, Duration totalTime, String activityTypeLocalized) {
TrackStatistics statistics = new TrackStatistics();
statistics.setStartTime(Instant.ofEpochMilli(1000L)); // Resulting start time
statistics.setStopTime(statistics.getStartTime().plus(totalTime));
statistics.setTotalTime(totalTime);
statistics.setMovingTime(totalTime);
statistics.setTotalDistance(totalDistance);
statistics.setTotalAltitudeGain(50.0f);
statistics.setMaxSpeed(Speed.of(50.0)); // Resulting max speed
statistics.setMaxAltitude(1250.0);
statistics.setMinAltitude(1200.0); // Resulting min altitude
private static void createTrack(Context context, Distance totalDistance, Duration totalTime, String activityTypeLocalized) {
Track track = new Track(
null,
UUID.randomUUID(), //TODO Use constant UUID
"",
"",
activityTypeLocalized,
ActivityType.findByLocalizedString(context, activityTypeLocalized),
ZoneOffset.UTC,
new Statistics(
Instant.ofEpochMilli(1000),
Instant.ofEpochMilli(1000).plus(totalTime),
totalTime,
totalTime,
totalDistance,
Speed.of(50),
new AltitudeExtremities(1250, 1250),
new AltitudeGainLoss(50, 50),
null,
null
));
Track track = new Track();
track.setActivityType(ActivityType.findByLocalizedString(context, activityTypeLocalized));
track.setActivityTypeLocalized(activityTypeLocalized);
track.setTrackStatistics(statistics);
return track;
new ContentProviderUtils(context).insertTrack(track);
}
@Before
public void setUp() {
new ContentProviderUtils(context).deleteAllTracks(context);
}
@Test
public void testAggregate() {
public void testAggregate_empty() {
// when
List<AggregatedStatistic> result = new ContentProviderUtils(context).getAggregatedStatisticsForTracks(new TrackSelection());
// then
assertEquals(List.of(), result);
}
@Test
public void testAggregate_oneBikingTrack() {
// given
// 10km in 40 minutes.
Distance totalDistance = Distance.of(10000);
Duration totalTime = Duration.ofMillis(2400000);
Distance totalDistance = Distance.ofKilometer(10);
Duration totalTime = Duration.ofMinutes(40);
String biking = context.getString(R.string.activity_type_biking);
Track track = createTrack(context, totalDistance, totalTime, biking);
createTrack(context, totalDistance, totalTime, biking);
// when
AggregatedStatistics aggregatedStatistics = new AggregatedStatistics(List.of(track));
List<AggregatedStatistic> result = new ContentProviderUtils(context).getAggregatedStatisticsForTracks(new TrackSelection());
// then
assertEquals(1, aggregatedStatistics.getCount());
assertNotNull(aggregatedStatistics.get(biking));
assertEquals(1, aggregatedStatistics.get(biking).getCountTracks());
TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
assertEquals(totalDistance, statistics2.getTotalDistance());
assertEquals(totalTime, statistics2.getMovingTime());
}
@Test
public void testAggregate_mountainBiking() {
// given
// 10km in 40 minutes.
Distance totalDistance = Distance.of(10000);
Duration totalTime = Duration.ofMillis(2400000);
String mountainBiking = context.getString(R.string.activity_type_mountain_biking);
Track track = createTrack(context, totalDistance, totalTime, mountainBiking);
// when
AggregatedStatistics aggregatedStatistics = new AggregatedStatistics(List.of(track));
// then
assertNotNull(aggregatedStatistics.get(mountainBiking));
}
@Test
public void testAggregate_trailRunning() {
// given
// 10km in 40 minutes.
Distance totalDistance = Distance.of(10000);
Duration totalTime = Duration.ofMillis(2400000);
String trailRunning = context.getString(R.string.activity_type_trail_running);
Track track = createTrack(context, totalDistance, totalTime, trailRunning);
// when
AggregatedStatistics aggregatedStatistics = new AggregatedStatistics(List.of(track));
// then
assertNotNull(aggregatedStatistics.get(trailRunning));
assertEquals(List.of(
new AggregatedStatistic("biking", 1, Duration.ofMinutes(40), Distance.ofKilometer(10), Speed.of(50))
), result);
}
@Test
public void testAggregate_twoBikingTracks() {
// given
// 10km in 40 minutes.
Distance totalDistance = Distance.of(10000);
Duration totalTime = Duration.ofMillis(2400000);
Distance totalDistance = Distance.ofKilometer(10);
Duration totalTime = Duration.ofMinutes(40);
String biking = context.getString(R.string.activity_type_biking);
List<Track> tracks = List.of(createTrack(context, totalDistance, totalTime, biking), createTrack(context, totalDistance, totalTime, biking));
createTrack(context, totalDistance, totalTime, biking);
createTrack(context, totalDistance, totalTime, biking);
// when
AggregatedStatistics aggregatedStatistics = new AggregatedStatistics(tracks);
List<AggregatedStatistic> result = new ContentProviderUtils(context).getAggregatedStatisticsForTracks(new TrackSelection());
// then
assertEquals(1, aggregatedStatistics.getCount());
assertNotNull(aggregatedStatistics.get(biking));
assertEquals(2, aggregatedStatistics.get(biking).getCountTracks());
TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
assertEquals(totalDistance.multipliedBy(2), statistics2.getTotalDistance());
assertEquals(totalTime.multipliedBy(2), statistics2.getMovingTime());
}
@Test
public void testAggregate_threeDifferentTracks() {
// given
// 10km in 40 minutes.
Distance totalDistance = Distance.of(10000);
String biking = context.getString(R.string.activity_type_biking);
String running = context.getString(R.string.activity_type_running);
String walking = context.getString(R.string.activity_type_walking);
Duration totalTime = Duration.ofMillis(2400000);
List<Track> tracks = List.of(
createTrack(context, totalDistance, totalTime, biking),
createTrack(context, totalDistance, totalTime, running),
createTrack(context, totalDistance, totalTime, walking)
);
// when
AggregatedStatistics aggregatedStatistics = new AggregatedStatistics(tracks);
// then
assertEquals(3, aggregatedStatistics.getCount());
assertNotNull(aggregatedStatistics.get(biking));
assertNotNull(aggregatedStatistics.get(running));
assertNotNull(aggregatedStatistics.get(walking));
assertEquals(1, aggregatedStatistics.get(biking).getCountTracks());
assertEquals(1, aggregatedStatistics.get(running).getCountTracks());
assertEquals(1, aggregatedStatistics.get(walking).getCountTracks());
{
TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
assertEquals(totalDistance, statistics2.getTotalDistance());
assertEquals(totalTime, statistics2.getMovingTime());
}
{
TrackStatistics statistics2 = aggregatedStatistics.get(running).getTrackStatistics();
assertEquals(totalDistance, statistics2.getTotalDistance());
assertEquals(totalTime, statistics2.getMovingTime());
}
{
TrackStatistics statistics2 = aggregatedStatistics.get(walking).getTrackStatistics();
assertEquals(totalDistance, statistics2.getTotalDistance());
assertEquals(totalTime, statistics2.getMovingTime());
}
assertEquals(List.of(
new AggregatedStatistic("biking", 2, Duration.ofMinutes(80), Distance.ofKilometer(20), Speed.of(50))
), result);
}
@Test
public void testAggregate_severalTracksWithSeveralActivities() {
// given
// 10km in 40 minutes.
Distance totalDistance = Distance.of(10000);
Duration totalTime = Duration.ofMillis(2400000);
Distance totalDistance = Distance.ofKilometer(10);
Duration totalTime = Duration.ofMinutes(40);
String biking = context.getString(R.string.activity_type_biking);
String running = context.getString(R.string.activity_type_running);
String walking = context.getString(R.string.activity_type_walking);
String driving = context.getString(R.string.activity_type_driving);
List<Track> tracks = List.of(
createTrack(context, totalDistance, totalTime, biking),
createTrack(context, totalDistance, totalTime, running),
createTrack(context, totalDistance, totalTime, walking),
createTrack(context, totalDistance, totalTime, biking),
createTrack(context, totalDistance, totalTime, running),
createTrack(context, totalDistance, totalTime, walking),
createTrack(context, totalDistance, totalTime, biking),
createTrack(context, totalDistance, totalTime, biking),
createTrack(context, totalDistance, totalTime, biking),
createTrack(context, totalDistance, totalTime, driving)
);
createTrack(context, totalDistance, totalTime, biking);
createTrack(context, totalDistance, totalTime, running);
createTrack(context, totalDistance, totalTime, walking);
createTrack(context, totalDistance, totalTime, biking);
createTrack(context, totalDistance, totalTime, running);
createTrack(context, totalDistance, totalTime, walking);
createTrack(context, totalDistance, totalTime, biking);
createTrack(context, totalDistance, totalTime, biking);
createTrack(context, totalDistance, totalTime, biking);
createTrack(context, totalDistance, totalTime, driving);
// when
AggregatedStatistics aggregatedStatistics = new AggregatedStatistics(tracks);
List<AggregatedStatistic> result = new ContentProviderUtils(context).getAggregatedStatisticsForTracks(new TrackSelection());
// then
// 4 sports.
assertEquals(4, aggregatedStatistics.getCount());
assertEquals(List.of(
new AggregatedStatistic("biking", 5, Duration.ofMinutes(200), Distance.ofKilometer(50), Speed.of(50)),
new AggregatedStatistic("walking", 2, Duration.ofMinutes(80), Distance.ofKilometer(20), Speed.of(50)),
new AggregatedStatistic("running", 2, Duration.ofMinutes(80), Distance.ofKilometer(20), Speed.of(50)),
new AggregatedStatistic("driving", 1, Duration.ofMinutes(40), Distance.ofKilometer(10), Speed.of(50))
), result);
}
@Test
public void testAggregate_severalTracksWithSeveralActivities_TrackSelection() {
// given
Distance totalDistance = Distance.ofKilometer(10);
Duration totalTime = Duration.ofMinutes(40);
// There is a map for every sport.
assertNotNull(aggregatedStatistics.get(biking));
assertNotNull(aggregatedStatistics.get(running));
assertNotNull(aggregatedStatistics.get(walking));
assertNotNull(aggregatedStatistics.get(driving));
String biking = context.getString(R.string.activity_type_biking);
String running = context.getString(R.string.activity_type_running);
String walking = context.getString(R.string.activity_type_walking);
String driving = context.getString(R.string.activity_type_driving);
// Number of tracks by sport.
assertEquals(5, aggregatedStatistics.get(biking).getCountTracks()); // Biking.
assertEquals(2, aggregatedStatistics.get(running).getCountTracks()); // Running.
assertEquals(2, aggregatedStatistics.get(walking).getCountTracks()); // Walking.
assertEquals(1, aggregatedStatistics.get(driving).getCountTracks()); // Driving.
createTrack(context, totalDistance, totalTime, biking);
createTrack(context, totalDistance, totalTime, running);
createTrack(context, totalDistance, totalTime, walking);
createTrack(context, totalDistance, totalTime, biking);
createTrack(context, totalDistance, totalTime, running);
createTrack(context, totalDistance, totalTime, walking);
createTrack(context, totalDistance, totalTime, biking);
createTrack(context, totalDistance, totalTime, biking);
createTrack(context, totalDistance, totalTime, biking);
createTrack(context, totalDistance, totalTime, driving);
// Biking.
{
TrackStatistics statistics2 = aggregatedStatistics.get(biking).getTrackStatistics();
assertEquals(totalDistance.multipliedBy(5), statistics2.getTotalDistance());
assertEquals(totalTime.multipliedBy(5), statistics2.getMovingTime());
}
TrackSelection trackSelection = new TrackSelection();
trackSelection.addActivityType("biking");
trackSelection.addActivityType("driving");
// Running.
{
TrackStatistics statistics2 = aggregatedStatistics.get(running).getTrackStatistics();
assertEquals(totalDistance.multipliedBy(2), statistics2.getTotalDistance());
assertEquals(totalTime.multipliedBy(2), statistics2.getMovingTime());
}
// when
List<AggregatedStatistic> result = new ContentProviderUtils(context).getAggregatedStatisticsForTracks(trackSelection);
// Walking.
{
TrackStatistics statistics2 = aggregatedStatistics.get(walking).getTrackStatistics();
assertEquals(totalDistance.multipliedBy(2), statistics2.getTotalDistance());
assertEquals(totalTime.multipliedBy(2), statistics2.getMovingTime());
}
// Driving.
{
TrackStatistics statistics2 = aggregatedStatistics.get(driving).getTrackStatistics();
assertEquals(totalDistance, statistics2.getTotalDistance());
assertEquals(totalTime, statistics2.getMovingTime());
}
// Check order
{
assertEquals(biking, aggregatedStatistics.getItem(0).getActivityTypeLocalized());
assertEquals(driving, aggregatedStatistics.getItem(3).getActivityTypeLocalized());
}
// then
assertEquals(List.of(
new AggregatedStatistic("biking", 5, Duration.ofMinutes(200), Distance.ofKilometer(50), Speed.of(50)),
new AggregatedStatistic("driving", 1, Duration.ofMinutes(40), Distance.ofKilometer(10), Speed.of(50))
), result);
}
}
@@ -34,13 +34,14 @@ import de.dennisguse.opentracks.TrackListActivity;
import de.dennisguse.opentracks.content.data.TestDataUtil;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackBuilder;
import de.dennisguse.opentracks.data.models.TrackPoint;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class EspressoAggregatedFilterTest {
private final String CATEGORY = "category";
private final String ACTIVITY_TYPE_LOCALIZED = "activityTypeLocalized";
@Rule
public ActivityScenarioRule<TrackListActivity> mActivityTestRule = new ActivityScenarioRule<>(TrackListActivity.class);
@@ -51,8 +52,9 @@ public class EspressoAggregatedFilterTest {
@Before
public void setUp() {
Pair<Track, List<TrackPoint>> pair = TestDataUtil.createTrack(new Track.Id(System.currentTimeMillis()), 20);
pair.first.setActivityTypeLocalized(CATEGORY);
TestDataUtil.insertTrackWithLocations(new ContentProviderUtils(ApplicationProvider.getApplicationContext()), pair.first, pair.second);
TrackBuilder trackBuilder = new TrackBuilder(pair.first);
trackBuilder.setActivityTypeLocalized(ACTIVITY_TYPE_LOCALIZED);
TestDataUtil.insertTrackWithLocations(new ContentProviderUtils(ApplicationProvider.getApplicationContext()), trackBuilder.getTrack(), pair.second);
}
@Test
@@ -67,9 +69,9 @@ public class EspressoAggregatedFilterTest {
onView(withId(R.id.bottom_app_bar)).check(matches(hasDescendant(withId(R.id.aggregated_statistics_filter))));
onView(withId(R.id.aggregated_statistics_filter)).perform(click());
// check there's a checkbox with CATEGORY text
// check there's a checkbox with ACTIVITY_TYPE_LOCALIZED text
ViewInteraction checkBox = onView(
allOf(withId(R.id.filter_dialog_check_button), withText(CATEGORY),
allOf(withId(R.id.filter_dialog_check_button), withText(ACTIVITY_TYPE_LOCALIZED),
withParent(allOf(withId(R.id.filter_items),
withParent(IsInstanceOf.instanceOf(android.view.ViewGroup.class)))),
isDisplayed()));
@@ -26,11 +26,11 @@ public class CsvRecordingLayoutUtilsTest extends TestCase {
// then
assertNotNull(partsOk);
assertEquals(partsOk.size(), 4);
assertEquals(partsOk.get(0), "Layout Name");
assertEquals(partsOk.get(1), "2");
assertEquals(partsOk.get(2), "distance,1,1");
assertEquals(partsOk.get(3), "speed,1,1");
assertEquals(4, partsOk.size());
assertEquals("Layout Name", partsOk.get(0));
assertEquals("2", partsOk.get(1));
assertEquals("distance,1,1", partsOk.get(2));
assertEquals("speed,1,1", partsOk.get(3));
assertNull(partsWrong1);
assertNull(partsWrong2);
}
@@ -32,9 +32,9 @@ public class RecordingLayoutTest extends TestCase {
List<DataField> dataFieldList = recordingLayout.getFields();
// then layout and data fields are built correctly
assertEquals(recordingLayout.getName(), "running");
assertEquals(recordingLayout.getColumnsPerRow(), 2);
assertEquals(dataFieldList.size(), 4);
assertEquals("running", recordingLayout.getName());
assertEquals(2, recordingLayout.getColumnsPerRow());
assertEquals(4, dataFieldList.size());
assertEquals(dataFieldList.get(0).getKey(), context.getString(R.string.stats_custom_layout_speed_key));
assertEquals(dataFieldList.get(1).getKey(), context.getString(R.string.stats_custom_layout_distance_key));
assertEquals(dataFieldList.get(2).getKey(), context.getString(R.string.stats_custom_layout_altitude_key));
@@ -66,7 +66,7 @@ public class RecordingLayoutTest extends TestCase {
// then layout and data fields are built correctly
assertEquals(recordingLayout.getName(), PreferencesUtils.getDefaultLayoutName());
assertEquals(recordingLayout.getColumnsPerRow(), PreferencesUtils.getLayoutColumnsByDefault());
assertEquals(recordingLayout.getFields().size(), 0);
assertEquals(0, recordingLayout.getFields().size());
}
@Test
@@ -81,7 +81,7 @@ public class RecordingLayoutTest extends TestCase {
// then layout and data fields are built correctly
assertEquals(recordingLayout.getName(), PreferencesUtils.getDefaultLayoutName());
assertEquals(recordingLayout.getColumnsPerRow(), PreferencesUtils.getLayoutColumnsByDefault());
assertEquals(recordingLayout.getFields().size(), 0);
assertEquals(0, recordingLayout.getFields().size());
}
@Test
@@ -94,9 +94,9 @@ public class RecordingLayoutTest extends TestCase {
List<DataField> dataFieldList = recordingLayout.getFields();
// then layout and data fields are built correctly
assertEquals(recordingLayout.getName(), "Layout Name");
assertEquals(recordingLayout.getColumnsPerRow(), 2);
assertEquals(recordingLayout.getFields().size(), 0);
assertEquals("Layout Name", recordingLayout.getName());
assertEquals(2, recordingLayout.getColumnsPerRow());
assertEquals(0, recordingLayout.getFields().size());
}
@Test
@@ -109,9 +109,9 @@ public class RecordingLayoutTest extends TestCase {
List<DataField> dataFieldList = recordingLayout.getFields();
// then layout and data fields are built correctly
assertEquals(recordingLayout.getName(), "Layout Name");
assertEquals(recordingLayout.getColumnsPerRow(), 2);
assertEquals(recordingLayout.getFields().size(), 1);
assertEquals("Layout Name", recordingLayout.getName());
assertEquals(2, recordingLayout.getColumnsPerRow());
assertEquals(1, recordingLayout.getFields().size());
}
@Test
@@ -128,7 +128,7 @@ public class RecordingLayoutTest extends TestCase {
String csv = recordingLayout.toCsv();
// then csv is well built
assertEquals(csv, "Test Layout;2;key1,0,0,0;key2,0,1,0;key3,1,0,0;key4,1,1,0;key5,1,1,1;");
assertEquals("Test Layout;2;key1,0,0,0;key2,0,1,0;key3,1,0,0;key4,1,1,0;key5,1,1,1;", csv);
}
@Test
@@ -1,201 +0,0 @@
package de.dennisguse.opentracks.ui.intervals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.util.Pair;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.util.List;
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.Distance;
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;
@RunWith(JUnit4.class)
public class IntervalStatisticsTest {
private static final String TAG = IntervalStatisticsTest.class.getSimpleName();
private final Context context = ApplicationProvider.getApplicationContext();
private ContentProviderUtils contentProviderUtils;
@Before
public void setUp() {
contentProviderUtils = new ContentProviderUtils(context);
}
private TrackStatistics buildTrackStatistics(List<TrackPoint> trackPoints) {
TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater();
for (TrackPoint tp : trackPoints) {
trackStatisticsUpdater.addTrackPoint(tp);
}
return trackStatisticsUpdater.getTrackStatistics();
}
/**
* Tests that build method compute the distance correctly comparing the result with TrackStatisticsUpdater result.
*/
@Test
public void testBuild_1() {
// With 50 points and interval distance of 1000m.
// given
float distanceInterval = 1000f;
// when and then
whenAndThen(50, distanceInterval);
}
/**
* Tests that build method compute the distance correctly comparing the result with TrackStatisticsUpdater result.
*/
@Test
public void testBuild_2() {
// With 200 points and interval distance of 1000m.
// given
float distanceInterval = 1000f;
// when and then
whenAndThen(200, distanceInterval);
}
/**
* Tests that build method compute the distance correctly comparing the result with TrackStatisticsUpdater result.
*/
@Test
public void testBuild_3() {
// With 200 points and interval distance of 3000m.
// given
float distanceInterval = 3000f;
// when and then
whenAndThen(3000, distanceInterval);
}
/**
* Tests that build method compute the distance correctly comparing the result with TrackStatisticsUpdater result.
*/
@Test
public void testBuild_4() {
// With 1000 points and interval distance of 3000m.
// given
float distanceInterval = 3000f;
// when and then
whenAndThen(1000, distanceInterval);
}
/**
* Tests that build method compute the distance correctly comparing the result with TrackStatisticsUpdater result.
*/
@Test
public void testBuild_5() {
// With 10000 points and interval distance of 1000m.
// given
float distanceInterval = 1000f;
// when and then
whenAndThen(10000, distanceInterval);
}
@Test
public void testWithNoLossTrackPoints() {
// TrackPoints with elevation gain but without elevation loss.
// given
float distanceInterval = 1000f;
int numberOfPoints = 10000;
Track dummyTrack = new Track();
dummyTrack.setId(new Track.Id(System.currentTimeMillis()));
dummyTrack.setName("Dummy Track Without Elevation Loss");
contentProviderUtils.insertTrack(dummyTrack);
TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater();
for (int i = 0; i < numberOfPoints; i++) {
TrackPoint tp = TestDataUtil.createTrackPoint(i);
tp.setAltitudeLoss(null);
contentProviderUtils.insertTrackPoint(tp, dummyTrack.getId());
trackStatisticsUpdater.addTrackPoint(tp);
}
dummyTrack.setTrackStatistics(trackStatisticsUpdater.getTrackStatistics());
contentProviderUtils.updateTrack(dummyTrack);
Pair<Track.Id, TrackStatistics> trackWithStats = new Pair<>(dummyTrack.getId(), trackStatisticsUpdater.getTrackStatistics());
// when and then
whenAndThen(trackWithStats, numberOfPoints, distanceInterval);
}
private void whenAndThen(int numberOfPoints, float distanceInterval) {
Pair<Track.Id, TrackStatistics> trackWithStats = TestDataUtil.buildTrackWithTrackPoints(contentProviderUtils, numberOfPoints);
whenAndThen(trackWithStats, numberOfPoints, distanceInterval);
}
private void whenAndThen(Pair<Track.Id, TrackStatistics> trackWithStats, int numberOfPoints, float distanceInterval) {
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(distanceInterval));
Track.Id trackId = trackWithStats.first;
TrackStatistics trackStatistics = trackWithStats.second;
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
assertEquals(trackPointIterator.getCount(), numberOfPoints);
intervalStatistics.addTrackPoints(trackPointIterator);
}
List<IntervalStatistics.Interval> intervalList = intervalStatistics.getIntervalList();
Distance totalDistance = Distance.of(0);
float totalTime = 0L;
Float totalGain = null;
Float totalLoss = null;
for (IntervalStatistics.Interval i : intervalList) {
totalDistance = totalDistance.plus(i.getDistance());
totalTime += i.getDistance().toM() / i.getSpeed().toMPS();
if (totalGain == null) {
totalGain = i.getGain_m();
} else if (i.getGain_m() != null) {
totalGain += i.getGain_m();
}
if (totalLoss == null) {
totalLoss = i.getLoss_m();
} else if (i.getLoss_m() != null) {
totalLoss += i.getLoss_m();
}
}
// then
assertEquals(trackStatistics.getTotalDistance().toM(), totalDistance.toM(), 0.01);
assertEquals(trackStatistics.getTotalTime().toSeconds(), totalTime, 0.01);
assertEquals(intervalList.size(), (int) Math.ceil(trackStatistics.getTotalDistance().toM() / distanceInterval));
if (totalGain != null) {
assertEquals(totalGain, numberOfPoints * TestDataUtil.ALTITUDE_GAIN, 0.1);
} else {
assertTrue(intervalStatistics.getIntervalList().stream().noneMatch(IntervalStatistics.Interval::hasGain));
}
if (totalLoss != null) {
assertEquals(totalLoss, numberOfPoints * TestDataUtil.ALTITUDE_LOSS, 0.1);
} else {
assertTrue(intervalStatistics.getIntervalList().stream().noneMatch(IntervalStatistics.Interval::hasLoss));
}
for (int i = 0; i < intervalList.size() - 1; i++) {
assertEquals(intervalList.get(i).getDistance().toM(), distanceInterval, 0.001);
totalDistance = totalDistance.minus(intervalList.get(i).getDistance());
}
assertEquals(intervalList.get(intervalList.size() - 1).getDistance().toM(), totalDistance.toM(), 0.01);
}
}
@@ -0,0 +1,199 @@
package de.dennisguse.opentracks.ui.intervals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.util.Pair;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;
import de.dennisguse.opentracks.content.data.TestDataUtil;
import de.dennisguse.opentracks.data.models.ActivityType;
import de.dennisguse.opentracks.data.models.Distance;
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(JUnit4.class)
public class IntervalStatisticsUpdaterTest {
/**
* Tests that build method compute the distance correctly comparing the result with TrackStatisticsUpdater result.
*/
@Test
public void testBuild_1() {
// With 50 points and interval distance of 1000m.
// given
float distanceInterval = 1000f;
// when and then
whenAndThen(50, distanceInterval);
}
/**
* Tests that build method compute the distance correctly comparing the result with TrackStatisticsUpdater result.
*/
@Test
public void testBuild_2() {
// With 200 points and interval distance of 1000m.
// given
float distanceInterval = 1000f;
// when and then
whenAndThen(200, distanceInterval);
}
/**
* Tests that build method compute the distance correctly comparing the result with TrackStatisticsUpdater result.
*/
@Test
public void testBuild_3() {
// With 200 points and interval distance of 3000m.
// given
float distanceInterval = 3000f;
// when and then
whenAndThen(3000, distanceInterval);
}
/**
* Tests that build method compute the distance correctly comparing the result with TrackStatisticsUpdater result.
*/
@Test
public void testBuild_4() {
// With 1000 points and interval distance of 3000m.
// given
float distanceInterval = 3000f;
// when and then
whenAndThen(1000, distanceInterval);
}
/**
* Tests that build method compute the distance correctly comparing the result with TrackStatisticsUpdater result.
*/
@Test
public void testBuild_5() {
// With 10000 points and interval distance of 1000m.
// given
float distanceInterval = 1000f;
// when and then
whenAndThen(10000, distanceInterval);
}
@Test
public void testWithNoLossTrackPoints() {
// TrackPoints with elevation gain but without elevation loss.
// given
float distanceInterval = 1000f;
int numberOfPoints = 10000;
ArrayList<TrackPoint> trackPoints = new ArrayList<>();
for (int i = 0; i < numberOfPoints; i++) {
trackPoints.add(TestDataUtil.createTrackPoint(i)
.setAltitudeGainLoss(null));
}
TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater(trackPoints);
Track dummyTrack = new Track(
new Track.Id(System.currentTimeMillis()),
null,
"Dummy Track Without Elevation Loss",
null,
"",
null,
ZoneOffset.UTC,
trackStatisticsUpdater.getTrackStatistics()
);
Pair<Track, List<TrackPoint>> trackWithStats = new Pair<>(dummyTrack, trackPoints);
// when and then
whenAndThen(trackWithStats.first, trackWithStats.second, numberOfPoints, distanceInterval);
}
private void whenAndThen(int numberOfPoints, float distanceInterval) {
Pair<Track, List<TrackPoint>> trackWithStats = buildTrackWithTrackPoints(numberOfPoints);
whenAndThen(trackWithStats.first, trackWithStats.second, numberOfPoints, distanceInterval);
}
private void whenAndThen(Track track, List<TrackPoint> trackPoints, int numberOfPoints, float distanceInterval) {
IntervalStatisticsUpdater intervalStatistics = new IntervalStatisticsUpdater(Distance.of(distanceInterval));
intervalStatistics.addTrackPoints(trackPoints.iterator());
List<Statistics> intervalList = intervalStatistics.getIntervalList();
Distance totalDistance = Distance.ZERO;
float totalTime = 0L;
Float totalGain = null;
Float totalLoss = null;
for (Statistics i : intervalList) {
totalDistance = totalDistance.plus(i.totalDistance());
totalTime += i.totalDistance().toM() / i.getAverageSpeed().toMPS();
if (totalGain == null) {
totalGain = i.altitudeGainLoss() != null ? i.altitudeGainLoss().gain_m() : null;
} else if (i.altitudeGainLoss() != null) {
totalGain += i.altitudeGainLoss().gain_m();
}
if (totalLoss == null) {
totalLoss = i.altitudeGainLoss() != null ? i.altitudeGainLoss().loss_m() : null;
} else if (i.altitudeGainLoss() != null) {
totalLoss += i.altitudeGainLoss().loss_m();
}
}
// then
assertEquals(track.statistics().totalDuration().toSeconds(), totalTime, 0.01);
assertEquals(track.statistics().totalDistance().toM(), totalDistance.toM(), 0.01);
assertEquals(intervalList.size(), (int) Math.ceil(track.statistics().totalDistance().toM() / distanceInterval));
if (totalGain != null && totalLoss != null) {
assertEquals(totalGain, numberOfPoints * TestDataUtil.ALTITUDE_GAIN, 0.1);
assertEquals(totalLoss, numberOfPoints * TestDataUtil.ALTITUDE_LOSS, 0.1);
} else {
assertTrue(intervalStatistics.getIntervalList().stream().noneMatch(i -> i.altitudeGainLoss() != null));
}
for (int i = 0; i < intervalList.size() - 1; i++) {
assertEquals(intervalList.get(i).totalDistance().toM(), distanceInterval, 0.001);
totalDistance = totalDistance.minus(intervalList.get(i).totalDistance());
}
assertEquals(intervalList.get(intervalList.size() - 1).totalDistance().toM(), totalDistance.toM(), 0.01);
}
private static Pair<Track, List<TrackPoint>> buildTrackWithTrackPoints(int numberOfPoints) {
ArrayList<TrackPoint> trackPoints = new ArrayList<>();
for (int i = 0; i < numberOfPoints; i++) {
trackPoints.add(TestDataUtil.createTrackPoint(i));
}
TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater(trackPoints);
Track track = new Track(
null,
null,
"",
"",
"",
ActivityType.UNKNOWN,
ZoneOffset.UTC,
trackStatisticsUpdater.getTrackStatistics());
return new Pair<>(track, trackPoints);
}
}
@@ -1,68 +0,0 @@
package de.dennisguse.opentracks.util;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.ui.customRecordingLayout.DataField;
import de.dennisguse.opentracks.ui.customRecordingLayout.RecordingLayout;
@RunWith(AndroidJUnit4.class)
public class StatisticsUtilsTest extends TestCase {
private final Context context = ApplicationProvider.getApplicationContext();
@Test
public void testEmptyValue() {
assertEquals(context.getString(R.string.stats_empty_value_float), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_distance_key)));
assertEquals(context.getString(R.string.stats_empty_value_time), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_total_time_key)));
assertEquals(context.getString(R.string.stats_empty_value_float), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_speed_key)));
assertEquals(context.getString(R.string.stats_empty_value_time), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_moving_time_key)));
assertEquals(context.getString(R.string.stats_empty_value_float), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_average_speed_key)));
assertEquals(context.getString(R.string.stats_empty_value_float), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_max_speed_key)));
assertEquals(context.getString(R.string.stats_empty_value_float), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_average_moving_speed_key)));
assertEquals(context.getString(R.string.stats_empty_value_integer), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_altitude_key)));
assertEquals(context.getString(R.string.stats_empty_value_integer), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_gain_key)));
assertEquals(context.getString(R.string.stats_empty_value_integer), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_loss_key)));
assertEquals(context.getString(R.string.stats_empty_value_time), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_pace_key)));
assertEquals(context.getString(R.string.stats_empty_value_time), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_average_moving_pace_key)));
assertEquals(context.getString(R.string.stats_empty_value_time), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_average_pace_key)));
assertEquals(context.getString(R.string.stats_empty_value_time), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_fastest_pace_key)));
assertEquals(context.getString(R.string.stats_empty_value_coordinates), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_coordinates_key)));
assertEquals(context.getString(R.string.stats_empty_value_integer), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_heart_rate_key)));
assertEquals(context.getString(R.string.stats_empty_value_integer), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_cadence_key)));
assertEquals(context.getString(R.string.stats_empty_value_integer), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_power_key)));
}
@Test
public void testFilterVisible() {
// given
RecordingLayout recordingLayout = new RecordingLayout("profile");
recordingLayout.addField(new DataField("key1", true, true, false));
recordingLayout.addField(new DataField("key2", false, true, false));
recordingLayout.addField(new DataField("key3", true, true, false));
recordingLayout.addField(new DataField("key4", false, true, false));
recordingLayout.addField(new DataField("key5", true, true, false));
// when
RecordingLayout resultTrue = recordingLayout.toRecordingLayout(true);
RecordingLayout resultFalse = recordingLayout.toRecordingLayout(false);
// then
assertEquals(resultTrue.getFields().size(), 3);
assertTrue(resultTrue.getFields().stream().anyMatch(f -> "key1".equals(f.getKey())));
assertTrue(resultTrue.getFields().stream().anyMatch(f -> "key3".equals(f.getKey())));
assertTrue(resultTrue.getFields().stream().anyMatch(f -> "key5".equals(f.getKey())));
assertEquals(resultFalse.getFields().size(), 2);
assertTrue(resultFalse.getFields().stream().anyMatch(f -> "key2".equals(f.getKey())));
assertTrue(resultFalse.getFields().stream().anyMatch(f -> "key4".equals(f.getKey())));
}
}
@@ -38,11 +38,10 @@ import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.TextStyle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import java.util.stream.Collectors;
import de.dennisguse.opentracks.LocaleRule;
import de.dennisguse.opentracks.TimezoneRule;
@@ -133,8 +132,10 @@ public class StringUtilsTest {
@Test
public void testFormatDateTodayRelative() {
// given
ArrayList<String> shortDays = Arrays.stream(DayOfWeek.values()).map(d -> d.getDisplayName(TextStyle.FULL, Locale.getDefault())).collect(Collectors.toCollection(ArrayList::new));
ArrayList<String> shortMonths = Arrays.stream(Month.values()).map(m -> m.getDisplayName(TextStyle.SHORT, Locale.getDefault())).collect(Collectors.toCollection(ArrayList::new));
List<String> shortDays = Arrays.stream(DayOfWeek.values()).map(d -> d.getDisplayName(TextStyle.FULL, Locale.getDefault()))
.toList();
List<String> shortMonths = Arrays.stream(Month.values()).map(m -> m.getDisplayName(TextStyle.SHORT, Locale.getDefault()))
.toList();
LocalDate today = LocalDateTime.ofInstant(Instant.now(), ZoneId.systemDefault()).toLocalDate();
LocalDate yesterday = today.minusDays(1);
@@ -1,55 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<gpx xmlns="http://www.topografix.com/GPX/1/1" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:gpxtpx="http://www.garmin.com/xmlschemes/TrackPointExtension/v2" xmlns:opentracks="http://opentracksapp.com/xmlschemas/v1" xmlns:topografix="http://www.topografix.com/GPX/Private/TopoGrafix/0/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.1" creator="OpenTracks (Debug)" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.topografix.com/GPX/Private/TopoGrafix/0/1 http://www.topografix.com/GPX/Private/TopoGrafix/0/1/topografix.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v2 https://www8.garmin.com/xmlschemas/TrackPointExtensionv2.xsd http://opentracksapp.com/xmlschemas/v1 http://opentracksapp.com/xmlschemas/OpenTracks_v1.xsd">
<metadata>
<name><![CDATA[2021-01-07 22:51]]></name>
<desc><![CDATA[the description]]></desc>
</metadata>
<wpt lat="3" lon="14">
<ele>10</ele>
<time>2021-01-07T21:51:59.179Z</time>
<name><![CDATA[Marker 1]]></name>
<desc><![CDATA[Marker 1 desc]]></desc>
<type><![CDATA[Marker 1 category]]></type>
</wpt>
<wpt lat="3" lon="14.002">
<ele>10</ele>
<time>2021-01-07T21:52:01.010Z</time>
<name><![CDATA[Marker 2]]></name>
<desc><![CDATA[Marker 2 desc]]></desc>
<type><![CDATA[Marker 2 category]]></type>
</wpt>
<trk>
<name><![CDATA[2021-01-07 22:51]]></name>
<desc><![CDATA[the description]]></desc>
<type><![CDATA[the category]]></type>
<extensions>
<topografix:color>c0c0c0</topografix:color>
<opentracks:trackid>7002101e-4198-4613-8c24-544e01ca3981</opentracks:trackid>
</extensions>
<trkseg>
<trkpt lat="3" lon="14">
<ele>10</ele>
<time>2021-01-07T21:51:59.179Z</time>
</trkpt>
<trkpt lat="3" lon="14.001">
<ele>10</ele>
<time>2021-01-07T21:52:00.653Z</time>
</trkpt>
<trkpt lat="3" lon="14.002">
<ele>10</ele>
<time>2021-01-07T21:52:01.010Z</time>
</trkpt>
<trkpt lat="100" lon="0">
<time>2021-01-07T21:52:02.658Z</time>
</trkpt>
<trkpt lat="200" lon="0">
<time>2021-01-07T21:52:03.873Z</time>
</trkpt>
<trkpt lat="3" lon="14.003">
<ele>10</ele>
<time>2021-01-07T21:52:04.103Z</time>
</trkpt>
</trkseg>
</trk>
</gpx>
@@ -74,7 +74,6 @@ Average moving pace: 0:00 min/km (0:00 min/mi)
Fastest pace: 0:00 min/km (0:00 min/mi)
Max elevation: -9223372036854775808 m (-9223372036854775808 ft)
Min elevation: 9223372036854775807 m (9223372036854775807 ft)
Elevation gain: 0 m (0 ft)
Max grade: 0 %
Min grade: 0 %
Recorded: 6/23 11:29]]></description>
@@ -126,11 +125,6 @@ Recorded: 6/23 11:29]]></description>
<gx:value>0.15777911</gx:value>
<gx:value>0.0</gx:value>
</gx:SimpleArrayData>
<gx:SimpleArrayData name="elevation_gain">
<gx:value>0.0</gx:value>
<gx:value>0.0</gx:value>
<gx:value>0.0</gx:value>
</gx:SimpleArrayData>
</SchemaData>
</ExtendedData>
</gx:Track>
@@ -148,14 +142,6 @@ Recorded: 6/23 11:29]]></description>
<gx:value>0.0</gx:value>
<gx:value>0.0</gx:value>
</gx:SimpleArrayData>
<gx:SimpleArrayData name="elevation_gain">
<gx:value>0.0</gx:value>
<gx:value>0.0</gx:value>
<gx:value>0.0</gx:value>
<gx:value>0.0</gx:value>
<gx:value>0.0</gx:value>
<gx:value>0.0</gx:value>
</gx:SimpleArrayData>
</SchemaData>
</ExtendedData>
</gx:Track>
@@ -179,7 +165,6 @@ Average moving pace: 0:00 min/km (0:00 min/mi)
Fastest pace: 0:00 min/km (0:00 min/mi)
Max elevation: 469 m (1540 ft)
Min elevation: 419 m (1376 ft)
Elevation gain: 0 m (0 ft)
Recorded: 11/28 18:06]]></description>
<TimeStamp>
<when>2020-11-28T17:07:20.870Z</when>
-15
View File
@@ -395,21 +395,6 @@ limitations under the License.
android:icon="@drawable/ic_logo_color_24dp"
android:label="@string/recording_service" />
<service
android:name=".io.file.exporter.ExportService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE" />
<service
android:name=".io.file.importer.ImportService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE" />
<service
android:name=".services.TrackDeleteService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE"/>
<!--Necessary for SDK < 33 to (re-)store per app locale information-->
<service
android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"

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