forked from upstream-mirrors/OpenTracks
Compare commits
325 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ecfcc180b9 | |||
| 9c1af67e7e | |||
| 873422540f | |||
| 6cf0b26058 | |||
| a94b227767 | |||
| c820a76102 | |||
| e61b065f2b | |||
| 24d8e976da | |||
| 79e45f7aea | |||
| 72f7b12da6 | |||
| 9973dd05bd | |||
| 41072a8981 | |||
| b1dcdf326c | |||
| c271dd32ac | |||
| 5dfa867034 | |||
| ada0f88538 | |||
| 4df0e2a65c | |||
| 9e7e8c60a6 | |||
| 1075021e21 | |||
| b5acfa022d | |||
| 6fe38453b3 | |||
| 2692cc553c | |||
| 3db4dc9422 | |||
| 01bb4429ad | |||
| ca817e789e | |||
| 7bf2110a54 | |||
| 78662a330f | |||
| 8bfaa1d542 | |||
| 5a1bee13f9 | |||
| b01045abe4 | |||
| d7fbae9321 | |||
| ab5e6cbfcd | |||
| 0848897ed0 | |||
| 1e4e7b8c15 | |||
| 7ca6925e7d | |||
| 5c06c7548f | |||
| 8001c03a74 | |||
| 30f9b6ffdc | |||
| a7fd6b8dfa | |||
| cc93384d1f | |||
| 78519883c0 | |||
| 29051ac978 | |||
| cf32c81035 | |||
| 094c97f78d | |||
| 8dca84456b | |||
| f962f27309 | |||
| 2f0826baf6 | |||
| b7ff0e2fac | |||
| fe6ef29f75 | |||
| 152cf72e8a | |||
| 4fd66a3830 | |||
| 9f715207e1 | |||
| e63ddbc7ae | |||
| 06e5545ac0 | |||
| 65413e0304 | |||
| 5e268463e1 | |||
| d31ffad2c9 | |||
| 46925a4c67 | |||
| 2a1aeb5dd8 | |||
| 454d5d16b5 | |||
| 45f51ff2dd | |||
| 785511913c | |||
| b937e8ad9b | |||
| 40534cd7f5 | |||
| f50b1c2f6c | |||
| 7c19621bfb | |||
| 7c06327084 | |||
| 19a958ccbb | |||
| 2dc362c105 | |||
| 708245bd50 | |||
| f4c07463b3 | |||
| d8ffc1318f | |||
| 5998f9127d | |||
| 40fb9b05bc | |||
| 8219bfe428 | |||
| bcdea5b08b | |||
| 5e49a38dce | |||
| 32e07c9d1f | |||
| efc37527f3 | |||
| 90a2710138 | |||
| bf4dd96235 | |||
| f578c6bc19 | |||
| a97bf6b883 | |||
| 838f3dc622 | |||
| 8ae4d75708 | |||
| 0c6813aca1 | |||
| 05bd2e6a71 | |||
| 8cad813d56 | |||
| 52626d5886 | |||
| c238aa7c6d | |||
| 019568144a | |||
| 9abe3cf05b | |||
| 1099102e29 | |||
| f64c1feb1a | |||
| e1d3b04dd0 | |||
| 619b82a23e | |||
| d18c67a648 | |||
| 0eda1eed1d | |||
| 1df1fe699a | |||
| 9a7183738f | |||
| 864bc8fad9 | |||
| 5ea651d340 | |||
| 7484ab03ce | |||
| 7caf33fb66 | |||
| 88c4e1a109 | |||
| 0645628d7e | |||
| cf993b73d7 | |||
| d49386259a | |||
| 10f00c4c99 | |||
| 2ca69df447 | |||
| 1a125ca60d | |||
| 5053c41bec | |||
| 46cf7f9acf | |||
| 522d8b41d8 | |||
| 43e1c99642 | |||
| 81d516d11a | |||
| b8ce386556 | |||
| bda8a9ea83 | |||
| 79b3e4ea5b | |||
| 1e15222e99 | |||
| 58b1396d64 | |||
| a9f1381dae | |||
| e508c53ca9 | |||
| d691c958b9 | |||
| bc1edec372 | |||
| 11de7d5868 | |||
| 44e8cd1491 | |||
| 9dac5d3e72 | |||
| cd7bf36aa9 | |||
| ab07d3b130 | |||
| 8b5320e40e | |||
| ef15632d7b | |||
| f5ce76955b | |||
| 3701b61852 | |||
| 3b8a243f55 | |||
| e19f55a618 | |||
| 9e6a787ed9 | |||
| 9626c5dd0b | |||
| 1e42ef5e6c | |||
| e5792336a8 | |||
| 9d4ec8ba2a | |||
| e928adf3b5 | |||
| f061243a7d | |||
| 1d623a076f | |||
| 13ed210933 | |||
| eba4918b01 | |||
| 9bde8944b9 | |||
| 1163f74b98 | |||
| c4b8082efc | |||
| 1fb8fc6a09 | |||
| dbc29a88ce | |||
| 05af52a21b | |||
| 1a5de37f8a | |||
| 015ddabf3a | |||
| 12a008a99a | |||
| 99ccf65cc2 | |||
| a159d4c375 | |||
| 01ac31716a | |||
| cfb2d0c2d3 | |||
| c05fa638a0 | |||
| 519f2b016e | |||
| 5cd6992c90 | |||
| 1631836327 | |||
| 07074ad260 | |||
| 8c20d5583a | |||
| 39bce2a487 | |||
| a221194ab1 | |||
| 55d3502ff9 | |||
| 0cd22a8ba0 | |||
| aff4bce3fe | |||
| bb290e2ee4 | |||
| 6d04659370 | |||
| 7193171a09 | |||
| 7d0d87e962 | |||
| d6cc7a0321 | |||
| c7bbaddc06 | |||
| 9af213fd12 | |||
| 77f56a5376 | |||
| ea5ac186d0 | |||
| 84c51ba8bb | |||
| 89f9f25c55 | |||
| f8cc257895 | |||
| ba66c45005 | |||
| 24b638aa30 | |||
| 45125bcda3 | |||
| 3359a30907 | |||
| 6f822afc71 | |||
| 230e97147c | |||
| b4ce99440a | |||
| 4d333bbafa | |||
| 0ee1c77680 | |||
| 183b47a1ea | |||
| 6fe6cee475 | |||
| 52228d44a9 | |||
| bc84e8cb9a | |||
| fb9e67ae85 | |||
| 8877f3fe14 | |||
| 963a37b877 | |||
| 3be1348df1 | |||
| 530967f4f6 | |||
| 25e590da02 | |||
| 0be4b25508 | |||
| 4c7d9384fb | |||
| 101701c6ff | |||
| 8f003e2f7f | |||
| 03d825d2ec | |||
| 0977d34889 | |||
| 6dee9884ff | |||
| 7b44b42def | |||
| ad712f28c6 | |||
| b287967bc4 | |||
| 29c72802aa | |||
| f5241e8046 | |||
| 1e720b2fa7 | |||
| 19382f19c4 | |||
| 14b8ab21db | |||
| 00b0e1face | |||
| 7f9057c519 | |||
| 02cec48ae4 | |||
| 0d45efdf07 | |||
| b6d935cf34 | |||
| 3228f58187 | |||
| 1e27542aea | |||
| fd7892bdf7 | |||
| 2ae8a753c9 | |||
| bb7efaa87c | |||
| 2eab7425f2 | |||
| a19bbd6153 | |||
| b523b8af9e | |||
| e9a71a10f6 | |||
| a0d69b589b | |||
| 71af495835 | |||
| ed4fb30b35 | |||
| 7f1c014bf8 | |||
| affa72fad7 | |||
| 14a14cd91f | |||
| ff89d2c5ec | |||
| 54f1690478 | |||
| 681058c3e6 | |||
| d93e025963 | |||
| 1f0a99c49a | |||
| 976d4f848f | |||
| 540a3340b3 | |||
| 2b4c68f3ec | |||
| 90d55e419e | |||
| ac31f4fd6a | |||
| 32a75bb479 | |||
| d32f1e05ec | |||
| defd6aed85 | |||
| 7463dc703c | |||
| 2ab04da936 | |||
| 6b84d3b9ba | |||
| 78b57cdc67 | |||
| 35de5b6b26 | |||
| d6da5f0862 | |||
| c3d55127fe | |||
| b1032f898a | |||
| d4a3762641 | |||
| ce5eec6a68 | |||
| cf71829bec | |||
| 39606ccd9f | |||
| 9dd67e4db7 | |||
| 212345dea1 | |||
| 08ba7d50c7 | |||
| 62401b2c5c | |||
| 7cfdacecc3 | |||
| 8f2e234c63 | |||
| dcd101a20a | |||
| cb5f3ace5a | |||
| 8e889fbce2 | |||
| ec390c4a81 | |||
| 30e9e930ab | |||
| 3719d9ac8f | |||
| e33cfa8666 | |||
| 8ff1db6a23 | |||
| a9228017fc | |||
| 41e5e71804 | |||
| 9f858168f8 | |||
| cfdcea2d88 | |||
| 2d2db41c5d | |||
| 2c73d0645a | |||
| ed1027eccc | |||
| 0dec17eba5 | |||
| 774d701a09 | |||
| 23bcbf09a5 | |||
| 115966cbdf | |||
| 1862bcc6f4 | |||
| 900910e9f7 | |||
| 45571c68c9 | |||
| 083b620e41 | |||
| 2f7a56bb17 | |||
| d8988663cb | |||
| c742dae6e0 | |||
| 292437e6bd | |||
| 8e9cde7222 | |||
| d07ab3cc22 | |||
| 90493ae498 | |||
| f6b994572a | |||
| 24826ff442 | |||
| d97e5ab1ef | |||
| 52a110d998 | |||
| 12e18b0bcd | |||
| 66dac4b0ca | |||
| 1bb8cbb82a | |||
| 2f5b7b63e4 | |||
| 58ca78b976 | |||
| 8079a25a42 | |||
| 0527e4ab14 | |||
| b6b4c5aa39 | |||
| 8c5c9d7947 | |||
| eac3d4b3db | |||
| d7bc550b29 | |||
| d76d5673a8 | |||
| 847be686ea | |||
| 1e3445cfa2 | |||
| d0f7939f1a | |||
| 000b8149f8 | |||
| 05ffa5a373 | |||
| e92f1107aa | |||
| 2ad1fab670 | |||
| 8c04129ef9 | |||
| 400d9fe948 | |||
| 5d79510750 | |||
| 18bb64580f | |||
| 7adebfc0d1 |
@@ -1,4 +1,5 @@
|
|||||||
# These are supported funding model platforms
|
# These are supported funding model platforms
|
||||||
|
|
||||||
liberapay: OpenTracks
|
liberapay: OpenTracks
|
||||||
|
github: [rgmf, pstorch, dennisguse]
|
||||||
custom: https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore
|
custom: https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore
|
||||||
|
|||||||
@@ -23,4 +23,5 @@ If applicable:
|
|||||||
**Technical information**
|
**Technical information**
|
||||||
- Device: [e.g. Nexus 7 (2013)]
|
- Device: [e.g. Nexus 7 (2013)]
|
||||||
- OS: [e.g. LineageOS 15.1]
|
- OS: [e.g. LineageOS 15.1]
|
||||||
- Version [e.g. v3.2.4]
|
- OpenTracks version: [e.g. v3.2.4]
|
||||||
|
- OpenTracks commit id (only for nightly builds): [e.g. 4b333bb]
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v2.3.4
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- uses: actions/setup-java@v2
|
- uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
@@ -29,6 +29,6 @@ jobs:
|
|||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: OpenTracks-nightly.apk
|
name: OpenTracks-nightly.apk
|
||||||
path: ./build/outputs/apk/nightly/OpenTracks-nightly.apk
|
path: ./build/outputs/apk/nightly/*.apk
|
||||||
retention-days: 7
|
retention-days: 7
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
name: Linting
|
name: Linting
|
||||||
|
|
||||||
on: [ push ]
|
on:
|
||||||
|
push:
|
||||||
|
pull_request_target:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
analyse:
|
analyse:
|
||||||
@@ -9,7 +11,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2.3.4
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- uses: actions/setup-java@v2
|
- uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -1,17 +1,21 @@
|
|||||||
#https://github.com/marketplace/actions/android-emulator-runner
|
#https://github.com/marketplace/actions/android-emulator-runner
|
||||||
name: Test
|
name: Test
|
||||||
on: [ push ]
|
on:
|
||||||
|
push:
|
||||||
|
pull_request_target:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
timeout-minutes: 45
|
timeout-minutes: 45
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
api-level: [ 23, 26 ] #TODO Re-enable 29
|
api-level: [ 23, 30 ]
|
||||||
target: [ default ]
|
target: [ default ]
|
||||||
|
fail-fast: false
|
||||||
steps:
|
steps:
|
||||||
- name: checkout
|
- name: checkout
|
||||||
uses: actions/checkout@v2.3.4
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- uses: actions/setup-java@v2
|
- uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
@@ -19,7 +23,7 @@ jobs:
|
|||||||
java-version: '11'
|
java-version: '11'
|
||||||
|
|
||||||
- name: run tests
|
- name: run tests
|
||||||
uses: reactivecircus/android-emulator-runner@v2.20.0
|
uses: reactivecircus/android-emulator-runner@v2.23.0
|
||||||
with:
|
with:
|
||||||
api-level: ${{ matrix.api-level }}
|
api-level: ${{ matrix.api-level }}
|
||||||
target: ${{ matrix.target }}
|
target: ${{ matrix.target }}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ captures/
|
|||||||
.idea/dictionaries
|
.idea/dictionaries
|
||||||
.idea/libraries
|
.idea/libraries
|
||||||
.idea/caches
|
.idea/caches
|
||||||
|
.idea/misc.xml
|
||||||
|
|
||||||
|
|
||||||
# IntelliJ IDEA
|
# IntelliJ IDEA
|
||||||
@@ -69,6 +70,7 @@ captures/
|
|||||||
.idea/jarRepositories.xml
|
.idea/jarRepositories.xml
|
||||||
.idea/markdown-navigator-enh.xml
|
.idea/markdown-navigator-enh.xml
|
||||||
.idea/markdown-navigator.xml
|
.idea/markdown-navigator.xml
|
||||||
|
.idea/deploymentTargetDropDown.xml
|
||||||
|
|
||||||
# Keystore files
|
# Keystore files
|
||||||
*.jks
|
*.jks
|
||||||
|
|||||||
Generated
-9
@@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectType">
|
|
||||||
<option name="id" value="Android" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@@ -6,7 +6,8 @@ _OpenTracks_ is a sport tracking application that completely respects your priva
|
|||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Free</th>
|
<th>Free (F-Droid)</th>
|
||||||
|
<th>Free (Nightly for F-Droid)</th>
|
||||||
<th>Donations</th>
|
<th>Donations</th>
|
||||||
<th>Translations</th>
|
<th>Translations</th>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -16,6 +17,11 @@ _OpenTracks_ is a sport tracking application that completely respects your priva
|
|||||||
<img alt="Get it on F-Droid" src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" height="60" align="middle">
|
<img alt="Get it on F-Droid" src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" height="60" align="middle">
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://fdroid.storchp.de/fdroid/repo?fingerprint=99985A7E73DCB0B16C9BDDCE7A0B4996F88068AE7C771ED53E217E69CD1FF196">
|
||||||
|
<img alt="Nightly builds (for F-Droid client)" src="https://opentracksapp.com/static/img/fdroid.storchp.de.png" height="90" align="middle">
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="https://liberapay.com/OpenTracks/donate">
|
<a href="https://liberapay.com/OpenTracks/donate">
|
||||||
<img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg" height="45" align="middle">
|
<img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg" height="45" align="middle">
|
||||||
@@ -31,14 +37,16 @@ _OpenTracks_ is a sport tracking application that completely respects your priva
|
|||||||
<td align="center">
|
<td align="center">
|
||||||
<img alt="OpenTracks version published on F-Droid" src="https://img.shields.io/f-droid/v/de.dennisguse.opentracks.svg" align="middle" >
|
<img alt="OpenTracks version published on F-Droid" src="https://img.shields.io/f-droid/v/de.dennisguse.opentracks.svg" align="middle" >
|
||||||
</td>
|
</td>
|
||||||
|
<td></td>
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="bitcoin:bc1qckpls3lpjlcpyxzm66hcy65hnesas9zgacy6yc">
|
<a href="bitcoin:bc1qckpls3lpjlcpyxzm66hcy65hnesas9zgacy6yc">
|
||||||
<img alt="bitcoin:bc1qckpls3lpjlcpyxzm66hcy65hnesas9zgacy6yc" src="promotion/donations-bitcoin.png" height="90" align="middle">
|
<img alt="bitcoin:bc1qckpls3lpjlcpyxzm66hcy65hnesas9zgacy6yc" src="promotion/donations-bitcoin.png" height="90" align="middle">
|
||||||
</a>
|
</a>
|
||||||
</td align="center">
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
<td></td>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td align="center">
|
<td align="center">
|
||||||
<a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore">
|
<a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore">
|
||||||
@@ -47,6 +55,16 @@ _OpenTracks_ is a sport tracking application that completely respects your priva
|
|||||||
</td>
|
</td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td align="center">
|
||||||
|
<a href="https://www.amazon.de/dp/B09K2KNQ7X/">
|
||||||
|
<img alt="Get it on Amazon App Store" src="https://images-na.ssl-images-amazon.com/images/G/01/mobile-apps/devportal2/res/images/amazon-appstore-badge-english-white.png" height="40" align="middle">
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
@@ -69,7 +87,7 @@ _OpenTracks_ is a sport tracking application that completely respects your priva
|
|||||||
* __Photos and Markers:__ mark interesting locations while tracking
|
* __Photos and Markers:__ mark interesting locations while tracking
|
||||||
* __Export:__
|
* __Export:__
|
||||||
* export tracks either as KMZ (incl. photos), KML, or GPX
|
* export tracks either as KMZ (incl. photos), KML, or GPX
|
||||||
* export automatically after each recording (e.g., to sync)
|
* export automatically after each recording (e.g., to sync via [Nextcloud](https://nextcloud.com/))
|
||||||
* avoid duplication: each exported file contain a random unique identifier (i.e., `opentracks:trackid`)
|
* avoid duplication: each exported file contain a random unique identifier (i.e., `opentracks:trackid`)
|
||||||
* __Altitude:__
|
* __Altitude:__
|
||||||
* gain/loss via barometric sensor (if present)
|
* gain/loss via barometric sensor (if present)
|
||||||
@@ -80,6 +98,8 @@ _OpenTracks_ is a sport tracking application that completely respects your priva
|
|||||||
* cycling: cadence
|
* cycling: cadence
|
||||||
* cycling: power meter
|
* cycling: power meter
|
||||||
* running: speed and cadence
|
* running: speed and cadence
|
||||||
|
* support for BLE sensor training only (i.e., without GPS) for indoor training
|
||||||
|
|
||||||
An overview of tested sensors: [README_TESTED_SENSORS.md](README_TESTED_SENSORS.md)
|
An overview of tested sensors: [README_TESTED_SENSORS.md](README_TESTED_SENSORS.md)
|
||||||
|
|
||||||
### Gadgetbridge integration
|
### Gadgetbridge integration
|
||||||
@@ -97,16 +117,34 @@ OpenTracks can be used with [Gadgetbridge](https://www.gadgetbridge.org/):
|
|||||||
__Only required permission:__
|
__Only required permission:__
|
||||||
* _ACCESS_FINE_LOCATION_: required to use the GPS.
|
* _ACCESS_FINE_LOCATION_: required to use the GPS.
|
||||||
|
|
||||||
An overview of Bluetooth LE sensors that are known to work with OpenTracks is in [README_TESTED_SENSORS.md](README_TESTED_SENSORS.md).
|
### API
|
||||||
|
|
||||||
|
OpenTracks includes an API for starting/stopping recording by another installed application (e.g., [Automate](https://llamalab.com/automate/), [Tasker](https://tasker.joaoapps.com), or [Easer](https://github.com/renyuneyun/Easer)).
|
||||||
|
The API can be invoked by sending an explicit Intent to start an activity.
|
||||||
|
|
||||||
|
`Package` (depends on the variant installed):
|
||||||
|
* F-Droid: `de.dennisguse.opentracks`
|
||||||
|
* GooglePlay: `de.dennisguse.opentracks.playStore`
|
||||||
|
* Debug: `de.dennisguse.opentracks.debug`
|
||||||
|
* Nightly: `de.dennisguse.opentracks.nightly`
|
||||||
|
|
||||||
|
`Class`:
|
||||||
|
* **Start a recording:** `de.dennisguse.opentracks.publicapi.StartRecording`
|
||||||
|
|
||||||
|
For testing via adb: `adb shell am start -n "package/class"`
|
||||||
|
|
||||||
|
The Start/Stop API is disabled by default to protect the user's privacy, but it can easily be enabled in the settings.
|
||||||
|
|
||||||
## Custom Dashboards (incl. map)
|
## Custom Dashboards (incl. map)
|
||||||
As of v3.3.1, OpenTracks supports custom dashboards.
|
As of v3.3.1, OpenTracks supports custom dashboards for displaying previously recorded and live tracks.
|
||||||
The reference implementation is [OSMDashboard](https://github.com/OpenTracksApp/OSMDashboard), which presents an OpenStreetMap map (showing the current track, incl. updates).
|
|
||||||
The developer documentation is in [README_API.md](README_API.md).
|
The reference implementation is [OSMDashboard](https://github.com/OpenTracksApp/OSMDashboard), which presents an OpenStreetMap map (showing the current track, incl. updates). The Dashboard API is also used by [Gadgetbridge](https://codeberg.org/Freeyourgadget/Gadgetbridge/) for displaying live track statistics on supported wearables.
|
||||||
|
|
||||||
Alternatively, recorded tracks can be shared as KMZ/GPX with installed applications (e.g., [OsmAnd](https://play.google.com/store/apps/details?id=net.osmand)).
|
Alternatively, recorded tracks can be shared as KMZ/GPX with installed applications (e.g., [OsmAnd](https://play.google.com/store/apps/details?id=net.osmand)).
|
||||||
However, this is rather slow and does not provide updates while recording.
|
However, this is rather slow and does not provide updates while recording.
|
||||||
|
|
||||||
|
The developer documentation is in [README_API.md](README_API.md).
|
||||||
|
|
||||||
## Project history
|
## Project history
|
||||||
|
|
||||||
_OpenTracks_ is based upon Google _My Tracks app_ ([code](https://code.google.com/archive/p/mytracks/)).
|
_OpenTracks_ is based upon Google _My Tracks app_ ([code](https://code.google.com/archive/p/mytracks/)).
|
||||||
|
|||||||
+12
-5
@@ -4,11 +4,13 @@
|
|||||||
OpenTracks by itself only provides basic features for data visualization and also lacks functionality for analytics.
|
OpenTracks by itself only provides basic features for data visualization and also lacks functionality for analytics.
|
||||||
By itself OpenTracks provides a basic dashboard that can show summary of a track (while recording as well as afterwards).
|
By itself OpenTracks provides a basic dashboard that can show summary of a track (while recording as well as afterwards).
|
||||||
Although this might be (mostly) sufficient, it has some limitations.
|
Although this might be (mostly) sufficient, it has some limitations.
|
||||||
This include limited configurability (e.g., ordering of shown elements) and the lack of Internet access.
|
This includes limited configurability (e.g., ordering of shown elements) and the lack of internet access.
|
||||||
In fact, the later is considered a feature but severely limits the implementation presenting a map (at least in an easy way).
|
In fact, the latter is considered a feature but severely limits the implementation presenting a map (at least in an easy way).
|
||||||
|
|
||||||
For the time being, the OpenTracks Data API can be used to implement mainly custom dashboards.
|
For the time being, the OpenTracks Data API can be used to implement mainly custom dashboards.
|
||||||
|
|
||||||
|
The Data API is disabled by default to protect the user's privacy, but it can easily be enabled in the settings.
|
||||||
|
|
||||||
## Implementation
|
## Implementation
|
||||||
OpenTracks by default does not expose any data to 3rd-party applications.
|
OpenTracks by default does not expose any data to 3rd-party applications.
|
||||||
On the request of the user (i.e., pressing a button), an Intent is created that exposes the `Track` data (it's summary), the `TrackPoint`s, and the `Waypoint`s of one or more selected tracks.
|
On the request of the user (i.e., pressing a button), an Intent is created that exposes the `Track` data (it's summary), the `TrackPoint`s, and the `Waypoint`s of one or more selected tracks.
|
||||||
@@ -17,10 +19,15 @@ These URIs notify observers if on content changes (e.g., a new `TrackPoint` was
|
|||||||
|
|
||||||
Limitations:
|
Limitations:
|
||||||
* only tracks selected by the user are exposed,
|
* only tracks selected by the user are exposed,
|
||||||
* `Waypoints` are not exposed,
|
* `Waypoint`s are not exposed,
|
||||||
* access is only granted temporarily and automatically revoked (see `FLAG_GRANT_READ_URI_PERMISSION`),
|
* access is only granted temporarily and automatically revoked (see `FLAG_GRANT_READ_URI_PERMISSION`),
|
||||||
* no write access is possible, and
|
* no write access is possible
|
||||||
* neither track recordings can be started, paused, or stopped.
|
|
||||||
|
The Data API can also be started automatically by leveraging Extra fields in the explicit Intent for the Start/Stop API.
|
||||||
|
An application that's starting a recording with an explicit Intent can add the `STATS_TARGET_PACKAGE` and `STATS_TARGET_CLASS` Extra fields to let OpenTracks know it wants to receive the Data API URIs.
|
||||||
|
OpenTracks will then (if enabled in the settings) automatically return an explicit Intent to the Package + Class as defined in the received Extra fields, including the Data API URIs and read permissions.
|
||||||
|
|
||||||
|
By using explicit Intents for the calls and URIs with specific temporary read permissions, OpenTracks tries to protect against data leaking as much as possible.
|
||||||
|
|
||||||
All required information can be found in `IntentDashboardUtils.java`.
|
All required information can be found in `IntentDashboardUtils.java`.
|
||||||
|
|
||||||
|
|||||||
+31
-12
@@ -1,6 +1,6 @@
|
|||||||
# Overview of tested Bluetooth LE sensors
|
# Overview of tested Bluetooth LE sensors
|
||||||
|
|
||||||
## HRS: Heartrate Service
|
## 0x180D: Heartrate Service
|
||||||
|
|
||||||
* Decathlon|Geonaute|Kalenji Dual HRM Belt
|
* Decathlon|Geonaute|Kalenji Dual HRM Belt
|
||||||
* moofit heart rate monitor
|
* moofit heart rate monitor
|
||||||
@@ -13,30 +13,28 @@
|
|||||||
* Amazfit Neo. But first you have to enable "Discoverable" and "Activity heart rate sharing" in the official Zepp app. (after pairing with OpenTracks you can disable them again)
|
* Amazfit Neo. But first you have to enable "Discoverable" and "Activity heart rate sharing" in the official Zepp app. (after pairing with OpenTracks you can disable them again)
|
||||||
* Garmin HRM-Dual (Reference: 010-12883-00)
|
* Garmin HRM-Dual (Reference: 010-12883-00)
|
||||||
|
|
||||||
## CSCP: Cycling Cadence and Speed Service
|
## 0x1816: Cycling Cadence and Speed Service
|
||||||
|
|
||||||
Please note that the according to the specification these sensors _may_ provide speed as well as cadence.
|
Please note that the according to the specification these sensors _may_ provide speed as well as cadence.
|
||||||
However, often only one value is provided.
|
However, often only one value is provided.
|
||||||
|
|
||||||
### Speed
|
### Speed & Cadence
|
||||||
|
|
||||||
|
* Wahoo Blue SC
|
||||||
|
|
||||||
|
### Speed only
|
||||||
|
|
||||||
* Garmin Speed Sensor 2
|
* Garmin Speed Sensor 2
|
||||||
* Has updatable firmware that requires an account for garmin.com
|
* Has updatable firmware that requires an account for garmin.com
|
||||||
* This sensor reports speed data as cadence.
|
|
||||||
A workaround is in place.
|
|
||||||
|
|
||||||
* Wahoo Speed (Model: WFRPMSPD)
|
* Wahoo Speed (Model: WFRPMSPD)
|
||||||
|
|
||||||
* CooSpo cadence and speed sensor (model: BK467)
|
* CooSpo cadence and speed sensor (model: BK467)
|
||||||
|
|
||||||
### Cadence
|
### Cadence only
|
||||||
|
|
||||||
* Garmin Cadence Sensor 2
|
* Garmin Cadence Sensor 2
|
||||||
* Wahoo Cadence (Model: WFPODCAD2)
|
* Wahoo Cadence (Model: WFPODCAD2)
|
||||||
This sensor reports cadence data as speed.
|
|
||||||
A workaround is in place.
|
|
||||||
|
|
||||||
## Cycling Power Measurement
|
## 0x1818: Power Measurement
|
||||||
|
|
||||||
We only support _Instantaneous Power_.
|
We only support _Instantaneous Power_.
|
||||||
|
|
||||||
@@ -44,6 +42,7 @@ _WARNING_: we only support physically movements with valid GPS coordinates.
|
|||||||
Using a device indoors (no GPS available) will only show the current power values, but won't store anything.
|
Using a device indoors (no GPS available) will only show the current power values, but won't store anything.
|
||||||
Also the distance is not computed.
|
Also the distance is not computed.
|
||||||
|
|
||||||
|
For cycling:
|
||||||
* Assioma Duo Powermeter
|
* Assioma Duo Powermeter
|
||||||
* Elite drivo II
|
* Elite drivo II
|
||||||
* QUARQ Red DZero Powermeter
|
* QUARQ Red DZero Powermeter
|
||||||
@@ -51,8 +50,28 @@ Also the distance is not computed.
|
|||||||
* Wahoo Kickr v4.0
|
* Wahoo Kickr v4.0
|
||||||
* Rotor 2INpower DM Road (only supports power measurement, cadence measurement is propietary @ firmware v1.061)
|
* Rotor 2INpower DM Road (only supports power measurement, cadence measurement is propietary @ firmware v1.061)
|
||||||
|
|
||||||
## RSC: running cadence and speed
|
For running:
|
||||||
|
* Stryd
|
||||||
|
|
||||||
|
## 0x1814: running cadence and speed
|
||||||
|
|
||||||
We do not support type of movement (i.e., walking vs running).
|
We do not support type of movement (i.e., walking vs running).
|
||||||
|
|
||||||
* Polar Stride
|
* Polar Stride
|
||||||
|
* Stryd (incl. power)
|
||||||
|
|
||||||
|
## Tested Barometric Sensor Smartphones
|
||||||
|
|
||||||
|
There are smartphones that have a barometric sensor that OpenTracks uses to compute altitude gain and loss.
|
||||||
|
|
||||||
|
In our tests there are smartphones whose barometric sensor works well and others don't. Here is a list of the smartphones tested:
|
||||||
|
|
||||||
|
|Brand|Model|Android Version|Tests|
|
||||||
|
|-----|-----|---------------|-----------|
|
||||||
|
|Google|Pixel|LineageOS 17.1|Ok|
|
||||||
|
|Google|Pixel 2 XL|LineageOS 17.1|Ok on the bike handlebars but it fails when I carry it in a pocket or backpack|
|
||||||
|
|Google|Pixel 3|Android 11|Failure|
|
||||||
|
|Google|Pixel 3a|Android 11|Ok|
|
||||||
|
|Google|Pixel 3a|Lineage 18.1|Ok|
|
||||||
|
|Google|Pixel 4a|Android 11|Ok|
|
||||||
|
|Sony|Xperia XZ1 Compact|LineageOS 16.1|Failure|
|
||||||
|
|||||||
+32
-16
@@ -6,7 +6,7 @@ buildscript {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:7.0.2'
|
classpath 'com.android.tools.build:gradle:7.1.2'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,6 +30,19 @@ def getVersionName = { ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def getVersionCode = { ->
|
||||||
|
try {
|
||||||
|
def stdout = new ByteArrayOutputStream()
|
||||||
|
exec {
|
||||||
|
commandLine 'git', 'rev-list', 'HEAD', '--count'
|
||||||
|
standardOutput = stdout
|
||||||
|
}
|
||||||
|
return Integer.valueOf(stdout.toString().trim())
|
||||||
|
} catch (ignored) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileOptions {
|
compileOptions {
|
||||||
coreLibraryDesugaringEnabled true
|
coreLibraryDesugaringEnabled true
|
||||||
@@ -41,25 +54,20 @@ android {
|
|||||||
compileSdkVersion 31
|
compileSdkVersion 31
|
||||||
|
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
viewBinding = true
|
viewBinding true
|
||||||
}
|
|
||||||
|
|
||||||
aaptOptions {
|
|
||||||
cruncherEnabled = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "de.dennisguse.opentracks"
|
applicationId "de.dennisguse.opentracks"
|
||||||
versionCode 4448
|
versionCode 4773
|
||||||
versionName "v3.20.2"
|
versionName "v3.26.0"
|
||||||
|
|
||||||
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
|
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
|
||||||
|
|
||||||
|
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 31
|
targetSdkVersion 31
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "de.dennisguse.opentracks.TestRunner"
|
||||||
testInstrumentationRunnerArguments clearPackageData: 'true'
|
testInstrumentationRunnerArguments clearPackageData: 'true'
|
||||||
}
|
}
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
@@ -82,10 +90,10 @@ android {
|
|||||||
nightly {
|
nightly {
|
||||||
signingConfig signingConfigs.nightly
|
signingConfig signingConfigs.nightly
|
||||||
applicationIdSuffix ".nightly"
|
applicationIdSuffix ".nightly"
|
||||||
versionNameSuffix "-nightly"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
release {
|
release {
|
||||||
|
crunchPngs false
|
||||||
minifyEnabled false
|
minifyEnabled false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,16 +105,24 @@ android {
|
|||||||
|
|
||||||
applicationVariants.all { variant ->
|
applicationVariants.all { variant ->
|
||||||
variant.resValue "string", "applicationId", variant.applicationId
|
variant.resValue "string", "applicationId", variant.applicationId
|
||||||
|
|
||||||
|
if (variant.buildType.name == 'nightly') {
|
||||||
|
variant.outputs.all {
|
||||||
|
setVersionCodeOverride(getVersionCode())
|
||||||
|
setVersionNameOverride(getVersionName())
|
||||||
|
outputFileName = "${applicationId}_${variant.versionCode}.apk"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
||||||
|
|
||||||
implementation 'androidx.appcompat:appcompat:1.3.1'
|
implementation 'androidx.appcompat:appcompat:1.4.1'
|
||||||
implementation 'androidx.preference:preference:1.1.1'
|
implementation 'androidx.preference:preference:1.2.0'
|
||||||
implementation 'androidx.documentfile:documentfile:1.0.1'
|
implementation 'androidx.documentfile:documentfile:1.0.1'
|
||||||
implementation 'com.google.android.material:material:1.4.0'
|
implementation 'com.google.android.material:material:1.5.0'
|
||||||
implementation 'com.android.support.constraint:constraint-layout:2.0.4'
|
implementation 'com.android.support.constraint:constraint-layout:2.0.4'
|
||||||
|
|
||||||
androidTestImplementation 'androidx.test:core:1.4.0'
|
androidTestImplementation 'androidx.test:core:1.4.0'
|
||||||
@@ -114,7 +130,7 @@ dependencies {
|
|||||||
androidTestImplementation 'androidx.test:rules:1.4.0'
|
androidTestImplementation 'androidx.test:rules:1.4.0'
|
||||||
androidTestImplementation 'androidx.test:runner:1.4.0'
|
androidTestImplementation 'androidx.test:runner:1.4.0'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||||
androidTestImplementation 'org.mockito:mockito-android:3.12.4'
|
androidTestImplementation 'org.mockito:mockito-android:4.4.0'
|
||||||
|
|
||||||
androidTestUtil 'androidx.test:orchestrator:1.4.0'
|
androidTestUtil 'androidx.test:orchestrator:1.4.1'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
height="22"
|
||||||
|
width="22"
|
||||||
|
fill="#000000"
|
||||||
|
version="1.0"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
viewBox="0 0 21.84952 21.99934"
|
||||||
|
enable-background="new 0 0 99.316 99.997"
|
||||||
|
xml:space="preserve"
|
||||||
|
id="svg10"
|
||||||
|
sodipodi:docname="ic_activity_swimming.svg"
|
||||||
|
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20, custom)"
|
||||||
|
inkscape:export-filename="/home/peter/StudioProjects/OpenTracks/drawable-svg/ic_activity_swimming.png"
|
||||||
|
inkscape:export-xdpi="1309.09"
|
||||||
|
inkscape:export-ydpi="1309.09"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"><metadata
|
||||||
|
id="metadata16"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs14" /><sodipodi:namedview
|
||||||
|
pagecolor="#000000"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="1"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1831"
|
||||||
|
inkscape:window-height="1039"
|
||||||
|
id="namedview12"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:pagecheckerboard="false"
|
||||||
|
inkscape:zoom="31.780381"
|
||||||
|
inkscape:cx="10.368032"
|
||||||
|
inkscape:cy="10.069105"
|
||||||
|
inkscape:window-x="33"
|
||||||
|
inkscape:window-y="3"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="svg10"
|
||||||
|
inkscape:document-rotation="0" /><path
|
||||||
|
id="path2"
|
||||||
|
style="fill:#ffffff;stroke-width:0.20758"
|
||||||
|
d="m 18.327285,15.516652 c -1.017125,-0.01824 -1.903328,0.770666 -2.945647,0.500454 -0.952298,-0.271819 -1.950516,-0.765534 -2.949277,-0.338881 -0.938402,0.492101 -2.078868,0.493759 -3.0170251,0 C 8.4157577,15.251421 7.4164572,15.744755 6.4634103,16.017106 5.261142,16.31195 4.2317908,15.256338 3.0296629,15.558611 2.2388959,15.806745 1.0534821,16.11293 1.0534821,16.11293 v 1.764949 c 1.0226762,0.01947 1.9128198,-0.776355 2.9601398,-0.498166 1.4912769,0.589492 1.7842151,0.623743 2.7777974,0.375279 0.9553792,-0.44042 2.0942104,-0.606317 3.0559286,-0.07975 0.9566571,0.429062 1.9815791,0.09313 2.8934291,-0.263824 1.038124,-0.339466 1.95525,0.382078 2.955963,0.461915 1.087184,0.105691 2.019821,-0.784126 3.121615,-0.493622 0.55673,-0.01509 1.943197,1.034046 1.977683,0.148315 v -1.471252 c -0.878739,0.05089 -1.592095,-0.588897 -2.468753,-0.540124 z"
|
||||||
|
sodipodi:nodetypes="scccccccccccccccss" /><path
|
||||||
|
id="path2-1"
|
||||||
|
style="fill:#ffffff;stroke-width:0.20758"
|
||||||
|
d="m 18.327285,12.592022 c -1.017125,-0.01824 -1.903328,0.770666 -2.945647,0.500454 -0.952298,-0.271819 -1.950516,-0.765534 -2.949277,-0.338881 -0.938402,0.492101 -2.078868,0.493759 -3.0170249,0 C 8.4157578,12.326791 7.4164573,12.820125 6.4634104,13.092476 5.2611421,13.38732 4.2317909,12.331708 3.029663,12.633981 2.238896,12.882115 1.0534822,13.1883 1.0534822,13.1883 v 1.764949 c 1.0226762,0.01947 1.9128198,-0.776355 2.9601398,-0.498166 1.4912769,0.589492 1.7842151,0.623743 2.7777974,0.375279 0.9553792,-0.44042 2.0942104,-0.606317 3.0559286,-0.07975 0.956657,0.429062 1.981579,0.09313 2.893429,-0.263824 1.038124,-0.339466 1.95525,0.382078 2.955963,0.461915 1.087184,0.105691 2.019821,-0.784126 3.121615,-0.493622 0.55673,-0.01509 1.943197,1.034046 1.977683,0.148315 v -1.471252 c -0.878739,0.05089 -1.592095,-0.588897 -2.468753,-0.540124 z"
|
||||||
|
sodipodi:nodetypes="scccccccccccccccss" /><path
|
||||||
|
id="path851"
|
||||||
|
style="fill:#ffffff;stroke-width:1.16861"
|
||||||
|
d="m 15.771645,8.3604958 c 0.05505,1.1807818 -1.406378,2.0132882 -2.394197,1.3656158 -1.044532,-0.5537235 -1.017922,-2.2353035 0.04332,-2.7559408 1.018447,-0.5919723 2.378758,0.20782 2.350877,1.390325 z" /><path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.18448px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="M 4.3145569,12.014368 9.3210561,8.9478742 6.786081,6.2628496 11.908511,3.5970428 c 0.936726,-0.3746046 1.601464,0.5528762 1.096915,1.1662478 L 9.4152098,6.6598661 15.504839,12.51419 c -1.334475,-0.390685 -1.595745,-1.008768 -2.663055,-0.656789 -2.818488,0.929488 -2.219707,0.0047 -4.240291,0.02086 -2.2836952,0.01821 -1.8989609,1.154049 -4.2869361,0.136107 z"
|
||||||
|
id="path2791"
|
||||||
|
sodipodi:nodetypes="cccccccssc" /></svg>
|
||||||
|
After Width: | Height: | Size: 4.5 KiB |
@@ -0,0 +1,84 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
height="22"
|
||||||
|
width="22"
|
||||||
|
fill="#000000"
|
||||||
|
version="1.0"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
viewBox="0 0 21.84952 21.99934"
|
||||||
|
enable-background="new 0 0 99.316 99.997"
|
||||||
|
xml:space="preserve"
|
||||||
|
id="svg10"
|
||||||
|
sodipodi:docname="ic_activity_swimming_open.svg"
|
||||||
|
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20, custom)"
|
||||||
|
inkscape:export-filename="/home/peter/StudioProjects/OpenTracks/drawable-svg/ic_activity_swimming_open.png"
|
||||||
|
inkscape:export-xdpi="1309.09"
|
||||||
|
inkscape:export-ydpi="1309.09"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"><metadata
|
||||||
|
id="metadata16"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs14" /><sodipodi:namedview
|
||||||
|
pagecolor="#000000"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="1"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1047"
|
||||||
|
id="namedview12"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:pagecheckerboard="false"
|
||||||
|
inkscape:zoom="15.890191"
|
||||||
|
inkscape:cx="10.006173"
|
||||||
|
inkscape:cy="13.719156"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg10"
|
||||||
|
inkscape:document-rotation="0" /><path
|
||||||
|
id="path2"
|
||||||
|
style="fill:#ffffff;stroke-width:0.150857"
|
||||||
|
d="m 2.8183594,17.572266 c -0.1057708,4.65e-4 -0.2130618,0.01356 -0.3222656,0.04102 -0.5746803,0.180329 -1.4355469,0.402344 -1.4355469,0.402344 v 1.28125 c 0.7432174,0.01415 1.3912167,-0.563498 2.1523437,-0.361328 1.0837672,0.428407 1.295504,0.454005 2.0175782,0.273437 0.6943098,-0.32007 1.5217861,-0.441266 2.2207031,-0.05859 0.6952388,0.311815 1.4408397,0.06801 2.1035156,-0.191407 0.7544435,-0.246702 1.4211805,0.277917 2.1484375,0.335938 0.621051,-0.0088 1.351954,-0.399393 1.818402,-0.396552 0.536698,0.02254 1.051376,0.234242 1.498081,0.382763 0.357762,0.07663 0.717881,0.02104 0.970698,-0.07223 0.717277,-0.264623 1.521787,-0.441266 2.220704,-0.05859 0.695237,0.311815 1.440839,0.06801 2.103515,-0.191407 0.229629,-0.07509 0.450663,-0.07784 0.667969,-0.04492 v -1.314453 c -0.295925,-0.04096 -0.594072,-0.02791 -0.892578,0.09961 -0.681973,0.357628 -1.511565,0.358833 -2.19336,0 -0.726431,-0.310175 -1.451915,0.04817 -2.144531,0.246093 -0.116646,0.02861 -0.230986,0.0388 -0.34375,0.03711 v -0.0078 c -0.304634,0.02335 -0.610512,-0.122847 -0.878909,-0.189453 -1.061726,-0.598921 -2.285933,0.148857 -3.056646,0.16011 -0.510364,-0.111475 -1.41674,-0.556159 -2.1425779,-0.246093 -0.6819724,0.357628 -1.5115649,0.358833 -2.1933593,0 C 6.410287,17.389044 5.6848033,17.747388 4.9921875,17.945312 4.2276707,18.132803 3.558755,17.569011 2.8183594,17.572266 Z"
|
||||||
|
transform="matrix(0.99997,0,0,0.99997,-0.07491,0)"
|
||||||
|
sodipodi:nodetypes="sccccccccccsccccccccccccccs" /><path
|
||||||
|
id="path2-1-1"
|
||||||
|
style="fill:#ffffff;stroke-width:0.150857"
|
||||||
|
d="m 10.229667,15.445213 c -0.2340521,-0.01177 -0.6643302,0.02851 -0.8995889,0.129006 -0.6819724,0.357628 -1.5115649,0.358834 -2.1933593,0 C 6.410287,15.264044 5.6848033,15.622386 4.9921875,15.820312 4.1184541,16.034604 3.3697256,15.266655 2.4960938,15.486328 1.9214135,15.666657 1.0605469,15.890625 1.0605469,15.890625 v 1.28125 c 0.7432175,0.01415 1.3912167,-0.563498 2.1523437,-0.361328 1.0837672,0.428406 1.2955041,0.454006 2.0175782,0.273437 0.6943098,-0.320069 1.5217861,-0.441275 2.2207031,-0.05859 0.3325161,0.149133 0.6767832,0.169105 1.0175781,0.123047 1.1763193,-0.377141 1.78456,-0.510947 3.130219,0.05666 0.64547,0.05184 1.34431,-0.445591 2.223297,-0.423842 0.264657,-0.01332 1.092167,0.246652 1.478515,0.365234 h 0.002 c 0.560757,0.08029 1.135035,-0.115511 1.658204,-0.320312 0.754443,-0.246704 1.42118,0.277917 2.148437,0.335937 0.679991,0.06611 1.277834,-0.402757 1.941406,-0.40039 v -1.3125 c -0.0096,3.1e-4 -0.01967,-5.36e-4 -0.0293,0 -0.739183,-0.01326 -1.383132,0.559654 -2.140625,0.363281 -0.69207,-0.197542 -1.41674,-0.556158 -2.142578,-0.246094 -1.655465,0.798879 -2.131536,-0.136064 -3.123047,-0.109375 -0.566651,-0.01017 -1.078155,0.324314 -1.626953,0.392578 -0.768304,0.02005 -1.124822,-0.242268 -1.758614,-0.404396 z"
|
||||||
|
transform="matrix(0.99997,0,0,0.99997,-0.07491,0)"
|
||||||
|
sodipodi:nodetypes="cccccccccccccccccccccccccc" /><path
|
||||||
|
id="path851"
|
||||||
|
style="fill:#ffffff;stroke-width:0.849248"
|
||||||
|
d="m 11.681761,12.380821 c 0.04001,0.858093 -1.022037,1.463089 -1.7399012,0.992415 -0.759078,-0.4024 -0.73974,-1.624431 0.03148,-2.002787 0.7401222,-0.430195 1.7286822,0.151027 1.7084202,1.010372 z" /><path
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.860781px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 3.355712,15.036148 3.6383028,-2.22847 -1.842207,-1.95125 3.722552,-1.9372846 c 0.680734,-0.2722312 1.1638102,0.4017839 0.797146,0.8475309 l -2.609068,1.3782717 4.4254312,4.254431 c -0.969784,-0.283917 -1.159653,-0.733088 -1.9352852,-0.477299 -2.04824,0.675474 -1.613096,0.0034 -3.081487,0.01516 -1.659598,0.01323 -1.380005,0.838666 -3.1153848,0.09891 z"
|
||||||
|
id="path2791"
|
||||||
|
sodipodi:nodetypes="cccccccssc" /><path
|
||||||
|
id="rect4320"
|
||||||
|
style="fill:#ffffff;stroke-width:1.00154;stroke-linecap:square;paint-order:markers fill stroke"
|
||||||
|
d="m 21.108524,13.306347 c -0.260342,0.07218 -0.504886,-0.363252 -0.886457,-0.333843 -0.682913,0.05263 -0.688525,0.273741 -1.170401,0.333103 -0.56376,-0.01179 -0.705141,-0.39106 -1.323093,-0.385461 -0.797244,0.05005 -0.816589,0.344784 -1.506419,0.327831 -0.635156,-0.006 -0.584758,-0.400757 -1.137589,-0.37363 -0.445887,0 -0.423469,0.363096 -1.030167,0.33682 0.804394,-1.992062 7.313411,-2.472785 7.054126,0.09518 z"
|
||||||
|
sodipodi:nodetypes="cscccccc" /><path
|
||||||
|
id="rect4573"
|
||||||
|
style="fill:#ffffff;stroke-width:1.00154;stroke-linecap:square;paint-order:markers fill stroke"
|
||||||
|
d="m 15.952342,6.3416747 0.804782,0.00553 c 0.791609,0.9558102 1.568049,2.3417023 2.288114,5.3258424 l -1.791332,0.368162 c 0.0085,-1.595974 -0.327662,-3.5171502 -1.301564,-5.6995303 z"
|
||||||
|
sodipodi:nodetypes="ccccc" /><path
|
||||||
|
id="rect5178"
|
||||||
|
style="fill:#ffffff;stroke-width:1.00154;stroke-linecap:square;paint-order:markers fill stroke"
|
||||||
|
d="M 15.714534,5.7993213 16.460602,5.694421 C 17.892566,5.5299173 18.930384,6.2178215 19.826278,7.1622728 18.315795,6.5191329 17.758674,6.2722082 16.194793,6.4666796 14.820535,6.8297473 13.804944,7.2159692 13.25106,7.9257197 13.396619,7.3313592 13.938011,6.4826988 15.714534,5.7993213 Z"
|
||||||
|
sodipodi:nodetypes="cccccc" /><path
|
||||||
|
id="rect5178-8"
|
||||||
|
style="fill:#ffffff;stroke-width:0.961457;stroke-linecap:square;paint-order:markers fill stroke"
|
||||||
|
d="m 16.165622,5.4722594 c -0.08973,0.080465 -0.17851,0.1681115 -0.26532,0.2648771 l -0.0964,0.1131325 0.390891,0.6164106 C 17.150623,5.4034465 17.686156,5.2561052 19.060064,4.8593949 18.032481,4.6520987 17.033002,4.6944293 16.165622,5.4722594 Z" /><path
|
||||||
|
id="rect5178-5"
|
||||||
|
style="fill:#ffffff;stroke-width:0.928756;stroke-linecap:square;paint-order:markers fill stroke"
|
||||||
|
d="M 16.314771,5.73079 C 16.294181,5.717361 16.273991,5.703711 16.252891,5.690635 L 15.674258,5.3521611 c -1.591186,-0.4463567 -2.388606,-0.054483 -2.781886,0.3520817 0.738652,-0.2696642 1.645743,-0.011014 2.795776,0.4705547 0.09419,0.057052 0.180726,0.1118664 0.264194,0.1668772 z" /></svg>
|
||||||
|
After Width: | Height: | Size: 7.6 KiB |
@@ -0,0 +1,469 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
sodipodi:docname="ic_activity_workout.01.svg"
|
||||||
|
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20, custom)"
|
||||||
|
id="svg8"
|
||||||
|
version="1.1"
|
||||||
|
viewBox="0 0 5.8208333 5.8208333"
|
||||||
|
height="22"
|
||||||
|
width="22"
|
||||||
|
inkscape:export-filename="/home/peter/StudioProjects/OpenTracks/drawable-svg/ic_activity_workout.01.png"
|
||||||
|
inkscape:export-xdpi="1309.09"
|
||||||
|
inkscape:export-ydpi="1309.09"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||||
|
<defs
|
||||||
|
id="defs2">
|
||||||
|
<inkscape:path-effect
|
||||||
|
lpeversion="1"
|
||||||
|
is_visible="true"
|
||||||
|
id="path-effect3162"
|
||||||
|
effect="spiro" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
hide_knots="false"
|
||||||
|
only_selected="false"
|
||||||
|
apply_with_radius="true"
|
||||||
|
apply_no_radius="true"
|
||||||
|
use_knot_distance="true"
|
||||||
|
flexible="false"
|
||||||
|
chamfer_steps="1"
|
||||||
|
radius="0"
|
||||||
|
mode="F"
|
||||||
|
method="auto"
|
||||||
|
unit="px"
|
||||||
|
satellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,1.9999999,0,1 @ F,0,0,1,0,2.0000001,0,1"
|
||||||
|
lpeversion="1"
|
||||||
|
is_visible="true"
|
||||||
|
id="path-effect3149"
|
||||||
|
effect="fillet_chamfer" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="fillet_chamfer"
|
||||||
|
id="path-effect2514"
|
||||||
|
is_visible="true"
|
||||||
|
lpeversion="1"
|
||||||
|
satellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,4,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.97014234,0,1 @ F,0,0,1,0,0,0,1"
|
||||||
|
unit="px"
|
||||||
|
method="auto"
|
||||||
|
mode="F"
|
||||||
|
radius="0"
|
||||||
|
chamfer_steps="1"
|
||||||
|
flexible="false"
|
||||||
|
use_knot_distance="true"
|
||||||
|
apply_no_radius="true"
|
||||||
|
apply_with_radius="true"
|
||||||
|
only_selected="false"
|
||||||
|
hide_knots="false" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
hide_knots="false"
|
||||||
|
only_selected="false"
|
||||||
|
apply_with_radius="true"
|
||||||
|
apply_no_radius="true"
|
||||||
|
use_knot_distance="true"
|
||||||
|
flexible="false"
|
||||||
|
chamfer_steps="1"
|
||||||
|
radius="0"
|
||||||
|
mode="F"
|
||||||
|
method="auto"
|
||||||
|
unit="px"
|
||||||
|
satellites_param="F,0,0,1,0,0.51887107,0,1 @ F,0,0,1,0,0.22687835,0,1 @ F,0,0,1,0,0,0,1 @ F,0,1,1,0,0.51887107,0,1 @ F,0,0,1,0,0.22687835,0,1 @ F,0,0,1,0,0,0,1"
|
||||||
|
lpeversion="1"
|
||||||
|
is_visible="true"
|
||||||
|
id="path-effect950"
|
||||||
|
effect="fillet_chamfer" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
hide_knots="false"
|
||||||
|
only_selected="false"
|
||||||
|
apply_with_radius="true"
|
||||||
|
apply_no_radius="true"
|
||||||
|
use_knot_distance="true"
|
||||||
|
flexible="false"
|
||||||
|
chamfer_steps="1"
|
||||||
|
radius="0"
|
||||||
|
mode="F"
|
||||||
|
method="auto"
|
||||||
|
unit="px"
|
||||||
|
satellites_param="F,0,0,1,0,0.34892149,0,1 @ F,0,0,1,0,0.18398697,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.34892149,0,1 @ F,0,0,1,0,0.18398697,0,1 @ F,0,1,1,0,0,0,1"
|
||||||
|
lpeversion="1"
|
||||||
|
is_visible="true"
|
||||||
|
id="path-effect946"
|
||||||
|
effect="fillet_chamfer" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
hide_knots="false"
|
||||||
|
only_selected="false"
|
||||||
|
apply_with_radius="true"
|
||||||
|
apply_no_radius="true"
|
||||||
|
use_knot_distance="true"
|
||||||
|
flexible="false"
|
||||||
|
chamfer_steps="1"
|
||||||
|
radius="0"
|
||||||
|
mode="F"
|
||||||
|
method="auto"
|
||||||
|
unit="px"
|
||||||
|
satellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,1,1,0,2.00309,0,1 @ F,0,0,1,0,2.00309,0,1"
|
||||||
|
lpeversion="1"
|
||||||
|
is_visible="true"
|
||||||
|
id="path-effect918"
|
||||||
|
effect="fillet_chamfer" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
hide_knots="false"
|
||||||
|
only_selected="false"
|
||||||
|
apply_with_radius="true"
|
||||||
|
apply_no_radius="true"
|
||||||
|
use_knot_distance="true"
|
||||||
|
flexible="false"
|
||||||
|
chamfer_steps="1"
|
||||||
|
radius="0"
|
||||||
|
mode="F"
|
||||||
|
method="auto"
|
||||||
|
unit="px"
|
||||||
|
satellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,7.0000002,0,1 @ F,0,0,1,0,0,0,1"
|
||||||
|
lpeversion="1"
|
||||||
|
is_visible="true"
|
||||||
|
id="path-effect912"
|
||||||
|
effect="fillet_chamfer" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
hide_knots="false"
|
||||||
|
only_selected="false"
|
||||||
|
apply_with_radius="true"
|
||||||
|
apply_no_radius="true"
|
||||||
|
use_knot_distance="true"
|
||||||
|
flexible="false"
|
||||||
|
chamfer_steps="1"
|
||||||
|
radius="0"
|
||||||
|
mode="F"
|
||||||
|
method="auto"
|
||||||
|
unit="px"
|
||||||
|
satellites_param="F,0,0,1,0,0.49832891,0,1 @ F,0,0,1,0,0.49832891,0,1 @ F,0,1,1,0,0.5316463,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.49999976,0,1 @ F,0,0,1,0,0.50000024,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,1.0000001,0,1 @ F,0,0,1,0,0.99999982,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,1.0295214,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0,0,1 @ F,0,0,1,0,0.5316463,0,1"
|
||||||
|
lpeversion="1"
|
||||||
|
is_visible="true"
|
||||||
|
id="path-effect894"
|
||||||
|
effect="fillet_chamfer" />
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-height="1047"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:guide-bbox="true"
|
||||||
|
showguides="false"
|
||||||
|
inkscape:snap-text-baseline="true"
|
||||||
|
inkscape:snap-center="true"
|
||||||
|
inkscape:snap-object-midpoints="true"
|
||||||
|
inkscape:snap-midpoints="true"
|
||||||
|
inkscape:snap-smooth-nodes="true"
|
||||||
|
inkscape:snap-intersection-paths="true"
|
||||||
|
inkscape:object-paths="true"
|
||||||
|
inkscape:snap-bbox-midpoints="true"
|
||||||
|
inkscape:snap-bbox-edge-midpoints="true"
|
||||||
|
inkscape:bbox-nodes="true"
|
||||||
|
inkscape:bbox-paths="true"
|
||||||
|
inkscape:snap-bbox="true"
|
||||||
|
units="px"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:cy="10.326952"
|
||||||
|
inkscape:cx="15.790447"
|
||||||
|
inkscape:zoom="31.664715"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:pageopacity="1"
|
||||||
|
borderopacity="1.0"
|
||||||
|
bordercolor="#666666"
|
||||||
|
pagecolor="#232629"
|
||||||
|
id="base"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:snap-grids="false">
|
||||||
|
<inkscape:grid
|
||||||
|
dotted="true"
|
||||||
|
empspacing="22"
|
||||||
|
id="grid833"
|
||||||
|
type="xygrid" />
|
||||||
|
<inkscape:grid
|
||||||
|
originy="0.26458333"
|
||||||
|
originx="0.26458333"
|
||||||
|
spacingx="1.0583333"
|
||||||
|
spacingy="1.0583333"
|
||||||
|
empspacing="1"
|
||||||
|
id="grid835"
|
||||||
|
type="xygrid" />
|
||||||
|
<sodipodi:guide
|
||||||
|
inkscape:color="rgb(0,0,255)"
|
||||||
|
inkscape:locked="false"
|
||||||
|
inkscape:label=""
|
||||||
|
id="guide887"
|
||||||
|
orientation="0.96592583,0.25881905"
|
||||||
|
position="4.195,4.2333333" />
|
||||||
|
<sodipodi:guide
|
||||||
|
id="guide900"
|
||||||
|
orientation="0,-1"
|
||||||
|
position="0.26458333,1.9843751" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
id="layer1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
inkscape:label="Layer 1">
|
||||||
|
<g
|
||||||
|
transform="matrix(0.38576851,0,0,0.38576851,152.56385,-12.494408)"
|
||||||
|
id="g954">
|
||||||
|
<rect
|
||||||
|
style="fill:#cacaca;fill-opacity:1;stroke-width:14.6855;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552"
|
||||||
|
id="rect919"
|
||||||
|
width="68.791664"
|
||||||
|
height="79.375"
|
||||||
|
x="-357.1875"
|
||||||
|
y="-7.9375" />
|
||||||
|
<rect
|
||||||
|
style="fill:#e74c3c;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552"
|
||||||
|
id="rect851"
|
||||||
|
width="10.583333"
|
||||||
|
height="10.583333"
|
||||||
|
x="-354.54169"
|
||||||
|
y="-5.2916665" />
|
||||||
|
<rect
|
||||||
|
y="-5.2916665"
|
||||||
|
x="-343.95834"
|
||||||
|
height="10.583333"
|
||||||
|
width="10.583333"
|
||||||
|
id="rect853"
|
||||||
|
style="fill:#ed1515;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552" />
|
||||||
|
<rect
|
||||||
|
style="fill:#f47750;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552"
|
||||||
|
id="rect855"
|
||||||
|
width="10.583333"
|
||||||
|
height="10.583333"
|
||||||
|
x="-333.375"
|
||||||
|
y="-5.2916665" />
|
||||||
|
<rect
|
||||||
|
y="-5.2916665"
|
||||||
|
x="-322.79169"
|
||||||
|
height="10.583333"
|
||||||
|
width="10.583333"
|
||||||
|
id="rect857"
|
||||||
|
style="fill:#fdbc4b;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552" />
|
||||||
|
<rect
|
||||||
|
style="fill:#c9ce3b;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552"
|
||||||
|
id="rect859"
|
||||||
|
width="10.583333"
|
||||||
|
height="10.583333"
|
||||||
|
x="-312.20834"
|
||||||
|
y="-5.2916665" />
|
||||||
|
<rect
|
||||||
|
y="5.291667"
|
||||||
|
x="-354.54169"
|
||||||
|
height="10.583333"
|
||||||
|
width="10.583333"
|
||||||
|
id="rect861"
|
||||||
|
style="fill:#da4453;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552" />
|
||||||
|
<rect
|
||||||
|
style="fill:#c0392b;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552"
|
||||||
|
id="rect863"
|
||||||
|
width="10.583333"
|
||||||
|
height="10.583333"
|
||||||
|
x="-343.95834"
|
||||||
|
y="5.291667" />
|
||||||
|
<rect
|
||||||
|
y="5.291667"
|
||||||
|
x="-333.375"
|
||||||
|
height="10.583333"
|
||||||
|
width="10.583333"
|
||||||
|
id="rect865"
|
||||||
|
style="fill:#d35400;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552" />
|
||||||
|
<rect
|
||||||
|
style="fill:#f67400;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552"
|
||||||
|
id="rect867"
|
||||||
|
width="10.583333"
|
||||||
|
height="10.583333"
|
||||||
|
x="-322.79169"
|
||||||
|
y="5.291667" />
|
||||||
|
<rect
|
||||||
|
y="5.291667"
|
||||||
|
x="-312.20834"
|
||||||
|
height="10.583333"
|
||||||
|
width="10.583333"
|
||||||
|
id="rect869"
|
||||||
|
style="fill:#f39c1f;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552" />
|
||||||
|
<rect
|
||||||
|
y="21.166666"
|
||||||
|
x="-354.54169"
|
||||||
|
height="10.583333"
|
||||||
|
width="10.583333"
|
||||||
|
id="rect871"
|
||||||
|
style="fill:#1cdc9a;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552" />
|
||||||
|
<rect
|
||||||
|
style="fill:#2ecc71;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552"
|
||||||
|
id="rect873"
|
||||||
|
width="10.583333"
|
||||||
|
height="10.583333"
|
||||||
|
x="-343.95834"
|
||||||
|
y="21.166666" />
|
||||||
|
<rect
|
||||||
|
y="21.166666"
|
||||||
|
x="-333.375"
|
||||||
|
height="10.583333"
|
||||||
|
width="10.583333"
|
||||||
|
id="rect875"
|
||||||
|
style="fill:#1abc9c;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552" />
|
||||||
|
<rect
|
||||||
|
style="fill:#3498db;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552"
|
||||||
|
id="rect877"
|
||||||
|
width="10.583333"
|
||||||
|
height="10.583333"
|
||||||
|
x="-322.79169"
|
||||||
|
y="21.166666" />
|
||||||
|
<rect
|
||||||
|
y="21.166666"
|
||||||
|
x="-312.20834"
|
||||||
|
height="10.583333"
|
||||||
|
width="10.583333"
|
||||||
|
id="rect879"
|
||||||
|
style="fill:#3daee9;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552" />
|
||||||
|
<rect
|
||||||
|
style="fill:#10d116;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552"
|
||||||
|
id="rect881"
|
||||||
|
width="10.583333"
|
||||||
|
height="10.583333"
|
||||||
|
x="-354.54169"
|
||||||
|
y="31.75" />
|
||||||
|
<rect
|
||||||
|
y="31.75"
|
||||||
|
x="-343.95834"
|
||||||
|
height="10.583333"
|
||||||
|
width="10.583333"
|
||||||
|
id="rect883"
|
||||||
|
style="fill:#27ae60;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552" />
|
||||||
|
<rect
|
||||||
|
style="fill:#16a085;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552"
|
||||||
|
id="rect885"
|
||||||
|
width="10.583333"
|
||||||
|
height="10.583333"
|
||||||
|
x="-333.375"
|
||||||
|
y="31.75" />
|
||||||
|
<rect
|
||||||
|
y="31.75"
|
||||||
|
x="-322.79169"
|
||||||
|
height="10.583333"
|
||||||
|
width="10.583333"
|
||||||
|
id="rect887"
|
||||||
|
style="fill:#2980b9;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552" />
|
||||||
|
<rect
|
||||||
|
style="fill:#1d99f3;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552"
|
||||||
|
id="rect889"
|
||||||
|
width="10.583333"
|
||||||
|
height="10.583333"
|
||||||
|
x="-312.20834"
|
||||||
|
y="31.75" />
|
||||||
|
<rect
|
||||||
|
style="fill:#9b59b6;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552"
|
||||||
|
id="rect891"
|
||||||
|
width="10.583333"
|
||||||
|
height="10.583333"
|
||||||
|
x="-301.625"
|
||||||
|
y="21.166666" />
|
||||||
|
<rect
|
||||||
|
y="31.75"
|
||||||
|
x="-301.625"
|
||||||
|
height="10.583333"
|
||||||
|
width="10.583333"
|
||||||
|
id="rect893"
|
||||||
|
style="fill:#8e44ad;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552" />
|
||||||
|
<rect
|
||||||
|
style="fill:#34495e;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552"
|
||||||
|
id="rect895"
|
||||||
|
width="10.583333"
|
||||||
|
height="10.583333"
|
||||||
|
x="-354.54166"
|
||||||
|
y="47.625" />
|
||||||
|
<rect
|
||||||
|
y="47.625"
|
||||||
|
x="-343.95831"
|
||||||
|
height="10.583333"
|
||||||
|
width="10.583333"
|
||||||
|
id="rect897"
|
||||||
|
style="fill:#31363b;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552" />
|
||||||
|
<rect
|
||||||
|
style="fill:#7f8c8d;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552"
|
||||||
|
id="rect899"
|
||||||
|
width="10.583333"
|
||||||
|
height="10.583333"
|
||||||
|
x="-333.37497"
|
||||||
|
y="47.625" />
|
||||||
|
<rect
|
||||||
|
y="47.625"
|
||||||
|
x="-322.79166"
|
||||||
|
height="10.583333"
|
||||||
|
width="10.583333"
|
||||||
|
id="rect901"
|
||||||
|
style="fill:#bdc3c7;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552" />
|
||||||
|
<rect
|
||||||
|
style="fill:#fcfcfc;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552"
|
||||||
|
id="rect903"
|
||||||
|
width="10.583333"
|
||||||
|
height="10.583333"
|
||||||
|
x="-312.20831"
|
||||||
|
y="47.625" />
|
||||||
|
<rect
|
||||||
|
y="58.208336"
|
||||||
|
x="-354.54166"
|
||||||
|
height="10.583333"
|
||||||
|
width="10.583333"
|
||||||
|
id="rect905"
|
||||||
|
style="fill:#2c3e50;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552" />
|
||||||
|
<rect
|
||||||
|
style="fill:#232629;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552"
|
||||||
|
id="rect907"
|
||||||
|
width="10.583333"
|
||||||
|
height="10.583333"
|
||||||
|
x="-343.95831"
|
||||||
|
y="58.208336" />
|
||||||
|
<rect
|
||||||
|
y="58.208336"
|
||||||
|
x="-333.37497"
|
||||||
|
height="10.583333"
|
||||||
|
width="10.583333"
|
||||||
|
id="rect909"
|
||||||
|
style="fill:#4d4d4d;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552" />
|
||||||
|
<rect
|
||||||
|
style="fill:#95a5a6;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552"
|
||||||
|
id="rect911"
|
||||||
|
width="10.583333"
|
||||||
|
height="10.583333"
|
||||||
|
x="-322.79166"
|
||||||
|
y="58.208336" />
|
||||||
|
<rect
|
||||||
|
y="58.208336"
|
||||||
|
x="-312.20831"
|
||||||
|
height="10.583333"
|
||||||
|
width="10.583333"
|
||||||
|
id="rect913"
|
||||||
|
style="fill:#eff0f1;fill-opacity:1;stroke-width:14.955;stroke-linecap:square;stroke-linejoin:round;stroke-dashoffset:531.552" />
|
||||||
|
</g>
|
||||||
|
<path
|
||||||
|
id="path17"
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.730205;stroke-opacity:1"
|
||||||
|
d="m 12.521484,5.0957031 c -0.795342,0 -1.447265,0.6634257 -1.447265,1.4746094 0,0.811183 0.651923,1.4746094 1.447265,1.4746094 0.795342,0 1.445313,-0.663426 1.445313,-1.4746094 0,-0.8111837 -0.649971,-1.4746094 -1.445313,-1.4746094 z m 5.697266,2.2871094 c -1.005293,9.03e-5 -1.820222,0.8150191 -1.820312,1.8203125 0.001,0.2581612 0.02839,0.6283924 0.303378,0.93547 L 15.712713,10.886411 13.488221,8.9477292 10.263672,8.5957031 7.5078513,10.338038 5.7695312,12.576172 c -0.3754732,0.661347 0.1816517,1.249724 0.7773438,0.966797 l 1.7128929,-2.075723 1.9003931,-1.220112 -0.5761766,4.110288 -2.5878906,5.929687 1.484375,-0.0293 c 0.4801983,-0.907334 2.5996092,-5.441406 2.5996092,-5.441406 l 2.054688,0.941406 v 4.423829 h 1.445312 v -5.53125 L 12.75,13.876953 l 0.650391,-3.398437 2.285156,2.103515 1.747452,-1.734477 c 0.31097,0.238627 0.542791,0.17537 0.785751,0.175884 1.005294,-9e-5 1.820222,-0.815019 1.820312,-1.820313 -9e-5,-1.0052934 -0.815019,-1.8202222 -1.820312,-1.8203125 z m 0.0059,1.3535156 c 0.274357,9.402e-4 0.496232,0.2236881 0.496094,0.4980469 1.38e-4,0.2743588 -0.221737,0.4971067 -0.496094,0.4980469 C 17.94953,9.7325585 17.726466,9.5094953 17.726603,9.234375 17.726466,8.9592547 17.94953,8.7361915 18.22465,8.7363281 Z"
|
||||||
|
transform="scale(0.26458333)"
|
||||||
|
sodipodi:nodetypes="sssssccccccccccccccccccccccccccccccc" />
|
||||||
|
<path
|
||||||
|
id="path9403"
|
||||||
|
style="fill:#ffffff;stroke:none;stroke-width:0.264999;stroke-linecap:square;stroke-miterlimit:4;stroke-dasharray:none;paint-order:markers fill stroke"
|
||||||
|
d="M 1.0131059,0.53415337 C 0.73729957,0.54114168 0.64785326,0.76400686 0.64775351,1.04575 c 0.001003,0.049428 0.006811,0.095893 0.0170532,0.1405599 H 1.1996578 L 1.3303992,1.4400412 1.6714636,0.85558076 1.9071081,1.1801088 2.1840938,1.1826926 C 2.1968962,1.1377378 2.2034247,1.0922518 2.2032141,1.04575 2.2031128,0.75953474 2.1266608,0.53477144 1.8404456,0.53467013 1.540136,0.53761574 1.5284374,0.67900891 1.4327185,0.76204643 1.3421819,0.69057893 1.2614053,0.53055962 1.0265417,0.53415337 c -0.00447,1.59e-6 -0.00906,-1.1091e-4 -0.013436,0 z M 2.1840938,1.1826926 c -0.016723,0.058723 -0.044375,0.116296 -0.079582,0.173116 l 0.4873088,-0.00258 V 1.1863099 Z M 2.1045121,1.3558086 1.7965206,1.3573589 1.6740474,1.16874 1.3009436,1.7361472 1.0828691,1.3532248 H 0.7273352 C 0.8490025,1.5865985 1.0981629,1.7800149 1.3903438,2.0580913 1.669028,1.8167708 1.9577231,1.5927143 2.1045121,1.3558086 Z M 0.7273352,1.3532248 C 0.69965645,1.3001334 0.67827264,1.2450376 0.66480673,1.1863099 H 0.25914674 v 0.1669149 z" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 19 KiB |
@@ -0,0 +1,62 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
id="vector"
|
||||||
|
version="1.1"
|
||||||
|
sodipodi:docname="ic_clear_filter.svg"
|
||||||
|
inkscape:version="1.0.2 (e86c870879, 2021-01-15)">
|
||||||
|
<metadata
|
||||||
|
id="metadata8">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs6" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1011"
|
||||||
|
id="namedview4"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="16.541667"
|
||||||
|
inkscape:cx="12.392292"
|
||||||
|
inkscape:cy="24.710689"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="0"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="vector" />
|
||||||
|
<path
|
||||||
|
id="path"
|
||||||
|
style="fill:#707070;fill-opacity:1"
|
||||||
|
d="M 5.0390625 4 C 4.2090625 4 3.74 4.949375 4.25 5.609375 C 6.0862696 7.9637998 8.9006606 11.587089 9.4765625 12.328125 L 17.804688 4 L 5.0390625 4 z M 14 13.958984 L 10 17.958984 L 10 19 C 10 19.55 10.45 20 11 20 L 13 20 C 13.55 20 14 19.55 14 19 L 14 13.958984 z " />
|
||||||
|
<rect
|
||||||
|
style="fill:#707070;fill-opacity:1;stroke:none;stroke-width:1.118;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="rect833"
|
||||||
|
width="21.37405"
|
||||||
|
height="1.7606405"
|
||||||
|
x="-10.108474"
|
||||||
|
y="16.886091"
|
||||||
|
ry="0.88032025"
|
||||||
|
transform="rotate(-45)" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,19 @@
|
|||||||
|
v3.21.0: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- While recording: remove idle/non-idle creation of TrackPoints
|
||||||
|
- Settings are now in separate folders
|
||||||
|
- Opening OpenTracks from notification (while recording) and pressing back opens track list
|
||||||
|
- GPX compatibilty: support <speed> for import
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
- Altitude and distance (from BlE sensor): only reset counters if data was actually stored
|
||||||
|
- Import without speed, requires computing speed
|
||||||
|
- BLE running sensor not connected, should not be reported as present
|
||||||
|
- BLE running sensor: show data while recording
|
||||||
|
- Activity type icon was not updated while changing activity
|
||||||
|
|
||||||
|
Developer:
|
||||||
|
- SharedPrefences via static reference
|
||||||
|
- Tests are executed against in-memory database
|
||||||
|
- TrackRecordingManager keeps last TrackPoint in memory
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
v3.22.0: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Locations are only stored if traveled distance > recording distance interval
|
||||||
|
(removed left over functionality from idle/non-idle detection)
|
||||||
|
- UI can be configured to show a clock
|
||||||
|
- Idle speed is now configurable
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Intervals: crash when gain but not loss was stored
|
||||||
|
- While recording: prevent crash when disabling voice announcements
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
v3.23.0: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Added UI profiles
|
||||||
|
- Aggregated statistics for selected tracks
|
||||||
|
- Re-implemented idle/non-idle TrackPoints as moving time stopped working (introduced in v3.22.0)
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
- BLE sensors: clear data on disconnect
|
||||||
|
- Automatic export needs to persist permission
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
v3.24.0: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- GPS is optional (also for indoor use): if using a BLE sensors that provide distance are used
|
||||||
|
- Settings: option to disable BLE filtering of devices
|
||||||
|
- Charts: altitude starts at minimal value instead of 0m.
|
||||||
|
- UI supports showing stored timezone information
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Re-added workaround for crash due to clock traveling back in time (workaround was removed in v3.23.0)
|
||||||
|
- Removed unecessary workaround for BLE cycling sensor (RTFM)
|
||||||
|
- GPX importer did not handle missing data properly
|
||||||
|
|
||||||
|
Developer:
|
||||||
|
- BLE sensors report data event-driven than pull-based
|
||||||
|
- Reworked and added integration tests for recording
|
||||||
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
v3.24.1: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Added API for starting recordings from other applications (disabled by default)
|
||||||
|
- Shortened ISO8601 track names
|
||||||
|
- BLE distance sensors: store GPS-locations based upon previous GPS-locations
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- While recording: fixed crash when opening charts
|
||||||
|
- TrackDataHub should end processing after stop()
|
||||||
|
- Prevent rare crash while deleting tracks
|
||||||
|
|
||||||
|
Developer:
|
||||||
|
- Refactored package structure
|
||||||
|
- Monotonic clock
|
||||||
|
- Value objects for heartrate, cadence, and power
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
v3.25.0: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- GPS is now optional incl. GPS disabled warning
|
||||||
|
- PublicAPI: other applications can now receive recorded data if they start a recording (implemented for Gadgetbridge)
|
||||||
|
- New activities: swimming, swimming open, and workout
|
||||||
|
- Removed share pic functionality
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- UI: speed/elevation where jumping between 0.0 and the actual value
|
||||||
|
- Tracks with emojis can be exported
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
v3.25.1: OpenTracks
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Automatic export: hopefully prevent silent failures
|
||||||
|
- Automatic export: prevent crash
|
||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
v3.26.0: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Voice announcements are configurable
|
||||||
|
- Voice announcements of heart rate
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Crash due to race condition
|
||||||
@@ -1,11 +1,22 @@
|
|||||||
OpenTracks is a sport tracking application that completely respects your privacy.
|
A sport tracking buddy that respects your privacy.
|
||||||
|
|
||||||
Features:
|
Sport and outdoor activities grants happiness, skill and confidence.
|
||||||
* Sport tracking: track your sport and outdoor activities
|
|
||||||
* Photos and markers: mark interesting locations while tracking
|
Value your health by keeping track on your training.
|
||||||
* Altitude gain and loss: via barometric sensor
|
Records as you go running or walking, and gives you a bike computer with a bigger screen for cycling.
|
||||||
* Altitude shown in EGM2008 (above mean sea level); exported as WGS84
|
Mark interesting locations along your way with pictures.
|
||||||
* Voice announcements
|
Keep recorded statistics in great detail for analysis.
|
||||||
* Supports Bluetooth LE sensors: heart rate, speed and distance (cycling), cadence (cycling), and power meter (cycling)
|
Share only the data you want others to have.
|
||||||
* Export data: export tracks either as KMZ (incl. photos), KML, or GPX
|
|
||||||
* No Internet access: Internet is not used
|
* Voice announcements.
|
||||||
|
* Supports Bluetooth LE sensors: heart rate, speed and distance (cycling), cadence (cycling), and power meter (cycling).
|
||||||
|
* Altitude gain and loss: via barometric sensor.
|
||||||
|
* Altitude shown in EGM2008 (above mean sea level); exported as WGS84.
|
||||||
|
* Export data as tracks either as KMZ (incl. photos), KML, or GPX.
|
||||||
|
* No Internet access or extra permissions.
|
||||||
|
* Dark and light theme, respecting system settings.
|
||||||
|
* No ads.
|
||||||
|
|
||||||
|
Libre software / Free Software / Open Source
|
||||||
|
meaning you can use, study, change and share the source code.
|
||||||
|
Licensed Apache 2.0
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
A sport tracker that completely respects your privacy.
|
A sport tracker buddy that respects your privacy.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
OpenTracks estas aplikaĵo por registri vian sportan aktivecon, kiu plene respektas vian privatecon.
|
OpenTracks estas aplikaĵo por registri vian sportan aktivecon, kiu plene respektas vian privatecon.
|
||||||
|
|
||||||
Eblaĵoj:
|
Ebloj:
|
||||||
• registri vian sportan kaj alian aktivecon eksterdome
|
• registri vian sportan kaj alian aktivecon eksterdome
|
||||||
• fotoj kaj markoj: marki interesajn lokojn dum registri aktivecon
|
• fotoj kaj markoj: marki interesajn lokojn dum registri aktivecon
|
||||||
• registri ŝanĝon de altitudo uzante barometron
|
• registri ŝanĝon de altitudo uzante barometron
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
v3.19.1: OpenTracks
|
||||||
|
|
||||||
|
Cambios:
|
||||||
|
- Traducciones actualizadas.
|
||||||
|
|
||||||
|
Corrección de errores:
|
||||||
|
- Corregido el error de exportar todas las pistas.
|
||||||
|
- Corregido el error de reanudar la pista.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
v3.20.0: OpenTracks
|
||||||
|
|
||||||
|
Cambios:
|
||||||
|
- Durante la grabación: la interfaz de usuario de las estadísticas es ahora configurable
|
||||||
|
|
||||||
|
Corrección de errores:
|
||||||
|
- Se ignoraba el cambio de nombre de pista/categoría durante la grabación (introducido en la v3.19.0)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
v3.20.1: OpenTracks
|
||||||
|
|
||||||
|
Cambios:
|
||||||
|
- Los anuncios ahora se pueden utilizar tanto por distancia como por tiempo
|
||||||
|
- Los anuncios emiten un pitido si no se ha instalado un software de texto a voz
|
||||||
|
- Se ha eliminado la frecuencia de localización GPS adaptativa
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
v3.23.0: OpenTracks
|
||||||
|
|
||||||
|
Cambios:
|
||||||
|
- Añadido perfiles UI
|
||||||
|
- Estadísticas agregadas para las pistas seleccionadas
|
||||||
|
- Reimplementación de TrackPoints inactivos/no inactivos ya que el tiempo de movimiento dejó de funcionar (introducido en la v3.22.0)
|
||||||
|
|
||||||
|
Corrección de errores:
|
||||||
|
- Sensores BLE: borrado de datos al desconectarse
|
||||||
|
- La exportación automática necesita persistir el permiso
|
||||||
@@ -1,11 +1,22 @@
|
|||||||
OpenTracks on spordi jälgimise rakendus, mis austab täielikult teie privaatsust.
|
Spordijälgija, mis austab teie privaatsust.
|
||||||
|
|
||||||
Omadused:
|
Sport ja välitegevused garanteerivad õnnelikkuse, vilumuse ja kindlustunde.
|
||||||
* Spordi jälgimine: jälgige oma spordi- ja vabaõhutegevust.
|
|
||||||
* Fotod ja markerid: märkige jälgimise ajal huvipakkuvad kohad.
|
Väärtusta oma tervist, jälgides on treeninguid.
|
||||||
* Kõrguse suurenemine ja vähenemine: baromeetrilise anduri abil
|
Salvestab kui lähed jooksma või jalutama ja annab teile jalgrattasõiduks suurema ekraani.
|
||||||
* Kõrgus näitab EGM2008 (üle keskmise merepinna); eksporditakse WGS84 kujul.
|
Märgi huvitavad asukohad oma teel, koos piltidega.
|
||||||
* Häälteated
|
Hoia salvestatud statistika analüüsimiseks.
|
||||||
* Toetab Bluetooth LE andureid: südame löögisagedus, kiirus ja distants (jalgrattasõit), takistus (jalgrattasõit) ja jõumõõtja (jalgrattasõit).
|
Jaga ainult neid andmeid, mida soovid, et teised näeksid.
|
||||||
* Andmete eksport: eksportida rajad kas KMZ (sh fotod), KML või GPX kujul.
|
|
||||||
* Interneti-ühendus puudub: Internetti ei kasutata
|
* Häälteated.
|
||||||
|
* Toetab Bluetooth LE andureid: pulss, kiirus, distants (jalgrattasõit), rütm (jalgrattasõit) ja jõumõõtja (jalgrattasõit).
|
||||||
|
* Kõrguse tõus ja langus: baromeetrilise anduri abil.
|
||||||
|
* Kõrgus näitab EGM2008 (üle keskmise merepinna); eksporditakse WGS84-na.
|
||||||
|
* Ekspordit teekond kas KMZ- (koos fotodega), KML- või GPX-vormingus.
|
||||||
|
* Ei vaja internetile ligipääsu ega lisalubasid.
|
||||||
|
* Tume ja hele teema, austab süsteemi sätteid.
|
||||||
|
* Reklaamivaba.
|
||||||
|
|
||||||
|
Vabavara / Avatud Lähtekoodiga Tarkvara
|
||||||
|
mis tähendab, et võite lähtekoodi kasutada, uurida, muuta ja jagada.
|
||||||
|
Litsentsitud Apache 2.0
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
Spordijälgija, mis austab täielikult teie privaatsust.
|
Spordijälgija, mis austab teie privaatsust.
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
v3.19.1 : OpenTracks
|
||||||
|
|
||||||
|
Changements :
|
||||||
|
- Traductions mises à jour.
|
||||||
|
|
||||||
|
Correction de bogue :
|
||||||
|
- Correction du bug de l'exportation de toutes les pistes.
|
||||||
|
- Correction du bogue "Reprendre une piste".
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
v3.20.0 : OpenTracks
|
||||||
|
|
||||||
|
Changements :
|
||||||
|
- Pendant l'enregistrement : l'interface des statistiques est maintenant configurable
|
||||||
|
|
||||||
|
Correction d'un bug :
|
||||||
|
- Le changement de nom de piste/catégorie pendant l'enregistrement était ignoré (introduit dans la v3.19.0)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
v3.20.1 : OpenTracks
|
||||||
|
|
||||||
|
Changements :
|
||||||
|
- Les annonces peuvent maintenant être utilisées à la fois par distance et par temps.
|
||||||
|
- Les annonces émettent un bip si aucun logiciel de synthèse vocale n'est installé.
|
||||||
|
- Suppression de la fréquence de localisation GPS adaptative
|
||||||
@@ -1 +1 @@
|
|||||||
OpenTracks - Suivi d'activités sportives respectueux de votre vie privée.
|
Appli de suivi des activités sportives respectueuse de votre vie privée.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
OpenTracks er en sportsporingsapp som respekterer ditt personvern.
|
OpenTracks er en app for opptak av sportsaktivitet som respekterer ditt personvern.
|
||||||
|
|
||||||
Funksjoner:
|
Funksjoner:
|
||||||
* Sportsporing: Registrer dine sports- og utendørsaktiviteter
|
* Sportsporing: Registrer dine sports- og utendørsaktiviteter
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
En sportsregistrerer som respekterer ditt personvern.
|
En opptaker av sportsaktivitet som respekterer ditt personvern.
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
v3.18.6: OpenTracks
|
||||||
|
|
||||||
|
Zmiany:
|
||||||
|
- "Pokaż na mapie"- Funkcjonalość wraz z KML zamiast KMZ
|
||||||
|
- Komunikaty głosowe nie podają nazwy aplikacji
|
||||||
|
- Podczas śledzenia: Zmiana wysokości aktualizowana co sekundę
|
||||||
|
- Przetłumaczone opisy w sklepach aplikacji
|
||||||
|
|
||||||
|
Naprawione błędy:
|
||||||
|
- Naprawiono nieprawidłowe tłumaczenia wiadomości głosowych
|
||||||
|
|
||||||
|
Developer:
|
||||||
|
- Uprawnienia Android12 (BLUETOOTH_SCAN)
|
||||||
|
- Uprawnienia Android12 (ACCESS_COARSE_LOCATION)
|
||||||
|
- Zastosowanie TrackPoints (testowane)
|
||||||
|
- Usunięcie niepotrzebnych tłumaczeń
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
v3.22.0: OpenTracks
|
||||||
|
|
||||||
|
Zmiany:
|
||||||
|
- Lokalizacja zapisywana tylko wtedy gdy pokonany dystans jest większy od minimalnego przedziału śledzenia dystansu
|
||||||
|
(usunięto funkcjonalność z wykrywania bezczynności)
|
||||||
|
- UI może zostać skonfigurowane do wyświetlania zegara
|
||||||
|
- Prędkość ruchu bez oporu (prędkość jałowa) jest teraz konfigurowalna
|
||||||
|
|
||||||
|
Poprawki:
|
||||||
|
- Przedziały: awaria, gdy zapisano zwiększenie wysokości, ale nie spadek
|
||||||
|
- Podczas nagrywania: zapobieganie awariom podczas wyłączania komunikatów głosowych
|
||||||
@@ -3,9 +3,9 @@ OpenTracks jest aplikacją do śledzenia sportu, która całkowicie szanuje Twoj
|
|||||||
Cechy:
|
Cechy:
|
||||||
* Śledzenie sportu: śledź swoją aktywność sportową i outdoorową.
|
* Śledzenie sportu: śledź swoją aktywność sportową i outdoorową.
|
||||||
* Zdjęcia i markery: zaznacz interesujące lokalizacje podczas śledzenia.
|
* Zdjęcia i markery: zaznacz interesujące lokalizacje podczas śledzenia.
|
||||||
* Przyrost i utrata wysokości: poprzez czujnik barometryczny
|
* Zmiana wysokości: poprzez czujnik barometryczny
|
||||||
* Wysokość pokazana w EGM2008 (powyżej średniego poziomu morza); wyeksportowana jako WGS84
|
* Wysokość pokazana w EGM2008 (powyżej średniego poziomu morza); wyeksportowana jako WGS84
|
||||||
* Komunikaty głosowe
|
* Komunikaty głosowe
|
||||||
* Obsługa czujników Bluetooth LE: tętno, prędkość i dystans (kolarstwo), kadencja (kolarstwo) i miernik mocy (kolarstwo)
|
* Obsługa czujników Bluetooth LE: tętno, prędkość i dystans (kolarstwo), kadencja (kolarstwo) i miernik mocy (kolarstwo)
|
||||||
* Eksport danych: eksport tras jako KMZ (w tym zdjęcia), KML lub GPX
|
* Eksport danych: eksport tras jako KMZ (w tym zdjęcia), KML lub GPX
|
||||||
* Brak dostępu do Internetu: Internet nie jest używany
|
* Dostępu do Internetu: Internet nie jest używany
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
#Wed Jul 28 23:10:13 CEST 2021
|
#Wed Jul 28 23:10:13 CEST 2021
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
<issue id="ExtraTranslation" severity="error" />
|
<issue id="ExtraTranslation" severity="error" />
|
||||||
<issue id="GifUsage" severity="error" />
|
<issue id="GifUsage" severity="error" />
|
||||||
<issue id="InconsistentArrays" severity="error" />
|
<issue id="InconsistentArrays" severity="error" />
|
||||||
|
<issue id="MissingQuantity"
|
||||||
|
severity="warning" />
|
||||||
<issue id="MissingTranslation" severity="warning" />
|
<issue id="MissingTranslation" severity="warning" />
|
||||||
<issue id="Proguard" severity="warning" />
|
<issue id="Proguard" severity="warning" />
|
||||||
<issue id="ScrollViewCount" severity="error" />
|
<issue id="ScrollViewCount" severity="error" />
|
||||||
|
|||||||
@@ -1,138 +0,0 @@
|
|||||||
package de.dennisguse.opentracks;
|
|
||||||
|
|
||||||
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
|
||||||
import androidx.test.espresso.NoMatchingViewException;
|
|
||||||
import androidx.test.espresso.UiController;
|
|
||||||
import androidx.test.espresso.ViewAction;
|
|
||||||
import androidx.test.espresso.ViewAssertion;
|
|
||||||
import androidx.test.espresso.ViewInteraction;
|
|
||||||
import androidx.test.espresso.action.MotionEvents;
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|
||||||
import androidx.test.filters.LargeTest;
|
|
||||||
import androidx.test.rule.ActivityTestRule;
|
|
||||||
import androidx.test.rule.GrantPermissionRule;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.ViewParent;
|
|
||||||
|
|
||||||
import static androidx.test.espresso.Espresso.onView;
|
|
||||||
import static androidx.test.espresso.action.ViewActions.*;
|
|
||||||
import static androidx.test.espresso.matcher.ViewMatchers.*;
|
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.DataField;
|
|
||||||
import de.dennisguse.opentracks.content.data.Layout;
|
|
||||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
|
||||||
|
|
||||||
import org.hamcrest.Description;
|
|
||||||
import org.hamcrest.Matcher;
|
|
||||||
import org.hamcrest.TypeSafeMatcher;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
|
||||||
|
|
||||||
@LargeTest
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
public class EspressoCustomLayoutTest {
|
|
||||||
|
|
||||||
private final Context context = ApplicationProvider.getApplicationContext();
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public ActivityTestRule<TrackListActivity> mActivityTestRule = new ActivityTestRule<>(TrackListActivity.class);
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public GrantPermissionRule mGrantPermissionRule =
|
|
||||||
GrantPermissionRule.grant(
|
|
||||||
"android.permission.ACCESS_FINE_LOCATION");
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void customLayoutTest() {
|
|
||||||
// TrackListActivity: start recording
|
|
||||||
ViewInteraction trackControllerRecordButton = onView(withId(R.id.controller_record));
|
|
||||||
trackControllerRecordButton.perform(click());
|
|
||||||
|
|
||||||
// Get custom layout preferences and check all data fields are showed.
|
|
||||||
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
|
||||||
Layout layout = PreferencesUtils.getCustomLayout(sharedPreferences, context);
|
|
||||||
|
|
||||||
onView(withId(R.id.stats_recycler_view)).check(new RecyclerViewItemCountAssertion((int) layout.getFields().stream().filter(DataField::isVisible).count()));
|
|
||||||
|
|
||||||
// stop recording
|
|
||||||
ViewInteraction trackControllerStopButton = onView(withId(R.id.controller_stop));
|
|
||||||
trackControllerStopButton.perform(veryLongTouch(1600));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class RecyclerViewItemCountAssertion implements ViewAssertion {
|
|
||||||
private final int expectedCount;
|
|
||||||
|
|
||||||
public RecyclerViewItemCountAssertion(int expectedCount) {
|
|
||||||
this.expectedCount = expectedCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void check(View view, NoMatchingViewException noViewFoundException) {
|
|
||||||
if (noViewFoundException != null) {
|
|
||||||
throw noViewFoundException;
|
|
||||||
}
|
|
||||||
|
|
||||||
RecyclerView recyclerView = (RecyclerView) view;
|
|
||||||
RecyclerView.Adapter<?> adapter = recyclerView.getAdapter();
|
|
||||||
assertThat(adapter.getItemCount(), is(expectedCount));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Matcher<View> childAtPosition(
|
|
||||||
final Matcher<View> parentMatcher, final int position) {
|
|
||||||
|
|
||||||
return new TypeSafeMatcher<View>() {
|
|
||||||
@Override
|
|
||||||
public void describeTo(Description description) {
|
|
||||||
description.appendText("Child at position " + position + " in parent ");
|
|
||||||
parentMatcher.describeTo(description);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean matchesSafely(View view) {
|
|
||||||
ViewParent parent = view.getParent();
|
|
||||||
return parent instanceof ViewGroup && parentMatcher.matches(parent)
|
|
||||||
&& view.equals(((ViewGroup) parent).getChildAt(position));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ViewAction veryLongTouch(final int duration_ms) {
|
|
||||||
return new ViewAction() {
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return "Perform long touch.";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Matcher<View> getConstraints() {
|
|
||||||
return isDisplayed();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void perform(UiController uiController, final View view) {
|
|
||||||
// Get view absolute position
|
|
||||||
int[] location = new int[2];
|
|
||||||
view.getLocationOnScreen(location);
|
|
||||||
|
|
||||||
// Offset coordinates by view position
|
|
||||||
float[] coordinates = new float[]{location[0] + 1, location[1] + 1};
|
|
||||||
|
|
||||||
// Send down event, pause, and send up
|
|
||||||
MotionEvent down = MotionEvents.sendDown(uiController, coordinates, new float[]{1f, 1f}).down;
|
|
||||||
uiController.loopMainThreadForAtLeast(duration_ms);
|
|
||||||
MotionEvents.sendUp(uiController, down, coordinates);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +1,6 @@
|
|||||||
package de.dennisguse.opentracks;
|
package de.dennisguse.opentracks;
|
||||||
|
|
||||||
|
|
||||||
import android.app.ActivityManager;
|
|
||||||
import android.app.Instrumentation;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.ViewParent;
|
|
||||||
import android.widget.ListView;
|
|
||||||
|
|
||||||
import androidx.test.espresso.Espresso;
|
|
||||||
import androidx.test.espresso.IdlingResource;
|
|
||||||
import androidx.test.espresso.UiController;
|
|
||||||
import androidx.test.espresso.ViewAction;
|
|
||||||
import androidx.test.espresso.ViewInteraction;
|
|
||||||
import androidx.test.espresso.action.MotionEvents;
|
|
||||||
import androidx.test.espresso.assertion.ViewAssertions;
|
|
||||||
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|
||||||
import androidx.test.filters.LargeTest;
|
|
||||||
import androidx.test.platform.app.InstrumentationRegistry;
|
|
||||||
import androidx.test.rule.GrantPermissionRule;
|
|
||||||
|
|
||||||
import org.hamcrest.Description;
|
|
||||||
import org.hamcrest.Matcher;
|
|
||||||
import org.hamcrest.TypeSafeMatcher;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import de.dennisguse.opentracks.services.TrackDeleteService;
|
|
||||||
|
|
||||||
import static androidx.test.espresso.Espresso.onData;
|
import static androidx.test.espresso.Espresso.onData;
|
||||||
import static androidx.test.espresso.Espresso.onView;
|
import static androidx.test.espresso.Espresso.onView;
|
||||||
import static androidx.test.espresso.Espresso.pressBack;
|
import static androidx.test.espresso.Espresso.pressBack;
|
||||||
@@ -47,6 +13,37 @@ import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
|||||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||||
import static org.hamcrest.Matchers.allOf;
|
import static org.hamcrest.Matchers.allOf;
|
||||||
import static org.hamcrest.Matchers.anything;
|
import static org.hamcrest.Matchers.anything;
|
||||||
|
import static de.dennisguse.opentracks.util.EspressoUtils.childAtPosition;
|
||||||
|
import static de.dennisguse.opentracks.util.EspressoUtils.veryLongTouch;
|
||||||
|
import static de.dennisguse.opentracks.util.EspressoUtils.waitFor;
|
||||||
|
import static de.dennisguse.opentracks.util.EspressoUtils.withListSize;
|
||||||
|
|
||||||
|
import android.app.ActivityManager;
|
||||||
|
import android.app.Instrumentation;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ListView;
|
||||||
|
|
||||||
|
import androidx.test.espresso.IdlingRegistry;
|
||||||
|
import androidx.test.espresso.IdlingResource;
|
||||||
|
import androidx.test.espresso.ViewInteraction;
|
||||||
|
import androidx.test.espresso.assertion.ViewAssertions;
|
||||||
|
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
import androidx.test.filters.LargeTest;
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry;
|
||||||
|
import androidx.test.rule.GrantPermissionRule;
|
||||||
|
|
||||||
|
import org.hamcrest.Description;
|
||||||
|
import org.hamcrest.TypeSafeMatcher;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.services.TrackDeleteService;
|
||||||
|
|
||||||
@LargeTest
|
@LargeTest
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
@@ -65,12 +62,12 @@ public class EspressoDeleteTrackTest {
|
|||||||
Instrumentation instrumentation
|
Instrumentation instrumentation
|
||||||
= InstrumentationRegistry.getInstrumentation();
|
= InstrumentationRegistry.getInstrumentation();
|
||||||
idlingResource = new MyIdlingResource(instrumentation.getTargetContext());
|
idlingResource = new MyIdlingResource(instrumentation.getTargetContext());
|
||||||
Espresso.registerIdlingResources(idlingResource);
|
IdlingRegistry.getInstance().register(idlingResource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void unregisterIntentServiceIdlingResource() {
|
public void unregisterIntentServiceIdlingResource() {
|
||||||
Espresso.unregisterIdlingResources(idlingResource);
|
IdlingRegistry.getInstance().unregister(idlingResource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("Test fails permanently")
|
@Ignore("Test fails permanently")
|
||||||
@@ -140,87 +137,6 @@ public class EspressoDeleteTrackTest {
|
|||||||
onView(withId(R.id.track_list)).check(ViewAssertions.matches(withListSize(countBefore - 1)));
|
onView(withId(R.id.track_list)).check(ViewAssertions.matches(withListSize(countBefore - 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Matcher<View> childAtPosition(
|
|
||||||
final Matcher<View> parentMatcher, final int position) {
|
|
||||||
|
|
||||||
return new TypeSafeMatcher<>() {
|
|
||||||
@Override
|
|
||||||
public void describeTo(Description description) {
|
|
||||||
description.appendText("Child at position " + position + " in parent ");
|
|
||||||
parentMatcher.describeTo(description);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean matchesSafely(View view) {
|
|
||||||
ViewParent parent = view.getParent();
|
|
||||||
return parent instanceof ViewGroup && parentMatcher.matches(parent)
|
|
||||||
&& view.equals(((ViewGroup) parent).getChildAt(position));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Matcher<View> withListSize (final int size) {
|
|
||||||
return new TypeSafeMatcher<>() {
|
|
||||||
@Override
|
|
||||||
public boolean matchesSafely(final View view) {
|
|
||||||
return ((ListView) view).getCount() == size;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeTo(final Description description) {
|
|
||||||
description.appendText("ListView should have " + size + " items");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ViewAction waitFor(final long duration_ms) {
|
|
||||||
return new ViewAction() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return "Wait for milliseconds.";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Matcher<View> getConstraints() {
|
|
||||||
return isDisplayed();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void perform(UiController uiController, final View view) {
|
|
||||||
uiController.loopMainThreadForAtLeast(duration_ms);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ViewAction veryLongTouch(final int duration_ms) {
|
|
||||||
return new ViewAction() {
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return "Perform long touch.";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Matcher<View> getConstraints() {
|
|
||||||
return isDisplayed();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void perform(UiController uiController, final View view) {
|
|
||||||
// Get view absolute position
|
|
||||||
int[] location = new int[2];
|
|
||||||
view.getLocationOnScreen(location);
|
|
||||||
|
|
||||||
// Offset coordinates by view position
|
|
||||||
float[] coordinates = new float[]{location[0] + 1, location[1] + 1};
|
|
||||||
|
|
||||||
// Send down event, pause, and send up
|
|
||||||
MotionEvent down = MotionEvents.sendDown(uiController, coordinates, new float[]{1f, 1f}).down;
|
|
||||||
uiController.loopMainThreadForAtLeast(duration_ms);
|
|
||||||
MotionEvents.sendUp(uiController, down, coordinates);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private int numberOfItemsListView() {
|
private int numberOfItemsListView() {
|
||||||
final int[] counts = new int[1];
|
final int[] counts = new int[1];
|
||||||
@@ -236,7 +152,6 @@ public class EspressoDeleteTrackTest {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void describeTo(Description description) {
|
public void describeTo(Description description) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|||||||
+16
-152
@@ -2,60 +2,48 @@ package de.dennisguse.opentracks;
|
|||||||
|
|
||||||
|
|
||||||
import static androidx.test.espresso.Espresso.onView;
|
import static androidx.test.espresso.Espresso.onView;
|
||||||
|
import static androidx.test.espresso.Espresso.openContextualActionModeOverflowMenu;
|
||||||
import static androidx.test.espresso.action.ViewActions.click;
|
import static androidx.test.espresso.action.ViewActions.click;
|
||||||
import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard;
|
import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard;
|
||||||
import static androidx.test.espresso.action.ViewActions.replaceText;
|
import static androidx.test.espresso.action.ViewActions.replaceText;
|
||||||
import static androidx.test.espresso.action.ViewActions.scrollTo;
|
import static androidx.test.espresso.action.ViewActions.scrollTo;
|
||||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||||
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
|
|
||||||
import static androidx.test.espresso.matcher.ViewMatchers.withClassName;
|
import static androidx.test.espresso.matcher.ViewMatchers.withClassName;
|
||||||
import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
|
|
||||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||||
import static androidx.test.espresso.matcher.ViewMatchers.withParent;
|
import static androidx.test.espresso.matcher.ViewMatchers.withParent;
|
||||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||||
import static org.hamcrest.Matchers.allOf;
|
import static org.hamcrest.Matchers.allOf;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static de.dennisguse.opentracks.util.EspressoUtils.childAtPosition;
|
||||||
|
import static de.dennisguse.opentracks.util.EspressoUtils.veryLongTouch;
|
||||||
|
import static de.dennisguse.opentracks.util.EspressoUtils.waitFor;
|
||||||
|
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.ViewParent;
|
|
||||||
|
|
||||||
import androidx.test.espresso.PerformException;
|
|
||||||
import androidx.test.espresso.UiController;
|
|
||||||
import androidx.test.espresso.ViewAction;
|
|
||||||
import androidx.test.espresso.ViewInteraction;
|
import androidx.test.espresso.ViewInteraction;
|
||||||
import androidx.test.espresso.action.MotionEvents;
|
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
||||||
import androidx.test.espresso.util.HumanReadables;
|
|
||||||
import androidx.test.espresso.util.TreeIterables;
|
|
||||||
import androidx.test.filters.LargeTest;
|
|
||||||
import androidx.test.rule.ActivityTestRule;
|
|
||||||
import androidx.test.rule.GrantPermissionRule;
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
import androidx.test.filters.LargeTest;
|
||||||
|
import androidx.test.rule.GrantPermissionRule;
|
||||||
|
|
||||||
import org.hamcrest.Description;
|
|
||||||
import org.hamcrest.Matcher;
|
|
||||||
import org.hamcrest.TypeSafeMatcher;
|
|
||||||
import org.hamcrest.core.IsInstanceOf;
|
import org.hamcrest.core.IsInstanceOf;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.Locale;
|
||||||
|
|
||||||
@LargeTest
|
@LargeTest
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class EspressoEditTrackRecordingTest {
|
public class EspressoEditTrackRecordingTest {
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public ActivityTestRule<TrackListActivity> mActivityTestRule = new ActivityTestRule<>(TrackListActivity.class);
|
public final LocaleRule mLocaleRule = new LocaleRule(Locale.ENGLISH);
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public GrantPermissionRule mGrantPermissionRule =
|
public ActivityScenarioRule<TrackListActivity> mActivityTestRule = new ActivityScenarioRule<>(TrackListActivity.class);
|
||||||
GrantPermissionRule.grant(
|
|
||||||
"android.permission.ACCESS_FINE_LOCATION",
|
@Rule
|
||||||
"android.permission.ACCESS_COARSE_LOCATION");
|
public GrantPermissionRule mGrantPermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
|
||||||
|
|
||||||
@LargeTest
|
@LargeTest
|
||||||
@Test
|
@Test
|
||||||
@@ -74,26 +62,10 @@ public class EspressoEditTrackRecordingTest {
|
|||||||
trackControllerRecordButton.perform(waitFor(15000));
|
trackControllerRecordButton.perform(waitFor(15000));
|
||||||
|
|
||||||
// open menu
|
// open menu
|
||||||
ViewInteraction overflowMenuButton = onView(
|
openContextualActionModeOverflowMenu();
|
||||||
allOf(withContentDescription("More options"),
|
|
||||||
childAtPosition(
|
|
||||||
childAtPosition(
|
|
||||||
withId(R.id.toolbar),
|
|
||||||
2),
|
|
||||||
2),
|
|
||||||
isDisplayed()));
|
|
||||||
overflowMenuButton.perform(click());
|
|
||||||
|
|
||||||
// click on edit
|
// Click the item.
|
||||||
ViewInteraction appCompatTextView = onView(
|
onView(withText(R.string.menu_edit)).perform(click());
|
||||||
allOf(withId(R.id.title), withText("Edit"),
|
|
||||||
childAtPosition(
|
|
||||||
childAtPosition(
|
|
||||||
withId(R.id.content),
|
|
||||||
0),
|
|
||||||
0),
|
|
||||||
isDisplayed()));
|
|
||||||
appCompatTextView.perform(click());
|
|
||||||
|
|
||||||
// change name for "New Name"
|
// change name for "New Name"
|
||||||
ViewInteraction textInputEditText = onView(
|
ViewInteraction textInputEditText = onView(
|
||||||
@@ -150,112 +122,4 @@ public class EspressoEditTrackRecordingTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Matcher<View> childAtPosition(
|
|
||||||
final Matcher<View> parentMatcher, final int position) {
|
|
||||||
|
|
||||||
return new TypeSafeMatcher<>() {
|
|
||||||
@Override
|
|
||||||
public void describeTo(Description description) {
|
|
||||||
description.appendText("Child at position " + position + " in parent ");
|
|
||||||
parentMatcher.describeTo(description);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean matchesSafely(View view) {
|
|
||||||
ViewParent parent = view.getParent();
|
|
||||||
return parent instanceof ViewGroup && parentMatcher.matches(parent)
|
|
||||||
&& view.equals(((ViewGroup) parent).getChildAt(position));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ViewAction waitId(final int viewId, final long millis) {
|
|
||||||
return new ViewAction() {
|
|
||||||
@Override
|
|
||||||
public Matcher<View> getConstraints() {
|
|
||||||
return isRoot();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return "wait for a specific view with id <" + viewId + "> during " + millis + " millis.";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void perform(final UiController uiController, final View view) {
|
|
||||||
uiController.loopMainThreadUntilIdle();
|
|
||||||
final long startTime = System.currentTimeMillis();
|
|
||||||
final long endTime = startTime + millis;
|
|
||||||
final Matcher<View> viewMatcher = withId(viewId);
|
|
||||||
|
|
||||||
do {
|
|
||||||
for (View child : TreeIterables.breadthFirstViewTraversal(view)) {
|
|
||||||
// found view with required ID
|
|
||||||
if (viewMatcher.matches(child)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uiController.loopMainThreadForAtLeast(50);
|
|
||||||
}
|
|
||||||
while (System.currentTimeMillis() < endTime);
|
|
||||||
|
|
||||||
// timeout happens
|
|
||||||
throw new PerformException.Builder()
|
|
||||||
.withActionDescription(this.getDescription())
|
|
||||||
.withViewDescription(HumanReadables.describe(view))
|
|
||||||
.withCause(new TimeoutException())
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ViewAction waitFor(final long duration_ms) {
|
|
||||||
return new ViewAction() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return "Wait for milliseconds.";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Matcher<View> getConstraints() {
|
|
||||||
return isDisplayed();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void perform(UiController uiController, final View view) {
|
|
||||||
uiController.loopMainThreadForAtLeast(duration_ms);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ViewAction veryLongTouch(final int duration_ms) {
|
|
||||||
return new ViewAction() {
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return "Perform long touch.";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Matcher<View> getConstraints() {
|
|
||||||
return isDisplayed();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void perform(UiController uiController, final View view) {
|
|
||||||
// Get view absolute position
|
|
||||||
int[] location = new int[2];
|
|
||||||
view.getLocationOnScreen(location);
|
|
||||||
|
|
||||||
// Offset coordinates by view position
|
|
||||||
float[] coordinates = new float[]{location[0] + 1, location[1] + 1};
|
|
||||||
|
|
||||||
// Send down event, pause, and send up
|
|
||||||
MotionEvent down = MotionEvents.sendDown(uiController, coordinates, new float[]{1f, 1f}).down;
|
|
||||||
uiController.loopMainThreadForAtLeast(duration_ms);
|
|
||||||
MotionEvents.sendUp(uiController, down, coordinates);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
package de.dennisguse.opentracks;
|
package de.dennisguse.opentracks;
|
||||||
|
|
||||||
|
import static androidx.test.espresso.Espresso.onData;
|
||||||
|
import static androidx.test.espresso.Espresso.onView;
|
||||||
|
import static androidx.test.espresso.action.ViewActions.click;
|
||||||
|
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||||
|
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||||
|
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||||
|
import static org.hamcrest.Matchers.anything;
|
||||||
|
import static de.dennisguse.opentracks.util.EspressoUtils.selectTabAtIndex;
|
||||||
|
import static de.dennisguse.opentracks.util.EspressoUtils.waitFor;
|
||||||
|
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
@@ -12,21 +22,11 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|||||||
import androidx.test.filters.LargeTest;
|
import androidx.test.filters.LargeTest;
|
||||||
import androidx.test.rule.GrantPermissionRule;
|
import androidx.test.rule.GrantPermissionRule;
|
||||||
|
|
||||||
import com.google.android.material.tabs.TabLayout;
|
|
||||||
|
|
||||||
import org.hamcrest.Matcher;
|
import org.hamcrest.Matcher;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
import static androidx.test.espresso.Espresso.onData;
|
|
||||||
import static androidx.test.espresso.Espresso.onView;
|
|
||||||
import static androidx.test.espresso.action.ViewActions.click;
|
|
||||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
|
||||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
|
||||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
|
||||||
import static org.hamcrest.Matchers.anything;
|
|
||||||
|
|
||||||
@LargeTest
|
@LargeTest
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class EspressoUITest {
|
public class EspressoUITest {
|
||||||
@@ -136,43 +136,4 @@ public class EspressoUITest {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ViewAction waitFor(final long duration_ms) {
|
|
||||||
return new ViewAction() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return "Wait for milliseconds.";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Matcher<View> getConstraints() {
|
|
||||||
return isDisplayed();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void perform(UiController uiController, final View view) {
|
|
||||||
uiController.loopMainThreadForAtLeast(duration_ms);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ViewAction selectTabAtIndex(final int index) {
|
|
||||||
return new ViewAction() {
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return "Selecting tab.";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Matcher<View> getConstraints() {
|
|
||||||
return isDisplayed();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void perform(UiController uiController, View view) {
|
|
||||||
TabLayout tabLayout = (TabLayout) view;
|
|
||||||
tabLayout.getTabAt(index).select();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package de.dennisguse.opentracks;
|
||||||
|
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
|
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
|
||||||
|
import org.junit.rules.TestRule;
|
||||||
|
import org.junit.runner.Description;
|
||||||
|
import org.junit.runners.model.Statement;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public class LocaleRule implements TestRule {
|
||||||
|
|
||||||
|
private final Locale[] mLocales;
|
||||||
|
private Locale mDeviceLocale;
|
||||||
|
|
||||||
|
|
||||||
|
public LocaleRule(Locale... locales) {
|
||||||
|
assert locales != null && locales.length > 0;
|
||||||
|
mLocales = locales;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Statement apply(Statement base, Description description) {
|
||||||
|
return new Statement() {
|
||||||
|
@Override
|
||||||
|
public void evaluate() throws Throwable {
|
||||||
|
try {
|
||||||
|
mDeviceLocale = Locale.getDefault();
|
||||||
|
for (Locale locale : mLocales) {
|
||||||
|
setLocale(locale);
|
||||||
|
base.evaluate();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (mDeviceLocale != null) {
|
||||||
|
setLocale(mDeviceLocale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setLocale(Locale locale) {
|
||||||
|
Resources resources = ApplicationProvider.getApplicationContext().getResources();
|
||||||
|
Locale.setDefault(locale);
|
||||||
|
Configuration config = resources.getConfiguration();
|
||||||
|
config.setLocale(locale);
|
||||||
|
DisplayMetrics displayMetrics = resources.getDisplayMetrics();
|
||||||
|
resources.updateConfiguration(config, displayMetrics);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,22 +1,15 @@
|
|||||||
package de.dennisguse.opentracks;
|
package de.dennisguse.opentracks;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
|
|
||||||
import org.junit.rules.TestRule;
|
import org.junit.rules.TestRule;
|
||||||
import org.junit.runner.Description;
|
import org.junit.runner.Description;
|
||||||
import org.junit.runners.model.Statement;
|
import org.junit.runners.model.Statement;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||||
|
|
||||||
public class PreferenceMetricUnitRule implements TestRule {
|
public class PreferenceMetricUnitRule implements TestRule {
|
||||||
private final Context context;
|
|
||||||
private final boolean metricUnits;
|
private final boolean metricUnits;
|
||||||
|
|
||||||
public PreferenceMetricUnitRule(@NonNull Context context, boolean metricUnits) {
|
public PreferenceMetricUnitRule(boolean metricUnits) {
|
||||||
this.context = context;
|
|
||||||
this.metricUnits = metricUnits;
|
this.metricUnits = metricUnits;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,14 +18,13 @@ public class PreferenceMetricUnitRule implements TestRule {
|
|||||||
return new Statement() {
|
return new Statement() {
|
||||||
@Override
|
@Override
|
||||||
public void evaluate() throws Throwable {
|
public void evaluate() throws Throwable {
|
||||||
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
final boolean previousMetricUnits = PreferencesUtils.isMetricUnits();
|
||||||
final boolean previousMetricUnits = PreferencesUtils.isMetricUnits(sharedPreferences, context);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
PreferencesUtils.setMetricUnits(sharedPreferences, context, metricUnits);
|
PreferencesUtils.setMetricUnits(metricUnits);
|
||||||
base.evaluate();
|
base.evaluate();
|
||||||
} finally {
|
} finally {
|
||||||
PreferencesUtils.setMetricUnits(sharedPreferences, context, previousMetricUnits);
|
PreferencesUtils.setMetricUnits(previousMetricUnits);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package de.dennisguse.opentracks;
|
||||||
|
|
||||||
|
public class TestApplication extends Startup {
|
||||||
|
@Override
|
||||||
|
public String getDatabaseName() {
|
||||||
|
// null will make SQLiteOpenHelper create an in-memory database
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package de.dennisguse.opentracks;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.test.runner.AndroidJUnitRunner;
|
||||||
|
|
||||||
|
public class TestRunner extends AndroidJUnitRunner {
|
||||||
|
@Override
|
||||||
|
public Application newApplication(ClassLoader cl, String className, Context context) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
|
||||||
|
return super.newApplication(cl, TestApplication.class.getName(), context);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
package de.dennisguse.opentracks.chart;
|
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 androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -7,15 +10,12 @@ import org.junit.runner.RunWith;
|
|||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
import de.dennisguse.opentracks.data.models.Altitude;
|
||||||
import de.dennisguse.opentracks.content.data.Speed;
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.data.models.Speed;
|
||||||
import de.dennisguse.opentracks.fragments.TrackStubUtils;
|
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class ChartPointTest {
|
public class ChartPointTest {
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ public class ChartPointTest {
|
|||||||
statistics.setTotalTime(Duration.ofSeconds(1000));
|
statistics.setTotalTime(Duration.ofSeconds(1000));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
ChartPoint point = new ChartPoint(statistics, TrackStubUtils.createDefaultTrackPoint(), Speed.of(0), 0, false, false);
|
ChartPoint point = new ChartPoint(statistics, TrackStubUtils.createDefaultTrackPoint(), Speed.of(0), Altitude.EGM2008.of(0), false, false);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(1000000, (long) point.getTimeOrDistance());
|
assertEquals(1000000, (long) point.getTimeOrDistance());
|
||||||
@@ -39,7 +39,7 @@ public class ChartPointTest {
|
|||||||
statistics.setTotalDistance(Distance.of(1000));
|
statistics.setTotalDistance(Distance.of(1000));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
ChartPoint point = new ChartPoint(statistics, TrackStubUtils.createDefaultTrackPoint(), Speed.of(0), 0, true, true);
|
ChartPoint point = new ChartPoint(statistics, TrackStubUtils.createDefaultTrackPoint(), Speed.of(0), Altitude.EGM2008.of(0), true, true);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(1, (long) point.getTimeOrDistance());
|
assertEquals(1, (long) point.getTimeOrDistance());
|
||||||
@@ -51,7 +51,7 @@ public class ChartPointTest {
|
|||||||
TrackStatistics statistics = new TrackStatistics();
|
TrackStatistics statistics = new TrackStatistics();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
ChartPoint point = new ChartPoint(statistics, TrackStubUtils.createDefaultTrackPoint(), Speed.of(10), 50, false, true);
|
ChartPoint point = new ChartPoint(statistics, TrackStubUtils.createDefaultTrackPoint(), Speed.of(10), Altitude.EGM2008.of(50), false, true);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(50, point.getAltitude(), 0.01);
|
assertEquals(50, point.getAltitude(), 0.01);
|
||||||
@@ -65,7 +65,7 @@ public class ChartPointTest {
|
|||||||
TrackStatistics statistics = new TrackStatistics();
|
TrackStatistics statistics = new TrackStatistics();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
ChartPoint point = new ChartPoint(statistics, TrackStubUtils.createDefaultTrackPoint(), Speed.of(10), 50, false, true);
|
ChartPoint point = new ChartPoint(statistics, TrackStubUtils.createDefaultTrackPoint(), Speed.of(10), Altitude.EGM2008.of(50), false, true);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertNull(point.getHeartRate());
|
assertNull(point.getHeartRate());
|
||||||
@@ -77,14 +77,14 @@ public class ChartPointTest {
|
|||||||
public void create_sensorAvailable() {
|
public void create_sensorAvailable() {
|
||||||
// given
|
// given
|
||||||
TrackPoint trackPoint = TrackStubUtils.createDefaultTrackPoint();
|
TrackPoint trackPoint = TrackStubUtils.createDefaultTrackPoint();
|
||||||
trackPoint.setHeartRate_bpm(100f);
|
trackPoint.setHeartRate(100f);
|
||||||
trackPoint.setCyclingCadence_rpm(101f);
|
trackPoint.setCadence(101f);
|
||||||
trackPoint.setPower(102f);
|
trackPoint.setPower(102f);
|
||||||
|
|
||||||
TrackStatistics statistics = new TrackStatistics();
|
TrackStatistics statistics = new TrackStatistics();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
ChartPoint point = new ChartPoint(statistics, trackPoint, Speed.of(10), 50, false, true);
|
ChartPoint point = new ChartPoint(statistics, trackPoint, Speed.of(10), Altitude.EGM2008.of(50), false, true);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(100.0, point.getHeartRate(), 0.01);
|
assertEquals(100.0, point.getHeartRate(), 0.01);
|
||||||
|
|||||||
+5
-5
@@ -14,20 +14,20 @@
|
|||||||
* the License.
|
* the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package de.dennisguse.opentracks.fragments;
|
package de.dennisguse.opentracks.chart;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
import de.dennisguse.opentracks.content.data.Speed;
|
import de.dennisguse.opentracks.data.models.Speed;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Commons utilities for creating stubs of track, location.
|
* Commons utilities for creating stubs of track, location.
|
||||||
*
|
*
|
||||||
* @author Youtao Liu
|
* @author Youtao Liu
|
||||||
*/
|
*/
|
||||||
public class TrackStubUtils {
|
class TrackStubUtils {
|
||||||
|
|
||||||
public static final double INITIAL_ALTITUDE = 22;
|
public static final double INITIAL_ALTITUDE = 22;
|
||||||
public static final long INITIAL_TIME = 1000L;
|
public static final long INITIAL_TIME = 1000L;
|
||||||
@@ -11,10 +11,16 @@ import java.time.Instant;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
import de.dennisguse.opentracks.data.TrackPointIterator;
|
||||||
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
|
import de.dennisguse.opentracks.data.models.Marker;
|
||||||
|
import de.dennisguse.opentracks.data.models.Speed;
|
||||||
|
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.TrackStatistics;
|
||||||
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
|
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
|
||||||
|
import de.dennisguse.opentracks.ui.markers.MarkerUtils;
|
||||||
import de.dennisguse.opentracks.util.FileUtils;
|
import de.dennisguse.opentracks.util.FileUtils;
|
||||||
|
|
||||||
public class TestDataUtil {
|
public class TestDataUtil {
|
||||||
@@ -119,8 +125,8 @@ public class TestDataUtil {
|
|||||||
trackPoint.setAltitude(i * ALTITUDE_INTERVAL);
|
trackPoint.setAltitude(i * ALTITUDE_INTERVAL);
|
||||||
trackPoint.setSpeed(Speed.of(5f + (i / 10f)));
|
trackPoint.setSpeed(Speed.of(5f + (i / 10f)));
|
||||||
|
|
||||||
trackPoint.setHeartRate_bpm(100f + i);
|
trackPoint.setHeartRate(100f + i % 80);
|
||||||
trackPoint.setCyclingCadence_rpm(300f + i);
|
trackPoint.setCadence(300f + i);
|
||||||
trackPoint.setPower(400f + i);
|
trackPoint.setPower(400f + i);
|
||||||
trackPoint.setAltitudeGain(ALTITUDE_GAIN);
|
trackPoint.setAltitudeGain(ALTITUDE_GAIN);
|
||||||
trackPoint.setAltitudeLoss(ALTITUDE_LOSS);
|
trackPoint.setAltitudeLoss(ALTITUDE_LOSS);
|
||||||
@@ -145,7 +151,7 @@ public class TestDataUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Marker createMarkerWithPhoto(Context context, Track.Id trackId, TrackPoint trackPoint) throws IOException {
|
public static Marker createMarkerWithPhoto(Context context, Track.Id trackId, TrackPoint trackPoint) throws IOException {
|
||||||
File dstFile = new File(FileUtils.getImageUrl(context, trackId));
|
File dstFile = new File(MarkerUtils.getImageUrl(context, trackId));
|
||||||
dstFile.createNewFile();
|
dstFile.createNewFile();
|
||||||
Uri photoUri = FileUtils.getUriForFile(context, dstFile);
|
Uri photoUri = FileUtils.getUriForFile(context, dstFile);
|
||||||
String photoUrl = photoUri.toString();
|
String photoUrl = photoUri.toString();
|
||||||
@@ -177,7 +183,7 @@ public class TestDataUtil {
|
|||||||
for (int i = 0; i < numberOfPoints; i++) {
|
for (int i = 0; i < numberOfPoints; i++) {
|
||||||
TrackPoint tp = TestDataUtil.createTrackPoint(i);
|
TrackPoint tp = TestDataUtil.createTrackPoint(i);
|
||||||
contentProviderUtils.insertTrackPoint(tp, dummyTrack.getId());
|
contentProviderUtils.insertTrackPoint(tp, dummyTrack.getId());
|
||||||
trackStatisticsUpdater.addTrackPoint(tp, Distance.of(0));
|
trackStatisticsUpdater.addTrackPoint(tp);
|
||||||
}
|
}
|
||||||
dummyTrack.setTrackStatistics(trackStatisticsUpdater.getTrackStatistics());
|
dummyTrack.setTrackStatistics(trackStatisticsUpdater.getTrackStatistics());
|
||||||
contentProviderUtils.updateTrack(dummyTrack);
|
contentProviderUtils.updateTrack(dummyTrack);
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ import java.time.Instant;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
|
import de.dennisguse.opentracks.data.models.Speed;
|
||||||
|
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||||
|
|
||||||
public class TestSensorDataUtil {
|
public class TestSensorDataUtil {
|
||||||
|
|
||||||
private final List<TrackPoint> trackPointList = new ArrayList<>();
|
private final List<TrackPoint> trackPointList = new ArrayList<>();
|
||||||
@@ -16,9 +20,15 @@ public class TestSensorDataUtil {
|
|||||||
int i = trackPointList.size() + 1;
|
int i = trackPointList.size() + 1;
|
||||||
tp.setLatitude(TestDataUtil.INITIAL_LATITUDE + (double) i / 10000.0);
|
tp.setLatitude(TestDataUtil.INITIAL_LATITUDE + (double) i / 10000.0);
|
||||||
tp.setLongitude(TestDataUtil.INITIAL_LONGITUDE - (double) i / 10000.0);
|
tp.setLongitude(TestDataUtil.INITIAL_LONGITUDE - (double) i / 10000.0);
|
||||||
tp.setHeartRate_bpm(hr);
|
if (hr != null) {
|
||||||
tp.setCyclingCadence_rpm(cadence);
|
tp.setHeartRate(hr);
|
||||||
|
}
|
||||||
|
if (cadence != null) {
|
||||||
|
tp.setCadence(cadence);
|
||||||
|
}
|
||||||
|
if (power != null) {
|
||||||
tp.setPower(power);
|
tp.setPower(power);
|
||||||
|
}
|
||||||
tp.setHorizontalAccuracy(Distance.of(1f));
|
tp.setHorizontalAccuracy(Distance.of(1f));
|
||||||
tp.setAltitude(1f);
|
tp.setAltitude(1f);
|
||||||
tp.setSpeed(Speed.of(5f + (i / 10f)));
|
tp.setSpeed(Speed.of(5f + (i / 10f)));
|
||||||
|
|||||||
+7
-7
@@ -14,7 +14,10 @@
|
|||||||
* the License.
|
* the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package de.dennisguse.opentracks.content.provider;
|
package de.dennisguse.opentracks.data;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import android.content.ContentUris;
|
import android.content.ContentUris;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -25,12 +28,9 @@ import androidx.test.core.app.ApplicationProvider;
|
|||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.MarkerColumns;
|
import de.dennisguse.opentracks.data.tables.MarkerColumns;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
import de.dennisguse.opentracks.data.tables.TrackPointsColumns;
|
||||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
import de.dennisguse.opentracks.data.tables.TracksColumns;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link CustomContentProvider}.
|
* Tests {@link CustomContentProvider}.
|
||||||
+111
-122
@@ -13,7 +13,14 @@
|
|||||||
* License for the specific language governing permissions and limitations under
|
* License for the specific language governing permissions and limitations under
|
||||||
* the License.
|
* the License.
|
||||||
*/
|
*/
|
||||||
package de.dennisguse.opentracks.content.provider;
|
package de.dennisguse.opentracks.data;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.ContentUris;
|
import android.content.ContentUris;
|
||||||
@@ -42,27 +49,20 @@ import java.util.Random;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
|
||||||
import de.dennisguse.opentracks.content.data.Marker;
|
|
||||||
import de.dennisguse.opentracks.content.data.MarkerColumns;
|
|
||||||
import de.dennisguse.opentracks.content.data.Speed;
|
|
||||||
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||||
import de.dennisguse.opentracks.content.data.TestSensorDataUtil;
|
import de.dennisguse.opentracks.content.data.TestSensorDataUtil;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.data.models.HeartRate;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
import de.dennisguse.opentracks.data.models.Marker;
|
||||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
import de.dennisguse.opentracks.data.models.Speed;
|
||||||
|
import de.dennisguse.opentracks.data.models.Track;
|
||||||
|
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.SensorStatistics;
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
import de.dennisguse.opentracks.util.FileUtils;
|
import de.dennisguse.opentracks.util.FileUtils;
|
||||||
import de.dennisguse.opentracks.util.UUIDUtils;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A unit test for {@link ContentProviderUtils}.
|
* A unit test for {@link ContentProviderUtils}.
|
||||||
@@ -192,6 +192,19 @@ public class CustomContentProviderUtilsTest {
|
|||||||
assertEquals(name, track.getName());
|
assertEquals(name, track.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertCount(int trackCount, int trackPointCount, int markerCount) {
|
||||||
|
ContentResolver contentResolver = context.getContentResolver();
|
||||||
|
try (Cursor tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID)) {
|
||||||
|
assertEquals(trackCount, tracksCursor.getCount());
|
||||||
|
}
|
||||||
|
try (Cursor tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, null, null, null, TrackPointsColumns._ID)) {
|
||||||
|
assertEquals(trackPointCount, tracksPointsCursor.getCount());
|
||||||
|
}
|
||||||
|
try (Cursor markerCursor = contentResolver.query(MarkerColumns.CONTENT_URI, null, null, null, MarkerColumns._ID)) {
|
||||||
|
assertEquals(markerCount, markerCursor.getCount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the method {@link ContentProviderUtils#deleteAllTracks(Context)}
|
* Tests the method {@link ContentProviderUtils#deleteAllTracks(Context)}
|
||||||
*/
|
*/
|
||||||
@@ -204,22 +217,13 @@ public class CustomContentProviderUtilsTest {
|
|||||||
Marker marker = new Marker(trackId, contentProviderUtils.getLastValidTrackPoint(trackId));
|
Marker marker = new Marker(trackId, contentProviderUtils.getLastValidTrackPoint(trackId));
|
||||||
contentProviderUtils.insertMarker(marker);
|
contentProviderUtils.insertMarker(marker);
|
||||||
|
|
||||||
ContentResolver contentResolver = context.getContentResolver();
|
assertCount(1, 10, 1);
|
||||||
Cursor tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
|
||||||
assertEquals(1, tracksCursor.getCount());
|
// when
|
||||||
Cursor tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, null, null, null, TrackPointsColumns._ID);
|
|
||||||
assertEquals(10, tracksPointsCursor.getCount());
|
|
||||||
Cursor markerCursor = contentResolver.query(MarkerColumns.CONTENT_URI, null, null, null, MarkerColumns._ID);
|
|
||||||
assertEquals(1, markerCursor.getCount());
|
|
||||||
// Delete all.
|
|
||||||
contentProviderUtils.deleteAllTracks(context);
|
contentProviderUtils.deleteAllTracks(context);
|
||||||
// Check whether all have been deleted.
|
|
||||||
tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
// then
|
||||||
assertEquals(0, tracksCursor.getCount());
|
assertCount(0, 0, 0);
|
||||||
tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, null, null, null, TrackPointsColumns._ID);
|
|
||||||
assertEquals(0, tracksPointsCursor.getCount());
|
|
||||||
markerCursor = contentResolver.query(MarkerColumns.CONTENT_URI, null, null, null, MarkerColumns._ID);
|
|
||||||
assertEquals(0, markerCursor.getCount());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -235,28 +239,18 @@ public class CustomContentProviderUtilsTest {
|
|||||||
Marker marker = TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint);
|
Marker marker = TestDataUtil.createMarkerWithPhoto(context, trackId, trackPoint);
|
||||||
contentProviderUtils.insertMarker(marker);
|
contentProviderUtils.insertMarker(marker);
|
||||||
|
|
||||||
ContentResolver contentResolver = context.getContentResolver();
|
assertCount(1, 10, 1);
|
||||||
Cursor tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
|
||||||
assertEquals(1, tracksCursor.getCount());
|
|
||||||
Cursor tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, null, null, null, TrackPointsColumns._ID);
|
|
||||||
assertEquals(10, tracksPointsCursor.getCount());
|
|
||||||
Cursor markerCursor = contentResolver.query(MarkerColumns.CONTENT_URI, null, null, null, MarkerColumns._ID);
|
|
||||||
assertEquals(1, markerCursor.getCount());
|
|
||||||
// Check marker has photo and it's in the external storage.
|
|
||||||
assertTrue(marker.hasPhoto());
|
assertTrue(marker.hasPhoto());
|
||||||
File dir = FileUtils.getPhotoDir(context, trackId);
|
File dir = FileUtils.getPhotoDir(context, trackId);
|
||||||
assertTrue(dir.isDirectory());
|
assertTrue(dir.isDirectory());
|
||||||
assertEquals(1, dir.list().length);
|
assertEquals(1, dir.list().length);
|
||||||
assertTrue(dir.exists());
|
assertTrue(dir.exists());
|
||||||
// Delete all.
|
|
||||||
|
// when
|
||||||
contentProviderUtils.deleteAllTracks(context);
|
contentProviderUtils.deleteAllTracks(context);
|
||||||
// Check whether all have been deleted.
|
|
||||||
tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
// then
|
||||||
assertEquals(0, tracksCursor.getCount());
|
assertCount(0, 0, 0);
|
||||||
tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, null, null, null, TrackPointsColumns._ID);
|
|
||||||
assertEquals(0, tracksPointsCursor.getCount());
|
|
||||||
markerCursor = contentResolver.query(MarkerColumns.CONTENT_URI, null, null, null, MarkerColumns._ID);
|
|
||||||
assertEquals(0, markerCursor.getCount());
|
|
||||||
assertFalse(dir.exists());
|
assertFalse(dir.exists());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,22 +273,13 @@ public class CustomContentProviderUtilsTest {
|
|||||||
Marker marker = new Marker(trackId1, contentProviderUtils.getLastValidTrackPoint(trackId2));
|
Marker marker = new Marker(trackId1, contentProviderUtils.getLastValidTrackPoint(trackId2));
|
||||||
contentProviderUtils.insertMarker(marker);
|
contentProviderUtils.insertMarker(marker);
|
||||||
|
|
||||||
ContentResolver contentResolver = context.getContentResolver();
|
assertCount(3, 30, 1);
|
||||||
Cursor tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
|
||||||
assertEquals(3, tracksCursor.getCount());
|
// when
|
||||||
Cursor tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, null, null, null, TrackPointsColumns._ID);
|
|
||||||
assertEquals(30, tracksPointsCursor.getCount());
|
|
||||||
Cursor markerCursor = contentResolver.query(MarkerColumns.CONTENT_URI, null, null, null, MarkerColumns._ID);
|
|
||||||
assertEquals(1, markerCursor.getCount());
|
|
||||||
// Delete one track.
|
|
||||||
contentProviderUtils.deleteTrack(context, trackId1);
|
contentProviderUtils.deleteTrack(context, trackId1);
|
||||||
// Check whether all data of a track has been deleted.
|
|
||||||
tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
// then
|
||||||
assertEquals(2, tracksCursor.getCount());
|
assertCount(2, 20, 0);
|
||||||
tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, null, null, null, TrackPointsColumns._ID);
|
|
||||||
assertEquals(20, tracksPointsCursor.getCount());
|
|
||||||
markerCursor = contentResolver.query(MarkerColumns.CONTENT_URI, null, null, null, MarkerColumns._ID);
|
|
||||||
assertEquals(0, markerCursor.getCount());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -324,13 +309,7 @@ public class CustomContentProviderUtilsTest {
|
|||||||
File dir2 = FileUtils.getPhotoDir(context, trackId2);
|
File dir2 = FileUtils.getPhotoDir(context, trackId2);
|
||||||
|
|
||||||
// Check.
|
// Check.
|
||||||
ContentResolver contentResolver = context.getContentResolver();
|
assertCount(3, 30, 2);
|
||||||
Cursor tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
|
||||||
assertEquals(3, tracksCursor.getCount());
|
|
||||||
Cursor tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, null, null, null, TrackPointsColumns._ID);
|
|
||||||
assertEquals(30, tracksPointsCursor.getCount());
|
|
||||||
Cursor markerCursor = contentResolver.query(MarkerColumns.CONTENT_URI, null, null, null, MarkerColumns._ID);
|
|
||||||
assertEquals(2, markerCursor.getCount());
|
|
||||||
assertTrue(marker1.hasPhoto());
|
assertTrue(marker1.hasPhoto());
|
||||||
assertTrue(dir1.isDirectory());
|
assertTrue(dir1.isDirectory());
|
||||||
assertEquals(1, dir1.list().length);
|
assertEquals(1, dir1.list().length);
|
||||||
@@ -338,15 +317,12 @@ public class CustomContentProviderUtilsTest {
|
|||||||
assertTrue(dir2.isDirectory());
|
assertTrue(dir2.isDirectory());
|
||||||
assertEquals(1, dir2.list().length);
|
assertEquals(1, dir2.list().length);
|
||||||
assertTrue(dir2.exists());
|
assertTrue(dir2.exists());
|
||||||
// Delete one track.
|
|
||||||
|
// when
|
||||||
contentProviderUtils.deleteTrack(context, trackId1);
|
contentProviderUtils.deleteTrack(context, trackId1);
|
||||||
// Check whether all data of a track has been deleted.
|
|
||||||
tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
// then
|
||||||
assertEquals(2, tracksCursor.getCount());
|
assertCount(2, 20, 1);
|
||||||
tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI_BY_ID, null, null, null, TrackPointsColumns._ID);
|
|
||||||
assertEquals(20, tracksPointsCursor.getCount());
|
|
||||||
markerCursor = contentResolver.query(MarkerColumns.CONTENT_URI, null, null, null, MarkerColumns._ID);
|
|
||||||
assertEquals(1, markerCursor.getCount());
|
|
||||||
assertFalse(dir1.exists());
|
assertFalse(dir1.exists());
|
||||||
assertTrue(dir2.exists());
|
assertTrue(dir2.exists());
|
||||||
}
|
}
|
||||||
@@ -763,11 +739,19 @@ public class CustomContentProviderUtilsTest {
|
|||||||
Pair<Track, List<TrackPoint>> track = TestDataUtil.createTrack(trackId, 10);
|
Pair<Track, List<TrackPoint>> track = TestDataUtil.createTrack(trackId, 10);
|
||||||
TestDataUtil.insertTrackWithLocations(contentProviderUtils, track.first, track.second);
|
TestDataUtil.insertTrackWithLocations(contentProviderUtils, track.first, track.second);
|
||||||
|
|
||||||
// when / then
|
// when
|
||||||
contentProviderUtils.bulkInsertTrackPoint(track.second, trackId);
|
contentProviderUtils.bulkInsertTrackPoint(track.second, trackId);
|
||||||
assertEquals(20, contentProviderUtils.getTrackPointCursor(trackId, null).getCount());
|
try (Cursor cursor = contentProviderUtils.getTrackPointCursor(trackId, null)) {
|
||||||
|
// then
|
||||||
|
assertEquals(20, cursor.getCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
// when
|
||||||
contentProviderUtils.bulkInsertTrackPoint(track.second.subList(0, 8), trackId);
|
contentProviderUtils.bulkInsertTrackPoint(track.second.subList(0, 8), trackId);
|
||||||
assertEquals(28, contentProviderUtils.getTrackPointCursor(trackId, null).getCount());
|
try (Cursor cursor = contentProviderUtils.getTrackPointCursor(trackId, null)) {
|
||||||
|
// then
|
||||||
|
assertEquals(28, cursor.getCount());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -801,6 +785,7 @@ public class CustomContentProviderUtilsTest {
|
|||||||
|
|
||||||
when(cursorMock.getColumnIndexOrThrow(TrackPointsColumns.SENSOR_HEARTRATE)).thenReturn(6);
|
when(cursorMock.getColumnIndexOrThrow(TrackPointsColumns.SENSOR_HEARTRATE)).thenReturn(6);
|
||||||
when(cursorMock.isNull(6)).thenReturn(false);
|
when(cursorMock.isNull(6)).thenReturn(false);
|
||||||
|
when(cursorMock.getFloat(6)).thenReturn(75f);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
TrackPoint trackPoint = contentProviderUtils.createTrackPoint(cursorMock);
|
TrackPoint trackPoint = contentProviderUtils.createTrackPoint(cursorMock);
|
||||||
@@ -810,7 +795,7 @@ public class CustomContentProviderUtilsTest {
|
|||||||
assertEquals(latitude, trackPoint.getLatitude(), 0.01);
|
assertEquals(latitude, trackPoint.getLatitude(), 0.01);
|
||||||
assertEquals(time, trackPoint.getTime().toEpochMilli());
|
assertEquals(time, trackPoint.getTime().toEpochMilli());
|
||||||
assertEquals(speed, trackPoint.getSpeed().toMPS(), 0.01);
|
assertEquals(speed, trackPoint.getSpeed().toMPS(), 0.01);
|
||||||
assertFalse(trackPoint.hasHeartRate());
|
assertEquals(HeartRate.of(75f), trackPoint.getHeartRate());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -824,7 +809,11 @@ public class CustomContentProviderUtilsTest {
|
|||||||
Track track = TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
Track track = TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||||
|
|
||||||
contentProviderUtils.insertTrackPoint(TestDataUtil.createTrackPoint(22), trackId);
|
contentProviderUtils.insertTrackPoint(TestDataUtil.createTrackPoint(22), trackId);
|
||||||
assertEquals(11, contentProviderUtils.getTrackPointCursor(trackId, null).getCount());
|
// when
|
||||||
|
try (Cursor cursor = contentProviderUtils.getTrackPointCursor(trackId, null)) {
|
||||||
|
// then
|
||||||
|
assertEquals(11, cursor.getCount());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -834,8 +823,8 @@ public class CustomContentProviderUtilsTest {
|
|||||||
Track track = TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
Track track = TestDataUtil.createTrackAndInsert(contentProviderUtils, trackId, 10);
|
||||||
|
|
||||||
TrackPoint trackPoint = TestDataUtil.createTrackPoint(5);
|
TrackPoint trackPoint = TestDataUtil.createTrackPoint(5);
|
||||||
trackPoint.setHeartRate_bpm(1F);
|
trackPoint.setHeartRate(1F);
|
||||||
trackPoint.setCyclingCadence_rpm(2F);
|
trackPoint.setCadence(2F);
|
||||||
trackPoint.setPower(3F);
|
trackPoint.setPower(3F);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
@@ -844,9 +833,9 @@ public class CustomContentProviderUtilsTest {
|
|||||||
// then
|
// then
|
||||||
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
||||||
assertTrue(trackPoints.get(10).hasHeartRate());
|
assertTrue(trackPoints.get(10).hasHeartRate());
|
||||||
assertEquals(trackPoint.getHeartRate_bpm(), trackPoints.get(10).getHeartRate_bpm(), 0.01);
|
assertEquals(trackPoint.getHeartRate(), trackPoints.get(10).getHeartRate());
|
||||||
assertEquals(trackPoint.getCyclingCadence_rpm(), trackPoints.get(10).getCyclingCadence_rpm(), 0.01);
|
assertEquals(trackPoint.getCadence(), trackPoints.get(10).getCadence());
|
||||||
assertEquals(trackPoint.getPower(), trackPoints.get(10).getPower(), 0.01);
|
assertEquals(trackPoint.getPower(), trackPoints.get(10).getPower());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -874,11 +863,11 @@ public class CustomContentProviderUtilsTest {
|
|||||||
.map(TrackPoint.Id::new).collect(Collectors.toList());
|
.map(TrackPoint.Id::new).collect(Collectors.toList());
|
||||||
|
|
||||||
// when
|
// when
|
||||||
Cursor cursor = contentProviderUtils.getTrackPointCursor(trackId, trackpointIds.get(8));
|
try (Cursor cursor = contentProviderUtils.getTrackPointCursor(trackId, trackpointIds.get(8))) {
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(2, cursor.getCount());
|
assertEquals(2, cursor.getCount());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetTrackPointLocationIterator_asc() {
|
public void testGetTrackPointLocationIterator_asc() {
|
||||||
@@ -934,8 +923,8 @@ public class CustomContentProviderUtilsTest {
|
|||||||
TrackPoint trackPoint = TestDataUtil.createTrackPoint(1);
|
TrackPoint trackPoint = TestDataUtil.createTrackPoint(1);
|
||||||
trackPoint.setType(TrackPoint.Type.TRACKPOINT);
|
trackPoint.setType(TrackPoint.Type.TRACKPOINT);
|
||||||
trackPoint.setPower(null);
|
trackPoint.setPower(null);
|
||||||
trackPoint.setCyclingCadence_rpm(null);
|
trackPoint.setCadence(null);
|
||||||
trackPoint.setHeartRate_bpm(null);
|
trackPoint.setHeartRate(null);
|
||||||
trackPointList.add(trackPoint);
|
trackPointList.add(trackPoint);
|
||||||
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
Track.Id trackId = new Track.Id(System.currentTimeMillis());
|
||||||
Track track = TestDataUtil.createTrack(trackId);
|
Track track = TestDataUtil.createTrack(trackId);
|
||||||
@@ -997,13 +986,13 @@ public class CustomContentProviderUtilsTest {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
assertTrue(sensorStatistics.hasHeartRate());
|
assertTrue(sensorStatistics.hasHeartRate());
|
||||||
assertEquals(sensorStatistics.getAvgHeartRate(), stats.avgHr, 0f);
|
assertEquals(sensorStatistics.getAvgHeartRate().getBPM(), stats.avgHr, 0f);
|
||||||
assertEquals(sensorStatistics.getMaxHeartRate(), stats.maxHr, 0f);
|
assertEquals(sensorStatistics.getMaxHeartRate().getBPM(), stats.maxHr, 0f);
|
||||||
assertTrue(sensorStatistics.hasCadence());
|
assertTrue(sensorStatistics.hasCadence());
|
||||||
assertEquals(sensorStatistics.getAvgCadence(), stats.avgCadence, 0f);
|
assertEquals(sensorStatistics.getAvgCadence().getRPM(), stats.avgCadence, 0f);
|
||||||
assertEquals(sensorStatistics.getMaxCadence(), stats.maxCadence, 0f);
|
assertEquals(sensorStatistics.getMaxCadence().getRPM(), stats.maxCadence, 0f);
|
||||||
assertTrue(sensorStatistics.hasPower());
|
assertTrue(sensorStatistics.hasPower());
|
||||||
assertEquals(sensorStatistics.getAvgPower(), stats.avgPower, 0f);
|
assertEquals(sensorStatistics.getAvgPower().getW(), stats.avgPower, 0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1029,8 +1018,8 @@ public class CustomContentProviderUtilsTest {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
assertTrue(sensorStatistics.hasHeartRate());
|
assertTrue(sensorStatistics.hasHeartRate());
|
||||||
assertEquals(sensorStatistics.getAvgHeartRate(), stats.avgHr, 0f);
|
assertEquals(sensorStatistics.getAvgHeartRate().getBPM(), stats.avgHr, 0f);
|
||||||
assertEquals(sensorStatistics.getMaxHeartRate(), stats.maxHr, 0f);
|
assertEquals(sensorStatistics.getMaxHeartRate().getBPM(), stats.maxHr, 0f);
|
||||||
assertFalse(sensorStatistics.hasCadence());
|
assertFalse(sensorStatistics.hasCadence());
|
||||||
assertFalse(sensorStatistics.hasPower());
|
assertFalse(sensorStatistics.hasPower());
|
||||||
}
|
}
|
||||||
@@ -1059,8 +1048,8 @@ public class CustomContentProviderUtilsTest {
|
|||||||
// then
|
// then
|
||||||
assertFalse(sensorStatistics.hasHeartRate());
|
assertFalse(sensorStatistics.hasHeartRate());
|
||||||
assertTrue(sensorStatistics.hasCadence());
|
assertTrue(sensorStatistics.hasCadence());
|
||||||
assertEquals(sensorStatistics.getAvgCadence(), stats.avgCadence, 0f);
|
assertEquals(sensorStatistics.getAvgCadence().getRPM(), stats.avgCadence, 0f);
|
||||||
assertEquals(sensorStatistics.getMaxCadence(), stats.maxCadence, 0f);
|
assertEquals(sensorStatistics.getMaxCadence().getRPM(), stats.maxCadence, 0f);
|
||||||
assertFalse(sensorStatistics.hasPower());
|
assertFalse(sensorStatistics.hasPower());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1089,7 +1078,7 @@ public class CustomContentProviderUtilsTest {
|
|||||||
assertFalse(sensorStatistics.hasHeartRate());
|
assertFalse(sensorStatistics.hasHeartRate());
|
||||||
assertFalse(sensorStatistics.hasCadence());
|
assertFalse(sensorStatistics.hasCadence());
|
||||||
assertTrue(sensorStatistics.hasPower());
|
assertTrue(sensorStatistics.hasPower());
|
||||||
assertEquals(sensorStatistics.getAvgPower(), stats.avgPower, 0f);
|
assertEquals(sensorStatistics.getAvgPower().getW(), stats.avgPower, 0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1122,11 +1111,11 @@ public class CustomContentProviderUtilsTest {
|
|||||||
TestSensorDataUtil.SensorDataStats stats = sensorDataUtil.computeStats();
|
TestSensorDataUtil.SensorDataStats stats = sensorDataUtil.computeStats();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(sensorStatistics.getAvgHeartRate(), stats.avgHr, 0f);
|
assertEquals(sensorStatistics.getAvgHeartRate().getBPM(), stats.avgHr, 0f);
|
||||||
assertEquals(sensorStatistics.getMaxHeartRate(), stats.maxHr, 0f);
|
assertEquals(sensorStatistics.getMaxHeartRate().getBPM(), stats.maxHr, 0f);
|
||||||
assertEquals(sensorStatistics.getAvgCadence(), stats.avgCadence, 0f);
|
assertEquals(sensorStatistics.getAvgCadence().getRPM(), stats.avgCadence, 0f);
|
||||||
assertEquals(sensorStatistics.getMaxCadence(), stats.maxCadence, 0f);
|
assertEquals(sensorStatistics.getMaxCadence().getRPM(), stats.maxCadence, 0f);
|
||||||
assertEquals(sensorStatistics.getAvgPower(), stats.avgPower, 0f);
|
assertEquals(sensorStatistics.getAvgPower().getW(), stats.avgPower, 0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1167,11 +1156,11 @@ public class CustomContentProviderUtilsTest {
|
|||||||
TestSensorDataUtil.SensorDataStats stats = sensorDataUtil.computeStats();
|
TestSensorDataUtil.SensorDataStats stats = sensorDataUtil.computeStats();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(sensorStatistics.getAvgHeartRate(), stats.avgHr, 0f);
|
assertEquals(sensorStatistics.getAvgHeartRate().getBPM(), stats.avgHr, 0f);
|
||||||
assertEquals(sensorStatistics.getMaxHeartRate(), stats.maxHr, 0f);
|
assertEquals(sensorStatistics.getMaxHeartRate().getBPM(), stats.maxHr, 0f);
|
||||||
assertEquals(sensorStatistics.getAvgCadence(), stats.avgCadence, 0f);
|
assertEquals(sensorStatistics.getAvgCadence().getRPM(), stats.avgCadence, 0f);
|
||||||
assertEquals(sensorStatistics.getMaxCadence(), stats.maxCadence, 0f);
|
assertEquals(sensorStatistics.getMaxCadence().getRPM(), stats.maxCadence, 0f);
|
||||||
assertEquals(sensorStatistics.getAvgPower(), stats.avgPower, 0f);
|
assertEquals(sensorStatistics.getAvgPower().getW(), stats.avgPower, 0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1212,11 +1201,11 @@ public class CustomContentProviderUtilsTest {
|
|||||||
TestSensorDataUtil.SensorDataStats stats = sensorDataUtil.computeStats();
|
TestSensorDataUtil.SensorDataStats stats = sensorDataUtil.computeStats();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(sensorStatistics.getAvgHeartRate(), stats.avgHr, 0f);
|
assertEquals(sensorStatistics.getAvgHeartRate().getBPM(), stats.avgHr, 0f);
|
||||||
assertEquals(sensorStatistics.getMaxHeartRate(), stats.maxHr, 0f);
|
assertEquals(sensorStatistics.getMaxHeartRate().getBPM(), stats.maxHr, 0f);
|
||||||
assertEquals(sensorStatistics.getAvgCadence(), stats.avgCadence, 0f);
|
assertEquals(sensorStatistics.getAvgCadence().getRPM(), stats.avgCadence, 0f);
|
||||||
assertEquals(sensorStatistics.getMaxCadence(), stats.maxCadence, 0f);
|
assertEquals(sensorStatistics.getMaxCadence().getRPM(), stats.maxCadence, 0f);
|
||||||
assertEquals(sensorStatistics.getAvgPower(), stats.avgPower, 0f);
|
assertEquals(sensorStatistics.getAvgPower().getW(), stats.avgPower, 0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testGetSensorStats_randomData(int totalPoints, boolean withStartSegments) {
|
private void testGetSensorStats_randomData(int totalPoints, boolean withStartSegments) {
|
||||||
@@ -1243,11 +1232,11 @@ public class CustomContentProviderUtilsTest {
|
|||||||
TestSensorDataUtil.SensorDataStats stats = sensorDataUtil.computeStats();
|
TestSensorDataUtil.SensorDataStats stats = sensorDataUtil.computeStats();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(sensorStatistics.getAvgHeartRate(), stats.avgHr, 0.01f);
|
assertEquals(sensorStatistics.getAvgHeartRate().getBPM(), stats.avgHr, 0.01f);
|
||||||
assertEquals(sensorStatistics.getMaxHeartRate(), stats.maxHr, 0.01f);
|
assertEquals(sensorStatistics.getMaxHeartRate().getBPM(), stats.maxHr, 0.01f);
|
||||||
assertEquals(sensorStatistics.getAvgCadence(), stats.avgCadence, 0.01f);
|
assertEquals(sensorStatistics.getAvgCadence().getRPM(), stats.avgCadence, 0.01f);
|
||||||
assertEquals(sensorStatistics.getMaxCadence(), stats.maxCadence, 0.01f);
|
assertEquals(sensorStatistics.getMaxCadence().getRPM(), stats.maxCadence, 0.01f);
|
||||||
assertEquals(sensorStatistics.getAvgPower(), stats.avgPower, 0.01f);
|
assertEquals(sensorStatistics.getAvgPower().getW(), stats.avgPower, 0.01f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
+8
-8
@@ -1,4 +1,8 @@
|
|||||||
package de.dennisguse.opentracks.content.provider;
|
package de.dennisguse.opentracks.data;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
@@ -20,13 +24,9 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.MarkerColumns;
|
import de.dennisguse.opentracks.data.tables.MarkerColumns;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
import de.dennisguse.opentracks.data.tables.TrackPointsColumns;
|
||||||
import de.dennisguse.opentracks.content.data.TracksColumns;
|
import de.dennisguse.opentracks.data.tables.TracksColumns;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class CustomSQLiteOpenHelperTest {
|
public class CustomSQLiteOpenHelperTest {
|
||||||
+4
-4
@@ -1,4 +1,6 @@
|
|||||||
package de.dennisguse.opentracks.content.provider;
|
package de.dennisguse.opentracks.data;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
@@ -8,11 +10,9 @@ import org.junit.Test;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.data.models.Track;
|
||||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
public class ShareContentProviderTest {
|
public class ShareContentProviderTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -0,0 +1,205 @@
|
|||||||
|
package de.dennisguse.opentracks.data;
|
||||||
|
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.data.models.Track;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class TrackSelectionTest extends TestCase {
|
||||||
|
@Test
|
||||||
|
public void testFilterBuildSelection_empty() {
|
||||||
|
// given
|
||||||
|
TrackSelection filter = new TrackSelection();
|
||||||
|
|
||||||
|
// when
|
||||||
|
SelectionData selection = filter.buildSelection();
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertNull(selection.getSelection());
|
||||||
|
assertNull(selection.getSelectionArgs());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFilterBuildSelection_onlyOneTrackId() {
|
||||||
|
// given
|
||||||
|
Track.Id trackId = new Track.Id(1);
|
||||||
|
TrackSelection filter = new TrackSelection().addTrackId(trackId);
|
||||||
|
|
||||||
|
// when
|
||||||
|
SelectionData selection = filter.buildSelection();
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertEquals(selection.getSelection(), "_id IN (?)");
|
||||||
|
assertEquals(selection.getSelectionArgs().length, 1);
|
||||||
|
assertEquals(selection.getSelectionArgs()[0], "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFilterBuildSelection_severalTracksId() {
|
||||||
|
// given
|
||||||
|
Track.Id trackId1 = new Track.Id(1);
|
||||||
|
Track.Id trackId2 = new Track.Id(2);
|
||||||
|
Track.Id trackId3 = new Track.Id(3);
|
||||||
|
TrackSelection filter = new TrackSelection()
|
||||||
|
.addTrackId(trackId1)
|
||||||
|
.addTrackId(trackId2)
|
||||||
|
.addTrackId(trackId3);
|
||||||
|
|
||||||
|
// when
|
||||||
|
SelectionData selection = filter.buildSelection();
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertEquals(selection.getSelection(), "_id IN (?,?,?)");
|
||||||
|
assertEquals(selection.getSelectionArgs().length, 3);
|
||||||
|
assertEquals(selection.getSelectionArgs()[0], "1");
|
||||||
|
assertEquals(selection.getSelectionArgs()[1], "2");
|
||||||
|
assertEquals(selection.getSelectionArgs()[2], "3");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFilterBuildSelection_onlyOneCategory() {
|
||||||
|
// given
|
||||||
|
TrackSelection filter = new TrackSelection().addCategory("running");
|
||||||
|
|
||||||
|
// when
|
||||||
|
SelectionData selection = filter.buildSelection();
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertEquals(selection.getSelection(), "category IN (?)");
|
||||||
|
assertEquals(selection.getSelectionArgs().length, 1);
|
||||||
|
assertEquals(selection.getSelectionArgs()[0], "running");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFilterBuildSelection_severalCategories() {
|
||||||
|
// given
|
||||||
|
TrackSelection filter = new TrackSelection()
|
||||||
|
.addCategory("running")
|
||||||
|
.addCategory("road biking")
|
||||||
|
.addCategory("mountain biking")
|
||||||
|
.addCategory("trail walking");
|
||||||
|
|
||||||
|
// when
|
||||||
|
SelectionData selection = filter.buildSelection();
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertEquals(selection.getSelection(), "category IN (?,?,?,?)");
|
||||||
|
assertEquals(selection.getSelectionArgs().length, 4);
|
||||||
|
assertEquals(selection.getSelectionArgs()[0], "running");
|
||||||
|
assertEquals(selection.getSelectionArgs()[1], "road biking");
|
||||||
|
assertEquals(selection.getSelectionArgs()[2], "mountain biking");
|
||||||
|
assertEquals(selection.getSelectionArgs()[3], "trail walking");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFilterBuildSelection_onlyDateRange() {
|
||||||
|
// given
|
||||||
|
Instant instant = Instant.now();
|
||||||
|
long oneDay = 24 * 60 * 60 * 1000;
|
||||||
|
TrackSelection filterWrong1 = new TrackSelection().addDateRange(instant, null);
|
||||||
|
TrackSelection filterWrong2 = new TrackSelection().addDateRange(null, instant);
|
||||||
|
TrackSelection filterOk = new TrackSelection().addDateRange(instant, instant.plusMillis(oneDay));
|
||||||
|
|
||||||
|
// when
|
||||||
|
SelectionData selectionWrong1 = filterWrong1.buildSelection();
|
||||||
|
SelectionData selectionWrong2 = filterWrong2.buildSelection();
|
||||||
|
SelectionData selectionOk = filterOk.buildSelection();
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertNull(selectionWrong1.getSelection());
|
||||||
|
assertNull(selectionWrong1.getSelectionArgs());
|
||||||
|
|
||||||
|
assertNull(selectionWrong2.getSelection());
|
||||||
|
assertNull(selectionWrong2.getSelectionArgs());
|
||||||
|
|
||||||
|
assertEquals(selectionOk.getSelection(), "starttime BETWEEN ? AND ?");
|
||||||
|
assertEquals(selectionOk.getSelectionArgs().length, 2);
|
||||||
|
assertEquals(selectionOk.getSelectionArgs()[0], Long.toString(instant.toEpochMilli()));
|
||||||
|
assertEquals(selectionOk.getSelectionArgs()[1], Long.toString(instant.toEpochMilli() + oneDay));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFilterBuildSelection_tracksId_and_categories() {
|
||||||
|
// given
|
||||||
|
Track.Id trackId1 = new Track.Id(1);
|
||||||
|
Track.Id trackId2 = new Track.Id(2);
|
||||||
|
Track.Id trackId3 = new Track.Id(3);
|
||||||
|
TrackSelection filter = new TrackSelection()
|
||||||
|
.addTrackId(trackId1)
|
||||||
|
.addTrackId(trackId2)
|
||||||
|
.addTrackId(trackId3)
|
||||||
|
.addCategory("running")
|
||||||
|
.addCategory("road biking");
|
||||||
|
|
||||||
|
// when
|
||||||
|
SelectionData selection = filter.buildSelection();
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertEquals(selection.getSelection(), "_id IN (?,?,?) AND category IN (?,?)");
|
||||||
|
assertEquals(selection.getSelectionArgs().length, 5);
|
||||||
|
assertEquals(selection.getSelectionArgs()[0], "1");
|
||||||
|
assertEquals(selection.getSelectionArgs()[1], "2");
|
||||||
|
assertEquals(selection.getSelectionArgs()[2], "3");
|
||||||
|
assertEquals(selection.getSelectionArgs()[3], "running");
|
||||||
|
assertEquals(selection.getSelectionArgs()[4], "road biking");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFilterBuildSelection_tracksId_and_dateRange() {
|
||||||
|
// given
|
||||||
|
Instant instant = Instant.now();
|
||||||
|
long oneDay = 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
|
Track.Id trackId1 = new Track.Id(1);
|
||||||
|
Track.Id trackId2 = new Track.Id(2);
|
||||||
|
Track.Id trackId3 = new Track.Id(3);
|
||||||
|
|
||||||
|
TrackSelection filter = new TrackSelection()
|
||||||
|
.addTrackId(trackId1)
|
||||||
|
.addTrackId(trackId2)
|
||||||
|
.addTrackId(trackId3)
|
||||||
|
.addDateRange(instant, instant.plusMillis(oneDay));
|
||||||
|
|
||||||
|
// when
|
||||||
|
SelectionData selection = filter.buildSelection();
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertEquals(selection.getSelection(), "_id IN (?,?,?) AND starttime BETWEEN ? AND ?");
|
||||||
|
assertEquals(selection.getSelectionArgs().length, 5);
|
||||||
|
assertEquals(selection.getSelectionArgs()[0], "1");
|
||||||
|
assertEquals(selection.getSelectionArgs()[1], "2");
|
||||||
|
assertEquals(selection.getSelectionArgs()[2], "3");
|
||||||
|
assertEquals(selection.getSelectionArgs()[3], Long.toString(instant.toEpochMilli()));
|
||||||
|
assertEquals(selection.getSelectionArgs()[4], Long.toString(instant.toEpochMilli() + oneDay));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFilterBuildSelection_categories_and_dateRange() {
|
||||||
|
// given
|
||||||
|
Instant instant = Instant.now();
|
||||||
|
long oneDay = 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
|
TrackSelection filter = new TrackSelection()
|
||||||
|
.addCategory("running")
|
||||||
|
.addCategory("road biking")
|
||||||
|
.addDateRange(instant, instant.plusMillis(oneDay));
|
||||||
|
|
||||||
|
// when
|
||||||
|
SelectionData selection = filter.buildSelection();
|
||||||
|
|
||||||
|
// Then
|
||||||
|
assertEquals(selection.getSelection(), "category IN (?,?) AND starttime BETWEEN ? AND ?");
|
||||||
|
assertEquals(selection.getSelectionArgs().length, 4);
|
||||||
|
assertEquals(selection.getSelectionArgs()[0], "running");
|
||||||
|
assertEquals(selection.getSelectionArgs()[1], "road biking");
|
||||||
|
assertEquals(selection.getSelectionArgs()[2], Long.toString(instant.toEpochMilli()));
|
||||||
|
assertEquals(selection.getSelectionArgs()[3], Long.toString(instant.toEpochMilli() + oneDay));
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-3
@@ -1,4 +1,6 @@
|
|||||||
package de.dennisguse.opentracks.util;
|
package de.dennisguse.opentracks.data;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
@@ -7,8 +9,6 @@ import org.junit.runner.RunWith;
|
|||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class UUIDUtilsTest {
|
public class UUIDUtilsTest {
|
||||||
|
|
||||||
+7
-4
@@ -1,13 +1,16 @@
|
|||||||
package de.dennisguse.opentracks.content.data;
|
package de.dennisguse.opentracks.data.model;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
import static org.junit.Assert.assertFalse;
|
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
public class TrackPointTest {
|
public class TrackPointTest {
|
||||||
|
|
||||||
+8
-4
@@ -1,5 +1,7 @@
|
|||||||
package de.dennisguse.opentracks.io.file.exporter;
|
package de.dennisguse.opentracks.io.file.exporter;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
@@ -10,12 +12,11 @@ import org.junit.runners.JUnit4;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
@RunWith(JUnit4.class)
|
@RunWith(JUnit4.class)
|
||||||
public class KmlTrackExporterTest {
|
public class KmlTrackExporterTest {
|
||||||
|
|
||||||
@@ -27,6 +28,8 @@ public class KmlTrackExporterTest {
|
|||||||
@Test
|
@Test
|
||||||
public void writeCloseSegment_only_write_sensordata_if_present() {
|
public void writeCloseSegment_only_write_sensordata_if_present() {
|
||||||
String expected = "<when>1970-01-01T00:00:00Z</when>\n" +
|
String expected = "<when>1970-01-01T00:00:00Z</when>\n" +
|
||||||
|
"<gx:coord/>\n" +
|
||||||
|
"<when>1970-01-01T01:00:00+01:00</when>\n" +
|
||||||
"<gx:coord/>\n" +
|
"<gx:coord/>\n" +
|
||||||
"<ExtendedData>\n" +
|
"<ExtendedData>\n" +
|
||||||
"<SchemaData schemaUrl=\"#schema\">\n" +
|
"<SchemaData schemaUrl=\"#schema\">\n" +
|
||||||
@@ -41,7 +44,8 @@ public class KmlTrackExporterTest {
|
|||||||
KMLTrackExporter kmlTrackWriter = (KMLTrackExporter) TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA.createTrackExporter(context);
|
KMLTrackExporter kmlTrackWriter = (KMLTrackExporter) TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA.createTrackExporter(context);
|
||||||
kmlTrackWriter.prepare(outputStream);
|
kmlTrackWriter.prepare(outputStream);
|
||||||
|
|
||||||
kmlTrackWriter.writeTrackPoint(trackPoint);
|
kmlTrackWriter.writeTrackPoint(ZoneOffset.UTC, trackPoint);
|
||||||
|
kmlTrackWriter.writeTrackPoint(ZoneOffset.ofTotalSeconds(3600), trackPoint);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
kmlTrackWriter.writeCloseSegment();
|
kmlTrackWriter.writeCloseSegment();
|
||||||
|
|||||||
+175
-109
@@ -30,34 +30,35 @@ import org.mockito.Mockito;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.time.Clock;
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.ZoneId;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
|
||||||
import de.dennisguse.opentracks.content.data.Marker;
|
|
||||||
import de.dennisguse.opentracks.content.data.Speed;
|
|
||||||
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.data.models.Cadence;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorDataCycling;
|
import de.dennisguse.opentracks.data.models.HeartRate;
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorDataCyclingPower;
|
import de.dennisguse.opentracks.data.models.Marker;
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorDataHeartRate;
|
import de.dennisguse.opentracks.data.models.Power;
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
import de.dennisguse.opentracks.data.models.Speed;
|
||||||
|
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.TrackFileFormat;
|
||||||
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
|
import de.dennisguse.opentracks.io.file.exporter.TrackExporter;
|
||||||
|
import de.dennisguse.opentracks.sensors.AltitudeSumManager;
|
||||||
|
import de.dennisguse.opentracks.sensors.BluetoothRemoteSensorManager;
|
||||||
|
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCycling;
|
||||||
|
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCyclingPower;
|
||||||
|
import de.dennisguse.opentracks.sensors.sensorData.SensorDataHeartRate;
|
||||||
|
import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet;
|
||||||
import de.dennisguse.opentracks.services.TrackRecordingService;
|
import de.dennisguse.opentracks.services.TrackRecordingService;
|
||||||
|
import de.dennisguse.opentracks.services.TrackRecordingServiceTestUtils;
|
||||||
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
|
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
|
||||||
import de.dennisguse.opentracks.services.sensors.AltitudeSumManager;
|
|
||||||
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
|
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -98,55 +99,68 @@ public class ExportImportTest {
|
|||||||
private TrackImporter trackImporter;
|
private TrackImporter trackImporter;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void fileSetup() throws IOException {
|
public void fileSetup() throws IOException, TimeoutException {
|
||||||
|
TrackRecordingServiceTestUtils.resetService(mServiceRule, context);
|
||||||
|
|
||||||
tmpFile = File.createTempFile("test", "test", context.getFilesDir());
|
tmpFile = File.createTempFile("test", "test", context.getFilesDir());
|
||||||
tmpFileUri = Uri.fromFile(tmpFile);
|
tmpFileUri = Uri.fromFile(tmpFile);
|
||||||
|
|
||||||
trackImporter = new TrackImporter(context, contentProviderUtils, Distance.of(10), Distance.of(200), true);
|
trackImporter = new TrackImporter(context, contentProviderUtils, Distance.of(200), true);
|
||||||
|
|
||||||
|
TrackRecordingServiceTestUtils.resetService(mServiceRule, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void FileTearDown() throws TimeoutException {
|
public void tearDown() throws TimeoutException {
|
||||||
tmpFile.deleteOnExit();
|
tmpFile.deleteOnExit();
|
||||||
tmpFileUri = null;
|
tmpFileUri = null;
|
||||||
|
|
||||||
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(new Intent(context, TrackRecordingService.class)))
|
// Ensure that the database is empty after every test
|
||||||
.getService();
|
contentProviderUtils.deleteAllTracks(context);
|
||||||
service.getTrackPointCreator().setClock(Clock.systemUTC());
|
|
||||||
|
TrackRecordingServiceTestUtils.resetService(mServiceRule, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUp(boolean hasSensorDistance) throws TimeoutException {
|
public void setUp() throws TimeoutException {
|
||||||
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(new Intent(context, TrackRecordingService.class)))
|
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(new Intent(context, TrackRecordingService.class)))
|
||||||
.getService();
|
.getService();
|
||||||
|
|
||||||
TrackPointCreator trackPointCreator = service.getTrackPointCreator();
|
TrackPointCreator trackPointCreator = service.getTrackPointCreator();
|
||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:02Z"), ZoneId.of("CET")));
|
trackPointCreator.setClock("2020-02-02T02:02:02Z");
|
||||||
trackId = service.startNewTrack();
|
trackId = service.startNewTrack();
|
||||||
|
|
||||||
Distance sensorDistance = hasSensorDistance ? Distance.of(5) : null;
|
Distance sensorDistance = Distance.of(10); // recording distance interval
|
||||||
|
|
||||||
sendLocation(trackPointCreator, Instant.parse("2020-02-02T02:02:03Z"), 3, 14, 10, 15, 10, 1, 66, 3, 50, sensorDistance);
|
sendLocation(trackPointCreator, "2020-02-02T02:02:03Z", 3, 14, 10, 15, 10, 1);
|
||||||
service.insertMarker("Marker 1", "Marker 1 category", "Marker 1 desc", null);
|
service.insertMarker("Marker 1", "Marker 1 category", "Marker 1 desc", null);
|
||||||
sendLocation(trackPointCreator, Instant.parse("2020-02-02T02:02:04Z"), 3, 14.001, 10, 15, 10, 0, 66, 3, 50, sensorDistance);
|
|
||||||
sendLocation(trackPointCreator, Instant.parse("2020-02-02T02:02:05Z"), 3, 14.002, 10, 15, 10, 0, 66, 3, 50, sensorDistance);
|
// A sensor-only TrackPoint
|
||||||
|
trackPointCreator.setClock("2020-02-02T02:02:04Z");
|
||||||
|
mockAltitudeChange(trackPointCreator, 1);
|
||||||
|
mockBLESensorData(trackPointCreator, 15f, sensorDistance, 66f, 3f, 50f);
|
||||||
|
|
||||||
|
trackPointCreator.setClock("2020-02-02T02:02:05Z");
|
||||||
|
mockBLESensorData(trackPointCreator, 5f, Distance.of(2), 66f, 3f, 50f); // Distance will be added to next TrackPoint
|
||||||
|
|
||||||
|
sendLocation(trackPointCreator, "2020-02-02T02:02:05Z", 3, 14.001, 10, 15, 10, 0);
|
||||||
service.insertMarker("Marker 2", "Marker 2 category", "Marker 2 desc", null);
|
service.insertMarker("Marker 2", "Marker 2 category", "Marker 2 desc", null);
|
||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:06Z"), ZoneId.of("CET")));
|
trackPointCreator.setClock("2020-02-02T02:02:06Z");
|
||||||
trackPointCreator.setRemoteSensorManager(new BluetoothRemoteSensorManager(context));
|
trackPointCreator.setRemoteSensorManager(new BluetoothRemoteSensorManager(context, trackPointCreator));
|
||||||
service.pauseCurrentTrack();
|
service.pauseCurrentTrack();
|
||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:20Z"), ZoneId.of("CET")));
|
trackPointCreator.setClock("2020-02-02T02:02:20Z");
|
||||||
service.resumeCurrentTrack();
|
service.resumeCurrentTrack();
|
||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:21Z"), ZoneId.of("CET")));
|
sendLocation(trackPointCreator, "2020-02-02T02:02:21Z", 3, 14.002, 10, 15, 10, 0);
|
||||||
sendLocation(trackPointCreator, Instant.parse("2020-02-02T02:02:21Z"), 3, 14.003, 10, 15, 10, 0, 66, 3, 50, sensorDistance);
|
|
||||||
|
|
||||||
sendLocation(trackPointCreator, Instant.parse("2020-02-02T02:02:22Z"), 3, 16, 10, 15, 10, 0, 66, 3, 50, sensorDistance);
|
sendLocation(trackPointCreator, "2020-02-02T02:02:22Z", 3, 16, 10, 15, 10, 0);
|
||||||
sendLocation(trackPointCreator, Instant.parse("2020-02-02T02:02:23Z"), 3, 16.001, 10, 15, 10, 0, 66, 3, 50, sensorDistance);
|
|
||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:24Z"), ZoneId.of("CET")));
|
sendLocation(trackPointCreator, "2020-02-02T02:02:23Z", 3, 16.001, 10, 15, 10, 0);
|
||||||
trackPointCreator.setRemoteSensorManager(new BluetoothRemoteSensorManager(context));
|
|
||||||
|
trackPointCreator.setClock("2020-02-02T02:02:24Z");
|
||||||
|
trackPointCreator.setRemoteSensorManager(new BluetoothRemoteSensorManager(context, trackPointCreator));
|
||||||
service.endCurrentTrack();
|
service.endCurrentTrack();
|
||||||
|
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
@@ -158,25 +172,15 @@ public class ExportImportTest {
|
|||||||
track = contentProviderUtils.getTrack(trackId);
|
track = contentProviderUtils.getTrack(trackId);
|
||||||
trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
||||||
markers = contentProviderUtils.getMarkers(trackId);
|
markers = contentProviderUtils.getMarkers(trackId);
|
||||||
assertEquals(10, trackPoints.size());
|
assertEquals(11, trackPoints.size());
|
||||||
assertEquals(2, markers.size());
|
assertEquals(2, markers.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDown() {
|
|
||||||
if (trackId != null) {
|
|
||||||
contentProviderUtils.deleteTrack(context, trackId);
|
|
||||||
}
|
|
||||||
if (importTrackId != null) {
|
|
||||||
contentProviderUtils.deleteTrack(context, importTrackId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO Does not test images
|
//TODO Does not test images
|
||||||
@LargeTest
|
@LargeTest
|
||||||
@Test
|
@Test
|
||||||
public void kmz_with_trackdetail_and_sensordata() throws TimeoutException, IOException {
|
public void kmz_with_trackdetail_and_sensordata() throws TimeoutException, IOException {
|
||||||
setUp(true);
|
setUp();
|
||||||
|
|
||||||
// given
|
// given
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
@@ -204,32 +208,51 @@ public class ExportImportTest {
|
|||||||
// 2. trackpoints
|
// 2. trackpoints
|
||||||
TrackPointAssert a = new TrackPointAssert()
|
TrackPointAssert a = new TrackPointAssert()
|
||||||
.noAccuracy();
|
.noAccuracy();
|
||||||
a.assertEquals(trackPoints, TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId));
|
List<TrackPoint> actual = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
|
||||||
|
a.assertEquals(trackPoints, actual);
|
||||||
|
|
||||||
// 3. trackstatistics
|
// 3. trackstatistics
|
||||||
TrackStatistics importedTrackStatistics = importedTrack.getTrackStatistics();
|
TrackStatistics importedTrackStatistics = importedTrack.getTrackStatistics();
|
||||||
|
|
||||||
// Time
|
// Time
|
||||||
|
assertEquals(track.getZoneOffset(), importedTrack.getZoneOffset());
|
||||||
assertEquals(Instant.parse("2020-02-02T02:02:02Z"), importedTrackStatistics.getStartTime());
|
assertEquals(Instant.parse("2020-02-02T02:02:02Z"), importedTrackStatistics.getStartTime());
|
||||||
assertEquals(Instant.parse("2020-02-02T02:02:24Z"), importedTrackStatistics.getStopTime());
|
assertEquals(Instant.parse("2020-02-02T02:02:24Z"), importedTrackStatistics.getStopTime());
|
||||||
|
|
||||||
assertEquals(track.getTrackStatistics().getTotalTime(), importedTrackStatistics.getTotalTime());
|
TrackStatistics originalTrackStatistics = track.getTrackStatistics();
|
||||||
assertEquals(Duration.ofSeconds(8), importedTrackStatistics.getTotalTime());
|
|
||||||
assertEquals(Duration.ofSeconds(4), importedTrackStatistics.getMovingTime());
|
assertEquals(originalTrackStatistics.getTotalTime(), importedTrackStatistics.getTotalTime());
|
||||||
|
assertEquals(Duration.ofSeconds(7), importedTrackStatistics.getTotalTime());
|
||||||
|
|
||||||
|
assertEquals(originalTrackStatistics.getMovingTime(), importedTrackStatistics.getMovingTime());
|
||||||
|
assertEquals(Duration.ofSeconds(3), importedTrackStatistics.getMovingTime());
|
||||||
|
|
||||||
// Distance
|
// Distance
|
||||||
assertEquals(Distance.of(30), importedTrackStatistics.getTotalDistance());
|
assertEquals(originalTrackStatistics.getTotalDistance(), importedTrackStatistics.getTotalDistance());
|
||||||
|
assertEquals(123.16, importedTrackStatistics.getTotalDistance().toM(), 0.01);
|
||||||
|
|
||||||
// Speed
|
// Speed
|
||||||
assertEquals(Speed.of(15), importedTrackStatistics.getMaxSpeed());
|
assertEquals(originalTrackStatistics.getMaxSpeed(), importedTrackStatistics.getMaxSpeed());
|
||||||
assertEquals(Speed.of(3.75), importedTrackStatistics.getAverageSpeed());
|
assertEquals(41.05, importedTrackStatistics.getMaxSpeed().toMPS(), 0.01);
|
||||||
assertEquals(Speed.of(7.5), importedTrackStatistics.getAverageMovingSpeed());
|
|
||||||
|
assertEquals(originalTrackStatistics.getAverageSpeed(), importedTrackStatistics.getAverageSpeed());
|
||||||
|
assertEquals(17.59, importedTrackStatistics.getAverageSpeed().toMPS(), 0.01);
|
||||||
|
|
||||||
|
assertEquals(originalTrackStatistics.getAverageMovingSpeed(), importedTrackStatistics.getAverageMovingSpeed());
|
||||||
|
assertEquals(41.05, importedTrackStatistics.getMaxSpeed().toMPS(), 0.01);
|
||||||
|
|
||||||
// Altitude
|
// Altitude
|
||||||
|
assertEquals(originalTrackStatistics.getMinAltitude(), importedTrackStatistics.getMinAltitude(), 0.01);
|
||||||
assertEquals(10, importedTrackStatistics.getMinAltitude(), 0.01);
|
assertEquals(10, importedTrackStatistics.getMinAltitude(), 0.01);
|
||||||
|
|
||||||
|
assertEquals(originalTrackStatistics.getMaxAltitude(), importedTrackStatistics.getMaxAltitude(), 0.01);
|
||||||
assertEquals(10, importedTrackStatistics.getMaxAltitude(), 0.01);
|
assertEquals(10, importedTrackStatistics.getMaxAltitude(), 0.01);
|
||||||
assertEquals(1, importedTrackStatistics.getTotalAltitudeGain(), 0.01);
|
|
||||||
assertEquals(1, importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
|
assertEquals(originalTrackStatistics.getTotalAltitudeGain(), importedTrackStatistics.getTotalAltitudeGain(), 0.01);
|
||||||
|
assertEquals(2, importedTrackStatistics.getTotalAltitudeGain(), 0.01);
|
||||||
|
|
||||||
|
assertEquals(originalTrackStatistics.getTotalAltitudeLoss(), importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
|
||||||
|
assertEquals(2, importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
|
||||||
|
|
||||||
// 4. markers
|
// 4. markers
|
||||||
assertMarkers();
|
assertMarkers();
|
||||||
@@ -238,7 +261,7 @@ public class ExportImportTest {
|
|||||||
@LargeTest
|
@LargeTest
|
||||||
@Test(expected = ImportAlreadyExistsException.class)
|
@Test(expected = ImportAlreadyExistsException.class)
|
||||||
public void kml_with_trackdetail_and_sensordata_duplicate_trackUUID() throws TimeoutException, IOException {
|
public void kml_with_trackdetail_and_sensordata_duplicate_trackUUID() throws TimeoutException, IOException {
|
||||||
setUp(false);
|
setUp();
|
||||||
|
|
||||||
// given
|
// given
|
||||||
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
|
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
|
||||||
@@ -264,7 +287,7 @@ public class ExportImportTest {
|
|||||||
@LargeTest
|
@LargeTest
|
||||||
@Test
|
@Test
|
||||||
public void gpx() throws TimeoutException, IOException {
|
public void gpx() throws TimeoutException, IOException {
|
||||||
setUp(true);
|
setUp();
|
||||||
|
|
||||||
// given
|
// given
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
Track track = contentProviderUtils.getTrack(trackId);
|
||||||
@@ -295,39 +318,78 @@ public class ExportImportTest {
|
|||||||
// 2. trackpoints
|
// 2. trackpoints
|
||||||
// The GPX exporter does not support exporting TrackPoints without lat/lng.
|
// The GPX exporter does not support exporting TrackPoints without lat/lng.
|
||||||
// Therefore, the track segmentation is changes.
|
// Therefore, the track segmentation is changes.
|
||||||
List<TrackPoint> trackPointsWithCoordinates = trackPoints.stream().filter(it -> TrackPoint.Type.SEGMENT_START_AUTOMATIC.equals(it.getType()) || TrackPoint.Type.TRACKPOINT.equals(it.getType())).collect(Collectors.toList());
|
|
||||||
trackPointsWithCoordinates.get(0).setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC);
|
|
||||||
trackPointsWithCoordinates.get(3).setType(TrackPoint.Type.SEGMENT_START_AUTOMATIC);
|
|
||||||
|
|
||||||
TrackPointAssert a = new TrackPointAssert()
|
TrackPointAssert a = new TrackPointAssert()
|
||||||
.setDelta(0.05)
|
.setDelta(0.05)
|
||||||
.noAccuracy(); // speed is not fully
|
.noAccuracy(); // speed is not fully
|
||||||
a.assertEquals(trackPointsWithCoordinates, TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId));
|
List<TrackPoint> actual = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
|
||||||
|
a.assertEquals(List.of(
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, Instant.parse("2020-02-02T02:02:03Z"))
|
||||||
|
.setLatitude(3)
|
||||||
|
.setLongitude(14)
|
||||||
|
.setAltitude(10)
|
||||||
|
.setSpeed(Speed.of(15))
|
||||||
|
.setAltitudeLoss(1f)
|
||||||
|
.setAltitudeGain(1f),
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse("2020-02-02T02:02:05Z"))
|
||||||
|
.setLatitude(3)
|
||||||
|
.setLongitude(14.001)
|
||||||
|
.setAltitude(10)
|
||||||
|
.setSpeed(Speed.of(5))
|
||||||
|
.setAltitudeLoss(1f)
|
||||||
|
.setAltitudeGain(1f)
|
||||||
|
.setSensorDistance(Distance.of(12))
|
||||||
|
.setHeartRate(66f)
|
||||||
|
.setPower(50f)
|
||||||
|
.setCadence(3f),
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, Instant.parse("2020-02-02T02:02:21Z"))
|
||||||
|
.setLatitude(3)
|
||||||
|
.setLongitude(14.002)
|
||||||
|
.setAltitude(10)
|
||||||
|
.setAltitudeLoss(0f)
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setSpeed(Speed.of(15)),
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, Instant.parse("2020-02-02T02:02:22Z"))
|
||||||
|
.setLatitude(3)
|
||||||
|
.setLongitude(16)
|
||||||
|
.setAltitude(10)
|
||||||
|
.setAltitudeLoss(0f)
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setSpeed(Speed.of(15)),
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse("2020-02-02T02:02:23Z"))
|
||||||
|
.setLatitude(3)
|
||||||
|
.setLongitude(16.001)
|
||||||
|
.setAltitude(10)
|
||||||
|
.setAltitudeLoss(0f)
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setSpeed(Speed.of(15))
|
||||||
|
), actual);
|
||||||
|
|
||||||
// 3. trackstatistics
|
// 3. trackstatistics
|
||||||
TrackStatistics trackStatistics = track.getTrackStatistics();
|
TrackStatistics trackStatistics = track.getTrackStatistics();
|
||||||
TrackStatistics importedTrackStatistics = importedTrack.getTrackStatistics();
|
TrackStatistics importedTrackStatistics = importedTrack.getTrackStatistics();
|
||||||
|
|
||||||
// Time
|
// Time
|
||||||
|
assertEquals(track.getZoneOffset(), importedTrack.getZoneOffset());
|
||||||
assertEquals(Instant.parse("2020-02-02T02:02:03Z"), importedTrackStatistics.getStartTime());
|
assertEquals(Instant.parse("2020-02-02T02:02:03Z"), importedTrackStatistics.getStartTime());
|
||||||
assertEquals(Instant.parse("2020-02-02T02:02:23Z"), importedTrackStatistics.getStopTime());
|
assertEquals(Instant.parse("2020-02-02T02:02:23Z"), importedTrackStatistics.getStopTime());
|
||||||
|
|
||||||
assertEquals(Duration.ofSeconds(20), importedTrackStatistics.getTotalTime());
|
assertEquals(Duration.ofSeconds(3), importedTrackStatistics.getTotalTime());
|
||||||
assertEquals(Duration.ofSeconds(19), importedTrackStatistics.getMovingTime());
|
assertEquals(Duration.ofSeconds(3), importedTrackStatistics.getMovingTime());
|
||||||
|
|
||||||
// Distance
|
// Distance
|
||||||
assertEquals(Distance.of(30), importedTrackStatistics.getTotalDistance());
|
assertEquals(123.16, importedTrackStatistics.getTotalDistance().toM(), 0.01);
|
||||||
|
|
||||||
// Speed
|
// Speed
|
||||||
assertEquals(Speed.of(15), importedTrackStatistics.getMaxSpeed());
|
assertEquals(41.05, importedTrackStatistics.getMaxSpeed().toMPS(), 0.01);
|
||||||
assertEquals(Speed.of(1.5), importedTrackStatistics.getAverageSpeed());
|
assertEquals(41.05, importedTrackStatistics.getAverageSpeed().toMPS(), 0.01);
|
||||||
assertEquals(Speed.of(1.5789473684210527), importedTrackStatistics.getAverageMovingSpeed());
|
assertEquals(41.05, importedTrackStatistics.getAverageMovingSpeed().toMPS(), 0.01);
|
||||||
|
|
||||||
// Altitude
|
// Altitude
|
||||||
assertEquals(10, importedTrackStatistics.getMinAltitude(), 0.01);
|
assertEquals(10, importedTrackStatistics.getMinAltitude(), 0.01);
|
||||||
assertEquals(10, importedTrackStatistics.getMaxAltitude(), 0.01);
|
assertEquals(10, importedTrackStatistics.getMaxAltitude(), 0.01);
|
||||||
assertEquals(1, importedTrackStatistics.getTotalAltitudeGain(), 0.01);
|
assertEquals(2, importedTrackStatistics.getTotalAltitudeGain(), 0.01);
|
||||||
assertEquals(1, importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
|
assertEquals(2, importedTrackStatistics.getTotalAltitudeLoss(), 0.01);
|
||||||
|
|
||||||
// 4. markers
|
// 4. markers
|
||||||
assertMarkers();
|
assertMarkers();
|
||||||
@@ -336,7 +398,7 @@ public class ExportImportTest {
|
|||||||
@LargeTest
|
@LargeTest
|
||||||
@Test(expected = ImportAlreadyExistsException.class)
|
@Test(expected = ImportAlreadyExistsException.class)
|
||||||
public void gpx_duplicate_trackUUID() throws TimeoutException, IOException {
|
public void gpx_duplicate_trackUUID() throws TimeoutException, IOException {
|
||||||
setUp(false);
|
setUp();
|
||||||
|
|
||||||
// given
|
// given
|
||||||
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
|
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
|
||||||
@@ -380,7 +442,43 @@ public class ExportImportTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendLocation(TrackPointCreator trackPointCreator, Instant time, double latitude, double longitude, float accuracy, float speed, float altitude, float altitudeGain, float heartRate, float cyclingCadence, float power, Distance distance) {
|
private void mockBLESensorData(TrackPointCreator trackPointCreator, Float speed, Distance distance, float heartRate, float cadence, Float power) {
|
||||||
|
trackPointCreator.setRemoteSensorManager(new BluetoothRemoteSensorManager(context, trackPointCreator) {
|
||||||
|
@Override
|
||||||
|
public SensorDataSet fill(@NonNull TrackPoint trackPoint) {
|
||||||
|
SensorDataSet sensorDataSet = new SensorDataSet();
|
||||||
|
sensorDataSet.set(new SensorDataCyclingPower("power", "power", Power.of(power)));
|
||||||
|
sensorDataSet.set(new SensorDataHeartRate("heartRate", "heartRate", HeartRate.of(heartRate)));
|
||||||
|
|
||||||
|
SensorDataCycling.CyclingCadence cyclingCadence = Mockito.mock(SensorDataCycling.CyclingCadence.class);
|
||||||
|
Mockito.when(cyclingCadence.hasValue()).thenReturn(true);
|
||||||
|
Mockito.when(cyclingCadence.getValue()).thenReturn(Cadence.of(cadence));
|
||||||
|
sensorDataSet.set(cyclingCadence);
|
||||||
|
|
||||||
|
if (distance != null && speed != null) {
|
||||||
|
SensorDataCycling.DistanceSpeed.Data distanceSpeedData = Mockito.mock(SensorDataCycling.DistanceSpeed.Data.class);
|
||||||
|
Mockito.when(distanceSpeedData.getDistanceOverall()).thenReturn(distance);
|
||||||
|
Mockito.when(distanceSpeedData.getSpeed()).thenReturn(Speed.of(speed));
|
||||||
|
SensorDataCycling.DistanceSpeed distanceSpeed = Mockito.mock(SensorDataCycling.DistanceSpeed.class);
|
||||||
|
Mockito.when(distanceSpeed.hasValue()).thenReturn(true);
|
||||||
|
Mockito.when(distanceSpeed.getValue()).thenReturn(distanceSpeedData);
|
||||||
|
sensorDataSet.set(distanceSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
sensorDataSet.fillTrackPoint(trackPoint);
|
||||||
|
return sensorDataSet;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
trackPointCreator.onChange(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mockAltitudeChange(TrackPointCreator trackPointCreator, float altitudeGain) {
|
||||||
|
AltitudeSumManager altitudeSumManager = trackPointCreator.getAltitudeSumManager();
|
||||||
|
altitudeSumManager.setAltitudeGain_m(altitudeGain);
|
||||||
|
altitudeSumManager.setAltitudeLoss_m(altitudeGain);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendLocation(TrackPointCreator trackPointCreator, String time, double latitude, double longitude, float accuracy, float speed, float altitude, float altitudeGain) {
|
||||||
Location location = new Location("mock");
|
Location location = new Location("mock");
|
||||||
location.setLatitude(latitude);
|
location.setLatitude(latitude);
|
||||||
location.setLongitude(longitude);
|
location.setLongitude(longitude);
|
||||||
@@ -388,41 +486,9 @@ public class ExportImportTest {
|
|||||||
location.setSpeed(speed);
|
location.setSpeed(speed);
|
||||||
location.setAltitude(altitude);
|
location.setAltitude(altitude);
|
||||||
|
|
||||||
trackPointCreator.setAltitudeSumManager(new AltitudeSumManager() {
|
mockAltitudeChange(trackPointCreator, altitudeGain);
|
||||||
@Override
|
|
||||||
public void fill(@NonNull TrackPoint trackPoint) {
|
|
||||||
trackPoint.setAltitudeGain(altitudeGain);
|
|
||||||
trackPoint.setAltitudeLoss(altitudeGain);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
trackPointCreator.setRemoteSensorManager(new BluetoothRemoteSensorManager(context) {
|
trackPointCreator.setClock(time);
|
||||||
@Override
|
trackPointCreator.getGpsHandler().onLocationChanged(location);
|
||||||
public SensorDataSet fill(@NonNull TrackPoint trackPoint) {
|
|
||||||
SensorDataSet sensorDataSet = new SensorDataSet();
|
|
||||||
sensorDataSet.set(new SensorDataCyclingPower("power", "power", power));
|
|
||||||
sensorDataSet.set(new SensorDataHeartRate("heartRate", "heartRate", heartRate));
|
|
||||||
|
|
||||||
SensorDataCycling.Cadence cadence = Mockito.mock(SensorDataCycling.Cadence.class);
|
|
||||||
Mockito.when(cadence.hasValue()).thenReturn(true);
|
|
||||||
Mockito.when(cadence.getValue()).thenReturn(cyclingCadence);
|
|
||||||
sensorDataSet.set(cadence);
|
|
||||||
|
|
||||||
SensorDataCycling.DistanceSpeed.Data distanceSpeedData = Mockito.mock(SensorDataCycling.DistanceSpeed.Data.class);
|
|
||||||
Mockito.when(distanceSpeedData.getDistanceOverall()).thenReturn(distance);
|
|
||||||
Mockito.when(distanceSpeedData.getSpeed()).thenReturn(Speed.of(speed));
|
|
||||||
SensorDataCycling.DistanceSpeed distanceSpeed = Mockito.mock(SensorDataCycling.DistanceSpeed.class);
|
|
||||||
Mockito.when(distanceSpeed.hasValue()).thenReturn(true);
|
|
||||||
Mockito.when(distanceSpeed.getValue()).thenReturn(distanceSpeedData);
|
|
||||||
|
|
||||||
sensorDataSet.set(distanceSpeed);
|
|
||||||
|
|
||||||
sensorDataSet.fillTrackPoint(trackPoint);
|
|
||||||
return sensorDataSet;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(time, ZoneId.of("CET")));
|
|
||||||
trackPointCreator.getLocationHandler().onLocationChanged(location);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+112
-10
@@ -1,5 +1,8 @@
|
|||||||
package de.dennisguse.opentracks.io.file.importer;
|
package de.dennisguse.opentracks.io.file.importer;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
@@ -14,18 +17,17 @@ import org.junit.runners.JUnit4;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
|
||||||
import de.dennisguse.opentracks.content.data.Speed;
|
|
||||||
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.data.models.Speed;
|
||||||
|
import de.dennisguse.opentracks.data.models.Track;
|
||||||
import static org.junit.Assert.assertEquals;
|
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that legacy KML/GPX formats can still be imported.
|
* Test that legacy KML/GPX formats can still be imported.
|
||||||
@@ -42,7 +44,7 @@ public class GPXImportTest {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
trackImporter = new TrackImporter(context, contentProviderUtils, Distance.of(10), Distance.of(200), true);
|
trackImporter = new TrackImporter(context, contentProviderUtils, Distance.of(200), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@@ -67,7 +69,7 @@ public class GPXImportTest {
|
|||||||
importTrackId = importer.importFile(inputStream).get(0);
|
importTrackId = importer.importFile(inputStream).get(0);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
// 1. track
|
// 2. track
|
||||||
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
|
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
|
||||||
assertNotNull(importedTrack);
|
assertNotNull(importedTrack);
|
||||||
assertEquals("the category", importedTrack.getCategory());
|
assertEquals("the category", importedTrack.getCategory());
|
||||||
@@ -75,6 +77,8 @@ public class GPXImportTest {
|
|||||||
assertEquals("2021-01-07 22:51", importedTrack.getName());
|
assertEquals("2021-01-07 22:51", importedTrack.getName());
|
||||||
assertEquals("UNKNOWN", importedTrack.getIcon());
|
assertEquals("UNKNOWN", importedTrack.getIcon());
|
||||||
|
|
||||||
|
//TODO Check trackstatistics
|
||||||
|
|
||||||
// 3. trackpoints
|
// 3. trackpoints
|
||||||
List<TrackPoint> importedTrackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
|
List<TrackPoint> importedTrackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
|
||||||
assertEquals(6, importedTrackPoints.size());
|
assertEquals(6, importedTrackPoints.size());
|
||||||
@@ -106,4 +110,102 @@ public class GPXImportTest {
|
|||||||
.setAltitude(10)
|
.setAltitude(10)
|
||||||
), importedTrackPoints);
|
), importedTrackPoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@LargeTest
|
||||||
|
@Test
|
||||||
|
public void gpx_without_speed() throws IOException {
|
||||||
|
// given
|
||||||
|
XMLImporter importer = new XMLImporter(new GpxTrackImporter(context, trackImporter));
|
||||||
|
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.debug.test.R.raw.gpx11_without_speed);
|
||||||
|
|
||||||
|
// when
|
||||||
|
// 1. import
|
||||||
|
importTrackId = importer.importFile(inputStream).get(0);
|
||||||
|
|
||||||
|
// then
|
||||||
|
// 2. track
|
||||||
|
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
|
||||||
|
assertNotNull(importedTrack);
|
||||||
|
assertEquals("", importedTrack.getCategory());
|
||||||
|
assertEquals("", importedTrack.getDescription());
|
||||||
|
assertEquals("20210907_213924.gpx", importedTrack.getName());
|
||||||
|
assertEquals("", importedTrack.getIcon());
|
||||||
|
|
||||||
|
// 3. trackstatistics
|
||||||
|
TrackStatistics trackStatistics = importedTrack.getTrackStatistics();
|
||||||
|
assertEquals(1.44, trackStatistics.getMaxSpeed().toMPS(), 0.01);
|
||||||
|
assertEquals(Duration.ofSeconds(53), trackStatistics.getMovingTime());
|
||||||
|
|
||||||
|
// 4. trackpoints
|
||||||
|
List<TrackPoint> importedTrackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
|
||||||
|
assertEquals(3, importedTrackPoints.size());
|
||||||
|
|
||||||
|
TrackPointAssert a = new TrackPointAssert();
|
||||||
|
a.assertEquals(List.of(
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, Instant.parse("2021-09-07T22:10:19Z"))
|
||||||
|
.setLatitude(30.14185982)
|
||||||
|
.setLongitude(-40.3863038)
|
||||||
|
.setAltitude(-5),
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse("2021-09-07T22:11:07Z"))
|
||||||
|
.setLatitude(30.14184657)
|
||||||
|
.setLongitude(-40.38670089)
|
||||||
|
.setAltitude(-5)
|
||||||
|
.setSpeed(Speed.of(0.7976524233818054)),
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse("2021-09-07T22:12:00Z"))
|
||||||
|
.setLatitude(30.14185982)
|
||||||
|
.setLongitude(-40.3863038)
|
||||||
|
.setAltitude(-5)
|
||||||
|
.setSpeed(Speed.of(0.7224021553993225))
|
||||||
|
), importedTrackPoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
@LargeTest
|
||||||
|
@Test
|
||||||
|
public void gpx_speed_no_namespace() throws IOException {
|
||||||
|
// given
|
||||||
|
XMLImporter importer = new XMLImporter(new GpxTrackImporter(context, trackImporter));
|
||||||
|
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.debug.test.R.raw.gpx11_with_speed_no_namespace);
|
||||||
|
|
||||||
|
// when
|
||||||
|
// 1. import
|
||||||
|
importTrackId = importer.importFile(inputStream).get(0);
|
||||||
|
|
||||||
|
// then
|
||||||
|
// 2. track
|
||||||
|
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
|
||||||
|
assertNotNull(importedTrack);
|
||||||
|
assertEquals("", importedTrack.getCategory());
|
||||||
|
assertEquals("", importedTrack.getDescription());
|
||||||
|
assertEquals("20210907_213924.gpx", importedTrack.getName());
|
||||||
|
assertEquals("", importedTrack.getIcon());
|
||||||
|
|
||||||
|
// 3. trackstatistics
|
||||||
|
TrackStatistics trackStatistics = importedTrack.getTrackStatistics();
|
||||||
|
assertEquals(4, trackStatistics.getMaxSpeed().toMPS(), 0.01);
|
||||||
|
assertEquals(Duration.ofSeconds(101), trackStatistics.getMovingTime());
|
||||||
|
|
||||||
|
// 4. trackpoints
|
||||||
|
List<TrackPoint> importedTrackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, importTrackId);
|
||||||
|
assertEquals(3, importedTrackPoints.size());
|
||||||
|
|
||||||
|
TrackPointAssert a = new TrackPointAssert();
|
||||||
|
a.assertEquals(List.of(
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, Instant.parse("2021-09-07T22:10:19Z"))
|
||||||
|
.setLatitude(30.14185982)
|
||||||
|
.setLongitude(-40.3863038)
|
||||||
|
.setAltitude(-5)
|
||||||
|
.setSpeed(Speed.of(5)),
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse("2021-09-07T22:11:07Z"))
|
||||||
|
.setLatitude(30.14184657)
|
||||||
|
.setLongitude(-40.38670089)
|
||||||
|
.setAltitude(-5)
|
||||||
|
.setSpeed(Speed.of(0.7976524233818054))
|
||||||
|
.setSpeed(Speed.of(4)),
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse("2021-09-07T22:12:00Z"))
|
||||||
|
.setLatitude(30.14185982)
|
||||||
|
.setLongitude(-40.3863038)
|
||||||
|
.setAltitude(-5)
|
||||||
|
.setSpeed(Speed.of(3))
|
||||||
|
), importedTrackPoints);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
package de.dennisguse.opentracks.io.file.importer;
|
package de.dennisguse.opentracks.io.file.importer;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
@@ -17,15 +20,12 @@ import java.io.InputStream;
|
|||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
|
||||||
import de.dennisguse.opentracks.content.data.Speed;
|
|
||||||
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.data.models.Speed;
|
||||||
|
import de.dennisguse.opentracks.data.models.Track;
|
||||||
import static org.junit.Assert.assertEquals;
|
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that legacy KML/GPX formats can still be imported.
|
* Test that legacy KML/GPX formats can still be imported.
|
||||||
@@ -42,7 +42,7 @@ public class KMLImportTest {
|
|||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
trackImporter = new TrackImporter(context, contentProviderUtils, Distance.of(10), Distance.of(200), true);
|
trackImporter = new TrackImporter(context, contentProviderUtils, Distance.of(200), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|||||||
+8
-17
@@ -4,11 +4,10 @@ import org.junit.Assert;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||||
|
|
||||||
public class TrackPointAssert {
|
public class TrackPointAssert {
|
||||||
|
|
||||||
private boolean assertTime = true;
|
|
||||||
private boolean assertAccuracy = true;
|
private boolean assertAccuracy = true;
|
||||||
|
|
||||||
private double delta = 0.001;
|
private double delta = 0.001;
|
||||||
@@ -17,10 +16,7 @@ public class TrackPointAssert {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void assertEquals(TrackPoint expected, TrackPoint actual) {
|
public void assertEquals(TrackPoint expected, TrackPoint actual) {
|
||||||
Assert.assertNotNull(actual.getTime());
|
|
||||||
if (assertTime) {
|
|
||||||
Assert.assertEquals(expected.getTime(), actual.getTime());
|
Assert.assertEquals(expected.getTime(), actual.getTime());
|
||||||
}
|
|
||||||
|
|
||||||
Assert.assertEquals(expected.getType(), actual.getType());
|
Assert.assertEquals(expected.getType(), actual.getType());
|
||||||
|
|
||||||
@@ -65,17 +61,17 @@ public class TrackPointAssert {
|
|||||||
|
|
||||||
Assert.assertEquals(expected.hasHeartRate(), actual.hasHeartRate());
|
Assert.assertEquals(expected.hasHeartRate(), actual.hasHeartRate());
|
||||||
if (expected.hasHeartRate()) {
|
if (expected.hasHeartRate()) {
|
||||||
Assert.assertEquals(expected.getHeartRate_bpm(), actual.getHeartRate_bpm(), delta);
|
Assert.assertEquals(expected.getHeartRate(), actual.getHeartRate());
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.assertEquals(expected.hasPower(), actual.hasPower());
|
Assert.assertEquals(expected.hasPower(), actual.hasPower());
|
||||||
if (expected.hasPower()) {
|
if (expected.hasPower()) {
|
||||||
Assert.assertEquals(expected.getPower(), actual.getPower(), delta);
|
Assert.assertEquals(expected.getPower(), actual.getPower());
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.assertEquals(expected.hasCyclingCadence(), actual.hasCyclingCadence());
|
Assert.assertEquals(expected.hasCadence(), actual.hasCadence());
|
||||||
if (expected.hasCyclingCadence()) {
|
if (expected.hasCadence()) {
|
||||||
Assert.assertEquals(expected.getCyclingCadence_rpm(), actual.getCyclingCadence_rpm(), delta);
|
Assert.assertEquals(expected.getCadence(), actual.getCadence());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,14 +79,14 @@ public class TrackPointAssert {
|
|||||||
try {
|
try {
|
||||||
Assert.assertEquals(expected.size(), actual.size());
|
Assert.assertEquals(expected.size(), actual.size());
|
||||||
} catch (AssertionError e) {
|
} catch (AssertionError e) {
|
||||||
throw new AssertionError("Expected: " + expected + " actual: " + actual);
|
throw new AssertionError("Size difference; expected: " + expected.size() + "; actual: " + actual.size() + "\nExpected: " + expected + "\n actual: " + actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < expected.size(); i++) {
|
for (int i = 0; i < expected.size(); i++) {
|
||||||
try {
|
try {
|
||||||
assertEquals(expected.get(i), actual.get(i));
|
assertEquals(expected.get(i), actual.get(i));
|
||||||
} catch (AssertionError e) {
|
} catch (AssertionError e) {
|
||||||
throw new AssertionError("Expected: " + expected.get(i) + " actual: " + actual.get(i), e);
|
throw new AssertionError("Expected: " + i + " to be " + expected.get(i) + "\n actual: " + actual.get(i), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Assert.assertEquals(expected.size(), actual.size());
|
Assert.assertEquals(expected.size(), actual.size());
|
||||||
@@ -100,11 +96,6 @@ public class TrackPointAssert {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public TrackPointAssert ignoreTime() {
|
|
||||||
this.assertTime = false;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TrackPointAssert noAccuracy() {
|
public TrackPointAssert noAccuracy() {
|
||||||
this.assertAccuracy = false;
|
this.assertAccuracy = false;
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package de.dennisguse.opentracks.services.sensors;
|
package de.dennisguse.opentracks.sensors;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
+17
-16
@@ -1,4 +1,4 @@
|
|||||||
package de.dennisguse.opentracks.util;
|
package de.dennisguse.opentracks.sensors;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
@@ -7,10 +7,11 @@ import android.bluetooth.BluetoothGattCharacteristic;
|
|||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
import de.dennisguse.opentracks.data.models.Cadence;
|
||||||
import de.dennisguse.opentracks.content.data.Speed;
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorDataCycling;
|
import de.dennisguse.opentracks.data.models.Speed;
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorDataRunning;
|
import de.dennisguse.opentracks.sensors.sensorData.SensorDataCycling;
|
||||||
|
import de.dennisguse.opentracks.sensors.sensorData.SensorDataRunning;
|
||||||
|
|
||||||
public class BluetoothUtilsTest {
|
public class BluetoothUtilsTest {
|
||||||
|
|
||||||
@@ -43,40 +44,40 @@ public class BluetoothUtilsTest {
|
|||||||
@Test
|
@Test
|
||||||
public void parseCyclingSpeedCadence_crankOnly() {
|
public void parseCyclingSpeedCadence_crankOnly() {
|
||||||
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.CYCLING_SPEED_CADENCE_SERVICE_UUID, 0, 0);
|
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.CYCLING_SPEED_CADENCE_SERVICE_UUID, 0, 0);
|
||||||
characteristic.setValue(new byte[]{0x01, (byte) 0xC8, 0x00, 0x00, 0x00, 0x06, (byte) 0x99});
|
characteristic.setValue(new byte[]{0x02, (byte) 0xC8, 0x00, 0x00, 0x00, 0x06, (byte) 0x99});
|
||||||
|
|
||||||
// when
|
// when
|
||||||
SensorDataCycling.CadenceAndSpeed sensor = BluetoothUtils.parseCyclingCrankAndWheel("address", "sensorName", characteristic);
|
SensorDataCycling.CadenceAndSpeed sensor = BluetoothUtils.parseCyclingCrankAndWheel("address", "sensorName", characteristic);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(200, sensor.getCadence().getCrankRevolutionsCount());
|
|
||||||
assertNull(sensor.getDistanceSpeed());
|
assertNull(sensor.getDistanceSpeed());
|
||||||
|
assertEquals(200, sensor.getCadence().getCrankRevolutionsCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void parseCyclingSpeedCadence_wheelOnly() {
|
public void parseCyclingSpeedCadence_wheelOnly() {
|
||||||
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.CYCLING_SPEED_CADENCE_SERVICE_UUID, 0, 0);
|
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.CYCLING_SPEED_CADENCE_SERVICE_UUID, 0, 0);
|
||||||
characteristic.setValue(new byte[]{0x02, (byte) 0xE1, 0x00, 0x45, (byte) 0x99});
|
characteristic.setValue(new byte[]{0x01, (byte) 0xFF, (byte) 0xFF, 0, 1, 0x45, (byte) 0x99});
|
||||||
|
|
||||||
// when
|
// when
|
||||||
SensorDataCycling.CadenceAndSpeed sensor = BluetoothUtils.parseCyclingCrankAndWheel("address", "sensorName", characteristic);
|
SensorDataCycling.CadenceAndSpeed sensor = BluetoothUtils.parseCyclingCrankAndWheel("address", "sensorName", characteristic);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
|
assertEquals(65535 + 16777216, sensor.getDistanceSpeed().getWheelRevolutionsCount());
|
||||||
assertNull(sensor.getCadence());
|
assertNull(sensor.getCadence());
|
||||||
assertEquals(225, sensor.getDistanceSpeed().getWheelRevolutionsCount());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void parseCyclingSpeedCadence_crankWheel() {
|
public void parseCyclingSpeedCadence_crankWheel() {
|
||||||
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.CYCLING_SPEED_CADENCE_SERVICE_UUID, 0, 0);
|
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.CYCLING_SPEED_CADENCE_SERVICE_UUID, 0, 0);
|
||||||
characteristic.setValue(new byte[]{0x03, (byte) 0xC8, 0x00, 0x00, 0x00, 0x06, (byte) 0x99, (byte) 0xE1, 0x00, 0x45, (byte) 0x99});
|
characteristic.setValue(new byte[]{0x03, (byte) 0xC8, 0x00, 0x00, 0x01, 0x06, (byte) 0x99, (byte) 0xE1, 0x00, 0x45, (byte) 0x99});
|
||||||
|
|
||||||
// when
|
// when
|
||||||
SensorDataCycling.CadenceAndSpeed sensor = BluetoothUtils.parseCyclingCrankAndWheel("address", "sensorName", characteristic);
|
SensorDataCycling.CadenceAndSpeed sensor = BluetoothUtils.parseCyclingCrankAndWheel("address", "sensorName", characteristic);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(200, sensor.getCadence().getCrankRevolutionsCount());
|
assertEquals(200 + 16777216, sensor.getDistanceSpeed().getWheelRevolutionsCount());
|
||||||
assertEquals(225, sensor.getDistanceSpeed().getWheelRevolutionsCount());
|
assertEquals(225, sensor.getCadence().getCrankRevolutionsCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -93,15 +94,15 @@ public class BluetoothUtilsTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void parseRunningSpeedAndCadence_with_distance() {
|
public void parseRunningSpeedAndCadence_with_distance() {
|
||||||
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.CYCLING_SPEED_CADENCE_MEASUREMENT_CHAR_UUID, 0, 0);
|
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(BluetoothUtils.RUNNING_RUNNING_SPEED_CADENCE_CHAR_UUID, 0, 0);
|
||||||
characteristic.setValue(new byte[]{2, 0, 5, 80, 12, 1});
|
characteristic.setValue(new byte[]{2, 0, 5, 80, (byte) 0xFF, (byte) 0xFF, 0, 1});
|
||||||
|
|
||||||
// when
|
// when
|
||||||
SensorDataRunning sensor = BluetoothUtils.parseRunningSpeedAndCadence("address", "sensorName", characteristic);
|
SensorDataRunning sensor = BluetoothUtils.parseRunningSpeedAndCadence("address", "sensorName", characteristic);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(Speed.of(5), sensor.getSpeed());
|
assertEquals(Speed.of(5), sensor.getSpeed());
|
||||||
assertEquals(80, sensor.getCadence(), 0.01);
|
assertEquals(Cadence.of(80), sensor.getCadence());
|
||||||
assertEquals(Distance.of(26.8), sensor.getTotalDistance());
|
assertEquals(Distance.of(6553.5 + 1677721.6), sensor.getTotalDistance());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+3
-3
@@ -1,10 +1,10 @@
|
|||||||
package de.dennisguse.opentracks.util;
|
package de.dennisguse.opentracks.sensors;
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
public class PressureSensorUtilsTest {
|
public class PressureSensorUtilsTest {
|
||||||
|
|
||||||
// real data at 500Hz stationary
|
// real data at 500Hz stationary
|
||||||
+3
-3
@@ -1,9 +1,9 @@
|
|||||||
package de.dennisguse.opentracks.util;
|
package de.dennisguse.opentracks.sensors;
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
public class UintUtilsTest {
|
public class UintUtilsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
+30
-29
@@ -1,4 +1,9 @@
|
|||||||
package de.dennisguse.opentracks.content.sensor;
|
package de.dennisguse.opentracks.sensors.sensorData;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
@@ -6,13 +11,9 @@ import org.junit.Ignore;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
import de.dennisguse.opentracks.data.models.Cadence;
|
||||||
import de.dennisguse.opentracks.util.UintUtils;
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
|
import de.dennisguse.opentracks.sensors.UintUtils;
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNotEquals;
|
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class SensorDataCyclingTest {
|
public class SensorDataCyclingTest {
|
||||||
@@ -20,48 +21,48 @@ public class SensorDataCyclingTest {
|
|||||||
@Test
|
@Test
|
||||||
public void compute_cadence_1() {
|
public void compute_cadence_1() {
|
||||||
// given
|
// given
|
||||||
SensorDataCycling.Cadence previous = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 1, 1024); // 1s
|
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 1, 1024); // 1s
|
||||||
SensorDataCycling.Cadence current = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 2, 2048); // 2s
|
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 2, 2048); // 2s
|
||||||
|
|
||||||
// when
|
// when
|
||||||
current.compute(previous);
|
current.compute(previous);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(60, current.getValue(), 0.01);
|
assertEquals(60, current.getValue().getRPM(), 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void compute_cadence_2() {
|
public void compute_cadence_2() {
|
||||||
// given
|
// given
|
||||||
SensorDataCycling.Cadence previous = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 1, 6184);
|
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 1, 6184);
|
||||||
SensorDataCycling.Cadence current = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 2, 8016);
|
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 2, 8016);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
current.compute(previous);
|
current.compute(previous);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(33.53, current.getValue(), 0.01);
|
assertEquals(33.53, current.getValue().getRPM(), 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void compute_cadence_sameCount() {
|
public void compute_cadence_sameCount() {
|
||||||
// given
|
// given
|
||||||
SensorDataCycling.Cadence previous = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 1, 1024);
|
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 1, 1024);
|
||||||
SensorDataCycling.Cadence current = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 1, 2048);
|
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 1, 2048);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
current.compute(previous);
|
current.compute(previous);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(0, current.getValue(), 0.01);
|
assertEquals(Cadence.of(0), current.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void compute_cadence_sameTime() {
|
public void compute_cadence_sameTime() {
|
||||||
// given
|
// given
|
||||||
SensorDataCycling.Cadence previous = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 1, 1024);
|
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 1, 1024);
|
||||||
SensorDataCycling.Cadence current = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 2, 1024);
|
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 2, 1024);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
current.compute(previous);
|
current.compute(previous);
|
||||||
@@ -73,14 +74,14 @@ public class SensorDataCyclingTest {
|
|||||||
@Test
|
@Test
|
||||||
public void compute_cadence_rollOverTime() {
|
public void compute_cadence_rollOverTime() {
|
||||||
// given
|
// given
|
||||||
SensorDataCycling.Cadence previous = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 1, UintUtils.UINT16_MAX - 1024);
|
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 1, UintUtils.UINT16_MAX - 1024);
|
||||||
SensorDataCycling.Cadence current = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 2, 0);
|
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 2, 0);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
current.compute(previous);
|
current.compute(previous);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(60, current.getValue(), 0.01);
|
assertEquals(60, current.getValue().getRPM(), 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("Disabled from #953")
|
@Ignore("Disabled from #953")
|
||||||
@@ -88,21 +89,21 @@ public class SensorDataCyclingTest {
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
public void compute_cadence_rollOverCount() {
|
public void compute_cadence_rollOverCount() {
|
||||||
// given
|
// given
|
||||||
SensorDataCycling.Cadence previous = new SensorDataCycling.Cadence("sensorAddress", "sensorName", UintUtils.UINT32_MAX - 1, 1024);
|
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", UintUtils.UINT32_MAX - 1, 1024);
|
||||||
SensorDataCycling.Cadence current = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 0, 2048);
|
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 0, 2048);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
current.compute(previous);
|
current.compute(previous);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(60, current.getValue(), 0.01);
|
assertEquals(60, current.getValue().getRPM(), 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void compute_cadence_overflow() {
|
public void compute_cadence_overflow() {
|
||||||
// given
|
// given
|
||||||
SensorDataCycling.Cadence previous = new SensorDataCycling.Cadence("sensorAddress", "sensorName", UintUtils.UINT32_MAX - 1, 1024);
|
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", UintUtils.UINT32_MAX - 1, 1024);
|
||||||
SensorDataCycling.Cadence current = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 0, 2048);
|
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 0, 2048);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
current.compute(previous);
|
current.compute(previous);
|
||||||
@@ -171,8 +172,8 @@ public class SensorDataCyclingTest {
|
|||||||
@Test
|
@Test
|
||||||
public void equals_cadence_with_no_data() {
|
public void equals_cadence_with_no_data() {
|
||||||
// given
|
// given
|
||||||
SensorDataCycling.Cadence previous = new SensorDataCycling.Cadence("sensorAddress");
|
SensorDataCycling.CyclingCadence previous = new SensorDataCycling.CyclingCadence("sensorAddress");
|
||||||
SensorDataCycling.Cadence current = new SensorDataCycling.Cadence("sensorAddress", "sensorName", 0, 2048);
|
SensorDataCycling.CyclingCadence current = new SensorDataCycling.CyclingCadence("sensorAddress", "sensorName", 0, 2048);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
previous.toString();
|
previous.toString();
|
||||||
+8
-8
@@ -1,5 +1,10 @@
|
|||||||
package de.dennisguse.opentracks.services;
|
package de.dennisguse.opentracks.services;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import android.app.NotificationManager;
|
import android.app.NotificationManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
@@ -11,16 +16,11 @@ import org.junit.runner.RunWith;
|
|||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
import de.dennisguse.opentracks.content.data.Speed;
|
import de.dennisguse.opentracks.data.models.Speed;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
|
||||||
import static org.mockito.Mockito.times;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class TrackRecordingServiceNotificationManagerTest {
|
public class TrackRecordingServiceNotificationManagerTest {
|
||||||
|
|
||||||
|
|||||||
-472
@@ -1,472 +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.services;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNotEquals;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
import android.content.ContentProvider;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.os.IBinder;
|
|
||||||
import android.os.Looper;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|
||||||
import androidx.test.filters.MediumTest;
|
|
||||||
import androidx.test.filters.SmallTest;
|
|
||||||
import androidx.test.rule.GrantPermissionRule;
|
|
||||||
import androidx.test.rule.ServiceTestRule;
|
|
||||||
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.AfterClass;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.BeforeClass;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import java.time.Clock;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.time.ZoneId;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
|
||||||
import de.dennisguse.opentracks.content.data.Marker;
|
|
||||||
import de.dennisguse.opentracks.content.data.Speed;
|
|
||||||
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
|
||||||
import de.dennisguse.opentracks.content.provider.CustomContentProvider;
|
|
||||||
import de.dennisguse.opentracks.io.file.importer.TrackPointAssert;
|
|
||||||
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
|
|
||||||
import de.dennisguse.opentracks.services.sensors.AltitudeSumManager;
|
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
|
||||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for the track recording service.
|
|
||||||
*
|
|
||||||
* @author Bartlomiej Niechwiej
|
|
||||||
* <p>
|
|
||||||
* //TODO ATTENTION: This tests deletes all stored tracks in the database.
|
|
||||||
* So, if it is executed on a real device, data might be lost.
|
|
||||||
*/
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
public class TrackRecordingServiceTest {
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(5, TimeUnit.SECONDS);
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
|
|
||||||
|
|
||||||
@BeforeClass
|
|
||||||
public static void preSetUp() {
|
|
||||||
// Prepare looper for Android's message queue
|
|
||||||
if (Looper.myLooper() == null) Looper.prepare();
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterClass
|
|
||||||
public static void finalTearDown() {
|
|
||||||
if (Looper.myLooper() != null) Looper.myLooper().quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Context context = ApplicationProvider.getApplicationContext();
|
|
||||||
private final SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
|
||||||
private ContentProviderUtils contentProviderUtils;
|
|
||||||
|
|
||||||
private final Track.Id trackId = new Track.Id(Math.abs(new Random().nextLong()));
|
|
||||||
|
|
||||||
static Intent createStartIntent(Context context) {
|
|
||||||
return new Intent(context, TrackRecordingService.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final AltitudeSumManager altitudeSumManager = new AltitudeSumManager() {
|
|
||||||
@Override
|
|
||||||
public void fill(@NonNull TrackPoint trackPoint) {
|
|
||||||
trackPoint.setAltitudeGain(0f);
|
|
||||||
trackPoint.setAltitudeLoss(0f);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() {
|
|
||||||
// Set up the mock content resolver
|
|
||||||
ContentProvider customContentProvider = new CustomContentProvider() {
|
|
||||||
};
|
|
||||||
customContentProvider.attachInfo(context, null);
|
|
||||||
|
|
||||||
contentProviderUtils = new ContentProviderUtils(context);
|
|
||||||
|
|
||||||
// Let's use default values.
|
|
||||||
sharedPreferences.edit().clear().commit();
|
|
||||||
|
|
||||||
// Ensure that the database is empty before every test
|
|
||||||
contentProviderUtils.deleteAllTracks(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDown() throws TimeoutException {
|
|
||||||
// Reset service (if some previous test failed)
|
|
||||||
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context)))
|
|
||||||
.getService();
|
|
||||||
if (service.isRecording() || service.isPaused()) {
|
|
||||||
service.endCurrentTrack();
|
|
||||||
}
|
|
||||||
service.getTrackPointCreator().setClock(Clock.systemUTC());
|
|
||||||
|
|
||||||
// Ensure that the database is empty after every test
|
|
||||||
contentProviderUtils.deleteAllTracks(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SmallTest
|
|
||||||
@Test
|
|
||||||
public void testStartable() throws TimeoutException {
|
|
||||||
mServiceRule.startService(createStartIntent(context));
|
|
||||||
assertNotNull(mServiceRule.bindService(createStartIntent(context)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testBindable() throws TimeoutException {
|
|
||||||
IBinder service = mServiceRule.bindService(createStartIntent(context));
|
|
||||||
assertNotNull(service);
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testRecording_noTracks() throws TimeoutException {
|
|
||||||
// given
|
|
||||||
List<Track> tracks = contentProviderUtils.getTracks();
|
|
||||||
assertTrue(tracks.isEmpty());
|
|
||||||
|
|
||||||
// when
|
|
||||||
Intent startIntent = createStartIntent(context);
|
|
||||||
mServiceRule.startService(startIntent);
|
|
||||||
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(startIntent))
|
|
||||||
.getService();
|
|
||||||
|
|
||||||
// then
|
|
||||||
// Test if we start in no-recording mode by default.
|
|
||||||
assertFalse(service.isRecording());
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testRecording_oldTracks() throws TimeoutException {
|
|
||||||
// given
|
|
||||||
createDummyTrack(trackId);
|
|
||||||
|
|
||||||
// when
|
|
||||||
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context)))
|
|
||||||
.getService();
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertFalse(service.isRecording());
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testRecording_serviceRestart_whileRecording() throws TimeoutException {
|
|
||||||
// given
|
|
||||||
createDummyTrack(trackId);
|
|
||||||
|
|
||||||
//when
|
|
||||||
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context)))
|
|
||||||
.getService();
|
|
||||||
service.resumeTrack(trackId);
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertTrue(service.isRecording());
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testRecording_stop() throws TimeoutException {
|
|
||||||
// given
|
|
||||||
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context)))
|
|
||||||
.getService();
|
|
||||||
|
|
||||||
TrackPointCreator trackPointCreator = service.getTrackPointCreator();
|
|
||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:02Z"), ZoneId.of("CET")));
|
|
||||||
Track.Id trackId = service.startNewTrack();
|
|
||||||
trackPointCreator.stopGPS();
|
|
||||||
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
|
||||||
|
|
||||||
// when
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:03Z"), ZoneId.of("CET")));
|
|
||||||
service.endCurrentTrack();
|
|
||||||
|
|
||||||
// then
|
|
||||||
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
|
||||||
|
|
||||||
TrackPointAssert a = new TrackPointAssert();
|
|
||||||
a.assertEquals(List.of(
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse("2020-02-02T02:02:02Z")),
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse("2020-02-02T02:02:03Z"))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f)
|
|
||||||
), trackPoints);
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testRecording_pauseAndResume() throws TimeoutException {
|
|
||||||
// given
|
|
||||||
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context)))
|
|
||||||
.getService();
|
|
||||||
|
|
||||||
TrackPointCreator trackPointCreator = service.getTrackPointCreator();
|
|
||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:02Z"), ZoneId.of("CET")));
|
|
||||||
Track.Id trackId = service.startNewTrack();
|
|
||||||
trackPointCreator.stopGPS();
|
|
||||||
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
|
||||||
|
|
||||||
// when
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:03Z"), ZoneId.of("CET")));
|
|
||||||
service.pauseCurrentTrack();
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertEquals(2, contentProviderUtils.getTrackPointCursor(trackId, null).getCount());
|
|
||||||
|
|
||||||
//when
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:04Z"), ZoneId.of("CET")));
|
|
||||||
service.resumeTrack(trackId);
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertTrue(service.isRecording());
|
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
|
||||||
TrackPointAssert a = new TrackPointAssert();
|
|
||||||
a.assertEquals(List.of(
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse("2020-02-02T02:02:02Z")),
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse("2020-02-02T02:02:03Z"))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f),
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse("2020-02-02T02:02:04Z"))
|
|
||||||
), trackPoints);
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testRecording_resumeStoppedTrack() throws TimeoutException {
|
|
||||||
// given
|
|
||||||
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context)))
|
|
||||||
.getService();
|
|
||||||
|
|
||||||
TrackPointCreator trackPointCreator = service.getTrackPointCreator();
|
|
||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:02Z"), ZoneId.of("CET")));
|
|
||||||
Track.Id trackId = service.startNewTrack();
|
|
||||||
trackPointCreator.stopGPS();
|
|
||||||
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
|
||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:03Z"), ZoneId.of("CET")));
|
|
||||||
service.endCurrentTrack();
|
|
||||||
|
|
||||||
// when
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:04Z"), ZoneId.of("CET")));
|
|
||||||
service.resumeTrack(trackId);
|
|
||||||
trackPointCreator.stopGPS();
|
|
||||||
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
|
||||||
|
|
||||||
trackPointCreator.onNewTrackPoint(new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse("2020-02-02T02:02:05Z")), Distance.of(50));
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertTrue(service.isRecording());
|
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
|
||||||
TrackPointAssert a = new TrackPointAssert();
|
|
||||||
a.assertEquals(List.of(
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse("2020-02-02T02:02:02Z")),
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse("2020-02-02T02:02:03Z"))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f),
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse("2020-02-02T02:02:04Z")),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse("2020-02-02T02:02:05Z"))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f)
|
|
||||||
), trackPoints);
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testRecording_stopPausedTrack() throws TimeoutException {
|
|
||||||
// given
|
|
||||||
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context)))
|
|
||||||
.getService();
|
|
||||||
|
|
||||||
TrackPointCreator trackPointCreator = service.getTrackPointCreator();
|
|
||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:02Z"), ZoneId.of("CET")));
|
|
||||||
Track.Id trackId = service.startNewTrack();
|
|
||||||
trackPointCreator.stopGPS();
|
|
||||||
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
|
||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:03Z"), ZoneId.of("CET")));
|
|
||||||
service.pauseCurrentTrack();
|
|
||||||
|
|
||||||
// when
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:04Z"), ZoneId.of("CET")));
|
|
||||||
service.endCurrentTrack();
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertFalse(service.isRecording());
|
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
|
||||||
TrackPointAssert a = new TrackPointAssert();
|
|
||||||
a.assertEquals(List.of(
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse("2020-02-02T02:02:02Z")),
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse("2020-02-02T02:02:03Z"))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f)
|
|
||||||
), trackPoints);
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testStartNewTrack_alreadyRecording() throws TimeoutException {
|
|
||||||
// given
|
|
||||||
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context)))
|
|
||||||
.getService();
|
|
||||||
Track.Id trackId = service.startNewTrack();
|
|
||||||
assertTrue(service.isRecording());
|
|
||||||
|
|
||||||
// when
|
|
||||||
Track.Id newTrackId = service.startNewTrack();
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertNotNull(trackId);
|
|
||||||
assertNull(newTrackId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testEndCurrentTrack_noRecording() throws TimeoutException {
|
|
||||||
// given
|
|
||||||
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context)))
|
|
||||||
.getService();
|
|
||||||
assertFalse(service.isRecording());
|
|
||||||
|
|
||||||
// when
|
|
||||||
// Ending the current track when there is no recording should not result in any error.
|
|
||||||
service.endCurrentTrack();
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertFalse(service.isRecording());
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testInsertWaypointMarker_noRecordingTrack() throws TimeoutException {
|
|
||||||
// given
|
|
||||||
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context)))
|
|
||||||
.getService();
|
|
||||||
assertFalse(service.isRecording());
|
|
||||||
|
|
||||||
// when
|
|
||||||
Marker.Id markerId = service.insertMarker(null, null, null, null);
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertNull(markerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testInsertWaypointMarker_validWaypoint() throws TimeoutException {
|
|
||||||
// given
|
|
||||||
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(createStartIntent(context)))
|
|
||||||
.getService();
|
|
||||||
|
|
||||||
TrackPointCreator trackPointCreator = service.getTrackPointCreator();
|
|
||||||
trackPointCreator.stopGPS();
|
|
||||||
|
|
||||||
trackPointCreator.setClock(Clock.fixed(Instant.parse("2020-02-02T02:02:02Z"), ZoneId.of("CET")));
|
|
||||||
Track.Id trackId = service.startNewTrack();
|
|
||||||
|
|
||||||
assertTrue(service.isRecording());
|
|
||||||
trackPointCreator.onNewTrackPoint(
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse("2020-02-02T02:02:03Z"))
|
|
||||||
.setLatitude(10)
|
|
||||||
.setLongitude(10)
|
|
||||||
, Distance.of(50));
|
|
||||||
|
|
||||||
// when
|
|
||||||
Marker.Id markerId = service.insertMarker(null, null, null, null);
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertNotEquals(new Marker.Id(-1L), markerId);
|
|
||||||
Marker wpt = contentProviderUtils.getMarker(markerId);
|
|
||||||
assertEquals(context.getString(R.string.marker_icon_url), wpt.getIcon());
|
|
||||||
assertEquals(context.getString(R.string.marker_name_format, 1), wpt.getName());
|
|
||||||
assertEquals(trackId, wpt.getTrackId());
|
|
||||||
assertEquals(0.0, wpt.getLength().toM(), 0.01);
|
|
||||||
assertNotNull(wpt.getLocation());
|
|
||||||
|
|
||||||
service.endCurrentTrack();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addTrack(Track track) {
|
|
||||||
assertNotNull(track.getId());
|
|
||||||
contentProviderUtils.insertTrack(track);
|
|
||||||
assertEquals(track.getId(), contentProviderUtils.getTrack(track.getId()).getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: Do not use to create a track that is currently recording.
|
|
||||||
private void createDummyTrack(Track.Id id) {
|
|
||||||
Track dummyTrack = new Track();
|
|
||||||
dummyTrack.setId(id);
|
|
||||||
dummyTrack.setName("Dummy Track");
|
|
||||||
TrackStatistics trackStatistics = new TrackStatistics();
|
|
||||||
Instant now = Instant.now();
|
|
||||||
trackStatistics.setStartTime(now.minusSeconds(5L));
|
|
||||||
trackStatistics.setStopTime(now.minusSeconds(1L));
|
|
||||||
dummyTrack.setTrackStatistics(trackStatistics);
|
|
||||||
addTrack(dummyTrack);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void newTrackPoint(TrackRecordingService trackRecordingService, double latitude, double longitude, float accuracy, long speed) {
|
|
||||||
newTrackPoint(trackRecordingService, latitude, longitude, accuracy, speed, System.currentTimeMillis());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts a location and waits for 200ms.
|
|
||||||
*/
|
|
||||||
private static void newTrackPoint(TrackRecordingService trackRecordingService, double latitude, double longitude, float accuracy, long speed, long time) {
|
|
||||||
TrackPoint trackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.ofEpochMilli(time))
|
|
||||||
.setLongitude(longitude)
|
|
||||||
.setLatitude(latitude)
|
|
||||||
.setHorizontalAccuracy(Distance.of(accuracy))
|
|
||||||
.setSpeed(Speed.of(speed))
|
|
||||||
.setBearing(3.0f);
|
|
||||||
|
|
||||||
trackRecordingService.getTrackPointCreator().onNewTrackPoint(trackPoint, Distance.of(50));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-500
@@ -1,500 +0,0 @@
|
|||||||
package de.dennisguse.opentracks.services;
|
|
||||||
|
|
||||||
import android.content.ContentProvider;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.os.Looper;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|
||||||
import androidx.test.filters.MediumTest;
|
|
||||||
import androidx.test.rule.GrantPermissionRule;
|
|
||||||
import androidx.test.rule.ServiceTestRule;
|
|
||||||
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.AfterClass;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.BeforeClass;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
|
||||||
import de.dennisguse.opentracks.content.data.Speed;
|
|
||||||
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
|
||||||
import de.dennisguse.opentracks.content.provider.CustomContentProvider;
|
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorDataHeartRate;
|
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
|
||||||
import de.dennisguse.opentracks.io.file.importer.TrackPointAssert;
|
|
||||||
import de.dennisguse.opentracks.services.sensors.AltitudeSumManager;
|
|
||||||
import de.dennisguse.opentracks.services.sensors.BluetoothRemoteSensorManager;
|
|
||||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests insert location.
|
|
||||||
* <p>
|
|
||||||
* //TODO ATTENTION: This tests deletes all stored tracks in the database.
|
|
||||||
* So, if it is executed on a real device, data might be lost.
|
|
||||||
*/
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
//TODO Implement as mock test; no need to store data in database
|
|
||||||
public class TrackRecordingServiceTestLocation {
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(5, TimeUnit.SECONDS);
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
|
|
||||||
|
|
||||||
private final Context context = ApplicationProvider.getApplicationContext();
|
|
||||||
private ContentProviderUtils contentProviderUtils;
|
|
||||||
|
|
||||||
private TrackRecordingService service;
|
|
||||||
|
|
||||||
private final AltitudeSumManager altitudeSumManager = new AltitudeSumManager() {
|
|
||||||
@Override
|
|
||||||
public void fill(@NonNull TrackPoint trackPoint) {
|
|
||||||
trackPoint.setAltitudeGain(0f);
|
|
||||||
trackPoint.setAltitudeLoss(0f);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@BeforeClass
|
|
||||||
public static void preSetUp() {
|
|
||||||
// Prepare looper for Android's message queue
|
|
||||||
if (Looper.myLooper() == null) Looper.prepare();
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterClass
|
|
||||||
public static void finalTearDown() {
|
|
||||||
if (Looper.myLooper() != null) Looper.myLooper().quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() throws TimeoutException {
|
|
||||||
// Set up the mock content resolver
|
|
||||||
ContentProvider customContentProvider = new CustomContentProvider() {
|
|
||||||
};
|
|
||||||
customContentProvider.attachInfo(context, null);
|
|
||||||
|
|
||||||
contentProviderUtils = new ContentProviderUtils(context);
|
|
||||||
tearDown();
|
|
||||||
|
|
||||||
// Let's use default values.
|
|
||||||
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
|
||||||
sharedPreferences.edit().clear().commit();
|
|
||||||
|
|
||||||
service = ((TrackRecordingService.Binder) mServiceRule.bindService(TrackRecordingServiceTest.createStartIntent(context)))
|
|
||||||
.getService();
|
|
||||||
service.getTrackPointCreator().stopGPS();
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDown() {
|
|
||||||
// Ensure that the database is empty after every test
|
|
||||||
contentProviderUtils.deleteAllTracks(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testOnLocationChangedAsync_movingAccurate() {
|
|
||||||
// given
|
|
||||||
Track.Id trackId = service.startNewTrack();
|
|
||||||
service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager);
|
|
||||||
|
|
||||||
// when
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 1, 15);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0001, 35.0, 2, 15);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0002, 35.0, 3, 15);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0003, 35.0, 4, 15);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0004, 35.0, 5, 15);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0005, 35.0, 6, 15);
|
|
||||||
|
|
||||||
service.endCurrentTrack();
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertFalse(service.isRecording());
|
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
|
||||||
TrackPointAssert a = new TrackPointAssert()
|
|
||||||
.ignoreTime();
|
|
||||||
a.assertEquals(List.of(
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, null),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null)
|
|
||||||
.setLatitude(45)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(1))
|
|
||||||
.setSpeed(Speed.of(15))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null)
|
|
||||||
.setLatitude(45.0001)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(2))
|
|
||||||
.setSpeed(Speed.of(15))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null)
|
|
||||||
.setLatitude(45.0001)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(3))
|
|
||||||
.setSpeed(Speed.of(15))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null)
|
|
||||||
.setLatitude(45.0002)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(4))
|
|
||||||
.setSpeed(Speed.of(15))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null)
|
|
||||||
.setLatitude(45.0003)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(5))
|
|
||||||
.setSpeed(Speed.of(15))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null)
|
|
||||||
.setLatitude(45.0004)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(6))
|
|
||||||
.setSpeed(Speed.of(15))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f),
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, null)
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f)
|
|
||||||
), trackPoints);
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testOnLocationChangedAsync_slowMovingAccurate() {
|
|
||||||
// given
|
|
||||||
Track.Id trackId = service.startNewTrack();
|
|
||||||
service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager);
|
|
||||||
|
|
||||||
// when
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 1, 15);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.000001, 35.0, 2, 15);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.000002, 35.0, 3, 15);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.000003, 35.0, 4, 15);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.000004, 35.0, 5, 15);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.000005, 35.0, 6, 15);
|
|
||||||
|
|
||||||
service.endCurrentTrack();
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertFalse(service.isRecording());
|
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
|
||||||
TrackPointAssert a = new TrackPointAssert()
|
|
||||||
.ignoreTime();
|
|
||||||
a.assertEquals(List.of(
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, null),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null)
|
|
||||||
.setLatitude(45)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(1))
|
|
||||||
.setSpeed(Speed.of(15))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null)
|
|
||||||
.setLatitude(45.0005)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(6))
|
|
||||||
.setSpeed(Speed.of(15))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f),
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, null)
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f)
|
|
||||||
), trackPoints);
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testOnLocationChangedAsync_idle() {
|
|
||||||
// given
|
|
||||||
Track.Id trackId = service.startNewTrack();
|
|
||||||
service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager);
|
|
||||||
|
|
||||||
// when
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 1, 0);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 2, 0);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 3, 0);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 4, 0);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 5, 0);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 6, 0);
|
|
||||||
|
|
||||||
service.endCurrentTrack();
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertFalse(service.isRecording());
|
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
|
||||||
TrackPointAssert a = new TrackPointAssert()
|
|
||||||
.ignoreTime();
|
|
||||||
a.assertEquals(List.of(
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, null),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null)
|
|
||||||
.setLatitude(45)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(1))
|
|
||||||
.setSpeed(Speed.of(0))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null) //TODO Why is this added? Systems is idle and not moving at all.
|
|
||||||
.setLatitude(45)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(2))
|
|
||||||
.setSpeed(Speed.of(0))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null)
|
|
||||||
.setLatitude(45)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(6))
|
|
||||||
.setSpeed(Speed.of(0))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f),
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, null)
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f)
|
|
||||||
), trackPoints);
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testOnLocationChangedAsync_idle_withMovement() {
|
|
||||||
// given
|
|
||||||
Track.Id trackId = service.startNewTrack();
|
|
||||||
service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager);
|
|
||||||
service.getTrackPointCreator().stopGPS();
|
|
||||||
|
|
||||||
// when
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 1, 15);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 2, 0);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 3, 0);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 4, 0);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 5, 0);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 6, 15);
|
|
||||||
|
|
||||||
service.endCurrentTrack();
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertFalse(service.isRecording());
|
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
|
||||||
TrackPointAssert a = new TrackPointAssert()
|
|
||||||
.ignoreTime();
|
|
||||||
a.assertEquals(List.of(
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, null),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null)
|
|
||||||
.setLatitude(45)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(1))
|
|
||||||
.setSpeed(Speed.of(15))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null) //TODO Check why this trackPoint is inserted.
|
|
||||||
.setLatitude(45)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(2))
|
|
||||||
.setSpeed(Speed.of(0))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null) //TODO Check why this trackPoint is inserted.
|
|
||||||
.setLatitude(45)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(5))
|
|
||||||
.setSpeed(Speed.of(0))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null)
|
|
||||||
.setLatitude(45)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(6))
|
|
||||||
.setSpeed(Speed.of(15))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f),
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, null)
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f)
|
|
||||||
), trackPoints);
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testOnLocationChangedAsync_idle_withSensorData() {
|
|
||||||
// given
|
|
||||||
Track.Id trackId = service.startNewTrack();
|
|
||||||
service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager);
|
|
||||||
service.getTrackPointCreator().setRemoteSensorManager(new BluetoothRemoteSensorManager(context) {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SensorDataSet fill(@NonNull TrackPoint trackPoint) {
|
|
||||||
SensorDataSet sensorDataSet = new SensorDataSet();
|
|
||||||
sensorDataSet.set(new SensorDataHeartRate("sensorName", "sensorAddress", 5f));
|
|
||||||
sensorDataSet.fillTrackPoint(trackPoint);
|
|
||||||
return sensorDataSet;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// when
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 1, 0);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 2, 0);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 3, 0);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 4, 0);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 5, 0);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 6, 0);
|
|
||||||
|
|
||||||
service.endCurrentTrack();
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertFalse(service.isRecording());
|
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
|
||||||
TrackPointAssert a = new TrackPointAssert()
|
|
||||||
.ignoreTime();
|
|
||||||
a.assertEquals(List.of(
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, null),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null)
|
|
||||||
.setLatitude(45)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(1))
|
|
||||||
.setSpeed(Speed.of(0))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f)
|
|
||||||
.setHeartRate_bpm(5f),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null)
|
|
||||||
.setLatitude(45)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(2))
|
|
||||||
.setSpeed(Speed.of(0))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f)
|
|
||||||
.setHeartRate_bpm(5f),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null)
|
|
||||||
.setLatitude(45)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(3))
|
|
||||||
.setSpeed(Speed.of(0))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f)
|
|
||||||
.setHeartRate_bpm(5f),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null)
|
|
||||||
.setLatitude(45)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(4))
|
|
||||||
.setSpeed(Speed.of(0))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f)
|
|
||||||
.setHeartRate_bpm(5f),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null)
|
|
||||||
.setLatitude(45)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(5))
|
|
||||||
.setSpeed(Speed.of(0))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f)
|
|
||||||
.setHeartRate_bpm(5f),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null)
|
|
||||||
.setLatitude(45)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(6))
|
|
||||||
.setSpeed(Speed.of(0))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f)
|
|
||||||
.setHeartRate_bpm(5f),
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, null)
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f)
|
|
||||||
.setHeartRate_bpm(5f)
|
|
||||||
), trackPoints);
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testOnLocationChangedAsync_segment() {
|
|
||||||
// given
|
|
||||||
Track.Id trackId = service.startNewTrack();
|
|
||||||
service.getTrackPointCreator().setAltitudeSumManager(altitudeSumManager);
|
|
||||||
|
|
||||||
// when
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.0, 35.0, 1, 0);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.1, 35.0, 2, 0);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.1, 35.0, 3, 0);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.2, 35.0, 4, 0);
|
|
||||||
TrackRecordingServiceTest.newTrackPoint(service, 45.2, 35.0, 5, 0);
|
|
||||||
|
|
||||||
service.endCurrentTrack();
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertFalse(service.isRecording());
|
|
||||||
|
|
||||||
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
|
||||||
|
|
||||||
TrackPointAssert a = new TrackPointAssert()
|
|
||||||
.ignoreTime();
|
|
||||||
a.assertEquals(List.of(
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, null),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null)
|
|
||||||
.setLatitude(45)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(1))
|
|
||||||
.setSpeed(Speed.of(0))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f),
|
|
||||||
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, null)
|
|
||||||
.setLatitude(45.1)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(2))
|
|
||||||
.setSpeed(Speed.of(0))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null)
|
|
||||||
.setLatitude(45.1)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(3))
|
|
||||||
.setSpeed(Speed.of(0))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f),
|
|
||||||
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, null)
|
|
||||||
.setLatitude(45.2)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(4))
|
|
||||||
.setSpeed(Speed.of(0))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f),
|
|
||||||
new TrackPoint(TrackPoint.Type.TRACKPOINT, null)
|
|
||||||
.setLatitude(45.2)
|
|
||||||
.setLongitude(35)
|
|
||||||
.setHorizontalAccuracy(Distance.of(5))
|
|
||||||
.setSpeed(Speed.of(0))
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f),
|
|
||||||
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, null)
|
|
||||||
.setAltitudeGain(0f)
|
|
||||||
.setAltitudeLoss(0f)
|
|
||||||
), trackPoints);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-237
@@ -1,237 +0,0 @@
|
|||||||
package de.dennisguse.opentracks.services;
|
|
||||||
|
|
||||||
import android.content.ContentProvider;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.os.Looper;
|
|
||||||
|
|
||||||
import androidx.preference.PreferenceManager;
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|
||||||
import androidx.test.filters.MediumTest;
|
|
||||||
import androidx.test.rule.ServiceTestRule;
|
|
||||||
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.AfterClass;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.BeforeClass;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
|
||||||
import de.dennisguse.opentracks.content.data.Speed;
|
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
|
||||||
import de.dennisguse.opentracks.content.provider.CustomContentProvider;
|
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
|
||||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for the track recording service, which require a {@link Looper}.
|
|
||||||
*
|
|
||||||
* @author Bartlomiej Niechwiej
|
|
||||||
* <p>
|
|
||||||
* ATTENTION: This tests deletes all stored tracks in the database.
|
|
||||||
* So, if it is executed on a real device, data might be lost.
|
|
||||||
*/
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
public class TrackRecordingServiceTestLooper {
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(5, TimeUnit.SECONDS);
|
|
||||||
|
|
||||||
private final Context context = ApplicationProvider.getApplicationContext();
|
|
||||||
private final SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
|
||||||
|
|
||||||
private ContentProviderUtils contentProviderUtils;
|
|
||||||
|
|
||||||
@BeforeClass
|
|
||||||
public static void preSetUp() {
|
|
||||||
// Prepare looper for Android's message queue
|
|
||||||
if (Looper.myLooper() == null) Looper.prepare();
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterClass
|
|
||||||
public static void finalTearDown() {
|
|
||||||
if (Looper.myLooper() != null) Looper.myLooper().quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() {
|
|
||||||
// Set up the mock content resolver
|
|
||||||
ContentProvider customContentProvider = new CustomContentProvider() {
|
|
||||||
};
|
|
||||||
customContentProvider.attachInfo(context, null);
|
|
||||||
|
|
||||||
contentProviderUtils = new ContentProviderUtils(context);
|
|
||||||
|
|
||||||
// Let's use default values.
|
|
||||||
sharedPreferences.edit().clear().apply();
|
|
||||||
|
|
||||||
// Ensure that the database is empty before every test
|
|
||||||
contentProviderUtils.deleteAllTracks(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDown() throws TimeoutException {
|
|
||||||
// Reset service (if some previous test failed)
|
|
||||||
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(TrackRecordingServiceTest.createStartIntent(context)))
|
|
||||||
.getService();
|
|
||||||
if (service.isRecording() || service.isPaused()) {
|
|
||||||
service.endCurrentTrack();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure that the database is empty after every test
|
|
||||||
contentProviderUtils.deleteAllTracks(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testWithProperties_minRequiredAccuracy() throws TimeoutException {
|
|
||||||
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
|
|
||||||
editor.putInt(context.getString(R.string.recording_gps_accuracy_key), 500);
|
|
||||||
editor.commit();
|
|
||||||
fullRecordingSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testWithProperties_maxRecordingDistanceDefault() throws TimeoutException {
|
|
||||||
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
|
|
||||||
editor.putInt(context.getString(R.string.max_recording_distance_key), Integer.parseInt(context.getResources().getString(R.string.max_recording_distance_default)));
|
|
||||||
editor.commit();
|
|
||||||
fullRecordingSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testWithProperties_maxRecordingDistance() throws TimeoutException {
|
|
||||||
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
|
|
||||||
editor.putInt(context.getString(R.string.max_recording_distance_key), 50);
|
|
||||||
editor.commit();
|
|
||||||
fullRecordingSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testWithProperties_minRecordingDistanceDefault() throws TimeoutException {
|
|
||||||
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
|
|
||||||
editor.putInt(context.getString(R.string.recording_distance_interval_key), Integer.parseInt(context.getResources().getString(R.string.min_recording_interval_default)));
|
|
||||||
editor.commit();
|
|
||||||
fullRecordingSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testWithProperties_minRecordingDistance() throws TimeoutException {
|
|
||||||
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
|
|
||||||
editor.putInt(context.getString(R.string.recording_distance_interval_key), 2);
|
|
||||||
editor.commit();
|
|
||||||
fullRecordingSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testWithProperties_metricUnitsDefault() throws TimeoutException {
|
|
||||||
PreferencesUtils.setString(sharedPreferences, context, R.string.stats_units_key, context.getString(R.string.stats_units_default));
|
|
||||||
fullRecordingSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testWithProperties_metricUnitsDisabled() throws TimeoutException {
|
|
||||||
PreferencesUtils.setString(sharedPreferences, context, R.string.stats_units_key, context.getString(R.string.stats_units_imperial));
|
|
||||||
fullRecordingSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testWithProperties_minRecordingIntervalDefault() throws TimeoutException {
|
|
||||||
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
|
|
||||||
editor.putInt(context.getString(R.string.min_recording_interval_key), Integer.parseInt(context.getResources().getString(R.string.min_recording_interval_default)));
|
|
||||||
editor.commit();
|
|
||||||
fullRecordingSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testWithProperties_minRecordingInterval() throws TimeoutException {
|
|
||||||
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
|
|
||||||
editor.putInt(context.getString(R.string.min_recording_interval_key), 2);
|
|
||||||
editor.commit();
|
|
||||||
fullRecordingSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testWithProperties_minRequiredAccuracyDefault() throws TimeoutException {
|
|
||||||
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
|
|
||||||
editor.putInt(context.getString(R.string.recording_gps_accuracy_key), Integer.parseInt(context.getResources().getString(R.string.recording_gps_accuracy_default)));
|
|
||||||
editor.commit();
|
|
||||||
fullRecordingSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
@MediumTest
|
|
||||||
@Test
|
|
||||||
public void testIntegration_completeRecordingSession() throws TimeoutException {
|
|
||||||
List<Track> tracks = contentProviderUtils.getTracks();
|
|
||||||
assertTrue(tracks.isEmpty());
|
|
||||||
fullRecordingSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void fullRecordingSession() throws TimeoutException {
|
|
||||||
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(TrackRecordingServiceTest.createStartIntent(context)))
|
|
||||||
.getService();
|
|
||||||
assertFalse(service.isRecording());
|
|
||||||
|
|
||||||
// Start a track.
|
|
||||||
Track.Id trackId = service.startNewTrack();
|
|
||||||
assertNotNull(trackId);
|
|
||||||
assertTrue(service.isRecording());
|
|
||||||
Track track = contentProviderUtils.getTrack(trackId);
|
|
||||||
assertNotNull(track);
|
|
||||||
assertEquals(trackId, track.getId());
|
|
||||||
|
|
||||||
// Insert a few points, markers and statistics.
|
|
||||||
for (int i = 0; i < 30; i++) {
|
|
||||||
//TODO Should send locations to LocationHandler instead of TrackPoints to TrackPointCreator?
|
|
||||||
TrackPoint trackPoint = new TrackPoint(TrackPoint.Type.TRACKPOINT, service.getTrackPointCreator().createNow())
|
|
||||||
.setLongitude(35.0f + i / 10.0f)
|
|
||||||
.setLatitude(45.0f - i / 5.0f)
|
|
||||||
.setHorizontalAccuracy(Distance.of(5))
|
|
||||||
.setSpeed(Speed.of(10))
|
|
||||||
.setBearing(3.0f);
|
|
||||||
|
|
||||||
Distance prefAccuracy = PreferencesUtils.getThresholdHorizontalAccuracy(sharedPreferences, context);
|
|
||||||
service.getTrackPointCreator().onNewTrackPoint(trackPoint, prefAccuracy);
|
|
||||||
|
|
||||||
if (i % 7 == 0) {
|
|
||||||
service.insertMarker(null, null, null, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop the track. Validate if it has correct data.
|
|
||||||
service.endCurrentTrack();
|
|
||||||
assertFalse(service.isRecording());
|
|
||||||
track = contentProviderUtils.getTrack(trackId);
|
|
||||||
assertNotNull(track);
|
|
||||||
assertEquals(trackId, track.getId());
|
|
||||||
TrackStatistics trackStatistics = track.getTrackStatistics();
|
|
||||||
assertNotNull(trackStatistics);
|
|
||||||
assertTrue(trackStatistics.getStartTime().isAfter(Instant.ofEpochMilli(0)));
|
|
||||||
assertTrue(trackStatistics.getStopTime().isAfter(trackStatistics.getStartTime()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+158
@@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
* 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.services;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Looper;
|
||||||
|
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
import androidx.test.filters.MediumTest;
|
||||||
|
import androidx.test.rule.GrantPermissionRule;
|
||||||
|
import androidx.test.rule.ServiceTestRule;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||||
|
import de.dennisguse.opentracks.data.models.Marker;
|
||||||
|
import de.dennisguse.opentracks.data.models.Track;
|
||||||
|
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||||
|
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class TrackRecordingServiceTestMarker {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(5, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
|
||||||
|
|
||||||
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
private ContentProviderUtils contentProviderUtils;
|
||||||
|
|
||||||
|
private TrackRecordingService service;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void preSetUp() {
|
||||||
|
// Prepare looper for Android's message queue
|
||||||
|
if (Looper.myLooper() == null) Looper.prepare();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void finalTearDown() {
|
||||||
|
if (Looper.myLooper() != null) Looper.myLooper().quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private TrackRecordingService startService() throws TimeoutException {
|
||||||
|
Intent startIntent = new Intent(context, TrackRecordingService.class);
|
||||||
|
return ((TrackRecordingService.Binder) mServiceRule.bindService(startIntent))
|
||||||
|
.getService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws TimeoutException {
|
||||||
|
contentProviderUtils = new ContentProviderUtils(context);
|
||||||
|
service = startService();
|
||||||
|
tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws TimeoutException {
|
||||||
|
TrackRecordingServiceTestUtils.resetService(mServiceRule, context);
|
||||||
|
|
||||||
|
// Ensure that the database is empty after every test
|
||||||
|
contentProviderUtils.deleteAllTracks(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
@Test
|
||||||
|
public void notRecording_testInsertMarker() {
|
||||||
|
// given
|
||||||
|
assertFalse(service.isRecording());
|
||||||
|
|
||||||
|
// when
|
||||||
|
Marker.Id markerId = service.insertMarker(null, null, null, null);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertNull(markerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
@Test
|
||||||
|
public void recording_noGPSfix_cannotCreateMarker() {
|
||||||
|
// given
|
||||||
|
service.startNewTrack();
|
||||||
|
|
||||||
|
// when
|
||||||
|
Marker.Id markerId = service.insertMarker(null, null, null, null);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertNull(markerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
@Test
|
||||||
|
public void recording_GPSfix_createsMarker() {
|
||||||
|
// given
|
||||||
|
TrackPointCreator trackPointCreator = service.getTrackPointCreator();
|
||||||
|
trackPointCreator.stopGPS();
|
||||||
|
|
||||||
|
trackPointCreator.setClock("2020-02-02T02:02:02Z");
|
||||||
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
service.stopUpdateRecordingData();
|
||||||
|
|
||||||
|
assertTrue(service.isRecording());
|
||||||
|
trackPointCreator.onNewTrackPoint(
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse("2020-02-02T02:02:03Z"))
|
||||||
|
.setLatitude(10)
|
||||||
|
.setLongitude(10)
|
||||||
|
);
|
||||||
|
|
||||||
|
// when
|
||||||
|
Marker.Id markerId = service.insertMarker(null, null, null, null);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertNotEquals(new Marker.Id(-1L), markerId);
|
||||||
|
Marker wpt = contentProviderUtils.getMarker(markerId);
|
||||||
|
assertEquals(context.getString(R.string.marker_icon_url), wpt.getIcon());
|
||||||
|
assertEquals(context.getString(R.string.marker_name_format, 1), wpt.getName());
|
||||||
|
assertEquals(trackId, wpt.getTrackId());
|
||||||
|
assertEquals(0.0, wpt.getLength().toM(), 0.01);
|
||||||
|
assertNotNull(wpt.getLocation());
|
||||||
|
|
||||||
|
service.endCurrentTrack();
|
||||||
|
}
|
||||||
|
}
|
||||||
+820
@@ -0,0 +1,820 @@
|
|||||||
|
package de.dennisguse.opentracks.services;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Looper;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
import androidx.test.filters.MediumTest;
|
||||||
|
import androidx.test.rule.GrantPermissionRule;
|
||||||
|
import androidx.test.rule.ServiceTestRule;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||||
|
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||||
|
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.data.models.TrackPoint;
|
||||||
|
import de.dennisguse.opentracks.io.file.importer.TrackPointAssert;
|
||||||
|
import de.dennisguse.opentracks.sensors.AltitudeSumManager;
|
||||||
|
import de.dennisguse.opentracks.sensors.BluetoothRemoteSensorManager;
|
||||||
|
import de.dennisguse.opentracks.sensors.sensorData.SensorDataRunning;
|
||||||
|
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 TrackRecordingServiceTestRecording {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(5, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
|
||||||
|
|
||||||
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
private ContentProviderUtils contentProviderUtils;
|
||||||
|
|
||||||
|
private TrackRecordingService service;
|
||||||
|
|
||||||
|
private final AltitudeSumManager altitudeSumManager = new AltitudeSumManager() {
|
||||||
|
@Override
|
||||||
|
public void fill(@NonNull TrackPoint trackPoint) {
|
||||||
|
trackPoint.setAltitudeGain(0f);
|
||||||
|
trackPoint.setAltitudeLoss(0f);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void preSetUp() {
|
||||||
|
// Prepare looper for Android's message queue
|
||||||
|
if (Looper.myLooper() == null) Looper.prepare();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void finalTearDown() {
|
||||||
|
if (Looper.myLooper() != null) Looper.myLooper().quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private TrackRecordingService startService() throws TimeoutException {
|
||||||
|
Intent startIntent = new Intent(context, TrackRecordingService.class);
|
||||||
|
return ((TrackRecordingService.Binder) mServiceRule.bindService(startIntent))
|
||||||
|
.getService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws TimeoutException {
|
||||||
|
contentProviderUtils = new ContentProviderUtils(context);
|
||||||
|
tearDown();
|
||||||
|
|
||||||
|
PreferencesUtils.setString(R.string.recording_distance_interval_key, R.string.recording_distance_interval_default);
|
||||||
|
PreferencesUtils.setString(R.string.idle_speed_key, R.string.idle_speed_default);
|
||||||
|
|
||||||
|
service = startService();
|
||||||
|
service.getTrackPointCreator().stopGPS();
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws TimeoutException {
|
||||||
|
TrackRecordingServiceTestUtils.resetService(mServiceRule, context);
|
||||||
|
// Ensure that the database is empty after every test
|
||||||
|
contentProviderUtils.deleteAllTracks(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
@Test
|
||||||
|
public void recording_startStop() {
|
||||||
|
|
||||||
|
// given
|
||||||
|
TrackPointCreator trackPointCreator = service.getTrackPointCreator();
|
||||||
|
|
||||||
|
|
||||||
|
// when
|
||||||
|
String startTime = "2020-02-02T02:02:02Z";
|
||||||
|
trackPointCreator.setClock(startTime);
|
||||||
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
trackPointCreator.stopGPS();
|
||||||
|
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(new TrackStatistics(startTime, startTime, 0, 0, 0, 0, null, null)
|
||||||
|
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
new TrackPointAssert().assertEquals(List.of(
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime))
|
||||||
|
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
|
||||||
|
|
||||||
|
|
||||||
|
// when
|
||||||
|
String stopTime = "2020-02-02T02:02:03Z";
|
||||||
|
trackPointCreator.setClock(stopTime);
|
||||||
|
service.endCurrentTrack();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(new TrackStatistics(startTime, stopTime, 0, 1, 0, 0, 0f, 0f)
|
||||||
|
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
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)
|
||||||
|
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
@Test
|
||||||
|
public void testRecording_startPauseResume() {
|
||||||
|
// given
|
||||||
|
String startTime = "2020-02-02T02:02:02Z";
|
||||||
|
TrackPointCreator trackPointCreator = service.getTrackPointCreator();
|
||||||
|
|
||||||
|
trackPointCreator.setClock(startTime);
|
||||||
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
trackPointCreator.stopGPS();
|
||||||
|
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
||||||
|
|
||||||
|
// when
|
||||||
|
String pauseTime = "2020-02-02T02:02:03Z";
|
||||||
|
trackPointCreator.setClock(pauseTime);
|
||||||
|
service.pauseCurrentTrack();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(new TrackStatistics(startTime, pauseTime, 0, 1, 0, 0, 0f, 0f)
|
||||||
|
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
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)
|
||||||
|
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
|
||||||
|
|
||||||
|
//when
|
||||||
|
String resumeTime = "2020-02-02T02:02:04Z";
|
||||||
|
trackPointCreator.setClock(resumeTime);
|
||||||
|
service.resumeTrack(trackId);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(new TrackStatistics(startTime, resumeTime, 0, 1, 0, 0, 0f, 0f)
|
||||||
|
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
new TrackPointAssert().assertEquals(List.of(
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(pauseTime))
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setAltitudeLoss(0f),
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(resumeTime))
|
||||||
|
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
@Test
|
||||||
|
public void testRecording_startPauseStop() {
|
||||||
|
// given
|
||||||
|
TrackPointCreator trackPointCreator = service.getTrackPointCreator();
|
||||||
|
|
||||||
|
String starTime = "2020-02-02T02:02:02Z";
|
||||||
|
trackPointCreator.setClock(starTime);
|
||||||
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
trackPointCreator.stopGPS();
|
||||||
|
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
||||||
|
|
||||||
|
String pauseTime = "2020-02-02T02:02:03Z";
|
||||||
|
trackPointCreator.setClock(pauseTime);
|
||||||
|
service.pauseCurrentTrack();
|
||||||
|
|
||||||
|
// when
|
||||||
|
trackPointCreator.setClock("2020-02-02T02:02:04Z");
|
||||||
|
service.endCurrentTrack();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertFalse(service.isRecording());
|
||||||
|
|
||||||
|
List<TrackPoint> trackPoints = TestDataUtil.getTrackPoints(contentProviderUtils, trackId);
|
||||||
|
TrackPointAssert a = new TrackPointAssert();
|
||||||
|
a.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)
|
||||||
|
), trackPoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
@Test
|
||||||
|
public void testRecording_startStopResumeStop() {
|
||||||
|
// given
|
||||||
|
String startTime = "2020-02-02T02:02:02Z";
|
||||||
|
TrackPointCreator trackPointCreator = service.getTrackPointCreator();
|
||||||
|
|
||||||
|
trackPointCreator.setClock(startTime);
|
||||||
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
trackPointCreator.stopGPS();
|
||||||
|
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
||||||
|
|
||||||
|
String stopTime = "2020-02-02T02:02:03Z";
|
||||||
|
trackPointCreator.setClock(stopTime);
|
||||||
|
service.endCurrentTrack();
|
||||||
|
|
||||||
|
// when
|
||||||
|
String resumeTime = "2020-02-02T02:02:04Z";
|
||||||
|
trackPointCreator.setClock(resumeTime);
|
||||||
|
service.resumeTrack(trackId);
|
||||||
|
trackPointCreator.stopGPS();
|
||||||
|
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
||||||
|
|
||||||
|
// then
|
||||||
|
new TrackPointAssert().assertEquals(List.of(
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setAltitudeLoss(0f),
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(resumeTime))
|
||||||
|
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
@Test
|
||||||
|
public void testRecording_gpsOnly_recordingDistance_above() {
|
||||||
|
// given
|
||||||
|
String startTime = "2020-02-02T02:02:02Z";
|
||||||
|
TrackPointCreator trackPointCreator = service.getTrackPointCreator();
|
||||||
|
trackPointCreator.setClock(startTime);
|
||||||
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
||||||
|
|
||||||
|
|
||||||
|
// when
|
||||||
|
String gps1 = "2020-02-02T02:02:03Z";
|
||||||
|
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(new TrackStatistics(startTime, gps1, 0, 1, 0, 0, 0f, 0f)
|
||||||
|
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
// when
|
||||||
|
String gps2 = "2020-02-02T02:02:06Z";
|
||||||
|
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps2, 45.0001, 35.0, 1, 15);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(new TrackStatistics(startTime, gps2, 11.113178253173828f, 4, 3, 15, 0f, 0f)
|
||||||
|
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
// when
|
||||||
|
String gps3 = "2020-02-02T02:02:08Z";
|
||||||
|
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps3, 45.0002, 35.0, 1, 15);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(new TrackStatistics(startTime, gps3, 22.226356506347656, 6, 5, 15, 0f, 0f)
|
||||||
|
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
|
||||||
|
// when
|
||||||
|
String stopTime = "2020-02-02T02:02:12Z";
|
||||||
|
trackPointCreator.setClock(stopTime);
|
||||||
|
service.endCurrentTrack();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(new TrackStatistics(startTime, stopTime, 22.226356506347656, 10, 5, 15, 0f, 0f)
|
||||||
|
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
new TrackPointAssert().assertEquals(List.of(
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps1))
|
||||||
|
.setLatitude(45)
|
||||||
|
.setLongitude(35)
|
||||||
|
.setHorizontalAccuracy(Distance.of(1))
|
||||||
|
.setSpeed(Speed.of(15))
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setAltitudeLoss(0f),
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps2))
|
||||||
|
.setLatitude(45.0001)
|
||||||
|
.setLongitude(35)
|
||||||
|
.setHorizontalAccuracy(Distance.of(1))
|
||||||
|
.setSpeed(Speed.of(15))
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setAltitudeLoss(0f),
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps3))
|
||||||
|
.setLatitude(45.0001)
|
||||||
|
.setLongitude(35)
|
||||||
|
.setHorizontalAccuracy(Distance.of(1))
|
||||||
|
.setSpeed(Speed.of(15))
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setAltitudeLoss(0f),
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setAltitudeLoss(0f)
|
||||||
|
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
@Test
|
||||||
|
public void testRecording_gpsOnly_recordingDistance_above_speed_0() {
|
||||||
|
// given
|
||||||
|
String startTime = "2020-02-02T02:02:02Z";
|
||||||
|
TrackPointCreator trackPointCreator = service.getTrackPointCreator();
|
||||||
|
trackPointCreator.setClock(startTime);
|
||||||
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
||||||
|
|
||||||
|
// when
|
||||||
|
String gps1 = "2020-02-02T02:02:03Z";
|
||||||
|
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 0);
|
||||||
|
|
||||||
|
// then
|
||||||
|
TrackStatistics gps1statistics = new TrackStatistics(startTime, gps1, 0, 1, 0, 0, 0f, 0f);
|
||||||
|
assertEquals(gps1statistics, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
// when
|
||||||
|
String gps2 = "2020-02-02T02:02:06Z";
|
||||||
|
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps2, 45.0001, 35.0, 1, 0);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(gps1statistics, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
// when
|
||||||
|
String gps3 = "2020-02-02T02:02:08Z";
|
||||||
|
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps3, 45.0002, 35.0, 1, 0);
|
||||||
|
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(gps1statistics, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
// when
|
||||||
|
String stopTime = "2020-02-02T02:02:12Z";
|
||||||
|
trackPointCreator.setClock(stopTime);
|
||||||
|
service.endCurrentTrack();
|
||||||
|
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(new TrackStatistics(startTime, stopTime, 0, 10, 0, 0, 0f, 0f)
|
||||||
|
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
new TrackPointAssert().assertEquals(List.of(
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps1))
|
||||||
|
.setLatitude(45)
|
||||||
|
.setLongitude(35)
|
||||||
|
.setHorizontalAccuracy(Distance.of(1))
|
||||||
|
.setSpeed(Speed.of(0))
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setAltitudeLoss(0f),
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps3))
|
||||||
|
.setLatitude(45.0001)
|
||||||
|
.setLongitude(35)
|
||||||
|
.setHorizontalAccuracy(Distance.of(1))
|
||||||
|
.setSpeed(Speed.of(0))
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setAltitudeLoss(0f),
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setAltitudeLoss(0f)
|
||||||
|
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
@Test
|
||||||
|
public void testRecording_gpsOnly_recordingDistance_below() {
|
||||||
|
// given
|
||||||
|
String startTime = "2020-02-02T02:02:02Z";
|
||||||
|
TrackPointCreator trackPointCreator = service.getTrackPointCreator();
|
||||||
|
trackPointCreator.setClock(startTime);
|
||||||
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
||||||
|
|
||||||
|
// when
|
||||||
|
String gps1 = "2020-02-02T02:02:03Z";
|
||||||
|
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15);
|
||||||
|
|
||||||
|
// then
|
||||||
|
TrackStatistics gps1Statistics = new TrackStatistics(startTime, gps1, 0, 1, 0, 0, 0f, 0f);
|
||||||
|
assertEquals(gps1Statistics, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
// when
|
||||||
|
String gps2 = "2020-02-02T02:02:06Z";
|
||||||
|
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps2, 45.00001, 35.0, 1, 15);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(gps1Statistics, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
// when
|
||||||
|
String gps3 = "2020-02-02T02:02:08Z";
|
||||||
|
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps3, 45.00002, 35.0, 1, 15);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(gps1Statistics, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
|
||||||
|
// when
|
||||||
|
String stopTime = "2020-02-02T02:02:12Z";
|
||||||
|
trackPointCreator.setClock(stopTime);
|
||||||
|
service.endCurrentTrack();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(new TrackStatistics(startTime, stopTime, 2.222635507583618, 10, 5, 15, 0f, 0f)
|
||||||
|
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
new TrackPointAssert().assertEquals(List.of(
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps1))
|
||||||
|
.setLatitude(45)
|
||||||
|
.setLongitude(35)
|
||||||
|
.setHorizontalAccuracy(Distance.of(1))
|
||||||
|
.setSpeed(Speed.of(15))
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setAltitudeLoss(0f),
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps3))
|
||||||
|
.setLatitude(45.00002)
|
||||||
|
.setLongitude(35)
|
||||||
|
.setHorizontalAccuracy(Distance.of(1))
|
||||||
|
.setSpeed(Speed.of(15))
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setAltitudeLoss(0f),
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setAltitudeLoss(0f)
|
||||||
|
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
@Test
|
||||||
|
public void testRecording_gpsOnly_recordingDistance_idle() {
|
||||||
|
// given
|
||||||
|
String startTime = "2020-02-02T02:02:02Z";
|
||||||
|
TrackPointCreator trackPointCreator = service.getTrackPointCreator();
|
||||||
|
trackPointCreator.setClock(startTime);
|
||||||
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
||||||
|
|
||||||
|
// when
|
||||||
|
String gps1 = "2020-02-02T02:02:03Z";
|
||||||
|
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 0);
|
||||||
|
|
||||||
|
// then
|
||||||
|
TrackStatistics gps1Statistics = new TrackStatistics(startTime, gps1, 0, 1, 0, 0, 0f, 0f);
|
||||||
|
assertEquals(gps1Statistics, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
// when
|
||||||
|
String gps2 = "2020-02-02T02:02:06Z";
|
||||||
|
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps2, 45.0, 35.0, 1, 0);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(gps1Statistics, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
// when
|
||||||
|
String gps3 = "2020-02-02T02:02:08Z";
|
||||||
|
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps3, 45.0, 35.0, 1, 0);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(gps1Statistics, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
|
||||||
|
// when
|
||||||
|
String stopTime = "2020-02-02T02:02:12Z";
|
||||||
|
trackPointCreator.setClock(stopTime);
|
||||||
|
service.endCurrentTrack();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(new TrackStatistics(startTime, stopTime, 0, 10, 0, 0, 0f, 0f)
|
||||||
|
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
new TrackPointAssert().assertEquals(List.of(
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps1))
|
||||||
|
.setLatitude(45)
|
||||||
|
.setLongitude(35)
|
||||||
|
.setHorizontalAccuracy(Distance.of(1))
|
||||||
|
.setSpeed(Speed.of(0))
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setAltitudeLoss(0f),
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps3))
|
||||||
|
.setLatitude(45.00002)
|
||||||
|
.setLongitude(35)
|
||||||
|
.setHorizontalAccuracy(Distance.of(1))
|
||||||
|
.setSpeed(Speed.of(0))
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setAltitudeLoss(0f),
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setAltitudeLoss(0f)
|
||||||
|
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
@Test
|
||||||
|
public void testRecording_gpsOnly_recordingDistance_idle_movement() {
|
||||||
|
// given
|
||||||
|
String startTime = "2020-02-02T02:02:02Z";
|
||||||
|
TrackPointCreator trackPointCreator = service.getTrackPointCreator();
|
||||||
|
trackPointCreator.setClock(startTime);
|
||||||
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
||||||
|
|
||||||
|
// when
|
||||||
|
String gps1 = "2020-02-02T02:02:03Z";
|
||||||
|
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(new TrackStatistics(startTime, gps1, 0, 1, 0, 0, 0f, 0f)
|
||||||
|
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
// when
|
||||||
|
String gps2 = "2020-02-02T02:02:06Z";
|
||||||
|
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps2, 45.0, 35.0, 1, 0);
|
||||||
|
|
||||||
|
// then
|
||||||
|
final TrackStatistics gps2statistics = new TrackStatistics(startTime, gps2, 0, 4, 0, 0, 0f, 0f);
|
||||||
|
assertEquals(gps2statistics
|
||||||
|
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
// when
|
||||||
|
String gps3 = "2020-02-02T02:02:08Z";
|
||||||
|
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps3, 45.0, 35.0, 1, 0);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(gps2statistics, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
|
||||||
|
// when
|
||||||
|
String gps4 = "2020-02-02T02:02:10Z";
|
||||||
|
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps4, 45.0, 35.0, 1, 15);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(new TrackStatistics(startTime, gps4, 0, 8, 0, 0, 0f, 0f)
|
||||||
|
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
// when
|
||||||
|
String stopTime = "2020-02-02T02:02:12Z";
|
||||||
|
trackPointCreator.setClock(stopTime);
|
||||||
|
service.endCurrentTrack();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(new TrackStatistics(startTime, stopTime, 0, 10, 0, 0, 0f, 0f)
|
||||||
|
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
new TrackPointAssert().assertEquals(List.of(
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps1))
|
||||||
|
.setLatitude(45)
|
||||||
|
.setLongitude(35)
|
||||||
|
.setHorizontalAccuracy(Distance.of(1))
|
||||||
|
.setSpeed(Speed.of(15))
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setAltitudeLoss(0f),
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps2))
|
||||||
|
.setLatitude(45)
|
||||||
|
.setLongitude(35)
|
||||||
|
.setHorizontalAccuracy(Distance.of(1))
|
||||||
|
.setSpeed(Speed.of(0))
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setAltitudeLoss(0f),
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps3))
|
||||||
|
.setLatitude(45)
|
||||||
|
.setLongitude(35)
|
||||||
|
.setHorizontalAccuracy(Distance.of(1))
|
||||||
|
.setSpeed(Speed.of(0))
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setAltitudeLoss(0f),
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps4))
|
||||||
|
.setLatitude(45)
|
||||||
|
.setLongitude(35)
|
||||||
|
.setHorizontalAccuracy(Distance.of(1))
|
||||||
|
.setSpeed(Speed.of(15))
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setAltitudeLoss(0f),
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setAltitudeLoss(0f)
|
||||||
|
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
@Test
|
||||||
|
public void testRecording_gpsOnly_ignore_inaccurate() {
|
||||||
|
// given
|
||||||
|
String startTime = "2020-02-02T02:02:02Z";
|
||||||
|
TrackPointCreator trackPointCreator = service.getTrackPointCreator();
|
||||||
|
trackPointCreator.setClock(startTime);
|
||||||
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
||||||
|
|
||||||
|
// when
|
||||||
|
String gps1 = "2020-02-02T02:02:03Z";
|
||||||
|
TrackRecordingServiceTestUtils.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());
|
||||||
|
|
||||||
|
|
||||||
|
// when
|
||||||
|
String gps2 = "2020-02-02T02:02:06Z";
|
||||||
|
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps2, 45.1, 35.0, 100, 15);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(startStatistics, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
|
||||||
|
// when
|
||||||
|
String stopTime = "2020-02-02T02:02:12Z";
|
||||||
|
trackPointCreator.setClock(stopTime);
|
||||||
|
service.endCurrentTrack();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(new TrackStatistics(startTime, stopTime, 0, 10, 0, 0, 0f, 0f)
|
||||||
|
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
@Test
|
||||||
|
public void testRecording_gpsOnly_segment() {
|
||||||
|
// given
|
||||||
|
String startTime = "2020-02-02T02:02:02Z";
|
||||||
|
TrackPointCreator trackPointCreator = service.getTrackPointCreator();
|
||||||
|
trackPointCreator.setClock(startTime);
|
||||||
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
||||||
|
|
||||||
|
// when
|
||||||
|
String gps1 = "2020-02-02T02:02:03Z";
|
||||||
|
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(new TrackStatistics(startTime, gps1, 0, 1, 0, 0, 0f, 0f), contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
// when
|
||||||
|
String gps2 = "2020-02-02T02:02:06Z";
|
||||||
|
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps2, 45.1, 35.0, 1, 15);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(new TrackStatistics(startTime, gps2, 0, 1, 0, 0, 0f, 0f), contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
|
||||||
|
// when
|
||||||
|
String stopTime = "2020-02-02T02:02:12Z";
|
||||||
|
trackPointCreator.setClock(stopTime);
|
||||||
|
service.endCurrentTrack();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(new TrackStatistics(startTime, stopTime, 0, 7, 0, 0, 0f, 0f)
|
||||||
|
, contentProviderUtils.getTrack(trackId).getTrackStatistics());
|
||||||
|
|
||||||
|
|
||||||
|
// then
|
||||||
|
new TrackPointAssert().assertEquals(List.of(
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps1))
|
||||||
|
.setLatitude(45)
|
||||||
|
.setLongitude(35)
|
||||||
|
.setHorizontalAccuracy(Distance.of(1))
|
||||||
|
.setSpeed(Speed.of(15))
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setAltitudeLoss(0f),
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_START_AUTOMATIC, Instant.parse(gps2))
|
||||||
|
.setLatitude(45.1)
|
||||||
|
.setLongitude(35)
|
||||||
|
.setHorizontalAccuracy(Distance.of(1))
|
||||||
|
.setSpeed(Speed.of(15))
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setAltitudeLoss(0f),
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
|
||||||
|
.setAltitudeGain(0f)
|
||||||
|
.setAltitudeLoss(0f)
|
||||||
|
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure that GPS-based TrackPoints are stored, if the distance to the previous GPS-based TrackPoint is greater than recordingDistanceInterval.
|
||||||
|
*/
|
||||||
|
@MediumTest
|
||||||
|
@Test
|
||||||
|
public void testRecording_gpsAndSensor_gpsIdleMoving_sensorMoving() {
|
||||||
|
// TODO Check TrackStatistics
|
||||||
|
AltitudeSumManager altitudeSumManager = new AltitudeSumManager();
|
||||||
|
|
||||||
|
// given
|
||||||
|
String startTime = "2020-02-02T02:02:02Z";
|
||||||
|
TrackPointCreator trackPointCreator = service.getTrackPointCreator();
|
||||||
|
trackPointCreator.setClock(startTime);
|
||||||
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
trackPointCreator.setAltitudeSumManager(altitudeSumManager);
|
||||||
|
BluetoothRemoteSensorManager remoteSensorManager = trackPointCreator.getRemoteSensorManager();
|
||||||
|
|
||||||
|
// when
|
||||||
|
String sensor1 = "2020-02-02T02:02:03Z";
|
||||||
|
trackPointCreator.setClock(sensor1);
|
||||||
|
remoteSensorManager.onChanged(new SensorDataRunning("", "", Speed.of(5), null, Distance.of(0))); //Should be ignored
|
||||||
|
|
||||||
|
// when
|
||||||
|
String sensor2 = "2020-02-02T02:02:04Z";
|
||||||
|
trackPointCreator.setClock(sensor2);
|
||||||
|
remoteSensorManager.onChanged(new SensorDataRunning("", "", Speed.of(5), null, Distance.of(2)));
|
||||||
|
|
||||||
|
// when
|
||||||
|
String gps1 = "2020-02-02T02:02:05Z";
|
||||||
|
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps1, 45.0, 35.0, 1, 15);
|
||||||
|
|
||||||
|
// when
|
||||||
|
String sensor3 = "2020-02-02T02:02:06Z";
|
||||||
|
trackPointCreator.setClock(sensor3);
|
||||||
|
remoteSensorManager.onChanged(new SensorDataRunning("", "", Speed.of(5), null, Distance.of(12)));
|
||||||
|
|
||||||
|
// when
|
||||||
|
String sensor4 = "2020-02-02T02:02:07Z";
|
||||||
|
trackPointCreator.setClock(sensor4);
|
||||||
|
remoteSensorManager.onChanged(new SensorDataRunning("", "", Speed.of(5), null, Distance.of(14))); //Should be ignored
|
||||||
|
|
||||||
|
// when
|
||||||
|
String gps2 = "2020-02-02T02:02:08Z";
|
||||||
|
TrackRecordingServiceTestUtils.sendGPSLocation(trackPointCreator, gps2, 45.0, 35.0, 4, 15); //Should be ignored
|
||||||
|
|
||||||
|
// when
|
||||||
|
String sensor5 = "2020-02-02T02:02:10Z";
|
||||||
|
trackPointCreator.setClock(sensor5);
|
||||||
|
remoteSensorManager.onChanged(new SensorDataRunning("", "", Speed.of(5), null, Distance.of(16))); //Should be ignored
|
||||||
|
|
||||||
|
// when
|
||||||
|
String gps3 = "2020-02-02T02:02:12Z";
|
||||||
|
TrackRecordingServiceTestUtils.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);
|
||||||
|
|
||||||
|
|
||||||
|
// when
|
||||||
|
String stopTime = "2020-02-02T02:02:16Z";
|
||||||
|
trackPointCreator.setClock(stopTime);
|
||||||
|
service.endCurrentTrack();
|
||||||
|
|
||||||
|
// then
|
||||||
|
new TrackPointAssert().assertEquals(List.of(
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.parse(startTime)),
|
||||||
|
new TrackPoint(TrackPoint.Type.SENSORPOINT, Instant.parse(sensor2)) //First moving TrackPoint: store as the time might be interesting.
|
||||||
|
.setSpeed(Speed.of(5))
|
||||||
|
.setSensorDistance(Distance.of(2)),
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps1))
|
||||||
|
.setLatitude(45)
|
||||||
|
.setLongitude(35)
|
||||||
|
.setHorizontalAccuracy(Distance.of(1))
|
||||||
|
.setSpeed(Speed.of(5))
|
||||||
|
.setSensorDistance(Distance.of(0)),
|
||||||
|
new TrackPoint(TrackPoint.Type.SENSORPOINT, Instant.parse(sensor3))
|
||||||
|
.setSpeed(Speed.of(5))
|
||||||
|
.setSensorDistance(Distance.of(10)),
|
||||||
|
new TrackPoint(TrackPoint.Type.SENSORPOINT, Instant.parse(sensor5)) //TODO No need to store this TrackPoint, data could be merged into the next one
|
||||||
|
.setSpeed(Speed.of(5))
|
||||||
|
.setSensorDistance(Distance.of(4)),
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps3))
|
||||||
|
.setLatitude(45.001)
|
||||||
|
.setLongitude(35)
|
||||||
|
.setHorizontalAccuracy(Distance.of(1))
|
||||||
|
.setSpeed(Speed.of(5))
|
||||||
|
.setSensorDistance(Distance.of(0)),
|
||||||
|
new TrackPoint(TrackPoint.Type.TRACKPOINT, Instant.parse(gps4))
|
||||||
|
.setLatitude(45.001)
|
||||||
|
.setLongitude(35)
|
||||||
|
.setHorizontalAccuracy(Distance.of(1))
|
||||||
|
.setSpeed(Speed.of(5))
|
||||||
|
.setSensorDistance(Distance.of(0)),
|
||||||
|
new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.parse(stopTime))
|
||||||
|
.setSensorDistance(Distance.of(11))
|
||||||
|
.setSpeed(Speed.of(5))
|
||||||
|
.setSensorDistance(Distance.of(0))
|
||||||
|
), TestDataUtil.getTrackPoints(contentProviderUtils, trackId));
|
||||||
|
}
|
||||||
|
}
|
||||||
+282
@@ -0,0 +1,282 @@
|
|||||||
|
/*
|
||||||
|
* 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.services;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Looper;
|
||||||
|
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
import androidx.test.filters.MediumTest;
|
||||||
|
import androidx.test.rule.GrantPermissionRule;
|
||||||
|
import androidx.test.rule.ServiceTestRule;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||||
|
import de.dennisguse.opentracks.data.models.Track;
|
||||||
|
import de.dennisguse.opentracks.services.handlers.GpsStatusValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Testing the states of TrackRecordingService.
|
||||||
|
* As states are checked against MutableLiveData that are updated via `postValue()` (is asynchronous to be inform other Threads), Thread.sleep() is required.
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class TrackRecordingServiceTestStateMachine {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final ServiceTestRule mServiceRule = ServiceTestRule.withTimeout(5, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
|
||||||
|
|
||||||
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
private ContentProviderUtils contentProviderUtils;
|
||||||
|
|
||||||
|
private TrackRecordingService service;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void preSetUp() {
|
||||||
|
// Prepare looper for Android's message queue
|
||||||
|
if (Looper.myLooper() == null) Looper.prepare();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void finalTearDown() {
|
||||||
|
if (Looper.myLooper() != null) Looper.myLooper().quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private TrackRecordingService startService() throws TimeoutException {
|
||||||
|
Intent startIntent = new Intent(context, TrackRecordingService.class);
|
||||||
|
return ((TrackRecordingService.Binder) mServiceRule.bindService(startIntent))
|
||||||
|
.getService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws TimeoutException {
|
||||||
|
contentProviderUtils = new ContentProviderUtils(context);
|
||||||
|
service = startService();
|
||||||
|
tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws TimeoutException {
|
||||||
|
TrackRecordingServiceTestUtils.resetService(mServiceRule, context);
|
||||||
|
// Ensure that the database is empty after every test
|
||||||
|
contentProviderUtils.deleteAllTracks(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
@Test
|
||||||
|
public void initialState() {
|
||||||
|
// given
|
||||||
|
List<Track> tracks = contentProviderUtils.getTracks();
|
||||||
|
assertTrue(tracks.isEmpty());
|
||||||
|
|
||||||
|
// when
|
||||||
|
// noop
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertFalse(service.isRecording());
|
||||||
|
assertEquals(TrackRecordingService.STATUS_DEFAULT, service.getRecordingStatusObservable().getValue());
|
||||||
|
assertEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue());
|
||||||
|
assertEquals(GpsStatusValue.GPS_NONE, service.getGpsStatusObservable().getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
@Test
|
||||||
|
public void gps_startStop() throws InterruptedException {
|
||||||
|
// given
|
||||||
|
assertEquals(GpsStatusValue.GPS_NONE, service.getGpsStatusObservable().getValue());
|
||||||
|
|
||||||
|
// when
|
||||||
|
service.tryStartSensors();
|
||||||
|
Thread.sleep(1000);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(TrackRecordingService.STATUS_DEFAULT, service.getRecordingStatusObservable().getValue());
|
||||||
|
assertEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue());
|
||||||
|
assertEquals(GpsStatusValue.GPS_ENABLED, service.getGpsStatusObservable().getValue());
|
||||||
|
|
||||||
|
// when
|
||||||
|
service.stopSensorsAndShutdown();
|
||||||
|
Thread.sleep(1000);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(TrackRecordingService.STATUS_DEFAULT, service.getRecordingStatusObservable().getValue());
|
||||||
|
assertEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue());
|
||||||
|
// assertEquals(GpsStatusValue.GPS_NONE, service.getGpsStatusObservable().getValue()); TODO BUG: GPS can only be stopped if a service is recording.
|
||||||
|
}
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
@Test
|
||||||
|
public void recording_startPauseStopResume_no_data() throws InterruptedException {
|
||||||
|
// given
|
||||||
|
assertFalse(service.isRecording());
|
||||||
|
|
||||||
|
// when
|
||||||
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
Thread.sleep(1000);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertTrue(service.isRecording());
|
||||||
|
assertEquals(new RecordingStatus(trackId, false), service.getRecordingStatusObservable().getValue());
|
||||||
|
assertNotEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue());
|
||||||
|
assertEquals(GpsStatusValue.GPS_ENABLED, service.getGpsStatusObservable().getValue());
|
||||||
|
|
||||||
|
|
||||||
|
// when
|
||||||
|
service.pauseCurrentTrack();
|
||||||
|
Thread.sleep(1000);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertTrue(service.isRecording());
|
||||||
|
assertTrue(service.isPaused());
|
||||||
|
assertEquals(new RecordingStatus(trackId, true), service.getRecordingStatusObservable().getValue());
|
||||||
|
assertNotEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue());
|
||||||
|
assertEquals(GpsStatusValue.GPS_NONE, service.getGpsStatusObservable().getValue()); //TODO The GPS is kept in pause, right? Might be a bug.
|
||||||
|
|
||||||
|
|
||||||
|
// when
|
||||||
|
service.resumeCurrentTrack();
|
||||||
|
Thread.sleep(1000);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertTrue(service.isRecording());
|
||||||
|
assertFalse(service.isPaused());
|
||||||
|
assertEquals(new RecordingStatus(trackId, false), service.getRecordingStatusObservable().getValue());
|
||||||
|
assertNotEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue());
|
||||||
|
assertEquals(GpsStatusValue.GPS_ENABLED, service.getGpsStatusObservable().getValue());
|
||||||
|
|
||||||
|
|
||||||
|
// when
|
||||||
|
service.endCurrentTrack();
|
||||||
|
Thread.sleep(1000);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertFalse(service.isRecording());
|
||||||
|
assertFalse(service.isPaused());
|
||||||
|
assertEquals(TrackRecordingService.STATUS_DEFAULT, service.getRecordingStatusObservable().getValue());
|
||||||
|
assertEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue());
|
||||||
|
assertEquals(GpsStatusValue.GPS_NONE, service.getGpsStatusObservable().getValue());
|
||||||
|
|
||||||
|
|
||||||
|
// when
|
||||||
|
service.resumeTrack(trackId);
|
||||||
|
Thread.sleep(1000);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertTrue(service.isRecording());
|
||||||
|
assertFalse(service.isPaused());
|
||||||
|
assertEquals(new RecordingStatus(trackId, false), 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());
|
||||||
|
assertEquals(GpsStatusValue.GPS_ENABLED, service.getGpsStatusObservable().getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
@Test
|
||||||
|
public void invalidStateChanges() throws InterruptedException {
|
||||||
|
// given
|
||||||
|
assertFalse(service.isRecording());
|
||||||
|
|
||||||
|
// when
|
||||||
|
service.pauseCurrentTrack();
|
||||||
|
Thread.sleep(2000);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(TrackRecordingService.STATUS_DEFAULT, service.getRecordingStatusObservable().getValue());
|
||||||
|
assertEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue());
|
||||||
|
assertEquals(GpsStatusValue.GPS_NONE, service.getGpsStatusObservable().getValue());
|
||||||
|
|
||||||
|
|
||||||
|
// when
|
||||||
|
service.resumeCurrentTrack();
|
||||||
|
Thread.sleep(1000);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(TrackRecordingService.STATUS_DEFAULT, service.getRecordingStatusObservable().getValue());
|
||||||
|
assertEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue());
|
||||||
|
assertEquals(GpsStatusValue.GPS_NONE, service.getGpsStatusObservable().getValue());
|
||||||
|
|
||||||
|
|
||||||
|
// when
|
||||||
|
service.endCurrentTrack();
|
||||||
|
Thread.sleep(1000);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(TrackRecordingService.STATUS_DEFAULT, service.getRecordingStatusObservable().getValue());
|
||||||
|
assertEquals(TrackRecordingService.NOT_RECORDING, service.getRecordingDataObservable().getValue());
|
||||||
|
assertEquals(GpsStatusValue.GPS_NONE, service.getGpsStatusObservable().getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Ignore("TODO Bug: GPS can be stopped although the current track is recording")
|
||||||
|
@MediumTest
|
||||||
|
@Test
|
||||||
|
public void recording_stopGPS_noop() throws InterruptedException {
|
||||||
|
// given
|
||||||
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
assertEquals(GpsStatusValue.GPS_ENABLED, service.getGpsStatusObservable().getValue());
|
||||||
|
|
||||||
|
// when
|
||||||
|
service.stopSensors(); //TODO Should be ignored as service is recording
|
||||||
|
Thread.sleep(1000);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertTrue(service.isRecording());
|
||||||
|
assertFalse(service.isPaused());
|
||||||
|
assertEquals(new RecordingStatus(trackId, false), 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());
|
||||||
|
assertEquals(GpsStatusValue.GPS_ENABLED, service.getGpsStatusObservable().getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@MediumTest
|
||||||
|
@Test
|
||||||
|
public void recording_startRecording_alreadyRecording() throws InterruptedException {
|
||||||
|
// given
|
||||||
|
Track.Id trackId = service.startNewTrack();
|
||||||
|
assertTrue(service.isRecording());
|
||||||
|
|
||||||
|
// when
|
||||||
|
Track.Id newTrackId = service.startNewTrack();
|
||||||
|
Thread.sleep(1000);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertNotNull(trackId);
|
||||||
|
assertNull(newTrackId);
|
||||||
|
}
|
||||||
|
}
|
||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
package de.dennisguse.opentracks.services;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.location.Location;
|
||||||
|
|
||||||
|
import androidx.test.rule.ServiceTestRule;
|
||||||
|
|
||||||
|
import java.time.Clock;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.sensors.BluetoothRemoteSensorManager;
|
||||||
|
import de.dennisguse.opentracks.services.handlers.TrackPointCreator;
|
||||||
|
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||||
|
|
||||||
|
public class TrackRecordingServiceTestUtils {
|
||||||
|
|
||||||
|
|
||||||
|
//TODO Workaround as service is not stopped on API23; thus sharedpreferences are not reset between tests.
|
||||||
|
//TODO Anyhow, the service should re-create all it's resources if a recording starts and makes sure that there is no leftovers from previous recordings.
|
||||||
|
@Deprecated
|
||||||
|
public static void resetService(ServiceTestRule mServiceRule, Context context) throws TimeoutException {
|
||||||
|
// Let's use default values.
|
||||||
|
PreferencesUtils.clear();
|
||||||
|
|
||||||
|
// Reset service (if some previous test failed)
|
||||||
|
TrackRecordingService service = ((TrackRecordingService.Binder) mServiceRule.bindService(new Intent(context, TrackRecordingService.class)))
|
||||||
|
.getService();
|
||||||
|
|
||||||
|
service.getTrackPointCreator().setRemoteSensorManager(new BluetoothRemoteSensorManager(context, service.getTrackPointCreator()));
|
||||||
|
service.getTrackPointCreator().setClock(Clock.systemUTC());
|
||||||
|
service.endCurrentTrack();
|
||||||
|
}
|
||||||
|
|
||||||
|
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.getGpsHandler().onLocationChanged(location);
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
-8
@@ -1,4 +1,6 @@
|
|||||||
package de.dennisguse.opentracks.services.tasks;
|
package de.dennisguse.opentracks.services.announcement;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -19,12 +21,10 @@ import java.time.Duration;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
import de.dennisguse.opentracks.services.TrackRecordingService;
|
import de.dennisguse.opentracks.services.TrackRecordingService;
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class VoiceAnnouncementManagerTest {
|
public class VoiceAnnouncementManagerTest {
|
||||||
|
|
||||||
@@ -60,11 +60,11 @@ public class VoiceAnnouncementManagerTest {
|
|||||||
// when
|
// when
|
||||||
TrackStatistics statistics = new TrackStatistics();
|
TrackStatistics statistics = new TrackStatistics();
|
||||||
statistics.setTotalDistance(Distance.ofKilometer(13));
|
statistics.setTotalDistance(Distance.ofKilometer(13));
|
||||||
voiceAnnouncementManager.restore(statistics);
|
voiceAnnouncementManager.start(statistics);
|
||||||
assertEquals(Distance.of(15000), voiceAnnouncementManager.getNextTotalDistance());
|
assertEquals(Distance.of(15000), voiceAnnouncementManager.getNextTotalDistance());
|
||||||
|
|
||||||
statistics.setTotalDistance(Distance.of(15100));
|
statistics.setTotalDistance(Distance.of(15100));
|
||||||
voiceAnnouncementManager.restore(statistics);
|
voiceAnnouncementManager.start(statistics);
|
||||||
assertEquals(Distance.of(20000), voiceAnnouncementManager.getNextTotalDistance());
|
assertEquals(Distance.of(20000), voiceAnnouncementManager.getNextTotalDistance());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,11 +80,11 @@ public class VoiceAnnouncementManagerTest {
|
|||||||
// when
|
// when
|
||||||
TrackStatistics statistics = new TrackStatistics();
|
TrackStatistics statistics = new TrackStatistics();
|
||||||
statistics.setTotalTime(Duration.ofSeconds(91));
|
statistics.setTotalTime(Duration.ofSeconds(91));
|
||||||
voiceAnnouncementManager.restore(statistics);
|
voiceAnnouncementManager.start(statistics);
|
||||||
assertEquals(Duration.ofSeconds(95), voiceAnnouncementManager.getNextTotalTime());
|
assertEquals(Duration.ofSeconds(95), voiceAnnouncementManager.getNextTotalTime());
|
||||||
|
|
||||||
statistics.setTotalTime(Duration.ofSeconds(95));
|
statistics.setTotalTime(Duration.ofSeconds(95));
|
||||||
voiceAnnouncementManager.restore(statistics);
|
voiceAnnouncementManager.start(statistics);
|
||||||
assertEquals(Duration.ofSeconds(100), voiceAnnouncementManager.getNextTotalTime());
|
assertEquals(Duration.ofSeconds(100), voiceAnnouncementManager.getNextTotalTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
+65
-88
@@ -1,4 +1,6 @@
|
|||||||
package de.dennisguse.opentracks.util;
|
package de.dennisguse.opentracks.services.announcement;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
@@ -7,24 +9,31 @@ import androidx.test.core.app.ApplicationProvider;
|
|||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
import de.dennisguse.opentracks.LocaleRule;
|
||||||
import de.dennisguse.opentracks.content.data.Speed;
|
|
||||||
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.data.TrackPointIterator;
|
||||||
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
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.Track;
|
||||||
|
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||||
|
import de.dennisguse.opentracks.stats.SensorStatistics;
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
import de.dennisguse.opentracks.viewmodels.IntervalStatistics;
|
import de.dennisguse.opentracks.ui.intervals.IntervalStatistics;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class AnnouncementUtilsTest {
|
public class VoiceAnnouncementUtilsTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final LocaleRule mLocaleRule = new LocaleRule(Locale.ENGLISH);
|
||||||
|
|
||||||
private final Context context = ApplicationProvider.getApplicationContext();
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
private ContentProviderUtils contentProviderUtils;
|
private ContentProviderUtils contentProviderUtils;
|
||||||
@@ -32,6 +41,7 @@ public class AnnouncementUtilsTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
contentProviderUtils = new ContentProviderUtils(context);
|
contentProviderUtils = new ContentProviderUtils(context);
|
||||||
|
PreferencesUtils.setVoiceAnnounceHeartRate(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -44,10 +54,10 @@ public class AnnouncementUtilsTest {
|
|||||||
stats.setTotalAltitudeGain(6000f);
|
stats.setTotalAltitudeGain(6000f);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
String announcement = AnnouncementUtils.getAnnouncement(context, stats, true, true, null);
|
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, true, true, null, null).toString();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals("total distance 20.00 kilometers in 1 hour 5 minutes 10 seconds at 18.4 kilometers per hour", announcement);
|
assertEquals("Total distance 20.00 kilometers. 1 hour 5 minutes 10 seconds. Speed 18.4 kilometers per hour.", announcement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -60,23 +70,16 @@ public class AnnouncementUtilsTest {
|
|||||||
IntervalStatistics.Interval lastInterval;
|
IntervalStatistics.Interval lastInterval;
|
||||||
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
|
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
|
||||||
assertEquals(trackPointIterator.getCount(), numberOfPoints);
|
assertEquals(trackPointIterator.getCount(), numberOfPoints);
|
||||||
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000), Distance.of(0));
|
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000));
|
||||||
|
intervalStatistics.addTrackPoints(trackPointIterator);
|
||||||
lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
|
lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
String announcement = AnnouncementUtils.getAnnouncement(context, stats, true, true, lastInterval);
|
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, true, true, lastInterval, null).toString();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(
|
assertEquals("Total distance 14.21 kilometers. 16 minutes 39 seconds. Speed 51.2 kilometers per hour. Lap speed 51.2 kilometers per hour.", announcement);
|
||||||
"total distance " +
|
|
||||||
StringUtils.getDistanceParts(context, stats.getTotalDistance(), true).first +
|
|
||||||
" kilometers in " + buildAndGetTimeText(stats.getTotalTime(), false) + " at " +
|
|
||||||
StringUtils.getSpeedParts(context, stats.getAverageMovingSpeed(), true, true).first +
|
|
||||||
" kilometers per hour Lap speed of " +
|
|
||||||
StringUtils.getSpeedParts(context, lastInterval.getSpeed(), true, true).first +
|
|
||||||
" kilometers per hour",
|
|
||||||
announcement);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -89,10 +92,10 @@ public class AnnouncementUtilsTest {
|
|||||||
stats.setTotalAltitudeGain(6000f);
|
stats.setTotalAltitudeGain(6000f);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
String announcement = AnnouncementUtils.getAnnouncement(context, stats, true, false, null);
|
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, true, false, null, null).toString();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals("total distance 20.00 kilometers in 1 hour 5 minutes 10 seconds at 3 minutes 15 seconds per kilometer", announcement);
|
assertEquals("Total distance 20.00 kilometers. 1 hour 5 minutes 10 seconds. Pace 3 minutes 15 seconds per kilometer.", announcement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -105,23 +108,16 @@ public class AnnouncementUtilsTest {
|
|||||||
IntervalStatistics.Interval lastInterval;
|
IntervalStatistics.Interval lastInterval;
|
||||||
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
|
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
|
||||||
assertEquals(trackPointIterator.getCount(), numberOfPoints);
|
assertEquals(trackPointIterator.getCount(), numberOfPoints);
|
||||||
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000), Distance.of(0));
|
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000));
|
||||||
|
intervalStatistics.addTrackPoints(trackPointIterator);
|
||||||
lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
|
lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
String announcement = AnnouncementUtils.getAnnouncement(context, stats, true, false, lastInterval);
|
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, true, false, lastInterval, null).toString();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(
|
assertEquals("Total distance 14.21 kilometers. 16 minutes 39 seconds. Pace 1 minute 10 seconds per kilometer. Lap time 1 minute 10 seconds per kilometer.", announcement);
|
||||||
"total distance " +
|
|
||||||
StringUtils.getDistanceParts(context, stats.getTotalDistance(), true).first +
|
|
||||||
" kilometers in " + buildAndGetTimeText(stats.getTotalTime(), false) + " at " +
|
|
||||||
buildAndGetTimeText(stats.getAverageMovingSpeed().toPace(true), true) +
|
|
||||||
" per kilometer Lap time of " +
|
|
||||||
buildAndGetTimeText(lastInterval.getSpeed().toPace(true), true) +
|
|
||||||
" per kilometer",
|
|
||||||
announcement);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -134,10 +130,10 @@ public class AnnouncementUtilsTest {
|
|||||||
stats.setTotalAltitudeGain(6000f);
|
stats.setTotalAltitudeGain(6000f);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
String announcement = AnnouncementUtils.getAnnouncement(context, stats, false, true, null);
|
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, false, true, null, null).toString();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals("total distance 12.43 miles in 1 hour 5 minutes 10 seconds at 11.4 miles per hour", announcement);
|
assertEquals("Total distance 12.43 miles. 1 hour 5 minutes 10 seconds. Speed 11.4 miles per hour.", announcement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -150,23 +146,16 @@ public class AnnouncementUtilsTest {
|
|||||||
IntervalStatistics.Interval lastInterval;
|
IntervalStatistics.Interval lastInterval;
|
||||||
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
|
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
|
||||||
assertEquals(trackPointIterator.getCount(), numberOfPoints);
|
assertEquals(trackPointIterator.getCount(), numberOfPoints);
|
||||||
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000), Distance.of(0));
|
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000));
|
||||||
|
intervalStatistics.addTrackPoints(trackPointIterator);
|
||||||
lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
|
lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
String announcement = AnnouncementUtils.getAnnouncement(context, stats, false, true, lastInterval);
|
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, false, true, lastInterval, null).toString();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(
|
assertEquals("Total distance 8.83 miles. 16 minutes 39 seconds. Speed 31.8 miles per hour. Lap speed 31.8 miles per hour.", announcement);
|
||||||
"total distance " +
|
|
||||||
StringUtils.getDistanceParts(context, stats.getTotalDistance(), false).first +
|
|
||||||
" miles in " + buildAndGetTimeText(stats.getTotalTime(), false) + " at " +
|
|
||||||
StringUtils.getSpeedParts(context, stats.getAverageMovingSpeed(), false, true).first +
|
|
||||||
" miles per hour Lap speed of " +
|
|
||||||
StringUtils.getSpeedParts(context, lastInterval.getSpeed(), false, true).first +
|
|
||||||
" miles per hour",
|
|
||||||
announcement);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -179,10 +168,10 @@ public class AnnouncementUtilsTest {
|
|||||||
stats.setTotalAltitudeGain(6000f);
|
stats.setTotalAltitudeGain(6000f);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
String announcement = AnnouncementUtils.getAnnouncement(context, stats, false, false, null);
|
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, false, false, null, null).toString();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals("total distance 12.43 miles in 1 hour 5 minutes 10 seconds at 5 minutes 15 seconds per mile", announcement);
|
assertEquals("Total distance 12.43 miles. 1 hour 5 minutes 10 seconds. Pace 5 minutes 15 seconds per mile.", announcement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -195,52 +184,40 @@ public class AnnouncementUtilsTest {
|
|||||||
IntervalStatistics.Interval lastInterval;
|
IntervalStatistics.Interval lastInterval;
|
||||||
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
|
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
|
||||||
assertEquals(trackPointIterator.getCount(), numberOfPoints);
|
assertEquals(trackPointIterator.getCount(), numberOfPoints);
|
||||||
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000), Distance.of(0));
|
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(1000));
|
||||||
|
intervalStatistics.addTrackPoints(trackPointIterator);
|
||||||
lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
|
lastInterval = intervalStatistics.getIntervalList().get(intervalStatistics.getIntervalList().size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// when
|
// when
|
||||||
String announcement = AnnouncementUtils.getAnnouncement(context, stats, false, false, lastInterval);
|
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, false, false, lastInterval, null).toString();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
//assertEquals("total distance 12.43 miles in 1 hour 5 minutes 10 seconds at 5 minutes 15 seconds per mile Lap time of 1 minute 53 seconds per mile", announcement);
|
assertEquals("Total distance 8.83 miles. 16 minutes 39 seconds. Pace 1 minute 53 seconds per mile. Lap time 1 minute 53 seconds per mile.", announcement);
|
||||||
assertEquals(
|
|
||||||
"total distance " +
|
|
||||||
StringUtils.getDistanceParts(context, stats.getTotalDistance(), false).first +
|
|
||||||
" miles in " + buildAndGetTimeText(stats.getTotalTime(), false) + " at " +
|
|
||||||
buildAndGetTimeText(stats.getAverageMovingSpeed().toPace(false), true) +
|
|
||||||
" per mile Lap time of " +
|
|
||||||
buildAndGetTimeText(lastInterval.getSpeed().toPace(false), true) +
|
|
||||||
" per mile",
|
|
||||||
announcement);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Test
|
||||||
* Builds an returns the text representing the duration's time.
|
public void getAnnouncement_heart_rate_and_sensor_statistics() {
|
||||||
*
|
PreferencesUtils.setVoiceAnnounceHeartRate(true);
|
||||||
* @param duration Duration object.
|
|
||||||
* @param showFromMinutes show minutes tough it's 0.
|
|
||||||
* @return text representing the duratin's time.
|
|
||||||
*/
|
|
||||||
private String buildAndGetTimeText(Duration duration, boolean showFromMinutes) {
|
|
||||||
long hours = Math.abs(duration.getSeconds()) / 3600;
|
|
||||||
long minutes = (Math.abs(duration.getSeconds()) % 3600) / 60;
|
|
||||||
long seconds = Math.abs(duration.getSeconds()) % 60;
|
|
||||||
String hUnit = hours > 1 || hours == 0 ? "hours" : "hour";
|
|
||||||
String mUnit = minutes > 1 || minutes == 0 ? "minutes" : "minute";
|
|
||||||
String sUnit = seconds > 1 || seconds == 0 ? "seconds" : "second";
|
|
||||||
|
|
||||||
String res = hours > 0 ? hours + " " + hUnit : "";
|
int numberOfPoints = 1000;
|
||||||
if (hours > 0) {
|
Pair<Track.Id, TrackStatistics> trackWithStats = TestDataUtil.buildTrackWithTrackPoints(contentProviderUtils, numberOfPoints);
|
||||||
res += minutes > 0 || showFromMinutes ? " " + minutes + " " + mUnit : "";
|
Track.Id trackId = trackWithStats.first;
|
||||||
} else {
|
TrackStatistics stats = trackWithStats.second;
|
||||||
res += minutes > 0 || showFromMinutes ? minutes + " " + mUnit : "";
|
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);
|
||||||
}
|
}
|
||||||
if (hours > 0 || minutes > 0 || showFromMinutes) {
|
|
||||||
res += " " + seconds + " " + sUnit;
|
SensorStatistics sensorStatistics = new SensorStatistics(HeartRate.of(180f), HeartRate.of(180f), null, null, null);
|
||||||
} else {
|
|
||||||
res += seconds + " " + sUnit;
|
// when
|
||||||
}
|
String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, true, true, lastInterval, sensorStatistics).toString();
|
||||||
return res;
|
|
||||||
|
// then
|
||||||
|
assertEquals("Total distance 14.21 kilometers. 16 minutes 39 seconds. Speed 51.2 kilometers per hour. Lap speed 51.2 kilometers per hour. Average heart rate 180 bpm. Current heart rate 133 bpm.", announcement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+12
-17
@@ -5,7 +5,6 @@ import static org.mockito.Mockito.times;
|
|||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
|
||||||
@@ -22,21 +21,20 @@ import org.mockito.junit.MockitoJUnitRunner;
|
|||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class LocationHandlerTest {
|
public class GPSHandlerTest {
|
||||||
|
|
||||||
private final Context context = ApplicationProvider.getApplicationContext();
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
private final SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private TrackPointCreator trackPointCreator;
|
private TrackPointCreator trackPointCreator;
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private LocationHandler locationHandler;
|
private GPSHandler locationHandler;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void preSetUp() {
|
public static void preSetUp() {
|
||||||
@@ -47,15 +45,12 @@ public class LocationHandlerTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
// Let's use default values.
|
// Let's use default values.
|
||||||
sharedPreferences.edit().clear().commit();
|
PreferencesUtils.clear();
|
||||||
|
|
||||||
Mockito.when(trackPointCreator.createNow())
|
Mockito.when(trackPointCreator.createNow())
|
||||||
.thenReturn(Instant.now());
|
.thenReturn(Instant.now());
|
||||||
|
|
||||||
//TODO REMOVE
|
locationHandler.onStart(context);
|
||||||
// locationHandler.onSharedPreferenceChanged(context, sharedPreferences, context.getString(R.string.recording_gps_accuracy_key));
|
|
||||||
// locationHandler.onSharedPreferenceChanged(context, sharedPreferences, context.getString(R.string.min_recording_interval_key));
|
|
||||||
locationHandler.onStart(context, sharedPreferences);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -67,7 +62,7 @@ public class LocationHandlerTest {
|
|||||||
locationHandler.onLocationChanged(createLocation(45f, 35f, 3, 5, System.currentTimeMillis()));
|
locationHandler.onLocationChanged(createLocation(45f, 35f, 3, 5, System.currentTimeMillis()));
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(trackPointCreator, times(1)).onNewTrackPoint(any(TrackPoint.class), any(Distance.class));
|
verify(trackPointCreator, times(1)).onNewTrackPoint(any(TrackPoint.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -83,7 +78,7 @@ public class LocationHandlerTest {
|
|||||||
locationHandler.onLocationChanged(createLocation(latitude, 35f, 3, 5, System.currentTimeMillis()));
|
locationHandler.onLocationChanged(createLocation(latitude, 35f, 3, 5, System.currentTimeMillis()));
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(trackPointCreator, times(0)).onNewTrackPoint(any(TrackPoint.class), any(Distance.class));
|
verify(trackPointCreator, times(0)).onNewTrackPoint(any(TrackPoint.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -92,14 +87,14 @@ public class LocationHandlerTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testOnLocationChanged_poorAccuracy() {
|
public void testOnLocationChanged_poorAccuracy() {
|
||||||
// given
|
// given
|
||||||
Distance prefAccuracy = PreferencesUtils.getThresholdHorizontalAccuracy(sharedPreferences, context);
|
Distance prefAccuracy = PreferencesUtils.getThresholdHorizontalAccuracy();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
locationHandler.onLocationChanged(createLocation(45f, 35f, (float) (prefAccuracy.toM() + 1), 5, System.currentTimeMillis()));
|
locationHandler.onLocationChanged(createLocation(45f, 35f, (float) (prefAccuracy.toM() + 1), 5, System.currentTimeMillis()));
|
||||||
|
|
||||||
// then
|
// then
|
||||||
// no newTrackPoint called
|
// no newTrackPoint called
|
||||||
verify(trackPointCreator, times(0)).onNewTrackPoint(any(TrackPoint.class), any(Distance.class));
|
verify(trackPointCreator, times(0)).onNewTrackPoint(any(TrackPoint.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -112,7 +107,7 @@ public class LocationHandlerTest {
|
|||||||
locationHandler.onLocationChanged(createLocation(99.0, 35.0, Long.MAX_VALUE, 15, System.currentTimeMillis()));
|
locationHandler.onLocationChanged(createLocation(99.0, 35.0, Long.MAX_VALUE, 15, System.currentTimeMillis()));
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(trackPointCreator, times(1)).onNewTrackPoint(any(TrackPoint.class), any(Distance.class));
|
verify(trackPointCreator, times(1)).onNewTrackPoint(any(TrackPoint.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
+4
-8
@@ -3,7 +3,6 @@ package de.dennisguse.opentracks.services.handlers;
|
|||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -13,8 +12,8 @@ import org.junit.runner.RunWith;
|
|||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class TrackPointCreatorTest {
|
public class TrackPointCreatorTest {
|
||||||
@@ -26,10 +25,7 @@ public class TrackPointCreatorTest {
|
|||||||
private TrackPointCreator.Callback server;
|
private TrackPointCreator.Callback server;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private LocationHandler locationHandler;
|
private GPSHandler locationHandler;
|
||||||
|
|
||||||
@Mock
|
|
||||||
private SharedPreferences sharedPreferences;
|
|
||||||
|
|
||||||
private TrackPointCreator subject;
|
private TrackPointCreator subject;
|
||||||
|
|
||||||
@@ -52,7 +48,7 @@ public class TrackPointCreatorTest {
|
|||||||
Distance horizontalAccuracyThreshold = Distance.of(50);
|
Distance horizontalAccuracyThreshold = Distance.of(50);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
subject.onNewTrackPoint(trackPoint, horizontalAccuracyThreshold);
|
subject.onNewTrackPoint(trackPoint);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
Thread.sleep(10); // Wait for executor service
|
Thread.sleep(10); // Wait for executor service
|
||||||
|
|||||||
+118
@@ -0,0 +1,118 @@
|
|||||||
|
package de.dennisguse.opentracks.settings;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.ui.customRecordingLayout.Layout;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class PreferencesOpenHelperTest {
|
||||||
|
|
||||||
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
private final Resources resources = ApplicationProvider.getApplicationContext().getResources();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_upgradeFrom0To1_withoutStatsCustomLayouts() {
|
||||||
|
// given the version 0
|
||||||
|
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
editor.remove(context.getString(R.string.stats_custom_layouts_key));
|
||||||
|
editor.putInt(context.getString(R.string.prefs_last_version_key), 0);
|
||||||
|
editor.commit();
|
||||||
|
|
||||||
|
// when update to version 1
|
||||||
|
PreferencesOpenHelper.newInstance(1).check();
|
||||||
|
|
||||||
|
// then there should be one layout with old custom layout that has the new CSV value.
|
||||||
|
List<Layout> layouts = PreferencesUtils.getAllCustomLayouts();
|
||||||
|
assertNotNull(layouts);
|
||||||
|
assertEquals(layouts.size(), 1);
|
||||||
|
assertEquals(layouts.get(0).toCsv(), PreferencesUtils.getCustomLayout().toCsv());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_upgradeFrom1To2_withOldVersion() {
|
||||||
|
// given the version 1
|
||||||
|
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
|
||||||
|
String oldCustomLayoutCsv = context.getString(R.string.activity_type_unknown) + ";distance,1,1,0;speed,1,1,0;";
|
||||||
|
editor.putString(context.getString(R.string.stats_custom_layouts_key), oldCustomLayoutCsv);
|
||||||
|
editor.putInt(context.getString(R.string.prefs_last_version_key), 1);
|
||||||
|
|
||||||
|
editor.commit();
|
||||||
|
|
||||||
|
// when update to version 2
|
||||||
|
PreferencesOpenHelper.newInstance(2).check();
|
||||||
|
|
||||||
|
String updatedOldCustomLayoutCsv = context.getString(R.string.activity_type_unknown) + ";"
|
||||||
|
+ PreferencesUtils.getLayoutColumnsByDefault() + ";distance,1,1,0;speed,1,1,0;";
|
||||||
|
|
||||||
|
// then there should be one layout with old custom layout that has the new CSV value.
|
||||||
|
List<Layout> layouts = PreferencesUtils.getAllCustomLayouts();
|
||||||
|
assertNotNull(layouts);
|
||||||
|
assertEquals(layouts.size(), 1);
|
||||||
|
assertEquals(layouts.get(0).toCsv(), updatedOldCustomLayoutCsv);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_upgradeFrom1To2_withNewVersion() {
|
||||||
|
// given the version 1
|
||||||
|
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
|
||||||
|
String oldCustomLayoutCsv = "whatever;3;distance,1,1,0;speed,1,1,0;";
|
||||||
|
editor.putString(context.getString(R.string.stats_custom_layouts_key), oldCustomLayoutCsv);
|
||||||
|
editor.putInt(context.getString(R.string.prefs_last_version_key), 1);
|
||||||
|
|
||||||
|
editor.commit();
|
||||||
|
|
||||||
|
// when update to version 2
|
||||||
|
PreferencesOpenHelper.newInstance(2).check();
|
||||||
|
|
||||||
|
String updatedOldCustomLayoutCsv = "whatever;3;distance,1,1,0;speed,1,1,0;";
|
||||||
|
|
||||||
|
// then there should be one layout with old custom layout that has the new CSV value.
|
||||||
|
List<Layout> layouts = PreferencesUtils.getAllCustomLayouts();
|
||||||
|
assertNotNull(layouts);
|
||||||
|
assertEquals(layouts.size(), 1);
|
||||||
|
assertEquals(layouts.get(0).toCsv(), updatedOldCustomLayoutCsv);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_downgrade() {
|
||||||
|
// given version 2
|
||||||
|
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
|
||||||
|
String customLayoutCsv = "whatever;3;distance,1,1,0;speed,1,1,0;";
|
||||||
|
editor.putString(context.getString(R.string.stats_custom_layouts_key), customLayoutCsv);
|
||||||
|
editor.putInt(context.getString(R.string.prefs_last_version_key), 2);
|
||||||
|
|
||||||
|
editor.commit();
|
||||||
|
|
||||||
|
// when downgrade to version 1
|
||||||
|
PreferencesOpenHelper.newInstance(1).check();
|
||||||
|
|
||||||
|
// then custom layout should be equals to default layout.
|
||||||
|
Layout defaultLayout = Layout.fromCsv(PreferencesUtils.buildDefaultLayout(), resources);
|
||||||
|
List<Layout> customLayout = PreferencesUtils.getAllCustomLayouts();
|
||||||
|
|
||||||
|
assertEquals(customLayout.size(), 1);
|
||||||
|
assertEquals(defaultLayout.toCsv(), customLayout.get(0).toCsv());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,345 @@
|
|||||||
|
package de.dennisguse.opentracks.settings;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||||
|
import de.dennisguse.opentracks.ui.customRecordingLayout.DataField;
|
||||||
|
import de.dennisguse.opentracks.ui.customRecordingLayout.Layout;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class PreferencesUtilsTest {
|
||||||
|
|
||||||
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
private final Resources resources = ApplicationProvider.getApplicationContext().getResources();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void ExportTrackFileFormat_ok() {
|
||||||
|
// given
|
||||||
|
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
|
||||||
|
editor.putString(context.getString(R.string.export_trackfileformat_key), TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA.name());
|
||||||
|
editor.commit();
|
||||||
|
|
||||||
|
// when
|
||||||
|
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA, trackFileFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void ExportTrackFileFormat_invalid() {
|
||||||
|
// given
|
||||||
|
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
editor.putString(context.getString(R.string.export_trackfileformat_key), "invalid");
|
||||||
|
editor.commit();
|
||||||
|
|
||||||
|
// when
|
||||||
|
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, trackFileFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void ExportTrackFileFormat_noValue() {
|
||||||
|
// given
|
||||||
|
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
editor.clear();
|
||||||
|
editor.commit();
|
||||||
|
|
||||||
|
// when
|
||||||
|
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, trackFileFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetAllCustomLayouts_default() {
|
||||||
|
// given
|
||||||
|
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
editor.clear();
|
||||||
|
editor.commit();
|
||||||
|
|
||||||
|
// when
|
||||||
|
List<Layout> layouts = PreferencesUtils.getAllCustomLayouts();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(layouts.size(), 1);
|
||||||
|
assertTrue(layouts.get(0).getFields().size() > 0);
|
||||||
|
assertEquals(layouts.get(0).getName(), context.getString(R.string.stats_custom_layout_default_layout));
|
||||||
|
assertTrue(layouts.get(0).getFields().stream().anyMatch(DataField::isVisible));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetCustomLayout_default() {
|
||||||
|
// given
|
||||||
|
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
editor.clear();
|
||||||
|
editor.commit();
|
||||||
|
|
||||||
|
// when
|
||||||
|
Layout layout = PreferencesUtils.getCustomLayout();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertTrue(layout.getFields().size() > 0);
|
||||||
|
assertEquals(layout.getName(), context.getString(R.string.stats_custom_layout_default_layout));
|
||||||
|
assertTrue(layout.getFields().stream().anyMatch(DataField::isVisible));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetCustomLayout_1() {
|
||||||
|
// given
|
||||||
|
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
editor.putString(
|
||||||
|
context.getString(R.string.stats_custom_layouts_key),
|
||||||
|
"run;2;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_moving_time_key) + ",1,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_distance_key) + ",1,0;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_average_moving_speed_key) + ",0,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_speed_key) + ",0,0;");
|
||||||
|
editor.apply();
|
||||||
|
|
||||||
|
// when
|
||||||
|
Layout layout = PreferencesUtils.getCustomLayout();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(layout.getFields().size(), 4);
|
||||||
|
assertEquals(layout.getName(), "run");
|
||||||
|
assertEquals(layout.getColumnsPerRow(), 2);
|
||||||
|
|
||||||
|
assertEquals(layout.getFields().get(0).getKey(), context.getString(R.string.stats_custom_layout_moving_time_key));
|
||||||
|
assertTrue(layout.getFields().get(0).isVisible());
|
||||||
|
assertTrue(layout.getFields().get(0).isPrimary());
|
||||||
|
|
||||||
|
assertEquals(layout.getFields().get(1).getKey(), context.getString(R.string.stats_custom_layout_distance_key));
|
||||||
|
assertTrue(layout.getFields().get(1).isVisible());
|
||||||
|
assertFalse(layout.getFields().get(1).isPrimary());
|
||||||
|
|
||||||
|
assertEquals(layout.getFields().get(2).getKey(), context.getString(R.string.stats_custom_layout_average_moving_speed_key));
|
||||||
|
assertFalse(layout.getFields().get(2).isVisible());
|
||||||
|
assertTrue(layout.getFields().get(2).isPrimary());
|
||||||
|
|
||||||
|
assertEquals(layout.getFields().get(3).getKey(), context.getString(R.string.stats_custom_layout_speed_key));
|
||||||
|
assertFalse(layout.getFields().get(3).isVisible());
|
||||||
|
assertFalse(layout.getFields().get(3).isPrimary());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetCustomLayout_coordinatesIsWide() {
|
||||||
|
// given
|
||||||
|
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
editor.putString(
|
||||||
|
context.getString(R.string.stats_custom_layouts_key),
|
||||||
|
"walking;2;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_moving_time_key) + ",1,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_distance_key) + ",1,0;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_coordinates_key) + ",0,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_speed_key) + ",0,0;");
|
||||||
|
editor.apply();
|
||||||
|
|
||||||
|
// when
|
||||||
|
Layout layout = PreferencesUtils.getCustomLayout();
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(layout.getFields().size(), 4);
|
||||||
|
assertEquals(layout.getName(), "walking");
|
||||||
|
assertEquals(layout.getColumnsPerRow(), 2);
|
||||||
|
|
||||||
|
assertEquals(layout.getFields().get(0).getKey(), context.getString(R.string.stats_custom_layout_moving_time_key));
|
||||||
|
assertTrue(layout.getFields().get(0).isVisible());
|
||||||
|
assertTrue(layout.getFields().get(0).isPrimary());
|
||||||
|
|
||||||
|
assertEquals(layout.getFields().get(1).getKey(), context.getString(R.string.stats_custom_layout_distance_key));
|
||||||
|
assertTrue(layout.getFields().get(1).isVisible());
|
||||||
|
assertFalse(layout.getFields().get(1).isPrimary());
|
||||||
|
|
||||||
|
assertEquals(layout.getFields().get(2).getKey(), context.getString(R.string.stats_custom_layout_coordinates_key));
|
||||||
|
assertFalse(layout.getFields().get(2).isVisible());
|
||||||
|
assertTrue(layout.getFields().get(2).isPrimary());
|
||||||
|
assertTrue(layout.getFields().get(2).isWide());
|
||||||
|
|
||||||
|
assertEquals(layout.getFields().get(3).getKey(), context.getString(R.string.stats_custom_layout_speed_key));
|
||||||
|
assertFalse(layout.getFields().get(3).isVisible());
|
||||||
|
assertFalse(layout.getFields().get(3).isPrimary());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetCustomLayout() {
|
||||||
|
// given
|
||||||
|
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
Layout layoutSrc = new Layout("road cycling");
|
||||||
|
layoutSrc.addField(new DataField(context.getString(R.string.stats_custom_layout_moving_time_key), context.getString(R.string.stats_moving_time), true, true, false));
|
||||||
|
layoutSrc.addField(new DataField(context.getString(R.string.stats_custom_layout_distance_key), context.getString(R.string.stats_distance), true, false, false));
|
||||||
|
layoutSrc.addField(new DataField(context.getString(R.string.stats_custom_layout_average_moving_speed_key), context.getString(R.string.stats_average_moving_speed), false, true, false));
|
||||||
|
layoutSrc.addField(new DataField(context.getString(R.string.stats_custom_layout_speed_key), context.getString(R.string.stats_speed), false, false, false));
|
||||||
|
|
||||||
|
// when
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
editor.putString(context.getString(R.string.stats_custom_layouts_key), layoutSrc.toCsv());
|
||||||
|
editor.commit();
|
||||||
|
|
||||||
|
// then
|
||||||
|
String csv = sharedPreferences.getString(context.getString(R.string.stats_custom_layouts_key), null);
|
||||||
|
assertNotNull(csv);
|
||||||
|
assertEquals(csv,
|
||||||
|
"road cycling;" + PreferencesUtils.getLayoutColumnsByDefault() + ";"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_moving_time_key) + ",1,1,0;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_distance_key) + ",1,0,0;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_average_moving_speed_key) + ",0,1,0;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_speed_key) + ",0,0,0;");
|
||||||
|
|
||||||
|
Layout layoutDst = PreferencesUtils.getCustomLayout();
|
||||||
|
assertEquals(layoutSrc.getName(), layoutDst.getName());
|
||||||
|
assertEquals(layoutSrc.getFields().size(), layoutDst.getFields().size());
|
||||||
|
for (int i = 0; i < layoutSrc.getFields().size(); i++) {
|
||||||
|
assertEquals(layoutSrc.getFields().get(i).getKey(), layoutDst.getFields().get(i).getKey());
|
||||||
|
assertEquals(layoutSrc.getFields().get(i).isVisible(), layoutDst.getFields().get(i).isVisible());
|
||||||
|
assertEquals(layoutSrc.getFields().get(i).isPrimary(), layoutDst.getFields().get(i).isPrimary());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEditCustomLayouts() {
|
||||||
|
// update all custom layouts
|
||||||
|
|
||||||
|
// given a custom layout with two profiles
|
||||||
|
String cyclingProfile = "cycling;2;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_moving_time_key) + ",1,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_distance_key) + ",1,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_average_moving_speed_key) + ",1,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_speed_key) + ",1,1;";
|
||||||
|
|
||||||
|
String runningProfile = "running;2;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_moving_time_key) + ",1,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_distance_key) + ",1,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_average_pace_key) + ",0,0;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_pace_key) + ",0,0;";
|
||||||
|
|
||||||
|
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
editor.putString(context.getString(R.string.stats_custom_layouts_key), cyclingProfile + "\n" + runningProfile);
|
||||||
|
editor.apply();
|
||||||
|
|
||||||
|
List<Layout> layoutsBefore = PreferencesUtils.getAllCustomLayouts();
|
||||||
|
|
||||||
|
// when cyling profile is updated
|
||||||
|
String cyclingProfileUpdated = "cycling;2;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_moving_time_key) + ",1,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_distance_key) + ",0,0;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_average_moving_speed_key) + ",0,0;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_speed_key) + ",0,0;";
|
||||||
|
|
||||||
|
List<Layout> layoutsToBeUpdated = new ArrayList<>();
|
||||||
|
layoutsToBeUpdated.add(Layout.fromCsv(cyclingProfileUpdated, resources));
|
||||||
|
layoutsToBeUpdated.add(Layout.fromCsv(runningProfile, resources));
|
||||||
|
|
||||||
|
PreferencesUtils.updateCustomLayouts(layoutsToBeUpdated);
|
||||||
|
|
||||||
|
// then only updated profile is modified in the custom layouts
|
||||||
|
List<Layout> layoutsAfter = PreferencesUtils.getAllCustomLayouts();
|
||||||
|
|
||||||
|
assertEquals(layoutsBefore.size(), 2);
|
||||||
|
assertEquals(layoutsAfter.size(), 2);
|
||||||
|
|
||||||
|
assertEquals(layoutsBefore.get(0).getFields().stream().filter(DataField::isVisible).count(), 4);
|
||||||
|
assertEquals(layoutsAfter.get(0).getFields().stream().filter(DataField::isVisible).count(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEditCustomLayout() {
|
||||||
|
// Update only one custom layout
|
||||||
|
|
||||||
|
// given a custom layout with two profiles
|
||||||
|
String cyclingProfile = "cycling;2;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_moving_time_key) + ",1,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_distance_key) + ",1,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_average_moving_speed_key) + ",1,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_speed_key) + ",1,1;";
|
||||||
|
|
||||||
|
String runningProfile = "running;2;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_moving_time_key) + ",1,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_distance_key) + ",1,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_average_pace_key) + ",0,0;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_pace_key) + ",0,0;";
|
||||||
|
|
||||||
|
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
editor.putString(context.getString(R.string.stats_custom_layouts_key), cyclingProfile + "\n" + runningProfile);
|
||||||
|
editor.apply();
|
||||||
|
|
||||||
|
List<Layout> layoutsBefore = PreferencesUtils.getAllCustomLayouts();
|
||||||
|
|
||||||
|
// when cyling profile is updated
|
||||||
|
String cyclingProfileUpdated = "cycling;2;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_moving_time_key) + ",1,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_distance_key) + ",0,0;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_average_moving_speed_key) + ",0,0;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_speed_key) + ",0,0;";
|
||||||
|
Layout layoutToBeUpdated = Layout.fromCsv(cyclingProfileUpdated, resources);
|
||||||
|
PreferencesUtils.updateCustomLayout(layoutToBeUpdated);
|
||||||
|
|
||||||
|
// then only updated profile is modified in the custom layouts
|
||||||
|
List<Layout> layoutsAfter = PreferencesUtils.getAllCustomLayouts();
|
||||||
|
|
||||||
|
assertEquals(layoutsBefore.size(), 2);
|
||||||
|
assertEquals(layoutsAfter.size(), 2);
|
||||||
|
|
||||||
|
assertEquals(layoutsBefore.get(0).getFields().stream().filter(DataField::isVisible).count(), 4);
|
||||||
|
assertEquals(layoutsAfter.get(0).getFields().stream().filter(DataField::isVisible).count(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetCustomLayout_whenSelectedOneNotExists() {
|
||||||
|
// given a custom layout with two profiles and not existing custom layout selected
|
||||||
|
String cyclingProfile = "cycling;2;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_moving_time_key) + ",1,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_distance_key) + ",1,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_average_moving_speed_key) + ",1,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_speed_key) + ",1,1;";
|
||||||
|
|
||||||
|
String runningProfile = "running;2;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_moving_time_key) + ",1,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_distance_key) + ",1,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_average_pace_key) + ",0,0;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_pace_key) + ",0,0;";
|
||||||
|
|
||||||
|
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
editor.putString(context.getString(R.string.stats_custom_layouts_key), cyclingProfile + "\n" + runningProfile);
|
||||||
|
editor.putString(context.getString(R.string.stats_custom_layout_selected_layout_key), "Not Exists");
|
||||||
|
editor.apply();
|
||||||
|
|
||||||
|
// when it gets the custom layout
|
||||||
|
Layout layout = PreferencesUtils.getCustomLayout();
|
||||||
|
|
||||||
|
// then the first one was returned
|
||||||
|
assertEquals(layout.getName(), "cycling");
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
-8
@@ -14,7 +14,9 @@
|
|||||||
* the License.
|
* the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package de.dennisguse.opentracks.content;
|
package de.dennisguse.opentracks.share;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
@@ -22,21 +24,24 @@ import androidx.test.core.app.ApplicationProvider;
|
|||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
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.R;
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
import de.dennisguse.opentracks.content.data.Speed;
|
import de.dennisguse.opentracks.data.models.Speed;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.data.models.Track;
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
import de.dennisguse.opentracks.util.StringUtils;
|
import de.dennisguse.opentracks.util.StringUtils;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link DescriptionGenerator}.
|
* Tests for {@link DescriptionGenerator}.
|
||||||
*
|
*
|
||||||
@@ -45,6 +50,9 @@ import static org.junit.Assert.assertEquals;
|
|||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class DescriptionGeneratorTest {
|
public class DescriptionGeneratorTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final LocaleRule mLocaleRule = new LocaleRule(Locale.ENGLISH);
|
||||||
|
|
||||||
private static final Instant START_TIME = Instant.ofEpochMilli(1288721514000L);
|
private static final Instant START_TIME = Instant.ofEpochMilli(1288721514000L);
|
||||||
private DescriptionGenerator descriptionGenerator;
|
private DescriptionGenerator descriptionGenerator;
|
||||||
|
|
||||||
@@ -91,7 +99,7 @@ public class DescriptionGeneratorTest {
|
|||||||
+ "Min elevation: -500 m (-1640 ft)<br>"
|
+ "Min elevation: -500 m (-1640 ft)<br>"
|
||||||
+ "Elevation gain: 6000 m (19685 ft)<br>"
|
+ "Elevation gain: 6000 m (19685 ft)<br>"
|
||||||
+ "Elevation loss: 6000 m (19685 ft)<br>"
|
+ "Elevation loss: 6000 m (19685 ft)<br>"
|
||||||
+ "Recorded: " + StringUtils.formatDateTime(context, START_TIME) + "<br>";
|
+ "Recorded: " + StringUtils.formatDateTime(OffsetDateTime.ofInstant(START_TIME, ZoneId.systemDefault())) + "<br>";
|
||||||
|
|
||||||
assertEquals(expected, descriptionGenerator.generateTrackDescription(track, true));
|
assertEquals(expected, descriptionGenerator.generateTrackDescription(track, true));
|
||||||
}
|
}
|
||||||
@@ -127,7 +135,7 @@ public class DescriptionGeneratorTest {
|
|||||||
+ "Fastest pace: 0:10 min/km (0:16 min/mi)<br>"
|
+ "Fastest pace: 0:10 min/km (0:16 min/mi)<br>"
|
||||||
+ "Elevation gain: 6000 m (19685 ft)<br>"
|
+ "Elevation gain: 6000 m (19685 ft)<br>"
|
||||||
+ "Elevation loss: 6000 m (19685 ft)<br>"
|
+ "Elevation loss: 6000 m (19685 ft)<br>"
|
||||||
+ "Recorded: " + StringUtils.formatDateTime(context, START_TIME) + "<br>";
|
+ "Recorded: " + StringUtils.formatDateTime(OffsetDateTime.ofInstant(START_TIME, ZoneId.systemDefault())) + "<br>";
|
||||||
|
|
||||||
assertEquals(expected, descriptionGenerator.generateTrackDescription(track, true));
|
assertEquals(expected, descriptionGenerator.generateTrackDescription(track, true));
|
||||||
}
|
}
|
||||||
@@ -15,6 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package de.dennisguse.opentracks.stats;
|
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 androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -24,11 +27,9 @@ import org.junit.runner.RunWith;
|
|||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
import de.dennisguse.opentracks.content.data.Speed;
|
import de.dennisguse.opentracks.data.models.HeartRate;
|
||||||
|
import de.dennisguse.opentracks.data.models.Speed;
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link TrackStatistics}.
|
* Tests for {@link TrackStatistics}.
|
||||||
@@ -67,6 +68,7 @@ public class TrackStatisticsTest {
|
|||||||
assertEquals(0.0, statistics.getMaxSpeed().toMPS(), 0.0);
|
assertEquals(0.0, statistics.getMaxSpeed().toMPS(), 0.0);
|
||||||
assertEquals(0.0, statistics.getAverageSpeed().toMPS(), 0.0);
|
assertEquals(0.0, statistics.getAverageSpeed().toMPS(), 0.0);
|
||||||
assertEquals(0.0, statistics.getAverageMovingSpeed().toMPS(), 0.0);
|
assertEquals(0.0, statistics.getAverageMovingSpeed().toMPS(), 0.0);
|
||||||
|
assertNull(statistics.getAverageHeartRate());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -91,6 +93,8 @@ public class TrackStatisticsTest {
|
|||||||
statistics.setMinAltitude(1200.0); // Resulting min altitude
|
statistics.setMinAltitude(1200.0); // Resulting min altitude
|
||||||
statistics2.setMaxAltitude(3575.0); // Resulting max altitude
|
statistics2.setMaxAltitude(3575.0); // Resulting max altitude
|
||||||
statistics2.setMinAltitude(2800.0);
|
statistics2.setMinAltitude(2800.0);
|
||||||
|
statistics.setAverageHeartRate(HeartRate.of(100f));
|
||||||
|
statistics2.setAverageHeartRate(HeartRate.of(200f));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
statistics.merge(statistics2);
|
statistics.merge(statistics2);
|
||||||
@@ -105,6 +109,7 @@ public class TrackStatisticsTest {
|
|||||||
assertEquals(Speed.of(statistics.getTotalDistance(), statistics.getMovingTime()).toMPS(), statistics.getMaxSpeed().toMPS(), 0.001);
|
assertEquals(Speed.of(statistics.getTotalDistance(), statistics.getMovingTime()).toMPS(), statistics.getMaxSpeed().toMPS(), 0.001);
|
||||||
assertEquals(1200.0, statistics.getMinAltitude(), 0.001);
|
assertEquals(1200.0, statistics.getMinAltitude(), 0.001);
|
||||||
assertEquals(3575.0, statistics.getMaxAltitude(), 0.001);
|
assertEquals(3575.0, statistics.getMaxAltitude(), 0.001);
|
||||||
|
assertEquals(150.0, statistics.getAverageHeartRate().getBPM(), 0.001);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
+53
-46
@@ -1,5 +1,8 @@
|
|||||||
package de.dennisguse.opentracks.stats;
|
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 androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
@@ -9,21 +12,16 @@ import org.junit.runner.RunWith;
|
|||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Altitude;
|
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
|
||||||
import de.dennisguse.opentracks.content.data.Speed;
|
|
||||||
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.data.models.Altitude;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
|
import de.dennisguse.opentracks.data.models.Speed;
|
||||||
import static org.junit.Assert.assertEquals;
|
import de.dennisguse.opentracks.data.models.Track;
|
||||||
import static org.junit.Assert.assertNull;
|
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class TrackStatisticsUpdaterTest {
|
public class TrackStatisticsUpdaterTest {
|
||||||
|
|
||||||
private static final Distance GPS_DISTANCE = Distance.of(50);
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void empty() {
|
public void empty() {
|
||||||
// when
|
// when
|
||||||
@@ -42,6 +40,7 @@ public class TrackStatisticsUpdaterTest {
|
|||||||
|
|
||||||
assertNull(statistics.getTotalAltitudeGain());
|
assertNull(statistics.getTotalAltitudeGain());
|
||||||
assertNull(statistics.getTotalAltitudeLoss());
|
assertNull(statistics.getTotalAltitudeLoss());
|
||||||
|
assertNull(statistics.getAverageHeartRate());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -53,7 +52,7 @@ public class TrackStatisticsUpdaterTest {
|
|||||||
// when
|
// when
|
||||||
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
|
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
|
||||||
|
|
||||||
subject.addTrackPoint(tp, GPS_DISTANCE);
|
subject.addTrackPoint(tp);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
TrackStatistics statistics = subject.getTrackStatistics();
|
TrackStatistics statistics = subject.getTrackStatistics();
|
||||||
@@ -68,6 +67,7 @@ public class TrackStatisticsUpdaterTest {
|
|||||||
|
|
||||||
assertNull(statistics.getTotalAltitudeGain());
|
assertNull(statistics.getTotalAltitudeGain());
|
||||||
assertNull(statistics.getTotalAltitudeLoss());
|
assertNull(statistics.getTotalAltitudeLoss());
|
||||||
|
assertNull(statistics.getAverageHeartRate());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -77,22 +77,23 @@ public class TrackStatisticsUpdaterTest {
|
|||||||
|
|
||||||
// when
|
// when
|
||||||
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
|
TrackStatisticsUpdater subject = new TrackStatisticsUpdater();
|
||||||
data.trackPoints.forEach(it -> subject.addTrackPoint(it, GPS_DISTANCE));
|
data.trackPoints.forEach(it -> subject.addTrackPoint(it));
|
||||||
|
|
||||||
// then
|
// then
|
||||||
TrackStatistics statistics = subject.getTrackStatistics();
|
TrackStatistics statistics = subject.getTrackStatistics();
|
||||||
assertEquals(99.58, statistics.getTotalDistance().toM(), 0.01);
|
assertEquals(128.03, statistics.getTotalDistance().toM(), 0.01);
|
||||||
assertEquals(Duration.ofSeconds(14), statistics.getTotalTime());
|
assertEquals(Duration.ofSeconds(13), statistics.getTotalTime());
|
||||||
assertEquals(Duration.ofSeconds(7), statistics.getMovingTime());
|
assertEquals(Duration.ofSeconds(9), statistics.getMovingTime());
|
||||||
|
|
||||||
assertEquals(2.5, statistics.getMinAltitude(), 0.01);
|
assertEquals(2.5, statistics.getMinAltitude(), 0.01);
|
||||||
assertEquals(27.5, statistics.getMaxAltitude(), 0.01);
|
assertEquals(28.75, statistics.getMaxAltitude(), 0.01);
|
||||||
assertEquals(36, statistics.getTotalAltitudeGain(), 0.01);
|
assertEquals(36, statistics.getTotalAltitudeGain(), 0.01);
|
||||||
assertEquals(36, statistics.getTotalAltitudeLoss(), 0.01);
|
assertEquals(36, statistics.getTotalAltitudeLoss(), 0.01);
|
||||||
|
|
||||||
assertEquals(14.226, statistics.getMaxSpeed().toMPS(), 0.01);
|
assertEquals(14.226, statistics.getMaxSpeed().toMPS(), 0.01);
|
||||||
assertEquals(14.226, statistics.getAverageMovingSpeed().toMPS(), 0.01);
|
assertEquals(14.226, statistics.getAverageMovingSpeed().toMPS(), 0.01);
|
||||||
assertEquals(7.11, statistics.getAverageSpeed().toMPS(), 0.01);
|
assertEquals(9.84, statistics.getAverageSpeed().toMPS(), 0.01);
|
||||||
|
assertEquals(106.85f, statistics.getAverageHeartRate().getBPM(), 0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -105,9 +106,9 @@ public class TrackStatisticsUpdaterTest {
|
|||||||
TrackPoint tp3 = new TrackPoint(0.00001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000));
|
TrackPoint tp3 = new TrackPoint(0.00001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
subject.addTrackPoint(tp1, GPS_DISTANCE);
|
subject.addTrackPoint(tp1);
|
||||||
subject.addTrackPoint(tp2, GPS_DISTANCE);
|
subject.addTrackPoint(tp2);
|
||||||
subject.addTrackPoint(tp3, GPS_DISTANCE);
|
subject.addTrackPoint(tp3);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(0, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
|
assertEquals(0, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
|
||||||
@@ -124,9 +125,9 @@ public class TrackStatisticsUpdaterTest {
|
|||||||
tp3.setSpeed(Speed.of(5f));
|
tp3.setSpeed(Speed.of(5f));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
subject.addTrackPoint(tp1, GPS_DISTANCE);
|
subject.addTrackPoint(tp1);
|
||||||
subject.addTrackPoint(tp2, GPS_DISTANCE);
|
subject.addTrackPoint(tp2);
|
||||||
subject.addTrackPoint(tp3, GPS_DISTANCE);
|
subject.addTrackPoint(tp3);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(1.10, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
|
assertEquals(1.10, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
|
||||||
@@ -141,24 +142,24 @@ public class TrackStatisticsUpdaterTest {
|
|||||||
TrackPoint tp2 = new TrackPoint(0, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(2000));
|
TrackPoint tp2 = new TrackPoint(0, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(2000));
|
||||||
tp2.setSpeed(Speed.of(5f));
|
tp2.setSpeed(Speed.of(5f));
|
||||||
TrackPoint tp3 = new TrackPoint(0.001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000));
|
TrackPoint tp3 = new TrackPoint(0.001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000));
|
||||||
tp2.setSpeed(Speed.of(5f));
|
tp3.setSpeed(Speed.of(5f));
|
||||||
TrackPoint tp4 = new TrackPoint(0.001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(4000));
|
TrackPoint tp4 = new TrackPoint(0.001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(4000));
|
||||||
tp2.setSpeed(Speed.of(5f));
|
tp4.setSpeed(Speed.of(5f));
|
||||||
tp4.setSensorDistance(Distance.of(5f));
|
tp4.setSensorDistance(Distance.of(5f));
|
||||||
TrackPoint tp5 = new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochMilli(5000));
|
TrackPoint tp5 = new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochMilli(5000));
|
||||||
tp5.setSensorDistance(Distance.of(10f));
|
tp5.setSensorDistance(Distance.of(10f));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
subject.addTrackPoint(tp1, GPS_DISTANCE);
|
subject.addTrackPoint(tp1);
|
||||||
subject.addTrackPoint(tp2, GPS_DISTANCE);
|
subject.addTrackPoint(tp2);
|
||||||
subject.addTrackPoint(tp3, GPS_DISTANCE);
|
subject.addTrackPoint(tp3);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(110.57, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
|
assertEquals(110.57, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
subject.addTrackPoint(tp4, GPS_DISTANCE);
|
subject.addTrackPoint(tp4);
|
||||||
subject.addTrackPoint(tp5, GPS_DISTANCE);
|
subject.addTrackPoint(tp5);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(125.57, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
|
assertEquals(125.57, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
|
||||||
@@ -178,16 +179,16 @@ public class TrackStatisticsUpdaterTest {
|
|||||||
tp5.setSensorDistance(Distance.of(10f));
|
tp5.setSensorDistance(Distance.of(10f));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
subject.addTrackPoint(tp1, GPS_DISTANCE);
|
subject.addTrackPoint(tp1);
|
||||||
subject.addTrackPoint(tp2, GPS_DISTANCE);
|
subject.addTrackPoint(tp2);
|
||||||
subject.addTrackPoint(tp3, GPS_DISTANCE);
|
subject.addTrackPoint(tp3);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(0, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
|
assertEquals(0, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
subject.addTrackPoint(tp4, GPS_DISTANCE);
|
subject.addTrackPoint(tp4);
|
||||||
subject.addTrackPoint(tp5, GPS_DISTANCE);
|
subject.addTrackPoint(tp5);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(15, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
|
assertEquals(15, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
|
||||||
@@ -200,22 +201,25 @@ public class TrackStatisticsUpdaterTest {
|
|||||||
|
|
||||||
TrackPoint tp1 = new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochMilli(1000));
|
TrackPoint tp1 = new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochMilli(1000));
|
||||||
TrackPoint tp2 = new TrackPoint(0, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(2000));
|
TrackPoint tp2 = new TrackPoint(0, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(2000));
|
||||||
|
tp2.setSpeed(Speed.of(5f));
|
||||||
TrackPoint tp3 = new TrackPoint(0.00001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000));
|
TrackPoint tp3 = new TrackPoint(0.00001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000));
|
||||||
tp3.setSensorDistance(Distance.of(5f));
|
tp3.setSensorDistance(Distance.of(5f));
|
||||||
|
tp3.setSpeed(Speed.of(5f));
|
||||||
TrackPoint tp4 = new TrackPoint(0.0005, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(4000));
|
TrackPoint tp4 = new TrackPoint(0.0005, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(4000));
|
||||||
|
tp4.setSpeed(Speed.of(5f));
|
||||||
TrackPoint tp5 = new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochMilli(5000));
|
TrackPoint tp5 = new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochMilli(5000));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
subject.addTrackPoint(tp1, GPS_DISTANCE);
|
subject.addTrackPoint(tp1);
|
||||||
subject.addTrackPoint(tp2, GPS_DISTANCE);
|
subject.addTrackPoint(tp2);
|
||||||
subject.addTrackPoint(tp3, GPS_DISTANCE);
|
subject.addTrackPoint(tp3);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(5, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
|
assertEquals(5, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
subject.addTrackPoint(tp4, GPS_DISTANCE);
|
subject.addTrackPoint(tp4);
|
||||||
subject.addTrackPoint(tp5, GPS_DISTANCE);
|
subject.addTrackPoint(tp5);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(59.18, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
|
assertEquals(59.18, subject.getTrackStatistics().getTotalDistance().toM(), 0.01);
|
||||||
@@ -248,19 +252,22 @@ public class TrackStatisticsUpdaterTest {
|
|||||||
|
|
||||||
TrackPoint tp1 = new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochMilli(1000));
|
TrackPoint tp1 = new TrackPoint(TrackPoint.Type.SEGMENT_START_MANUAL, Instant.ofEpochMilli(1000));
|
||||||
TrackPoint tp2 = new TrackPoint(0, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(2000));
|
TrackPoint tp2 = new TrackPoint(0, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(2000));
|
||||||
|
tp2.setSpeed(Speed.of(5f));
|
||||||
TrackPoint tp3 = new TrackPoint(0.00001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000));
|
TrackPoint tp3 = new TrackPoint(0.00001, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(3000));
|
||||||
|
tp3.setSpeed(Speed.of(5f));
|
||||||
TrackPoint tp4 = new TrackPoint(0.0005, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(4000));
|
TrackPoint tp4 = new TrackPoint(0.0005, 0, Altitude.WGS84.of(5.0), Instant.ofEpochMilli(4000));
|
||||||
|
tp4.setSpeed(Speed.of(5f));
|
||||||
TrackPoint tp5 = new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochMilli(5000));
|
TrackPoint tp5 = new TrackPoint(TrackPoint.Type.SEGMENT_END_MANUAL, Instant.ofEpochMilli(5000));
|
||||||
|
|
||||||
subject.addTrackPoint(tp1, GPS_DISTANCE);
|
subject.addTrackPoint(tp1);
|
||||||
subject.addTrackPoint(tp2, GPS_DISTANCE);
|
subject.addTrackPoint(tp2);
|
||||||
subject.addTrackPoint(tp3, GPS_DISTANCE);
|
subject.addTrackPoint(tp3);
|
||||||
subject.addTrackPoint(tp4, GPS_DISTANCE);
|
subject.addTrackPoint(tp4);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
TrackStatisticsUpdater copy = new TrackStatisticsUpdater(subject);
|
TrackStatisticsUpdater copy = new TrackStatisticsUpdater(subject);
|
||||||
subject.addTrackPoint(tp5, GPS_DISTANCE);
|
subject.addTrackPoint(tp5);
|
||||||
copy.addTrackPoint(tp5, GPS_DISTANCE);
|
copy.addTrackPoint(tp5);
|
||||||
|
|
||||||
|
|
||||||
// then
|
// then
|
||||||
|
|||||||
+7
-7
@@ -1,4 +1,7 @@
|
|||||||
package de.dennisguse.opentracks.viewmodels;
|
package de.dennisguse.opentracks.ui.aggregatedStatistics;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
@@ -13,15 +16,12 @@ import java.time.Instant;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
import de.dennisguse.opentracks.content.data.Speed;
|
import de.dennisguse.opentracks.data.models.Speed;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.data.models.Track;
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
import de.dennisguse.opentracks.util.TrackIconUtils;
|
import de.dennisguse.opentracks.util.TrackIconUtils;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
|
|
||||||
@RunWith(JUnit4.class)
|
@RunWith(JUnit4.class)
|
||||||
public class AggregatedStatisticsTest {
|
public class AggregatedStatisticsTest {
|
||||||
|
|
||||||
+86
@@ -0,0 +1,86 @@
|
|||||||
|
package de.dennisguse.opentracks.ui.aggregatedStatistics;
|
||||||
|
|
||||||
|
import static androidx.test.espresso.Espresso.onView;
|
||||||
|
import static androidx.test.espresso.action.ViewActions.click;
|
||||||
|
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
||||||
|
import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
|
||||||
|
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||||
|
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||||
|
import static androidx.test.espresso.matcher.ViewMatchers.withParent;
|
||||||
|
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
||||||
|
import static org.hamcrest.Matchers.allOf;
|
||||||
|
import static de.dennisguse.opentracks.util.EspressoUtils.waitFor;
|
||||||
|
|
||||||
|
import android.util.Pair;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
import androidx.test.espresso.ViewInteraction;
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers;
|
||||||
|
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
import androidx.test.filters.LargeTest;
|
||||||
|
import androidx.test.rule.GrantPermissionRule;
|
||||||
|
|
||||||
|
import org.hamcrest.core.IsInstanceOf;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.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.TrackPoint;
|
||||||
|
|
||||||
|
@LargeTest
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class EspressoAggregatedFilterTest {
|
||||||
|
|
||||||
|
private final String CATEGORY = "category";
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ActivityScenarioRule<TrackListActivity> mActivityTestRule = new ActivityScenarioRule<>(TrackListActivity.class);
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public GrantPermissionRule mGrantPermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
Pair<Track, List<TrackPoint>> pair = TestDataUtil.createTrack(new Track.Id(System.currentTimeMillis()), 20);
|
||||||
|
pair.first.setCategory(CATEGORY);
|
||||||
|
TestDataUtil.insertTrackWithLocations(new ContentProviderUtils(ApplicationProvider.getApplicationContext()), pair.first, pair.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void espressoAggregatedFilterTest() {
|
||||||
|
// open AggregatedStatisticsActivity through toolbar's menu item
|
||||||
|
onView(ViewMatchers.withId(R.id.toolbar)).check(matches(isDisplayed()));
|
||||||
|
onView(withId(R.id.toolbar)).check(matches(hasDescendant(withId(R.id.track_list_aggregated_stats))));
|
||||||
|
onView(withId(R.id.track_list_aggregated_stats)).perform(click());
|
||||||
|
|
||||||
|
// open FilterDialogFragment through toolbar's menu item
|
||||||
|
onView(withId(R.id.toolbar)).check(matches(isDisplayed()));
|
||||||
|
onView(withId(R.id.toolbar)).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
|
||||||
|
ViewInteraction checkBox = onView(
|
||||||
|
allOf(withId(R.id.filter_dialog_check_button), withText(CATEGORY),
|
||||||
|
withParent(allOf(withId(R.id.filter_items),
|
||||||
|
withParent(IsInstanceOf.<View>instanceOf(android.view.ViewGroup.class)))),
|
||||||
|
isDisplayed()));
|
||||||
|
checkBox.perform(waitFor(2000));
|
||||||
|
|
||||||
|
// check there's an edit text for "from date"
|
||||||
|
onView(withId(R.id.filter_date_edit_text_from)).check(matches(isDisplayed()));
|
||||||
|
|
||||||
|
// check there's an edit text for "to date"
|
||||||
|
onView(withId(R.id.filter_date_edit_text_to)).check(matches(isDisplayed()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+93
@@ -0,0 +1,93 @@
|
|||||||
|
package de.dennisguse.opentracks.ui.customRecordingLayout;
|
||||||
|
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class CsvLayoutUtilsTest extends TestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetCsvLineParts() {
|
||||||
|
// given
|
||||||
|
String csvLineOk = "Layout Name;2;distance,1,1;speed,1,1;";
|
||||||
|
String csvLineWrong1 = "Layout Name;distance,1,1;speed,1,1;";
|
||||||
|
String csvLineWrong2 = "Layout Name;1;";
|
||||||
|
|
||||||
|
// when
|
||||||
|
List<String> partsOk = CsvLayoutUtils.getCsvLineParts(csvLineOk);
|
||||||
|
List<String> partsWrong1 = CsvLayoutUtils.getCsvLineParts(csvLineWrong1);
|
||||||
|
List<String> partsWrong2 = CsvLayoutUtils.getCsvLineParts(csvLineWrong2);
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
assertNull(partsWrong1);
|
||||||
|
assertNull(partsWrong2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetCsvFieldParts() {
|
||||||
|
// given
|
||||||
|
String csvFieldOk1 = "distance,0,0";
|
||||||
|
String csvFieldOk2 = "speed,0,1";
|
||||||
|
String csvFieldOk3 = "time,1,0";
|
||||||
|
String csvFieldOk4 = "moving time,1,1";
|
||||||
|
String csvFieldOk5 = ";moving time,1,1";
|
||||||
|
String csvLineWrong1 = "";
|
||||||
|
String csvLineWrong2 = "distance,speed,time";
|
||||||
|
String csvLineWrong3 = "distance,0,1o";
|
||||||
|
String csvLineWrong4 = "distance,0z,1";
|
||||||
|
String csvLineWrong5 = "distance";
|
||||||
|
String csvLineWrong6 = "distance,0";
|
||||||
|
String csvLineWrong7 = "distance,1,1;";
|
||||||
|
|
||||||
|
// when
|
||||||
|
String[] ok1 = CsvLayoutUtils.getCsvFieldParts(csvFieldOk1);
|
||||||
|
String[] ok2 = CsvLayoutUtils.getCsvFieldParts(csvFieldOk2);
|
||||||
|
String[] ok3 = CsvLayoutUtils.getCsvFieldParts(csvFieldOk3);
|
||||||
|
String[] ok4 = CsvLayoutUtils.getCsvFieldParts(csvFieldOk4);
|
||||||
|
String[] ok5 = CsvLayoutUtils.getCsvFieldParts(csvFieldOk5);
|
||||||
|
String[] wrong1 = CsvLayoutUtils.getCsvFieldParts(csvLineWrong1);
|
||||||
|
String[] wrong2 = CsvLayoutUtils.getCsvFieldParts(csvLineWrong2);
|
||||||
|
String[] wrong3 = CsvLayoutUtils.getCsvFieldParts(csvLineWrong3);
|
||||||
|
String[] wrong4 = CsvLayoutUtils.getCsvFieldParts(csvLineWrong4);
|
||||||
|
String[] wrong5 = CsvLayoutUtils.getCsvFieldParts(csvLineWrong5);
|
||||||
|
String[] wrong6 = CsvLayoutUtils.getCsvFieldParts(csvLineWrong6);
|
||||||
|
String[] wrong7 = CsvLayoutUtils.getCsvFieldParts(csvLineWrong7);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertNotNull(ok1);
|
||||||
|
assertNotNull(ok2);
|
||||||
|
assertNotNull(ok3);
|
||||||
|
assertNotNull(ok4);
|
||||||
|
assertNotNull(ok5);
|
||||||
|
assertFieldOk(ok1, "distance", "0", "0");
|
||||||
|
assertFieldOk(ok2, "speed", "0", "1");
|
||||||
|
assertFieldOk(ok3, "time", "1", "0");
|
||||||
|
assertFieldOk(ok4, "moving time", "1", "1");
|
||||||
|
assertFieldOk(ok5, ";moving time", "1", "1");
|
||||||
|
assertNull(wrong1);
|
||||||
|
assertNull(wrong2);
|
||||||
|
assertNull(wrong3);
|
||||||
|
assertNull(wrong4);
|
||||||
|
assertNull(wrong5);
|
||||||
|
assertNull(wrong6);
|
||||||
|
assertNull(wrong7);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertFieldOk(String[] ok, String name, String val1, String val2) {
|
||||||
|
assertEquals(ok[0], name);
|
||||||
|
assertEquals(ok[1], val1);
|
||||||
|
assertEquals(ok[2], val2);
|
||||||
|
}
|
||||||
|
}
|
||||||
+76
@@ -0,0 +1,76 @@
|
|||||||
|
package de.dennisguse.opentracks.ui.customRecordingLayout;
|
||||||
|
|
||||||
|
|
||||||
|
import static androidx.test.espresso.Espresso.onView;
|
||||||
|
import static androidx.test.espresso.action.ViewActions.click;
|
||||||
|
import static androidx.test.espresso.matcher.ViewMatchers.assertThat;
|
||||||
|
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static de.dennisguse.opentracks.util.EspressoUtils.veryLongTouch;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import androidx.test.espresso.NoMatchingViewException;
|
||||||
|
import androidx.test.espresso.ViewAssertion;
|
||||||
|
import androidx.test.espresso.ViewInteraction;
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers;
|
||||||
|
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
import androidx.test.filters.LargeTest;
|
||||||
|
import androidx.test.rule.GrantPermissionRule;
|
||||||
|
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.TrackListActivity;
|
||||||
|
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||||
|
|
||||||
|
@LargeTest
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class EspressoCustomLayoutTest {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ActivityScenarioRule<TrackListActivity> mActivityTestRule = new ActivityScenarioRule<>(TrackListActivity.class);
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public GrantPermissionRule mGrantPermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void customLayoutTest() {
|
||||||
|
// TrackListActivity: start recording
|
||||||
|
ViewInteraction trackControllerRecordButton = onView(ViewMatchers.withId(R.id.controller_record));
|
||||||
|
trackControllerRecordButton.perform(click());
|
||||||
|
|
||||||
|
// Get custom layout preferences and check all data fields are showed.
|
||||||
|
Layout layout = PreferencesUtils.getCustomLayout();
|
||||||
|
|
||||||
|
onView(withId(R.id.stats_recycler_view)).check(new RecyclerViewItemCountAssertion((int) layout.getFields().stream().filter(DataField::isVisible).count()));
|
||||||
|
|
||||||
|
// stop recording
|
||||||
|
ViewInteraction trackControllerStopButton = onView(withId(R.id.controller_stop));
|
||||||
|
trackControllerStopButton.perform(veryLongTouch(1600));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class RecyclerViewItemCountAssertion implements ViewAssertion {
|
||||||
|
private final int expectedCount;
|
||||||
|
|
||||||
|
public RecyclerViewItemCountAssertion(int expectedCount) {
|
||||||
|
this.expectedCount = expectedCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void check(View view, NoMatchingViewException noViewFoundException) {
|
||||||
|
if (noViewFoundException != null) {
|
||||||
|
throw noViewFoundException;
|
||||||
|
}
|
||||||
|
|
||||||
|
RecyclerView recyclerView = (RecyclerView) view;
|
||||||
|
RecyclerView.Adapter<?> adapter = recyclerView.getAdapter();
|
||||||
|
assertThat(adapter.getItemCount(), is(expectedCount));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+154
@@ -0,0 +1,154 @@
|
|||||||
|
package de.dennisguse.opentracks.ui.customRecordingLayout;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
|
||||||
|
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 java.util.List;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class LayoutTest extends TestCase {
|
||||||
|
|
||||||
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
private final Resources resources = ApplicationProvider.getApplicationContext().getResources();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromCsv() {
|
||||||
|
// given a csv line
|
||||||
|
String csv = "running;2;" + context.getString(R.string.stats_custom_layout_speed_key) + ",1,1,0;" + context.getString(R.string.stats_custom_layout_distance_key) + ",1,0,0;" + context.getString(R.string.stats_custom_layout_altitude_key) + ",0,1,0;" + context.getString(R.string.stats_custom_layout_gain_key) + ",0,0,0;";
|
||||||
|
|
||||||
|
// when create a layout from CSV line
|
||||||
|
Layout layout = Layout.fromCsv(csv, resources);
|
||||||
|
List<DataField> dataFieldList = layout.getFields();
|
||||||
|
|
||||||
|
// then layout and data fields are built correctly
|
||||||
|
assertEquals(layout.getName(), "running");
|
||||||
|
assertEquals(layout.getColumnsPerRow(), 2);
|
||||||
|
assertEquals(dataFieldList.size(), 4);
|
||||||
|
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));
|
||||||
|
assertEquals(dataFieldList.get(3).getKey(), context.getString(R.string.stats_custom_layout_gain_key));
|
||||||
|
assertEquals(dataFieldList.get(0).getTitle(), context.getString(R.string.stats_speed));
|
||||||
|
assertEquals(dataFieldList.get(1).getTitle(), context.getString(R.string.stats_distance));
|
||||||
|
assertEquals(dataFieldList.get(2).getTitle(), context.getString(R.string.stats_altitude));
|
||||||
|
assertEquals(dataFieldList.get(3).getTitle(), context.getString(R.string.stats_gain));
|
||||||
|
assertTrue(dataFieldList.get(0).isVisible());
|
||||||
|
assertTrue(dataFieldList.get(0).isPrimary());
|
||||||
|
assertFalse(dataFieldList.get(0).isWide());
|
||||||
|
assertTrue(dataFieldList.get(1).isVisible());
|
||||||
|
assertFalse(dataFieldList.get(1).isPrimary());
|
||||||
|
assertFalse(dataFieldList.get(1).isWide());
|
||||||
|
assertFalse(dataFieldList.get(2).isVisible());
|
||||||
|
assertTrue(dataFieldList.get(2).isPrimary());
|
||||||
|
assertFalse(dataFieldList.get(2).isWide());
|
||||||
|
assertFalse(dataFieldList.get(3).isVisible());
|
||||||
|
assertFalse(dataFieldList.get(3).isPrimary());
|
||||||
|
assertFalse(dataFieldList.get(3).isWide());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromCsv_Wrong1() {
|
||||||
|
// given a csv line without number of columns
|
||||||
|
String csv1 = "Layout Name;speed,1,1;distance,0,0;";
|
||||||
|
|
||||||
|
// when create a layout from CSV line
|
||||||
|
Layout layout = Layout.fromCsv(csv1, resources);
|
||||||
|
List<DataField> dataFieldList = layout.getFields();
|
||||||
|
|
||||||
|
// then layout and data fields are built correctly
|
||||||
|
assertEquals(layout.getName(), PreferencesUtils.getDefaultLayoutName());
|
||||||
|
assertEquals(layout.getColumnsPerRow(), PreferencesUtils.getLayoutColumnsByDefault());
|
||||||
|
assertEquals(layout.getFields().size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromCsv_Wrong2() {
|
||||||
|
// given a csv line without any field
|
||||||
|
String csv1 = "Layout Name;2;";
|
||||||
|
|
||||||
|
// when create a layout from CSV line
|
||||||
|
Layout layout = Layout.fromCsv(csv1, resources);
|
||||||
|
List<DataField> dataFieldList = layout.getFields();
|
||||||
|
|
||||||
|
// then layout and data fields are built correctly
|
||||||
|
assertEquals(layout.getName(), PreferencesUtils.getDefaultLayoutName());
|
||||||
|
assertEquals(layout.getColumnsPerRow(), PreferencesUtils.getLayoutColumnsByDefault());
|
||||||
|
assertEquals(layout.getFields().size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromCsv_Wrong3() {
|
||||||
|
// given a csv line with wrong fields description
|
||||||
|
String csv1 = "Layout Name;2;speed,distance,total time;";
|
||||||
|
|
||||||
|
// when create a layout from CSV line
|
||||||
|
Layout layout = Layout.fromCsv(csv1, resources);
|
||||||
|
List<DataField> dataFieldList = layout.getFields();
|
||||||
|
|
||||||
|
// then layout and data fields are built correctly
|
||||||
|
assertEquals(layout.getName(), "Layout Name");
|
||||||
|
assertEquals(layout.getColumnsPerRow(), 2);
|
||||||
|
assertEquals(layout.getFields().size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromCsv_Wrong4() {
|
||||||
|
// given a csv line with the first field ok but not the others
|
||||||
|
String csv1 = "Layout Name;2;speed,1,0;distance;";
|
||||||
|
|
||||||
|
// when create a layout from CSV line
|
||||||
|
Layout layout = Layout.fromCsv(csv1, resources);
|
||||||
|
List<DataField> dataFieldList = layout.getFields();
|
||||||
|
|
||||||
|
// then layout and data fields are built correctly
|
||||||
|
assertEquals(layout.getName(), "Layout Name");
|
||||||
|
assertEquals(layout.getColumnsPerRow(), 2);
|
||||||
|
assertEquals(layout.getFields().size(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToCsv() {
|
||||||
|
// given a layout's object
|
||||||
|
Layout layout = new Layout("Test Layout", 2);
|
||||||
|
layout.addField("key1", "Title 1", false, false, false);
|
||||||
|
layout.addField("key2", "Title 2", false, true, false);
|
||||||
|
layout.addField("key3", "Title 3", true, false, false);
|
||||||
|
layout.addField("key4", "Title 4", true, true, false);
|
||||||
|
layout.addField("key5", "Title 5", true, true, true);
|
||||||
|
|
||||||
|
// when converts it to CSV
|
||||||
|
String csv = layout.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;");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToCsv_columnsByDefault() {
|
||||||
|
// given a layout's object
|
||||||
|
Layout layout = new Layout("Test Layout");
|
||||||
|
layout.addField("key1", "Title 1", false, false, false);
|
||||||
|
layout.addField("key2", "Title 2", false, true, false);
|
||||||
|
layout.addField("key3", "Title 3", true, false, false);
|
||||||
|
layout.addField("key4", "Title 4", true, true, false);
|
||||||
|
layout.addField("key5", "Title 5", true, true, true);
|
||||||
|
|
||||||
|
// when converts it to CSV
|
||||||
|
String csv = layout.toCsv();
|
||||||
|
|
||||||
|
// then csv is well built
|
||||||
|
assertEquals(csv, "Test Layout;" + PreferencesUtils.getLayoutColumnsByDefault() + ";key1,0,0,0;key2,0,1,0;key3,1,0,0;key4,1,1,0;key5,1,1,1;");
|
||||||
|
}
|
||||||
|
}
|
||||||
+65
-12
@@ -1,4 +1,7 @@
|
|||||||
package de.dennisguse.opentracks.viewmodels;
|
package de.dennisguse.opentracks.ui.intervals;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
@@ -12,17 +15,15 @@ import org.junit.runners.JUnit4;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
|
||||||
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
import de.dennisguse.opentracks.content.data.TestDataUtil;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.data.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.data.TrackPointIterator;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.data.models.Distance;
|
||||||
import de.dennisguse.opentracks.content.provider.TrackPointIterator;
|
import de.dennisguse.opentracks.data.models.Track;
|
||||||
|
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||||
|
import de.dennisguse.opentracks.data.models.UnitConversions;
|
||||||
import de.dennisguse.opentracks.stats.TrackStatistics;
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
|
import de.dennisguse.opentracks.stats.TrackStatisticsUpdater;
|
||||||
import de.dennisguse.opentracks.util.UnitConversions;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
@RunWith(JUnit4.class)
|
@RunWith(JUnit4.class)
|
||||||
public class IntervalStatisticsTest {
|
public class IntervalStatisticsTest {
|
||||||
@@ -40,7 +41,7 @@ public class IntervalStatisticsTest {
|
|||||||
private TrackStatistics buildTrackStatistics(List<TrackPoint> trackPoints) {
|
private TrackStatistics buildTrackStatistics(List<TrackPoint> trackPoints) {
|
||||||
TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater();
|
TrackStatisticsUpdater trackStatisticsUpdater = new TrackStatisticsUpdater();
|
||||||
for (TrackPoint tp : trackPoints) {
|
for (TrackPoint tp : trackPoints) {
|
||||||
trackStatisticsUpdater.addTrackPoint(tp, Distance.of(0));
|
trackStatisticsUpdater.addTrackPoint(tp);
|
||||||
}
|
}
|
||||||
return trackStatisticsUpdater.getTrackStatistics();
|
return trackStatisticsUpdater.getTrackStatistics();
|
||||||
}
|
}
|
||||||
@@ -115,9 +116,40 @@ public class IntervalStatisticsTest {
|
|||||||
whenAndThen(10000, distanceInterval);
|
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) {
|
private void whenAndThen(int numberOfPoints, float distanceInterval) {
|
||||||
IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.of(distanceInterval), Distance.of(0));
|
|
||||||
Pair<Track.Id, TrackStatistics> trackWithStats = TestDataUtil.buildTrackWithTrackPoints(contentProviderUtils, numberOfPoints);
|
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;
|
Track.Id trackId = trackWithStats.first;
|
||||||
TrackStatistics trackStatistics = trackWithStats.second;
|
TrackStatistics trackStatistics = trackWithStats.second;
|
||||||
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
|
try (TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(trackId, null)) {
|
||||||
@@ -127,18 +159,39 @@ public class IntervalStatisticsTest {
|
|||||||
List<IntervalStatistics.Interval> intervalList = intervalStatistics.getIntervalList();
|
List<IntervalStatistics.Interval> intervalList = intervalStatistics.getIntervalList();
|
||||||
Distance totalDistance = Distance.of(0);
|
Distance totalDistance = Distance.of(0);
|
||||||
float totalTime = 0L;
|
float totalTime = 0L;
|
||||||
float totalGain = 0f;
|
Float totalGain = null;
|
||||||
|
Float totalLoss = null;
|
||||||
for (IntervalStatistics.Interval i : intervalList) {
|
for (IntervalStatistics.Interval i : intervalList) {
|
||||||
totalDistance = totalDistance.plus(i.getDistance());
|
totalDistance = totalDistance.plus(i.getDistance());
|
||||||
totalTime += i.getDistance().toM() / i.getSpeed().toMPS();
|
totalTime += i.getDistance().toM() / i.getSpeed().toMPS();
|
||||||
|
|
||||||
|
if (totalGain == null) {
|
||||||
|
totalGain = i.getGain_m();
|
||||||
|
} else if (i.getGain_m() != null) {
|
||||||
totalGain += i.getGain_m();
|
totalGain += i.getGain_m();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (totalLoss == null) {
|
||||||
|
totalLoss = i.getLoss_m();
|
||||||
|
} else if (i.getLoss_m() != null) {
|
||||||
|
totalLoss += i.getLoss_m();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertEquals(trackStatistics.getTotalDistance().toM(), totalDistance.toM(), 0.01);
|
assertEquals(trackStatistics.getTotalDistance().toM(), totalDistance.toM(), 0.01);
|
||||||
assertEquals(trackStatistics.getTotalTime().toMillis(), totalTime * UnitConversions.S_TO_MS, 1);
|
assertEquals(trackStatistics.getTotalTime().toMillis(), totalTime * UnitConversions.S_TO_MS, 1);
|
||||||
assertEquals(intervalList.size(), (int) Math.ceil(trackStatistics.getTotalDistance().toM() / distanceInterval));
|
assertEquals(intervalList.size(), (int) Math.ceil(trackStatistics.getTotalDistance().toM() / distanceInterval));
|
||||||
|
if (totalGain != null) {
|
||||||
assertEquals(totalGain, numberOfPoints * TestDataUtil.ALTITUDE_GAIN, 0.1);
|
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++) {
|
for (int i = 0; i < intervalList.size() - 1; i++) {
|
||||||
assertEquals(intervalList.get(i).getDistance().toM(), distanceInterval, 0.001);
|
assertEquals(intervalList.get(i).getDistance().toM(), distanceInterval, 0.001);
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
package de.dennisguse.opentracks.util;
|
package de.dennisguse.opentracks.util;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
@@ -16,10 +19,7 @@ import java.io.InputStreamReader;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.data.models.TrackPoint;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertNotEquals;
|
|
||||||
|
|
||||||
@RunWith(JUnit4.class)
|
@RunWith(JUnit4.class)
|
||||||
public class EGM2008UtilsTest {
|
public class EGM2008UtilsTest {
|
||||||
|
|||||||
@@ -0,0 +1,173 @@
|
|||||||
|
package de.dennisguse.opentracks.util;
|
||||||
|
|
||||||
|
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||||
|
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
|
||||||
|
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||||
|
import static androidx.test.espresso.util.TreeIterables.breadthFirstViewTraversal;
|
||||||
|
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.ViewParent;
|
||||||
|
import android.widget.ListView;
|
||||||
|
|
||||||
|
import androidx.test.espresso.PerformException;
|
||||||
|
import androidx.test.espresso.UiController;
|
||||||
|
import androidx.test.espresso.ViewAction;
|
||||||
|
import androidx.test.espresso.action.MotionEvents;
|
||||||
|
import androidx.test.espresso.util.HumanReadables;
|
||||||
|
|
||||||
|
import com.google.android.material.tabs.TabLayout;
|
||||||
|
|
||||||
|
import org.hamcrest.Description;
|
||||||
|
import org.hamcrest.Matcher;
|
||||||
|
import org.hamcrest.TypeSafeMatcher;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
public class EspressoUtils {
|
||||||
|
|
||||||
|
public static Matcher<View> childAtPosition(
|
||||||
|
final Matcher<View> parentMatcher, final int position) {
|
||||||
|
|
||||||
|
return new TypeSafeMatcher<>() {
|
||||||
|
@Override
|
||||||
|
public void describeTo(Description description) {
|
||||||
|
description.appendText("Child at position " + position + " in parent ");
|
||||||
|
parentMatcher.describeTo(description);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matchesSafely(View view) {
|
||||||
|
ViewParent parent = view.getParent();
|
||||||
|
return parent instanceof ViewGroup && parentMatcher.matches(parent)
|
||||||
|
&& view.equals(((ViewGroup) parent).getChildAt(position));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Matcher<View> withListSize (final int size) {
|
||||||
|
return new TypeSafeMatcher<>() {
|
||||||
|
@Override
|
||||||
|
public boolean matchesSafely(final View view) {
|
||||||
|
return ((ListView) view).getCount() == size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void describeTo(final Description description) {
|
||||||
|
description.appendText("ListView should have " + size + " items");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ViewAction waitFor(final long duration_ms) {
|
||||||
|
return new ViewAction() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Wait for milliseconds.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Matcher<View> getConstraints() {
|
||||||
|
return isDisplayed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void perform(UiController uiController, final View view) {
|
||||||
|
uiController.loopMainThreadForAtLeast(duration_ms);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ViewAction veryLongTouch(final int duration_ms) {
|
||||||
|
return new ViewAction() {
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Perform long touch.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Matcher<View> getConstraints() {
|
||||||
|
return isDisplayed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void perform(UiController uiController, final View view) {
|
||||||
|
// Get view absolute position
|
||||||
|
int[] location = new int[2];
|
||||||
|
view.getLocationOnScreen(location);
|
||||||
|
|
||||||
|
// Offset coordinates by view position
|
||||||
|
float[] coordinates = new float[]{location[0] + 1, location[1] + 1};
|
||||||
|
|
||||||
|
// Send down event, pause, and send up
|
||||||
|
MotionEvent down = MotionEvents.sendDown(uiController, coordinates, new float[]{1f, 1f}).down;
|
||||||
|
uiController.loopMainThreadForAtLeast(duration_ms);
|
||||||
|
MotionEvents.sendUp(uiController, down, coordinates);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ViewAction waitId(final int viewId, final long millis) {
|
||||||
|
return new ViewAction() {
|
||||||
|
@Override
|
||||||
|
public Matcher<View> getConstraints() {
|
||||||
|
return isRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "wait for a specific view with id <" + viewId + "> during " + millis + " millis.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void perform(final UiController uiController, final View view) {
|
||||||
|
uiController.loopMainThreadUntilIdle();
|
||||||
|
final long startTime = System.currentTimeMillis();
|
||||||
|
final long endTime = startTime + millis;
|
||||||
|
final Matcher<View> viewMatcher = withId(viewId);
|
||||||
|
|
||||||
|
do {
|
||||||
|
for (View child : breadthFirstViewTraversal(view)) {
|
||||||
|
// found view with required ID
|
||||||
|
if (viewMatcher.matches(child)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uiController.loopMainThreadForAtLeast(50);
|
||||||
|
}
|
||||||
|
while (System.currentTimeMillis() < endTime);
|
||||||
|
|
||||||
|
// timeout happens
|
||||||
|
throw new PerformException.Builder()
|
||||||
|
.withActionDescription(this.getDescription())
|
||||||
|
.withViewDescription(HumanReadables.describe(view))
|
||||||
|
.withCause(new TimeoutException())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ViewAction selectTabAtIndex(final int index) {
|
||||||
|
return new ViewAction() {
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "Selecting tab.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Matcher<View> getConstraints() {
|
||||||
|
return isDisplayed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void perform(UiController uiController, View view) {
|
||||||
|
TabLayout tabLayout = (TabLayout) view;
|
||||||
|
tabLayout.getTabAt(index).select();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package de.dennisguse.opentracks.util;
|
package de.dennisguse.opentracks.util;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.JUnit4;
|
import org.junit.runners.JUnit4;
|
||||||
@@ -22,8 +24,6 @@ import org.junit.runners.JUnit4;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link FileUtils}.
|
* Tests for {@link FileUtils}.
|
||||||
*
|
*
|
||||||
@@ -101,6 +101,13 @@ public class FileUtilsTest {
|
|||||||
assertEquals(expected, FileUtils.sanitizeFileName(name));
|
assertEquals(expected, FileUtils.sanitizeFileName(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSanitizeFileName_emoji() {
|
||||||
|
String name = "\uD83C\uDF5B-Food";
|
||||||
|
String expected = "_-Food";
|
||||||
|
assertEquals(expected, FileUtils.sanitizeFileName(name));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link FileUtils#truncateFileName(File, String, String)}.
|
* Tests {@link FileUtils#truncateFileName(File, String, String)}.
|
||||||
* Verifies the a long file name is truncated.
|
* Verifies the a long file name is truncated.
|
||||||
|
|||||||
@@ -1,199 +0,0 @@
|
|||||||
package de.dennisguse.opentracks.util;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
|
||||||
import de.dennisguse.opentracks.content.data.DataField;
|
|
||||||
import de.dennisguse.opentracks.content.data.Layout;
|
|
||||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
public class PreferencesUtilsTest {
|
|
||||||
|
|
||||||
private final Context context = ApplicationProvider.getApplicationContext();
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void ExportTrackFileFormat_ok() {
|
|
||||||
// given
|
|
||||||
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
|
||||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
|
||||||
|
|
||||||
editor.putString(context.getString(R.string.export_trackfileformat_key), TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA.name());
|
|
||||||
editor.commit();
|
|
||||||
|
|
||||||
// when
|
|
||||||
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(sharedPreferences, context);
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertEquals(TrackFileFormat.KML_WITH_TRACKDETAIL_AND_SENSORDATA, trackFileFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void ExportTrackFileFormat_invalid() {
|
|
||||||
// given
|
|
||||||
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
|
||||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
|
||||||
editor.putString(context.getString(R.string.export_trackfileformat_key), "invalid");
|
|
||||||
editor.commit();
|
|
||||||
|
|
||||||
// when
|
|
||||||
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(sharedPreferences, context);
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, trackFileFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void ExportTrackFileFormat_noValue() {
|
|
||||||
// given
|
|
||||||
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
|
||||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
|
||||||
editor.clear();
|
|
||||||
editor.commit();
|
|
||||||
|
|
||||||
// when
|
|
||||||
TrackFileFormat trackFileFormat = PreferencesUtils.getExportTrackFileFormat(sharedPreferences, context);
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, trackFileFormat);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetCustomLayout_default() {
|
|
||||||
// given
|
|
||||||
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
|
||||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
|
||||||
editor.clear();
|
|
||||||
editor.commit();
|
|
||||||
|
|
||||||
// when
|
|
||||||
Layout layout = PreferencesUtils.getCustomLayout(sharedPreferences, context);
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertTrue(layout.getFields().size() > 0);
|
|
||||||
assertEquals(layout.getProfile(), context.getString(R.string.default_activity_default));
|
|
||||||
assertTrue(layout.getFields().stream().anyMatch(DataField::isVisible));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetCustomLayout_1() {
|
|
||||||
// given
|
|
||||||
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
|
||||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
|
||||||
editor.putString(
|
|
||||||
context.getString(R.string.stats_custom_layout_fields_key),
|
|
||||||
"run;"
|
|
||||||
+ context.getString(R.string.stats_custom_layout_moving_time_key) + ",1,1;"
|
|
||||||
+ context.getString(R.string.stats_custom_layout_distance_key) + ",1,0;"
|
|
||||||
+ context.getString(R.string.stats_custom_layout_average_moving_speed_key) + ",0,1;"
|
|
||||||
+ context.getString(R.string.stats_custom_layout_speed_key) + ",0,0;");
|
|
||||||
editor.apply();
|
|
||||||
|
|
||||||
// when
|
|
||||||
Layout layout = PreferencesUtils.getCustomLayout(sharedPreferences, context);
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertEquals(layout.getFields().size(), 4);
|
|
||||||
assertEquals(layout.getProfile(), "run");
|
|
||||||
|
|
||||||
assertEquals(layout.getFields().get(0).getKey(), context.getString(R.string.stats_custom_layout_moving_time_key));
|
|
||||||
assertTrue(layout.getFields().get(0).isVisible());
|
|
||||||
assertTrue(layout.getFields().get(0).isPrimary());
|
|
||||||
|
|
||||||
assertEquals(layout.getFields().get(1).getKey(), context.getString(R.string.stats_custom_layout_distance_key));
|
|
||||||
assertTrue(layout.getFields().get(1).isVisible());
|
|
||||||
assertFalse(layout.getFields().get(1).isPrimary());
|
|
||||||
|
|
||||||
assertEquals(layout.getFields().get(2).getKey(), context.getString(R.string.stats_custom_layout_average_moving_speed_key));
|
|
||||||
assertFalse(layout.getFields().get(2).isVisible());
|
|
||||||
assertTrue(layout.getFields().get(2).isPrimary());
|
|
||||||
|
|
||||||
assertEquals(layout.getFields().get(3).getKey(), context.getString(R.string.stats_custom_layout_speed_key));
|
|
||||||
assertFalse(layout.getFields().get(3).isVisible());
|
|
||||||
assertFalse(layout.getFields().get(3).isPrimary());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetCustomLayout_coordinatesIsWide() {
|
|
||||||
// given
|
|
||||||
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
|
||||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
|
||||||
editor.putString(
|
|
||||||
context.getString(R.string.stats_custom_layout_fields_key),
|
|
||||||
"walking;"
|
|
||||||
+ context.getString(R.string.stats_custom_layout_moving_time_key) + ",1,1;"
|
|
||||||
+ context.getString(R.string.stats_custom_layout_distance_key) + ",1,0;"
|
|
||||||
+ context.getString(R.string.stats_custom_layout_coordinates_key) + ",0,1;"
|
|
||||||
+ context.getString(R.string.stats_custom_layout_speed_key) + ",0,0;");
|
|
||||||
editor.apply();
|
|
||||||
|
|
||||||
// when
|
|
||||||
Layout layout = PreferencesUtils.getCustomLayout(sharedPreferences, context);
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertEquals(layout.getFields().size(), 4);
|
|
||||||
assertEquals(layout.getProfile(), "walking");
|
|
||||||
|
|
||||||
assertEquals(layout.getFields().get(0).getKey(), context.getString(R.string.stats_custom_layout_moving_time_key));
|
|
||||||
assertTrue(layout.getFields().get(0).isVisible());
|
|
||||||
assertTrue(layout.getFields().get(0).isPrimary());
|
|
||||||
|
|
||||||
assertEquals(layout.getFields().get(1).getKey(), context.getString(R.string.stats_custom_layout_distance_key));
|
|
||||||
assertTrue(layout.getFields().get(1).isVisible());
|
|
||||||
assertFalse(layout.getFields().get(1).isPrimary());
|
|
||||||
|
|
||||||
assertEquals(layout.getFields().get(2).getKey(), context.getString(R.string.stats_custom_layout_coordinates_key));
|
|
||||||
assertFalse(layout.getFields().get(2).isVisible());
|
|
||||||
assertTrue(layout.getFields().get(2).isPrimary());
|
|
||||||
assertTrue(layout.getFields().get(2).isWide());
|
|
||||||
|
|
||||||
assertEquals(layout.getFields().get(3).getKey(), context.getString(R.string.stats_custom_layout_speed_key));
|
|
||||||
assertFalse(layout.getFields().get(3).isVisible());
|
|
||||||
assertFalse(layout.getFields().get(3).isPrimary());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSetCustomLayout() {
|
|
||||||
// given
|
|
||||||
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
|
||||||
Layout layoutSrc = new Layout("road cycling");
|
|
||||||
layoutSrc.addField(new DataField(context.getString(R.string.stats_custom_layout_moving_time_key), context.getString(R.string.stats_moving_time), true, true, false));
|
|
||||||
layoutSrc.addField(new DataField(context.getString(R.string.stats_custom_layout_distance_key), context.getString(R.string.stats_distance), true, false, false));
|
|
||||||
layoutSrc.addField(new DataField(context.getString(R.string.stats_custom_layout_average_moving_speed_key), context.getString(R.string.stats_average_moving_speed), false, true, false));
|
|
||||||
layoutSrc.addField(new DataField(context.getString(R.string.stats_custom_layout_speed_key), context.getString(R.string.stats_speed), false, false, false));
|
|
||||||
|
|
||||||
// when
|
|
||||||
PreferencesUtils.setCustomLayout(sharedPreferences, context, layoutSrc);
|
|
||||||
|
|
||||||
// then
|
|
||||||
String csv = sharedPreferences.getString(context.getString(R.string.stats_custom_layout_fields_key), null);
|
|
||||||
assertNotNull(csv);
|
|
||||||
assertEquals(csv,
|
|
||||||
"road cycling;"
|
|
||||||
+ context.getString(R.string.stats_custom_layout_moving_time_key) + ",1,1;"
|
|
||||||
+ context.getString(R.string.stats_custom_layout_distance_key) + ",1,0;"
|
|
||||||
+ context.getString(R.string.stats_custom_layout_average_moving_speed_key) + ",0,1;"
|
|
||||||
+ context.getString(R.string.stats_custom_layout_speed_key) + ",0,0;");
|
|
||||||
|
|
||||||
Layout layoutDst = PreferencesUtils.getCustomLayout(sharedPreferences, context);
|
|
||||||
assertEquals(layoutSrc.getProfile(), layoutDst.getProfile());
|
|
||||||
assertEquals(layoutSrc.getFields().size(), layoutDst.getFields().size());
|
|
||||||
for (int i = 0; i < layoutSrc.getFields().size(); i++) {
|
|
||||||
assertEquals(layoutSrc.getFields().get(i).getKey(), layoutDst.getFields().get(i).getKey());
|
|
||||||
assertEquals(layoutSrc.getFields().get(i).isVisible(), layoutDst.getFields().get(i).isVisible());
|
|
||||||
assertEquals(layoutSrc.getFields().get(i).isPrimary(), layoutDst.getFields().get(i).isPrimary());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -11,8 +11,8 @@ import org.junit.Test;
|
|||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.content.data.DataField;
|
import de.dennisguse.opentracks.ui.customRecordingLayout.DataField;
|
||||||
import de.dennisguse.opentracks.content.data.Layout;
|
import de.dennisguse.opentracks.ui.customRecordingLayout.Layout;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class StatisticsUtilsTest extends TestCase {
|
public class StatisticsUtilsTest extends TestCase {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user