Compare commits
419 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1feb5cbb65 | |||
| 1d2fde6e69 | |||
| 20423121ee | |||
| ebf7b0a0c3 | |||
| 1189a07794 | |||
| 63e9041922 | |||
| 699be450b0 | |||
| 66b175c56c | |||
| 81a7aca4a0 | |||
| 065f42fbef | |||
| c92371b36a | |||
| 97c46183c3 | |||
| c02b8fab53 | |||
| 6540913d59 | |||
| b70c3be5af | |||
| 461f1c246b | |||
| 6d091dfa81 | |||
| 97ad6bc2f8 | |||
| 93ee8a53ed | |||
| bf9b6d6627 | |||
| 5f637952aa | |||
| 17de8cea6f | |||
| afea79476f | |||
| 7215a2def0 | |||
| b8d2d14d68 | |||
| a2b53c75f4 | |||
| 7a5f69d3a5 | |||
| 7fd9893560 | |||
| f209031df0 | |||
| 2dbab929ac | |||
| e9eb764d12 | |||
| 41a4a5527a | |||
| 4ded3c6bc8 | |||
| 51e573e475 | |||
| 98c3169929 | |||
| ff65a4d04f | |||
| 278f49dec8 | |||
| d444e1ca3c | |||
| 13e07696b9 | |||
| 23c3a4d651 | |||
| c9869bab0e | |||
| ecdb509371 | |||
| de376a84f8 | |||
| 9abd8bcaa6 | |||
| 8ddadb8e6d | |||
| 924ef3313e | |||
| 8cb68a6e64 | |||
| 23f47f10f8 | |||
| 251fa17487 | |||
| bae3373fe9 | |||
| 0a685a66e3 | |||
| 5ca9ca857a | |||
| d9dfa6d746 | |||
| 3a5220546e | |||
| 047d5c2340 | |||
| 725c21c0a1 | |||
| 7939e39fc1 | |||
| a133bd8f9e | |||
| 1f9790cba8 | |||
| a3ba1e1490 | |||
| accb30152f | |||
| dc7daa6e8c | |||
| 1d8e788d53 | |||
| 568b908b26 | |||
| 3ab63adb34 | |||
| 91692f345e | |||
| dbdb98a682 | |||
| df66cd5753 | |||
| 6e39dd37f8 | |||
| 7212f7be94 | |||
| 77fe494e6c | |||
| 2f491e8c10 | |||
| f4fe7b1ab3 | |||
| 7e444cbf31 | |||
| ed6ab9c53c | |||
| f91ca3154c | |||
| bbfab1b201 | |||
| 1f2e3bcf70 | |||
| d1f3791f97 | |||
| 490b95a001 | |||
| 12e6f03098 | |||
| d86f42e2e9 | |||
| 360d59d3de | |||
| b617420290 | |||
| 53b267150b | |||
| 0dfd55ed52 | |||
| daabd5381d | |||
| a842129e37 | |||
| e8b9c2bbc3 | |||
| e55924dae3 | |||
| e3a8143d58 | |||
| 30310bb874 | |||
| 9f377b172d | |||
| 23175902fb | |||
| 706bd8b01f | |||
| dc4ac07e11 | |||
| 5be4129ba9 | |||
| f75a48ccab | |||
| 2815aa4b62 | |||
| 0383b0e1c7 | |||
| 1601741495 | |||
| be1fae956b | |||
| c7557d80bb | |||
| ac28124664 | |||
| 1deaf7650e | |||
| 9074fa1b6c | |||
| 5721a615a2 | |||
| fadcf1cd41 | |||
| a50b1ac78e | |||
| 9a7d4fdb36 | |||
| 9fb51a689d | |||
| 65bda35001 | |||
| 443ded86a5 | |||
| 83b5ebb02c | |||
| 240d8f6b6c | |||
| 39c5422341 | |||
| 4893a2b743 | |||
| 3408ea97f4 | |||
| ddb17f61cb | |||
| bbe182cf82 | |||
| b7b7bdf19b | |||
| 5681938a9e | |||
| 74835dcef5 | |||
| ed0dc05366 | |||
| 653eb8320a | |||
| 54b9c4370b | |||
| fa9cb3903c | |||
| 0f1d8500d1 | |||
| 20d7fd2c03 | |||
| 1d838344dc | |||
| fd826199e2 | |||
| f485d90ef2 | |||
| ec39e67a09 | |||
| 1a86db0a8b | |||
| 6a1fada22f | |||
| 2898e06246 | |||
| 0d87c65b49 | |||
| 9b97cdfcd1 | |||
| 95feae846a | |||
| b09eeaede3 | |||
| 35dec1634c | |||
| e49a425106 | |||
| adbad04867 | |||
| 850bd2f887 | |||
| d240b457e2 | |||
| 6d800caab1 | |||
| 7bf153db39 | |||
| 1b69f29751 | |||
| dfc3837739 | |||
| 30e847866e | |||
| fbc902e830 | |||
| 208f1d71ba | |||
| 38a15a96b3 | |||
| 46f8753746 | |||
| 70bc8f33b1 | |||
| 6cd27ab096 | |||
| 5581b404f7 | |||
| 2ef74eb908 | |||
| 16c654141f | |||
| dfc785f2fd | |||
| f621cdf032 | |||
| 8b04d9c4a6 | |||
| 364b4702e3 | |||
| a98c16de28 | |||
| 881bf1982a | |||
| f340622977 | |||
| 194379295d | |||
| 901cffee97 | |||
| d93c2ec5f3 | |||
| 306522863a | |||
| e54d85e04d | |||
| cb30ad27c3 | |||
| 8685c9cc88 | |||
| a6f03d0f23 | |||
| e3c812b155 | |||
| f149de9ce3 | |||
| 3447dd2569 | |||
| b2b8c7fd54 | |||
| 486bcd0aec | |||
| c8a33201f5 | |||
| 4a37c2cc7e | |||
| d23db5bafd | |||
| ac528f9a10 | |||
| 256eadd49d | |||
| 64e58934a5 | |||
| 92dfadfdba | |||
| cbce70143b | |||
| f4b9e3159e | |||
| 928781391d | |||
| 05cd672464 | |||
| d3109bbc37 | |||
| eabdb7c721 | |||
| ad990e8cd7 | |||
| db3eef0104 | |||
| c4f1ba7962 | |||
| 7451fbd413 | |||
| b6c55de55a | |||
| dd3ee6d99e | |||
| bbb6a7c22c | |||
| dc1b50a7bf | |||
| 21bfb88e0b | |||
| aaab8adce9 | |||
| df502f835c | |||
| dd6a4cd153 | |||
| 76656997ef | |||
| 32070a0bd6 | |||
| b9420d4dde | |||
| 1b810e1294 | |||
| f16d59bff6 | |||
| b5bf3aadc5 | |||
| f6a27a1522 | |||
| 83758fcd72 | |||
| 070917bc0b | |||
| 543a04dfdd | |||
| b4d5eb0eec | |||
| 9f84cc4952 | |||
| 09fe35f1ca | |||
| 27e50b2dd9 | |||
| 971460848b | |||
| 8bc2937bb4 | |||
| 0e9b68c2a1 | |||
| ba298c2afb | |||
| 79f5ed4dc3 | |||
| bbb2f874ee | |||
| 9af3759b07 | |||
| 1f6fe6bf0c | |||
| 7b291e85d7 | |||
| 0f72066bc0 | |||
| 70e0e7b216 | |||
| 7e50bb1b6d | |||
| a3eb107068 | |||
| 6133ef121a | |||
| c6d24e9534 | |||
| 441d3f721f | |||
| 3c212e4bcc | |||
| 50eb71bc1f | |||
| 0806821b5f | |||
| 36d0f17953 | |||
| 700adb7972 | |||
| a156369f8b | |||
| c0f6dc511b | |||
| 63e1461eba | |||
| 804e5f10c8 | |||
| 6cc7271a41 | |||
| f66194189b | |||
| 5d97d6d492 | |||
| f3a308e669 | |||
| a230504925 | |||
| 90e19e282c | |||
| b585bfe44c | |||
| 475e04eeb4 | |||
| f89b2b0efb | |||
| b94f3c176b | |||
| d1d729d287 | |||
| e23bbcc405 | |||
| 4129985b0f | |||
| 5cb7b623d9 | |||
| 3c52efadd6 | |||
| 73b4977051 | |||
| 422c2c02ce | |||
| d692329975 | |||
| 931574bc11 | |||
| caddbd8501 | |||
| 8ece2c8612 | |||
| 3a219321d1 | |||
| 35cb924a17 | |||
| b67e5bbd20 | |||
| 1db275230e | |||
| 5ac72092fb | |||
| bdd9ded1e8 | |||
| 759aeb6ed6 | |||
| 12023d51ae | |||
| c426785b90 | |||
| 09d960c7a1 | |||
| f37fe4a503 | |||
| 013e56bef0 | |||
| d6835ba766 | |||
| d7890cbc81 | |||
| 2b6886c534 | |||
| e77590a125 | |||
| ca330b2d80 | |||
| 20f1524701 | |||
| 96b2a15643 | |||
| ad59392e02 | |||
| 29f92b887c | |||
| 46328211c2 | |||
| 3760130d1f | |||
| 1094827fac | |||
| 36fcb44af5 | |||
| a683fbac4b | |||
| 64ad9019d1 | |||
| 1e80d5c8a8 | |||
| ac765b1ee8 | |||
| 850c4f0a9a | |||
| 4c32999752 | |||
| 76823b167a | |||
| 9994cfd260 | |||
| 1750236474 | |||
| fed6e31f9e | |||
| 9bafc7d4a1 | |||
| be58b48d20 | |||
| 303abac980 | |||
| d1a459efc2 | |||
| 96069e6f09 | |||
| 301a721329 | |||
| e8c6801a32 | |||
| 355f3ef614 | |||
| eaa6083586 | |||
| a0c5d02c51 | |||
| 76f9f5fc82 | |||
| 8e2598e93b | |||
| c0672c41df | |||
| 4c6601fbc5 | |||
| b99c87d1bd | |||
| 66ffbfe951 | |||
| 8cb01a1027 | |||
| 193e5eccbb | |||
| bf7fc28bb0 | |||
| e35cbc343a | |||
| 1c7b053c8c | |||
| 88cdcd4b47 | |||
| 1432fed8f9 | |||
| a14307b9a4 | |||
| 3bdce5aa08 | |||
| d7526f93b8 | |||
| 8932578b90 | |||
| 631ac9881d | |||
| 78334ed797 | |||
| b06da89654 | |||
| d6c2e78993 | |||
| 67d1ac551d | |||
| dcb6be717d | |||
| f2c04eec1a | |||
| a08311cf43 | |||
| 1e28f3aa86 | |||
| 426af41f2c | |||
| fd08a219f9 | |||
| 25b6aec0e9 | |||
| 3e40209d15 | |||
| 54ff94f905 | |||
| 7a4faf6b0d | |||
| 8922b00a5f | |||
| 702efa8693 | |||
| e7a8c897a3 | |||
| c59d1d87bd | |||
| a706efb8b3 | |||
| e391e83a00 | |||
| 2940bf20d8 | |||
| 081db5a58b | |||
| b34805272f | |||
| 98443dba99 | |||
| dd6e733d8c | |||
| 92d3439c3b | |||
| bd155cd600 | |||
| e14e53c0ae | |||
| 77a6a63174 | |||
| 40f2463f09 | |||
| e5d1048c8d | |||
| bf3b529fb2 | |||
| d0fde46027 | |||
| 0f348dff10 | |||
| d3f5080e73 | |||
| a453c8ec1e | |||
| 2a60aa8f59 | |||
| 41e7870509 | |||
| 57f66b77ab | |||
| 53572406e9 | |||
| a288255ab1 | |||
| 353c958ae0 | |||
| bc5ab0d7e5 | |||
| 9d915b5640 | |||
| 3aaee270eb | |||
| d53a7156e2 | |||
| 3af24ea3d0 | |||
| 5483212b06 | |||
| 419279fe5e | |||
| 501e899b27 | |||
| 3bb9edb009 | |||
| e52b1188a3 | |||
| 9e877e4762 | |||
| 5711757110 | |||
| e1c33dad43 | |||
| 4b2400774c | |||
| afd4a59622 | |||
| bdce437470 | |||
| 33479cda11 | |||
| 385cee3dc7 | |||
| d0bbd7655b | |||
| a83b8f62fe | |||
| 0cd9176703 | |||
| d8e526923d | |||
| 3a6f417662 | |||
| 7d807a7f11 | |||
| e9d5718495 | |||
| 0dd7f74a11 | |||
| 9bd4ba489c | |||
| dd55b50dad | |||
| 1719d21a5b | |||
| 75ef8d99d4 | |||
| ae06fd1680 | |||
| 2b03f7dea8 | |||
| 7591b012b4 | |||
| 0e089f49f3 | |||
| 5ad1856b13 | |||
| 965dbbe829 | |||
| 262c9886df | |||
| ac5a9ea65d | |||
| ed9b4c8f3d | |||
| 209aa6a8a5 | |||
| 81ee6ac1fa | |||
| 024dd603cb | |||
| 50654c6baf | |||
| 8c9bf60fc6 | |||
| a83eb0b983 | |||
| ab3cbfea0f | |||
| c93e5ca1a6 | |||
| c2841092da | |||
| 8b11e1d611 | |||
| 6375a851b2 |
@@ -0,0 +1,4 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
liberapay: dennis.guse
|
||||||
|
custom: https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Report issues of OpenTracks features
|
||||||
|
title: ''
|
||||||
|
labels: potential bug
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
1. Go to '...'
|
||||||
|
2. Click on '....'
|
||||||
|
3. Scroll down to '....'
|
||||||
|
4. See error
|
||||||
|
|
||||||
|
If applicable:
|
||||||
|
* add screenshots
|
||||||
|
* add logcat output
|
||||||
|
|
||||||
|
**Technical information**
|
||||||
|
- Device: [e.g. Nexus 7 (2013)]
|
||||||
|
- OS: [e.g. LineageOS 15.1]
|
||||||
|
- Version [e.g. v3.2.4]
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for OpenTracks
|
||||||
|
title: ''
|
||||||
|
labels: enhancement
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Is your feature request related to a problem? Please describe.**
|
||||||
|
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
|
|
||||||
|
**Describe the solution you'd like**
|
||||||
|
A clear and concise description of what you want to happen.
|
||||||
|
|
||||||
|
**Describe alternatives you've considered**
|
||||||
|
A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Add any other context or screenshots about the feature request here.
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# Thanks for your contribution.
|
||||||
|
|
||||||
|
**Describe the pull request**
|
||||||
|
A clear and concise description of what the pull request changes/adds.
|
||||||
|
|
||||||
|
**Link to the the issue**
|
||||||
|
(If available): The link to the issue that this pull request solves.
|
||||||
|
|
||||||
|
**License agreement**
|
||||||
|
By opening this pull request, you are providing your contribution under the _Apache License 2.0_ (see [LICENSE.md](LICENSE.md)).
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#https://github.com/marketplace/actions/android-emulator-runner
|
||||||
|
name: Test
|
||||||
|
on: [push, pull_request]
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: macos-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
api-level: [29]
|
||||||
|
target: [default]
|
||||||
|
steps:
|
||||||
|
- name: checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: run tests
|
||||||
|
uses: reactivecircus/android-emulator-runner@v2
|
||||||
|
with:
|
||||||
|
api-level: ${{ matrix.api-level }}
|
||||||
|
target: ${{ matrix.target }}
|
||||||
|
arch: x86_64
|
||||||
|
script: ./gradlew connectedCheck
|
||||||
@@ -45,19 +45,16 @@ captures/
|
|||||||
|
|
||||||
|
|
||||||
# IntelliJ IDEA
|
# IntelliJ IDEA
|
||||||
*.iml
|
|
||||||
*.iws
|
*.iws
|
||||||
/out/
|
/out/
|
||||||
|
|
||||||
# User-specific configurations
|
# User-specific configurations
|
||||||
.idea/.name
|
.idea/.name
|
||||||
.idea/assetWizardSettings.xml
|
|
||||||
.idea/caches/
|
.idea/caches/
|
||||||
.idea/compiler.xml
|
.idea/compiler.xml
|
||||||
.idea/copyright/profiles_settings.xml
|
.idea/copyright/profiles_settings.xml
|
||||||
.idea/dataSources.ids
|
.idea/dataSources.ids
|
||||||
.idea/datasources.xml
|
.idea/datasources.xml
|
||||||
.idea/dictionaries
|
|
||||||
.idea/dynamic.xml
|
.idea/dynamic.xml
|
||||||
.idea/encodings.xml
|
.idea/encodings.xml
|
||||||
.idea/jsLibraryMappings.xml
|
.idea/jsLibraryMappings.xml
|
||||||
@@ -67,14 +64,16 @@ captures/
|
|||||||
.idea/scopes/scope_settings.xml
|
.idea/scopes/scope_settings.xml
|
||||||
.idea/shelf/
|
.idea/shelf/
|
||||||
.idea/sqlDataSources.xml
|
.idea/sqlDataSources.xml
|
||||||
.idea/tasks.xml
|
|
||||||
.idea/vcs.xml
|
.idea/vcs.xml
|
||||||
.idea/uiDesigner.xml
|
.idea/uiDesigner.xml
|
||||||
.idea/workspace.xml
|
|
||||||
|
|
||||||
# Keystore files
|
# Keystore files
|
||||||
# Uncomment the following line if you do not want to check your keystore files in.
|
*.jks
|
||||||
#*.jks
|
|
||||||
|
|
||||||
# External native build folder generated in Android Studio 2.2 and later
|
# External native build folder generated in Android Studio 2.2 and later
|
||||||
.externalNativeBuild
|
.externalNativeBuild
|
||||||
|
|
||||||
|
# Fastlane
|
||||||
|
Appfile
|
||||||
|
releasePlayStore/*
|
||||||
|
Gemfile.lock
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="RenderSettings">
|
||||||
|
<option name="showDecorations" value="true" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
language: android
|
|
||||||
dist: trusty
|
|
||||||
|
|
||||||
android:
|
|
||||||
components:
|
|
||||||
- build-tools-28.0.3
|
|
||||||
- android-29
|
|
||||||
|
|
||||||
script:
|
|
||||||
- ./gradlew build
|
|
||||||
#TODO: When all tests are passing, CI should also execute them.
|
|
||||||
#- ./gradlew connectedCheck
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
# OpenTrack: Developer information
|
|
||||||
|
|
||||||
## Create releases for FDroid
|
|
||||||
|
|
||||||
1. Get next _version code_ (master branch): `git rev-list HEAD --count master`
|
|
||||||
2. Decide on _version name_ (semantic versioning)
|
|
||||||
3. Manually update _version code_ and _version name_ in `AndroidManifest.xml` (used by FDroid)
|
|
||||||
4. Create changelog (`_version code_.txt`)
|
|
||||||
5. Create commit with all changes
|
|
||||||
6. Push commits
|
|
||||||
7. Tag newly create commit with _version name_
|
|
||||||
8. Push the tagged to public repository
|
|
||||||
@@ -2,33 +2,78 @@
|
|||||||
|
|
||||||
_OpenTracks_ is a sport tracking application that completely respects your privacy.
|
_OpenTracks_ is a sport tracking application that completely respects your privacy.
|
||||||
|
|
||||||
<a href="https://f-droid.org/packages/de.dennisguse.opentracks">
|
<table>
|
||||||
<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" alt="Get it on F-Droid" height="60">
|
<tr>
|
||||||
</a>
|
<th>Free</th>
|
||||||
|
<th>Paid (same as free)</th>
|
||||||
|
<th>Donations</th>
|
||||||
|
<th>Translations</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="https://f-droid.org/packages/de.dennisguse.opentracks">
|
||||||
|
<img alt="Get it on F-Droid" src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" height="60" align="middle">
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://play.google.com/store/apps/details?id=de.dennisguse.opentracks.playstore">
|
||||||
|
<img alt="Get it on Google Play" src="https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png" height="60" align="middle">
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://liberapay.com/dennis.guse/donate">
|
||||||
|
<img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg" height="45" align="middle">
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="https://www.transifex.com/opentracks/opentracks/">
|
||||||
|
Transifex
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
## Features:
|
## Features:
|
||||||
* __Tracking:__ track your sport and outdoor activities
|
* __Tracking:__ track your sport and outdoor activities
|
||||||
* __Photos and Markers:__ mark interesting locations while tracking (also with photos)
|
* __Photos and Markers:__ mark interesting locations while tracking (also with photos)
|
||||||
* __Heart rate:__ supports bluetooth LE sensors
|
* __Bluetooth LE sensors:__
|
||||||
|
* heart rate
|
||||||
|
* cycling: speed and cadence
|
||||||
* __Export data:__ export tracks either as KMZ (incl. photos), KML or GPX
|
* __Export data:__ export tracks either as KMZ (incl. photos), KML or GPX
|
||||||
* __No Internet access:__ Internet is not used
|
* __No Internet access:__ Internet is not used
|
||||||
* __Voice annoucements__
|
* __Voice announcements__
|
||||||
* __No advertising__
|
* __No advertising__
|
||||||
* __Privacy:__
|
* __Privacy:__
|
||||||
* _does not contain any in-app analytics_
|
* _does not contain any in-app analytics_
|
||||||
* _does not have Google Play Services_
|
* _does not use Google Play Services_
|
||||||
* _has no cloud integration_
|
* _has no cloud integration_
|
||||||
|
|
||||||
__Only required permissions:__
|
__Only required permissions:__
|
||||||
* _ACCESS_FINE_LOCATION_: required to use the GPS.
|
* _ACCESS_FINE_LOCATION_: required to use the GPS.
|
||||||
|
|
||||||
_Please note:_
|
An overview of Bluetooth LE sensors that are known to work with OpenTracks is in [README_TESTED_SENSORS.md](README_TESTED_SENSORS.md).
|
||||||
_Tracks_ does not contain a _map_ (as this would required Internet access).
|
|
||||||
To show your tracks on a map, a 3rd party application (e.g., [OsmAnd](https://play.google.com/store/apps/details?id=net.osmand) or [MAPS.ME](https://play.google.com/store/apps/details?id=com.mapswithme.maps.pro)) needs to be installed.
|
|
||||||
|
|
||||||
<a href="https://liberapay.com/dennis.guse/donate">
|
_Please note:_
|
||||||
<img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg" height="45">
|
_OpenTracks_ does not contain a _map_ (as this would required Internet access).
|
||||||
</a>
|
|
||||||
|
## Custom Dashboards (incl. Map)
|
||||||
|
As of v3.3.1 OpenTracks enables to use custom dashboards.
|
||||||
|
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).
|
||||||
|
|
||||||
|
Alternatively, recorded tracks can be shared as KMZ/GPX to installed applications (e.g., [OsmAnd](https://play.google.com/store/apps/details?id=net.osmand) or [MAPS.ME](https://play.google.com/store/apps/details?id=com.mapswithme.maps.pro)).
|
||||||
|
However, this is rather slow and does not provide updates while recording.
|
||||||
|
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
<div>
|
||||||
|
<img width="15%" src="fastlane/metadata/android/en-US/phoneScreenshots/screenshot_1.png">
|
||||||
|
<img width="15%" src="fastlane/metadata/android/en-US/phoneScreenshots/screenshot_2.png">
|
||||||
|
<img width="15%" src="fastlane/metadata/android/en-US/phoneScreenshots/screenshot_3.png">
|
||||||
|
<img width="15%" src="fastlane/metadata/android/en-US/phoneScreenshots/screenshot_4.png">
|
||||||
|
<img width="15%" src="fastlane/metadata/android/en-US/phoneScreenshots/screenshot_5.png">
|
||||||
|
<img width="15%" src="fastlane/metadata/android/en-US/phoneScreenshots/screenshot_6.png">
|
||||||
|
</div>
|
||||||
|
|
||||||
## Project history
|
## Project history
|
||||||
|
|
||||||
@@ -48,7 +93,7 @@ Rework of _OpenTracks_ included:
|
|||||||
* removing calorie estimation and activity estimation,
|
* removing calorie estimation and activity estimation,
|
||||||
* removing support for ANT+ and Classic Bluetooth,
|
* removing support for ANT+ and Classic Bluetooth,
|
||||||
* adding support for Bluetooth LE heart rate sensors,
|
* adding support for Bluetooth LE heart rate sensors,
|
||||||
* removing Protobuf (store sensor data in SQLite columns directly), and
|
* removing Protobuf (store sensosensorr data in SQLite columns directly), and
|
||||||
* removing Android Service API for other apps.
|
* removing Android Service API for other apps.
|
||||||
|
|
||||||
Artwork, logos and user interface remained more or less unchanged.
|
Artwork, logos and user interface remained more or less unchanged.
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# OpenTracks Data API
|
||||||
|
|
||||||
|
## Reason
|
||||||
|
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).
|
||||||
|
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.
|
||||||
|
In fact, the later 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.
|
||||||
|
|
||||||
|
## Implementation
|
||||||
|
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.
|
||||||
|
For each, one URI is provided.
|
||||||
|
These URIs notify observers if on content changes (e.g., a new `TrackPoint` was added).
|
||||||
|
|
||||||
|
Limitations:
|
||||||
|
* only tracks selected by the user are exposed,
|
||||||
|
* `Waypoints` are not exposed,
|
||||||
|
* access is only granted temporarily and automatically revoked (see `FLAG_GRANT_READ_URI_PERMISSION`),
|
||||||
|
* no write access is possible, and
|
||||||
|
* neither track recordings can be started, paused, or stopped.
|
||||||
|
|
||||||
|
All required information can be found in `IntentDashboardUtils.java`.
|
||||||
|
|
||||||
|
A _reference implementation_ is the [OSMDashboard](https://github.com/OpenTracksApp/OSMDashboard).
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# OpenTracks: Developer information
|
||||||
|
|
||||||
|
## Craft new releases
|
||||||
|
|
||||||
|
1. Get next _version code_ (main): `git rev-list HEAD --count main`
|
||||||
|
2. Decide on _version name_ (semantic versioning)
|
||||||
|
3. Manually update _version code_ and _version name_ in `build.gradle`
|
||||||
|
4. Create changelog (`_version code_.txt`)
|
||||||
|
5. Create commit with all changes
|
||||||
|
6. Tag newly create commit with _version name_ (e.g., v3.2.1)
|
||||||
|
7. Push commits and tags to public repository
|
||||||
|
8. Add changelog to tag (Github releases)
|
||||||
|
|
||||||
|
## F-Droid
|
||||||
|
Application id: de.dennisguse.opentracks
|
||||||
|
|
||||||
|
It if it properly tagged F-Droid takes care of building the app and publishing.
|
||||||
|
Usually, it takes two days before the update is published (build, signed, and published).
|
||||||
|
|
||||||
|
The recent build activity can be found [here](https://f-droid.org/wiki/index.php?title=Special:RecentChanges&days=7&from=&hidebots=0&hideanons=1&hideliu=1&limit=500)
|
||||||
|
|
||||||
|
## Google Play Store
|
||||||
|
Application id: de.dennisguse.opentracks.playstore
|
||||||
|
|
||||||
|
Requirement: `gem install fastlane`
|
||||||
|
|
||||||
|
1. Build signed apk
|
||||||
|
(requires keystore)
|
||||||
|
2. Upload signed apk to [Google Play Console](https://play.google.com/apps/publish)
|
||||||
|
3. Update store meta data (e.g., description and screenshots)
|
||||||
|
`fastlane supply --version_code VERSION_CODE --skip_upload_apk`
|
||||||
|
(use the version code from the manifest)
|
||||||
|
(requires API key)
|
||||||
|
|
||||||
|
## Translations (localization)
|
||||||
|
|
||||||
|
Translations of the OpenTracks are handled in Transifex: [https://www.transifex.com/opentracks](https://www.transifex.com/opentracks/).
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Overview of tested Bluetooth LE sensors
|
||||||
|
|
||||||
|
## HRS: Heartrate Service
|
||||||
|
* Decathlon|Geonaute|Kalenji Dual HRM Belt
|
||||||
|
* Polar H7
|
||||||
|
* Polar OH1
|
||||||
|
Has updatable firmware that requires a user account at polar.com
|
||||||
|
* Wahoo Tickr (Model: WFBTHR02)
|
||||||
|
|
||||||
|
## CSCP: Cycling Cadence and Speed Service
|
||||||
|
Please note that the according to the specification these sensors _may_ provide speed as well as cadence.
|
||||||
|
However, often only one value is provided.
|
||||||
|
|
||||||
|
### Speed
|
||||||
|
* Wahoo Speed (Model: WFRPMSPD)
|
||||||
|
|
||||||
|
### Cadence
|
||||||
|
* Wahoo Cadence (Model: WFPODCAD2)
|
||||||
|
This sensor reports cadence data as speed.
|
||||||
|
A workaround is in place.
|
||||||
@@ -6,7 +6,7 @@ buildscript {
|
|||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.5.0'
|
classpath 'com.android.tools.build:gradle:4.0.1'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,28 +17,18 @@ allprojects {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def getVersionCode = { ->
|
|
||||||
try {
|
|
||||||
def stdout = new ByteArrayOutputStream()
|
|
||||||
exec {
|
|
||||||
commandLine 'git', 'rev-list', 'HEAD', '--count'
|
|
||||||
standardOutput = stdout
|
|
||||||
}
|
|
||||||
return Integer.parseInt(stdout.toString().trim())
|
|
||||||
}
|
|
||||||
catch (ignored) {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def getVersionName = { ->
|
def getVersionName = { ->
|
||||||
try {
|
try {
|
||||||
def stdout = new ByteArrayOutputStream()
|
def stdout = new ByteArrayOutputStream()
|
||||||
exec {
|
exec {
|
||||||
commandLine 'git', 'describe', '--tags', '--dirty'
|
commandLine 'git', 'describe', '--tags'
|
||||||
standardOutput = stdout
|
standardOutput = stdout
|
||||||
}
|
}
|
||||||
return stdout.toString().trim()
|
exec {
|
||||||
|
commandLine 'git', 'log', '--format="%h"', '-n 1'
|
||||||
|
standardOutput = stdout
|
||||||
|
}
|
||||||
|
return stdout.toString().replace('\n', '-').replace('"', '').trim()
|
||||||
}
|
}
|
||||||
catch (ignored) {
|
catch (ignored) {
|
||||||
return null
|
return null
|
||||||
@@ -46,17 +36,29 @@ def getVersionName = { ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 29
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
|
||||||
|
compileSdkVersion 30
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "de.dennisguse.opentracks"
|
applicationId "de.dennisguse.opentracks"
|
||||||
//Useful for debugging.
|
manifestPlaceholders = [
|
||||||
//versionCode getVersionCode()
|
applicationLogo: "@mipmap/ic_launcher",
|
||||||
|
applicationName: "@string/app_name"
|
||||||
|
]
|
||||||
|
|
||||||
|
versionCode 3474
|
||||||
|
versionName "v3.8.1"
|
||||||
|
|
||||||
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
|
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 29
|
targetSdkVersion 30
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
@@ -65,33 +67,37 @@ android {
|
|||||||
debug {
|
debug {
|
||||||
applicationIdSuffix ".debug"
|
applicationIdSuffix ".debug"
|
||||||
versionNameSuffix "-debug"
|
versionNameSuffix "-debug"
|
||||||
|
manifestPlaceholders = [
|
||||||
|
applicationLogo: "@mipmap/ic_launcher_debug",
|
||||||
|
applicationName: "OpenTracks (Debug)"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
release {
|
release {
|
||||||
minifyEnabled false
|
minifyEnabled false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
releasePlayStore {
|
||||||
|
applicationIdSuffix ".playstore"
|
||||||
|
versionNameSuffix "-PlayStore"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
applicationVariants.all { variant ->
|
applicationVariants.all { variant ->
|
||||||
variant.resValue "string", "applicationId", variant.applicationId
|
variant.resValue "string", "applicationId", variant.applicationId
|
||||||
}
|
}
|
||||||
|
|
||||||
lintOptions {
|
|
||||||
disable "AppCompatResource" // TODO Disable complaint to use androidx's SearchView as it is null.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||||
|
implementation 'androidx.preference:preference:1.1.1'
|
||||||
|
implementation 'androidx.documentfile:documentfile:1.0.1'
|
||||||
|
implementation 'com.google.android.material:material:1.1.0'
|
||||||
|
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
|
||||||
|
|
||||||
androidTestImplementation 'androidx.test:core:1.2.0'
|
androidTestImplementation 'androidx.test:core:1.2.0'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.2.0'
|
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||||
androidTestImplementation 'androidx.test:rules:1.2.0'
|
androidTestImplementation 'androidx.test:rules:1.2.0'
|
||||||
androidTestImplementation 'androidx.test:runner:1.2.0'
|
androidTestImplementation 'androidx.test:runner:1.2.0'
|
||||||
androidTestImplementation 'org.mockito:mockito-android:3.0.0'
|
androidTestImplementation 'org.mockito:mockito-android:3.4.4'
|
||||||
|
|
||||||
testImplementation 'androidx.test:core:1.2.0'
|
|
||||||
testImplementation 'org.mockito:mockito-core:3.0.0'
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
@startuml
|
||||||
|
title
|
||||||
|
State of OpenTracks
|
||||||
|
end title
|
||||||
|
|
||||||
|
legend right
|
||||||
|
SettingsActivity can be reached
|
||||||
|
from every activity showing a menu.
|
||||||
|
endlegend
|
||||||
|
|
||||||
|
[*] --> TrackListActivity
|
||||||
|
TrackListActivity --> TrackRecordingActivity : Start recording
|
||||||
|
TrackListActivity --> SearchListActivity
|
||||||
|
TrackListActivity --> MarkerListActivity : Show all markers
|
||||||
|
TrackListActivity --> AggregatedStatisticsActivity : Aggregated stats
|
||||||
|
TrackListActivity --> TrackRecordedActivity : Show track
|
||||||
|
TrackListActivity --> TrackDeleteActivity
|
||||||
|
|
||||||
|
SearchListActivity --> MarkerDetailActivity : Search result
|
||||||
|
SearchListActivity --> TrackRecordedActivity : Search result
|
||||||
|
|
||||||
|
TrackRecordedActivity --> TrackDeleteActivity
|
||||||
|
TrackRecordedActivity --> TrackEditActivity
|
||||||
|
TrackRecordedActivity --> MarkerListActivity
|
||||||
|
TrackRecordedActivity --> MarkerEditActivity : Add marker
|
||||||
|
TrackRecordedActivity --> CameraIntent : Add marker (with photo)
|
||||||
|
TrackRecordedActivity --> ShareFileIntent
|
||||||
|
TrackRecordedActivity --> DashboardIntent : Database cursor
|
||||||
|
TrackRecordedActivity --> TrackOnMapIntent : KMZ
|
||||||
|
TrackRecordedActivity --> TrackRecordingActivity
|
||||||
|
TrackRecordedActivity --> SettingsActivity
|
||||||
|
TrackRecordedActivity --> TrackListActivity : Back button
|
||||||
|
|
||||||
|
TrackRecordingActivity --> TrackOnMapIntent
|
||||||
|
TrackRecordingActivity --> MarkerEditActivity : Add marker
|
||||||
|
TrackRecordingActivity --> MarkerListActivity
|
||||||
|
TrackRecordingActivity --> TrackEditActivity
|
||||||
|
TrackRecordingActivity --> SettingsActivity
|
||||||
|
TrackRecordingActivity --> TrackRecordedActivity : Stop recording
|
||||||
|
TrackRecordingActivity --> TrackListActivity : Back button
|
||||||
|
|
||||||
|
MarkerListActivity --> MarkerDetailActivity
|
||||||
|
|
||||||
|
MarkerDetailActivity --> MarkerEditActivity
|
||||||
|
MarkerDetailActivity --> CoordinateOnMapIntent : URI
|
||||||
|
|
||||||
|
SettingsActivity --> AboutActivity
|
||||||
|
SettingsActivity --> HelpActivity
|
||||||
|
SettingsActivity --> ExportActivity
|
||||||
|
SettingsActivity --> DirectoryChooserActivity
|
||||||
|
SettingsActivity --> DirectoryChooserActivity
|
||||||
|
DirectoryChooserActivity$ImportDirectoryChooserActivity --> ImportActivity
|
||||||
|
DirectoryChooserActivity$ExportDirectoryChooserActivity --> ExportActivity
|
||||||
|
|
||||||
|
@enduml
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
@startuml
|
||||||
|
SensorManager --> ElevationSumManager
|
||||||
|
LocationManager --> TrackRecordingService
|
||||||
|
ElevationSumManager --> TrackRecordingService
|
||||||
|
|
||||||
|
TrackRecordingService --> TrackRecordingServiceConnection
|
||||||
|
TrackRecordingService --> Database
|
||||||
|
|
||||||
|
Database --> CustomContentProvider
|
||||||
|
CustomContentProvider --> TrackDataHub
|
||||||
|
CustomContentProvider --> ShareContentProvider
|
||||||
|
TrackDataHub --> StatisticsRecordingFragment : TrackPoints, TrackStatistics, Waypoints (push)
|
||||||
|
TrackDataHub --> StatisticsRecordedFragment : TrackPoints, TrackStatistics, Waypoints (push)
|
||||||
|
TrackDataHub --> ChartFragment --> ChartView
|
||||||
|
|
||||||
|
TrackRecordingServiceConnection --> StatisticsRecordingFragment : Sensor data (heartrate, cadence, elevation gain; pull 1s)
|
||||||
|
TrackRecordingServiceConnection --> TrackController : Start time (pull, onStart)
|
||||||
|
@enduml
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
@startuml
|
||||||
|
class Track {
|
||||||
|
-id
|
||||||
|
-name
|
||||||
|
-description
|
||||||
|
-category
|
||||||
|
-numberOfPoints
|
||||||
|
-icon
|
||||||
|
}
|
||||||
|
Track o-- TrackPoint
|
||||||
|
Track o-- Waypoint
|
||||||
|
Track "1" - "1" TripStatistics
|
||||||
|
|
||||||
|
class TripStatistics {
|
||||||
|
- startTime
|
||||||
|
- stopTime
|
||||||
|
- totalDistance
|
||||||
|
- totalTime
|
||||||
|
- movingTime
|
||||||
|
- maxSpeed
|
||||||
|
- totalElevationGain
|
||||||
|
}
|
||||||
|
|
||||||
|
class TrackPoint extends android.location.Location {
|
||||||
|
- id
|
||||||
|
- trackId
|
||||||
|
- longitude
|
||||||
|
- latitude
|
||||||
|
- time
|
||||||
|
- altitude
|
||||||
|
- accuracy
|
||||||
|
- speed
|
||||||
|
- bearing
|
||||||
|
- sensor_heartrate
|
||||||
|
- sensor_cadence
|
||||||
|
- sensor_power
|
||||||
|
}
|
||||||
|
|
||||||
|
class Waypoint {
|
||||||
|
- id
|
||||||
|
- trackId
|
||||||
|
- name
|
||||||
|
- description
|
||||||
|
- category
|
||||||
|
- icon
|
||||||
|
- length
|
||||||
|
- duration
|
||||||
|
- location
|
||||||
|
- tripStatistics
|
||||||
|
- photoUrl
|
||||||
|
}
|
||||||
|
@enduml
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
<rdf:RDF>
|
<rdf:RDF>
|
||||||
<cc:Work rdf:about="">
|
<cc:Work rdf:about="">
|
||||||
<dc:format>image/svg+xml</dc:format>
|
<dc:format>image/svg+xml</dc:format>
|
||||||
<dc:title></dc:title>
|
<dc:title />
|
||||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
</cc:Work>
|
</cc:Work>
|
||||||
</rdf:RDF>
|
</rdf:RDF>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
@@ -43,7 +43,7 @@
|
|||||||
<rdf:RDF>
|
<rdf:RDF>
|
||||||
<cc:Work rdf:about="">
|
<cc:Work rdf:about="">
|
||||||
<dc:format>image/svg+xml</dc:format>
|
<dc:format>image/svg+xml</dc:format>
|
||||||
<dc:title></dc:title>
|
<dc:title />
|
||||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
</cc:Work>
|
</cc:Work>
|
||||||
</rdf:RDF>
|
</rdf:RDF>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
@@ -41,7 +41,7 @@
|
|||||||
<rdf:RDF>
|
<rdf:RDF>
|
||||||
<cc:Work rdf:about="">
|
<cc:Work rdf:about="">
|
||||||
<dc:format>image/svg+xml</dc:format>
|
<dc:format>image/svg+xml</dc:format>
|
||||||
<dc:title></dc:title>
|
<dc:title />
|
||||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
</cc:Work>
|
</cc:Work>
|
||||||
</rdf:RDF>
|
</rdf:RDF>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
@@ -33,7 +33,7 @@
|
|||||||
<rdf:RDF>
|
<rdf:RDF>
|
||||||
<cc:Work rdf:about="">
|
<cc:Work rdf:about="">
|
||||||
<dc:format>image/svg+xml</dc:format>
|
<dc:format>image/svg+xml</dc:format>
|
||||||
<dc:title></dc:title>
|
<dc:title />
|
||||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
</cc:Work>
|
</cc:Work>
|
||||||
</rdf:RDF>
|
</rdf:RDF>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
@@ -39,7 +39,7 @@
|
|||||||
<rdf:RDF>
|
<rdf:RDF>
|
||||||
<cc:Work rdf:about="">
|
<cc:Work rdf:about="">
|
||||||
<dc:format>image/svg+xml</dc:format>
|
<dc:format>image/svg+xml</dc:format>
|
||||||
<dc:title></dc:title>
|
<dc:title />
|
||||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
</cc:Work>
|
</cc:Work>
|
||||||
</rdf:RDF>
|
</rdf:RDF>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
@@ -0,0 +1,116 @@
|
|||||||
|
<?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:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="210mm"
|
||||||
|
height="297mm"
|
||||||
|
viewBox="0 0 210 297"
|
||||||
|
version="1.1"
|
||||||
|
id="svg8"
|
||||||
|
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||||
|
sodipodi:docname="ic_marker_orange_pushpin_with_shadow.svg">
|
||||||
|
<defs
|
||||||
|
id="defs2">
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient871"
|
||||||
|
|
||||||
|
x1="91.712517"
|
||||||
|
y1="266.48581"
|
||||||
|
x2="95.902588"
|
||||||
|
y2="266.72339"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="rotate(22.027833,208.46275,168.26892)"
|
||||||
|
|
||||||
|
|
||||||
|
>
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1"
|
||||||
|
offset="0"
|
||||||
|
id="stop867" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#898d8d;stop-opacity:1"
|
||||||
|
offset="1"
|
||||||
|
id="stop869" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1.0"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="0.49497475"
|
||||||
|
inkscape:cx="298.98541"
|
||||||
|
inkscape:cy="561.0427"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1012"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="1080"
|
||||||
|
inkscape:window-maximized="1" />
|
||||||
|
<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" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
inkscape:label="Ebene 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<path
|
||||||
|
d="m 108.52826,213.29755 a 56.035402,7.0061195 5.281088 0 0 -22.425508,2.5321 56.035402,7.0061195 5.281088 0 0 -0.233576,0.17697 l -0.206706,-0.0237 c -0.04471,0.11554 -0.07454,0.2314 -0.09612,0.34752 a 56.035402,7.0061195 5.281088 0 0 0.337963,1.58159 c 0.980726,1.70884 3.760629,3.46326 6.583579,5.2188 l -22.744347,15.50009 a 67.064653,11.556784 4.2275244 0 0 -39.967588,5.26867 67.064653,11.556784 4.2275244 0 0 -0.729154,0.57564 67.064653,11.556784 4.2275244 0 0 -2.754353,1.36358 67.064653,11.556784 4.2275244 0 0 38.908736,16.04324 l -32.176847,27.0646 52.228334,-24.74551 a 67.064653,11.556784 4.2275244 0 0 71.411147,-3.8186 67.064653,11.556784 4.2275244 0 0 0.72812,-0.57507 67.064653,11.556784 4.2275244 0 0 2.75539,-1.36415 67.064653,11.556784 4.2275244 0 0 -12.38374,-10.59818 40.033569,5.0733922 5.2502179 0 0 0.0563,-0.0369 40.033569,5.0733922 5.2502179 0 0 0.37672,-0.34325 l 22.45186,-15.30075 c 8.23597,-0.65161 17.65581,-1.47811 22.94433,-3.00957 a 56.035402,7.0061195 5.281088 0 0 2.65514,-1.03772 56.035402,7.0061195 5.281088 0 0 -46.08401,-12.26953 56.035402,7.0061195 5.281088 0 0 -41.6357,-2.54991 z"
|
||||||
|
style="fill:#333333;fill-opacity:0.49421525;stroke:#000000;stroke-width:0.138931px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.265501"
|
||||||
|
id="path839" />
|
||||||
|
<path
|
||||||
|
style="fill:url(#linearGradient871);fill-opacity:1;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.265501"
|
||||||
|
d="M 70.603317,174.30832 33.024148,288.94657 94.566672,183.19473 Z"
|
||||||
|
id="path865"
|
||||||
|
sodipodi:nodetypes="cccc" />
|
||||||
|
<ellipse
|
||||||
|
cx="144.42586"
|
||||||
|
cy="113.06232"
|
||||||
|
rx="70.318817"
|
||||||
|
ry="39.974442"
|
||||||
|
id="ellipse26"
|
||||||
|
style="fill:#d45500;fill-opacity:1;fill-rule:evenodd;stroke-width:0.264583"
|
||||||
|
transform="rotate(22.027833)" />
|
||||||
|
<ellipse
|
||||||
|
style="fill:#ff6600;fill-opacity:1;fill-rule:evenodd;stroke-width:0.264583"
|
||||||
|
id="ellipse30"
|
||||||
|
ry="39.974442"
|
||||||
|
rx="70.318817"
|
||||||
|
cy="105.23625"
|
||||||
|
cx="145.017"
|
||||||
|
transform="rotate(22.027833)" />
|
||||||
|
<path
|
||||||
|
id="rect28"
|
||||||
|
style="fill:#d45500;fill-opacity:1;fill-rule:evenodd;stroke-width:0.264583"
|
||||||
|
d="m 85.662408,24.322061 c -0.890996,8.350369 2.928035,17.133472 6.825491,25.923906 l -23.333902,57.672763 -0.730686,1.80598 0.248621,0.10059 a 42.43035,17.360788 22.027833 0 0 33.303948,30.10067 42.43035,17.360788 22.027833 0 0 44.86507,1.52585 l 0.13892,0.0562 0.24519,-0.60599 a 42.43035,17.360788 22.027833 0 0 0.59472,-1.15581 42.43035,17.360788 22.027833 0 0 0.37668,-1.24514 l 22.45185,-55.492655 c 9.28986,-2.66566 20.09069,-6.13552 24.76397,-13.17485 z" />
|
||||||
|
<ellipse
|
||||||
|
style="fill:#ff6600;fill-opacity:1;fill-rule:evenodd;stroke-width:0.264583"
|
||||||
|
id="path24"
|
||||||
|
ry="23.966745"
|
||||||
|
rx="59.409279"
|
||||||
|
cy="-10.262156"
|
||||||
|
cx="148.14029"
|
||||||
|
transform="rotate(22.027833)" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 5.0 KiB |
@@ -18,7 +18,7 @@
|
|||||||
<rdf:RDF>
|
<rdf:RDF>
|
||||||
<cc:Work rdf:about="">
|
<cc:Work rdf:about="">
|
||||||
<dc:format>image/svg+xml</dc:format>
|
<dc:format>image/svg+xml</dc:format>
|
||||||
<dc:title></dc:title>
|
<dc:title />
|
||||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
</cc:Work>
|
</cc:Work>
|
||||||
</rdf:RDF>
|
</rdf:RDF>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
@@ -21,7 +21,7 @@
|
|||||||
<rdf:RDF>
|
<rdf:RDF>
|
||||||
<cc:Work rdf:about="">
|
<cc:Work rdf:about="">
|
||||||
<dc:format>image/svg+xml</dc:format>
|
<dc:format>image/svg+xml</dc:format>
|
||||||
<dc:title></dc:title>
|
<dc:title />
|
||||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
</cc:Work>
|
</cc:Work>
|
||||||
</rdf:RDF>
|
</rdf:RDF>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
@@ -0,0 +1,38 @@
|
|||||||
|
# This file contains the fastlane.tools configuration
|
||||||
|
# You can find the documentation at https://docs.fastlane.tools
|
||||||
|
#
|
||||||
|
# For a list of all available actions, check out
|
||||||
|
#
|
||||||
|
# https://docs.fastlane.tools/actions
|
||||||
|
#
|
||||||
|
# For a list of all available plugins, check out
|
||||||
|
#
|
||||||
|
# https://docs.fastlane.tools/plugins/available-plugins
|
||||||
|
#
|
||||||
|
|
||||||
|
# Uncomment the line if you want fastlane to automatically update itself
|
||||||
|
# update_fastlane
|
||||||
|
|
||||||
|
default_platform(:android)
|
||||||
|
|
||||||
|
platform :android do
|
||||||
|
desc "Runs all the tests"
|
||||||
|
lane :test do
|
||||||
|
gradle(task: "test")
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "Submit a new Beta Build to Crashlytics Beta"
|
||||||
|
lane :beta do
|
||||||
|
gradle(task: "clean assembleRelease")
|
||||||
|
crashlytics
|
||||||
|
|
||||||
|
# sh "your_script.sh"
|
||||||
|
# You can also use other beta testing services here
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "Deploy a new version to the Google Play"
|
||||||
|
lane :deploy do
|
||||||
|
gradle(task: "clean assembleRelease")
|
||||||
|
upload_to_play_store
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
OpenTracks – ein GPS-Tracker, der deine Daten für sich behält.
|
||||||
|
Erfasst deine Kilometer, ohne dass es jemand anderes tut.
|
||||||
|
|
||||||
|
Funktionen & Features:
|
||||||
|
* zeichnet Sport und andere Outdooraktivitäten auf
|
||||||
|
* unterstützt das Markieren interessanter Orte, inkl. Foto-Funktion
|
||||||
|
* zeichnet deine Herzfrequenz auf (Bluetooth LE)
|
||||||
|
* nutze beim Radfahren deine Trittfrequenz- und Geschwindigkeitssensoren (Bluetooth LE)
|
||||||
|
* exportiert deine Daten als KML oder GPX
|
||||||
|
* funktioniert ganz ohne Internet
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
OpenTracks – ein GPS-Tracker, der deine Daten für sich behält.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
v3.2: OpenTracks
|
v3.2.0: OpenTracks
|
||||||
|
|
||||||
Changes:
|
Changes:
|
||||||
- Removed Widget
|
- Removed Widget
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
v3.2.1: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Settings are now on a single page
|
||||||
|
|
||||||
|
Developer:
|
||||||
|
- Settings moved to Androidx compat (uses fragments)
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
v3.2.2: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Removed aggregated stats
|
||||||
|
- Migrated to Material Design
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Fixed export of sensor data
|
||||||
|
- Fixed import of incomplete sensor data
|
||||||
|
|
||||||
|
Developer:
|
||||||
|
- Replaced actionbar with toolbar
|
||||||
|
- Migrated to androidx appcompat (incl. Material Design)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
v3.2.3: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Sharing: use Android Sharesheet
|
||||||
|
- Sharing: share multiple tracks as individual files
|
||||||
|
- Use Android ShareSheet
|
||||||
|
- Heart rate sensor (Bluetooth LE): automatic reconnect
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Heart rate sensor (Bluetooth LE): disconnect properly
|
||||||
|
- Heart rate wasn't always shown while recording
|
||||||
|
|
||||||
|
Developer:
|
||||||
|
- Enabled TravisCI instrumentation tests
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
v3.2.4: OpenTracks
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Settings activity crashes
|
||||||
|
Removed possibility to change voice/split frequency from the context menu
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
v3.2.5: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Disable activity change
|
||||||
|
- Add permission for Android 10: recording location data
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Fix reset settings
|
||||||
|
|
||||||
|
Developer:
|
||||||
|
- Preferences
|
||||||
|
- if Settings cannot be loaded reset all preferences
|
||||||
|
- moved access to preferences to PreferencesUtil
|
||||||
|
- moved default of preferences from code to xml
|
||||||
|
- use SummaryProvider
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
v3.2.6: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Heart rate monitor: scan for available devices
|
||||||
|
- Remove shortcut to Bluetooth settings
|
||||||
|
|
||||||
|
Developer:
|
||||||
|
- Preferences: moved default of preferences from code to xml
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
v3.2.7: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Notification show GPS accuracy
|
||||||
|
- Show heads-up notification if GPS accuracy drops beyond threshold
|
||||||
|
- Always show chart by time as well as by distance
|
||||||
|
- Added help (in Settings)
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- TrackDetailActivity: disabled non-working landscape mode (temporary)
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
v3.2.8: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Chart: zoom via gestures
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
- Export via KMZ did not export picture filenames correctly
|
||||||
|
- Sharing multiple tracks did not include KMZ files
|
||||||
|
- MarkerDetailActivity's UI was not shown
|
||||||
|
- Settings crashed if preference of heart rate was not initialized
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
v3.2.9: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Option to keep screen on while recording
|
||||||
|
- Markers: removed split markers completely
|
||||||
|
- Voice announcement now work without READ_PHONE_STATE permission
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
- Statistics: heart rate was not shown
|
||||||
|
- Statistics: time was briefly reset to 0s
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
v3.2.10: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- ChartView is not configurable anymore
|
||||||
|
- After reboot: removed automatic restart of an unfinished recording
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Speech announcements use MAY_DUCK (again)
|
||||||
|
- ChartView shows markers (again)
|
||||||
|
- Fixed landscape layout of TrackListActivity
|
||||||
|
- Request legacy file API behavior (necessary for Android 10)
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
v3.2.11: OpenTracks
|
||||||
|
|
||||||
|
Bug:
|
||||||
|
- Max speed is identical to avg speed
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Crash on heart rate sensor selection
|
||||||
|
|
||||||
|
Developer:
|
||||||
|
- Replaced TabHost by TabsLayout
|
||||||
|
- Removed special first waypoint
|
||||||
|
- Removed duplicate translations
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
v3.3.0: OpenTracks
|
||||||
|
|
||||||
|
Breaking changes:
|
||||||
|
- Pictures are now stored in app-private storage (do not show up other picture apps)
|
||||||
|
NOTE: Pictures taking with previous version cannot be shown
|
||||||
|
- Localization for Spanish (Latin America) only works on Android 7.0 or later
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Import/Export via Storage Access Framework (avoids READ/WRITE_EXTERNAL_STORAGE permission)
|
||||||
|
|
||||||
|
Developer:
|
||||||
|
- Cleaned internal data structures
|
||||||
|
- Use separate icons/app names for debug version
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
v3.3.1: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Android 10: on uninstall allow to keep app data
|
||||||
|
- Introduced Dashboard API: map icon can be used to open current track in external app
|
||||||
|
(requires installation of another app like OSMDashboard)
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- App label was broken (introduced in v3.3.0)
|
||||||
|
|
||||||
|
Developer:
|
||||||
|
- Documentation for Dashboard API can be found in README_DEVELOPER.md
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
v3.3.2: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Export: overwrites files now
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Always remove recording notification
|
||||||
|
|
||||||
|
Developer:
|
||||||
|
- On API 26+ java.time is used for parsing and writing dates
|
||||||
|
- Refactoring of TrackRecordingService
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
v3.4.0: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Dashboard API: multiple tracks
|
||||||
|
- Updated help
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Fixed crash on fragment re-creation
|
||||||
|
- When paused: prevent stopping app
|
||||||
|
|
||||||
|
Developer:
|
||||||
|
- Enable testing via CI (Github Actions and TravisCI)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
v3.5.0: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Marker: select pictures from gallery
|
||||||
|
- Marker: share picture
|
||||||
|
- Use track name as filename when sharing
|
||||||
|
- Removed elevation min/max (was imprecise)
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Charts use preferred units and rate
|
||||||
|
|
||||||
|
Developer:
|
||||||
|
- Database: remove unused columns
|
||||||
|
- Database: add indices
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
v3.6.0: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Stopped tracks can now be resumed
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Import of KMZ did not process the photo URL correctly
|
||||||
|
|
||||||
|
Developer:
|
||||||
|
- Simplified data processing
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
v3.6.1: OpenTracks
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- KMZ import: store correct picture path
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
v3.6.2: OpenTracks
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Charts were not shown correctly (introduced in v3.6.0)
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
v3.7.0: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Report speed/pace by activity type
|
||||||
|
- Added workaround for GPS week rollover
|
||||||
|
- (Experimental) Support for Bluetooth LE cycling sensors (cadence and speed)
|
||||||
|
- KMZ/KML import enhanced
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- KMZ import: only import used images
|
||||||
|
|
||||||
|
Developer:
|
||||||
|
- Refactored TrackRecordingService
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
v3.7.1: OpenTracks
|
||||||
|
|
||||||
|
Workaround:
|
||||||
|
- Hide start GPS button
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Fixed null pointer
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
v3.7.2: OpenTracks
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Re-added start GPS button
|
||||||
|
- Track name is not overwritten at the end of a recording
|
||||||
|
- Markers: removing a photo also deletes the file
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
v3.7.3: OpenTracks
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Fixed computation of cadence and speed (via Bluetooth LE sensor)
|
||||||
|
|
||||||
|
Developer:
|
||||||
|
- Removed unused translations
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
v3.7.4: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Sharing/export format configurable
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- Wheel diameter not stored correctly (for speed sensor)
|
||||||
|
- Help: links are clickable
|
||||||
|
|
||||||
|
Developer:
|
||||||
|
- Split TrackDetailActivity
|
||||||
|
- StatsFragement successor uses ConstraintLayout
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
v3.7.5: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Added aggregated statistics summary (from main the screen's menu)
|
||||||
|
- Dashboard API: pass "show on lock screen"- and "keep screen on"-setting
|
||||||
|
- Updated translations
|
||||||
|
- Import: be lenient with ISO8601 date format
|
||||||
|
- Show track on map: file format can be selected and opening dashboard works on Android R (API 30+)
|
||||||
|
|
||||||
|
Bugfix:
|
||||||
|
- App icon now correctly implemented
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
v3.7.6: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Landscape mode
|
||||||
|
- Track deletion UI is now only a spinner
|
||||||
|
- Speed is exported and imported (GPX/KML/KMZ)
|
||||||
|
- Default export format is KMZ incl. all data and pictures
|
||||||
|
|
||||||
|
Developer:
|
||||||
|
- Replaced AsyncTasks with Threads
|
||||||
|
- Synchronization: UUID is generated per track (not yet exported)
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
v3.8.0: OpenTracks
|
||||||
|
|
||||||
|
Breaking change:
|
||||||
|
- GPX import/export speed, cadence, and heartrate via TrackPointExtension/v2
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- Dashboard API: provide access to markers (incl. callback to show in OpenTracks)
|
||||||
|
- New marker icon (orange push pin, SVG)
|
||||||
|
- Files to import can be selected via file manager
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
- Aggregated stats UI respects preferred rate
|
||||||
|
- Editing a marker failed on orientation change
|
||||||
|
|
||||||
|
Developer:
|
||||||
|
- Refactored TrackRecordingService
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
v3.8.1: OpenTracks
|
||||||
|
|
||||||
|
Changes:
|
||||||
|
- While recording: add option for fullscreen
|
||||||
|
- Dashboard is started on the same task
|
||||||
|
|
||||||
|
Bugfixes:
|
||||||
|
- Intent filters for importing files were far too optimistic
|
||||||
@@ -3,6 +3,8 @@ OpenTracks is a sport tracking application that completely respects your privacy
|
|||||||
Features:
|
Features:
|
||||||
* Sport tracking: track your sport and outdoor activities
|
* Sport tracking: track your sport and outdoor activities
|
||||||
* Photos and markers: mark interesting locations while tracking
|
* Photos and markers: mark interesting locations while tracking
|
||||||
* Heart rate: supports bluetooth LE sensors
|
* Supports Bluetooth LE sensors:
|
||||||
* Export data: Export tracks either as KML or GPX
|
* heart rate
|
||||||
|
* cycling: speed and cadence
|
||||||
|
* Export data: export tracks either as KML or GPX
|
||||||
* No Internet access: Internet is not used
|
* No Internet access: Internet is not used
|
||||||
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 104 KiB |
|
After Width: | Height: | Size: 184 KiB |
|
After Width: | Height: | Size: 237 KiB |
|
After Width: | Height: | Size: 129 KiB |
|
After Width: | Height: | Size: 174 KiB |
|
After Width: | Height: | Size: 168 KiB |
@@ -0,0 +1 @@
|
|||||||
|
OpenTracks
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
OpenTracks es un tracker deportivo que respeta tu privacidad.
|
||||||
|
|
||||||
|
Funciones:
|
||||||
|
* Tracker deportivo: haz un seguimiento de tus actividades al aire libre
|
||||||
|
* Marca lugares de interés, incluso agrega fotos a los marcadores
|
||||||
|
* Pulsómetro (compatible con dispositivos Bluetooth LE)
|
||||||
|
* Exporta tus rutas como KML o GPX
|
||||||
|
* Completamente offline, no necesitas internet
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
OpenTracks es un tracker deportivo que respeta tu privacidad.
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
OpenTracks
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
OpenTracks est une application de suivi d'activités sportives qui respecte totalement votre vie privée.
|
||||||
|
|
||||||
|
Fonctionnalités :
|
||||||
|
|
||||||
|
* Suivi d'activité : enregistre vos activités sportives et de plein air
|
||||||
|
* Photos et repères : ajout de photos et de repères pendant l'enregistrement de l'activité
|
||||||
|
* Rythme cardiaque : support des capteurs Bluetooth LE
|
||||||
|
* Export : export des traces au format KML ou GPX
|
||||||
|
* Pas d'accès internet requis : Internet n'est pas nécessaire pour le fonctionnement de l'application
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
OpenTracks - Suivi d'activités sportives respectueux de votre vie privée.
|
||||||
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 129 KiB |
|
Before Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 85 KiB |
@@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.5-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ esac
|
|||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
# Determine the Java command to use to start the JVM.
|
||||||
if [ -n "$JAVA_HOME" ] ; then
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
@@ -129,6 +130,7 @@ fi
|
|||||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
|
||||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
# We build the pattern for arguments to be converted via cygpath
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
@@ -154,19 +156,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
|||||||
else
|
else
|
||||||
eval `echo args$i`="\"$arg\""
|
eval `echo args$i`="\"$arg\""
|
||||||
fi
|
fi
|
||||||
i=$((i+1))
|
i=`expr $i + 1`
|
||||||
done
|
done
|
||||||
case $i in
|
case $i in
|
||||||
(0) set -- ;;
|
0) set -- ;;
|
||||||
(1) set -- "$args0" ;;
|
1) set -- "$args0" ;;
|
||||||
(2) set -- "$args0" "$args1" ;;
|
2) set -- "$args0" "$args1" ;;
|
||||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -175,14 +177,9 @@ save () {
|
|||||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
echo " "
|
echo " "
|
||||||
}
|
}
|
||||||
APP_ARGS=$(save "$@")
|
APP_ARGS=`save "$@"`
|
||||||
|
|
||||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||||
|
|
||||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
|
||||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
|
||||||
cd "$(dirname "$0")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec "$JAVACMD" "$@"
|
exec "$JAVACMD" "$@"
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
|
|||||||
set APP_BASE_NAME=%~n0
|
set APP_BASE_NAME=%~n0
|
||||||
set APP_HOME=%DIRNAME%
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
@@ -81,6 +84,7 @@ set CMD_LINE_ARGS=%*
|
|||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute Gradle
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||||
|
|
||||||
|
|||||||
|
After Width: | Height: | Size: 125 KiB |
@@ -1,103 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
* use this file except in compliance with the License. You may obtain a copy of
|
|
||||||
* the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
package de.dennisguse.opentracks;
|
|
||||||
|
|
||||||
import android.app.ActivityManager;
|
|
||||||
import android.app.ActivityManager.RunningServiceInfo;
|
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|
||||||
import androidx.test.platform.app.InstrumentationRegistry;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import de.dennisguse.opentracks.services.TrackRecordingService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for the BootReceiver.
|
|
||||||
*
|
|
||||||
* @author Youtao Liu
|
|
||||||
*/
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
public class BootReceiverTest {
|
|
||||||
private static final String SERVICE_NAME = "de.dennisguse.opentracks.services.TrackRecordingService";
|
|
||||||
|
|
||||||
private Context context = InstrumentationRegistry.getInstrumentation().getContext();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the behavior when receive notification which is the phone boot.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testOnReceive_startService() {
|
|
||||||
// Make sure no TrackRecordingService
|
|
||||||
Intent stopIntent = new Intent(context, TrackRecordingService.class);
|
|
||||||
context.stopService(stopIntent);
|
|
||||||
Assert.assertFalse(isServiceExisted(context));
|
|
||||||
|
|
||||||
BootReceiver bootReceiver = new BootReceiver();
|
|
||||||
Intent intent = new Intent();
|
|
||||||
intent.setAction(Intent.ACTION_BOOT_COMPLETED);
|
|
||||||
bootReceiver.onReceive(context, intent);
|
|
||||||
// Check if the service is started
|
|
||||||
Assert.assertFalse(isServiceExisted(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the behavior when receive notification which is not the phone boot.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testOnReceive_noStartService() {
|
|
||||||
// Make sure no TrackRecordingService
|
|
||||||
Intent stopIntent = new Intent(context, TrackRecordingService.class);
|
|
||||||
context.stopService(stopIntent);
|
|
||||||
Assert.assertFalse(isServiceExisted(context));
|
|
||||||
|
|
||||||
BootReceiver bootReceiver = new BootReceiver();
|
|
||||||
Intent intent = new Intent();
|
|
||||||
intent.setAction(Intent.ACTION_BUG_REPORT);
|
|
||||||
bootReceiver.onReceive(context, intent);
|
|
||||||
|
|
||||||
// Check if the service is not started
|
|
||||||
Assert.assertFalse(isServiceExisted(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a service is started in a context.
|
|
||||||
*
|
|
||||||
* @param context the context for checking a service
|
|
||||||
*/
|
|
||||||
private boolean isServiceExisted(Context context) {
|
|
||||||
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
|
||||||
Assert.assertNotNull(activityManager);
|
|
||||||
|
|
||||||
List<ActivityManager.RunningServiceInfo> serviceList = activityManager.getRunningServices(Integer.MAX_VALUE);
|
|
||||||
|
|
||||||
for (int i = 0; i < serviceList.size(); i++) {
|
|
||||||
RunningServiceInfo serviceInfo = serviceList.get(i);
|
|
||||||
ComponentName componentName = serviceInfo.service;
|
|
||||||
if (componentName.getClassName().equals(SERVICE_NAME)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -18,9 +18,7 @@ package de.dennisguse.opentracks;
|
|||||||
|
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.SensorDataSetLocation;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
import de.dennisguse.opentracks.content.Track;
|
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Commons utilities for creating stubs of track, location.
|
* Commons utilities for creating stubs of track, location.
|
||||||
@@ -37,50 +35,31 @@ public class TrackStubUtils {
|
|||||||
private static final float INITIAL_ACCURACY = 5;
|
private static final float INITIAL_ACCURACY = 5;
|
||||||
private static final float INITIAL_SPEED = 10;
|
private static final float INITIAL_SPEED = 10;
|
||||||
private static final float INITIAL_BEARING = 3.0f;
|
private static final float INITIAL_BEARING = 3.0f;
|
||||||
// Used to change the value of latitude, longitude, and altitude.
|
|
||||||
private static final double DIFFERENCE = 0.01;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a a {@link Track} stub with specified number of locations.
|
|
||||||
*
|
|
||||||
* @param numberOfLocations the number of locations for the track
|
|
||||||
* @return a track stub.
|
|
||||||
*/
|
|
||||||
public static Track createTrack(int numberOfLocations) {
|
|
||||||
Track track = new Track();
|
|
||||||
for (int i = 0; i < numberOfLocations; i++) {
|
|
||||||
track.addLocation(createSensorDataSetLocation(INITIAL_LATITUDE + i * DIFFERENCE, INITIAL_LONGITUDE + i * DIFFERENCE, INITIAL_ALTITUDE + i * DIFFERENCE));
|
|
||||||
}
|
|
||||||
|
|
||||||
return track;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a MyTracks location with default values.
|
* Create a MyTracks location with default values.
|
||||||
*
|
*
|
||||||
* @return a track stub.
|
* @return a track stub.
|
||||||
*/
|
*/
|
||||||
public static SensorDataSetLocation createSensorDataSetLocation() {
|
public static TrackPoint createDefaultTrackPoint() {
|
||||||
return createSensorDataSetLocation(INITIAL_LATITUDE, INITIAL_LONGITUDE, INITIAL_ALTITUDE);
|
return createDefaultTrackPoint(INITIAL_LATITUDE, INITIAL_LONGITUDE, INITIAL_ALTITUDE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link SensorDataSetLocation} stub with specified values.
|
* Creates a {@link TrackPoint} stub with specified values.
|
||||||
*
|
*
|
||||||
* @return a SensorDataSetLocation stub.
|
* @return a SensorDataSetLocation stub.
|
||||||
*/
|
*/
|
||||||
private static SensorDataSetLocation createSensorDataSetLocation(double latitude, double longitude, double altitude) {
|
private static TrackPoint createDefaultTrackPoint(double latitude, double longitude, double altitude) {
|
||||||
// Initial Location
|
Location location = new Location(LOCATION_PROVIDER);
|
||||||
Location loc = new Location(LOCATION_PROVIDER);
|
location.setLatitude(latitude);
|
||||||
loc.setLatitude(latitude);
|
location.setLongitude(longitude);
|
||||||
loc.setLongitude(longitude);
|
location.setAltitude(altitude);
|
||||||
loc.setAltitude(altitude);
|
location.setAccuracy(INITIAL_ACCURACY);
|
||||||
loc.setAccuracy(INITIAL_ACCURACY);
|
location.setSpeed(INITIAL_SPEED);
|
||||||
loc.setSpeed(INITIAL_SPEED);
|
location.setTime(INITIAL_TIME);
|
||||||
loc.setTime(INITIAL_TIME);
|
location.setBearing(INITIAL_BEARING);
|
||||||
loc.setBearing(INITIAL_BEARING);
|
|
||||||
SensorDataSet sd = new SensorDataSet(Float.NaN, Float.NaN);
|
|
||||||
|
|
||||||
return new SensorDataSetLocation(loc, sd);
|
return new TrackPoint(location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,9 @@
|
|||||||
* 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;
|
package de.dennisguse.opentracks.chart;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
@@ -23,6 +24,8 @@ import org.junit.Before;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.R;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link ChartValueSeries}.
|
* Tests {@link ChartValueSeries}.
|
||||||
*
|
*
|
||||||
@@ -42,7 +45,17 @@ public class ChartValueSeriesTest {
|
|||||||
R.string.description_elevation_metric,
|
R.string.description_elevation_metric,
|
||||||
R.string.description_elevation_imperial,
|
R.string.description_elevation_imperial,
|
||||||
R.color.chart_elevation_fill,
|
R.color.chart_elevation_fill,
|
||||||
R.color.chart_elevation_border);
|
R.color.chart_elevation_border) {
|
||||||
|
@Override
|
||||||
|
double extractDataFromChartPoint(@NonNull ChartPoint chartPoint) {
|
||||||
|
return chartPoint.getElevation();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean drawIfChartPointHasNoData() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -61,8 +74,8 @@ public class ChartValueSeriesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSmallUpdates() {
|
public void testSmallUpdates() {
|
||||||
series.update(0);
|
series.update(new ChartPoint(0));
|
||||||
series.update(10);
|
series.update(new ChartPoint(10));
|
||||||
series.updateDimension();
|
series.updateDimension();
|
||||||
Assert.assertEquals(100, series.getInterval());
|
Assert.assertEquals(100, series.getInterval());
|
||||||
Assert.assertEquals(0, series.getMinMarkerValue());
|
Assert.assertEquals(0, series.getMinMarkerValue());
|
||||||
@@ -71,8 +84,8 @@ public class ChartValueSeriesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBigUpdates() {
|
public void testBigUpdates() {
|
||||||
series.update(0);
|
series.update(new ChartPoint(0));
|
||||||
series.update(901);
|
series.update(new ChartPoint(901));
|
||||||
series.updateDimension();
|
series.updateDimension();
|
||||||
Assert.assertEquals(1000, series.getInterval());
|
Assert.assertEquals(1000, series.getInterval());
|
||||||
Assert.assertEquals(0, series.getMinMarkerValue());
|
Assert.assertEquals(0, series.getMinMarkerValue());
|
||||||
@@ -81,8 +94,8 @@ public class ChartValueSeriesTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNotZeroBasedUpdates() {
|
public void testNotZeroBasedUpdates() {
|
||||||
series.update(220);
|
series.update(new ChartPoint(220));
|
||||||
series.update(250);
|
series.update(new ChartPoint(250));
|
||||||
series.updateDimension();
|
series.updateDimension();
|
||||||
Assert.assertEquals(100, series.getInterval());
|
Assert.assertEquals(100, series.getInterval());
|
||||||
Assert.assertEquals(200, series.getMinMarkerValue());
|
Assert.assertEquals(200, series.getMinMarkerValue());
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012 Google Inc.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
||||||
* use this file except in compliance with the License. You may obtain a copy of
|
|
||||||
* the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
* License for the specific language governing permissions and limitations under
|
|
||||||
* the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package de.dennisguse.opentracks.content;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
|
||||||
import android.net.Uri;
|
|
||||||
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.CustomContentProvider.DatabaseHelper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link CustomContentProvider}.
|
|
||||||
*
|
|
||||||
* @author Youtao Liu
|
|
||||||
*/
|
|
||||||
public class CustomContentProviderTest {
|
|
||||||
|
|
||||||
private static final String DATABASE_NAME = "test.db";
|
|
||||||
|
|
||||||
private SQLiteDatabase db;
|
|
||||||
private CustomContentProvider customContentProvider;
|
|
||||||
private Context context = ApplicationProvider.getApplicationContext();
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() {
|
|
||||||
context.deleteDatabase(DATABASE_NAME);
|
|
||||||
db = (new DatabaseHelper(context, DATABASE_NAME)).getWritableDatabase();
|
|
||||||
customContentProvider = new CustomContentProvider() {
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link CustomContentProvider.DatabaseHelper#onCreate(SQLiteDatabase)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testDatabaseHelper_OnCreate() {
|
|
||||||
Assert.assertTrue(hasTable(TracksColumns.TABLE_NAME));
|
|
||||||
Assert.assertTrue(hasTable(TrackPointsColumns.TABLE_NAME));
|
|
||||||
Assert.assertTrue(hasTable(WaypointsColumns.TABLE_NAME));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link CustomContentProvider#onCreate(android.content.Context)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testOnCreate() {
|
|
||||||
Assert.assertTrue(customContentProvider.onCreate(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link CustomContentProvider#getType(Uri)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetType() {
|
|
||||||
Assert.assertEquals(TracksColumns.CONTENT_TYPE, customContentProvider.getType(TracksColumns.CONTENT_URI));
|
|
||||||
Assert.assertEquals(TrackPointsColumns.CONTENT_TYPE, customContentProvider.getType(TrackPointsColumns.CONTENT_URI));
|
|
||||||
Assert.assertEquals(WaypointsColumns.CONTENT_TYPE, customContentProvider.getType(WaypointsColumns.CONTENT_URI));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a table, containing one column.
|
|
||||||
*
|
|
||||||
* @param table the table name
|
|
||||||
*/
|
|
||||||
private void createTable(String table) {
|
|
||||||
db.execSQL("CREATE TABLE " + table + " (test INTEGER)");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Drops a table in database.
|
|
||||||
*
|
|
||||||
* @param table the table name
|
|
||||||
*/
|
|
||||||
private void dropTable(String table) {
|
|
||||||
db.execSQL("Drop TABLE " + table);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the table exists.
|
|
||||||
*
|
|
||||||
* @param table the table name
|
|
||||||
*/
|
|
||||||
private boolean hasTable(String table) {
|
|
||||||
try {
|
|
||||||
db.rawQuery("select count(*) from " + table, null);
|
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if the column in the table exists.
|
|
||||||
*
|
|
||||||
* @param table the table name
|
|
||||||
* @param column the column name
|
|
||||||
*/
|
|
||||||
private boolean hasColumn(String table, String column) {
|
|
||||||
try {
|
|
||||||
db.execSQL("SElECT count(*) from " + table + " order by " + column);
|
|
||||||
} catch (Exception e) {
|
|
||||||
if (e.getMessage().contains("no such column")) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets up upgrade.
|
|
||||||
*
|
|
||||||
* @param oldVersion thd old database version
|
|
||||||
*/
|
|
||||||
private void setupUpgrade(int oldVersion) {
|
|
||||||
dropTable(TracksColumns.TABLE_NAME);
|
|
||||||
dropTable(TrackPointsColumns.TABLE_NAME);
|
|
||||||
dropTable(WaypointsColumns.TABLE_NAME);
|
|
||||||
createTable(TracksColumns.TABLE_NAME);
|
|
||||||
createTable(TrackPointsColumns.TABLE_NAME);
|
|
||||||
createTable(WaypointsColumns.TABLE_NAME);
|
|
||||||
|
|
||||||
DatabaseHelper databaseHelper = new DatabaseHelper(context);
|
|
||||||
databaseHelper.onUpgrade(db, oldVersion, CustomContentProvider.DATABASE_VERSION);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,918 +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.content;
|
|
||||||
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.content.ContentUris;
|
|
||||||
import android.content.ContentValues;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.database.Cursor;
|
|
||||||
import android.location.Location;
|
|
||||||
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
|
||||||
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.ContentProviderUtils.LocationFactory;
|
|
||||||
import de.dennisguse.opentracks.content.ContentProviderUtils.LocationIterator;
|
|
||||||
import de.dennisguse.opentracks.content.Waypoint.WaypointType;
|
|
||||||
import de.dennisguse.opentracks.stats.TripStatistics;
|
|
||||||
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A unit test for {@link ContentProviderUtilsImpl}.
|
|
||||||
*
|
|
||||||
* @author Bartlomiej Niechwiej
|
|
||||||
* @author Youtao Liu
|
|
||||||
*/
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
|
||||||
public class CustomContentProviderUtilsImplTest {
|
|
||||||
private static final String NAME_PREFIX = "test name";
|
|
||||||
private static final String MOCK_DESC = "Mock Next Waypoint Desc!";
|
|
||||||
private static final String TEST_DESC = "Test Desc!";
|
|
||||||
private static final String TEST_DESC_NEW = "Test Desc new!";
|
|
||||||
private static final double INITIAL_LATITUDE = 37.0;
|
|
||||||
private static final double INITIAL_LONGITUDE = -57.0;
|
|
||||||
private static final double ALTITUDE_INTERVAL = 2.5;
|
|
||||||
|
|
||||||
private Context context = ApplicationProvider.getApplicationContext();
|
|
||||||
private ContentProviderUtils providerUtils;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private Cursor cursorMock;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private ContentResolver contentResolverMock;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setUp() {
|
|
||||||
providerUtils = ContentProviderUtils.Factory.get(context);
|
|
||||||
providerUtils.deleteAllTracks(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testLocationIterator_noPoints() {
|
|
||||||
testIterator(1, 0, 1, false, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testLocationIterator_customFactory() {
|
|
||||||
final Location location = new Location("test_location");
|
|
||||||
final AtomicInteger counter = new AtomicInteger();
|
|
||||||
testIterator(1, 15, 4, false, new LocationFactory() {
|
|
||||||
@Override
|
|
||||||
public Location createLocation() {
|
|
||||||
counter.incrementAndGet();
|
|
||||||
return location;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Make sure we were called exactly as many times as we had track points.
|
|
||||||
Assert.assertEquals(15, counter.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testLocationIterator_nullFactory() {
|
|
||||||
try {
|
|
||||||
testIterator(1, 15, 4, false, null);
|
|
||||||
Assert.fail("Expecting IllegalArgumentException");
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
// Expected.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testLocationIterator_noBatchAscending() {
|
|
||||||
testIterator(1, 50, 100, false, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
|
|
||||||
testIterator(2, 50, 50, false, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testLocationIterator_noBatchDescending() {
|
|
||||||
testIterator(1, 50, 100, true, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
|
|
||||||
testIterator(2, 50, 50, true, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testLocationIterator_batchAscending() {
|
|
||||||
testIterator(1, 50, 11, false, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
|
|
||||||
testIterator(2, 50, 25, false, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testLocationIterator_batchDescending() {
|
|
||||||
testIterator(1, 50, 11, true, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
|
|
||||||
testIterator(2, 50, 25, true, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testLocationIterator_largeTrack() {
|
|
||||||
testIterator(1, 20000, 2000, false, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Location> testIterator(long trackId, int numPoints, int batchSize, boolean descending, LocationFactory locationFactory) {
|
|
||||||
long lastPointId = initializeTrack(trackId, numPoints);
|
|
||||||
((ContentProviderUtilsImpl) providerUtils).setDefaultCursorBatchSize(batchSize);
|
|
||||||
List<Location> locations = new ArrayList<Location>(numPoints);
|
|
||||||
try (LocationIterator it = providerUtils.getTrackPointLocationIterator(trackId, -1L, descending, locationFactory)) {
|
|
||||||
while (it.hasNext()) {
|
|
||||||
Location loc = it.next();
|
|
||||||
Assert.assertNotNull(loc);
|
|
||||||
locations.add(loc);
|
|
||||||
// Make sure the IDs are returned in the right order.
|
|
||||||
Assert.assertEquals(descending ? lastPointId - locations.size() + 1
|
|
||||||
: lastPointId - numPoints + locations.size(), it.getLocationId());
|
|
||||||
}
|
|
||||||
Assert.assertEquals(numPoints, locations.size());
|
|
||||||
}
|
|
||||||
return locations;
|
|
||||||
}
|
|
||||||
|
|
||||||
private long initializeTrack(long id, int numPoints) {
|
|
||||||
Track track = new Track();
|
|
||||||
track.setId(id);
|
|
||||||
track.setName("Test: " + id);
|
|
||||||
track.setNumberOfPoints(numPoints);
|
|
||||||
providerUtils.insertTrack(track);
|
|
||||||
track = providerUtils.getTrack(id);
|
|
||||||
Assert.assertNotNull(track);
|
|
||||||
|
|
||||||
Location[] locations = new Location[numPoints];
|
|
||||||
for (int i = 0; i < numPoints; ++i) {
|
|
||||||
Location loc = new Location("test");
|
|
||||||
loc.setLatitude(37.0 + (double) i / 10000.0);
|
|
||||||
loc.setLongitude(57.0 - (double) i / 10000.0);
|
|
||||||
loc.setAccuracy((float) i / 100.0f);
|
|
||||||
loc.setAltitude(i * 2.5);
|
|
||||||
locations[i] = loc;
|
|
||||||
}
|
|
||||||
providerUtils.bulkInsertTrackPoint(locations, numPoints, id);
|
|
||||||
|
|
||||||
// Load all inserted locations.
|
|
||||||
long lastPointId = -1;
|
|
||||||
int counter = 0;
|
|
||||||
try (LocationIterator it = providerUtils.getTrackPointLocationIterator(id, -1L, false, ContentProviderUtils.DEFAULT_LOCATION_FACTORY)) {
|
|
||||||
while (it.hasNext()) {
|
|
||||||
it.next();
|
|
||||||
lastPointId = it.getLocationId();
|
|
||||||
counter++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.assertTrue(numPoints == 0 || lastPointId > 0);
|
|
||||||
Assert.assertEquals(numPoints, track.getNumberOfPoints());
|
|
||||||
Assert.assertEquals(numPoints, counter);
|
|
||||||
|
|
||||||
return lastPointId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link ContentProviderUtilsImpl#createTrack(Cursor)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testCreateTrack() {
|
|
||||||
int startColumnIndex = 1;
|
|
||||||
int columnIndex = startColumnIndex;
|
|
||||||
when(cursorMock.getColumnIndexOrThrow(TracksColumns._ID)).thenReturn(columnIndex++);
|
|
||||||
when(cursorMock.getColumnIndexOrThrow(TracksColumns.NAME)).thenReturn(columnIndex++);
|
|
||||||
columnIndex = startColumnIndex;
|
|
||||||
// Id
|
|
||||||
when(cursorMock.isNull(columnIndex++)).thenReturn(false);
|
|
||||||
// Name
|
|
||||||
when(cursorMock.isNull(columnIndex++)).thenReturn(false);
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
columnIndex = startColumnIndex;
|
|
||||||
// Id
|
|
||||||
when(cursorMock.getLong(columnIndex++)).thenReturn(trackId);
|
|
||||||
// Name
|
|
||||||
String name = NAME_PREFIX + trackId;
|
|
||||||
when(cursorMock.getString(columnIndex++)).thenReturn(name);
|
|
||||||
|
|
||||||
Track track = providerUtils.createTrack(cursorMock);
|
|
||||||
Assert.assertEquals(trackId, track.getId());
|
|
||||||
Assert.assertEquals(name, track.getName());
|
|
||||||
verify(cursorMock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link ContentProviderUtilsImpl#deleteAllTracks(Context)}
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testDeleteAllTracks() {
|
|
||||||
// Insert track, points and waypoint at first.
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
Track track = getTrack(trackId, 10);
|
|
||||||
insertTrackWithLocations(track);
|
|
||||||
Waypoint waypoint = new Waypoint();
|
|
||||||
providerUtils.insertWaypoint(waypoint);
|
|
||||||
ContentResolver contentResolver = context.getContentResolver();
|
|
||||||
Cursor tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
|
||||||
Assert.assertEquals(1, tracksCursor.getCount());
|
|
||||||
Cursor tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI, null, null, null, TrackPointsColumns._ID);
|
|
||||||
Assert.assertEquals(10, tracksPointsCursor.getCount());
|
|
||||||
Cursor waypointCursor = contentResolver.query(WaypointsColumns.CONTENT_URI, null, null, null, WaypointsColumns._ID);
|
|
||||||
Assert.assertEquals(1, waypointCursor.getCount());
|
|
||||||
// Delete all.
|
|
||||||
providerUtils.deleteAllTracks(context);
|
|
||||||
// Check whether all have been deleted.
|
|
||||||
tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
|
||||||
Assert.assertEquals(0, tracksCursor.getCount());
|
|
||||||
tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI, null, null, null, TrackPointsColumns._ID);
|
|
||||||
Assert.assertEquals(0, tracksPointsCursor.getCount());
|
|
||||||
waypointCursor = contentResolver.query(WaypointsColumns.CONTENT_URI, null, null, null, WaypointsColumns._ID);
|
|
||||||
Assert.assertEquals(0, waypointCursor.getCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link ContentProviderUtilsImpl#deleteTrack(Context, long)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testDeleteTrack() {
|
|
||||||
// Insert three tracks, points of two tracks and way point of one track.
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
Track track = getTrack(trackId, 10);
|
|
||||||
|
|
||||||
providerUtils.insertTrack(track);
|
|
||||||
insertTrackWithLocations(getTrack(trackId + 1, 10));
|
|
||||||
insertTrackWithLocations(getTrack(trackId + 2, 10));
|
|
||||||
|
|
||||||
Waypoint waypoint = new Waypoint();
|
|
||||||
waypoint.setTrackId(trackId);
|
|
||||||
providerUtils.insertWaypoint(waypoint);
|
|
||||||
|
|
||||||
ContentResolver contentResolver = context.getContentResolver();
|
|
||||||
Cursor tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
|
||||||
Assert.assertEquals(3, tracksCursor.getCount());
|
|
||||||
Cursor tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI, null, null, null, TrackPointsColumns._ID);
|
|
||||||
Assert.assertEquals(20, tracksPointsCursor.getCount());
|
|
||||||
Cursor waypointCursor = contentResolver.query(WaypointsColumns.CONTENT_URI, null, null, null, WaypointsColumns._ID);
|
|
||||||
Assert.assertEquals(1, waypointCursor.getCount());
|
|
||||||
// Delete one track.
|
|
||||||
providerUtils.deleteTrack(context, trackId);
|
|
||||||
// Check whether all data of a track has been deleted.
|
|
||||||
tracksCursor = contentResolver.query(TracksColumns.CONTENT_URI, null, null, null, TracksColumns._ID);
|
|
||||||
Assert.assertEquals(2, tracksCursor.getCount());
|
|
||||||
tracksPointsCursor = contentResolver.query(TrackPointsColumns.CONTENT_URI, null, null, null, TrackPointsColumns._ID);
|
|
||||||
Assert.assertEquals(20, tracksPointsCursor.getCount());
|
|
||||||
waypointCursor = contentResolver.query(WaypointsColumns.CONTENT_URI, null, null, null, WaypointsColumns._ID);
|
|
||||||
Assert.assertEquals(0, waypointCursor.getCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link ContentProviderUtilsImpl#getAllTracks()}
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetAllTracks() {
|
|
||||||
int initialTrackNumber = providerUtils.getAllTracks().size();
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
providerUtils.insertTrack(getTrack(trackId, 0));
|
|
||||||
List<Track> allTracks = providerUtils.getAllTracks();
|
|
||||||
Assert.assertEquals(initialTrackNumber + 1, allTracks.size());
|
|
||||||
Assert.assertEquals(trackId, allTracks.get(allTracks.size() - 1).getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link ContentProviderUtilsImpl#getLastTrack()}
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetLastTrack() {
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
providerUtils.insertTrack(getTrack(trackId, 0));
|
|
||||||
Assert.assertEquals(trackId, providerUtils.getLastTrack().getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link ContentProviderUtilsImpl#getTrack(long)}
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetTrack() {
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
providerUtils.insertTrack(getTrack(trackId, 0));
|
|
||||||
Assert.assertNotNull(providerUtils.getTrack(trackId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link ContentProviderUtilsImpl#updateTrack(Track)}
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testUpdateTrack() {
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
Track track = getTrack(trackId, 0);
|
|
||||||
String nameOld = "name1";
|
|
||||||
String nameNew = "name2";
|
|
||||||
track.setName(nameOld);
|
|
||||||
providerUtils.insertTrack(track);
|
|
||||||
Assert.assertEquals(nameOld, providerUtils.getTrack(trackId).getName());
|
|
||||||
track.setName(nameNew);
|
|
||||||
providerUtils.updateTrack(track);
|
|
||||||
Assert.assertEquals(nameNew, providerUtils.getTrack(trackId).getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link ContentProviderUtilsImpl#createContentValues(Waypoint)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testCreateContentValues_waypoint() {
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
Track track = getTrack(trackId, 10);
|
|
||||||
providerUtils.insertTrack(track);
|
|
||||||
// Bottom
|
|
||||||
long startTime = 1000L;
|
|
||||||
// AverageSpeed
|
|
||||||
double minGrade = -20.11;
|
|
||||||
TripStatistics statistics = new TripStatistics();
|
|
||||||
statistics.setStartTime(startTime);
|
|
||||||
statistics.setStopTime(2500L);
|
|
||||||
statistics.setTotalTime(1500L);
|
|
||||||
statistics.setMovingTime(700L);
|
|
||||||
statistics.setTotalDistance(750.0);
|
|
||||||
statistics.setTotalElevationGain(50.0);
|
|
||||||
statistics.setMaxSpeed(60.0);
|
|
||||||
statistics.setMaxElevation(1250.0);
|
|
||||||
statistics.setMinElevation(1200.0);
|
|
||||||
statistics.setMaxGrade(15.0);
|
|
||||||
statistics.setMinGrade(minGrade);
|
|
||||||
statistics.setBounds(-10000, 20000, 30000, -40000);
|
|
||||||
// Insert at first.
|
|
||||||
Waypoint waypoint = new Waypoint();
|
|
||||||
waypoint.setDescription(TEST_DESC);
|
|
||||||
waypoint.setType(WaypointType.STATISTICS);
|
|
||||||
waypoint.setTripStatistics(statistics);
|
|
||||||
|
|
||||||
Location location = new Location("test");
|
|
||||||
location.setLatitude(22);
|
|
||||||
location.setLongitude(22);
|
|
||||||
location.setAccuracy((float) 1 / 100.0f);
|
|
||||||
location.setAltitude(2.5);
|
|
||||||
waypoint.setLocation(location);
|
|
||||||
providerUtils.insertWaypoint(waypoint);
|
|
||||||
|
|
||||||
ContentProviderUtilsImpl contentProviderUtils = new ContentProviderUtilsImpl(contentResolverMock);
|
|
||||||
|
|
||||||
long waypointId = System.currentTimeMillis();
|
|
||||||
waypoint.setId(waypointId);
|
|
||||||
ContentValues contentValues = contentProviderUtils.createContentValues(waypoint);
|
|
||||||
Assert.assertEquals(waypointId, contentValues.get(WaypointsColumns._ID));
|
|
||||||
Assert.assertEquals(22 * 1000000, contentValues.get(WaypointsColumns.LONGITUDE));
|
|
||||||
Assert.assertEquals(TEST_DESC, contentValues.get(WaypointsColumns.DESCRIPTION));
|
|
||||||
Assert.assertEquals(startTime, contentValues.get(WaypointsColumns.STARTTIME));
|
|
||||||
Assert.assertEquals(minGrade, contentValues.get(WaypointsColumns.MINGRADE));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link ContentProviderUtilsImpl#createWaypoint(Cursor)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testCreateWaypoint() {
|
|
||||||
int startColumnIndex = 1;
|
|
||||||
int columnIndex = startColumnIndex;
|
|
||||||
when(cursorMock.getColumnIndexOrThrow(WaypointsColumns._ID)).thenReturn(columnIndex++);
|
|
||||||
when(cursorMock.getColumnIndexOrThrow(WaypointsColumns.NAME)).thenReturn(columnIndex++);
|
|
||||||
when(cursorMock.getColumnIndexOrThrow(WaypointsColumns.TRACKID)).thenReturn(columnIndex++);
|
|
||||||
columnIndex = startColumnIndex;
|
|
||||||
// Id
|
|
||||||
when(cursorMock.isNull(columnIndex++)).thenReturn(false);
|
|
||||||
// Name
|
|
||||||
when(cursorMock.isNull(columnIndex++)).thenReturn(false);
|
|
||||||
// trackIdIndex
|
|
||||||
when(cursorMock.isNull(columnIndex++)).thenReturn(false);
|
|
||||||
long id = System.currentTimeMillis();
|
|
||||||
columnIndex = startColumnIndex;
|
|
||||||
// Id
|
|
||||||
when(cursorMock.getLong(columnIndex++)).thenReturn(id);
|
|
||||||
// Name
|
|
||||||
String name = NAME_PREFIX + id;
|
|
||||||
when(cursorMock.getString(columnIndex++)).thenReturn(name);
|
|
||||||
// trackIdIndex
|
|
||||||
long trackId = 11L;
|
|
||||||
when(cursorMock.getLong(columnIndex++)).thenReturn(trackId);
|
|
||||||
|
|
||||||
Waypoint waypoint = providerUtils.createWaypoint(cursorMock);
|
|
||||||
Assert.assertEquals(id, waypoint.getId());
|
|
||||||
Assert.assertEquals(name, waypoint.getName());
|
|
||||||
Assert.assertEquals(trackId, waypoint.getTrackId());
|
|
||||||
verify(cursorMock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method
|
|
||||||
* {@link ContentProviderUtilsImpl#deleteWaypoint(Context, long, DescriptionGenerator)}
|
|
||||||
* when there is only one waypoint in the track.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testDeleteWaypoint_onlyOneWayPoint() {
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
Track track = getTrack(trackId, 10);
|
|
||||||
providerUtils.insertTrack(track);
|
|
||||||
|
|
||||||
// Insert at first.
|
|
||||||
Waypoint waypoint1 = new Waypoint();
|
|
||||||
waypoint1.setDescription(TEST_DESC);
|
|
||||||
waypoint1.setTrackId(trackId);
|
|
||||||
waypoint1.setType(WaypointType.STATISTICS);
|
|
||||||
providerUtils.insertWaypoint(waypoint1);
|
|
||||||
|
|
||||||
// Delete
|
|
||||||
DescriptionGenerator descriptionGenerator = new DescriptionGenerator() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String generateWaypointDescription(TripStatistics tripStatistics) {
|
|
||||||
return CustomContentProviderUtilsImplTest.MOCK_DESC;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String generateTrackDescription(Track aTrack, boolean html) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
providerUtils.deleteWaypoint(context, 1, descriptionGenerator);
|
|
||||||
|
|
||||||
Assert.assertNull(providerUtils.getWaypoint(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method
|
|
||||||
* {@link ContentProviderUtilsImpl#deleteWaypoint(Context, long, DescriptionGenerator)}
|
|
||||||
* when there is more than one waypoint in the track.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testDeleteWaypoint_hasNextWayPoint() {
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
Track track = getTrack(trackId, 10);
|
|
||||||
providerUtils.insertTrack(track);
|
|
||||||
|
|
||||||
TripStatistics statistics = new TripStatistics();
|
|
||||||
statistics.setStartTime(1000L);
|
|
||||||
statistics.setStopTime(2500L);
|
|
||||||
statistics.setTotalTime(1500L);
|
|
||||||
statistics.setMovingTime(700L);
|
|
||||||
statistics.setTotalDistance(750.0);
|
|
||||||
statistics.setTotalElevationGain(50.0);
|
|
||||||
statistics.setMaxSpeed(60.0);
|
|
||||||
statistics.setMaxElevation(1250.0);
|
|
||||||
statistics.setMinElevation(1200.0);
|
|
||||||
statistics.setMaxGrade(15.0);
|
|
||||||
statistics.setMinGrade(-25.0);
|
|
||||||
statistics.setBounds(-10000, 20000, 30000, -40000);
|
|
||||||
|
|
||||||
// Insert at first.
|
|
||||||
Waypoint waypoint1 = new Waypoint();
|
|
||||||
waypoint1.setDescription(Long.toString(trackId));
|
|
||||||
waypoint1.setTrackId(trackId);
|
|
||||||
waypoint1.setType(WaypointType.STATISTICS);
|
|
||||||
waypoint1.setTripStatistics(statistics);
|
|
||||||
long waypoint1Id = ContentUris.parseId(providerUtils.insertWaypoint(waypoint1));
|
|
||||||
|
|
||||||
Waypoint waypoint2 = new Waypoint();
|
|
||||||
waypoint2.setDescription(Long.toString(trackId));
|
|
||||||
waypoint2.setTrackId(trackId);
|
|
||||||
waypoint2.setType(WaypointType.STATISTICS);
|
|
||||||
waypoint2.setTripStatistics(statistics);
|
|
||||||
long waypoint2Id = ContentUris.parseId(providerUtils.insertWaypoint(waypoint2));
|
|
||||||
|
|
||||||
|
|
||||||
// Delete
|
|
||||||
DescriptionGenerator descriptionGenerator = new DescriptionGenerator() {
|
|
||||||
@Override
|
|
||||||
public String generateWaypointDescription(TripStatistics tripStatistics) {
|
|
||||||
return CustomContentProviderUtilsImplTest.MOCK_DESC;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String generateTrackDescription(Track aTrack, boolean html) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Assert.assertNotNull(providerUtils.getWaypoint(waypoint1Id));
|
|
||||||
providerUtils.deleteWaypoint(context, waypoint1Id, descriptionGenerator);
|
|
||||||
Assert.assertNull(providerUtils.getWaypoint(waypoint1Id));
|
|
||||||
|
|
||||||
Assert.assertEquals(CustomContentProviderUtilsImplTest.MOCK_DESC, providerUtils.getWaypoint(waypoint2Id)
|
|
||||||
.getDescription());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link ContentProviderUtilsImpl#getFirstWaypointId(long)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetFirstWaypointId() {
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
Track track = getTrack(trackId, 10);
|
|
||||||
providerUtils.insertTrack(track);
|
|
||||||
|
|
||||||
Waypoint waypoint1 = new Waypoint();
|
|
||||||
waypoint1.setTrackId(trackId);
|
|
||||||
long waypoint1id = ContentUris.parseId(providerUtils.insertWaypoint(waypoint1));
|
|
||||||
|
|
||||||
Waypoint waypoint2 = new Waypoint();
|
|
||||||
waypoint2.setTrackId(trackId);
|
|
||||||
long waypoint2id = ContentUris.parseId(providerUtils.insertWaypoint(waypoint2));
|
|
||||||
|
|
||||||
Assert.assertEquals(-1L, providerUtils.getFirstWaypointId(-1));
|
|
||||||
Assert.assertEquals(waypoint1id, providerUtils.getFirstWaypointId(trackId));
|
|
||||||
Assert.assertEquals(waypoint2id, providerUtils.getLastWaypoint(trackId, WaypointType.WAYPOINT).getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link ContentProviderUtilsImpl#getNextWaypointNumber(long, WaypointType)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetNextWaypointNumber() {
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
Track track = getTrack(trackId, 10);
|
|
||||||
providerUtils.insertTrack(track);
|
|
||||||
|
|
||||||
Waypoint waypoint1 = new Waypoint();
|
|
||||||
waypoint1.setType(WaypointType.STATISTICS);
|
|
||||||
waypoint1.setTrackId(trackId);
|
|
||||||
Waypoint waypoint2 = new Waypoint();
|
|
||||||
waypoint2.setType(WaypointType.WAYPOINT);
|
|
||||||
waypoint2.setTrackId(trackId);
|
|
||||||
Waypoint waypoint3 = new Waypoint();
|
|
||||||
waypoint3.setType(WaypointType.STATISTICS);
|
|
||||||
waypoint3.setTrackId(trackId);
|
|
||||||
Waypoint waypoint4 = new Waypoint();
|
|
||||||
waypoint4.setType(WaypointType.WAYPOINT);
|
|
||||||
waypoint4.setTrackId(trackId);
|
|
||||||
providerUtils.insertWaypoint(waypoint1);
|
|
||||||
providerUtils.insertWaypoint(waypoint2);
|
|
||||||
providerUtils.insertWaypoint(waypoint3);
|
|
||||||
providerUtils.insertWaypoint(waypoint4);
|
|
||||||
|
|
||||||
Assert.assertEquals(2, providerUtils.getNextWaypointNumber(trackId, WaypointType.STATISTICS));
|
|
||||||
Assert.assertEquals(3, providerUtils.getNextWaypointNumber(trackId, WaypointType.WAYPOINT));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method
|
|
||||||
* {@link ContentProviderUtils#getLastWaypoint(long, WaypointType)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetLastStatisticsWaypoint() {
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
Track track = getTrack(trackId, 10);
|
|
||||||
providerUtils.insertTrack(track);
|
|
||||||
|
|
||||||
Waypoint waypoint1 = new Waypoint();
|
|
||||||
waypoint1.setTrackId(trackId);
|
|
||||||
waypoint1.setType(WaypointType.STATISTICS);
|
|
||||||
waypoint1.setDescription("Desc1");
|
|
||||||
Waypoint waypoint2 = new Waypoint();
|
|
||||||
waypoint2.setTrackId(trackId);
|
|
||||||
waypoint2.setType(WaypointType.STATISTICS);
|
|
||||||
waypoint2.setDescription("Desc2");
|
|
||||||
Waypoint waypoint3 = new Waypoint();
|
|
||||||
waypoint3.setTrackId(trackId);
|
|
||||||
waypoint3.setType(WaypointType.WAYPOINT);
|
|
||||||
waypoint3.setDescription("Desc3");
|
|
||||||
providerUtils.insertWaypoint(waypoint1);
|
|
||||||
providerUtils.insertWaypoint(waypoint2);
|
|
||||||
providerUtils.insertWaypoint(waypoint3);
|
|
||||||
|
|
||||||
Assert.assertEquals("Desc2", providerUtils.getLastWaypoint(trackId, WaypointType.STATISTICS).getDescription());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link ContentProviderUtilsImpl#insertWaypoint(Waypoint)} and
|
|
||||||
* {@link ContentProviderUtilsImpl#getWaypoint(long)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testInsertAndGetWaypoint() {
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
Track track = getTrack(trackId, 10);
|
|
||||||
providerUtils.insertTrack(track);
|
|
||||||
|
|
||||||
Waypoint waypoint = new Waypoint();
|
|
||||||
waypoint.setDescription(TEST_DESC);
|
|
||||||
waypoint.setTrackId(trackId);
|
|
||||||
long waypointId = ContentUris.parseId(providerUtils.insertWaypoint(waypoint));
|
|
||||||
|
|
||||||
Assert.assertEquals(TEST_DESC, providerUtils.getWaypoint(waypointId).getDescription());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link ContentProviderUtilsImpl#updateWaypoint(Waypoint)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testUpdateWaypoint() {
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
Track track = getTrack(trackId, 10);
|
|
||||||
providerUtils.insertTrack(track);
|
|
||||||
// Insert at first.
|
|
||||||
Waypoint waypoint = new Waypoint();
|
|
||||||
waypoint.setDescription(TEST_DESC);
|
|
||||||
waypoint.setTrackId(trackId);
|
|
||||||
long waypointId = ContentUris.parseId(providerUtils.insertWaypoint(waypoint));
|
|
||||||
|
|
||||||
// Update
|
|
||||||
waypoint = providerUtils.getWaypoint(waypointId);
|
|
||||||
waypoint.setDescription(TEST_DESC_NEW);
|
|
||||||
providerUtils.updateWaypoint(waypoint);
|
|
||||||
|
|
||||||
Assert.assertEquals(TEST_DESC_NEW, providerUtils.getWaypoint(waypointId).getDescription());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link ContentProviderUtilsImpl#bulkInsertTrackPoint(Location[], int, long)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testBulkInsertTrackPoint() {
|
|
||||||
// Insert track, point at first.
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
Track track = getTrack(trackId, 10);
|
|
||||||
insertTrackWithLocations(track);
|
|
||||||
|
|
||||||
providerUtils.bulkInsertTrackPoint(track.getLocations().toArray(new Location[0]), -1, trackId);
|
|
||||||
Assert.assertEquals(20, providerUtils.getTrackPointCursor(trackId, -1L, 1000, false).getCount());
|
|
||||||
providerUtils.bulkInsertTrackPoint(track.getLocations().toArray(new Location[0]), 8, trackId);
|
|
||||||
Assert.assertEquals(28, providerUtils.getTrackPointCursor(trackId, -1L, 1000, false).getCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link ContentProviderUtilsImpl#createTrackPoint(Cursor)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testCreateTrackPoint() {
|
|
||||||
// Set index.
|
|
||||||
int index = 1;
|
|
||||||
// Id
|
|
||||||
when(cursorMock.getColumnIndex(TrackPointsColumns._ID)).thenReturn(index++);
|
|
||||||
// Longitude
|
|
||||||
when(cursorMock.getColumnIndexOrThrow(TrackPointsColumns.LONGITUDE)).thenReturn(index++);
|
|
||||||
// Latitude
|
|
||||||
when(cursorMock.getColumnIndexOrThrow(TrackPointsColumns.LATITUDE)).thenReturn(index++);
|
|
||||||
// Time
|
|
||||||
when(cursorMock.getColumnIndexOrThrow(TrackPointsColumns.TIME))
|
|
||||||
.thenReturn(index++);
|
|
||||||
// Speed
|
|
||||||
when(cursorMock.getColumnIndexOrThrow(TrackPointsColumns.SPEED)).thenReturn(index++);
|
|
||||||
// Sensor
|
|
||||||
when(cursorMock.getColumnIndexOrThrow(TrackPointsColumns.SENSOR_HEARTRATE)).thenReturn(index++);
|
|
||||||
|
|
||||||
// Set return value of isNull().
|
|
||||||
index = 2;
|
|
||||||
// Longitude
|
|
||||||
when(cursorMock.isNull(index++)).thenReturn(false);
|
|
||||||
// Latitude
|
|
||||||
when(cursorMock.isNull(index++)).thenReturn(false);
|
|
||||||
// Time
|
|
||||||
when(cursorMock.isNull(index++)).thenReturn(false);
|
|
||||||
// Speed
|
|
||||||
when(cursorMock.isNull(index++)).thenReturn(false);
|
|
||||||
// Sensor
|
|
||||||
when(cursorMock.isNull(index++)).thenReturn(false);
|
|
||||||
|
|
||||||
// Set return value of isNull().
|
|
||||||
index = 2;
|
|
||||||
// Longitude
|
|
||||||
int longitude = 11;
|
|
||||||
when(cursorMock.getInt(index++)).thenReturn(longitude * 1000000);
|
|
||||||
// Latitude.
|
|
||||||
int latitude = 22;
|
|
||||||
when(cursorMock.getInt(index++)).thenReturn(latitude * 1000000);
|
|
||||||
// Time
|
|
||||||
long time = System.currentTimeMillis();
|
|
||||||
when(cursorMock.getLong(index++)).thenReturn(time);
|
|
||||||
// Speed
|
|
||||||
float speed = 2.2f;
|
|
||||||
when(cursorMock.getFloat(index++)).thenReturn(speed);
|
|
||||||
// Sensor
|
|
||||||
byte[] sensor = "Sensor state".getBytes();
|
|
||||||
when(cursorMock.getBlob(index++)).thenReturn(sensor);
|
|
||||||
|
|
||||||
Location location = providerUtils.createTrackPoint(cursorMock);
|
|
||||||
Assert.assertEquals((double) longitude, location.getLongitude(), 0.01);
|
|
||||||
Assert.assertEquals((double) latitude, location.getLatitude(), 0.01);
|
|
||||||
Assert.assertEquals(time, location.getTime(), 0.01);
|
|
||||||
Assert.assertEquals(speed, location.getSpeed(), 0.01);
|
|
||||||
verify(cursorMock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method
|
|
||||||
* {@link ContentProviderUtilsImpl#insertTrackPoint(Location, long)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testInsertTrackPoint() {
|
|
||||||
// Insert track, point at first.
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
Track track = getTrack(trackId, 10);
|
|
||||||
insertTrackWithLocations(track);
|
|
||||||
|
|
||||||
providerUtils.insertTrackPoint(createLocation(22), trackId);
|
|
||||||
Assert.assertEquals(11, providerUtils.getTrackPointCursor(trackId, -1L, 1000, false).getCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link ContentProviderUtilsImpl#getFirstTrackPointId(long)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetFirstTrackPointId() {
|
|
||||||
// Insert track, point at first.
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
Track track = getTrack(trackId, 10);
|
|
||||||
insertTrackWithLocations(track);
|
|
||||||
|
|
||||||
Assert.assertNotEquals(-1L, providerUtils.getFirstTrackPointId(trackId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link ContentProviderUtilsImpl#getLastTrackPointId(long)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetLastTrackPointId() {
|
|
||||||
// Insert track, point at first.
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
Track track = getTrack(trackId, 10);
|
|
||||||
insertTrackWithLocations(track);
|
|
||||||
|
|
||||||
Assert.assertTrue(providerUtils.getFirstTrackPointId(trackId) < providerUtils.getLastTrackPointId(trackId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link ContentProviderUtilsImpl#getLastValidTrackPoint(long)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetLastValidTrackPoint() {
|
|
||||||
// Insert track, points at first.
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
Track track = getTrack(trackId, 10);
|
|
||||||
insertTrackWithLocations(track);
|
|
||||||
|
|
||||||
Location lastLocation = providerUtils.getLastValidTrackPoint(trackId);
|
|
||||||
checkLocation(9, lastLocation);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link ContentProviderUtilsImpl#getTrackPointCursor(long, long, int, boolean)} in descending.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetTrackPointCursor_desc() {
|
|
||||||
// Insert track, points at first.
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
Track track = getTrack(trackId, 10);
|
|
||||||
providerUtils.insertTrack(track);
|
|
||||||
|
|
||||||
long[] trackpointIds = new long[track.getNumberOfPoints()];
|
|
||||||
for (int i = 0; i < trackpointIds.length; i++) {
|
|
||||||
trackpointIds[i] = ContentUris.parseId(providerUtils.insertTrackPoint(track.getLocations().get(i), track.getId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
Cursor cursor = providerUtils.getTrackPointCursor(trackId, trackpointIds[1], 5, true);
|
|
||||||
Assert.assertEquals(2, cursor.getCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link ContentProviderUtilsImpl#getTrackPointCursor(long, long, int, boolean)} in ascending.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetTrackPointCursor_asc() {
|
|
||||||
// Insert track, points at first.
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
Track track = getTrack(trackId, 10);
|
|
||||||
providerUtils.insertTrack(track);
|
|
||||||
|
|
||||||
long[] trackpointIds = new long[track.getNumberOfPoints()];
|
|
||||||
for (int i = 0; i < trackpointIds.length; i++) {
|
|
||||||
trackpointIds[i] = ContentUris.parseId(providerUtils.insertTrackPoint(track.getLocations().get(i), track.getId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
Cursor cursor = providerUtils.getTrackPointCursor(trackId, trackpointIds[8], 5, false);
|
|
||||||
Assert.assertEquals(2, cursor.getCount());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link ContentProviderUtilsImpl#getTrackPointLocationIterator(long, long, boolean, LocationFactory)} in descending.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetTrackPointLocationIterator_desc() {
|
|
||||||
// Insert track, points at first.
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
Track track = getTrack(trackId, 10);
|
|
||||||
providerUtils.insertTrack(track);
|
|
||||||
|
|
||||||
long[] trackpointIds = new long[track.getNumberOfPoints()];
|
|
||||||
for (int i = 0; i < trackpointIds.length; i++) {
|
|
||||||
trackpointIds[i] = ContentUris.parseId(providerUtils.insertTrackPoint(track.getLocations().get(i), track.getId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
long startTrackPointId = trackpointIds[9];
|
|
||||||
|
|
||||||
LocationIterator locationIterator = providerUtils.getTrackPointLocationIterator(trackId, startTrackPointId, true, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
|
|
||||||
for (int i = 0; i < trackpointIds.length; i++) {
|
|
||||||
Assert.assertTrue(locationIterator.hasNext());
|
|
||||||
Location location = locationIterator.next();
|
|
||||||
Assert.assertEquals(startTrackPointId - i, locationIterator.getLocationId());
|
|
||||||
checkLocation((trackpointIds.length - 1) - i, location);
|
|
||||||
}
|
|
||||||
Assert.assertFalse(locationIterator.hasNext());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the method {@link ContentProviderUtilsImpl#getTrackPointLocationIterator(long, long, boolean, LocationFactory)} in ascending.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testGetTrackPointLocationIterator_asc() {
|
|
||||||
// Insert track, point at first.
|
|
||||||
long trackId = System.currentTimeMillis();
|
|
||||||
Track track = getTrack(trackId, 10);
|
|
||||||
providerUtils.insertTrack(track);
|
|
||||||
|
|
||||||
long[] trackpointIds = new long[track.getNumberOfPoints()];
|
|
||||||
for (int i = 0; i < trackpointIds.length; i++) {
|
|
||||||
trackpointIds[i] = ContentUris.parseId(providerUtils.insertTrackPoint(track.getLocations().get(i), track.getId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
long startTrackPointId = trackpointIds[0];
|
|
||||||
|
|
||||||
LocationIterator locationIterator = providerUtils.getTrackPointLocationIterator(trackId, startTrackPointId, false, ContentProviderUtils.DEFAULT_LOCATION_FACTORY);
|
|
||||||
for (int i = 0; i < trackpointIds.length; i++) {
|
|
||||||
Assert.assertTrue(locationIterator.hasNext());
|
|
||||||
Location location = locationIterator.next();
|
|
||||||
Assert.assertEquals(startTrackPointId + i, locationIterator.getLocationId());
|
|
||||||
|
|
||||||
checkLocation(i, location);
|
|
||||||
}
|
|
||||||
Assert.assertFalse(locationIterator.hasNext());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simulates a track which is used for testing.
|
|
||||||
*
|
|
||||||
* @param id the id of the track
|
|
||||||
* @param numPoints the location number in the track
|
|
||||||
* @return the simulated track
|
|
||||||
*/
|
|
||||||
private Track getTrack(long id, int numPoints) {
|
|
||||||
Track track = new Track();
|
|
||||||
track.setId(id);
|
|
||||||
track.setName("Test: " + id);
|
|
||||||
track.setNumberOfPoints(numPoints);
|
|
||||||
for (int i = 0; i < numPoints; i++) {
|
|
||||||
track.addLocation(createLocation(i));
|
|
||||||
}
|
|
||||||
return track;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a location.
|
|
||||||
*
|
|
||||||
* @param i the index to set the value of location.
|
|
||||||
* @return created location
|
|
||||||
*/
|
|
||||||
private Location createLocation(int i) {
|
|
||||||
Location loc = new Location("test");
|
|
||||||
loc.setLatitude(INITIAL_LATITUDE + (double) i / 10000.0);
|
|
||||||
loc.setLongitude(INITIAL_LONGITUDE - (double) i / 10000.0);
|
|
||||||
loc.setAccuracy((float) i / 100.0f);
|
|
||||||
loc.setAltitude(i * ALTITUDE_INTERVAL);
|
|
||||||
return loc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks the value of a location.
|
|
||||||
*
|
|
||||||
* @param i the index of this location which created in the method {@link CustomContentProviderUtilsImplTest#getTrack(long, int)}
|
|
||||||
* @param location the location to be checked
|
|
||||||
*/
|
|
||||||
private void checkLocation(int i, Location location) {
|
|
||||||
Assert.assertEquals(INITIAL_LATITUDE + (double) i / 10000.0, location.getLatitude(), 0.01);
|
|
||||||
Assert.assertEquals(INITIAL_LONGITUDE - (double) i / 10000.0, location.getLongitude(), 0.01);
|
|
||||||
Assert.assertEquals((float) i / 100.0f, location.getAccuracy(), 0.01);
|
|
||||||
Assert.assertEquals(i * ALTITUDE_INTERVAL, location.getAltitude(), 0.01);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts a track with locations into the database.
|
|
||||||
*
|
|
||||||
* @param track track to be inserted
|
|
||||||
*/
|
|
||||||
private void insertTrackWithLocations(Track track) {
|
|
||||||
providerUtils.insertTrack(track);
|
|
||||||
providerUtils.bulkInsertTrackPoint(track.getLocations().toArray(new Location[0]), track.getLocations().size(), track.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -27,34 +27,35 @@ 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.stats.TripStatistics;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
import de.dennisguse.opentracks.util.StringUtils;
|
import de.dennisguse.opentracks.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link DescriptionGeneratorImpl}.
|
* Tests for {@link DescriptionGenerator}.
|
||||||
*
|
*
|
||||||
* @author Jimmy Shih
|
* @author Jimmy Shih
|
||||||
*/
|
*/
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class DescriptionGeneratorImplTest {
|
public class DescriptionGeneratorTest {
|
||||||
|
|
||||||
private static final long START_TIME = 1288721514000L;
|
private static final long START_TIME = 1288721514000L;
|
||||||
private DescriptionGeneratorImpl descriptionGenerator;
|
private DescriptionGenerator descriptionGenerator;
|
||||||
|
|
||||||
private Context context = ApplicationProvider.getApplicationContext();
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
descriptionGenerator = new DescriptionGeneratorImpl(ApplicationProvider.getApplicationContext());
|
descriptionGenerator = new DescriptionGenerator(ApplicationProvider.getApplicationContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link DescriptionGeneratorImpl#generateTrackDescription(Track, boolean)}.
|
* Tests {@link DescriptionGenerator#generateTrackDescription(Track, boolean)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGenerateTrackDescription() {
|
public void testGenerateTrackDescription() {
|
||||||
Track track = new Track();
|
Track track = new Track();
|
||||||
TripStatistics stats = new TripStatistics();
|
TrackStatistics stats = new TrackStatistics();
|
||||||
stats.setTotalDistance(20000);
|
stats.setTotalDistance(20000);
|
||||||
stats.setTotalTime(600000);
|
stats.setTotalTime(600000);
|
||||||
stats.setMovingTime(300000);
|
stats.setMovingTime(300000);
|
||||||
@@ -62,13 +63,11 @@ public class DescriptionGeneratorImplTest {
|
|||||||
stats.setMaxElevation(550);
|
stats.setMaxElevation(550);
|
||||||
stats.setMinElevation(-500);
|
stats.setMinElevation(-500);
|
||||||
stats.setTotalElevationGain(6000);
|
stats.setTotalElevationGain(6000);
|
||||||
stats.setMaxGrade(0.42);
|
stats.setStartTime_ms(START_TIME);
|
||||||
stats.setMinGrade(0.11);
|
track.setTrackStatistics(stats);
|
||||||
stats.setStartTime(START_TIME);
|
|
||||||
track.setTripStatistics(stats);
|
|
||||||
track.setCategory("hiking");
|
track.setCategory("hiking");
|
||||||
String expected = //"Created by"
|
String expected = //"Created by"
|
||||||
"<a href='https://github.com/dennisguse/opentracks'>OpenTracks</a><p>"
|
"<a href='https://github.com/OpenTracksApp/OpenTracks'>OpenTracks</a><p>"
|
||||||
+ "Name: -<br>"
|
+ "Name: -<br>"
|
||||||
+ "Activity type: hiking<br>"
|
+ "Activity type: hiking<br>"
|
||||||
+ "Description: -<br>"
|
+ "Description: -<br>"
|
||||||
@@ -84,51 +83,48 @@ public class DescriptionGeneratorImplTest {
|
|||||||
+ "Max elevation: 550 m (1804 ft)<br>"
|
+ "Max elevation: 550 m (1804 ft)<br>"
|
||||||
+ "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>"
|
||||||
+ "Max grade: 42 %<br>"
|
|
||||||
+ "Min grade: 11 %<br>"
|
|
||||||
+ "Recorded: " + StringUtils.formatDateTime(context, START_TIME) + "<br>";
|
+ "Recorded: " + StringUtils.formatDateTime(context, START_TIME) + "<br>";
|
||||||
|
|
||||||
Assert.assertEquals(expected, descriptionGenerator.generateTrackDescription(track, true));
|
Assert.assertEquals(expected, descriptionGenerator.generateTrackDescription(track, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link DescriptionGeneratorImpl#generateWaypointDescription(TripStatistics)}.
|
|
||||||
*/
|
|
||||||
@Test
|
@Test
|
||||||
public void testGenerateWaypointDescription() {
|
public void testGenerateTrackDescriptionWithoutMaxMinElevation() {
|
||||||
Waypoint waypoint = new Waypoint();
|
Track track = new Track();
|
||||||
TripStatistics stats = new TripStatistics();
|
TrackStatistics stats = new TrackStatistics();
|
||||||
stats.setTotalDistance(20000);
|
stats.setTotalDistance(20000);
|
||||||
stats.setTotalTime(600000);
|
stats.setTotalTime(600000);
|
||||||
stats.setMovingTime(300000);
|
stats.setMovingTime(300000);
|
||||||
stats.setMaxSpeed(100);
|
stats.setMaxSpeed(100);
|
||||||
stats.setMaxElevation(550);
|
stats.setMaxElevation(Double.POSITIVE_INFINITY);
|
||||||
stats.setMinElevation(-500);
|
stats.setMinElevation(Double.NEGATIVE_INFINITY);
|
||||||
stats.setTotalElevationGain(6000);
|
stats.setTotalElevationGain(6000);
|
||||||
stats.setMaxGrade(0.42);
|
stats.setStartTime_ms(START_TIME);
|
||||||
stats.setMinGrade(0.11);
|
track.setTrackStatistics(stats);
|
||||||
stats.setStartTime(START_TIME);
|
track.setCategory("hiking");
|
||||||
waypoint.setTripStatistics(stats);
|
String expected = //"Created by"
|
||||||
String expected = "Total distance: 20.00 km (12.4 mi)\n"
|
"<a href='https://github.com/OpenTracksApp/OpenTracks'>OpenTracks</a><p>"
|
||||||
+ "Total time: 10:00\n"
|
+ "Name: -<br>"
|
||||||
+ "Moving time: 05:00\n"
|
+ "Activity type: hiking<br>"
|
||||||
+ "Average speed: 120.00 km/h (74.6 mi/h)\n"
|
+ "Description: -<br>"
|
||||||
+ "Average moving speed: 240.00 km/h (149.1 mi/h)\n"
|
+ "Total distance: 20.00 km (12.4 mi)<br>"
|
||||||
+ "Max speed: 360.00 km/h (223.7 mi/h)\n"
|
+ "Total time: 10:00<br>"
|
||||||
+ "Average pace: 0:30 min/km (0:48 min/mi)\n"
|
+ "Moving time: 05:00<br>"
|
||||||
+ "Average moving pace: 0:15 min/km (0:24 min/mi)\n"
|
+ "Average speed: 120.00 km/h (74.6 mi/h)<br>"
|
||||||
+ "Fastest pace: 0:10 min/km (0:16 min/mi)\n"
|
+ "Average moving speed: 240.00 km/h (149.1 mi/h)<br>"
|
||||||
+ "Max elevation: 550 m (1804 ft)\n"
|
+ "Max speed: 360.00 km/h (223.7 mi/h)<br>"
|
||||||
+ "Min elevation: -500 m (-1640 ft)\n"
|
+ "Average pace: 0:30 min/km (0:48 min/mi)<br>"
|
||||||
+ "Elevation gain: 6000 m (19685 ft)\n"
|
+ "Average moving pace: 0:15 min/km (0:24 min/mi)<br>"
|
||||||
+ "Max grade: 42 %\n"
|
+ "Fastest pace: 0:10 min/km (0:16 min/mi)<br>"
|
||||||
+ "Min grade: 11 %\n"
|
+ "Elevation gain: 6000 m (19685 ft)<br>"
|
||||||
+ "Recorded: " + StringUtils.formatDateTime(context, START_TIME) + "\n";
|
+ "Recorded: " + StringUtils.formatDateTime(context, START_TIME) + "<br>";
|
||||||
Assert.assertEquals(expected, descriptionGenerator.generateWaypointDescription(waypoint.getTripStatistics()));
|
|
||||||
|
Assert.assertEquals(expected, descriptionGenerator.generateTrackDescription(track, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link DescriptionGeneratorImpl#writeDistance(double, StringBuilder, int, String)}.
|
* Tests {@link DescriptionGenerator#writeDistance(double, StringBuilder, int, String)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testWriteDistance() {
|
public void testWriteDistance() {
|
||||||
@@ -138,7 +134,7 @@ public class DescriptionGeneratorImplTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link DescriptionGeneratorImpl#writeTime(long, StringBuilder, int, String)}.
|
* Tests {@link DescriptionGenerator#writeTime(long, StringBuilder, int, String)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testWriteTime() {
|
public void testWriteTime() {
|
||||||
@@ -148,7 +144,7 @@ public class DescriptionGeneratorImplTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link DescriptionGeneratorImpl#writeSpeed(double, StringBuilder, int, String)}.
|
* Tests {@link DescriptionGenerator#writeSpeed(double, StringBuilder, int, String)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testWriteSpeed() {
|
public void testWriteSpeed() {
|
||||||
@@ -158,7 +154,7 @@ public class DescriptionGeneratorImplTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link DescriptionGeneratorImpl#writeElevation(double, StringBuilder, int, String)}.
|
* Tests {@link DescriptionGenerator#writeElevation(double, StringBuilder, int, String)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testWriteElevation() {
|
public void testWriteElevation() {
|
||||||
@@ -168,7 +164,7 @@ public class DescriptionGeneratorImplTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link DescriptionGeneratorImpl#writePace(double, StringBuilder, int, String)}.
|
* Tests {@link DescriptionGenerator#writePace(double, StringBuilder, int, String)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testWritePace() {
|
public void testWritePace() {
|
||||||
@@ -176,34 +172,4 @@ public class DescriptionGeneratorImplTest {
|
|||||||
descriptionGenerator.writePace(1.1, builder, R.string.description_average_pace_in_minute, "\n");
|
descriptionGenerator.writePace(1.1, builder, R.string.description_average_pace_in_minute, "\n");
|
||||||
Assert.assertEquals("Average pace: 15:09 min/km (24:23 min/mi)\n", builder.toString());
|
Assert.assertEquals("Average pace: 15:09 min/km (24:23 min/mi)\n", builder.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link DescriptionGeneratorImpl#writeGrade(double, StringBuilder, int, String)}.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testWriteGrade() {
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
descriptionGenerator.writeGrade(.042, builder, R.string.description_max_grade, "<br>");
|
|
||||||
Assert.assertEquals("Max grade: 4 %<br>", builder.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link DescriptionGeneratorImpl#writeGrade(double, StringBuilder, int, String)} with a NaN.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testWriteGrade_nan() {
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
descriptionGenerator.writeGrade(Double.NaN, builder, R.string.description_max_grade, "<br>");
|
|
||||||
Assert.assertEquals("Max grade: 0 %<br>", builder.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link DescriptionGeneratorImpl#writeGrade(double, StringBuilder, int, String)} with an infinite number.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testWriteGrade_infinite() {
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
descriptionGenerator.writeGrade(Double.POSITIVE_INFINITY, builder, R.string.description_max_grade, "<br>");
|
|
||||||
Assert.assertEquals("Max grade: 0 %<br>", builder.toString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -36,7 +36,10 @@ import java.util.List;
|
|||||||
|
|
||||||
import de.dennisguse.opentracks.content.SearchEngine.ScoredResult;
|
import de.dennisguse.opentracks.content.SearchEngine.ScoredResult;
|
||||||
import de.dennisguse.opentracks.content.SearchEngine.SearchQuery;
|
import de.dennisguse.opentracks.content.SearchEngine.SearchQuery;
|
||||||
import de.dennisguse.opentracks.stats.TripStatistics;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
|
import de.dennisguse.opentracks.content.data.Waypoint;
|
||||||
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link SearchEngine}.
|
* Tests for {@link SearchEngine}.
|
||||||
@@ -53,67 +56,56 @@ public class SearchEngineTest {
|
|||||||
private ContentProviderUtils providerUtils;
|
private ContentProviderUtils providerUtils;
|
||||||
private SearchEngine engine;
|
private SearchEngine engine;
|
||||||
|
|
||||||
private Context context = ApplicationProvider.getApplicationContext();
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
providerUtils = ContentProviderUtils.Factory.get(context);
|
providerUtils = new ContentProviderUtils(context);
|
||||||
engine = new SearchEngine(providerUtils);
|
engine = new SearchEngine(providerUtils);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws Exception {
|
public void tearDown() {
|
||||||
providerUtils.deleteAllTracks(context);
|
providerUtils.deleteAllTracks(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long insertTrack(String title, String description, String category, double distance, long hoursAgo) {
|
private long insertTrack(String title, String description, String category, long hoursAgo) {
|
||||||
Track track = new Track();
|
Track track = new Track();
|
||||||
track.setName(title);
|
track.setName(title);
|
||||||
track.setDescription(description);
|
track.setDescription(description);
|
||||||
track.setCategory(category);
|
track.setCategory(category);
|
||||||
|
|
||||||
TripStatistics stats = track.getTripStatistics();
|
TrackStatistics stats = track.getTrackStatistics();
|
||||||
if (hoursAgo > 0) {
|
if (hoursAgo > 0) {
|
||||||
// Started twice hoursAgo, so the average time is hoursAgo.
|
// Started twice hoursAgo, so the average time is hoursAgo.
|
||||||
stats.setStartTime(NOW - hoursAgo * 1000L * 60L * 60L * 2);
|
stats.setStartTime_ms(NOW - hoursAgo * 1000L * 60L * 60L * 2);
|
||||||
stats.setStopTime(NOW);
|
stats.setStopTime_ms(NOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
int latitude = (int) ((HERE.getLatitude() + distance) * 1E6);
|
|
||||||
int longitude = (int) ((HERE.getLongitude() + distance) * 1E6);
|
|
||||||
stats.setBounds(latitude, longitude, latitude, longitude);
|
|
||||||
|
|
||||||
Uri uri = providerUtils.insertTrack(track);
|
Uri uri = providerUtils.insertTrack(track);
|
||||||
return ContentUris.parseId(uri);
|
return ContentUris.parseId(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long insertTrack(String title, String description, String category) {
|
private long insertTrack(String title, String description, String category) {
|
||||||
return insertTrack(title, description, category, 0, -1);
|
return insertTrack(title, description, category, -1);
|
||||||
}
|
|
||||||
|
|
||||||
private long insertTrack(String title, double distance) {
|
|
||||||
return insertTrack(title, "", "", distance, -1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private long insertTrack(String title, long hoursAgo) {
|
private long insertTrack(String title, long hoursAgo) {
|
||||||
return insertTrack(title, "", "", 0.0, hoursAgo);
|
return insertTrack(title, "", "", hoursAgo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long insertWaypoint(String title, String description, String category, double distance, long hoursAgo, long trackId) {
|
private long insertWaypoint(String title, String description, String category, double distance, long hoursAgo, long trackId) {
|
||||||
Waypoint waypoint = new Waypoint();
|
|
||||||
waypoint.setName(title);
|
|
||||||
waypoint.setDescription(description);
|
|
||||||
waypoint.setCategory(category);
|
|
||||||
waypoint.setTrackId(trackId);
|
|
||||||
|
|
||||||
Location location = new Location(HERE);
|
Location location = new Location(HERE);
|
||||||
location.setLatitude(location.getLatitude() + distance);
|
location.setLatitude(location.getLatitude() + distance);
|
||||||
location.setLongitude(location.getLongitude() + distance);
|
location.setLongitude(location.getLongitude() + distance);
|
||||||
if (hoursAgo >= 0) {
|
if (hoursAgo >= 0) {
|
||||||
location.setTime(NOW - hoursAgo * 1000L * 60L * 60L);
|
location.setTime(NOW - hoursAgo * 1000L * 60L * 60L);
|
||||||
}
|
}
|
||||||
waypoint.setLocation(location);
|
Waypoint waypoint = new Waypoint(location);
|
||||||
|
waypoint.setName(title);
|
||||||
|
waypoint.setDescription(description);
|
||||||
|
waypoint.setCategory(category);
|
||||||
|
waypoint.setTrackId(trackId);
|
||||||
|
|
||||||
Uri uri = providerUtils.insertWaypoint(waypoint);
|
Uri uri = providerUtils.insertWaypoint(waypoint);
|
||||||
return ContentUris.parseId(uri);
|
return ContentUris.parseId(uri);
|
||||||
@@ -154,7 +146,7 @@ public class SearchEngineTest {
|
|||||||
long allMatchId = insertTrack("aa", "ba", "ca");
|
long allMatchId = insertTrack("aa", "ba", "ca");
|
||||||
|
|
||||||
SearchQuery query = new SearchQuery("a", null, -1, NOW);
|
SearchQuery query = new SearchQuery("a", null, -1, NOW);
|
||||||
ArrayList<ScoredResult> results = new ArrayList<ScoredResult>(engine.search(query));
|
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
||||||
|
|
||||||
// Title > Description > Category.
|
// Title > Description > Category.
|
||||||
assertTrackResults(results, allMatchId, titleDescriptionMatchId, titleCategoryMatchId, titleMatchId, descriptionMatchId, categoryMatchId);
|
assertTrackResults(results, allMatchId, titleDescriptionMatchId, titleCategoryMatchId, titleMatchId, descriptionMatchId, categoryMatchId);
|
||||||
@@ -179,7 +171,7 @@ public class SearchEngineTest {
|
|||||||
long allMatchId = insertWaypoint("aa", "ba", "ca");
|
long allMatchId = insertWaypoint("aa", "ba", "ca");
|
||||||
|
|
||||||
SearchQuery query = new SearchQuery("a", null, -1, NOW);
|
SearchQuery query = new SearchQuery("a", null, -1, NOW);
|
||||||
ArrayList<ScoredResult> results = new ArrayList<ScoredResult>(engine.search(query));
|
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
||||||
|
|
||||||
// Title > Description > Category.
|
// Title > Description > Category.
|
||||||
assertWaypointResults(results, allMatchId, titleDescriptionMatchId, titleCategoryMatchId, titleMatchId, descriptionMatchId, categoryMatchId);
|
assertWaypointResults(results, allMatchId, titleDescriptionMatchId, titleCategoryMatchId, titleMatchId, descriptionMatchId, categoryMatchId);
|
||||||
@@ -200,7 +192,7 @@ public class SearchEngineTest {
|
|||||||
long trackId = insertTrack("aa", "bb", "cc");
|
long trackId = insertTrack("aa", "bb", "cc");
|
||||||
|
|
||||||
SearchQuery query = new SearchQuery("a", null, -1, NOW);
|
SearchQuery query = new SearchQuery("a", null, -1, NOW);
|
||||||
ArrayList<ScoredResult> results = new ArrayList<ScoredResult>(engine.search(query));
|
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
||||||
|
|
||||||
// Title > Description > Category.
|
// Title > Description > Category.
|
||||||
Assert.assertEquals(results.toString(), 3, results.size());
|
Assert.assertEquals(results.toString(), 3, results.size());
|
||||||
@@ -209,20 +201,6 @@ public class SearchEngineTest {
|
|||||||
assertWaypointResult(descriptionWaypointId, results.get(2));
|
assertWaypointResult(descriptionWaypointId, results.get(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSearchTrackDistance() {
|
|
||||||
// All results match text, but they're at difference distances from the user.
|
|
||||||
long farFarAwayId = insertTrack("aa", 0.3);
|
|
||||||
long nearId = insertTrack("ab", 0.1);
|
|
||||||
long farId = insertTrack("ac", 0.2);
|
|
||||||
|
|
||||||
SearchQuery query = new SearchQuery("a", HERE, -1, NOW);
|
|
||||||
ArrayList<ScoredResult> results = new ArrayList<ScoredResult>(engine.search(query));
|
|
||||||
|
|
||||||
// Distance order.
|
|
||||||
assertTrackResults(results, nearId, farId, farFarAwayId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSearchWaypointDistance() {
|
public void testSearchWaypointDistance() {
|
||||||
// All results match text, but they're at difference distances from the user.
|
// All results match text, but they're at difference distances from the user.
|
||||||
@@ -231,7 +209,7 @@ public class SearchEngineTest {
|
|||||||
long farId = insertWaypoint("ac", 0.2);
|
long farId = insertWaypoint("ac", 0.2);
|
||||||
|
|
||||||
SearchQuery query = new SearchQuery("a", HERE, -1, NOW);
|
SearchQuery query = new SearchQuery("a", HERE, -1, NOW);
|
||||||
ArrayList<ScoredResult> results = new ArrayList<ScoredResult>(engine.search(query));
|
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
||||||
|
|
||||||
// Distance order.
|
// Distance order.
|
||||||
assertWaypointResults(results, nearId, farId, farFarAwayId);
|
assertWaypointResults(results, nearId, farId, farFarAwayId);
|
||||||
@@ -244,7 +222,7 @@ public class SearchEngineTest {
|
|||||||
long oldId = insertTrack("ac", 2);
|
long oldId = insertTrack("ac", 2);
|
||||||
|
|
||||||
SearchQuery query = new SearchQuery("a", null, -1, NOW);
|
SearchQuery query = new SearchQuery("a", null, -1, NOW);
|
||||||
ArrayList<ScoredResult> results = new ArrayList<ScoredResult>(engine.search(query));
|
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
||||||
|
|
||||||
// Reverse time order.
|
// Reverse time order.
|
||||||
assertTrackResults(results, recentId, oldId, oldestId);
|
assertTrackResults(results, recentId, oldId, oldestId);
|
||||||
@@ -258,7 +236,7 @@ public class SearchEngineTest {
|
|||||||
long oldId = insertWaypoint("ac", 1);
|
long oldId = insertWaypoint("ac", 1);
|
||||||
|
|
||||||
SearchQuery query = new SearchQuery("a", null, -1, NOW);
|
SearchQuery query = new SearchQuery("a", null, -1, NOW);
|
||||||
ArrayList<ScoredResult> results = new ArrayList<ScoredResult>(engine.search(query));
|
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
||||||
|
|
||||||
// Reverse time order.
|
// Reverse time order.
|
||||||
assertWaypointResults(results, recentId, oldId, oldestId);
|
assertWaypointResults(results, recentId, oldId, oldestId);
|
||||||
@@ -271,7 +249,7 @@ public class SearchEngineTest {
|
|||||||
long otherId = insertTrack("aa", 1);
|
long otherId = insertTrack("aa", 1);
|
||||||
|
|
||||||
SearchQuery query = new SearchQuery("a", null, currentId, NOW);
|
SearchQuery query = new SearchQuery("a", null, currentId, NOW);
|
||||||
ArrayList<ScoredResult> results = new ArrayList<ScoredResult>(engine.search(query));
|
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
||||||
|
|
||||||
// Current track should be demoted.
|
// Current track should be demoted.
|
||||||
assertTrackResults(results, otherId, currentId);
|
assertTrackResults(results, otherId, currentId);
|
||||||
@@ -284,7 +262,7 @@ public class SearchEngineTest {
|
|||||||
long currentId = insertWaypoint("ab", 1, 123);
|
long currentId = insertWaypoint("ab", 1, 123);
|
||||||
|
|
||||||
SearchQuery query = new SearchQuery("a", null, 123, NOW);
|
SearchQuery query = new SearchQuery("a", null, 123, NOW);
|
||||||
ArrayList<ScoredResult> results = new ArrayList<ScoredResult>(engine.search(query));
|
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
||||||
|
|
||||||
// Waypoint in current track should be promoted.
|
// Waypoint in current track should be promoted.
|
||||||
assertWaypointResults(results, currentId, otherId);
|
assertWaypointResults(results, currentId, otherId);
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
package de.dennisguse.opentracks.content.data;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.location.Location;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
|
import de.dennisguse.opentracks.util.FileUtils;
|
||||||
|
|
||||||
|
public class TestDataUtil {
|
||||||
|
|
||||||
|
public static final double INITIAL_LATITUDE = 37.0;
|
||||||
|
public static final double INITIAL_LONGITUDE = -57.0;
|
||||||
|
public static final double ALTITUDE_INTERVAL = 2.5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a track without any trackPoints.
|
||||||
|
*/
|
||||||
|
public static Track createTrack(long trackId) {
|
||||||
|
Track track = new Track();
|
||||||
|
track.setId(trackId);
|
||||||
|
track.setName("Test: " + trackId);
|
||||||
|
|
||||||
|
return track;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simulates a track which is used for testing.
|
||||||
|
*
|
||||||
|
* @param trackId the trackId of the track
|
||||||
|
* @param numPoints the trackPoints number in the track
|
||||||
|
*/
|
||||||
|
public static Pair<Track, TrackPoint[]> createTrack(long trackId, int numPoints) {
|
||||||
|
Track track = createTrack(trackId);
|
||||||
|
|
||||||
|
TrackPoint[] trackPoints = new TrackPoint[numPoints];
|
||||||
|
for (int i = 0; i < numPoints; i++) {
|
||||||
|
trackPoints[i] = createTrackPoint(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Pair<>(track, trackPoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Track createTrackAndInsert(ContentProviderUtils contentProviderUtils, long trackId, int numPoints) {
|
||||||
|
Pair<Track, TrackPoint[]> pair = createTrack(trackId, numPoints);
|
||||||
|
|
||||||
|
insertTrackWithLocations(contentProviderUtils, pair.first, pair.second);
|
||||||
|
|
||||||
|
return pair.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a location.
|
||||||
|
*
|
||||||
|
* @param i the index for the TrackPoint.
|
||||||
|
*/
|
||||||
|
public static TrackPoint createTrackPoint(int i) {
|
||||||
|
TrackPoint trackPoint = new TrackPoint();
|
||||||
|
trackPoint.setLatitude(INITIAL_LATITUDE + (double) i / 10000.0);
|
||||||
|
trackPoint.setLongitude(INITIAL_LONGITUDE - (double) i / 10000.0);
|
||||||
|
trackPoint.setAccuracy((float) i / 100.0f);
|
||||||
|
trackPoint.setAltitude(i * ALTITUDE_INTERVAL);
|
||||||
|
trackPoint.setTime(i + 1);
|
||||||
|
trackPoint.setSpeed(5f + (i / 10));
|
||||||
|
|
||||||
|
trackPoint.setHeartRate_bpm(100f + i);
|
||||||
|
trackPoint.setCyclingCadence_rpm(200f + i);
|
||||||
|
trackPoint.setCyclingCadence_rpm(300f + i);
|
||||||
|
trackPoint.setPower(400f + i);
|
||||||
|
return trackPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts a track with locations into the database.
|
||||||
|
*
|
||||||
|
* @param track track to be inserted
|
||||||
|
* @param trackPoints trackPoints to be inserted
|
||||||
|
*/
|
||||||
|
public static void insertTrackWithLocations(ContentProviderUtils contentProviderUtils, Track track, TrackPoint[] trackPoints) {
|
||||||
|
contentProviderUtils.insertTrack(track);
|
||||||
|
contentProviderUtils.bulkInsertTrackPoint(trackPoints, track.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Waypoint with a photo.
|
||||||
|
*
|
||||||
|
* @param context The context.
|
||||||
|
* @param trackId The track id.
|
||||||
|
* @param location The location.
|
||||||
|
* @return the Waypoint created.
|
||||||
|
*/
|
||||||
|
public static Waypoint createWaypointWithPhoto(Context context, long trackId, Location location) throws IOException {
|
||||||
|
String photoUrl = "";
|
||||||
|
File dstFile = new File(FileUtils.getImageUrl(context, trackId));
|
||||||
|
dstFile.createNewFile();
|
||||||
|
Uri photoUri = FileUtils.getUriForFile(context, dstFile);
|
||||||
|
photoUrl = photoUri.toString();
|
||||||
|
|
||||||
|
return new Waypoint("Waypoint name", "Waypoint description", "Waypoint category", "", trackId, 0.0, 0, location, photoUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012 Google Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
* the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations under
|
||||||
|
* the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.dennisguse.opentracks.content.provider;
|
||||||
|
|
||||||
|
import android.content.ContentUris;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.TrackPointsColumns;
|
||||||
|
import de.dennisguse.opentracks.content.data.TracksColumns;
|
||||||
|
import de.dennisguse.opentracks.content.data.WaypointsColumns;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link CustomContentProvider}.
|
||||||
|
*
|
||||||
|
* @author Youtao Liu
|
||||||
|
*/
|
||||||
|
public class CustomContentProviderTest {
|
||||||
|
|
||||||
|
private CustomContentProvider customContentProvider;
|
||||||
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
customContentProvider = new CustomContentProvider() {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link CustomContentProvider#onCreate(android.content.Context)}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testOnCreate() {
|
||||||
|
Assert.assertTrue(customContentProvider.onCreate(context));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link CustomContentProvider#getType(Uri)}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testGetType() {
|
||||||
|
Assert.assertEquals(TracksColumns.CONTENT_TYPE, customContentProvider.getType(TracksColumns.CONTENT_URI));
|
||||||
|
Assert.assertEquals(TracksColumns.CONTENT_ITEMTYPE, customContentProvider.getType(ContentUris.appendId(TracksColumns.CONTENT_URI.buildUpon(), 1).build()));
|
||||||
|
|
||||||
|
Assert.assertEquals(TrackPointsColumns.CONTENT_TYPE, customContentProvider.getType(TrackPointsColumns.CONTENT_URI_BY_ID));
|
||||||
|
Assert.assertEquals(TrackPointsColumns.CONTENT_ITEMTYPE, customContentProvider.getType(ContentUris.appendId(TrackPointsColumns.CONTENT_URI_BY_TRACKID.buildUpon(), 1).build()));
|
||||||
|
|
||||||
|
Assert.assertEquals(WaypointsColumns.CONTENT_TYPE, customContentProvider.getType(WaypointsColumns.CONTENT_URI));
|
||||||
|
Assert.assertEquals(WaypointsColumns.CONTENT_ITEMTYPE, customContentProvider.getType(ContentUris.appendId(WaypointsColumns.CONTENT_URI.buildUpon(), 1).build()));
|
||||||
|
}
|
||||||
|
}
|
||||||